md.c
来自「Linux Kernel 2.6.9 for OMAP1710」· C语言 代码 · 共 2,796 行 · 第 1/5 页
C
2,796 行
bdevname(rdev->bdev, b); sb = (mdp_super_t*)page_address(rdev->sb_page); if (sb->md_magic != MD_SB_MAGIC) { printk(KERN_ERR "md: invalid raid superblock magic on %s\n", b); goto abort; } if (sb->major_version != 0 || sb->minor_version != 90) { printk(KERN_WARNING "Bad version number %d.%d on %s\n", sb->major_version, sb->minor_version, b); goto abort; } if (sb->raid_disks <= 0) goto abort; if (calc_sb_csum(sb) != sb->sb_csum && calc_sb_csum_common(sb) != sb->sb_csum) { printk(KERN_WARNING "md: invalid superblock checksum on %s\n", b); goto abort; } rdev->preferred_minor = sb->md_minor; rdev->data_offset = 0; if (sb->level == MULTIPATH) rdev->desc_nr = -1; else rdev->desc_nr = sb->this_disk.number; if (refdev == 0) ret = 1; else { __u64 ev1, ev2; mdp_super_t *refsb = (mdp_super_t*)page_address(refdev->sb_page); if (!uuid_equal(refsb, sb)) { printk(KERN_WARNING "md: %s has different UUID to %s\n", b, bdevname(refdev->bdev,b2)); goto abort; } if (!sb_equal(refsb, sb)) { printk(KERN_WARNING "md: %s has same UUID" " but different superblock to %s\n", b, bdevname(refdev->bdev, b2)); goto abort; } ev1 = md_event(sb); ev2 = md_event(refsb); if (ev1 > ev2) ret = 1; else ret = 0; } rdev->size = calc_dev_size(rdev, sb->chunk_size); abort: return ret;}/* * validate_super for 0.90.0 */static int super_90_validate(mddev_t *mddev, mdk_rdev_t *rdev){ mdp_disk_t *desc; mdp_super_t *sb = (mdp_super_t *)page_address(rdev->sb_page); if (mddev->raid_disks == 0) { mddev->major_version = 0; mddev->minor_version = sb->minor_version; mddev->patch_version = sb->patch_version; mddev->persistent = ! sb->not_persistent; mddev->chunk_size = sb->chunk_size; mddev->ctime = sb->ctime; mddev->utime = sb->utime; mddev->level = sb->level; mddev->layout = sb->layout; mddev->raid_disks = sb->raid_disks; mddev->size = sb->size; mddev->events = md_event(sb); if (sb->state & (1<<MD_SB_CLEAN)) mddev->recovery_cp = MaxSector; else { if (sb->events_hi == sb->cp_events_hi && sb->events_lo == sb->cp_events_lo) { mddev->recovery_cp = sb->recovery_cp; } else mddev->recovery_cp = 0; } memcpy(mddev->uuid+0, &sb->set_uuid0, 4); memcpy(mddev->uuid+4, &sb->set_uuid1, 4); memcpy(mddev->uuid+8, &sb->set_uuid2, 4); memcpy(mddev->uuid+12,&sb->set_uuid3, 4); mddev->max_disks = MD_SB_DISKS; } else { __u64 ev1; ev1 = md_event(sb); ++ev1; if (ev1 < mddev->events) return -EINVAL; } if (mddev->level != LEVEL_MULTIPATH) { rdev->raid_disk = -1; rdev->in_sync = rdev->faulty = 0; desc = sb->disks + rdev->desc_nr; if (desc->state & (1<<MD_DISK_FAULTY)) rdev->faulty = 1; else if (desc->state & (1<<MD_DISK_SYNC) && desc->raid_disk < mddev->raid_disks) { rdev->in_sync = 1; rdev->raid_disk = desc->raid_disk; } } return 0;}/* * sync_super for 0.90.0 */static void super_90_sync(mddev_t *mddev, mdk_rdev_t *rdev){ mdp_super_t *sb; struct list_head *tmp; mdk_rdev_t *rdev2; int next_spare = mddev->raid_disks; /* make rdev->sb match mddev data.. * * 1/ zero out disks * 2/ Add info for each disk, keeping track of highest desc_nr (next_spare); * 3/ any empty disks < next_spare become removed * * disks[0] gets initialised to REMOVED because * we cannot be sure from other fields if it has * been initialised or not. */ int i; int active=0, working=0,failed=0,spare=0,nr_disks=0; sb = (mdp_super_t*)page_address(rdev->sb_page); memset(sb, 0, sizeof(*sb)); sb->md_magic = MD_SB_MAGIC; sb->major_version = mddev->major_version; sb->minor_version = mddev->minor_version; sb->patch_version = mddev->patch_version; sb->gvalid_words = 0; /* ignored */ memcpy(&sb->set_uuid0, mddev->uuid+0, 4); memcpy(&sb->set_uuid1, mddev->uuid+4, 4); memcpy(&sb->set_uuid2, mddev->uuid+8, 4); memcpy(&sb->set_uuid3, mddev->uuid+12,4); sb->ctime = mddev->ctime; sb->level = mddev->level; sb->size = mddev->size; sb->raid_disks = mddev->raid_disks; sb->md_minor = mddev->md_minor; sb->not_persistent = !mddev->persistent; sb->utime = mddev->utime; sb->state = 0; sb->events_hi = (mddev->events>>32); sb->events_lo = (u32)mddev->events; if (mddev->in_sync) { sb->recovery_cp = mddev->recovery_cp; sb->cp_events_hi = (mddev->events>>32); sb->cp_events_lo = (u32)mddev->events; if (mddev->recovery_cp == MaxSector) sb->state = (1<< MD_SB_CLEAN); } else sb->recovery_cp = 0; sb->layout = mddev->layout; sb->chunk_size = mddev->chunk_size; sb->disks[0].state = (1<<MD_DISK_REMOVED); ITERATE_RDEV(mddev,rdev2,tmp) { mdp_disk_t *d; if (rdev2->raid_disk >= 0 && rdev2->in_sync && !rdev2->faulty) rdev2->desc_nr = rdev2->raid_disk; else rdev2->desc_nr = next_spare++; d = &sb->disks[rdev2->desc_nr]; nr_disks++; d->number = rdev2->desc_nr; d->major = MAJOR(rdev2->bdev->bd_dev); d->minor = MINOR(rdev2->bdev->bd_dev); if (rdev2->raid_disk >= 0 && rdev->in_sync && !rdev2->faulty) d->raid_disk = rdev2->raid_disk; else d->raid_disk = rdev2->desc_nr; /* compatibility */ if (rdev2->faulty) { d->state = (1<<MD_DISK_FAULTY); failed++; } else if (rdev2->in_sync) { d->state = (1<<MD_DISK_ACTIVE); d->state |= (1<<MD_DISK_SYNC); active++; working++; } else { d->state = 0; spare++; working++; } } /* now set the "removed" and "faulty" bits on any missing devices */ for (i=0 ; i < mddev->raid_disks ; i++) { mdp_disk_t *d = &sb->disks[i]; if (d->state == 0 && d->number == 0) { d->number = i; d->raid_disk = i; d->state = (1<<MD_DISK_REMOVED); d->state |= (1<<MD_DISK_FAULTY); failed++; } } sb->nr_disks = nr_disks; sb->active_disks = active; sb->working_disks = working; sb->failed_disks = failed; sb->spare_disks = spare; sb->this_disk = sb->disks[rdev->desc_nr]; sb->sb_csum = calc_sb_csum(sb);}/* * version 1 superblock */static unsigned int calc_sb_1_csum(struct mdp_superblock_1 * sb){ unsigned int disk_csum, csum; unsigned long long newcsum; int size = 256 + sb->max_dev*2; unsigned int *isuper = (unsigned int*)sb; int i; disk_csum = sb->sb_csum; sb->sb_csum = 0; newcsum = 0; for (i=0; size>=4; size -= 4 ) newcsum += le32_to_cpu(*isuper++); if (size == 2) newcsum += le16_to_cpu(*(unsigned short*) isuper); csum = (newcsum & 0xffffffff) + (newcsum >> 32); sb->sb_csum = disk_csum; return csum;}static int super_1_load(mdk_rdev_t *rdev, mdk_rdev_t *refdev, int minor_version){ struct mdp_superblock_1 *sb; int ret; sector_t sb_offset; char b[BDEVNAME_SIZE], b2[BDEVNAME_SIZE]; /* * Calculate the position of the superblock. * It is always aligned to a 4K boundary and * depeding on minor_version, it can be: * 0: At least 8K, but less than 12K, from end of device * 1: At start of device * 2: 4K from start of device. */ switch(minor_version) { case 0: sb_offset = rdev->bdev->bd_inode->i_size >> 9; sb_offset -= 8*2; sb_offset &= ~(4*2); /* convert from sectors to K */ sb_offset /= 2; break; case 1: sb_offset = 0; break; case 2: sb_offset = 4; break; default: return -EINVAL; } rdev->sb_offset = sb_offset; ret = read_disk_sb(rdev); if (ret) return ret; sb = (struct mdp_superblock_1*)page_address(rdev->sb_page); if (sb->magic != cpu_to_le32(MD_SB_MAGIC) || sb->major_version != cpu_to_le32(1) || le32_to_cpu(sb->max_dev) > (4096-256)/2 || le64_to_cpu(sb->super_offset) != (rdev->sb_offset<<1) || sb->feature_map != 0) return -EINVAL; if (calc_sb_1_csum(sb) != sb->sb_csum) { printk("md: invalid superblock checksum on %s\n", bdevname(rdev->bdev,b)); return -EINVAL; } rdev->preferred_minor = 0xffff; rdev->data_offset = le64_to_cpu(sb->data_offset); if (refdev == 0) return 1; else { __u64 ev1, ev2; struct mdp_superblock_1 *refsb = (struct mdp_superblock_1*)page_address(refdev->sb_page); if (memcmp(sb->set_uuid, refsb->set_uuid, 16) != 0 || sb->level != refsb->level || sb->layout != refsb->layout || sb->chunksize != refsb->chunksize) { printk(KERN_WARNING "md: %s has strangely different" " superblock to %s\n", bdevname(rdev->bdev,b), bdevname(refdev->bdev,b2)); return -EINVAL; } ev1 = le64_to_cpu(sb->events); ev2 = le64_to_cpu(refsb->events); if (ev1 > ev2) return 1; } if (minor_version) rdev->size = ((rdev->bdev->bd_inode->i_size>>9) - le64_to_cpu(sb->data_offset)) / 2; else rdev->size = rdev->sb_offset; if (rdev->size < le64_to_cpu(sb->data_size)/2) return -EINVAL; rdev->size = le64_to_cpu(sb->data_size)/2; if (le32_to_cpu(sb->chunksize)) rdev->size &= ~((sector_t)le32_to_cpu(sb->chunksize)/2 - 1); return 0;}static int super_1_validate(mddev_t *mddev, mdk_rdev_t *rdev){ struct mdp_superblock_1 *sb = (struct mdp_superblock_1*)page_address(rdev->sb_page); if (mddev->raid_disks == 0) { mddev->major_version = 1; mddev->minor_version = 0; mddev->patch_version = 0; mddev->persistent = 1; mddev->chunk_size = le32_to_cpu(sb->chunksize) << 9; mddev->ctime = le64_to_cpu(sb->ctime) & ((1ULL << 32)-1); mddev->utime = le64_to_cpu(sb->utime) & ((1ULL << 32)-1); mddev->level = le32_to_cpu(sb->level); mddev->layout = le32_to_cpu(sb->layout); mddev->raid_disks = le32_to_cpu(sb->raid_disks); mddev->size = (u32)le64_to_cpu(sb->size); mddev->events = le64_to_cpu(sb->events); mddev->recovery_cp = le64_to_cpu(sb->resync_offset); memcpy(mddev->uuid, sb->set_uuid, 16); mddev->max_disks = (4096-256)/2; } else { __u64 ev1; ev1 = le64_to_cpu(sb->events); ++ev1; if (ev1 < mddev->events) return -EINVAL; } if (mddev->level != LEVEL_MULTIPATH) { int role; rdev->desc_nr = le32_to_cpu(sb->dev_number); role = le16_to_cpu(sb->dev_roles[rdev->desc_nr]); switch(role) { case 0xffff: /* spare */ rdev->in_sync = 0; rdev->faulty = 0; rdev->raid_disk = -1; break; case 0xfffe: /* faulty */ rdev->in_sync = 0; rdev->faulty = 1; rdev->raid_disk = -1; break; default: rdev->in_sync = 1; rdev->faulty = 0; rdev->raid_disk = role; break; } } return 0;}static void super_1_sync(mddev_t *mddev, mdk_rdev_t *rdev){ struct mdp_superblock_1 *sb; struct list_head *tmp; mdk_rdev_t *rdev2; int max_dev, i; /* make rdev->sb match mddev and rdev data. */ sb = (struct mdp_superblock_1*)page_address(rdev->sb_page); sb->feature_map = 0; sb->pad0 = 0; memset(sb->pad1, 0, sizeof(sb->pad1)); memset(sb->pad2, 0, sizeof(sb->pad2)); memset(sb->pad3, 0, sizeof(sb->pad3)); sb->utime = cpu_to_le64((__u64)mddev->utime); sb->events = cpu_to_le64(mddev->events); if (mddev->in_sync) sb->resync_offset = cpu_to_le64(mddev->recovery_cp); else sb->resync_offset = cpu_to_le64(0); max_dev = 0; ITERATE_RDEV(mddev,rdev2,tmp) if (rdev2->desc_nr > max_dev) max_dev = rdev2->desc_nr; sb->max_dev = max_dev; for (i=0; i<max_dev;i++) sb->dev_roles[max_dev] = cpu_to_le16(0xfffe); ITERATE_RDEV(mddev,rdev2,tmp) { i = rdev2->desc_nr; if (rdev2->faulty) sb->dev_roles[i] = cpu_to_le16(0xfffe); else if (rdev2->in_sync) sb->dev_roles[i] = cpu_to_le16(rdev2->raid_disk); else sb->dev_roles[i] = cpu_to_le16(0xffff); } sb->recovery_offset = cpu_to_le64(0); /* not supported yet */}struct super_type super_types[] = { [0] = { .name = "0.90.0", .owner = THIS_MODULE, .load_super = super_90_load, .validate_super = super_90_validate, .sync_super = super_90_sync, }, [1] = { .name = "md-1", .owner = THIS_MODULE, .load_super = super_1_load, .validate_super = super_1_validate, .sync_super = super_1_sync, },}; static mdk_rdev_t * match_dev_unit(mddev_t *mddev, mdk_rdev_t *dev){ struct list_head *tmp; mdk_rdev_t *rdev; ITERATE_RDEV(mddev,rdev,tmp) if (rdev->bdev->bd_contains == dev->bdev->bd_contains) return rdev; return NULL;}static int match_mddev_units(mddev_t *mddev1, mddev_t *mddev2){ struct list_head *tmp; mdk_rdev_t *rdev; ITERATE_RDEV(mddev1,rdev,tmp) if (match_dev_unit(mddev2, rdev)) return 1; return 0;}static LIST_HEAD(pending_raid_disks);static int bind_rdev_to_array(mdk_rdev_t * rdev, mddev_t * mddev){ mdk_rdev_t *same_pdev; char b[BDEVNAME_SIZE], b2[BDEVNAME_SIZE]; if (rdev->mddev) { MD_BUG(); return -EINVAL; } same_pdev = match_dev_unit(mddev, rdev); if (same_pdev) printk(KERN_WARNING "%s: WARNING: %s appears to be on the same physical" " disk as %s. True\n protection against single-disk" " failure might be compromised.\n", mdname(mddev), bdevname(rdev->bdev,b), bdevname(same_pdev->bdev,b2)); /* Verify rdev->desc_nr is unique. * If it is -1, assign a free number, else * check number is not in use */ if (rdev->desc_nr < 0) { int choice = 0; if (mddev->pers) choice = mddev->raid_disks; while (find_rdev_nr(mddev, choice)) choice++; rdev->desc_nr = choice; } else { if (find_rdev_nr(mddev, rdev->desc_nr)) return -EBUSY; } list_add(&rdev->same_set, &mddev->disks); rdev->mddev = mddev; printk(KERN_INFO "md: bind<%s>\n", bdevname(rdev->bdev,b)); return 0;}static void unbind_rdev_from_array(mdk_rdev_t * rdev){ char b[BDEVNAME_SIZE]; if (!rdev->mddev) { MD_BUG(); return; } list_del_init(&rdev->same_set); printk(KERN_INFO "md: unbind<%s>\n", bdevname(rdev->bdev,b)); rdev->mddev = NULL;}/* * prevent the device from being mounted, repartitioned or * otherwise reused by a RAID array (or any other kernel * subsystem), by bd_claiming the device. */static int lock_rdev(mdk_rdev_t *rdev, dev_t dev){ int err = 0; struct block_device *bdev; char b[BDEVNAME_SIZE];
⌨️ 快捷键说明
复制代码Ctrl + C
搜索代码Ctrl + F
全屏模式F11
增大字号Ctrl + =
减小字号Ctrl + -
显示快捷键?