Commit a2a32cd1 authored by Linus Torvalds's avatar Linus Torvalds

Merge tag 'nfs-for-3.19-2' of git://git.linux-nfs.org/projects/trondmy/linux-nfs

Pull NFS client bugfixes from Trond Myklebust:
 "Highlights include:

   - Stable fix for a NFSv3/lockd race
   - Fixes for several NFSv4.1 client id trunking bugs
   - Remove an incorrect test when checking for delegated opens"

* tag 'nfs-for-3.19-2' of git://git.linux-nfs.org/projects/trondmy/linux-nfs:
  NFSv4: Remove incorrect check in can_open_delegated()
  NFS: Ignore transport protocol when detecting server trunking
  NFSv4/v4.1: Verify the client owner id during trunking detection
  NFSv4: Cache the NFSv4/v4.1 client owner_id in the struct nfs_client
  NFSv4.1: Fix client id trunking on Linux
  LOCKD: Fix a race when initialising nlmsvc_timeout
parents 23aa4b41 4e379d36
...@@ -138,10 +138,6 @@ lockd(void *vrqstp) ...@@ -138,10 +138,6 @@ lockd(void *vrqstp)
dprintk("NFS locking service started (ver " LOCKD_VERSION ").\n"); dprintk("NFS locking service started (ver " LOCKD_VERSION ").\n");
if (!nlm_timeout)
nlm_timeout = LOCKD_DFLT_TIMEO;
nlmsvc_timeout = nlm_timeout * HZ;
/* /*
* The main request loop. We don't terminate until the last * The main request loop. We don't terminate until the last
* NFS mount or NFS daemon has gone away. * NFS mount or NFS daemon has gone away.
...@@ -350,6 +346,10 @@ static struct svc_serv *lockd_create_svc(void) ...@@ -350,6 +346,10 @@ static struct svc_serv *lockd_create_svc(void)
printk(KERN_WARNING printk(KERN_WARNING
"lockd_up: no pid, %d users??\n", nlmsvc_users); "lockd_up: no pid, %d users??\n", nlmsvc_users);
if (!nlm_timeout)
nlm_timeout = LOCKD_DFLT_TIMEO;
nlmsvc_timeout = nlm_timeout * HZ;
serv = svc_create(&nlmsvc_program, LOCKD_BUFSIZE, svc_rpcb_cleanup); serv = svc_create(&nlmsvc_program, LOCKD_BUFSIZE, svc_rpcb_cleanup);
if (!serv) { if (!serv) {
printk(KERN_WARNING "lockd_up: create service failed\n"); printk(KERN_WARNING "lockd_up: create service failed\n");
......
...@@ -228,6 +228,7 @@ static void nfs4_shutdown_client(struct nfs_client *clp) ...@@ -228,6 +228,7 @@ static void nfs4_shutdown_client(struct nfs_client *clp)
kfree(clp->cl_serverowner); kfree(clp->cl_serverowner);
kfree(clp->cl_serverscope); kfree(clp->cl_serverscope);
kfree(clp->cl_implid); kfree(clp->cl_implid);
kfree(clp->cl_owner_id);
} }
void nfs4_free_client(struct nfs_client *clp) void nfs4_free_client(struct nfs_client *clp)
...@@ -452,6 +453,14 @@ static void nfs4_swap_callback_idents(struct nfs_client *keep, ...@@ -452,6 +453,14 @@ static void nfs4_swap_callback_idents(struct nfs_client *keep,
spin_unlock(&nn->nfs_client_lock); spin_unlock(&nn->nfs_client_lock);
} }
static bool nfs4_match_client_owner_id(const struct nfs_client *clp1,
const struct nfs_client *clp2)
{
if (clp1->cl_owner_id == NULL || clp2->cl_owner_id == NULL)
return true;
return strcmp(clp1->cl_owner_id, clp2->cl_owner_id) == 0;
}
/** /**
* nfs40_walk_client_list - Find server that recognizes a client ID * nfs40_walk_client_list - Find server that recognizes a client ID
* *
...@@ -483,9 +492,6 @@ int nfs40_walk_client_list(struct nfs_client *new, ...@@ -483,9 +492,6 @@ int nfs40_walk_client_list(struct nfs_client *new,
if (pos->rpc_ops != new->rpc_ops) if (pos->rpc_ops != new->rpc_ops)
continue; continue;
if (pos->cl_proto != new->cl_proto)
continue;
if (pos->cl_minorversion != new->cl_minorversion) if (pos->cl_minorversion != new->cl_minorversion)
continue; continue;
...@@ -510,6 +516,9 @@ int nfs40_walk_client_list(struct nfs_client *new, ...@@ -510,6 +516,9 @@ int nfs40_walk_client_list(struct nfs_client *new,
if (pos->cl_clientid != new->cl_clientid) if (pos->cl_clientid != new->cl_clientid)
continue; continue;
if (!nfs4_match_client_owner_id(pos, new))
continue;
atomic_inc(&pos->cl_count); atomic_inc(&pos->cl_count);
spin_unlock(&nn->nfs_client_lock); spin_unlock(&nn->nfs_client_lock);
...@@ -566,20 +575,14 @@ static bool nfs4_match_clientids(struct nfs_client *a, struct nfs_client *b) ...@@ -566,20 +575,14 @@ static bool nfs4_match_clientids(struct nfs_client *a, struct nfs_client *b)
} }
/* /*
* Returns true if the server owners match * Returns true if the server major ids match
*/ */
static bool static bool
nfs4_match_serverowners(struct nfs_client *a, struct nfs_client *b) nfs4_check_clientid_trunking(struct nfs_client *a, struct nfs_client *b)
{ {
struct nfs41_server_owner *o1 = a->cl_serverowner; struct nfs41_server_owner *o1 = a->cl_serverowner;
struct nfs41_server_owner *o2 = b->cl_serverowner; struct nfs41_server_owner *o2 = b->cl_serverowner;
if (o1->minor_id != o2->minor_id) {
dprintk("NFS: --> %s server owner minor IDs do not match\n",
__func__);
return false;
}
if (o1->major_id_sz != o2->major_id_sz) if (o1->major_id_sz != o2->major_id_sz)
goto out_major_mismatch; goto out_major_mismatch;
if (memcmp(o1->major_id, o2->major_id, o1->major_id_sz) != 0) if (memcmp(o1->major_id, o2->major_id, o1->major_id_sz) != 0)
...@@ -621,9 +624,6 @@ int nfs41_walk_client_list(struct nfs_client *new, ...@@ -621,9 +624,6 @@ int nfs41_walk_client_list(struct nfs_client *new,
if (pos->rpc_ops != new->rpc_ops) if (pos->rpc_ops != new->rpc_ops)
continue; continue;
if (pos->cl_proto != new->cl_proto)
continue;
if (pos->cl_minorversion != new->cl_minorversion) if (pos->cl_minorversion != new->cl_minorversion)
continue; continue;
...@@ -654,7 +654,19 @@ int nfs41_walk_client_list(struct nfs_client *new, ...@@ -654,7 +654,19 @@ int nfs41_walk_client_list(struct nfs_client *new,
if (!nfs4_match_clientids(pos, new)) if (!nfs4_match_clientids(pos, new))
continue; continue;
if (!nfs4_match_serverowners(pos, new)) /*
* Note that session trunking is just a special subcase of
* client id trunking. In either case, we want to fall back
* to using the existing nfs_client.
*/
if (!nfs4_check_clientid_trunking(pos, new))
continue;
/* Unlike NFSv4.0, we know that NFSv4.1 always uses the
* uniform string, however someone might switch the
* uniquifier string on us.
*/
if (!nfs4_match_client_owner_id(pos, new))
continue; continue;
atomic_inc(&pos->cl_count); atomic_inc(&pos->cl_count);
......
...@@ -1117,8 +1117,6 @@ static int can_open_delegated(struct nfs_delegation *delegation, fmode_t fmode) ...@@ -1117,8 +1117,6 @@ static int can_open_delegated(struct nfs_delegation *delegation, fmode_t fmode)
return 0; return 0;
if ((delegation->type & fmode) != fmode) if ((delegation->type & fmode) != fmode)
return 0; return 0;
if (test_bit(NFS_DELEGATION_NEED_RECLAIM, &delegation->flags))
return 0;
if (test_bit(NFS_DELEGATION_RETURNING, &delegation->flags)) if (test_bit(NFS_DELEGATION_RETURNING, &delegation->flags))
return 0; return 0;
nfs_mark_delegation_referenced(delegation); nfs_mark_delegation_referenced(delegation);
...@@ -4917,11 +4915,14 @@ static void nfs4_init_boot_verifier(const struct nfs_client *clp, ...@@ -4917,11 +4915,14 @@ static void nfs4_init_boot_verifier(const struct nfs_client *clp,
} }
static unsigned int static unsigned int
nfs4_init_nonuniform_client_string(const struct nfs_client *clp, nfs4_init_nonuniform_client_string(struct nfs_client *clp,
char *buf, size_t len) char *buf, size_t len)
{ {
unsigned int result; unsigned int result;
if (clp->cl_owner_id != NULL)
return strlcpy(buf, clp->cl_owner_id, len);
rcu_read_lock(); rcu_read_lock();
result = scnprintf(buf, len, "Linux NFSv4.0 %s/%s %s", result = scnprintf(buf, len, "Linux NFSv4.0 %s/%s %s",
clp->cl_ipaddr, clp->cl_ipaddr,
...@@ -4930,24 +4931,32 @@ nfs4_init_nonuniform_client_string(const struct nfs_client *clp, ...@@ -4930,24 +4931,32 @@ nfs4_init_nonuniform_client_string(const struct nfs_client *clp,
rpc_peeraddr2str(clp->cl_rpcclient, rpc_peeraddr2str(clp->cl_rpcclient,
RPC_DISPLAY_PROTO)); RPC_DISPLAY_PROTO));
rcu_read_unlock(); rcu_read_unlock();
clp->cl_owner_id = kstrdup(buf, GFP_KERNEL);
return result; return result;
} }
static unsigned int static unsigned int
nfs4_init_uniform_client_string(const struct nfs_client *clp, nfs4_init_uniform_client_string(struct nfs_client *clp,
char *buf, size_t len) char *buf, size_t len)
{ {
const char *nodename = clp->cl_rpcclient->cl_nodename; const char *nodename = clp->cl_rpcclient->cl_nodename;
unsigned int result;
if (clp->cl_owner_id != NULL)
return strlcpy(buf, clp->cl_owner_id, len);
if (nfs4_client_id_uniquifier[0] != '\0') if (nfs4_client_id_uniquifier[0] != '\0')
return scnprintf(buf, len, "Linux NFSv%u.%u %s/%s", result = scnprintf(buf, len, "Linux NFSv%u.%u %s/%s",
clp->rpc_ops->version, clp->rpc_ops->version,
clp->cl_minorversion, clp->cl_minorversion,
nfs4_client_id_uniquifier, nfs4_client_id_uniquifier,
nodename); nodename);
return scnprintf(buf, len, "Linux NFSv%u.%u %s", else
result = scnprintf(buf, len, "Linux NFSv%u.%u %s",
clp->rpc_ops->version, clp->cl_minorversion, clp->rpc_ops->version, clp->cl_minorversion,
nodename); nodename);
clp->cl_owner_id = kstrdup(buf, GFP_KERNEL);
return result;
} }
/* /*
......
...@@ -74,6 +74,9 @@ struct nfs_client { ...@@ -74,6 +74,9 @@ struct nfs_client {
/* idmapper */ /* idmapper */
struct idmap * cl_idmap; struct idmap * cl_idmap;
/* Client owner identifier */
const char * cl_owner_id;
/* Our own IP address, as a null-terminated string. /* Our own IP address, as a null-terminated string.
* This is used to generate the mv0 callback address. * This is used to generate the mv0 callback address.
*/ */
......
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment