Linux kernel mirror (for testing) git.kernel.org/pub/scm/linux/kernel/git/torvalds/linux.git
kernel os linux

LOCKD: Don't call utsname()->nodename from nlmclnt_setlockargs

Firstly, nlmclnt_setlockargs can be called from a reclaimer thread, in
which case we're in entirely the wrong namespace.

Secondly, commit 8aac62706adaaf0fab02c4327761561c8bda9448 (move
exit_task_namespaces() outside of exit_notify()) now means that
exit_task_work() is called after exit_task_namespaces(), which
triggers an Oops when we're freeing up the locks.

Fix this by ensuring that we initialise the nlm_host's rpc_client at mount
time, so that the cl_nodename field is initialised to the value of
utsname()->nodename that the net namespace uses. Then replace the
lockd callers of utsname()->nodename.

Signed-off-by: Trond Myklebust <Trond.Myklebust@netapp.com>
Cc: Toralf Förster <toralf.foerster@gmx.de>
Cc: Oleg Nesterov <oleg@redhat.com>
Cc: Nix <nix@esperi.org.uk>
Cc: Jeff Layton <jlayton@redhat.com>
Cc: stable@vger.kernel.org # 3.10.x

+12 -6
+9 -4
fs/lockd/clntlock.c
··· 64 64 nlm_init->protocol, nlm_version, 65 65 nlm_init->hostname, nlm_init->noresvport, 66 66 nlm_init->net); 67 - if (host == NULL) { 68 - lockd_down(nlm_init->net); 69 - return ERR_PTR(-ENOLCK); 70 - } 67 + if (host == NULL) 68 + goto out_nohost; 69 + if (host->h_rpcclnt == NULL && nlm_bind_host(host) == NULL) 70 + goto out_nobind; 71 71 72 72 return host; 73 + out_nobind: 74 + nlmclnt_release_host(host); 75 + out_nohost: 76 + lockd_down(nlm_init->net); 77 + return ERR_PTR(-ENOLCK); 73 78 } 74 79 EXPORT_SYMBOL_GPL(nlmclnt_init); 75 80
+3 -2
fs/lockd/clntproc.c
··· 125 125 { 126 126 struct nlm_args *argp = &req->a_args; 127 127 struct nlm_lock *lock = &argp->lock; 128 + char *nodename = req->a_host->h_rpcclnt->cl_nodename; 128 129 129 130 nlmclnt_next_cookie(&argp->cookie); 130 131 memcpy(&lock->fh, NFS_FH(file_inode(fl->fl_file)), sizeof(struct nfs_fh)); 131 - lock->caller = utsname()->nodename; 132 + lock->caller = nodename; 132 133 lock->oh.data = req->a_owner; 133 134 lock->oh.len = snprintf(req->a_owner, sizeof(req->a_owner), "%u@%s", 134 135 (unsigned int)fl->fl_u.nfs_fl.owner->pid, 135 - utsname()->nodename); 136 + nodename); 136 137 lock->svid = fl->fl_u.nfs_fl.owner->pid; 137 138 lock->fl.fl_start = fl->fl_start; 138 139 lock->fl.fl_end = fl->fl_end;