md.c
来自「linux 内核源代码」· C语言 代码 · 共 2,595 行 · 第 1/5 页
C
2,595 行
goto abort_free; } } INIT_LIST_HEAD(&rdev->same_set); return rdev;abort_free: if (rdev->sb_page) { if (rdev->bdev) unlock_rdev(rdev); free_disk_sb(rdev); } kfree(rdev); return ERR_PTR(err);}/* * Check a full RAID array for plausibility */static void analyze_sbs(mddev_t * mddev){ int i; struct list_head *tmp; mdk_rdev_t *rdev, *freshest; char b[BDEVNAME_SIZE]; freshest = NULL; ITERATE_RDEV(mddev,rdev,tmp) switch (super_types[mddev->major_version]. load_super(rdev, freshest, mddev->minor_version)) { case 1: freshest = rdev; break; case 0: break; default: printk( KERN_ERR \ "md: fatal superblock inconsistency in %s" " -- removing from array\n", bdevname(rdev->bdev,b)); kick_rdev_from_array(rdev); } super_types[mddev->major_version]. validate_super(mddev, freshest); i = 0; ITERATE_RDEV(mddev,rdev,tmp) { if (rdev != freshest) if (super_types[mddev->major_version]. validate_super(mddev, rdev)) { printk(KERN_WARNING "md: kicking non-fresh %s" " from array!\n", bdevname(rdev->bdev,b)); kick_rdev_from_array(rdev); continue; } if (mddev->level == LEVEL_MULTIPATH) { rdev->desc_nr = i++; rdev->raid_disk = rdev->desc_nr; set_bit(In_sync, &rdev->flags); } else if (rdev->raid_disk >= mddev->raid_disks) { rdev->raid_disk = -1; clear_bit(In_sync, &rdev->flags); } } if (mddev->recovery_cp != MaxSector && mddev->level >= 1) printk(KERN_ERR "md: %s: raid array is not clean" " -- starting background reconstruction\n", mdname(mddev));}static ssize_tsafe_delay_show(mddev_t *mddev, char *page){ int msec = (mddev->safemode_delay*1000)/HZ; return sprintf(page, "%d.%03d\n", msec/1000, msec%1000);}static ssize_tsafe_delay_store(mddev_t *mddev, const char *cbuf, size_t len){ int scale=1; int dot=0; int i; unsigned long msec; char buf[30]; char *e; /* remove a period, and count digits after it */ if (len >= sizeof(buf)) return -EINVAL; strlcpy(buf, cbuf, len); buf[len] = 0; for (i=0; i<len; i++) { if (dot) { if (isdigit(buf[i])) { buf[i-1] = buf[i]; scale *= 10; } buf[i] = 0; } else if (buf[i] == '.') { dot=1; buf[i] = 0; } } msec = simple_strtoul(buf, &e, 10); if (e == buf || (*e && *e != '\n')) return -EINVAL; msec = (msec * 1000) / scale; if (msec == 0) mddev->safemode_delay = 0; else { mddev->safemode_delay = (msec*HZ)/1000; if (mddev->safemode_delay == 0) mddev->safemode_delay = 1; } return len;}static struct md_sysfs_entry md_safe_delay =__ATTR(safe_mode_delay, S_IRUGO|S_IWUSR,safe_delay_show, safe_delay_store);static ssize_tlevel_show(mddev_t *mddev, char *page){ struct mdk_personality *p = mddev->pers; if (p) return sprintf(page, "%s\n", p->name); else if (mddev->clevel[0]) return sprintf(page, "%s\n", mddev->clevel); else if (mddev->level != LEVEL_NONE) return sprintf(page, "%d\n", mddev->level); else return 0;}static ssize_tlevel_store(mddev_t *mddev, const char *buf, size_t len){ int rv = len; if (mddev->pers) return -EBUSY; if (len == 0) return 0; if (len >= sizeof(mddev->clevel)) return -ENOSPC; strncpy(mddev->clevel, buf, len); if (mddev->clevel[len-1] == '\n') len--; mddev->clevel[len] = 0; mddev->level = LEVEL_NONE; return rv;}static struct md_sysfs_entry md_level =__ATTR(level, S_IRUGO|S_IWUSR, level_show, level_store);static ssize_tlayout_show(mddev_t *mddev, char *page){ /* just a number, not meaningful for all levels */ if (mddev->reshape_position != MaxSector && mddev->layout != mddev->new_layout) return sprintf(page, "%d (%d)\n", mddev->new_layout, mddev->layout); return sprintf(page, "%d\n", mddev->layout);}static ssize_tlayout_store(mddev_t *mddev, const char *buf, size_t len){ char *e; unsigned long n = simple_strtoul(buf, &e, 10); if (!*buf || (*e && *e != '\n')) return -EINVAL; if (mddev->pers) return -EBUSY; if (mddev->reshape_position != MaxSector) mddev->new_layout = n; else mddev->layout = n; return len;}static struct md_sysfs_entry md_layout =__ATTR(layout, S_IRUGO|S_IWUSR, layout_show, layout_store);static ssize_traid_disks_show(mddev_t *mddev, char *page){ if (mddev->raid_disks == 0) return 0; if (mddev->reshape_position != MaxSector && mddev->delta_disks != 0) return sprintf(page, "%d (%d)\n", mddev->raid_disks, mddev->raid_disks - mddev->delta_disks); return sprintf(page, "%d\n", mddev->raid_disks);}static int update_raid_disks(mddev_t *mddev, int raid_disks);static ssize_traid_disks_store(mddev_t *mddev, const char *buf, size_t len){ char *e; int rv = 0; unsigned long n = simple_strtoul(buf, &e, 10); if (!*buf || (*e && *e != '\n')) return -EINVAL; if (mddev->pers) rv = update_raid_disks(mddev, n); else if (mddev->reshape_position != MaxSector) { int olddisks = mddev->raid_disks - mddev->delta_disks; mddev->delta_disks = n - olddisks; mddev->raid_disks = n; } else mddev->raid_disks = n; return rv ? rv : len;}static struct md_sysfs_entry md_raid_disks =__ATTR(raid_disks, S_IRUGO|S_IWUSR, raid_disks_show, raid_disks_store);static ssize_tchunk_size_show(mddev_t *mddev, char *page){ if (mddev->reshape_position != MaxSector && mddev->chunk_size != mddev->new_chunk) return sprintf(page, "%d (%d)\n", mddev->new_chunk, mddev->chunk_size); return sprintf(page, "%d\n", mddev->chunk_size);}static ssize_tchunk_size_store(mddev_t *mddev, const char *buf, size_t len){ /* can only set chunk_size if array is not yet active */ char *e; unsigned long n = simple_strtoul(buf, &e, 10); if (!*buf || (*e && *e != '\n')) return -EINVAL; if (mddev->pers) return -EBUSY; else if (mddev->reshape_position != MaxSector) mddev->new_chunk = n; else mddev->chunk_size = n; return len;}static struct md_sysfs_entry md_chunk_size =__ATTR(chunk_size, S_IRUGO|S_IWUSR, chunk_size_show, chunk_size_store);static ssize_tresync_start_show(mddev_t *mddev, char *page){ return sprintf(page, "%llu\n", (unsigned long long)mddev->recovery_cp);}static ssize_tresync_start_store(mddev_t *mddev, const char *buf, size_t len){ /* can only set chunk_size if array is not yet active */ char *e; unsigned long long n = simple_strtoull(buf, &e, 10); if (mddev->pers) return -EBUSY; if (!*buf || (*e && *e != '\n')) return -EINVAL; mddev->recovery_cp = n; return len;}static struct md_sysfs_entry md_resync_start =__ATTR(resync_start, S_IRUGO|S_IWUSR, resync_start_show, resync_start_store);/* * The array state can be: * * clear * No devices, no size, no level * Equivalent to STOP_ARRAY ioctl * inactive * May have some settings, but array is not active * all IO results in error * When written, doesn't tear down array, but just stops it * suspended (not supported yet) * All IO requests will block. The array can be reconfigured. * Writing this, if accepted, will block until array is quiessent * readonly * no resync can happen. no superblocks get written. * write requests fail * read-auto * like readonly, but behaves like 'clean' on a write request. * * clean - no pending writes, but otherwise active. * When written to inactive array, starts without resync * If a write request arrives then * if metadata is known, mark 'dirty' and switch to 'active'. * if not known, block and switch to write-pending * If written to an active array that has pending writes, then fails. * active * fully active: IO and resync can be happening. * When written to inactive array, starts with resync * * write-pending * clean, but writes are blocked waiting for 'active' to be written. * * active-idle * like active, but no writes have been seen for a while (100msec). * */enum array_state { clear, inactive, suspended, readonly, read_auto, clean, active, write_pending, active_idle, bad_word};static char *array_states[] = { "clear", "inactive", "suspended", "readonly", "read-auto", "clean", "active", "write-pending", "active-idle", NULL };static int match_word(const char *word, char **list){ int n; for (n=0; list[n]; n++) if (cmd_match(word, list[n])) break; return n;}static ssize_tarray_state_show(mddev_t *mddev, char *page){ enum array_state st = inactive; if (mddev->pers) switch(mddev->ro) { case 1: st = readonly; break; case 2: st = read_auto; break; case 0: if (mddev->in_sync) st = clean; else if (mddev->safemode) st = active_idle; else st = active; } else { if (list_empty(&mddev->disks) && mddev->raid_disks == 0 && mddev->size == 0) st = clear; else st = inactive; } return sprintf(page, "%s\n", array_states[st]);}static int do_md_stop(mddev_t * mddev, int ro);static int do_md_run(mddev_t * mddev);static int restart_array(mddev_t *mddev);static ssize_tarray_state_store(mddev_t *mddev, const char *buf, size_t len){ int err = -EINVAL; enum array_state st = match_word(buf, array_states); switch(st) { case bad_word: break; case clear: /* stopping an active array */ if (mddev->pers) { if (atomic_read(&mddev->active) > 1) return -EBUSY; err = do_md_stop(mddev, 0); } break; case inactive: /* stopping an active array */ if (mddev->pers) { if (atomic_read(&mddev->active) > 1) return -EBUSY; err = do_md_stop(mddev, 2); } break; case suspended: break; /* not supported yet */ case readonly: if (mddev->pers) err = do_md_stop(mddev, 1); else { mddev->ro = 1; err = do_md_run(mddev); } break; case read_auto: /* stopping an active array */ if (mddev->pers) { err = do_md_stop(mddev, 1); if (err == 0) mddev->ro = 2; /* FIXME mark devices writable */ } else { mddev->ro = 2; err = do_md_run(mddev); } break; case clean: if (mddev->pers) { restart_array(mddev); spin_lock_irq(&mddev->write_lock); if (atomic_read(&mddev->writes_pending) == 0) { mddev->in_sync = 1; set_bit(MD_CHANGE_CLEAN, &mddev->flags); } spin_unlock_irq(&mddev->write_lock); } else { mddev->ro = 0; mddev->recovery_cp = MaxSector; err = do_md_run(mddev); } break; case active: if (mddev->pers) { restart_array(mddev); clear_bit(MD_CHANGE_CLEAN, &mddev->flags); wake_up(&mddev->sb_wait); err = 0; } else { mddev->ro = 0; err = do_md_run(mddev); } break; case write_pending: case active_idle: /* these cannot be set */ break; } if (err) return err; else return len;}static struct md_sysfs_entry md_array_state =__ATTR(array_state, S_IRUGO|S_IWUSR, array_state_show, array_state_store);static ssize_tnull_show(mddev_t *mddev, char *page){ return -EINVAL;}static ssize_tnew_dev_store(mddev_t *mddev, const char *buf, size_t len){ /* buf must be %d:%d\n? giving major and minor numbers */ /* The new device is added to the array. * If the array has a persistent superblock, we read the * superblock to initialise info and check validity. * Otherwise, only checking done is that in bind_rdev_to_array, * which mainly checks size. */ char *e; int major = simple_strtoul(buf, &e, 10); int minor; dev_t dev; mdk_rdev_t *rdev; int err; if (!*buf || *e != ':' || !e[1] || e[1] == '\n') return -EINVAL; minor = simple_strtoul(e+1, &e, 10); if (*e && *e != '\n') return -EINVAL; dev = MKDEV(major, minor); if (major != MAJOR(dev) || minor != MINOR(dev)) return -EOVERFLOW; if (mddev->persistent) { rdev = md_import_device(dev, mddev->major_version, mddev->minor_version); if (!IS_ERR(rdev) && !list_empty(&mddev->disks)) { mdk_rdev_t *rdev0 = list_entry(mddev->disks.next, mdk_rdev_t, same_set); err = super_types[mddev->major_version] .load_super(rdev, rdev0, mddev->minor_version); if (err < 0) goto out; } } else rdev = md_import_device(dev, -1, -1); if (IS_ERR(rdev)) return PTR_ERR(rdev); err = bind_rdev_to_array(rdev, mddev); out: if (err) export_rdev(rdev); return err ? err : len;}static struct md_sysfs_entry md_new_device =__ATTR(new_dev, S_IWUSR, null
⌨️ 快捷键说明
复制代码Ctrl + C
搜索代码Ctrl + F
全屏模式F11
增大字号Ctrl + =
减小字号Ctrl + -
显示快捷键?