?? raidlib.c
字號:
/* raidlib.c : Multiple Devices tools for Linux Copyright (C) 1994-96 Marc ZYNGIER <zyngier@ufr-info-p7.ibp.fr> or <maz@gloups.fdn.fr> Copyright (C) 1998 Erik Troan <ewt@redhat.com> This program is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation; either version 2, or (at your option) any later version. You should have received a copy of the GNU General Public License (for example /usr/src/linux/COPYING); if not, write to the Free Software Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. */#include "common.h"#include "parser.h"#include "raidlib.h"#include "version.h"#include <string.h>#include <popt.h>#include <asm/page.h>#include <sys/sysmacros.h>#ifndef PAGE_SIZE#define PAGE_SIZE (sizeof(long)*1024)#endifmdu_version_t md_ver;#define OLD_MDTOOLS ((md_ver.major == 0) && (md_ver.minor < 0.50))static int save_errno = 0;md_cfg_entry_t *cfg_head = NULL, *cfg = NULL;int do_quiet_flag = 0;int open_or_die (char *file){ int fd; fd = open(file, O_RDWR); if (fd == -1) { if (errno == EACCES) fprintf(stderr, "need to be run as root.\n"); else if (errno == ENOSYS) fprintf(stderr, "kernel has no RAID support.\n"); else if (errno == EEXIST) fprintf(stderr, "device already running!\n"); else if (errno == ENOENT) fprintf(stderr, "no MD device file in /dev.\n"); else perror (file); exit (EXIT_FAILURE); } return fd;}int getpageshift(void){ int i,pagesize,pageshift=0; pagesize=getpagesize(); for (i=1; i <= 8*sizeof(int); i++) { if( pagesize & (1UL << i)) { pageshift += i; } } return pageshift;}/* * converts a size in bytes to 'factor' metrics, which is a * kernel-internal way of dealing with chunk sizes and stuff. * It's the number of pages within the given number. */static int s2f (int bytes){ int factor, c, i; int kbytes, pageshift; if (bytes % 1024) { fprintf (stderr, "chunk_size must be an integral number of k\n"); return 0; } kbytes = bytes >> 10; pageshift=getpageshift(); factor = kbytes >> (pageshift - 10); for (i=1, c=0; i<kbytes; i*=2) if (factor & i) c++; if ((kbytes*MD_BLK_SIZ) % PAGE_SIZE || c!=1) { fprintf (stderr, "Cannot handle %dk chunks. Defaulting to %dk\n", kbytes, 1 << (pageshift-10)); return (0); } for (i=0; !(factor & (1 << i)); i++); return (i);}__u32 get_random(void){ __u32 num; int fd; fd = open("/dev/urandom", O_RDONLY); if (fd != -1 && read(fd, &num, 4) == 4) {#if DEBUG printf("raid set magic: %x\n", num);#endif close(fd); } else { num = rand();#if DEBUG printf("raid set magic (pseudo-random): %x\n", num);#endif } return num;}static int do_mdrun (int fd, char *dev, mdu_param_t *param) { int rc; int pers; /* Old versions of md (< 0.50) used this instead. Thank Ingo for fixing it. */#define MD_PERSONALITY_SHIFT 16/* These are the ioctls for md versions < 0.50 */#define REGISTER_MD_DEV _IO (MD_MAJOR, 1)#define START_MD _IO (MD_MAJOR, 2)#define STOP_MD _IO (MD_MAJOR, 3) if (OLD_MDTOOLS) { pers = param->personality << MD_PERSONALITY_SHIFT; if ((param->personality == LINEAR || param->personality == RAID0) && param->chunk_size) pers |= s2f(param->chunk_size); rc = ioctl (fd, START_MD, (unsigned long)pers); return 0; } if ((rc = ioctl (fd, RUN_ARRAY, (unsigned long)param))) { save_errno=errno; switch (save_errno) { case EBUSY: fprintf(stderr,"%s: already running\n",dev); break; /* fall through */ default: perror (dev); } errno=save_errno; return 1; } return 0;}static int do_mdstart (int fd, char *dev, dev_t rdev) { int rc; if ((rc = ioctl (fd, START_ARRAY, (unsigned long)rdev))) { save_errno=errno; switch (save_errno) { case EEXIST: case EBUSY: fprintf(stderr,"%s: already running\n",dev); break; /* fall through */ default: perror (dev); } errno=save_errno; return 1; } return 0;}int do_raidstart_rw (int fd, char *dev){ int func = RESTART_ARRAY_RW; int rc; struct stat s; fstat (fd, &s); if (major (s.st_rdev) != MD_MAJOR) { fprintf(stderr,"%s: not an MD device!\n",dev); exit(EXIT_FAILURE); } if (OLD_MDTOOLS) exit(EXIT_FAILURE); if ((rc = ioctl (fd, func, 0UL))) { save_errno = errno; switch (save_errno) { case EBUSY: fprintf(stderr,"%s: device already read-write!\n",dev); break; case ENXIO: fprintf(stderr,"%s: not running!\n",dev); break; case EINVAL: fprintf(stderr,"%s: old kernel?\n",dev); /* fall through */ default: perror (dev); } errno = save_errno; return 1; } return 0;}int do_raidstop (int fd, char *dev, int ro){ int func = ro ? STOP_ARRAY_RO : STOP_ARRAY; int rc; struct stat s; fstat (fd, &s); if (major (s.st_rdev) != MD_MAJOR) { fprintf(stderr,"%s: not an MD device!\n",dev); exit(EXIT_FAILURE); } if (OLD_MDTOOLS) if (func == STOP_ARRAY) { rc = ioctl(fd, STOP_MD, 0UL); return 0; } if ((rc = ioctl (fd, func, 0UL))) { save_errno = errno; switch (save_errno) { case ENODEV: case ENXIO: fprintf(stderr,"%s: device already stopped\n",dev); break; case EINVAL: if (func == STOP_ARRAY_RO) { fprintf(stderr,"%s: old kernel!\n",dev); break; } /* fall through */ default: perror (dev); } errno = save_errno; return 1; } return 0;}int do_raidhotadd (int md_fd, char * disk_name, char * md_name){ int rc; struct stat s; if (OLD_MDTOOLS) { fprintf(stderr,"kernel does not support hot-add!\n"); exit(EXIT_FAILURE); } fstat (md_fd, &s); if (major (s.st_rdev) != MD_MAJOR) { fprintf(stderr,"%s: not an MD device!\n",md_name); exit(EXIT_FAILURE); } stat (disk_name, &s); rc = ioctl (md_fd, HOT_ADD_DISK, (unsigned long)s.st_rdev); if (rc) { save_errno = errno; fprintf(stderr,"%s: can not hot-add disk: ", md_name); switch (save_errno) { case ENXIO: fprintf(stderr,"disk does not exist!\n"); break; case EBUSY: fprintf(stderr,"disk busy!\n"); break; case ENOSPC: fprintf(stderr,"too small disk!\n"); break; case ENODEV: fprintf(stderr,"array not running!\n"); break; case EINVAL: fprintf(stderr,"invalid argument.\n"); break; default: perror (md_name); } errno = save_errno; return 1; } return 0;}int do_raidhotgenerateerror (int md_fd, char * disk_name, char * md_name){ int rc; struct stat s; if (OLD_MDTOOLS) { fprintf(stderr,"kernel does not support hot-generate-error!\n"); exit(EXIT_FAILURE); } fstat (md_fd, &s); if (major (s.st_rdev) != MD_MAJOR) { fprintf(stderr,"%s: not an MD device!\n",md_name); exit(EXIT_FAILURE); } stat (disk_name, &s); rc = ioctl (md_fd, HOT_GENERATE_ERROR, (unsigned long)s.st_rdev); if (rc) { save_errno = errno; fprintf(stderr,"%s: can not hot-generate-error disk: ", md_name); switch (save_errno) { case ENXIO: fprintf(stderr,"disk not in array!\n"); break; case EBUSY: fprintf(stderr,"disk busy!\n"); break; case ENOSPC: fprintf(stderr,"too small disk!\n"); break; case ENODEV: fprintf(stderr,"array not running!\n"); break; case EINVAL: fprintf(stderr,"invalid argument.\n"); break; default: perror (md_name); } errno = save_errno; return 1; } return 0;}int do_raidhotremove (int md_fd, char * disk_name, char * md_name){ int rc; struct stat s; if (OLD_MDTOOLS) { fprintf(stderr,"kernel does not support hot-remove!\n"); exit(EXIT_FAILURE); } fstat (md_fd, &s); if (major (s.st_rdev) != MD_MAJOR) { fprintf(stderr,"%s: not an MD device!\n",md_name); exit(EXIT_FAILURE); } stat (disk_name, &s); rc = ioctl (md_fd, HOT_REMOVE_DISK, (unsigned long)s.st_rdev); if (rc) { save_errno = errno; fprintf(stderr,"%s: can not hot-remove disk: ", md_name); switch (save_errno) { case ENXIO: fprintf(stderr,"disk not in array!\n"); break; case EBUSY: fprintf(stderr,"disk busy!\n"); break; case ENOSPC: fprintf(stderr,"too small disk!\n"); break; case ENODEV: fprintf(stderr,"array not running!\n"); break; case EINVAL: fprintf(stderr,"invalid argument.\n"); break; default: perror (md_name); } errno = save_errno; return 1; } return 0;}int do_raidsetfaulty (int md_fd, char * disk_name, char * md_name){ int rc; struct stat s; if (OLD_MDTOOLS) { fprintf(stderr,"kernel does not support hot-add!\n"); exit(EXIT_FAILURE); } fstat (md_fd, &s); if (major (s.st_rdev) != MD_MAJOR) { fprintf(stderr,"%s: not an MD device!\n",md_name); exit(EXIT_FAILURE); } stat (disk_name, &s); rc = ioctl (md_fd, SET_DISK_FAULTY, (unsigned long)s.st_rdev); if (rc) { save_errno = errno; fprintf(stderr,"%s: can not set disk faulty: ", md_name); switch (save_errno) { case ENXIO: fprintf(stderr,"disk does not exist!\n"); break; case EBUSY: fprintf(stderr,"disk busy!\n"); break; case ENOSPC: fprintf(stderr,"too small disk!\n"); break; case ENODEV: fprintf(stderr,"array not running!\n"); break; case EINVAL: fprintf(stderr,"invalid argument.\n"); break; default: perror (md_name); } errno = save_errno; return 1; } return 0;}int handleOneConfig(enum raidFunc func, md_cfg_entry_t * cfg) { int rc = 0; int fd = -1; mdu_param_t param; switch (func) { case raidstart: { struct stat s; stat (cfg->device_name[0], &s); fd = open_or_die(cfg->md_name); if (do_mdstart (fd, cfg->md_name, s.st_rdev)) rc++; break; } case raidrun: memset(¶m,0,sizeof(param)); switch (cfg->array.param.level) { case -4: param.personality = MULTIPATH; break; case -3: param.personality = HSM; break; case -2: param.personality = TRANSLUCENT; break; case -1: param.personality = LINEAR; break; case 0: param.personality = RAID0; break; case 1: param.personality = RAID1; break; case 4: case 5: param.personality = RAID5; break; default: exit (EXIT_FAILURE); } param.chunk_size = cfg->array.param.chunk_size; fd = open_or_die(cfg->md_name); if (do_mdrun (fd, cfg->md_name, ¶m)) rc++; break; case raidstop: return 1; case raidstop_ro: return 1; case raidhotremove: return 1; case raidhotadd: return 1; case raidhotgenerateerror: return 1; case raidsetfaulty: return 1; } close (fd); return rc;}int prepare_raidlib (void){ if (getMdVersion(&md_ver)) return EXIT_FAILURE; return 0;}
?? 快捷鍵說明
復制代碼
Ctrl + C
搜索代碼
Ctrl + F
全屏模式
F11
切換主題
Ctrl + Shift + D
顯示快捷鍵
?
增大字號
Ctrl + =
減小字號
Ctrl + -