Commit b8ea0d06 authored by Linus Torvalds's avatar Linus Torvalds

Merge tag 'nfs-for-3.11-4' of git://git.linux-nfs.org/projects/trondmy/linux-nfs

Pull NFS client bugfixes from Trond Myklebust:

 - Stable patch for lockd to fix Oopses due to inappropriate calls to
   utsname()->nodename

 - Stable patches for sunrpc to fix Oopses on shutdown when using
   AF_LOCAL sockets with rpcbind

 - Fix memory leak and error checking issues in nfs4_proc_lookup_mountpoint

 - Fix a regression with the sync mount option failing to work for nfs4
   mounts

 - Fix a writeback performance issue when doing cache invalidation

 - Remove an incorrect call to nfs_setsecurity in nfs_fhget

* tag 'nfs-for-3.11-4' of git://git.linux-nfs.org/projects/trondmy/linux-nfs:
  NFSv4: Fix up nfs4_proc_lookup_mountpoint
  NFS: Remove unnecessary call to nfs_setsecurity in nfs_fhget()
  NFSv4: Fix the sync mount option for nfs4 mounts
  NFS: Fix writeback performance issue on cache invalidation
  SUNRPC: If the rpcbind channel is disconnected, fail the call to unregister
  SUNRPC: Don't auto-disconnect from the local rpcbind socket
  LOCKD: Don't call utsname()->nodename from nlmclnt_setlockargs
parents 022e5d09 b72888cb
...@@ -64,12 +64,17 @@ struct nlm_host *nlmclnt_init(const struct nlmclnt_initdata *nlm_init) ...@@ -64,12 +64,17 @@ struct nlm_host *nlmclnt_init(const struct nlmclnt_initdata *nlm_init)
nlm_init->protocol, nlm_version, nlm_init->protocol, nlm_version,
nlm_init->hostname, nlm_init->noresvport, nlm_init->hostname, nlm_init->noresvport,
nlm_init->net); nlm_init->net);
if (host == NULL) { if (host == NULL)
lockd_down(nlm_init->net); goto out_nohost;
return ERR_PTR(-ENOLCK); if (host->h_rpcclnt == NULL && nlm_bind_host(host) == NULL)
} goto out_nobind;
return host; return host;
out_nobind:
nlmclnt_release_host(host);
out_nohost:
lockd_down(nlm_init->net);
return ERR_PTR(-ENOLCK);
} }
EXPORT_SYMBOL_GPL(nlmclnt_init); EXPORT_SYMBOL_GPL(nlmclnt_init);
......
...@@ -125,14 +125,15 @@ static void nlmclnt_setlockargs(struct nlm_rqst *req, struct file_lock *fl) ...@@ -125,14 +125,15 @@ static void nlmclnt_setlockargs(struct nlm_rqst *req, struct file_lock *fl)
{ {
struct nlm_args *argp = &req->a_args; struct nlm_args *argp = &req->a_args;
struct nlm_lock *lock = &argp->lock; struct nlm_lock *lock = &argp->lock;
char *nodename = req->a_host->h_rpcclnt->cl_nodename;
nlmclnt_next_cookie(&argp->cookie); nlmclnt_next_cookie(&argp->cookie);
memcpy(&lock->fh, NFS_FH(file_inode(fl->fl_file)), sizeof(struct nfs_fh)); memcpy(&lock->fh, NFS_FH(file_inode(fl->fl_file)), sizeof(struct nfs_fh));
lock->caller = utsname()->nodename; lock->caller = nodename;
lock->oh.data = req->a_owner; lock->oh.data = req->a_owner;
lock->oh.len = snprintf(req->a_owner, sizeof(req->a_owner), "%u@%s", lock->oh.len = snprintf(req->a_owner, sizeof(req->a_owner), "%u@%s",
(unsigned int)fl->fl_u.nfs_fl.owner->pid, (unsigned int)fl->fl_u.nfs_fl.owner->pid,
utsname()->nodename); nodename);
lock->svid = fl->fl_u.nfs_fl.owner->pid; lock->svid = fl->fl_u.nfs_fl.owner->pid;
lock->fl.fl_start = fl->fl_start; lock->fl.fl_start = fl->fl_start;
lock->fl.fl_end = fl->fl_end; lock->fl.fl_end = fl->fl_end;
......
...@@ -463,7 +463,6 @@ nfs_fhget(struct super_block *sb, struct nfs_fh *fh, struct nfs_fattr *fattr, st ...@@ -463,7 +463,6 @@ nfs_fhget(struct super_block *sb, struct nfs_fh *fh, struct nfs_fattr *fattr, st
unlock_new_inode(inode); unlock_new_inode(inode);
} else } else
nfs_refresh_inode(inode, fattr); nfs_refresh_inode(inode, fattr);
nfs_setsecurity(inode, fattr, label);
dprintk("NFS: nfs_fhget(%s/%Ld fh_crc=0x%08x ct=%d)\n", dprintk("NFS: nfs_fhget(%s/%Ld fh_crc=0x%08x ct=%d)\n",
inode->i_sb->s_id, inode->i_sb->s_id,
(long long)NFS_FILEID(inode), (long long)NFS_FILEID(inode),
...@@ -963,9 +962,15 @@ EXPORT_SYMBOL_GPL(nfs_revalidate_inode); ...@@ -963,9 +962,15 @@ EXPORT_SYMBOL_GPL(nfs_revalidate_inode);
static int nfs_invalidate_mapping(struct inode *inode, struct address_space *mapping) static int nfs_invalidate_mapping(struct inode *inode, struct address_space *mapping)
{ {
struct nfs_inode *nfsi = NFS_I(inode); struct nfs_inode *nfsi = NFS_I(inode);
int ret;
if (mapping->nrpages != 0) { if (mapping->nrpages != 0) {
int ret = invalidate_inode_pages2(mapping); if (S_ISREG(inode->i_mode)) {
ret = nfs_sync_mapping(mapping);
if (ret < 0)
return ret;
}
ret = invalidate_inode_pages2(mapping);
if (ret < 0) if (ret < 0)
return ret; return ret;
} }
......
...@@ -3071,15 +3071,13 @@ struct rpc_clnt * ...@@ -3071,15 +3071,13 @@ struct rpc_clnt *
nfs4_proc_lookup_mountpoint(struct inode *dir, struct qstr *name, nfs4_proc_lookup_mountpoint(struct inode *dir, struct qstr *name,
struct nfs_fh *fhandle, struct nfs_fattr *fattr) struct nfs_fh *fhandle, struct nfs_fattr *fattr)
{ {
struct rpc_clnt *client = NFS_CLIENT(dir);
int status; int status;
struct rpc_clnt *client = rpc_clone_client(NFS_CLIENT(dir));
status = nfs4_proc_lookup_common(&client, dir, name, fhandle, fattr, NULL); status = nfs4_proc_lookup_common(&client, dir, name, fhandle, fattr, NULL);
if (status < 0) { if (status < 0)
rpc_shutdown_client(client);
return ERR_PTR(status); return ERR_PTR(status);
} return (client == NFS_CLIENT(dir)) ? rpc_clone_client(client) : client;
return client;
} }
static int _nfs4_proc_access(struct inode *inode, struct nfs_access_entry *entry) static int _nfs4_proc_access(struct inode *inode, struct nfs_access_entry *entry)
......
...@@ -2478,6 +2478,10 @@ struct dentry *nfs_fs_mount_common(struct nfs_server *server, ...@@ -2478,6 +2478,10 @@ struct dentry *nfs_fs_mount_common(struct nfs_server *server,
if (server->flags & NFS_MOUNT_NOAC) if (server->flags & NFS_MOUNT_NOAC)
sb_mntdata.mntflags |= MS_SYNCHRONOUS; sb_mntdata.mntflags |= MS_SYNCHRONOUS;
if (mount_info->cloned != NULL && mount_info->cloned->sb != NULL)
if (mount_info->cloned->sb->s_flags & MS_SYNCHRONOUS)
sb_mntdata.mntflags |= MS_SYNCHRONOUS;
/* Get a superblock - note that we may end up sharing one that already exists */ /* Get a superblock - note that we may end up sharing one that already exists */
s = sget(nfs_mod->nfs_fs, compare_super, nfs_set_super, flags, &sb_mntdata); s = sget(nfs_mod->nfs_fs, compare_super, nfs_set_super, flags, &sb_mntdata);
if (IS_ERR(s)) { if (IS_ERR(s)) {
......
...@@ -121,6 +121,7 @@ struct rpc_task_setup { ...@@ -121,6 +121,7 @@ struct rpc_task_setup {
#define RPC_TASK_SOFTCONN 0x0400 /* Fail if can't connect */ #define RPC_TASK_SOFTCONN 0x0400 /* Fail if can't connect */
#define RPC_TASK_SENT 0x0800 /* message was sent */ #define RPC_TASK_SENT 0x0800 /* message was sent */
#define RPC_TASK_TIMEOUT 0x1000 /* fail with ETIMEDOUT on timeout */ #define RPC_TASK_TIMEOUT 0x1000 /* fail with ETIMEDOUT on timeout */
#define RPC_TASK_NOCONNECT 0x2000 /* return ENOTCONN if not connected */
#define RPC_IS_ASYNC(t) ((t)->tk_flags & RPC_TASK_ASYNC) #define RPC_IS_ASYNC(t) ((t)->tk_flags & RPC_TASK_ASYNC)
#define RPC_IS_SWAPPER(t) ((t)->tk_flags & RPC_TASK_SWAPPER) #define RPC_IS_SWAPPER(t) ((t)->tk_flags & RPC_TASK_SWAPPER)
......
...@@ -1660,6 +1660,10 @@ call_connect(struct rpc_task *task) ...@@ -1660,6 +1660,10 @@ call_connect(struct rpc_task *task)
task->tk_action = call_connect_status; task->tk_action = call_connect_status;
if (task->tk_status < 0) if (task->tk_status < 0)
return; return;
if (task->tk_flags & RPC_TASK_NOCONNECT) {
rpc_exit(task, -ENOTCONN);
return;
}
xprt_connect(task); xprt_connect(task);
} }
} }
......
...@@ -23,6 +23,7 @@ struct sunrpc_net { ...@@ -23,6 +23,7 @@ struct sunrpc_net {
struct rpc_clnt *rpcb_local_clnt4; struct rpc_clnt *rpcb_local_clnt4;
spinlock_t rpcb_clnt_lock; spinlock_t rpcb_clnt_lock;
unsigned int rpcb_users; unsigned int rpcb_users;
unsigned int rpcb_is_af_local : 1;
struct mutex gssp_lock; struct mutex gssp_lock;
wait_queue_head_t gssp_wq; wait_queue_head_t gssp_wq;
......
...@@ -204,13 +204,15 @@ void rpcb_put_local(struct net *net) ...@@ -204,13 +204,15 @@ void rpcb_put_local(struct net *net)
} }
static void rpcb_set_local(struct net *net, struct rpc_clnt *clnt, static void rpcb_set_local(struct net *net, struct rpc_clnt *clnt,
struct rpc_clnt *clnt4) struct rpc_clnt *clnt4,
bool is_af_local)
{ {
struct sunrpc_net *sn = net_generic(net, sunrpc_net_id); struct sunrpc_net *sn = net_generic(net, sunrpc_net_id);
/* Protected by rpcb_create_local_mutex */ /* Protected by rpcb_create_local_mutex */
sn->rpcb_local_clnt = clnt; sn->rpcb_local_clnt = clnt;
sn->rpcb_local_clnt4 = clnt4; sn->rpcb_local_clnt4 = clnt4;
sn->rpcb_is_af_local = is_af_local ? 1 : 0;
smp_wmb(); smp_wmb();
sn->rpcb_users = 1; sn->rpcb_users = 1;
dprintk("RPC: created new rpcb local clients (rpcb_local_clnt: " dprintk("RPC: created new rpcb local clients (rpcb_local_clnt: "
...@@ -238,6 +240,14 @@ static int rpcb_create_local_unix(struct net *net) ...@@ -238,6 +240,14 @@ static int rpcb_create_local_unix(struct net *net)
.program = &rpcb_program, .program = &rpcb_program,
.version = RPCBVERS_2, .version = RPCBVERS_2,
.authflavor = RPC_AUTH_NULL, .authflavor = RPC_AUTH_NULL,
/*
* We turn off the idle timeout to prevent the kernel
* from automatically disconnecting the socket.
* Otherwise, we'd have to cache the mount namespace
* of the caller and somehow pass that to the socket
* reconnect code.
*/
.flags = RPC_CLNT_CREATE_NO_IDLE_TIMEOUT,
}; };
struct rpc_clnt *clnt, *clnt4; struct rpc_clnt *clnt, *clnt4;
int result = 0; int result = 0;
...@@ -263,7 +273,7 @@ static int rpcb_create_local_unix(struct net *net) ...@@ -263,7 +273,7 @@ static int rpcb_create_local_unix(struct net *net)
clnt4 = NULL; clnt4 = NULL;
} }
rpcb_set_local(net, clnt, clnt4); rpcb_set_local(net, clnt, clnt4, true);
out: out:
return result; return result;
...@@ -315,7 +325,7 @@ static int rpcb_create_local_net(struct net *net) ...@@ -315,7 +325,7 @@ static int rpcb_create_local_net(struct net *net)
clnt4 = NULL; clnt4 = NULL;
} }
rpcb_set_local(net, clnt, clnt4); rpcb_set_local(net, clnt, clnt4, false);
out: out:
return result; return result;
...@@ -376,13 +386,16 @@ static struct rpc_clnt *rpcb_create(struct net *net, const char *hostname, ...@@ -376,13 +386,16 @@ static struct rpc_clnt *rpcb_create(struct net *net, const char *hostname,
return rpc_create(&args); return rpc_create(&args);
} }
static int rpcb_register_call(struct rpc_clnt *clnt, struct rpc_message *msg) static int rpcb_register_call(struct sunrpc_net *sn, struct rpc_clnt *clnt, struct rpc_message *msg, bool is_set)
{ {
int result, error = 0; int flags = RPC_TASK_NOCONNECT;
int error, result = 0;
if (is_set || !sn->rpcb_is_af_local)
flags = RPC_TASK_SOFTCONN;
msg->rpc_resp = &result; msg->rpc_resp = &result;
error = rpc_call_sync(clnt, msg, RPC_TASK_SOFTCONN); error = rpc_call_sync(clnt, msg, flags);
if (error < 0) { if (error < 0) {
dprintk("RPC: failed to contact local rpcbind " dprintk("RPC: failed to contact local rpcbind "
"server (errno %d).\n", -error); "server (errno %d).\n", -error);
...@@ -439,16 +452,19 @@ int rpcb_register(struct net *net, u32 prog, u32 vers, int prot, unsigned short ...@@ -439,16 +452,19 @@ int rpcb_register(struct net *net, u32 prog, u32 vers, int prot, unsigned short
.rpc_argp = &map, .rpc_argp = &map,
}; };
struct sunrpc_net *sn = net_generic(net, sunrpc_net_id); struct sunrpc_net *sn = net_generic(net, sunrpc_net_id);
bool is_set = false;
dprintk("RPC: %sregistering (%u, %u, %d, %u) with local " dprintk("RPC: %sregistering (%u, %u, %d, %u) with local "
"rpcbind\n", (port ? "" : "un"), "rpcbind\n", (port ? "" : "un"),
prog, vers, prot, port); prog, vers, prot, port);
msg.rpc_proc = &rpcb_procedures2[RPCBPROC_UNSET]; msg.rpc_proc = &rpcb_procedures2[RPCBPROC_UNSET];
if (port) if (port != 0) {
msg.rpc_proc = &rpcb_procedures2[RPCBPROC_SET]; msg.rpc_proc = &rpcb_procedures2[RPCBPROC_SET];
is_set = true;
}
return rpcb_register_call(sn->rpcb_local_clnt, &msg); return rpcb_register_call(sn, sn->rpcb_local_clnt, &msg, is_set);
} }
/* /*
...@@ -461,6 +477,7 @@ static int rpcb_register_inet4(struct sunrpc_net *sn, ...@@ -461,6 +477,7 @@ static int rpcb_register_inet4(struct sunrpc_net *sn,
const struct sockaddr_in *sin = (const struct sockaddr_in *)sap; const struct sockaddr_in *sin = (const struct sockaddr_in *)sap;
struct rpcbind_args *map = msg->rpc_argp; struct rpcbind_args *map = msg->rpc_argp;
unsigned short port = ntohs(sin->sin_port); unsigned short port = ntohs(sin->sin_port);
bool is_set = false;
int result; int result;
map->r_addr = rpc_sockaddr2uaddr(sap, GFP_KERNEL); map->r_addr = rpc_sockaddr2uaddr(sap, GFP_KERNEL);
...@@ -471,10 +488,12 @@ static int rpcb_register_inet4(struct sunrpc_net *sn, ...@@ -471,10 +488,12 @@ static int rpcb_register_inet4(struct sunrpc_net *sn,
map->r_addr, map->r_netid); map->r_addr, map->r_netid);
msg->rpc_proc = &rpcb_procedures4[RPCBPROC_UNSET]; msg->rpc_proc = &rpcb_procedures4[RPCBPROC_UNSET];
if (port) if (port != 0) {
msg->rpc_proc = &rpcb_procedures4[RPCBPROC_SET]; msg->rpc_proc = &rpcb_procedures4[RPCBPROC_SET];
is_set = true;
}
result = rpcb_register_call(sn->rpcb_local_clnt4, msg); result = rpcb_register_call(sn, sn->rpcb_local_clnt4, msg, is_set);
kfree(map->r_addr); kfree(map->r_addr);
return result; return result;
} }
...@@ -489,6 +508,7 @@ static int rpcb_register_inet6(struct sunrpc_net *sn, ...@@ -489,6 +508,7 @@ static int rpcb_register_inet6(struct sunrpc_net *sn,
const struct sockaddr_in6 *sin6 = (const struct sockaddr_in6 *)sap; const struct sockaddr_in6 *sin6 = (const struct sockaddr_in6 *)sap;
struct rpcbind_args *map = msg->rpc_argp; struct rpcbind_args *map = msg->rpc_argp;
unsigned short port = ntohs(sin6->sin6_port); unsigned short port = ntohs(sin6->sin6_port);
bool is_set = false;
int result; int result;
map->r_addr = rpc_sockaddr2uaddr(sap, GFP_KERNEL); map->r_addr = rpc_sockaddr2uaddr(sap, GFP_KERNEL);
...@@ -499,10 +519,12 @@ static int rpcb_register_inet6(struct sunrpc_net *sn, ...@@ -499,10 +519,12 @@ static int rpcb_register_inet6(struct sunrpc_net *sn,
map->r_addr, map->r_netid); map->r_addr, map->r_netid);
msg->rpc_proc = &rpcb_procedures4[RPCBPROC_UNSET]; msg->rpc_proc = &rpcb_procedures4[RPCBPROC_UNSET];
if (port) if (port != 0) {
msg->rpc_proc = &rpcb_procedures4[RPCBPROC_SET]; msg->rpc_proc = &rpcb_procedures4[RPCBPROC_SET];
is_set = true;
}
result = rpcb_register_call(sn->rpcb_local_clnt4, msg); result = rpcb_register_call(sn, sn->rpcb_local_clnt4, msg, is_set);
kfree(map->r_addr); kfree(map->r_addr);
return result; return result;
} }
...@@ -519,7 +541,7 @@ static int rpcb_unregister_all_protofamilies(struct sunrpc_net *sn, ...@@ -519,7 +541,7 @@ static int rpcb_unregister_all_protofamilies(struct sunrpc_net *sn,
map->r_addr = ""; map->r_addr = "";
msg->rpc_proc = &rpcb_procedures4[RPCBPROC_UNSET]; msg->rpc_proc = &rpcb_procedures4[RPCBPROC_UNSET];
return rpcb_register_call(sn->rpcb_local_clnt4, msg); return rpcb_register_call(sn, sn->rpcb_local_clnt4, msg, false);
} }
/** /**
......
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