diff options
| author | Ingo Molnar <mingo@kernel.org> | 2012-12-07 12:15:33 +0100 | 
|---|---|---|
| committer | Ingo Molnar <mingo@kernel.org> | 2012-12-07 12:15:33 +0100 | 
| commit | 222e82bef4bd520a31d48c31ab24e49dd46daa46 (patch) | |
| tree | b6e73cad8e0b3a1c3e1acc537789e97aadaefa92 /fs/nfs | |
| parent | 38ca9c927c7d3db61f57e3d3a9334958c3af6e9a (diff) | |
| parent | 18a2f371f5edf41810f6469cb9be39931ef9deb9 (diff) | |
Merge branch 'linus' into sched/core
Pick up the autogroups fix and other fixes.
Signed-off-by: Ingo Molnar <mingo@kernel.org>
Diffstat (limited to 'fs/nfs')
| -rw-r--r-- | fs/nfs/dir.c | 7 | ||||
| -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/nfs4namespace.c | 3 | ||||
| -rw-r--r-- | fs/nfs/nfs4proc.c | 46 | ||||
| -rw-r--r-- | fs/nfs/pnfs.c | 4 | ||||
| -rw-r--r-- | fs/nfs/super.c | 51 | ||||
| -rw-r--r-- | fs/nfs/unlink.c | 2 | 
11 files changed, 113 insertions, 37 deletions
diff --git a/fs/nfs/dir.c b/fs/nfs/dir.c index ce8cb926526b..b9e66b7e0c14 100644 --- a/fs/nfs/dir.c +++ b/fs/nfs/dir.c @@ -450,7 +450,8 @@ void nfs_prime_dcache(struct dentry *parent, struct nfs_entry *entry)  			nfs_refresh_inode(dentry->d_inode, entry->fattr);  			goto out;  		} else { -			d_drop(dentry); +			if (d_invalidate(dentry) != 0) +				goto out;  			dput(dentry);  		}  	} @@ -1100,6 +1101,8 @@ out_set_verifier:  out_zap_parent:  	nfs_zap_caches(dir);   out_bad: +	nfs_free_fattr(fattr); +	nfs_free_fhandle(fhandle);  	nfs_mark_for_revalidate(dir);  	if (inode && S_ISDIR(inode->i_mode)) {  		/* Purge readdir caches. */ @@ -1112,8 +1115,6 @@ out_zap_parent:  		shrink_dcache_parent(dentry);  	}  	d_drop(dentry); -	nfs_free_fattr(fattr); -	nfs_free_fhandle(fhandle);  	dput(parent);  	dfprintk(LOOKUPCACHE, "NFS: %s(%s/%s) is invalid\n",  			__func__, dentry->d_parent->d_name.name, diff --git a/fs/nfs/dns_resolve.c b/fs/nfs/dns_resolve.c index 31c26c4dcc23..ca4b11ec87a2 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 5c7325c5c5e6..6fa01aea2488 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 59b133c5d652..05521cadac2e 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 8e65c7f1f87c..015f71f8f62c 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 655925373b91..dd057bc6b65b 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/nfs4namespace.c b/fs/nfs/nfs4namespace.c index 79fbb61ce202..1e09eb78543b 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 68b21d81b7ac..5eec4429970c 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/pnfs.c b/fs/nfs/pnfs.c index fe624c91bd00..2878f97bd78d 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/super.c b/fs/nfs/super.c index e831bce49766..652d3f7176a9 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 13cea637eff8..3f79c77153b8 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)  | 
