this is a first attempt at fixing up branching race conditions in unionfs, it's by no means complete.
1) It introduce a rw semaphore. The semantic is, that "write" is an operation that can change the branching structure. while "read" is operations that depend on the branching structure not changing. 2) I've removed the use of lock_super() in place of read/write locks as that would possibly kill performance due to being unable to run multiple branchput/gets at once and forcing a process to sleep. I haven't touched all the places that matter, just putting this out for discussion. my read_lock/unlock's around branchput in commonfops.c should probably be made much wider, but again this is just for proof of concept.
diff -ru unionfs-20050929-0844.bak/branchman.c unionfs-20050929-0844/branchman.c --- unionfs-20050929-0844.bak/branchman.c 2005-10-16 03:07:39.000000000 -0400 +++ unionfs-20050929-0844/branchman.c 2005-10-16 03:19:59.000000000 -0400 @@ -159,7 +159,7 @@ sb = file->f_dentry->d_sb; - lock_super(sb); + unionfs_write_lock(sb); if ((err = newputmap(sb))) goto out; @@ -170,7 +170,7 @@ atomic_set(&itopd(sb->s_root->d_inode)->uii_generation, err); out: - unlock_super(sb); + unionfs_write_unlock(sb); print_exit_status(err); return err; } @@ -232,7 +232,7 @@ goto out; } - lock_super(inode->i_sb); + unionfs_write_lock(inode->i_sb); lock_dentry(inode->i_sb->s_root); err = -EINVAL; @@ -372,7 +372,7 @@ out: unlock_dentry(inode->i_sb->s_root); - unlock_super(inode->i_sb); + unionfs_write_unlock(inode->i_sb); KFREE(new_hidden_mnt); KFREE(new_udi_dentry); @@ -483,7 +483,7 @@ print_entry_location(); - lock_super(inode->i_sb); + unionfs_write_lock(inode->i_sb); lock_dentry(inode->i_sb->s_root); if ((err = newputmap(inode->i_sb))) @@ -518,8 +518,8 @@ err = 0; out: - unlock_super(inode->i_sb); unlock_dentry(inode->i_sb->s_root); + unionfs_write_unlock(inode->i_sb); KFREE(rdwrargs); print_exit_status(err); diff -ru unionfs-20050929-0844.bak/commonfops.c unionfs-20050929-0844/commonfops.c --- unionfs-20050929-0844.bak/commonfops.c 2005-10-16 03:07:39.000000000 -0400 +++ unionfs-20050929-0844/commonfops.c 2005-10-16 03:16:35.000000000 -0400 @@ -28,9 +28,11 @@ { struct putmap *putmap; + unionfs_read_lock(sb); + if (generation == atomic_read(&stopd(sb)->usi_generation)) { branchput(sb, index); - return; + goto out; } ASSERT(stopd(sb)->usi_firstputmap <= generation); @@ -49,6 +51,9 @@ fist_dprint(8, "Freeing putmap %d.\n", generation); KFREE(putmap); } + +out: + unionfs_read_unlock(sb); } char *get_random_name(int size, unsigned char *name) @@ -344,7 +349,9 @@ bend = fbend(file); for (bindex = bstart; bindex <= bend; bindex++) { if (ftohf_index(file, bindex)) { + unionfs_read_lock(dentry->d_sb); branchput(dentry->d_sb, bindex); + unionfs_read_unlock(dentry->d_sb); fput(ftohf_index(file, bindex)); set_ftohf_index(file, bindex, NULL); } @@ -490,7 +497,9 @@ for (bindex = bstart; bindex <= bend; bindex++) { hidden_file = ftohf_index(file, bindex); if (hidden_file) { + unionfs_read_lock(file->f_dentry->d_sb); branchput(file->f_dentry->d_sb, bindex); + unionfs_read_unlock(file->f_dentry->d_sb); /* fput calls dput for hidden_dentry */ fput(hidden_file); } diff -ru unionfs-20050929-0844.bak/dentry.c unionfs-20050929-0844/dentry.c --- unionfs-20050929-0844.bak/dentry.c 2005-10-16 03:07:39.000000000 -0400 +++ unionfs-20050929-0844/dentry.c 2005-10-16 03:21:24.000000000 -0400 @@ -62,7 +62,7 @@ struct dentry *result; int pdgen; - lock_super(dentry->d_sb); + unionfs_read_lock(dentry->d_sb); locked = 1; /* The root entry should always be valid */ @@ -74,7 +74,7 @@ if (!restart && (pdgen != sbgen)) { PASSERT(dentry->d_parent->d_op); PASSERT(dentry->d_parent->d_op->d_revalidate); - unlock_super(dentry->d_sb); + unionfs_read_unlock(dentry->d_sb); locked = 0; /* We must be locked before our parent. */ lock_dentry(dentry->d_parent); @@ -172,7 +172,7 @@ out: if (locked) - unlock_super(dentry->d_sb); + unionfs_read_unlock(dentry->d_sb); if (invalid) err = 0; fist_print_dentry("revalidate out", dentry); diff -ru unionfs-20050929-0844.bak/main.c unionfs-20050929-0844/main.c --- unionfs-20050929-0844.bak/main.c 2005-10-16 03:07:39.000000000 -0400 +++ unionfs-20050929-0844/main.c 2005-10-16 03:17:11.000000000 -0400 @@ -740,6 +740,7 @@ memset(stopd(sb), 0, sizeof(struct unionfs_sb_info)); stopd(sb)->b_end = -1; atomic_set(&stopd(sb)->usi_generation, 1); + init_rwsem(&stopd(sb)->usi_rwsem); hidden_root_info = unionfs_parse_options(sb, raw_data); if (IS_ERR(hidden_root_info)) { diff -ru unionfs-20050929-0844.bak/unionfs.h unionfs-20050929-0844/unionfs.h --- unionfs-20050929-0844.bak/unionfs.h 2005-10-16 03:07:39.000000000 -0400 +++ unionfs-20050929-0844/unionfs.h 2005-10-16 03:15:09.000000000 -0400 @@ -127,6 +127,7 @@ atomic_t usi_generation; unsigned long usi_mount_flag; + struct rw_semaphore usi_rwsem; int usi_persistent; @@ -261,6 +262,11 @@ #define stohiddenmnt_ptr(super) (stopd(super)->usi_hidden_mnt_p) #define stohiddenmnt_inline(super) (stopd(super)->usi_hidden_mnt_i) +#define unionfs_read_lock(sb) down_read(&stopd(sb)->usi_rwsem) +#define unionfs_read_unlock(sb) up_read(&stopd(sb)->usi_rwsem) +#define unionfs_write_lock(sb) down_write(&stopd(sb)->usi_rwsem) +#define unionfs_write_unlock(sb) up_write(&stopd(sb)->usi_rwsem) + /* The UNIONFS_NDEBUG versions are defines, the debug versions are inline * functions with extra checks. */ #ifdef UNIONFS_NDEBUG
_______________________________________________ unionfs mailing list unionfs@mail.fsl.cs.sunysb.edu http://www.fsl.cs.sunysb.edu/mailman/listinfo/unionfs