diff options
Diffstat (limited to 'fs/nfs')
| -rw-r--r-- | fs/nfs/callback.c | 2 | ||||
| -rw-r--r-- | fs/nfs/dns_resolve.c | 5 | ||||
| -rw-r--r-- | fs/nfs/inode.c | 5 | ||||
| -rw-r--r-- | fs/nfs/internal.h | 6 | ||||
| -rw-r--r-- | fs/nfs/mount_clnt.c | 2 | ||||
| -rw-r--r-- | fs/nfs/namespace.c | 19 | ||||
| -rw-r--r-- | fs/nfs/nfs4filelayout.c | 21 | ||||
| -rw-r--r-- | fs/nfs/nfs4filelayout.h | 1 | ||||
| -rw-r--r-- | fs/nfs/nfs4filelayoutdev.c | 22 | ||||
| -rw-r--r-- | fs/nfs/nfs4getroot.c | 1 | ||||
| -rw-r--r-- | fs/nfs/nfs4namespace.c | 3 | ||||
| -rw-r--r-- | fs/nfs/nfs4proc.c | 46 | ||||
| -rw-r--r-- | fs/nfs/objlayout/objio_osd.c | 6 | ||||
| -rw-r--r-- | fs/nfs/pnfs.c | 4 | ||||
| -rw-r--r-- | fs/nfs/pnfs.h | 1 | ||||
| -rw-r--r-- | fs/nfs/super.c | 51 | ||||
| -rw-r--r-- | fs/nfs/unlink.c | 2 | 
17 files changed, 131 insertions, 66 deletions
diff --git a/fs/nfs/callback.c b/fs/nfs/callback.c index 9a521fb3986..5088b57b078 100644 --- a/fs/nfs/callback.c +++ b/fs/nfs/callback.c @@ -241,7 +241,7 @@ static int nfs_callback_start_svc(int minorversion, struct rpc_xprt *xprt,  		svc_exit_thread(cb_info->rqst);  		cb_info->rqst = NULL;  		cb_info->task = NULL; -		return PTR_ERR(cb_info->task); +		return ret;  	}  	dprintk("nfs_callback_up: service started\n");  	return 0; diff --git a/fs/nfs/dns_resolve.c b/fs/nfs/dns_resolve.c index 31c26c4dcc2..ca4b11ec87a 100644 --- a/fs/nfs/dns_resolve.c +++ b/fs/nfs/dns_resolve.c @@ -217,7 +217,7 @@ static int nfs_dns_parse(struct cache_detail *cd, char *buf, int buflen)  {  	char buf1[NFS_DNS_HOSTNAME_MAXLEN+1];  	struct nfs_dns_ent key, *item; -	unsigned long ttl; +	unsigned int ttl;  	ssize_t len;  	int ret = -EINVAL; @@ -240,7 +240,8 @@ static int nfs_dns_parse(struct cache_detail *cd, char *buf, int buflen)  	key.namelen = len;  	memset(&key.h, 0, sizeof(key.h)); -	ttl = get_expiry(&buf); +	if (get_uint(&buf, &ttl) < 0) +		goto out;  	if (ttl == 0)  		goto out;  	key.h.expiry_time = ttl + seconds_since_boot(); diff --git a/fs/nfs/inode.c b/fs/nfs/inode.c index 5c7325c5c5e..6fa01aea248 100644 --- a/fs/nfs/inode.c +++ b/fs/nfs/inode.c @@ -685,7 +685,10 @@ static void __put_nfs_open_context(struct nfs_open_context *ctx, int is_sync)  	if (ctx->cred != NULL)  		put_rpccred(ctx->cred);  	dput(ctx->dentry); -	nfs_sb_deactive(sb); +	if (is_sync) +		nfs_sb_deactive(sb); +	else +		nfs_sb_deactive_async(sb);  	kfree(ctx->mdsthreshold);  	kfree(ctx);  } diff --git a/fs/nfs/internal.h b/fs/nfs/internal.h index 59b133c5d65..05521cadac2 100644 --- a/fs/nfs/internal.h +++ b/fs/nfs/internal.h @@ -351,10 +351,12 @@ extern int __init register_nfs_fs(void);  extern void __exit unregister_nfs_fs(void);  extern void nfs_sb_active(struct super_block *sb);  extern void nfs_sb_deactive(struct super_block *sb); +extern void nfs_sb_deactive_async(struct super_block *sb);  /* namespace.c */ +#define NFS_PATH_CANONICAL 1  extern char *nfs_path(char **p, struct dentry *dentry, -		      char *buffer, ssize_t buflen); +		      char *buffer, ssize_t buflen, unsigned flags);  extern struct vfsmount *nfs_d_automount(struct path *path);  struct vfsmount *nfs_submount(struct nfs_server *, struct dentry *,  			      struct nfs_fh *, struct nfs_fattr *); @@ -498,7 +500,7 @@ static inline char *nfs_devname(struct dentry *dentry,  				char *buffer, ssize_t buflen)  {  	char *dummy; -	return nfs_path(&dummy, dentry, buffer, buflen); +	return nfs_path(&dummy, dentry, buffer, buflen, NFS_PATH_CANONICAL);  }  /* diff --git a/fs/nfs/mount_clnt.c b/fs/nfs/mount_clnt.c index 8e65c7f1f87..015f71f8f62 100644 --- a/fs/nfs/mount_clnt.c +++ b/fs/nfs/mount_clnt.c @@ -181,7 +181,7 @@ int nfs_mount(struct nfs_mount_request *info)  	else  		msg.rpc_proc = &mnt_clnt->cl_procinfo[MOUNTPROC_MNT]; -	status = rpc_call_sync(mnt_clnt, &msg, 0); +	status = rpc_call_sync(mnt_clnt, &msg, RPC_TASK_SOFT|RPC_TASK_TIMEOUT);  	rpc_shutdown_client(mnt_clnt);  	if (status < 0) diff --git a/fs/nfs/namespace.c b/fs/nfs/namespace.c index 655925373b9..dd057bc6b65 100644 --- a/fs/nfs/namespace.c +++ b/fs/nfs/namespace.c @@ -33,6 +33,7 @@ int nfs_mountpoint_expiry_timeout = 500 * HZ;   * @dentry - pointer to dentry   * @buffer - result buffer   * @buflen - length of buffer + * @flags - options (see below)   *   * Helper function for constructing the server pathname   * by arbitrary hashed dentry. @@ -40,8 +41,14 @@ int nfs_mountpoint_expiry_timeout = 500 * HZ;   * This is mainly for use in figuring out the path on the   * server side when automounting on top of an existing partition   * and in generating /proc/mounts and friends. + * + * Supported flags: + * NFS_PATH_CANONICAL: ensure there is exactly one slash after + *		       the original device (export) name + *		       (if unset, the original name is returned verbatim)   */ -char *nfs_path(char **p, struct dentry *dentry, char *buffer, ssize_t buflen) +char *nfs_path(char **p, struct dentry *dentry, char *buffer, ssize_t buflen, +	       unsigned flags)  {  	char *end;  	int namelen; @@ -74,7 +81,7 @@ rename_retry:  		rcu_read_unlock();  		goto rename_retry;  	} -	if (*end != '/') { +	if ((flags & NFS_PATH_CANONICAL) && *end != '/') {  		if (--buflen < 0) {  			spin_unlock(&dentry->d_lock);  			rcu_read_unlock(); @@ -91,9 +98,11 @@ rename_retry:  		return end;  	}  	namelen = strlen(base); -	/* Strip off excess slashes in base string */ -	while (namelen > 0 && base[namelen - 1] == '/') -		namelen--; +	if (flags & NFS_PATH_CANONICAL) { +		/* Strip off excess slashes in base string */ +		while (namelen > 0 && base[namelen - 1] == '/') +			namelen--; +	}  	buflen -= namelen;  	if (buflen < 0) {  		spin_unlock(&dentry->d_lock); diff --git a/fs/nfs/nfs4filelayout.c b/fs/nfs/nfs4filelayout.c index 52d84721206..2e45fd9c02a 100644 --- a/fs/nfs/nfs4filelayout.c +++ b/fs/nfs/nfs4filelayout.c @@ -122,12 +122,21 @@ static void filelayout_reset_read(struct nfs_read_data *data)  	}  } +static void filelayout_fenceme(struct inode *inode, struct pnfs_layout_hdr *lo) +{ +	if (!test_and_clear_bit(NFS_LAYOUT_RETURN, &lo->plh_flags)) +		return; +	clear_bit(NFS_INO_LAYOUTCOMMIT, &NFS_I(inode)->flags); +	pnfs_return_layout(inode); +} +  static int filelayout_async_handle_error(struct rpc_task *task,  					 struct nfs4_state *state,  					 struct nfs_client *clp,  					 struct pnfs_layout_segment *lseg)  { -	struct inode *inode = lseg->pls_layout->plh_inode; +	struct pnfs_layout_hdr *lo = lseg->pls_layout; +	struct inode *inode = lo->plh_inode;  	struct nfs_server *mds_server = NFS_SERVER(inode);  	struct nfs4_deviceid_node *devid = FILELAYOUT_DEVID_NODE(lseg);  	struct nfs_client *mds_client = mds_server->nfs_client; @@ -204,10 +213,8 @@ static int filelayout_async_handle_error(struct rpc_task *task,  		dprintk("%s DS connection error %d\n", __func__,  			task->tk_status);  		nfs4_mark_deviceid_unavailable(devid); -		clear_bit(NFS_INO_LAYOUTCOMMIT, &NFS_I(inode)->flags); -		_pnfs_return_layout(inode); +		set_bit(NFS_LAYOUT_RETURN, &lo->plh_flags);  		rpc_wake_up(&tbl->slot_tbl_waitq); -		nfs4_ds_disconnect(clp);  		/* fall through */  	default:  reset: @@ -331,7 +338,9 @@ static void filelayout_read_count_stats(struct rpc_task *task, void *data)  static void filelayout_read_release(void *data)  {  	struct nfs_read_data *rdata = data; +	struct pnfs_layout_hdr *lo = rdata->header->lseg->pls_layout; +	filelayout_fenceme(lo->plh_inode, lo);  	nfs_put_client(rdata->ds_clp);  	rdata->header->mds_ops->rpc_release(data);  } @@ -429,7 +438,9 @@ static void filelayout_write_count_stats(struct rpc_task *task, void *data)  static void filelayout_write_release(void *data)  {  	struct nfs_write_data *wdata = data; +	struct pnfs_layout_hdr *lo = wdata->header->lseg->pls_layout; +	filelayout_fenceme(lo->plh_inode, lo);  	nfs_put_client(wdata->ds_clp);  	wdata->header->mds_ops->rpc_release(data);  } @@ -739,7 +750,7 @@ filelayout_decode_layout(struct pnfs_layout_hdr *flo,  		goto out_err;  	if (fl->num_fh > 0) { -		fl->fh_array = kzalloc(fl->num_fh * sizeof(struct nfs_fh *), +		fl->fh_array = kcalloc(fl->num_fh, sizeof(fl->fh_array[0]),  				       gfp_flags);  		if (!fl->fh_array)  			goto out_err; diff --git a/fs/nfs/nfs4filelayout.h b/fs/nfs/nfs4filelayout.h index dca47d78671..8c07241fe52 100644 --- a/fs/nfs/nfs4filelayout.h +++ b/fs/nfs/nfs4filelayout.h @@ -149,6 +149,5 @@ extern void nfs4_fl_put_deviceid(struct nfs4_file_layout_dsaddr *dsaddr);  extern void nfs4_fl_free_deviceid(struct nfs4_file_layout_dsaddr *dsaddr);  struct nfs4_file_layout_dsaddr *  filelayout_get_device_info(struct inode *inode, struct nfs4_deviceid *dev_id, gfp_t gfp_flags); -void nfs4_ds_disconnect(struct nfs_client *clp);  #endif /* FS_NFS_NFS4FILELAYOUT_H */ diff --git a/fs/nfs/nfs4filelayoutdev.c b/fs/nfs/nfs4filelayoutdev.c index 3336d5eaf87..a8eaa9b7bb0 100644 --- a/fs/nfs/nfs4filelayoutdev.c +++ b/fs/nfs/nfs4filelayoutdev.c @@ -149,28 +149,6 @@ _data_server_lookup_locked(const struct list_head *dsaddrs)  }  /* - * Lookup DS by nfs_client pointer. Zero data server client pointer - */ -void nfs4_ds_disconnect(struct nfs_client *clp) -{ -	struct nfs4_pnfs_ds *ds; -	struct nfs_client *found = NULL; - -	dprintk("%s clp %p\n", __func__, clp); -	spin_lock(&nfs4_ds_cache_lock); -	list_for_each_entry(ds, &nfs4_data_server_cache, ds_node) -		if (ds->ds_clp && ds->ds_clp == clp) { -			found = ds->ds_clp; -			ds->ds_clp = NULL; -		} -	spin_unlock(&nfs4_ds_cache_lock); -	if (found) { -		set_bit(NFS_CS_STOP_RENEW, &clp->cl_res_state); -		nfs_put_client(clp); -	} -} - -/*   * Create an rpc connection to the nfs4_pnfs_ds data server   * Currently only supports IPv4 and IPv6 addresses   */ diff --git a/fs/nfs/nfs4getroot.c b/fs/nfs/nfs4getroot.c index 6a83780e0ce..549462e5b9b 100644 --- a/fs/nfs/nfs4getroot.c +++ b/fs/nfs/nfs4getroot.c @@ -5,6 +5,7 @@  #include <linux/nfs_fs.h>  #include "nfs4_fs.h" +#include "internal.h"  #define NFSDBG_FACILITY		NFSDBG_CLIENT diff --git a/fs/nfs/nfs4namespace.c b/fs/nfs/nfs4namespace.c index 79fbb61ce20..1e09eb78543 100644 --- a/fs/nfs/nfs4namespace.c +++ b/fs/nfs/nfs4namespace.c @@ -81,7 +81,8 @@ static char *nfs_path_component(const char *nfspath, const char *end)  static char *nfs4_path(struct dentry *dentry, char *buffer, ssize_t buflen)  {  	char *limit; -	char *path = nfs_path(&limit, dentry, buffer, buflen); +	char *path = nfs_path(&limit, dentry, buffer, buflen, +			      NFS_PATH_CANONICAL);  	if (!IS_ERR(path)) {  		char *path_component = nfs_path_component(path, limit);  		if (path_component) diff --git a/fs/nfs/nfs4proc.c b/fs/nfs/nfs4proc.c index 68b21d81b7a..5eec4429970 100644 --- a/fs/nfs/nfs4proc.c +++ b/fs/nfs/nfs4proc.c @@ -339,8 +339,7 @@ static int nfs4_handle_exception(struct nfs_server *server, int errorcode, struc  			dprintk("%s ERROR: %d Reset session\n", __func__,  				errorcode);  			nfs4_schedule_session_recovery(clp->cl_session, errorcode); -			exception->retry = 1; -			break; +			goto wait_on_recovery;  #endif /* defined(CONFIG_NFS_V4_1) */  		case -NFS4ERR_FILE_OPEN:  			if (exception->timeout > HZ) { @@ -1572,9 +1571,11 @@ static void nfs4_open_prepare(struct rpc_task *task, void *calldata)  	data->timestamp = jiffies;  	if (nfs4_setup_sequence(data->o_arg.server,  				&data->o_arg.seq_args, -				&data->o_res.seq_res, task)) -		return; -	rpc_call_start(task); +				&data->o_res.seq_res, +				task) != 0) +		nfs_release_seqid(data->o_arg.seqid); +	else +		rpc_call_start(task);  	return;  unlock_no_action:  	rcu_read_unlock(); @@ -1748,7 +1749,7 @@ static int nfs4_opendata_access(struct rpc_cred *cred,  	/* even though OPEN succeeded, access is denied. Close the file */  	nfs4_close_state(state, fmode); -	return -NFS4ERR_ACCESS; +	return -EACCES;  }  /* @@ -2196,7 +2197,7 @@ static void nfs4_free_closedata(void *data)  	nfs4_put_open_state(calldata->state);  	nfs_free_seqid(calldata->arg.seqid);  	nfs4_put_state_owner(sp); -	nfs_sb_deactive(sb); +	nfs_sb_deactive_async(sb);  	kfree(calldata);  } @@ -2296,9 +2297,10 @@ static void nfs4_close_prepare(struct rpc_task *task, void *data)  	if (nfs4_setup_sequence(NFS_SERVER(inode),  				&calldata->arg.seq_args,  				&calldata->res.seq_res, -				task)) -		goto out; -	rpc_call_start(task); +				task) != 0) +		nfs_release_seqid(calldata->arg.seqid); +	else +		rpc_call_start(task);  out:  	dprintk("%s: done!\n", __func__);  } @@ -4529,6 +4531,7 @@ static void nfs4_locku_done(struct rpc_task *task, void *data)  			if (nfs4_async_handle_error(task, calldata->server, NULL) == -EAGAIN)  				rpc_restart_call_prepare(task);  	} +	nfs_release_seqid(calldata->arg.seqid);  }  static void nfs4_locku_prepare(struct rpc_task *task, void *data) @@ -4545,9 +4548,11 @@ static void nfs4_locku_prepare(struct rpc_task *task, void *data)  	calldata->timestamp = jiffies;  	if (nfs4_setup_sequence(calldata->server,  				&calldata->arg.seq_args, -				&calldata->res.seq_res, task)) -		return; -	rpc_call_start(task); +				&calldata->res.seq_res, +				task) != 0) +		nfs_release_seqid(calldata->arg.seqid); +	else +		rpc_call_start(task);  }  static const struct rpc_call_ops nfs4_locku_ops = { @@ -4692,7 +4697,7 @@ static void nfs4_lock_prepare(struct rpc_task *task, void *calldata)  	/* Do we need to do an open_to_lock_owner? */  	if (!(data->arg.lock_seqid->sequence->flags & NFS_SEQID_CONFIRMED)) {  		if (nfs_wait_on_sequence(data->arg.open_seqid, task) != 0) -			return; +			goto out_release_lock_seqid;  		data->arg.open_stateid = &state->stateid;  		data->arg.new_lock_owner = 1;  		data->res.open_seqid = data->arg.open_seqid; @@ -4701,10 +4706,15 @@ static void nfs4_lock_prepare(struct rpc_task *task, void *calldata)  	data->timestamp = jiffies;  	if (nfs4_setup_sequence(data->server,  				&data->arg.seq_args, -				&data->res.seq_res, task)) +				&data->res.seq_res, +				task) == 0) { +		rpc_call_start(task);  		return; -	rpc_call_start(task); -	dprintk("%s: done!, ret = %d\n", __func__, data->rpc_status); +	} +	nfs_release_seqid(data->arg.open_seqid); +out_release_lock_seqid: +	nfs_release_seqid(data->arg.lock_seqid); +	dprintk("%s: done!, ret = %d\n", __func__, task->tk_status);  }  static void nfs4_recover_lock_prepare(struct rpc_task *task, void *calldata) @@ -5667,7 +5677,7 @@ static void nfs4_add_and_init_slots(struct nfs4_slot_table *tbl,  		tbl->slots = new;  		tbl->max_slots = max_slots;  	} -	tbl->highest_used_slotid = -1;	/* no slot is currently used */ +	tbl->highest_used_slotid = NFS4_NO_SLOT;  	for (i = 0; i < tbl->max_slots; i++)  		tbl->slots[i].seq_nr = ivalue;  	spin_unlock(&tbl->slot_tbl_lock); diff --git a/fs/nfs/objlayout/objio_osd.c b/fs/nfs/objlayout/objio_osd.c index be731e6b7b9..c6f990656f8 100644 --- a/fs/nfs/objlayout/objio_osd.c +++ b/fs/nfs/objlayout/objio_osd.c @@ -369,7 +369,7 @@ void objio_free_result(struct objlayout_io_res *oir)  	kfree(objios);  } -enum pnfs_osd_errno osd_pri_2_pnfs_err(enum osd_err_priority oep) +static enum pnfs_osd_errno osd_pri_2_pnfs_err(enum osd_err_priority oep)  {  	switch (oep) {  	case OSD_ERR_PRI_NO_ERROR: @@ -574,7 +574,7 @@ static bool objio_pg_test(struct nfs_pageio_descriptor *pgio,  			(unsigned long)pgio->pg_layout_private;  } -void objio_init_read(struct nfs_pageio_descriptor *pgio, struct nfs_page *req) +static void objio_init_read(struct nfs_pageio_descriptor *pgio, struct nfs_page *req)  {  	pnfs_generic_pg_init_read(pgio, req);  	if (unlikely(pgio->pg_lseg == NULL)) @@ -604,7 +604,7 @@ static bool aligned_on_raid_stripe(u64 offset, struct ore_layout *layout,  	return false;  } -void objio_init_write(struct nfs_pageio_descriptor *pgio, struct nfs_page *req) +static void objio_init_write(struct nfs_pageio_descriptor *pgio, struct nfs_page *req)  {  	unsigned long stripe_end = 0;  	u64 wb_size; diff --git a/fs/nfs/pnfs.c b/fs/nfs/pnfs.c index fe624c91bd0..2878f97bd78 100644 --- a/fs/nfs/pnfs.c +++ b/fs/nfs/pnfs.c @@ -925,8 +925,8 @@ pnfs_find_alloc_layout(struct inode *ino,  	if (likely(nfsi->layout == NULL)) {	/* Won the race? */  		nfsi->layout = new;  		return new; -	} -	pnfs_free_layout_hdr(new); +	} else if (new != NULL) +		pnfs_free_layout_hdr(new);  out_existing:  	pnfs_get_layout_hdr(nfsi->layout);  	return nfsi->layout; diff --git a/fs/nfs/pnfs.h b/fs/nfs/pnfs.h index 2d722dba111..dbf7bba52da 100644 --- a/fs/nfs/pnfs.h +++ b/fs/nfs/pnfs.h @@ -62,6 +62,7 @@ enum {  	NFS_LAYOUT_RW_FAILED,		/* get rw layout failed stop trying */  	NFS_LAYOUT_BULK_RECALL,		/* bulk recall affecting layout */  	NFS_LAYOUT_ROC,			/* some lseg had roc bit set */ +	NFS_LAYOUT_RETURN,		/* Return this layout ASAP */  };  enum layoutdriver_policy_flags { diff --git a/fs/nfs/super.c b/fs/nfs/super.c index e831bce4976..652d3f7176a 100644 --- a/fs/nfs/super.c +++ b/fs/nfs/super.c @@ -54,6 +54,7 @@  #include <linux/parser.h>  #include <linux/nsproxy.h>  #include <linux/rcupdate.h> +#include <linux/kthread.h>  #include <asm/uaccess.h> @@ -415,6 +416,54 @@ void nfs_sb_deactive(struct super_block *sb)  }  EXPORT_SYMBOL_GPL(nfs_sb_deactive); +static int nfs_deactivate_super_async_work(void *ptr) +{ +	struct super_block *sb = ptr; + +	deactivate_super(sb); +	module_put_and_exit(0); +	return 0; +} + +/* + * same effect as deactivate_super, but will do final unmount in kthread + * context + */ +static void nfs_deactivate_super_async(struct super_block *sb) +{ +	struct task_struct *task; +	char buf[INET6_ADDRSTRLEN + 1]; +	struct nfs_server *server = NFS_SB(sb); +	struct nfs_client *clp = server->nfs_client; + +	if (!atomic_add_unless(&sb->s_active, -1, 1)) { +		rcu_read_lock(); +		snprintf(buf, sizeof(buf), +			rpc_peeraddr2str(clp->cl_rpcclient, RPC_DISPLAY_ADDR)); +		rcu_read_unlock(); + +		__module_get(THIS_MODULE); +		task = kthread_run(nfs_deactivate_super_async_work, sb, +				"%s-deactivate-super", buf); +		if (IS_ERR(task)) { +			pr_err("%s: kthread_run: %ld\n", +				__func__, PTR_ERR(task)); +			/* make synchronous call and hope for the best */ +			deactivate_super(sb); +			module_put(THIS_MODULE); +		} +	} +} + +void nfs_sb_deactive_async(struct super_block *sb) +{ +	struct nfs_server *server = NFS_SB(sb); + +	if (atomic_dec_and_test(&server->active)) +		nfs_deactivate_super_async(sb); +} +EXPORT_SYMBOL_GPL(nfs_sb_deactive_async); +  /*   * Deliver file system statistics to userspace   */ @@ -771,7 +820,7 @@ int nfs_show_devname(struct seq_file *m, struct dentry *root)  	int err = 0;  	if (!page)  		return -ENOMEM; -	devname = nfs_path(&dummy, root, page, PAGE_SIZE); +	devname = nfs_path(&dummy, root, page, PAGE_SIZE, 0);  	if (IS_ERR(devname))  		err = PTR_ERR(devname);  	else diff --git a/fs/nfs/unlink.c b/fs/nfs/unlink.c index 13cea637eff..3f79c77153b 100644 --- a/fs/nfs/unlink.c +++ b/fs/nfs/unlink.c @@ -95,7 +95,7 @@ static void nfs_async_unlink_release(void *calldata)  	nfs_dec_sillycount(data->dir);  	nfs_free_unlinkdata(data); -	nfs_sb_deactive(sb); +	nfs_sb_deactive_async(sb);  }  static void nfs_unlink_prepare(struct rpc_task *task, void *calldata)  |