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

NFS: Clean up nfs_sb_active/nfs_sb_deactive

Instead of causing umount requests to block on server->active_wq while the
asynchronous sillyrename deletes are executing, we can use the sb->s_active
counter to obtain a reference to the super_block, and then release that
reference in nfs_async_unlink_release().

Signed-off-by: Trond Myklebust <Trond.Myklebust@netapp.com>

+17 -26
-1
fs/nfs/client.c
··· 850 850 INIT_LIST_HEAD(&server->client_link); 851 851 INIT_LIST_HEAD(&server->master_link); 852 852 853 - init_waitqueue_head(&server->active_wq); 854 853 atomic_set(&server->active, 0); 855 854 856 855 server->io_stats = nfs_alloc_iostats();
+2 -2
fs/nfs/internal.h
··· 163 163 164 164 extern int __init register_nfs_fs(void); 165 165 extern void __exit unregister_nfs_fs(void); 166 - extern void nfs_sb_active(struct nfs_server *server); 167 - extern void nfs_sb_deactive(struct nfs_server *server); 166 + extern void nfs_sb_active(struct super_block *sb); 167 + extern void nfs_sb_deactive(struct super_block *sb); 168 168 169 169 /* namespace.c */ 170 170 extern char *nfs_path(const char *base,
+12 -20
fs/nfs/super.c
··· 209 209 static int nfs_xdev_get_sb(struct file_system_type *fs_type, 210 210 int flags, const char *dev_name, void *raw_data, struct vfsmount *mnt); 211 211 static void nfs_kill_super(struct super_block *); 212 - static void nfs_put_super(struct super_block *); 213 212 static int nfs_remount(struct super_block *sb, int *flags, char *raw_data); 214 213 215 214 static struct file_system_type nfs_fs_type = { ··· 231 232 .alloc_inode = nfs_alloc_inode, 232 233 .destroy_inode = nfs_destroy_inode, 233 234 .write_inode = nfs_write_inode, 234 - .put_super = nfs_put_super, 235 235 .statfs = nfs_statfs, 236 236 .clear_inode = nfs_clear_inode, 237 237 .umount_begin = nfs_umount_begin, ··· 335 337 unregister_filesystem(&nfs_fs_type); 336 338 } 337 339 338 - void nfs_sb_active(struct nfs_server *server) 339 - { 340 - atomic_inc(&server->active); 341 - } 342 - 343 - void nfs_sb_deactive(struct nfs_server *server) 344 - { 345 - if (atomic_dec_and_test(&server->active)) 346 - wake_up(&server->active_wq); 347 - } 348 - 349 - static void nfs_put_super(struct super_block *sb) 340 + void nfs_sb_active(struct super_block *sb) 350 341 { 351 342 struct nfs_server *server = NFS_SB(sb); 352 - /* 353 - * Make sure there are no outstanding ops to this server. 354 - * If so, wait for them to finish before allowing the 355 - * unmount to continue. 356 - */ 357 - wait_event(server->active_wq, atomic_read(&server->active) == 0); 343 + 344 + if (atomic_inc_return(&server->active) == 1) 345 + atomic_inc(&sb->s_active); 346 + } 347 + 348 + void nfs_sb_deactive(struct super_block *sb) 349 + { 350 + struct nfs_server *server = NFS_SB(sb); 351 + 352 + if (atomic_dec_and_test(&server->active)) 353 + deactivate_super(sb); 358 354 } 359 355 360 356 /*
+3 -2
fs/nfs/unlink.c
··· 99 99 100 100 nfs_dec_sillycount(data->dir); 101 101 nfs_free_unlinkdata(data); 102 - nfs_sb_deactive(NFS_SB(sb)); 102 + nfs_sb_deactive(sb); 103 103 } 104 104 105 105 static const struct rpc_call_ops nfs_unlink_ops = { ··· 118 118 .rpc_message = &msg, 119 119 .callback_ops = &nfs_unlink_ops, 120 120 .callback_data = data, 121 + .workqueue = nfsiod_workqueue, 121 122 .flags = RPC_TASK_ASYNC, 122 123 }; 123 124 struct rpc_task *task; ··· 150 149 nfs_dec_sillycount(dir); 151 150 return 0; 152 151 } 153 - nfs_sb_active(NFS_SERVER(dir)); 152 + nfs_sb_active(dir->i_sb); 154 153 data->args.fh = NFS_FH(dir); 155 154 nfs_fattr_init(&data->res.dir_attr); 156 155
-1
include/linux/nfs_fs_sb.h
··· 119 119 void (*destroy)(struct nfs_server *); 120 120 121 121 atomic_t active; /* Keep trace of any activity to this server */ 122 - wait_queue_head_t active_wq; /* Wait for any activity to stop */ 123 122 124 123 /* mountd-related mount options */ 125 124 struct sockaddr_storage mountd_address;