NFS client bugfixe for Linux 3.8
- Error reporting in nfs_xdev_mount incorrectly maps all errors to ENOMEM - Fix an NFSv4 refcounting issue - Fix a mount failure when the server reboots during NFSv4 trunking discovery - NFSv4.1 mounts may need to run the lease recovery thread. - Don't silently fail setattr() requests on mountpoints - Fix a SUNRPC socket/transport livelock and priority queue issue - We must handle NFS4ERR_DELAY when resetting the NFSv4.1 session. -----BEGIN PGP SIGNATURE----- Version: GnuPG v1.4.13 (GNU/Linux) iQIcBAABAgAGBQJRCpS4AAoJEGcL54qWCgDyqucP/2CTv5leu+X5/0PXBOykAIHg 8oEsTEz7/4IvIxTXzuHDYirMnm/mulfGF6NrdPqfvxpAHqRfVBfLFocfNLMVhQci 97RmBfEEGM22AToYUubML5bIxr0QllV4s9Vmyh/zGDan52y7zNNlZX+v6aLjZbJB Fbolihpcch6lhQEUNAzK0B0ddimDl9lazx/WTmMOD/JrwOqzA4FJC+YxBe88nfzQ c6sYyEptBaSirbCOlueqGpv8skB1CLpFJXguXToPXFxpWed6uoGrIwLO7MLUdFpJ Xw+j8cuv/wjyYJGVKjhW7kXtwK8T7+u4bT2L883R01XYXr8XfkkLON0dgG1X/unk 80mLzCO1+qRdoDSQ4b/V4B0nScPRCJuoZpftjCi2uhKewNcxQPMZ2V5/D7pO3uyE NdhxByB8D86JfNrIcBcRaxfuiQsurQBDvsDNmWPBZSOmH/dmHqTQGLcIe6N94A0B c7KFtXrN2MzOl8S68dUpbhftObq9X0oK2oxFFLWRQoqjrFtiDLU5JilV0bEH2CMo gJX7CRrPoJ2wmNToKdPJRWBYDmtMMIThq3vIpCj1FFzX17r5grJpqCmp/TViu/ER r8rmJzni+nmHaO1NLJMTCHzLJ8soiKyBq8PZKAbipTJxy+TXI/69jnWzpIQ/pbM/ JN+0tiCcqmUmXsO+hrCP =lWFV -----END PGP SIGNATURE----- Merge tag 'nfs-for-3.8-4' of git://git.linux-nfs.org/projects/trondmy/linux-nfs Pull NFS client bugfixes from Trond Myklebust: - Error reporting in nfs_xdev_mount incorrectly maps all errors to ENOMEM - Fix an NFSv4 refcounting issue - Fix a mount failure when the server reboots during NFSv4 trunking discovery - NFSv4.1 mounts may need to run the lease recovery thread. - Don't silently fail setattr() requests on mountpoints - Fix a SUNRPC socket/transport livelock and priority queue issue - We must handle NFS4ERR_DELAY when resetting the NFSv4.1 session. * tag 'nfs-for-3.8-4' of git://git.linux-nfs.org/projects/trondmy/linux-nfs: NFSv4.1: Handle NFS4ERR_DELAY when resetting the NFSv4.1 session SUNRPC: When changing the queue priority, ensure that we change the owner NFS: Don't silently fail setattr() requests on mountpoints NFSv4.1: Ensure that nfs41_walk_client_list() does start lease recovery NFSv4: Fix NFSv4 trunking discovery NFSv4: Fix NFSv4 reference counting for trunked sessions NFS: Fix error reporting in nfs_xdev_mount
This commit is contained in:
commit
bf6c8a8148
|
@ -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)
|
||||
|
|
|
@ -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 */
|
||||
|
||||
|
|
|
@ -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;
|
||||
}
|
||||
|
|
|
@ -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:
|
||||
if (IS_ERR(server))
|
||||
mntroot = ERR_CAST(server);
|
||||
else
|
||||
mntroot = nfs_fs_mount_common(server, flags,
|
||||
dev_name, &mount_info, nfs_mod);
|
||||
|
||||
dprintk("<-- nfs_xdev_mount() = %ld\n",
|
||||
IS_ERR(mntroot) ? PTR_ERR(mntroot) : 0L);
|
||||
return mntroot;
|
||||
|
||||
out_err:
|
||||
dprintk("<-- nfs_xdev_mount_common() = %d [error]\n", error);
|
||||
goto out;
|
||||
}
|
||||
|
||||
#if IS_ENABLED(CONFIG_NFS_V4)
|
||||
|
|
|
@ -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)
|
||||
|
|
Loading…
Reference in New Issue