📄 md.c
字号:
SET_SB(size); SET_SB(nr_disks); SET_SB(raid_disks); SET_SB(md_minor); SET_SB(not_persistent); SET_SB(state); SET_SB(active_disks); SET_SB(working_disks); SET_SB(failed_disks); SET_SB(spare_disks); SET_SB(layout); SET_SB(chunk_size); mddev->sb->md_magic = MD_SB_MAGIC; /* * Generate a 128 bit UUID */ get_random_bytes(&mddev->sb->set_uuid0, 4); get_random_bytes(&mddev->sb->set_uuid1, 4); get_random_bytes(&mddev->sb->set_uuid2, 4); get_random_bytes(&mddev->sb->set_uuid3, 4); return 0;}#undef SET_SBstatic int set_disk_info (mddev_t * mddev, void * arg){ printk("not yet"); return -EINVAL;}static int clear_array (mddev_t * mddev){ printk("not yet"); return -EINVAL;}static int write_raid_info (mddev_t * mddev){ printk("not yet"); return -EINVAL;}static int protect_array (mddev_t * mddev){ printk("not yet"); return -EINVAL;}static int unprotect_array (mddev_t * mddev){ printk("not yet"); return -EINVAL;}static int set_disk_faulty (mddev_t *mddev, kdev_t dev){ int ret; fsync_dev(mddev_to_kdev(mddev)); ret = md_error(mddev_to_kdev(mddev), dev); return ret;}static int md_ioctl (struct inode *inode, struct file *file, unsigned int cmd, unsigned long arg){ unsigned int minor; int err = 0; struct hd_geometry *loc = (struct hd_geometry *) arg; mddev_t *mddev = NULL; kdev_t dev; if (!md_capable_admin()) return -EACCES; dev = inode->i_rdev; minor = MINOR(dev); if (minor >= MAX_MD_DEVS) return -EINVAL; /* * Commands dealing with the RAID driver but not any * particular array: */ switch (cmd) { case RAID_VERSION: err = get_version((void *)arg); goto done; case PRINT_RAID_DEBUG: err = 0; md_print_devices(); goto done_unlock; case BLKGETSIZE: /* Return device size */ if (!arg) { err = -EINVAL; goto abort; } err = md_put_user(md_hd_struct[minor].nr_sects, (long *) arg); goto done; case BLKFLSBUF: fsync_dev(dev); invalidate_buffers(dev); goto done; case BLKRASET: if (arg > 0xff) { err = -EINVAL; goto abort; } read_ahead[MAJOR(dev)] = arg; goto done; case BLKRAGET: if (!arg) { err = -EINVAL; goto abort; } err = md_put_user (read_ahead[ MAJOR(dev)], (long *) arg); goto done; default: } /* * Commands creating/starting a new array: */ mddev = kdev_to_mddev(dev); switch (cmd) { case SET_ARRAY_INFO: case START_ARRAY: if (mddev) { printk("array md%d already exists!\n", mdidx(mddev)); err = -EEXIST; goto abort; } default: } switch (cmd) { case SET_ARRAY_INFO: mddev = alloc_mddev(dev); if (!mddev) { err = -ENOMEM; goto abort; } atomic_inc(&mddev->active); /* * alloc_mddev() should possibly self-lock. */ err = lock_mddev(mddev); if (err) { printk("ioctl, reason %d, cmd %d\n", err, cmd); goto abort; } if (mddev->sb) { printk("array md%d already has a superblock!\n", mdidx(mddev)); err = -EBUSY; goto abort_unlock; } if (arg) { mdu_array_info_t info; if (md_copy_from_user(&info, (void*)arg, sizeof(info))) { err = -EFAULT; goto abort_unlock; } err = set_array_info(mddev, &info); if (err) { printk("couldnt set array info. %d\n", err); goto abort_unlock; } } goto done_unlock; case START_ARRAY: /* * possibly make it lock the array ... */ err = autostart_array((kdev_t)arg, dev); if (err) { printk("autostart %s failed!\n", partition_name((kdev_t)arg)); goto abort; } goto done; default: } /* * Commands querying/configuring an existing array: */ if (!mddev) { err = -ENODEV; goto abort; } err = lock_mddev(mddev); if (err) { printk("ioctl lock interrupted, reason %d, cmd %d\n",err, cmd); goto abort; } /* if we don't have a superblock yet, only ADD_NEW_DISK or STOP_ARRAY is allowed */ if (!mddev->sb && cmd != ADD_NEW_DISK && cmd != STOP_ARRAY && cmd != RUN_ARRAY) { err = -ENODEV; goto abort_unlock; } /* * Commands even a read-only array can execute: */ switch (cmd) { case GET_ARRAY_INFO: err = get_array_info(mddev, (void *)arg); goto done_unlock; case GET_DISK_INFO: err = get_disk_info(mddev, (void *)arg); goto done_unlock; case RESTART_ARRAY_RW: err = restart_array(mddev); goto done_unlock; case STOP_ARRAY: if (!(err = do_md_stop (mddev, 0))) mddev = NULL; goto done_unlock; case STOP_ARRAY_RO: err = do_md_stop (mddev, 1); goto done_unlock; /* * We have a problem here : there is no easy way to give a CHS * virtual geometry. We currently pretend that we have a 2 heads * 4 sectors (with a BIG number of cylinders...). This drives * dosfs just mad... ;-) */ case HDIO_GETGEO: if (!loc) { err = -EINVAL; goto abort_unlock; } err = md_put_user (2, (char *) &loc->heads); if (err) goto abort_unlock; err = md_put_user (4, (char *) &loc->sectors); if (err) goto abort_unlock; err = md_put_user (md_hd_struct[mdidx(mddev)].nr_sects/8, (short *) &loc->cylinders); if (err) goto abort_unlock; err = md_put_user (md_hd_struct[minor].start_sect, (long *) &loc->start); goto done_unlock; } /* * The remaining ioctls are changing the state of the * superblock, so we do not allow read-only arrays * here: */ if (mddev->ro) { err = -EROFS; goto abort_unlock; } switch (cmd) { case CLEAR_ARRAY: err = clear_array(mddev); goto done_unlock; case ADD_NEW_DISK: { mdu_disk_info_t info; if (md_copy_from_user(&info, (void*)arg, sizeof(info))) err = -EFAULT; else err = add_new_disk(mddev, &info); goto done_unlock; } case HOT_REMOVE_DISK: err = hot_remove_disk(mddev, (kdev_t)arg); goto done_unlock; case HOT_ADD_DISK: err = hot_add_disk(mddev, (kdev_t)arg); goto done_unlock; case SET_DISK_INFO: err = set_disk_info(mddev, (void *)arg); goto done_unlock; case WRITE_RAID_INFO: err = write_raid_info(mddev); goto done_unlock; case UNPROTECT_ARRAY: err = unprotect_array(mddev); goto done_unlock; case PROTECT_ARRAY: err = protect_array(mddev); goto done_unlock; case SET_DISK_FAULTY: err = set_disk_faulty(mddev, (kdev_t)arg); goto done_unlock; case RUN_ARRAY: {/* The data is never used.... mdu_param_t param; err = md_copy_from_user(¶m, (mdu_param_t *)arg, sizeof(param)); if (err) goto abort_unlock;*/ err = do_md_run (mddev); /* * we have to clean up the mess if * the array cannot be run for some * reason ... */ if (err) { mddev->sb_dirty = 0; if (!do_md_stop (mddev, 0)) mddev = NULL; } goto done_unlock; } default: printk(KERN_WARNING "%s(pid %d) used obsolete MD ioctl, upgrade your software to use new ictls.\n", current->comm, current->pid); err = -EINVAL; goto abort_unlock; }done_unlock:abort_unlock: if (mddev) unlock_mddev(mddev); return err;done: if (err) printk("huh12?\n");abort: return err;}static int md_open (struct inode *inode, struct file *file){ /* * Always succeed, but increment the usage count */ mddev_t *mddev = kdev_to_mddev(inode->i_rdev); if (mddev) atomic_inc(&mddev->active); return (0);}static int md_release (struct inode *inode, struct file * file){ mddev_t *mddev = kdev_to_mddev(inode->i_rdev); if (mddev) atomic_dec(&mddev->active); return 0;}static struct block_device_operations md_fops={ open: md_open, release: md_release, ioctl: md_ioctl,};int md_thread(void * arg){ mdk_thread_t *thread = arg; md_lock_kernel(); /* * Detach thread */ daemonize(); sprintf(current->comm, thread->name); md_init_signals(); md_flush_signals(); thread->tsk = current; /* * md_thread is a 'system-thread', it's priority should be very * high. We avoid resource deadlocks individually in each * raid personality. (RAID5 does preallocation) We also use RR and * the very same RT priority as kswapd, thus we will never get * into a priority inversion deadlock. * * we definitely have to have equal or higher priority than * bdflush, otherwise bdflush will deadlock if there are too * many dirty RAID5 blocks. */ current->policy = SCHED_OTHER; current->nice = -20;// md_unlock_kernel(); up(thread->sem); for (;;) { DECLARE_WAITQUEUE(wait, current); add_wait_queue(&thread->wqueue, &wait); set_task_state(current, TASK_INTERRUPTIBLE); if (!test_bit(THREAD_WAKEUP, &thread->flags)) { dprintk("thread %p went to sleep.\n", thread); schedule(); dprintk("thread %p woke up.\n", thread); } current->state = TASK_RUNNING; remove_wait_queue(&thread->wqueue, &wait); clear_bit(THREAD_WAKEUP, &thread->flags); if (thread->run) { thread->run(thread->data); run_task_queue(&tq_disk); } else break; if (md_signal_pending(current)) { printk("%8s(%d) flushing signals.\n", current->comm, current->pid); md_flush_signals(); } } up(thread->sem); return 0;}void md_wakeup_thread(mdk_thread_t *thread){ dprintk("waking up MD thread %p.\n", thread); set_bit(THREAD_WAKEUP, &thread->flags); wake_up(&thread->wqueue);}mdk_thread_t *md_register_thread (void (*run) (void *), void *data, const char *name){ mdk_thread_t *thread; int ret; DECLARE_MUTEX_LOCKED(sem); thread = (mdk_thread_t *) kmalloc (sizeof(mdk_thread_t), GFP_KERNEL); if (!thread) return NULL; memset(thread, 0, sizeof(mdk_thread_t)); md_init_waitqueue_head(&thread->wqueue); thread->sem = &sem; thread->run = run; thread->data = data; thread->name = name; ret = kernel_thread(md_thread, thread, 0); if (ret < 0) { kfree(thread); return NULL; } down(&sem); return thread;}void md_interrupt_thread (mdk_thread_t *thread){ if (!thread->tsk) { MD_BUG(); return; } printk("interrupting MD-thread pid %d\n", thread->tsk->pid); send_sig(SIGKILL, thread->tsk, 1);}void md_unregister_thread (mdk_thread_t *thread){ DECLARE_MUTEX_LOCKED(sem); thread->sem = &sem; thread->run = NULL; thread->name = NULL; if (!thread->tsk) { MD_BUG(); return; } md_interrupt_thread(thread); down(&sem);}void md_recover_arrays (void){ if (!md_recovery_thread) { MD_BUG(); return; } md_wakeup_thread(md_recovery_thread);}int md_error (kdev_t dev, kdev_t rdev){ mddev_t *mddev; mdk_rdev_t * rrdev; int rc; mddev = kdev_to_mddev(dev);/* printk("md_error dev:(%d:%d), rdev:(%d:%d), (caller: %p,%p,%p,%p).\n",MAJOR(dev),MINOR(dev),MAJOR(rdev),MINOR(rdev), __builtin_return_address(0),__builtin_return_address(1),__builtin_return_address(2),__builtin_return_address(3)); */ if (!mddev) { MD_BUG(); return 0; } rrdev = find_rdev(mddev, rdev); mark_rdev_faulty(rrdev); /* * if recovery was running, stop it now. */ if (mddev->pers->stop_resync) mddev->pers->stop_resync(mddev); if (mddev->recovery_running) md_interrupt_thread(md_recovery_thread); if (mddev->pers->error_handler) { rc = mddev->pers->error_handler(mddev, rdev); md_recover_arrays(); return rc; } return 0;}static int status_unused (char * page){ int sz = 0, i = 0; mdk_rdev_t *rdev; struct md_list_head *tmp; sz += sprintf(page + sz, "unused devices: "); ITERATE_RDEV_ALL(rdev,tmp) { if (!rdev->same_set.next && !rdev->same_set.prev) { /* * The device is not yet used by any array. */ i++; sz += sprintf(page + sz, "%s ", partition_name(rdev->dev)); } } if (!i) sz += sprintf(page + sz, "<none>"); sz += sprintf(page + sz, "\n"); return sz;}static int status_resync (char * page, mddev_t * mddev){ int sz = 0; unsigned long max_blocks, resync, res, dt, db, rt; resync = mddev->curr_resync - atomic_read(&mddev->recovery_active); max_blocks = mddev->sb->size; /* * Should not happen. */ if (!max_blocks) { MD_BUG(); return 0; } res = (resync/1024)*1000/(max_blocks/1024 + 1); { int i, x = res/50, y = 20-x; sz += sprintf(page + sz, "["); for (i = 0; i < x; i++) sz += sprintf(page + sz, "="); sz += sprintf(page + sz, ">"); for (i = 0; i < y; i++) sz += sprintf(page + sz, "."); sz +=
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -