📄 md.c
字号:
if (!rdev) { MD_BUG(); return -EINVAL; } if (rdev->faulty) { printk(KERN_WARNING "md: can not hot-add faulty %s disk to md%d!\n", partition_name(dev), mdidx(mddev)); err = -EINVAL; goto abort_export; } bind_rdev_to_array(rdev, mddev); /* * The rest should better be atomic, we can have disk failures * noticed in interrupt contexts ... */ rdev->old_dev = dev; rdev->size = size; rdev->sb_offset = calc_dev_sboffset(dev, mddev, persistent); disk = mddev->sb->disks + mddev->sb->raid_disks; for (i = mddev->sb->raid_disks; i < MD_SB_DISKS; i++) { disk = mddev->sb->disks + i; if (!disk->major && !disk->minor) break; if (disk_removed(disk)) break; } if (i == MD_SB_DISKS) { printk(KERN_WARNING "md%d: can not hot-add to full array!\n", mdidx(mddev)); err = -EBUSY; goto abort_unbind_export; } if (disk_removed(disk)) { /* * reuse slot */ if (disk->number != i) { MD_BUG(); err = -EINVAL; goto abort_unbind_export; } } else { disk->number = i; } disk->raid_disk = disk->number; disk->major = MAJOR(dev); disk->minor = MINOR(dev); if (mddev->pers->diskop(mddev, &disk, DISKOP_HOT_ADD_DISK)) { MD_BUG(); err = -EINVAL; goto abort_unbind_export; } mark_disk_spare(disk); mddev->sb->nr_disks++; mddev->sb->spare_disks++; mddev->sb->working_disks++; mddev->sb_dirty = 1; md_update_sb(mddev); /* * Kick recovery, maybe this spare has to be added to the * array immediately. */ md_recover_arrays(); return 0;abort_unbind_export: unbind_rdev_from_array(rdev);abort_export: export_rdev(rdev); return err;}#define SET_SB(x) mddev->sb->x = info->xstatic int set_array_info(mddev_t * mddev, mdu_array_info_t *info){ if (alloc_array_sb(mddev)) return -ENOMEM; mddev->sb->major_version = MD_MAJOR_VERSION; mddev->sb->minor_version = MD_MINOR_VERSION; mddev->sb->patch_version = MD_PATCHLEVEL_VERSION; mddev->sb->ctime = CURRENT_TIME; SET_SB(level); 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(KERN_INFO "md: not yet"); return -EINVAL;}static int clear_array(mddev_t * mddev){ printk(KERN_INFO "md: not yet"); return -EINVAL;}static int write_raid_info(mddev_t * mddev){ printk(KERN_INFO "md: not yet"); return -EINVAL;}static int protect_array(mddev_t * mddev){ printk(KERN_INFO "md: not yet"); return -EINVAL;}static int unprotect_array(mddev_t * mddev){ printk(KERN_INFO "md: not yet"); return -EINVAL;}static int set_disk_faulty(mddev_t *mddev, kdev_t dev){ int ret; ret = md_error(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) { MD_BUG(); 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;#ifndef MODULE case RAID_AUTORUN: err = 0; autostart_arrays(); goto done;#endif case BLKGETSIZE: /* Return device size */ if (!arg) { err = -EINVAL; MD_BUG(); goto abort; } err = md_put_user(md_hd_struct[minor].nr_sects, (unsigned long *) arg); goto done; case BLKGETSIZE64: /* Return device size */ err = md_put_user((u64)md_hd_struct[minor].nr_sects << 9, (u64 *) arg); goto done; case BLKRAGET: case BLKRASET: case BLKFLSBUF: case BLKBSZGET: case BLKBSZSET: err = blk_ioctl (dev, cmd, arg); goto abort; default:; } /* * Commands creating/starting a new array: */ mddev = kdev_to_mddev(dev); switch (cmd) { case SET_ARRAY_INFO: case START_ARRAY: if (mddev) { printk(KERN_WARNING "md: 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(KERN_WARNING "md: ioctl, reason %d, cmd %d\n", err, cmd); goto abort; } if (mddev->sb) { printk(KERN_WARNING "md: 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(KERN_WARNING "md: 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(KERN_WARNING "md: 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(KERN_INFO "md: 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_GENERATE_ERROR: err = hot_generate_error(mddev, (kdev_t)arg); 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 "md: %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) MD_BUG();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={ owner: THIS_MODULE, 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(); complete(thread->event); while (thread->run) { void (*run)(void *data); DECLARE_WAITQUEUE(wait, current); add_wait_queue(&thread->wqueue, &wait); set_task_state(current, TASK_INTERRUPTIBLE); if (!test_bit(THREAD_WAKEUP, &thread->flags)) { dprintk("md: thread %p went to sleep.\n", thread); schedule(); dprintk("md: thread %p woke up.\n", thread); } current->state = TASK_RUNNING; remove_wait_queue(&thread->wqueue, &wait); clear_bit(THREAD_WAKEUP, &thread->flags); run = thread->run; if (run) { run(thread->data); run_task_queue(&tq_disk); } if (md_signal_pending(current)) md_flush_signals(); } complete(thread->event); return 0;}void md_wakeup_thread(mdk_thread_t *thread){ dprintk("md: 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; struct completion event; 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); init_completion(&event); thread->event = &event; thread->run = run; thread->data = data; thread->name = name; ret = kernel_thread(md_thread, thread, 0); if (ret < 0) { kfree(thread); return NULL; } wait_for_completion(&event); return thread;}void md_interrupt_thread(mdk_thread_t *thread){ if (!thread->tsk) { MD_BUG()
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -