commit 6b9cad8b3caae993763b413e85d9e646cc81c163 Author: Steve Dickson Date: Wed Nov 7 12:12:54 2007 -0500 Added an active/deactive mechanism to the nfs_server structure allowing async operations to hold off umount until the operations are done. Signed-off-by: Steve Dickson diff --git a/fs/nfs/client.c b/fs/nfs/client.c index 70587f3..774283d 100644 --- a/fs/nfs/client.c +++ b/fs/nfs/client.c @@ -593,6 +593,10 @@ static int nfs_init_server(struct nfs_server *server, server->namelen = data->namlen; /* Create a client RPC handle for the NFSv3 ACL management interface */ nfs_init_server_aclclient(server); + + init_waitqueue_head(&server->active_wq); + atomic_set(&server->active, 1); + dprintk("<-- nfs_init_server() = 0 [new %p]\n", clp); return 0; diff --git a/fs/nfs/super.c b/fs/nfs/super.c index fa517ae..690e485 100644 --- a/fs/nfs/super.c +++ b/fs/nfs/super.c @@ -202,6 +202,7 @@ static int nfs_get_sb(struct file_system_type *, int, const char *, void *, stru static int nfs_xdev_get_sb(struct file_system_type *fs_type, int flags, const char *dev_name, void *raw_data, struct vfsmount *mnt); static void nfs_kill_super(struct super_block *); +static void nfs_put_super(struct super_block *); static struct file_system_type nfs_fs_type = { .owner = THIS_MODULE, @@ -223,6 +224,7 @@ static const struct super_operations nfs_sops = { .alloc_inode = nfs_alloc_inode, .destroy_inode = nfs_destroy_inode, .write_inode = nfs_write_inode, + .put_super = nfs_put_super, .statfs = nfs_statfs, .clear_inode = nfs_clear_inode, .umount_begin = nfs_umount_begin, @@ -1767,6 +1769,20 @@ static void nfs4_kill_super(struct super_block *sb) nfs_free_server(server); } +void nfs_put_super(struct super_block *sb) +{ + struct nfs_server *server = NFS_SB(sb); + /* + * Make sure there are no outstanding ops to this server. + * If so, wait for them to finish before allowing the + * unmount to continue. + */ + if (atomic_read(&server->active) > 1) { + wait_event(server->active_wq, + atomic_read(&server->active) == 1); + } +} + /* * Clone an NFS4 server record on xdev traversal (FSID-change) */ diff --git a/fs/nfs/unlink.c b/fs/nfs/unlink.c index 233ad38..cf12a24 100644 --- a/fs/nfs/unlink.c +++ b/fs/nfs/unlink.c @@ -29,6 +29,7 @@ struct nfs_unlinkdata { static void nfs_free_unlinkdata(struct nfs_unlinkdata *data) { + nfs_sb_deactive(NFS_SERVER(data->dir)); iput(data->dir); put_rpccred(data->cred); kfree(data->args.name.name); @@ -151,6 +152,7 @@ static int nfs_do_call_unlink(struct dentry *parent, struct inode *dir, struct n nfs_dec_sillycount(dir); return 0; } + nfs_sb_active(NFS_SERVER(dir)); data->args.fh = NFS_FH(dir); nfs_fattr_init(&data->res.dir_attr); diff --git a/include/linux/nfs_fs_sb.h b/include/linux/nfs_fs_sb.h index 0cac49b..70a991b 100644 --- a/include/linux/nfs_fs_sb.h +++ b/include/linux/nfs_fs_sb.h @@ -4,6 +4,8 @@ #include #include +#include + struct nfs_iostats; /* @@ -110,8 +112,23 @@ struct nfs_server { filesystem */ #endif void (*destroy)(struct nfs_server *); + + atomic_t active; /* Keep trace of any activity to this server */ + wait_queue_head_t active_wq; /* Wait for any activity to stop */ }; +static inline void +nfs_sb_active(struct nfs_server *server) +{ + atomic_inc(&server->active); +} +static inline void +nfs_sb_deactive(struct nfs_server *server) +{ + if (atomic_dec_return(&server->active) == 1) + wake_up(&server->active_wq); +} + /* Server capabilities */ #define NFS_CAP_READDIRPLUS (1U << 0) #define NFS_CAP_HARDLINKS (1U << 1)