summaryrefslogtreecommitdiff
path: root/fs/nfs/nfs4namespace.c
diff options
context:
space:
mode:
authorLinus Torvalds <torvalds@linux-foundation.org>2012-05-02 08:17:57 -0700
committerLinus Torvalds <torvalds@linux-foundation.org>2012-05-02 08:17:57 -0700
commit529acf58981440eefeaf1451387e2a0aa4825c12 (patch)
treeffcf408493a34ab1e0e1530dca83aa279708560c /fs/nfs/nfs4namespace.c
parentb821861b905a79f71746945237968c3382d99adc (diff)
parent3617e5031b3acec04efaa36566a8111ac8f07325 (diff)
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
Diffstat (limited to 'fs/nfs/nfs4namespace.c')
-rw-r--r--fs/nfs/nfs4namespace.c86
1 files changed, 81 insertions, 5 deletions
diff --git a/fs/nfs/nfs4namespace.c b/fs/nfs/nfs4namespace.c
index 9c8eca315f4..a7f3dedc4ec 100644
--- a/fs/nfs/nfs4namespace.c
+++ b/fs/nfs/nfs4namespace.c
@@ -52,6 +52,30 @@ Elong:
}
/*
+ * 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
*/
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 *path = nfs_path(&limit, dentry, buffer, buflen);
if (!IS_ERR(path)) {
- char *colon = strchr(path, ':');
- if (colon && colon < limit)
- path = colon + 1;
+ char *path_component = nfs_path_component(path, limit);
+ if (path_component)
+ return path_component;
}
return path;
}
@@ -108,6 +132,58 @@ static size_t nfs_parse_server_name(char *string, size_t len,
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,
char *page, char *page2,
const struct nfs4_fs_location *location)
@@ -224,7 +300,7 @@ out:
* @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 dentry *parent;
@@ -250,7 +326,7 @@ struct vfsmount *nfs_do_refmount(struct dentry *dentry)
dprintk("%s: getting locations for %s/%s\n",
__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);
if (err != 0 ||
fs_locations->nlocations <= 0 ||