diff options
author | Al Viro <viro@zeniv.linux.org.uk> | 2016-03-26 00:56:34 +0100 |
---|---|---|
committer | Mike Marshall <hubcap@omnibond.com> | 2016-03-26 12:22:00 +0100 |
commit | 45996492e5c85aa0ac93a95d1b2d1ed56851c865 (patch) | |
tree | 3ee74b07ce43cdb0b637c3747fadbb1f2ba59eb6 /fs/orangefs/super.c | |
parent | orangefs: fix do_readv_writev() handling of error halfway through (diff) | |
download | linux-45996492e5c85aa0ac93a95d1b2d1ed56851c865.tar.xz linux-45996492e5c85aa0ac93a95d1b2d1ed56851c865.zip |
orangefs: fix orangefs_superblock locking
* switch orangefs_remount() to taking ORANGEFS_SB(sb) instead of sb
* remove from the list _before_ orangefs_unmount() - request_mutex
in the latter will make sure that nothing observed in the loop in
ORANGEFS_DEV_REMOUNT_ALL handling will get freed until the end
of loop
* on removal, keep the forward pointer and zero the back one. That
way we can drop and regain the spinlock in the loop body (again,
ORANGEFS_DEV_REMOUNT_ALL one) and still be able to get to the
rest of the list.
Signed-off-by: Al Viro <viro@zeniv.linux.org.uk>
Signed-off-by: Mike Marshall <hubcap@omnibond.com>
Diffstat (limited to 'fs/orangefs/super.c')
-rw-r--r-- | fs/orangefs/super.c | 30 |
1 files changed, 23 insertions, 7 deletions
diff --git a/fs/orangefs/super.c b/fs/orangefs/super.c index 5a89b8083966..b9da9a0281c9 100644 --- a/fs/orangefs/super.c +++ b/fs/orangefs/super.c @@ -210,7 +210,7 @@ static int orangefs_remount_fs(struct super_block *sb, int *flags, char *data) * the client regains all of the mount information from us. * NOTE: this function assumes that the request_mutex is already acquired! */ -int orangefs_remount(struct super_block *sb) +int orangefs_remount(struct orangefs_sb_info_s *orangefs_sb) { struct orangefs_kernel_op_s *new_op; int ret = -EINVAL; @@ -221,7 +221,7 @@ int orangefs_remount(struct super_block *sb) if (!new_op) return -ENOMEM; strncpy(new_op->upcall.req.fs_mount.orangefs_config_server, - ORANGEFS_SB(sb)->devname, + orangefs_sb->devname, ORANGEFS_MAX_SERVER_ADDR_LEN); gossip_debug(GOSSIP_SUPER_DEBUG, @@ -244,8 +244,8 @@ int orangefs_remount(struct super_block *sb) * short-lived mapping that the system interface uses * to map this superblock to a particular mount entry */ - ORANGEFS_SB(sb)->id = new_op->downcall.resp.fs_mount.id; - ORANGEFS_SB(sb)->mount_pending = 0; + orangefs_sb->id = new_op->downcall.resp.fs_mount.id; + orangefs_sb->mount_pending = 0; } op_release(new_op); @@ -485,7 +485,12 @@ struct dentry *orangefs_mount(struct file_system_type *fst, * finally, add this sb to our list of known orangefs * sb's */ - add_orangefs_sb(sb); + gossip_debug(GOSSIP_SUPER_DEBUG, + "Adding SB %p to orangefs superblocks\n", + ORANGEFS_SB(sb)); + spin_lock(&orangefs_superblocks_lock); + list_add_tail(&ORANGEFS_SB(sb)->list, &orangefs_superblocks); + spin_unlock(&orangefs_superblocks_lock); op_release(new_op); return dget(sb->s_root); @@ -512,10 +517,21 @@ void orangefs_kill_sb(struct super_block *sb) * issue the unmount to userspace to tell it to remove the * dynamic mount info it has for this superblock */ - orangefs_unmount_sb(sb); + orangefs_unmount_sb(sb); /* remove the sb from our list of orangefs specific sb's */ - remove_orangefs_sb(sb); + + spin_lock(&orangefs_superblocks_lock); + __list_del_entry(&ORANGEFS_SB(sb)->list); /* not list_del_init */ + ORANGEFS_SB(sb)->list.prev = NULL; + spin_unlock(&orangefs_superblocks_lock); + + /* + * make sure that ORANGEFS_DEV_REMOUNT_ALL loop that might've seen us + * gets completed before we free the dang thing. + */ + mutex_lock(&request_mutex); + mutex_unlock(&request_mutex); /* free the orangefs superblock private data */ kfree(ORANGEFS_SB(sb)); |