diff options
| -rw-r--r-- | fs/nfs/namespace.c | 20 | ||||
| -rw-r--r-- | fs/nfs/nfs4client.c | 62 | ||||
| -rw-r--r-- | fs/nfs/nfs4state.c | 22 | ||||
| -rw-r--r-- | fs/nfs/super.c | 22 | ||||
| -rw-r--r-- | net/sunrpc/sched.c | 18 | 
5 files changed, 86 insertions, 58 deletions
diff --git a/fs/nfs/namespace.c b/fs/nfs/namespace.c index dd057bc6b65..fc8dc20fdeb 100644 --- a/fs/nfs/namespace.c +++ b/fs/nfs/namespace.c @@ -177,11 +177,31 @@ out_nofree:  	return mnt;  } +static int +nfs_namespace_getattr(struct vfsmount *mnt, struct dentry *dentry, struct kstat *stat) +{ +	if (NFS_FH(dentry->d_inode)->size != 0) +		return nfs_getattr(mnt, dentry, stat); +	generic_fillattr(dentry->d_inode, stat); +	return 0; +} + +static int +nfs_namespace_setattr(struct dentry *dentry, struct iattr *attr) +{ +	if (NFS_FH(dentry->d_inode)->size != 0) +		return nfs_setattr(dentry, attr); +	return -EACCES; +} +  const struct inode_operations nfs_mountpoint_inode_operations = {  	.getattr	= nfs_getattr, +	.setattr	= nfs_setattr,  };  const struct inode_operations nfs_referral_inode_operations = { +	.getattr	= nfs_namespace_getattr, +	.setattr	= nfs_namespace_setattr,  };  static void nfs_expire_automounts(struct work_struct *work) diff --git a/fs/nfs/nfs4client.c b/fs/nfs/nfs4client.c index acc34726812..2e9779b58b7 100644 --- a/fs/nfs/nfs4client.c +++ b/fs/nfs/nfs4client.c @@ -236,11 +236,10 @@ struct nfs_client *nfs4_init_client(struct nfs_client *clp,  	error = nfs4_discover_server_trunking(clp, &old);  	if (error < 0)  		goto error; +	nfs_put_client(clp);  	if (clp != old) {  		clp->cl_preserve_clid = true; -		nfs_put_client(clp);  		clp = old; -		atomic_inc(&clp->cl_count);  	}  	return clp; @@ -306,7 +305,7 @@ int nfs40_walk_client_list(struct nfs_client *new,  		.clientid	= new->cl_clientid,  		.confirm	= new->cl_confirm,  	}; -	int status; +	int status = -NFS4ERR_STALE_CLIENTID;  	spin_lock(&nn->nfs_client_lock);  	list_for_each_entry_safe(pos, n, &nn->nfs_client_list, cl_share_link) { @@ -332,40 +331,33 @@ int nfs40_walk_client_list(struct nfs_client *new,  		if (prev)  			nfs_put_client(prev); +		prev = pos;  		status = nfs4_proc_setclientid_confirm(pos, &clid, cred); -		if (status == 0) { +		switch (status) { +		case -NFS4ERR_STALE_CLIENTID: +			break; +		case 0:  			nfs4_swap_callback_idents(pos, new); -			nfs_put_client(pos); +			prev = NULL;  			*result = pos;  			dprintk("NFS: <-- %s using nfs_client = %p ({%d})\n",  				__func__, pos, atomic_read(&pos->cl_count)); -			return 0; -		} -		if (status != -NFS4ERR_STALE_CLIENTID) { -			nfs_put_client(pos); -			dprintk("NFS: <-- %s status = %d, no result\n", -				__func__, status); -			return status; +		default: +			goto out;  		}  		spin_lock(&nn->nfs_client_lock); -		prev = pos;  	} +	spin_unlock(&nn->nfs_client_lock); -	/* -	 * No matching nfs_client found.  This should be impossible, -	 * because the new nfs_client has already been added to -	 * nfs_client_list by nfs_get_client(). -	 * -	 * Don't BUG(), since the caller is holding a mutex. -	 */ +	/* No match found. The server lost our clientid */ +out:  	if (prev)  		nfs_put_client(prev); -	spin_unlock(&nn->nfs_client_lock); -	pr_err("NFS: %s Error: no matching nfs_client found\n", __func__); -	return -NFS4ERR_STALE_CLIENTID; +	dprintk("NFS: <-- %s status = %d\n", __func__, status); +	return status;  }  #ifdef CONFIG_NFS_V4_1 @@ -432,7 +424,7 @@ int nfs41_walk_client_list(struct nfs_client *new,  {  	struct nfs_net *nn = net_generic(new->cl_net, nfs_net_id);  	struct nfs_client *pos, *n, *prev = NULL; -	int error; +	int status = -NFS4ERR_STALE_CLIENTID;  	spin_lock(&nn->nfs_client_lock);  	list_for_each_entry_safe(pos, n, &nn->nfs_client_list, cl_share_link) { @@ -448,14 +440,17 @@ int nfs41_walk_client_list(struct nfs_client *new,  				nfs_put_client(prev);  			prev = pos; -			error = nfs_wait_client_init_complete(pos); -			if (error < 0) { +			nfs4_schedule_lease_recovery(pos); +			status = nfs_wait_client_init_complete(pos); +			if (status < 0) {  				nfs_put_client(pos);  				spin_lock(&nn->nfs_client_lock);  				continue;  			} - +			status = pos->cl_cons_state;  			spin_lock(&nn->nfs_client_lock); +			if (status < 0) +				continue;  		}  		if (pos->rpc_ops != new->rpc_ops) @@ -473,6 +468,7 @@ int nfs41_walk_client_list(struct nfs_client *new,  		if (!nfs4_match_serverowners(pos, new))  			continue; +		atomic_inc(&pos->cl_count);  		spin_unlock(&nn->nfs_client_lock);  		dprintk("NFS: <-- %s using nfs_client = %p ({%d})\n",  			__func__, pos, atomic_read(&pos->cl_count)); @@ -481,16 +477,10 @@ int nfs41_walk_client_list(struct nfs_client *new,  		return 0;  	} -	/* -	 * No matching nfs_client found.  This should be impossible, -	 * because the new nfs_client has already been added to -	 * nfs_client_list by nfs_get_client(). -	 * -	 * Don't BUG(), since the caller is holding a mutex. -	 */ +	/* No matching nfs_client found. */  	spin_unlock(&nn->nfs_client_lock); -	pr_err("NFS: %s Error: no matching nfs_client found\n", __func__); -	return -NFS4ERR_STALE_CLIENTID; +	dprintk("NFS: <-- %s status = %d\n", __func__, status); +	return status;  }  #endif	/* CONFIG_NFS_V4_1 */ diff --git a/fs/nfs/nfs4state.c b/fs/nfs/nfs4state.c index 9448c579d41..e61f68d5ef2 100644 --- a/fs/nfs/nfs4state.c +++ b/fs/nfs/nfs4state.c @@ -136,16 +136,11 @@ int nfs40_discover_server_trunking(struct nfs_client *clp,  	clp->cl_confirm = clid.confirm;  	status = nfs40_walk_client_list(clp, result, cred); -	switch (status) { -	case -NFS4ERR_STALE_CLIENTID: -		set_bit(NFS4CLNT_LEASE_CONFIRM, &clp->cl_state); -	case 0: +	if (status == 0) {  		/* Sustain the lease, even if it's empty.  If the clientid4  		 * goes stale it's of no use for trunking discovery. */  		nfs4_schedule_state_renewal(*result); -		break;  	} -  out:  	return status;  } @@ -1863,6 +1858,7 @@ again:  	case -ETIMEDOUT:  	case -EAGAIN:  		ssleep(1); +	case -NFS4ERR_STALE_CLIENTID:  		dprintk("NFS: %s after status %d, retrying\n",  			__func__, status);  		goto again; @@ -2022,8 +2018,18 @@ static int nfs4_reset_session(struct nfs_client *clp)  	nfs4_begin_drain_session(clp);  	cred = nfs4_get_exchange_id_cred(clp);  	status = nfs4_proc_destroy_session(clp->cl_session, cred); -	if (status && status != -NFS4ERR_BADSESSION && -	    status != -NFS4ERR_DEADSESSION) { +	switch (status) { +	case 0: +	case -NFS4ERR_BADSESSION: +	case -NFS4ERR_DEADSESSION: +		break; +	case -NFS4ERR_BACK_CHAN_BUSY: +	case -NFS4ERR_DELAY: +		set_bit(NFS4CLNT_SESSION_RESET, &clp->cl_state); +		status = 0; +		ssleep(1); +		goto out; +	default:  		status = nfs4_recovery_handle_error(clp, status);  		goto out;  	} diff --git a/fs/nfs/super.c b/fs/nfs/super.c index 2e7e8c878e5..b056b162872 100644 --- a/fs/nfs/super.c +++ b/fs/nfs/super.c @@ -2589,27 +2589,23 @@ nfs_xdev_mount(struct file_system_type *fs_type, int flags,  	struct nfs_server *server;  	struct dentry *mntroot = ERR_PTR(-ENOMEM);  	struct nfs_subversion *nfs_mod = NFS_SB(data->sb)->nfs_client->cl_nfs_mod; -	int error; -	dprintk("--> nfs_xdev_mount_common()\n"); +	dprintk("--> nfs_xdev_mount()\n");  	mount_info.mntfh = mount_info.cloned->fh;  	/* create a new volume representation */  	server = nfs_mod->rpc_ops->clone_server(NFS_SB(data->sb), data->fh, data->fattr, data->authflavor); -	if (IS_ERR(server)) { -		error = PTR_ERR(server); -		goto out_err; -	} -	mntroot = nfs_fs_mount_common(server, flags, dev_name, &mount_info, nfs_mod); -	dprintk("<-- nfs_xdev_mount_common() = 0\n"); -out: -	return mntroot; +	if (IS_ERR(server)) +		mntroot = ERR_CAST(server); +	else +		mntroot = nfs_fs_mount_common(server, flags, +				dev_name, &mount_info, nfs_mod); -out_err: -	dprintk("<-- nfs_xdev_mount_common() = %d [error]\n", error); -	goto out; +	dprintk("<-- nfs_xdev_mount() = %ld\n", +			IS_ERR(mntroot) ? PTR_ERR(mntroot) : 0L); +	return mntroot;  }  #if IS_ENABLED(CONFIG_NFS_V4) diff --git a/net/sunrpc/sched.c b/net/sunrpc/sched.c index bfa31714581..fb20f25ddec 100644 --- a/net/sunrpc/sched.c +++ b/net/sunrpc/sched.c @@ -98,9 +98,25 @@ __rpc_add_timer(struct rpc_wait_queue *queue, struct rpc_task *task)  	list_add(&task->u.tk_wait.timer_list, &queue->timer_list.list);  } +static void rpc_rotate_queue_owner(struct rpc_wait_queue *queue) +{ +	struct list_head *q = &queue->tasks[queue->priority]; +	struct rpc_task *task; + +	if (!list_empty(q)) { +		task = list_first_entry(q, struct rpc_task, u.tk_wait.list); +		if (task->tk_owner == queue->owner) +			list_move_tail(&task->u.tk_wait.list, q); +	} +} +  static void rpc_set_waitqueue_priority(struct rpc_wait_queue *queue, int priority)  { -	queue->priority = priority; +	if (queue->priority != priority) { +		/* Fairness: rotate the list when changing priority */ +		rpc_rotate_queue_owner(queue); +		queue->priority = priority; +	}  }  static void rpc_set_waitqueue_owner(struct rpc_wait_queue *queue, pid_t pid)  |