Linux kernel mirror (for testing) git.kernel.org/pub/scm/linux/kernel/git/torvalds/linux.git
kernel os linux

md/bitmap: don't abuse i_writecount for bitmap files.

md bitmap code currently tries to use i_writecount to stop any other
process from writing to out bitmap file. But that is really an abuse
and has bit-rotted so locking is all wrong.

So discard that - root should be allowed to shoot self in foot.

Still use it in a much less intrusive way to stop the same file being
used as bitmap on two different array, and apply other checks to
ensure the file is at least vaguely usable for bitmap storage
(is regular, is open for write. Support for ->bmap is already checked
elsewhere).

Reported-by: Al Viro <viro@ZenIV.linux.org.uk>
Signed-off-by: NeilBrown <neilb@suse.de>

NeilBrown 035328c2 455c6fdb

+16 -35
-1
drivers/md/bitmap.c
··· 1988 1988 if (mddev->bitmap_info.file) { 1989 1989 struct file *f = mddev->bitmap_info.file; 1990 1990 mddev->bitmap_info.file = NULL; 1991 - restore_bitmap_write_access(f); 1992 1991 fput(f); 1993 1992 } 1994 1993 } else {
+16 -33
drivers/md/md.c
··· 5181 5181 return 0; 5182 5182 } 5183 5183 5184 - /* similar to deny_write_access, but accounts for our holding a reference 5185 - * to the file ourselves */ 5186 - static int deny_bitmap_write_access(struct file * file) 5187 - { 5188 - struct inode *inode = file->f_mapping->host; 5189 - 5190 - spin_lock(&inode->i_lock); 5191 - if (atomic_read(&inode->i_writecount) > 1) { 5192 - spin_unlock(&inode->i_lock); 5193 - return -ETXTBSY; 5194 - } 5195 - atomic_set(&inode->i_writecount, -1); 5196 - spin_unlock(&inode->i_lock); 5197 - 5198 - return 0; 5199 - } 5200 - 5201 - void restore_bitmap_write_access(struct file *file) 5202 - { 5203 - struct inode *inode = file->f_mapping->host; 5204 - 5205 - spin_lock(&inode->i_lock); 5206 - atomic_set(&inode->i_writecount, 1); 5207 - spin_unlock(&inode->i_lock); 5208 - } 5209 - 5210 5184 static void md_clean(struct mddev *mddev) 5211 5185 { 5212 5186 mddev->array_sectors = 0; ··· 5401 5427 5402 5428 bitmap_destroy(mddev); 5403 5429 if (mddev->bitmap_info.file) { 5404 - restore_bitmap_write_access(mddev->bitmap_info.file); 5405 5430 fput(mddev->bitmap_info.file); 5406 5431 mddev->bitmap_info.file = NULL; 5407 5432 } ··· 5952 5979 5953 5980 static int set_bitmap_file(struct mddev *mddev, int fd) 5954 5981 { 5955 - int err; 5982 + int err = 0; 5956 5983 5957 5984 if (mddev->pers) { 5958 5985 if (!mddev->pers->quiesce) ··· 5964 5991 5965 5992 5966 5993 if (fd >= 0) { 5994 + struct inode *inode; 5967 5995 if (mddev->bitmap) 5968 5996 return -EEXIST; /* cannot add when bitmap is present */ 5969 5997 mddev->bitmap_info.file = fget(fd); ··· 5975 6001 return -EBADF; 5976 6002 } 5977 6003 5978 - err = deny_bitmap_write_access(mddev->bitmap_info.file); 5979 - if (err) { 6004 + inode = mddev->bitmap_info.file->f_mapping->host; 6005 + if (!S_ISREG(inode->i_mode)) { 6006 + printk(KERN_ERR "%s: error: bitmap file must be a regular file\n", 6007 + mdname(mddev)); 6008 + err = -EBADF; 6009 + } else if (!(mddev->bitmap_info.file->f_mode & FMODE_WRITE)) { 6010 + printk(KERN_ERR "%s: error: bitmap file must open for write\n", 6011 + mdname(mddev)); 6012 + err = -EBADF; 6013 + } else if (atomic_read(&inode->i_writecount) != 1) { 5980 6014 printk(KERN_ERR "%s: error: bitmap file is already in use\n", 5981 6015 mdname(mddev)); 6016 + err = -EBUSY; 6017 + } 6018 + if (err) { 5982 6019 fput(mddev->bitmap_info.file); 5983 6020 mddev->bitmap_info.file = NULL; 5984 6021 return err; ··· 6012 6027 mddev->pers->quiesce(mddev, 0); 6013 6028 } 6014 6029 if (fd < 0) { 6015 - if (mddev->bitmap_info.file) { 6016 - restore_bitmap_write_access(mddev->bitmap_info.file); 6030 + if (mddev->bitmap_info.file) 6017 6031 fput(mddev->bitmap_info.file); 6018 - } 6019 6032 mddev->bitmap_info.file = NULL; 6020 6033 } 6021 6034
-1
drivers/md/md.h
··· 605 605 extern int md_integrity_register(struct mddev *mddev); 606 606 extern void md_integrity_add_rdev(struct md_rdev *rdev, struct mddev *mddev); 607 607 extern int strict_strtoul_scaled(const char *cp, unsigned long *res, int scale); 608 - extern void restore_bitmap_write_access(struct file *file); 609 608 610 609 extern void mddev_init(struct mddev *mddev); 611 610 extern int md_run(struct mddev *mddev);