Commit 529acf58 authored by Linus Torvalds's avatar Linus Torvalds

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

Pull NFS client bugfixes from Trond Myklebust:
 - Fixes for the NFSv4 security negotiation
 - Use the correct hostname when mounting from a private namespace
 - NFS net namespace bugfixes for the pipefs filesystem
 - NFSv4 GETACL bugfixes
 - IPv6 bugfix for NFSv4 referrals

* tag 'nfs-for-3.4-4' of git://git.linux-nfs.org/projects/trondmy/linux-nfs:
  NFSv4.1: Use the correct hostname in the client identifier string
  SUNRPC: RPC client must use the current utsname hostname string
  NFS: get module in idmap PipeFS notifier callback
  NFS: Remove unused function nfs_lookup_with_sec()
  NFS: Honor the authflavor set in the clone mount data
  NFS: Fix following referral mount points with different security
  NFS: Do secinfo as part of lookup
  NFS: Handle exceptions coming out of nfs4_proc_fs_locations()
  NFS: Fix SECINFO_NO_NAME
  SUNRPC: traverse clients tree on PipeFS event
  SUNRPC: set per-net PipeFS superblock before notification
  SUNRPC: skip clients with program without PipeFS entries
  SUNRPC: skip dead but not buried clients on PipeFS events
  Avoid beyond bounds copy while caching ACL
  Avoid reading past buffer when calling GETACL
  fix page number calculation bug for block layout decode buffer
  NFSv4.1 fix page number calculation bug for filelayout decode buffers
  pnfs-obj: Remove unused variable from objlayout_get_deviceinfo()
  nfs4: fix referrals on mounts that use IPv6 addrs
parents b821861b 3617e503
...@@ -38,6 +38,8 @@ ...@@ -38,6 +38,8 @@
#include <linux/buffer_head.h> /* various write calls */ #include <linux/buffer_head.h> /* various write calls */
#include <linux/prefetch.h> #include <linux/prefetch.h>
#include "../pnfs.h"
#include "../internal.h"
#include "blocklayout.h" #include "blocklayout.h"
#define NFSDBG_FACILITY NFSDBG_PNFS_LD #define NFSDBG_FACILITY NFSDBG_PNFS_LD
...@@ -868,7 +870,7 @@ nfs4_blk_get_deviceinfo(struct nfs_server *server, const struct nfs_fh *fh, ...@@ -868,7 +870,7 @@ nfs4_blk_get_deviceinfo(struct nfs_server *server, const struct nfs_fh *fh,
* GETDEVICEINFO's maxcount * GETDEVICEINFO's maxcount
*/ */
max_resp_sz = server->nfs_client->cl_session->fc_attrs.max_resp_sz; max_resp_sz = server->nfs_client->cl_session->fc_attrs.max_resp_sz;
max_pages = max_resp_sz >> PAGE_SHIFT; max_pages = nfs_page_array_len(0, max_resp_sz);
dprintk("%s max_resp_sz %u max_pages %d\n", dprintk("%s max_resp_sz %u max_pages %d\n",
__func__, max_resp_sz, max_pages); __func__, max_resp_sz, max_pages);
......
...@@ -1729,7 +1729,8 @@ struct nfs_server *nfs4_create_referral_server(struct nfs_clone_mount *data, ...@@ -1729,7 +1729,8 @@ struct nfs_server *nfs4_create_referral_server(struct nfs_clone_mount *data,
*/ */
struct nfs_server *nfs_clone_server(struct nfs_server *source, struct nfs_server *nfs_clone_server(struct nfs_server *source,
struct nfs_fh *fh, struct nfs_fh *fh,
struct nfs_fattr *fattr) struct nfs_fattr *fattr,
rpc_authflavor_t flavor)
{ {
struct nfs_server *server; struct nfs_server *server;
struct nfs_fattr *fattr_fsinfo; struct nfs_fattr *fattr_fsinfo;
...@@ -1758,7 +1759,7 @@ struct nfs_server *nfs_clone_server(struct nfs_server *source, ...@@ -1758,7 +1759,7 @@ struct nfs_server *nfs_clone_server(struct nfs_server *source,
error = nfs_init_server_rpcclient(server, error = nfs_init_server_rpcclient(server,
source->client->cl_timeout, source->client->cl_timeout,
source->client->cl_auth->au_flavor); flavor);
if (error < 0) if (error < 0)
goto out_free_server; goto out_free_server;
if (!IS_ERR(source->client_acl)) if (!IS_ERR(source->client_acl))
......
...@@ -554,12 +554,16 @@ static int rpc_pipefs_event(struct notifier_block *nb, unsigned long event, ...@@ -554,12 +554,16 @@ static int rpc_pipefs_event(struct notifier_block *nb, unsigned long event,
struct nfs_client *clp; struct nfs_client *clp;
int error = 0; int error = 0;
if (!try_module_get(THIS_MODULE))
return 0;
while ((clp = nfs_get_client_for_event(sb->s_fs_info, event))) { while ((clp = nfs_get_client_for_event(sb->s_fs_info, event))) {
error = __rpc_pipefs_event(clp, event, sb); error = __rpc_pipefs_event(clp, event, sb);
nfs_put_client(clp); nfs_put_client(clp);
if (error) if (error)
break; break;
} }
module_put(THIS_MODULE);
return error; return error;
} }
......
...@@ -165,7 +165,8 @@ extern struct nfs_server *nfs4_create_referral_server(struct nfs_clone_mount *, ...@@ -165,7 +165,8 @@ extern struct nfs_server *nfs4_create_referral_server(struct nfs_clone_mount *,
extern void nfs_free_server(struct nfs_server *server); extern void nfs_free_server(struct nfs_server *server);
extern struct nfs_server *nfs_clone_server(struct nfs_server *, extern struct nfs_server *nfs_clone_server(struct nfs_server *,
struct nfs_fh *, struct nfs_fh *,
struct nfs_fattr *); struct nfs_fattr *,
rpc_authflavor_t);
extern void nfs_mark_client_ready(struct nfs_client *clp, int state); extern void nfs_mark_client_ready(struct nfs_client *clp, int state);
extern int nfs4_check_client_ready(struct nfs_client *clp); extern int nfs4_check_client_ready(struct nfs_client *clp);
extern struct nfs_client *nfs4_set_ds_client(struct nfs_client* mds_clp, extern struct nfs_client *nfs4_set_ds_client(struct nfs_client* mds_clp,
...@@ -186,10 +187,10 @@ static inline void nfs_fs_proc_exit(void) ...@@ -186,10 +187,10 @@ static inline void nfs_fs_proc_exit(void)
/* nfs4namespace.c */ /* nfs4namespace.c */
#ifdef CONFIG_NFS_V4 #ifdef CONFIG_NFS_V4
extern struct vfsmount *nfs_do_refmount(struct dentry *dentry); extern struct vfsmount *nfs_do_refmount(struct rpc_clnt *client, struct dentry *dentry);
#else #else
static inline static inline
struct vfsmount *nfs_do_refmount(struct dentry *dentry) struct vfsmount *nfs_do_refmount(struct rpc_clnt *client, struct dentry *dentry)
{ {
return ERR_PTR(-ENOENT); return ERR_PTR(-ENOENT);
} }
...@@ -234,7 +235,6 @@ extern const u32 nfs41_maxwrite_overhead; ...@@ -234,7 +235,6 @@ extern const u32 nfs41_maxwrite_overhead;
/* nfs4proc.c */ /* nfs4proc.c */
#ifdef CONFIG_NFS_V4 #ifdef CONFIG_NFS_V4
extern struct rpc_procinfo nfs4_procedures[]; extern struct rpc_procinfo nfs4_procedures[];
void nfs_fixup_secinfo_attributes(struct nfs_fattr *, struct nfs_fh *);
#endif #endif
extern int nfs4_init_ds_session(struct nfs_client *clp); extern int nfs4_init_ds_session(struct nfs_client *clp);
......
...@@ -148,66 +148,31 @@ rpc_authflavor_t nfs_find_best_sec(struct nfs4_secinfo_flavors *flavors) ...@@ -148,66 +148,31 @@ rpc_authflavor_t nfs_find_best_sec(struct nfs4_secinfo_flavors *flavors)
return pseudoflavor; return pseudoflavor;
} }
static int nfs_negotiate_security(const struct dentry *parent, static struct rpc_clnt *nfs_lookup_mountpoint(struct inode *dir,
const struct dentry *dentry, struct qstr *name,
rpc_authflavor_t *flavor) struct nfs_fh *fh,
{ struct nfs_fattr *fattr)
struct page *page;
struct nfs4_secinfo_flavors *flavors;
int (*secinfo)(struct inode *, const struct qstr *, struct nfs4_secinfo_flavors *);
int ret = -EPERM;
secinfo = NFS_PROTO(parent->d_inode)->secinfo;
if (secinfo != NULL) {
page = alloc_page(GFP_KERNEL);
if (!page) {
ret = -ENOMEM;
goto out;
}
flavors = page_address(page);
ret = secinfo(parent->d_inode, &dentry->d_name, flavors);
*flavor = nfs_find_best_sec(flavors);
put_page(page);
}
out:
return ret;
}
static int nfs_lookup_with_sec(struct nfs_server *server, struct dentry *parent,
struct dentry *dentry, struct path *path,
struct nfs_fh *fh, struct nfs_fattr *fattr,
rpc_authflavor_t *flavor)
{ {
struct rpc_clnt *clone;
struct rpc_auth *auth;
int err; int err;
err = nfs_negotiate_security(parent, path->dentry, flavor); if (NFS_PROTO(dir)->version == 4)
if (err < 0) return nfs4_proc_lookup_mountpoint(dir, name, fh, fattr);
goto out;
clone = rpc_clone_client(server->client); err = NFS_PROTO(dir)->lookup(NFS_SERVER(dir)->client, dir, name, fh, fattr);
auth = rpcauth_create(*flavor, clone); if (err)
if (!auth) { return ERR_PTR(err);
err = -EIO; return rpc_clone_client(NFS_SERVER(dir)->client);
goto out_shutdown;
}
err = server->nfs_client->rpc_ops->lookup(clone, parent->d_inode,
&path->dentry->d_name,
fh, fattr);
out_shutdown:
rpc_shutdown_client(clone);
out:
return err;
} }
#else /* CONFIG_NFS_V4 */ #else /* CONFIG_NFS_V4 */
static inline int nfs_lookup_with_sec(struct nfs_server *server, static inline struct rpc_clnt *nfs_lookup_mountpoint(struct inode *dir,
struct dentry *parent, struct dentry *dentry, struct qstr *name,
struct path *path, struct nfs_fh *fh, struct nfs_fh *fh,
struct nfs_fattr *fattr, struct nfs_fattr *fattr)
rpc_authflavor_t *flavor)
{ {
return -EPERM; int err = NFS_PROTO(dir)->lookup(NFS_SERVER(dir)->client, dir, name, fh, fattr);
if (err)
return ERR_PTR(err);
return rpc_clone_client(NFS_SERVER(dir)->client);
} }
#endif /* CONFIG_NFS_V4 */ #endif /* CONFIG_NFS_V4 */
...@@ -226,12 +191,10 @@ static inline int nfs_lookup_with_sec(struct nfs_server *server, ...@@ -226,12 +191,10 @@ static inline int nfs_lookup_with_sec(struct nfs_server *server,
struct vfsmount *nfs_d_automount(struct path *path) struct vfsmount *nfs_d_automount(struct path *path)
{ {
struct vfsmount *mnt; struct vfsmount *mnt;
struct nfs_server *server = NFS_SERVER(path->dentry->d_inode);
struct dentry *parent; struct dentry *parent;
struct nfs_fh *fh = NULL; struct nfs_fh *fh = NULL;
struct nfs_fattr *fattr = NULL; struct nfs_fattr *fattr = NULL;
int err; struct rpc_clnt *client;
rpc_authflavor_t flavor = RPC_AUTH_UNIX;
dprintk("--> nfs_d_automount()\n"); dprintk("--> nfs_d_automount()\n");
...@@ -249,21 +212,19 @@ struct vfsmount *nfs_d_automount(struct path *path) ...@@ -249,21 +212,19 @@ struct vfsmount *nfs_d_automount(struct path *path)
/* Look it up again to get its attributes */ /* Look it up again to get its attributes */
parent = dget_parent(path->dentry); parent = dget_parent(path->dentry);
err = server->nfs_client->rpc_ops->lookup(server->client, parent->d_inode, client = nfs_lookup_mountpoint(parent->d_inode, &path->dentry->d_name, fh, fattr);
&path->dentry->d_name,
fh, fattr);
if (err == -EPERM && NFS_PROTO(parent->d_inode)->secinfo != NULL)
err = nfs_lookup_with_sec(server, parent, path->dentry, path, fh, fattr, &flavor);
dput(parent); dput(parent);
if (err != 0) { if (IS_ERR(client)) {
mnt = ERR_PTR(err); mnt = ERR_CAST(client);
goto out; goto out;
} }
if (fattr->valid & NFS_ATTR_FATTR_V4_REFERRAL) if (fattr->valid & NFS_ATTR_FATTR_V4_REFERRAL)
mnt = nfs_do_refmount(path->dentry); mnt = nfs_do_refmount(client, path->dentry);
else else
mnt = nfs_do_submount(path->dentry, fh, fattr, flavor); mnt = nfs_do_submount(path->dentry, fh, fattr, client->cl_auth->au_flavor);
rpc_shutdown_client(client);
if (IS_ERR(mnt)) if (IS_ERR(mnt))
goto out; goto out;
......
...@@ -205,6 +205,9 @@ struct nfs4_state_maintenance_ops { ...@@ -205,6 +205,9 @@ struct nfs4_state_maintenance_ops {
extern const struct dentry_operations nfs4_dentry_operations; extern const struct dentry_operations nfs4_dentry_operations;
extern const struct inode_operations nfs4_dir_inode_operations; extern const struct inode_operations nfs4_dir_inode_operations;
/* nfs4namespace.c */
struct rpc_clnt *nfs4_create_sec_client(struct rpc_clnt *, struct inode *, struct qstr *);
/* nfs4proc.c */ /* nfs4proc.c */
extern int nfs4_proc_setclientid(struct nfs_client *, u32, unsigned short, struct rpc_cred *, struct nfs4_setclientid_res *); extern int nfs4_proc_setclientid(struct nfs_client *, u32, unsigned short, struct rpc_cred *, struct nfs4_setclientid_res *);
extern int nfs4_proc_setclientid_confirm(struct nfs_client *, struct nfs4_setclientid_res *arg, struct rpc_cred *); extern int nfs4_proc_setclientid_confirm(struct nfs_client *, struct nfs4_setclientid_res *arg, struct rpc_cred *);
...@@ -213,8 +216,11 @@ extern int nfs4_init_clientid(struct nfs_client *, struct rpc_cred *); ...@@ -213,8 +216,11 @@ extern int nfs4_init_clientid(struct nfs_client *, struct rpc_cred *);
extern int nfs41_init_clientid(struct nfs_client *, struct rpc_cred *); extern int nfs41_init_clientid(struct nfs_client *, struct rpc_cred *);
extern int nfs4_do_close(struct nfs4_state *state, gfp_t gfp_mask, int wait, bool roc); extern int nfs4_do_close(struct nfs4_state *state, gfp_t gfp_mask, int wait, bool roc);
extern int nfs4_server_capabilities(struct nfs_server *server, struct nfs_fh *fhandle); extern int nfs4_server_capabilities(struct nfs_server *server, struct nfs_fh *fhandle);
extern int nfs4_proc_fs_locations(struct inode *dir, const struct qstr *name, extern int nfs4_proc_fs_locations(struct rpc_clnt *, struct inode *, const struct qstr *,
struct nfs4_fs_locations *fs_locations, struct page *page); struct nfs4_fs_locations *, struct page *);
extern struct rpc_clnt *nfs4_proc_lookup_mountpoint(struct inode *, struct qstr *,
struct nfs_fh *, struct nfs_fattr *);
extern int nfs4_proc_secinfo(struct inode *, const struct qstr *, struct nfs4_secinfo_flavors *);
extern int nfs4_release_lockowner(struct nfs4_lock_state *); extern int nfs4_release_lockowner(struct nfs4_lock_state *);
extern const struct xattr_handler *nfs4_xattr_handlers[]; extern const struct xattr_handler *nfs4_xattr_handlers[];
......
...@@ -699,7 +699,7 @@ get_device_info(struct inode *inode, struct nfs4_deviceid *dev_id, gfp_t gfp_fla ...@@ -699,7 +699,7 @@ get_device_info(struct inode *inode, struct nfs4_deviceid *dev_id, gfp_t gfp_fla
* GETDEVICEINFO's maxcount * GETDEVICEINFO's maxcount
*/ */
max_resp_sz = server->nfs_client->cl_session->fc_attrs.max_resp_sz; max_resp_sz = server->nfs_client->cl_session->fc_attrs.max_resp_sz;
max_pages = max_resp_sz >> PAGE_SHIFT; max_pages = nfs_page_array_len(0, max_resp_sz);
dprintk("%s inode %p max_resp_sz %u max_pages %d\n", dprintk("%s inode %p max_resp_sz %u max_pages %d\n",
__func__, inode, max_resp_sz, max_pages); __func__, inode, max_resp_sz, max_pages);
......
...@@ -51,6 +51,30 @@ static inline char *nfs4_pathname_string(const struct nfs4_pathname *pathname, ...@@ -51,6 +51,30 @@ static inline char *nfs4_pathname_string(const struct nfs4_pathname *pathname,
return ERR_PTR(-ENAMETOOLONG); return ERR_PTR(-ENAMETOOLONG);
} }
/*
* return the path component of "<server>:<path>"
* nfspath - the "<server>:<path>" string
* end - one past the last char that could contain "<server>:"
* returns NULL on failure
*/
static char *nfs_path_component(const char *nfspath, const char *end)
{
char *p;
if (*nfspath == '[') {
/* parse [] escaped IPv6 addrs */
p = strchr(nfspath, ']');
if (p != NULL && ++p < end && *p == ':')
return p + 1;
} else {
/* otherwise split on first colon */
p = strchr(nfspath, ':');
if (p != NULL && p < end)
return p + 1;
}
return NULL;
}
/* /*
* Determine the mount path as a string * Determine the mount path as a string
*/ */
...@@ -59,9 +83,9 @@ static char *nfs4_path(struct dentry *dentry, char *buffer, ssize_t buflen) ...@@ -59,9 +83,9 @@ static char *nfs4_path(struct dentry *dentry, char *buffer, ssize_t buflen)
char *limit; char *limit;
char *path = nfs_path(&limit, dentry, buffer, buflen); char *path = nfs_path(&limit, dentry, buffer, buflen);
if (!IS_ERR(path)) { if (!IS_ERR(path)) {
char *colon = strchr(path, ':'); char *path_component = nfs_path_component(path, limit);
if (colon && colon < limit) if (path_component)
path = colon + 1; return path_component;
} }
return path; return path;
} }
...@@ -108,6 +132,58 @@ static size_t nfs_parse_server_name(char *string, size_t len, ...@@ -108,6 +132,58 @@ static size_t nfs_parse_server_name(char *string, size_t len,
return ret; return ret;
} }
static rpc_authflavor_t nfs4_negotiate_security(struct inode *inode, struct qstr *name)
{
struct page *page;
struct nfs4_secinfo_flavors *flavors;
rpc_authflavor_t flavor;
int err;
page = alloc_page(GFP_KERNEL);
if (!page)
return -ENOMEM;
flavors = page_address(page);
err = nfs4_proc_secinfo(inode, name, flavors);
if (err < 0) {
flavor = err;
goto out;
}
flavor = nfs_find_best_sec(flavors);
out:
put_page(page);
return flavor;
}
/*
* Please call rpc_shutdown_client() when you are done with this client.
*/
struct rpc_clnt *nfs4_create_sec_client(struct rpc_clnt *clnt, struct inode *inode,
struct qstr *name)
{
struct rpc_clnt *clone;
struct rpc_auth *auth;
rpc_authflavor_t flavor;
flavor = nfs4_negotiate_security(inode, name);
if (flavor < 0)
return ERR_PTR(flavor);
clone = rpc_clone_client(clnt);
if (IS_ERR(clone))
return clone;
auth = rpcauth_create(flavor, clone);
if (!auth) {
rpc_shutdown_client(clone);
clone = ERR_PTR(-EIO);
}
return clone;
}
static struct vfsmount *try_location(struct nfs_clone_mount *mountdata, static struct vfsmount *try_location(struct nfs_clone_mount *mountdata,
char *page, char *page2, char *page, char *page2,
const struct nfs4_fs_location *location) const struct nfs4_fs_location *location)
...@@ -224,7 +300,7 @@ static struct vfsmount *nfs_follow_referral(struct dentry *dentry, ...@@ -224,7 +300,7 @@ static struct vfsmount *nfs_follow_referral(struct dentry *dentry,
* @dentry - dentry of referral * @dentry - dentry of referral
* *
*/ */
struct vfsmount *nfs_do_refmount(struct dentry *dentry) struct vfsmount *nfs_do_refmount(struct rpc_clnt *client, struct dentry *dentry)
{ {
struct vfsmount *mnt = ERR_PTR(-ENOMEM); struct vfsmount *mnt = ERR_PTR(-ENOMEM);
struct dentry *parent; struct dentry *parent;
...@@ -250,7 +326,7 @@ struct vfsmount *nfs_do_refmount(struct dentry *dentry) ...@@ -250,7 +326,7 @@ struct vfsmount *nfs_do_refmount(struct dentry *dentry)
dprintk("%s: getting locations for %s/%s\n", dprintk("%s: getting locations for %s/%s\n",
__func__, parent->d_name.name, dentry->d_name.name); __func__, parent->d_name.name, dentry->d_name.name);
err = nfs4_proc_fs_locations(parent->d_inode, &dentry->d_name, fs_locations, page); err = nfs4_proc_fs_locations(client, parent->d_inode, &dentry->d_name, fs_locations, page);
dput(parent); dput(parent);
if (err != 0 || if (err != 0 ||
fs_locations->nlocations <= 0 || fs_locations->nlocations <= 0 ||
......
...@@ -2377,8 +2377,9 @@ static int nfs4_proc_get_root(struct nfs_server *server, struct nfs_fh *fhandle, ...@@ -2377,8 +2377,9 @@ static int nfs4_proc_get_root(struct nfs_server *server, struct nfs_fh *fhandle,
* Note that we'll actually follow the referral later when * Note that we'll actually follow the referral later when
* we detect fsid mismatch in inode revalidation * we detect fsid mismatch in inode revalidation
*/ */
static int nfs4_get_referral(struct inode *dir, const struct qstr *name, static int nfs4_get_referral(struct rpc_clnt *client, struct inode *dir,
struct nfs_fattr *fattr, struct nfs_fh *fhandle) const struct qstr *name, struct nfs_fattr *fattr,
struct nfs_fh *fhandle)
{ {
int status = -ENOMEM; int status = -ENOMEM;
struct page *page = NULL; struct page *page = NULL;
...@@ -2391,7 +2392,7 @@ static int nfs4_get_referral(struct inode *dir, const struct qstr *name, ...@@ -2391,7 +2392,7 @@ static int nfs4_get_referral(struct inode *dir, const struct qstr *name,
if (locations == NULL) if (locations == NULL)
goto out; goto out;
status = nfs4_proc_fs_locations(dir, name, locations, page); status = nfs4_proc_fs_locations(client, dir, name, locations, page);
if (status != 0) if (status != 0)
goto out; goto out;
/* Make sure server returned a different fsid for the referral */ /* Make sure server returned a different fsid for the referral */
...@@ -2528,39 +2529,84 @@ static int _nfs4_proc_lookup(struct rpc_clnt *clnt, struct inode *dir, ...@@ -2528,39 +2529,84 @@ static int _nfs4_proc_lookup(struct rpc_clnt *clnt, struct inode *dir,
return status; return status;
} }
void nfs_fixup_secinfo_attributes(struct nfs_fattr *fattr, struct nfs_fh *fh) static void nfs_fixup_secinfo_attributes(struct nfs_fattr *fattr)
{ {
memset(fh, 0, sizeof(struct nfs_fh));
fattr->fsid.major = 1;
fattr->valid |= NFS_ATTR_FATTR_TYPE | NFS_ATTR_FATTR_MODE | fattr->valid |= NFS_ATTR_FATTR_TYPE | NFS_ATTR_FATTR_MODE |
NFS_ATTR_FATTR_NLINK | NFS_ATTR_FATTR_FSID | NFS_ATTR_FATTR_MOUNTPOINT; NFS_ATTR_FATTR_NLINK | NFS_ATTR_FATTR_MOUNTPOINT;
fattr->mode = S_IFDIR | S_IRUGO | S_IXUGO; fattr->mode = S_IFDIR | S_IRUGO | S_IXUGO;
fattr->nlink = 2; fattr->nlink = 2;
} }
static int nfs4_proc_lookup(struct rpc_clnt *clnt, struct inode *dir, struct qstr *name, static int nfs4_proc_lookup_common(struct rpc_clnt **clnt, struct inode *dir,
struct nfs_fh *fhandle, struct nfs_fattr *fattr) struct qstr *name, struct nfs_fh *fhandle,
struct nfs_fattr *fattr)
{ {
struct nfs4_exception exception = { }; struct nfs4_exception exception = { };
struct rpc_clnt *client = *clnt;
int err; int err;
do { do {
int status; err = _nfs4_proc_lookup(client, dir, name, fhandle, fattr);
switch (err) {
status = _nfs4_proc_lookup(clnt, dir, name, fhandle, fattr);
switch (status) {
case -NFS4ERR_BADNAME: case -NFS4ERR_BADNAME:
return -ENOENT; err = -ENOENT;
goto out;
case -NFS4ERR_MOVED: case -NFS4ERR_MOVED:
return nfs4_get_referral(dir, name, fattr, fhandle); err = nfs4_get_referral(client, dir, name, fattr, fhandle);
goto out;
case -NFS4ERR_WRONGSEC: case -NFS4ERR_WRONGSEC:
nfs_fixup_secinfo_attributes(fattr, fhandle); err = -EPERM;
if (client != *clnt)
goto out;
client = nfs4_create_sec_client(client, dir, name);
if (IS_ERR(client))
return PTR_ERR(client);
exception.retry = 1;
break;
default:
err = nfs4_handle_exception(NFS_SERVER(dir), err, &exception);
} }
err = nfs4_handle_exception(NFS_SERVER(dir),
status, &exception);
} while (exception.retry); } while (exception.retry);
out:
if (err == 0)
*clnt = client;
else if (client != *clnt)
rpc_shutdown_client(client);
return err; return err;
} }
static int nfs4_proc_lookup(struct rpc_clnt *clnt, struct inode *dir, struct qstr *name,
struct nfs_fh *fhandle, struct nfs_fattr *fattr)
{
int status;
struct rpc_clnt *client = NFS_CLIENT(dir);
status = nfs4_proc_lookup_common(&client, dir, name, fhandle, fattr);
if (client != NFS_CLIENT(dir)) {
rpc_shutdown_client(client);
nfs_fixup_secinfo_attributes(fattr);
}
return status;
}
struct rpc_clnt *
nfs4_proc_lookup_mountpoint(struct inode *dir, struct qstr *name,
struct nfs_fh *fhandle, struct nfs_fattr *fattr)
{
int status;
struct rpc_clnt *client = rpc_clone_client(NFS_CLIENT(dir));
status = nfs4_proc_lookup_common(&client, dir, name, fhandle, fattr);
if (status < 0) {
rpc_shutdown_client(client);
return ERR_PTR(status);
}
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)
{ {
struct nfs_server *server = NFS_SERVER(inode); struct nfs_server *server = NFS_SERVER(inode);
...@@ -3628,16 +3674,16 @@ static inline ssize_t nfs4_read_cached_acl(struct inode *inode, char *buf, size_ ...@@ -3628,16 +3674,16 @@ static inline ssize_t nfs4_read_cached_acl(struct inode *inode, char *buf, size_
return ret; return ret;
} }
static void nfs4_write_cached_acl(struct inode *inode, const char *buf, size_t acl_len) static void nfs4_write_cached_acl(struct inode *inode, struct page **pages, size_t pgbase, size_t acl_len)
{ {
struct nfs4_cached_acl *acl; struct nfs4_cached_acl *acl;
if (buf && acl_len <= PAGE_SIZE) { if (pages && acl_len <= PAGE_SIZE) {
acl = kmalloc(sizeof(*acl) + acl_len, GFP_KERNEL); acl = kmalloc(sizeof(*acl) + acl_len, GFP_KERNEL);
if (acl == NULL) if (acl == NULL)
goto out; goto out;
acl->cached = 1; acl->cached = 1;
memcpy(acl->data, buf, acl_len); _copy_from_pages(acl->data, pages, pgbase, acl_len);
} else { } else {
acl = kmalloc(sizeof(*acl), GFP_KERNEL); acl = kmalloc(sizeof(*acl), GFP_KERNEL);
if (acl == NULL) if (acl == NULL)
...@@ -3670,7 +3716,6 @@ static ssize_t __nfs4_get_acl_uncached(struct inode *inode, void *buf, size_t bu ...@@ -3670,7 +3716,6 @@ static ssize_t __nfs4_get_acl_uncached(struct inode *inode, void *buf, size_t bu
struct nfs_getaclres res = { struct nfs_getaclres res = {
.acl_len = buflen, .acl_len = buflen,
}; };
void *resp_buf;
struct rpc_message msg = { struct rpc_message msg = {
.rpc_proc = &nfs4_procedures[NFSPROC4_CLNT_GETACL], .rpc_proc = &nfs4_procedures[NFSPROC4_CLNT_GETACL],
.rpc_argp = &args, .rpc_argp = &args,
...@@ -3684,24 +3729,27 @@ static ssize_t __nfs4_get_acl_uncached(struct inode *inode, void *buf, size_t bu ...@@ -3684,24 +3729,27 @@ static ssize_t __nfs4_get_acl_uncached(struct inode *inode, void *buf, size_t bu
if (npages == 0) if (npages == 0)
npages = 1; npages = 1;
/* Add an extra page to handle the bitmap returned */
npages++;
for (i = 0; i < npages; i++) { for (i = 0; i < npages; i++) {
pages[i] = alloc_page(GFP_KERNEL); pages[i] = alloc_page(GFP_KERNEL);
if (!pages[i]) if (!pages[i])
goto out_free; goto out_free;
} }
if (npages > 1) {
/* for decoding across pages */ /* for decoding across pages */
res.acl_scratch = alloc_page(GFP_KERNEL); res.acl_scratch = alloc_page(GFP_KERNEL);
if (!res.acl_scratch) if (!res.acl_scratch)
goto out_free; goto out_free;
}
args.acl_len = npages * PAGE_SIZE; args.acl_len = npages * PAGE_SIZE;
args.acl_pgbase = 0; args.acl_pgbase = 0;
/* Let decode_getfacl know not to fail if the ACL data is larger than /* Let decode_getfacl know not to fail if the ACL data is larger than
* the page we send as a guess */ * the page we send as a guess */
if (buf == NULL) if (buf == NULL)
res.acl_flags |= NFS4_ACL_LEN_REQUEST; res.acl_flags |= NFS4_ACL_LEN_REQUEST;
resp_buf = page_address(pages[0]);
dprintk("%s buf %p buflen %zu npages %d args.acl_len %zu\n", dprintk("%s buf %p buflen %zu npages %d args.acl_len %zu\n",
__func__, buf, buflen, npages, args.acl_len); __func__, buf, buflen, npages, args.acl_len);
...@@ -3712,9 +3760,9 @@ static ssize_t __nfs4_get_acl_uncached(struct inode *inode, void *buf, size_t bu ...@@ -3712,9 +3760,9 @@ static ssize_t __nfs4_get_acl_uncached(struct inode *inode, void *buf, size_t bu
acl_len = res.acl_len - res.acl_data_offset; acl_len = res.acl_len - res.acl_data_offset;
if (acl_len > args.acl_len) if (acl_len > args.acl_len)
nfs4_write_cached_acl(inode, NULL, acl_len); nfs4_write_cached_acl(inode, NULL, 0, acl_len);
else else
nfs4_write_cached_acl(inode, resp_buf + res.acl_data_offset, nfs4_write_cached_acl(inode, pages, res.acl_data_offset,
acl_len); acl_len);
if (buf) { if (buf) {
ret = -ERANGE; ret = -ERANGE;
...@@ -4919,8 +4967,10 @@ static void nfs_fixup_referral_attributes(struct nfs_fattr *fattr) ...@@ -4919,8 +4967,10 @@ static void nfs_fixup_referral_attributes(struct nfs_fattr *fattr)
fattr->nlink = 2; fattr->nlink = 2;
} }
int nfs4_proc_fs_locations(struct inode *dir, const struct qstr *name, static int _nfs4_proc_fs_locations(struct rpc_clnt *client, struct inode *dir,
struct nfs4_fs_locations *fs_locations, struct page *page) const struct qstr *name,
struct nfs4_fs_locations *fs_locations,
struct page *page)
{ {
struct nfs_server *server = NFS_SERVER(dir); struct nfs_server *server = NFS_SERVER(dir);
u32 bitmask[2] = { u32 bitmask[2] = {
...@@ -4954,11 +5004,26 @@ int nfs4_proc_fs_locations(struct inode *dir, const struct qstr *name, ...@@ -4954,11 +5004,26 @@ int nfs4_proc_fs_locations(struct inode *dir, const struct qstr *name,
nfs_fattr_init(&fs_locations->fattr); nfs_fattr_init(&fs_locations->fattr);
fs_locations->server = server; fs_locations->server = server;
fs_locations->nlocations = 0; fs_locations->nlocations = 0;
status = nfs4_call_sync(server->client, server, &msg, &args.seq_args, &res.seq_res, 0); status = nfs4_call_sync(client, server, &msg, &args.seq_args, &res.seq_res, 0);
dprintk("%s: returned status = %d\n", __func__, status); dprintk("%s: returned status = %d\n", __func__, status);
return status; return status;
} }
int nfs4_proc_fs_locations(struct rpc_clnt *client, struct inode *dir,
const struct qstr *name,
struct nfs4_fs_locations *fs_locations,
struct page *page)
{
struct nfs4_exception exception = { };
int err;
do {
err = nfs4_handle_exception(NFS_SERVER(dir),
_nfs4_proc_fs_locations(client, dir, name, fs_locations, page),
&exception);
} while (exception.retry);
return err;
}
static int _nfs4_proc_secinfo(struct inode *dir, const struct qstr *name, struct nfs4_secinfo_flavors *flavors) static int _nfs4_proc_secinfo(struct inode *dir, const struct qstr *name, struct nfs4_secinfo_flavors *flavors)
{ {
int status; int status;
...@@ -4981,7 +5046,7 @@ static int _nfs4_proc_secinfo(struct inode *dir, const struct qstr *name, struct ...@@ -4981,7 +5046,7 @@ static int _nfs4_proc_secinfo(struct inode *dir, const struct qstr *name, struct
return status; return status;
} }
static int nfs4_proc_secinfo(struct inode *dir, const struct qstr *name, int nfs4_proc_secinfo(struct inode *dir, const struct qstr *name,
struct nfs4_secinfo_flavors *flavors) struct nfs4_secinfo_flavors *flavors)
{ {
struct nfs4_exception exception = { }; struct nfs4_exception exception = { };
...@@ -5057,10 +5122,9 @@ int nfs4_proc_exchange_id(struct nfs_client *clp, struct rpc_cred *cred) ...@@ -5057,10 +5122,9 @@ int nfs4_proc_exchange_id(struct nfs_client *clp, struct rpc_cred *cred)
nfs4_construct_boot_verifier(clp, &verifier); nfs4_construct_boot_verifier(clp, &verifier);
args.id_len = scnprintf(args.id, sizeof(args.id), args.id_len = scnprintf(args.id, sizeof(args.id),
"%s/%s.%s/%u", "%s/%s/%u",
clp->cl_ipaddr, clp->cl_ipaddr,
init_utsname()->nodename, clp->cl_rpcclient->cl_nodename,
init_utsname()->domainname,
clp->cl_rpcclient->cl_auth->au_flavor); clp->cl_rpcclient->cl_auth->au_flavor);
res.server_scope = kzalloc(sizeof(struct server_scope), GFP_KERNEL); res.server_scope = kzalloc(sizeof(struct server_scope), GFP_KERNEL);
......
...@@ -4258,8 +4258,6 @@ static int decode_getfattr_attrs(struct xdr_stream *xdr, uint32_t *bitmap, ...@@ -4258,8 +4258,6 @@ static int decode_getfattr_attrs(struct xdr_stream *xdr, uint32_t *bitmap,
status = decode_attr_error(xdr, bitmap, &err); status = decode_attr_error(xdr, bitmap, &err);
if (status < 0) if (status < 0)
goto xdr_error; goto xdr_error;
if (err == -NFS4ERR_WRONGSEC)
nfs_fixup_secinfo_attributes(fattr, fh);
status = decode_attr_filehandle(xdr, bitmap, fh); status = decode_attr_filehandle(xdr, bitmap, fh);
if (status < 0) if (status < 0)
...@@ -4902,11 +4900,19 @@ static int decode_getacl(struct xdr_stream *xdr, struct rpc_rqst *req, ...@@ -4902,11 +4900,19 @@ static int decode_getacl(struct xdr_stream *xdr, struct rpc_rqst *req,
bitmap[3] = {0}; bitmap[3] = {0};
struct kvec *iov = req->rq_rcv_buf.head; struct kvec *iov = req->rq_rcv_buf.head;
int status; int status;
size_t page_len = xdr->buf->page_len;
res->acl_len = 0; res->acl_len = 0;
if ((status = decode_op_hdr(xdr, OP_GETATTR)) != 0) if ((status = decode_op_hdr(xdr, OP_GETATTR)) != 0)
goto out; goto out;
bm_p = xdr->p; bm_p = xdr->p;
res->acl_data_offset = be32_to_cpup(bm_p) + 2;
res->acl_data_offset <<= 2;
/* Check if the acl data starts beyond the allocated buffer */
if (res->acl_data_offset > page_len)
return -ERANGE;
if ((status = decode_attr_bitmap(xdr, bitmap)) != 0) if ((status = decode_attr_bitmap(xdr, bitmap)) != 0)
goto out; goto out;
if ((status = decode_attr_length(xdr, &attrlen, &savep)) != 0) if ((status = decode_attr_length(xdr, &attrlen, &savep)) != 0)
...@@ -4916,28 +4922,24 @@ static int decode_getacl(struct xdr_stream *xdr, struct rpc_rqst *req, ...@@ -4916,28 +4922,24 @@ static int decode_getacl(struct xdr_stream *xdr, struct rpc_rqst *req,
return -EIO; return -EIO;
if (likely(bitmap[0] & FATTR4_WORD0_ACL)) { if (likely(bitmap[0] & FATTR4_WORD0_ACL)) {
size_t hdrlen; size_t hdrlen;
u32 recvd;
/* The bitmap (xdr len + bitmaps) and the attr xdr len words /* The bitmap (xdr len + bitmaps) and the attr xdr len words
* are stored with the acl data to handle the problem of * are stored with the acl data to handle the problem of
* variable length bitmaps.*/ * variable length bitmaps.*/
xdr->p = bm_p; xdr->p = bm_p;
res->acl_data_offset = be32_to_cpup(bm_p) + 2;
res->acl_data_offset <<= 2;
/* We ignore &savep and don't do consistency checks on /* We ignore &savep and don't do consistency checks on
* the attr length. Let userspace figure it out.... */ * the attr length. Let userspace figure it out.... */
hdrlen = (u8 *)xdr->p - (u8 *)iov->iov_base; hdrlen = (u8 *)xdr->p - (u8 *)iov->iov_base;
attrlen += res->acl_data_offset; attrlen += res->acl_data_offset;
recvd = req->rq_rcv_buf.len - hdrlen; if (attrlen > page_len) {
if (attrlen > recvd) {
if (res->acl_flags & NFS4_ACL_LEN_REQUEST) { if (res->acl_flags & NFS4_ACL_LEN_REQUEST) {
/* getxattr interface called with a NULL buf */ /* getxattr interface called with a NULL buf */
res->acl_len = attrlen; res->acl_len = attrlen;
goto out; goto out;
} }
dprintk("NFS: acl reply: attrlen %u > recvd %u\n", dprintk("NFS: acl reply: attrlen %u > page_len %zu\n",
attrlen, recvd); attrlen, page_len);
return -EINVAL; return -EINVAL;
} }
xdr_read_pages(xdr, attrlen); xdr_read_pages(xdr, attrlen);
...@@ -5090,16 +5092,13 @@ static int decode_secinfo_gss(struct xdr_stream *xdr, struct nfs4_secinfo_flavor ...@@ -5090,16 +5092,13 @@ static int decode_secinfo_gss(struct xdr_stream *xdr, struct nfs4_secinfo_flavor
return -EINVAL; return -EINVAL;
} }
static int decode_secinfo(struct xdr_stream *xdr, struct nfs4_secinfo_res *res) static int decode_secinfo_common(struct xdr_stream *xdr, struct nfs4_secinfo_res *res)
{ {
struct nfs4_secinfo_flavor *sec_flavor; struct nfs4_secinfo_flavor *sec_flavor;
int status; int status;
__be32 *p; __be32 *p;
int i, num_flavors; int i, num_flavors;
status = decode_op_hdr(xdr, OP_SECINFO);
if (status)
goto out;
p = xdr_inline_decode(xdr, 4); p = xdr_inline_decode(xdr, 4);
if (unlikely(!p)) if (unlikely(!p))
goto out_overflow; goto out_overflow;
...@@ -5125,6 +5124,7 @@ static int decode_secinfo(struct xdr_stream *xdr, struct nfs4_secinfo_res *res) ...@@ -5125,6 +5124,7 @@ static int decode_secinfo(struct xdr_stream *xdr, struct nfs4_secinfo_res *res)
res->flavors->num_flavors++; res->flavors->num_flavors++;
} }
status = 0;
out: out:
return status; return status;
out_overflow: out_overflow:
...@@ -5132,7 +5132,23 @@ static int decode_secinfo(struct xdr_stream *xdr, struct nfs4_secinfo_res *res) ...@@ -5132,7 +5132,23 @@ static int decode_secinfo(struct xdr_stream *xdr, struct nfs4_secinfo_res *res)
return -EIO; return -EIO;
} }
static int decode_secinfo(struct xdr_stream *xdr, struct nfs4_secinfo_res *res)
{
int status = decode_op_hdr(xdr, OP_SECINFO);
if (status)
return status;
return decode_secinfo_common(xdr, res);
}
#if defined(CONFIG_NFS_V4_1) #if defined(CONFIG_NFS_V4_1)
static int decode_secinfo_no_name(struct xdr_stream *xdr, struct nfs4_secinfo_res *res)
{
int status = decode_op_hdr(xdr, OP_SECINFO_NO_NAME);
if (status)
return status;
return decode_secinfo_common(xdr, res);
}
static int decode_exchange_id(struct xdr_stream *xdr, static int decode_exchange_id(struct xdr_stream *xdr,
struct nfs41_exchange_id_res *res) struct nfs41_exchange_id_res *res)
{ {
...@@ -6817,7 +6833,7 @@ static int nfs4_xdr_dec_secinfo_no_name(struct rpc_rqst *rqstp, ...@@ -6817,7 +6833,7 @@ static int nfs4_xdr_dec_secinfo_no_name(struct rpc_rqst *rqstp,
status = decode_putrootfh(xdr); status = decode_putrootfh(xdr);
if (status) if (status)
goto out; goto out;
status = decode_secinfo(xdr, res); status = decode_secinfo_no_name(xdr, res);
out: out:
return status; return status;
} }
......
...@@ -604,7 +604,6 @@ int objlayout_get_deviceinfo(struct pnfs_layout_hdr *pnfslay, ...@@ -604,7 +604,6 @@ int objlayout_get_deviceinfo(struct pnfs_layout_hdr *pnfslay,
{ {
struct objlayout_deviceinfo *odi; struct objlayout_deviceinfo *odi;
struct pnfs_device pd; struct pnfs_device pd;
struct super_block *sb;
struct page *page, **pages; struct page *page, **pages;
u32 *p; u32 *p;
int err; int err;
...@@ -623,7 +622,6 @@ int objlayout_get_deviceinfo(struct pnfs_layout_hdr *pnfslay, ...@@ -623,7 +622,6 @@ int objlayout_get_deviceinfo(struct pnfs_layout_hdr *pnfslay,
pd.pglen = PAGE_SIZE; pd.pglen = PAGE_SIZE;
pd.mincount = 0; pd.mincount = 0;
sb = pnfslay->plh_inode->i_sb;
err = nfs4_proc_getdeviceinfo(NFS_SERVER(pnfslay->plh_inode), &pd); err = nfs4_proc_getdeviceinfo(NFS_SERVER(pnfslay->plh_inode), &pd);
dprintk("%s nfs_getdeviceinfo returned %d\n", __func__, err); dprintk("%s nfs_getdeviceinfo returned %d\n", __func__, err);
if (err) if (err)
......
...@@ -587,7 +587,7 @@ send_layoutget(struct pnfs_layout_hdr *lo, ...@@ -587,7 +587,7 @@ send_layoutget(struct pnfs_layout_hdr *lo,
/* allocate pages for xdr post processing */ /* allocate pages for xdr post processing */
max_resp_sz = server->nfs_client->cl_session->fc_attrs.max_resp_sz; max_resp_sz = server->nfs_client->cl_session->fc_attrs.max_resp_sz;
max_pages = max_resp_sz >> PAGE_SHIFT; max_pages = nfs_page_array_len(0, max_resp_sz);
pages = kcalloc(max_pages, sizeof(struct page *), gfp_flags); pages = kcalloc(max_pages, sizeof(struct page *), gfp_flags);
if (!pages) if (!pages)
......
...@@ -2428,7 +2428,7 @@ nfs_xdev_mount(struct file_system_type *fs_type, int flags, ...@@ -2428,7 +2428,7 @@ nfs_xdev_mount(struct file_system_type *fs_type, int flags,
dprintk("--> nfs_xdev_mount()\n"); dprintk("--> nfs_xdev_mount()\n");
/* create a new volume representation */ /* create a new volume representation */
server = nfs_clone_server(NFS_SB(data->sb), data->fh, data->fattr); server = nfs_clone_server(NFS_SB(data->sb), data->fh, data->fattr, data->authflavor);
if (IS_ERR(server)) { if (IS_ERR(server)) {
error = PTR_ERR(server); error = PTR_ERR(server);
goto out_err_noserver; goto out_err_noserver;
...@@ -2955,7 +2955,7 @@ nfs4_xdev_mount(struct file_system_type *fs_type, int flags, ...@@ -2955,7 +2955,7 @@ nfs4_xdev_mount(struct file_system_type *fs_type, int flags,
dprintk("--> nfs4_xdev_mount()\n"); dprintk("--> nfs4_xdev_mount()\n");
/* create a new volume representation */ /* create a new volume representation */
server = nfs_clone_server(NFS_SB(data->sb), data->fh, data->fattr); server = nfs_clone_server(NFS_SB(data->sb), data->fh, data->fattr, data->authflavor);
if (IS_ERR(server)) { if (IS_ERR(server)) {
error = PTR_ERR(server); error = PTR_ERR(server);
goto out_err_noserver; goto out_err_noserver;
......
...@@ -176,7 +176,15 @@ rpc_setup_pipedir(struct rpc_clnt *clnt, const char *dir_name) ...@@ -176,7 +176,15 @@ rpc_setup_pipedir(struct rpc_clnt *clnt, const char *dir_name)
return 0; return 0;
} }
static int __rpc_pipefs_event(struct rpc_clnt *clnt, unsigned long event, static inline int rpc_clnt_skip_event(struct rpc_clnt *clnt, unsigned long event)
{
if (((event == RPC_PIPEFS_MOUNT) && clnt->cl_dentry) ||
((event == RPC_PIPEFS_UMOUNT) && !clnt->cl_dentry))
return 1;
return 0;
}
static int __rpc_clnt_handle_event(struct rpc_clnt *clnt, unsigned long event,
struct super_block *sb) struct super_block *sb)
{ {
struct dentry *dentry; struct dentry *dentry;
...@@ -184,8 +192,6 @@ static int __rpc_pipefs_event(struct rpc_clnt *clnt, unsigned long event, ...@@ -184,8 +192,6 @@ static int __rpc_pipefs_event(struct rpc_clnt *clnt, unsigned long event,
switch (event) { switch (event) {
case RPC_PIPEFS_MOUNT: case RPC_PIPEFS_MOUNT:
if (clnt->cl_program->pipe_dir_name == NULL)
break;
dentry = rpc_setup_pipedir_sb(sb, clnt, dentry = rpc_setup_pipedir_sb(sb, clnt,
clnt->cl_program->pipe_dir_name); clnt->cl_program->pipe_dir_name);
BUG_ON(dentry == NULL); BUG_ON(dentry == NULL);
...@@ -208,6 +214,20 @@ static int __rpc_pipefs_event(struct rpc_clnt *clnt, unsigned long event, ...@@ -208,6 +214,20 @@ static int __rpc_pipefs_event(struct rpc_clnt *clnt, unsigned long event,
return err; return err;
} }
static int __rpc_pipefs_event(struct rpc_clnt *clnt, unsigned long event,
struct super_block *sb)
{
int error = 0;
for (;; clnt = clnt->cl_parent) {
if (!rpc_clnt_skip_event(clnt, event))
error = __rpc_clnt_handle_event(clnt, event, sb);
if (error || clnt == clnt->cl_parent)
break;
}
return error;
}
static struct rpc_clnt *rpc_get_client_for_event(struct net *net, int event) static struct rpc_clnt *rpc_get_client_for_event(struct net *net, int event)
{ {
struct sunrpc_net *sn = net_generic(net, sunrpc_net_id); struct sunrpc_net *sn = net_generic(net, sunrpc_net_id);
...@@ -215,10 +235,12 @@ static struct rpc_clnt *rpc_get_client_for_event(struct net *net, int event) ...@@ -215,10 +235,12 @@ static struct rpc_clnt *rpc_get_client_for_event(struct net *net, int event)
spin_lock(&sn->rpc_client_lock); spin_lock(&sn->rpc_client_lock);
list_for_each_entry(clnt, &sn->all_clients, cl_clients) { list_for_each_entry(clnt, &sn->all_clients, cl_clients) {
if (((event == RPC_PIPEFS_MOUNT) && clnt->cl_dentry) || if (clnt->cl_program->pipe_dir_name == NULL)
((event == RPC_PIPEFS_UMOUNT) && !clnt->cl_dentry)) break;
if (rpc_clnt_skip_event(clnt, event))
continue;
if (atomic_inc_not_zero(&clnt->cl_count) == 0)
continue; continue;
atomic_inc(&clnt->cl_count);
spin_unlock(&sn->rpc_client_lock); spin_unlock(&sn->rpc_client_lock);
return clnt; return clnt;
} }
...@@ -257,6 +279,14 @@ void rpc_clients_notifier_unregister(void) ...@@ -257,6 +279,14 @@ void rpc_clients_notifier_unregister(void)
return rpc_pipefs_notifier_unregister(&rpc_clients_block); return rpc_pipefs_notifier_unregister(&rpc_clients_block);
} }
static void rpc_clnt_set_nodename(struct rpc_clnt *clnt, const char *nodename)
{
clnt->cl_nodelen = strlen(nodename);
if (clnt->cl_nodelen > UNX_MAXNODENAME)
clnt->cl_nodelen = UNX_MAXNODENAME;
memcpy(clnt->cl_nodename, nodename, clnt->cl_nodelen);
}
static struct rpc_clnt * rpc_new_client(const struct rpc_create_args *args, struct rpc_xprt *xprt) static struct rpc_clnt * rpc_new_client(const struct rpc_create_args *args, struct rpc_xprt *xprt)
{ {
const struct rpc_program *program = args->program; const struct rpc_program *program = args->program;
...@@ -337,10 +367,7 @@ static struct rpc_clnt * rpc_new_client(const struct rpc_create_args *args, stru ...@@ -337,10 +367,7 @@ static struct rpc_clnt * rpc_new_client(const struct rpc_create_args *args, stru
} }
/* save the nodename */ /* save the nodename */
clnt->cl_nodelen = strlen(init_utsname()->nodename); rpc_clnt_set_nodename(clnt, utsname()->nodename);
if (clnt->cl_nodelen > UNX_MAXNODENAME)
clnt->cl_nodelen = UNX_MAXNODENAME;
memcpy(clnt->cl_nodename, init_utsname()->nodename, clnt->cl_nodelen);
rpc_register_client(clnt); rpc_register_client(clnt);
return clnt; return clnt;
...@@ -499,6 +526,7 @@ rpc_clone_client(struct rpc_clnt *clnt) ...@@ -499,6 +526,7 @@ rpc_clone_client(struct rpc_clnt *clnt)
err = rpc_setup_pipedir(new, clnt->cl_program->pipe_dir_name); err = rpc_setup_pipedir(new, clnt->cl_program->pipe_dir_name);
if (err != 0) if (err != 0)
goto out_no_path; goto out_no_path;
rpc_clnt_set_nodename(new, utsname()->nodename);
if (new->cl_auth) if (new->cl_auth)
atomic_inc(&new->cl_auth->au_count); atomic_inc(&new->cl_auth->au_count);
atomic_inc(&clnt->cl_count); atomic_inc(&clnt->cl_count);
......
...@@ -1126,19 +1126,20 @@ rpc_fill_super(struct super_block *sb, void *data, int silent) ...@@ -1126,19 +1126,20 @@ rpc_fill_super(struct super_block *sb, void *data, int silent)
return -ENOMEM; return -ENOMEM;
dprintk("RPC: sending pipefs MOUNT notification for net %p%s\n", net, dprintk("RPC: sending pipefs MOUNT notification for net %p%s\n", net,
NET_NAME(net)); NET_NAME(net));
sn->pipefs_sb = sb;
err = blocking_notifier_call_chain(&rpc_pipefs_notifier_list, err = blocking_notifier_call_chain(&rpc_pipefs_notifier_list,
RPC_PIPEFS_MOUNT, RPC_PIPEFS_MOUNT,
sb); sb);
if (err) if (err)
goto err_depopulate; goto err_depopulate;
sb->s_fs_info = get_net(net); sb->s_fs_info = get_net(net);
sn->pipefs_sb = sb;
return 0; return 0;
err_depopulate: err_depopulate:
blocking_notifier_call_chain(&rpc_pipefs_notifier_list, blocking_notifier_call_chain(&rpc_pipefs_notifier_list,
RPC_PIPEFS_UMOUNT, RPC_PIPEFS_UMOUNT,
sb); sb);
sn->pipefs_sb = NULL;
__rpc_depopulate(root, files, RPCAUTH_lockd, RPCAUTH_RootEOF); __rpc_depopulate(root, files, RPCAUTH_lockd, RPCAUTH_RootEOF);
return err; return err;
} }
......
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