2017-06-27 15:44:09

by Christoph Hellwig

[permalink] [raw]
Subject: open by handle support for NFS

Hi all,

this resurrects parts of an old series to add open by handle support to
NFS. The prime intent here is to support the actual open by handle
ioctls, although it will also allow very crude re-exporting. Without
the other patches from Jeff's series that re-exporting will suck badly
though.



2017-06-27 15:44:15

by Christoph Hellwig

[permalink] [raw]
Subject: [PATCH 4/4] nfs: add export operations

From: Peng Tao <[email protected]>

This support for opening files on NFS by file handle, both through the
open_by_handle syscall, and for re-exporting NFS (for example using a
different version). The support is very basic for now, as each open by
handle will have to do an NFSv4 open operation on the wire. In the
future this will hopefully be mitigated by an open file cache, as well
as various optimizations in NFS for this specific case.

Signed-off-by: Peng Tao <[email protected]>
[hch: incorporated various changes, resplit the patches, new changelog]
Signed-off-by: Christoph Hellwig <[email protected]>
---
fs/nfs/Makefile | 2 +-
fs/nfs/export.c | 177 ++++++++++++++++++++++++++++++++++++++++++++++++++++++
fs/nfs/internal.h | 2 +
fs/nfs/super.c | 2 +
4 files changed, 182 insertions(+), 1 deletion(-)
create mode 100644 fs/nfs/export.c

diff --git a/fs/nfs/Makefile b/fs/nfs/Makefile
index 98f4e5728a67..1fb118902d57 100644
--- a/fs/nfs/Makefile
+++ b/fs/nfs/Makefile
@@ -7,7 +7,7 @@ obj-$(CONFIG_NFS_FS) += nfs.o
CFLAGS_nfstrace.o += -I$(src)
nfs-y := client.o dir.o file.o getroot.o inode.o super.o \
io.o direct.o pagelist.o read.o symlink.o unlink.o \
- write.o namespace.o mount_clnt.o nfstrace.o
+ write.o namespace.o mount_clnt.o nfstrace.o export.o
nfs-$(CONFIG_ROOT_NFS) += nfsroot.o
nfs-$(CONFIG_SYSCTL) += sysctl.o
nfs-$(CONFIG_NFS_FSCACHE) += fscache.o fscache-index.o
diff --git a/fs/nfs/export.c b/fs/nfs/export.c
new file mode 100644
index 000000000000..249cb96cc5b5
--- /dev/null
+++ b/fs/nfs/export.c
@@ -0,0 +1,177 @@
+/*
+ * Copyright (c) 2015, Primary Data, Inc. All rights reserved.
+ *
+ * Tao Peng <[email protected]>
+ */
+#include <linux/dcache.h>
+#include <linux/exportfs.h>
+#include <linux/nfs.h>
+#include <linux/nfs_fs.h>
+
+#include "internal.h"
+#include "nfstrace.h"
+
+#define NFSDBG_FACILITY NFSDBG_VFS
+
+enum {
+ FILEID_HIGH_OFF = 0, /* inode fileid high */
+ FILEID_LOW_OFF, /* inode fileid low */
+ FILE_I_TYPE_OFF, /* inode type */
+ EMBED_FH_OFF /* embeded server fh */
+};
+
+
+static struct nfs_fh *nfs_exp_embedfh(__u32 *p)
+{
+ return (struct nfs_fh *)(p + EMBED_FH_OFF);
+}
+
+/*
+ * Let's break subtree checking for now... otherwise we'll have to embed parent fh
+ * but there might not be enough space.
+ */
+static int
+nfs_encode_fh(struct inode *inode, __u32 *p, int *max_len, struct inode *parent)
+{
+ struct nfs_fh *server_fh = NFS_FH(inode);
+ struct nfs_fh *clnt_fh = nfs_exp_embedfh(p);
+ size_t fh_size = offsetof(struct nfs_fh, data) + server_fh->size;
+ int len = EMBED_FH_OFF + XDR_QUADLEN(fh_size);
+
+ dprintk("%s: max fh len %d inode %p parent %p",
+ __func__, *max_len, inode, parent);
+
+ if (*max_len < len || IS_AUTOMOUNT(inode)) {
+ dprintk("%s: fh len %d too small, required %d\n",
+ __func__, *max_len, len);
+ *max_len = len;
+ return FILEID_INVALID;
+ }
+ if (IS_AUTOMOUNT(inode)) {
+ *max_len = FILEID_INVALID;
+ goto out;
+ }
+
+ p[FILEID_HIGH_OFF] = NFS_FILEID(inode) >> 32;
+ p[FILEID_LOW_OFF] = NFS_FILEID(inode);
+ p[FILE_I_TYPE_OFF] = inode->i_mode & S_IFMT;
+ p[len - 1] = 0; /* Padding */
+ nfs_copy_fh(clnt_fh, server_fh);
+ *max_len = len;
+out:
+ dprintk("%s: result fh fileid %llu mode %u size %d\n",
+ __func__, NFS_FILEID(inode), inode->i_mode, *max_len);
+ return *max_len;
+}
+
+static struct dentry *
+nfs_fh_to_dentry(struct super_block *sb, struct fid *fid,
+ int fh_len, int fh_type)
+{
+ struct nfs4_label *label = NULL;
+ struct nfs_fattr *fattr = NULL;
+ struct nfs_fh *server_fh = nfs_exp_embedfh(fid->raw);
+ size_t fh_size = offsetof(struct nfs_fh, data) + server_fh->size;
+ const struct nfs_rpc_ops *rpc_ops;
+ struct dentry *dentry;
+ struct inode *inode;
+ int len = EMBED_FH_OFF + XDR_QUADLEN(fh_size);
+ u32 *p = fid->raw;
+ int ret;
+
+ /* NULL translates to ESTALE */
+ if (fh_len < len || fh_type != len)
+ return NULL;
+
+ fattr = nfs_alloc_fattr();
+ if (fattr == NULL) {
+ dentry = ERR_PTR(-ENOMEM);
+ goto out;
+ }
+
+ fattr->fileid = ((u64)p[FILEID_HIGH_OFF] << 32) + p[FILEID_LOW_OFF];
+ fattr->mode = p[FILE_I_TYPE_OFF];
+ fattr->valid |= NFS_ATTR_FATTR_FILEID | NFS_ATTR_FATTR_TYPE;
+
+ dprintk("%s: fileid %llu mode %d\n", __func__, fattr->fileid, fattr->mode);
+
+ inode = nfs_ilookup(sb, fattr, server_fh);
+ if (inode)
+ goto out_found;
+
+ label = nfs4_label_alloc(NFS_SB(sb), GFP_KERNEL);
+ if (IS_ERR(label)) {
+ dentry = ERR_CAST(label);
+ goto out_free_fattr;
+ }
+
+ rpc_ops = NFS_SB(sb)->nfs_client->rpc_ops;
+ ret = rpc_ops->getattr(NFS_SB(sb), server_fh, fattr, label);
+ if (ret) {
+ dprintk("%s: getattr failed %d\n", __func__, ret);
+ dentry = ERR_PTR(ret);
+ goto out_free_label;
+ }
+
+ inode = nfs_fhget(sb, server_fh, fattr, label);
+
+out_found:
+ dentry = d_obtain_alias(inode);
+
+out_free_label:
+ nfs4_label_free(label);
+out_free_fattr:
+ nfs_free_fattr(fattr);
+out:
+ return dentry;
+}
+
+static struct dentry *
+nfs_get_parent(struct dentry *dentry)
+{
+ int ret;
+ struct inode *inode = d_inode(dentry), *pinode;
+ struct super_block *sb = inode->i_sb;
+ struct nfs_server *server = NFS_SB(sb);
+ struct nfs_fattr *fattr = NULL;
+ struct nfs4_label *label = NULL;
+ struct dentry *parent;
+ struct nfs_rpc_ops const *ops = server->nfs_client->rpc_ops;
+ struct nfs_fh fh;
+
+ if (!ops->lookupp)
+ return ERR_PTR(-EACCES);
+
+ fattr = nfs_alloc_fattr();
+ if (fattr == NULL) {
+ parent = ERR_PTR(-ENOMEM);
+ goto out;
+ }
+
+ label = nfs4_label_alloc(server, GFP_KERNEL);
+ if (IS_ERR(label)) {
+ parent = ERR_CAST(label);
+ goto out_free_fattr;
+ }
+
+ ret = ops->lookupp(inode, &fh, fattr, label);
+ if (ret) {
+ parent = ERR_PTR(ret);
+ goto out_free_label;
+ }
+
+ pinode = nfs_fhget(sb, &fh, fattr, label);
+ parent = d_obtain_alias(pinode);
+out_free_label:
+ nfs4_label_free(label);
+out_free_fattr:
+ nfs_free_fattr(fattr);
+out:
+ return parent;
+}
+
+const struct export_operations nfs_export_ops = {
+ .encode_fh = nfs_encode_fh,
+ .fh_to_dentry = nfs_fh_to_dentry,
+ .get_parent = nfs_get_parent,
+};
diff --git a/fs/nfs/internal.h b/fs/nfs/internal.h
index 3e24392f2caa..cb38c3cd6a49 100644
--- a/fs/nfs/internal.h
+++ b/fs/nfs/internal.h
@@ -10,6 +10,8 @@

#define NFS_MS_MASK (MS_RDONLY|MS_NOSUID|MS_NODEV|MS_NOEXEC|MS_SYNCHRONOUS)

+extern const struct export_operations nfs_export_ops;
+
struct nfs_string;

/* Maximum number of readahead requests
diff --git a/fs/nfs/super.c b/fs/nfs/super.c
index eceb4eabb064..86781a630c22 100644
--- a/fs/nfs/super.c
+++ b/fs/nfs/super.c
@@ -2339,6 +2339,7 @@ void nfs_fill_super(struct super_block *sb, struct nfs_mount_info *mount_info)
*/
sb->s_flags |= MS_POSIXACL;
sb->s_time_gran = 1;
+ sb->s_export_op = &nfs_export_ops;
}

nfs_initialise_sb(sb);
@@ -2360,6 +2361,7 @@ static void nfs_clone_super(struct super_block *sb,
sb->s_xattr = old_sb->s_xattr;
sb->s_op = old_sb->s_op;
sb->s_time_gran = 1;
+ sb->s_export_op = old_sb->s_export_op;

if (server->nfs_client->rpc_ops->version != 2) {
/* The VFS shouldn't apply the umask to mode bits. We will do
--
2.11.0


2017-06-27 15:44:08

by Christoph Hellwig

[permalink] [raw]
Subject: [PATCH 1/4] nfs: replace d_add with d_splice_alias in atomic_open

From: Peng Tao <[email protected]>

It's a trival change but follows knfsd export document that asks
for d_splice_alias during lookup.

Signed-off-by: Peng Tao <[email protected]>
---
fs/nfs/dir.c | 2 +-
1 file changed, 1 insertion(+), 1 deletion(-)

diff --git a/fs/nfs/dir.c b/fs/nfs/dir.c
index 32ccd7754f8a..0296c06dcdc5 100644
--- a/fs/nfs/dir.c
+++ b/fs/nfs/dir.c
@@ -1512,7 +1512,7 @@ int nfs_atomic_open(struct inode *dir, struct dentry *dentry,
d_drop(dentry);
switch (err) {
case -ENOENT:
- d_add(dentry, NULL);
+ d_splice_alias(NULL, dentry);
nfs_set_verifier(dentry, nfs_save_change_attribute(dir));
break;
case -EISDIR:
--
2.11.0


2017-06-27 15:44:09

by Christoph Hellwig

[permalink] [raw]
Subject: [PATCH 2/4] nfs: add a nfs_ilookup helper

From: Peng Tao <[email protected]>

This helper will allow to find an existing NFS inode by the file handle
and fattr.

Signed-off-by: Peng Tao <[email protected]>
[hch: split from a larger patch]
Signed-off-by: Christoph Hellwig <[email protected]>
---
fs/nfs/inode.c | 22 ++++++++++++++++++++++
include/linux/nfs_fs.h | 1 +
2 files changed, 23 insertions(+)

diff --git a/fs/nfs/inode.c b/fs/nfs/inode.c
index 1de93ba78dc9..a84eab1a18a7 100644
--- a/fs/nfs/inode.c
+++ b/fs/nfs/inode.c
@@ -386,6 +386,28 @@ void nfs_setsecurity(struct inode *inode, struct nfs_fattr *fattr,
#endif
EXPORT_SYMBOL_GPL(nfs_setsecurity);

+/* Search for inode identified by fh, fileid and i_mode in inode cache. */
+struct inode *
+nfs_ilookup(struct super_block *sb, struct nfs_fattr *fattr, struct nfs_fh *fh)
+{
+ struct nfs_find_desc desc = {
+ .fh = fh,
+ .fattr = fattr,
+ };
+ struct inode *inode;
+ unsigned long hash;
+
+ if (!(fattr->valid & NFS_ATTR_FATTR_FILEID) ||
+ !(fattr->valid & NFS_ATTR_FATTR_TYPE))
+ return NULL;
+
+ hash = nfs_fattr_to_ino_t(fattr);
+ inode = ilookup5(sb, hash, nfs_find_actor, &desc);
+
+ dprintk("%s: returning %p\n", __func__, inode);
+ return inode;
+}
+
/*
* This is our front-end to iget that looks up inodes by file handle
* instead of inode number.
diff --git a/include/linux/nfs_fs.h b/include/linux/nfs_fs.h
index bb0eb2c9acca..e52cc55ac300 100644
--- a/include/linux/nfs_fs.h
+++ b/include/linux/nfs_fs.h
@@ -332,6 +332,7 @@ extern void nfs_zap_caches(struct inode *);
extern void nfs_invalidate_atime(struct inode *);
extern struct inode *nfs_fhget(struct super_block *, struct nfs_fh *,
struct nfs_fattr *, struct nfs4_label *);
+struct inode *nfs_ilookup(struct super_block *sb, struct nfs_fattr *, struct nfs_fh *);
extern int nfs_refresh_inode(struct inode *, struct nfs_fattr *);
extern int nfs_post_op_update_inode(struct inode *inode, struct nfs_fattr *fattr);
extern int nfs_post_op_update_inode_force_wcc(struct inode *inode, struct nfs_fattr *fattr);
--
2.11.0


2017-06-27 15:44:09

by Christoph Hellwig

[permalink] [raw]
Subject: [PATCH 3/4] nfs4: add NFSv4 LOOKUPP handlers

From: Jeff Layton <[email protected]>

This will be needed in order to implement the get_parent export op
for nfsd.

Signed-off-by: Jeff Layton <[email protected]>
---
fs/nfs/nfs4proc.c | 49 +++++++++++++++++++++++++++++++++
fs/nfs/nfs4trace.h | 29 ++++++++++++++++++++
fs/nfs/nfs4xdr.c | 73 +++++++++++++++++++++++++++++++++++++++++++++++++
include/linux/nfs4.h | 1 +
include/linux/nfs_xdr.h | 17 +++++++++++-
5 files changed, 168 insertions(+), 1 deletion(-)

diff --git a/fs/nfs/nfs4proc.c b/fs/nfs/nfs4proc.c
index c08c46a3b8cd..6fd9eee8e4ee 100644
--- a/fs/nfs/nfs4proc.c
+++ b/fs/nfs/nfs4proc.c
@@ -3802,6 +3802,54 @@ nfs4_proc_lookup_mountpoint(struct inode *dir, const struct qstr *name,
return (client == NFS_CLIENT(dir)) ? rpc_clone_client(client) : client;
}

+static int _nfs4_proc_lookupp(struct inode *inode,
+ struct nfs_fh *fhandle, struct nfs_fattr *fattr,
+ struct nfs4_label *label)
+{
+ struct rpc_clnt *clnt = NFS_CLIENT(inode);
+ struct nfs_server *server = NFS_SERVER(inode);
+ int status;
+ struct nfs4_lookupp_arg args = {
+ .bitmask = server->attr_bitmask,
+ .fh = NFS_FH(inode),
+ };
+ struct nfs4_lookupp_res res = {
+ .server = server,
+ .fattr = fattr,
+ .label = label,
+ .fh = fhandle,
+ };
+ struct rpc_message msg = {
+ .rpc_proc = &nfs4_procedures[NFSPROC4_CLNT_LOOKUPP],
+ .rpc_argp = &args,
+ .rpc_resp = &res,
+ };
+
+ args.bitmask = nfs4_bitmask(server, label);
+
+ nfs_fattr_init(fattr);
+
+ dprintk("NFS call lookupp ino=0x%lx\n", inode->i_ino);
+ status = nfs4_call_sync(clnt, server, &msg, &args.seq_args,
+ &res.seq_res, 0);
+ dprintk("NFS reply lookupp: %d\n", status);
+ return status;
+}
+
+static int nfs4_proc_lookupp(struct inode *inode, struct nfs_fh *fhandle,
+ struct nfs_fattr *fattr, struct nfs4_label *label)
+{
+ struct nfs4_exception exception = { };
+ int err;
+ do {
+ err = _nfs4_proc_lookupp(inode, fhandle, fattr, label);
+ trace_nfs4_lookupp(inode, err);
+ err = nfs4_handle_exception(NFS_SERVER(inode), err,
+ &exception);
+ } while (exception.retry);
+ return err;
+}
+
static int _nfs4_proc_access(struct inode *inode, struct nfs_access_entry *entry)
{
struct nfs_server *server = NFS_SERVER(inode);
@@ -9312,6 +9360,7 @@ const struct nfs_rpc_ops nfs_v4_clientops = {
.getattr = nfs4_proc_getattr,
.setattr = nfs4_proc_setattr,
.lookup = nfs4_proc_lookup,
+ .lookupp = nfs4_proc_lookupp,
.access = nfs4_proc_access,
.readlink = nfs4_proc_readlink,
.create = nfs4_proc_create,
diff --git a/fs/nfs/nfs4trace.h b/fs/nfs/nfs4trace.h
index 845d0eadefc9..be1da19c65d6 100644
--- a/fs/nfs/nfs4trace.h
+++ b/fs/nfs/nfs4trace.h
@@ -891,6 +891,35 @@ DEFINE_NFS4_LOOKUP_EVENT(nfs4_remove);
DEFINE_NFS4_LOOKUP_EVENT(nfs4_get_fs_locations);
DEFINE_NFS4_LOOKUP_EVENT(nfs4_secinfo);

+TRACE_EVENT(nfs4_lookupp,
+ TP_PROTO(
+ const struct inode *inode,
+ int error
+ ),
+
+ TP_ARGS(inode, error),
+
+ TP_STRUCT__entry(
+ __field(dev_t, dev)
+ __field(u64, ino)
+ __field(int, error)
+ ),
+
+ TP_fast_assign(
+ __entry->dev = inode->i_sb->s_dev;
+ __entry->ino = NFS_FILEID(inode);
+ __entry->error = error;
+ ),
+
+ TP_printk(
+ "error=%d (%s) inode=%02x:%02x:%llu",
+ __entry->error,
+ show_nfsv4_errors(__entry->error),
+ MAJOR(__entry->dev), MINOR(__entry->dev),
+ (unsigned long long)__entry->ino
+ )
+);
+
TRACE_EVENT(nfs4_rename,
TP_PROTO(
const struct inode *olddir,
diff --git a/fs/nfs/nfs4xdr.c b/fs/nfs/nfs4xdr.c
index 3aebfdc82b30..b55017987dcd 100644
--- a/fs/nfs/nfs4xdr.c
+++ b/fs/nfs/nfs4xdr.c
@@ -159,6 +159,8 @@ static int nfs4_stat_to_errno(int);
(op_decode_hdr_maxsz)
#define encode_lookup_maxsz (op_encode_hdr_maxsz + nfs4_name_maxsz)
#define decode_lookup_maxsz (op_decode_hdr_maxsz)
+#define encode_lookupp_maxsz (op_encode_hdr_maxsz)
+#define decode_lookupp_maxsz (op_decode_hdr_maxsz)
#define encode_share_access_maxsz \
(2)
#define encode_createmode_maxsz (1 + encode_attrs_maxsz + encode_verifier_maxsz)
@@ -618,6 +620,18 @@ static int nfs4_stat_to_errno(int);
decode_lookup_maxsz + \
decode_getattr_maxsz + \
decode_getfh_maxsz)
+#define NFS4_enc_lookupp_sz (compound_encode_hdr_maxsz + \
+ encode_sequence_maxsz + \
+ encode_putfh_maxsz + \
+ encode_lookupp_maxsz + \
+ encode_getattr_maxsz + \
+ encode_getfh_maxsz)
+#define NFS4_dec_lookupp_sz (compound_decode_hdr_maxsz + \
+ decode_sequence_maxsz + \
+ decode_putfh_maxsz + \
+ decode_lookupp_maxsz + \
+ decode_getattr_maxsz + \
+ decode_getfh_maxsz)
#define NFS4_enc_lookup_root_sz (compound_encode_hdr_maxsz + \
encode_sequence_maxsz + \
encode_putrootfh_maxsz + \
@@ -1368,6 +1382,11 @@ static void encode_lookup(struct xdr_stream *xdr, const struct qstr *name, struc
encode_string(xdr, name->len, name->name);
}

+static void encode_lookupp(struct xdr_stream *xdr, struct compound_hdr *hdr)
+{
+ encode_op_hdr(xdr, OP_LOOKUPP, decode_lookupp_maxsz, hdr);
+}
+
static void encode_share_access(struct xdr_stream *xdr, u32 share_access)
{
__be32 *p;
@@ -2120,6 +2139,25 @@ static void nfs4_xdr_enc_lookup(struct rpc_rqst *req, struct xdr_stream *xdr,
}

/*
+ * Encode LOOKUPP request
+ */
+static void nfs4_xdr_enc_lookupp(struct rpc_rqst *req, struct xdr_stream *xdr,
+ const struct nfs4_lookupp_arg *args)
+{
+ struct compound_hdr hdr = {
+ .minorversion = nfs4_xdr_minorversion(&args->seq_args),
+ };
+
+ encode_compound_hdr(xdr, req, &hdr);
+ encode_sequence(xdr, &args->seq_args, &hdr);
+ encode_putfh(xdr, args->fh, &hdr);
+ encode_lookupp(xdr, &hdr);
+ encode_getfh(xdr, &hdr);
+ encode_getfattr(xdr, args->bitmask, &hdr);
+ encode_nops(&hdr);
+}
+
+/*
* Encode LOOKUP_ROOT request
*/
static void nfs4_xdr_enc_lookup_root(struct rpc_rqst *req,
@@ -5005,6 +5043,11 @@ static int decode_lookup(struct xdr_stream *xdr)
return decode_op_hdr(xdr, OP_LOOKUP);
}

+static int decode_lookupp(struct xdr_stream *xdr)
+{
+ return decode_op_hdr(xdr, OP_LOOKUPP);
+}
+
/* This is too sick! */
static int decode_space_limit(struct xdr_stream *xdr,
unsigned long *pagemod_limit)
@@ -6182,6 +6225,35 @@ static int nfs4_xdr_dec_lookup(struct rpc_rqst *rqstp, struct xdr_stream *xdr,
}

/*
+ * Decode LOOKUPP response
+ */
+static int nfs4_xdr_dec_lookupp(struct rpc_rqst *rqstp, struct xdr_stream *xdr,
+ struct nfs4_lookupp_res *res)
+{
+ struct compound_hdr hdr;
+ int status;
+
+ status = decode_compound_hdr(xdr, &hdr);
+ if (status)
+ goto out;
+ status = decode_sequence(xdr, &res->seq_res, rqstp);
+ if (status)
+ goto out;
+ status = decode_putfh(xdr);
+ if (status)
+ goto out;
+ status = decode_lookupp(xdr);
+ if (status)
+ goto out;
+ status = decode_getfh(xdr, res->fh);
+ if (status)
+ goto out;
+ status = decode_getfattr_label(xdr, res->fattr, res->label, res->server);
+out:
+ return status;
+}
+
+/*
* Decode LOOKUP_ROOT response
*/
static int nfs4_xdr_dec_lookup_root(struct rpc_rqst *rqstp,
@@ -7517,6 +7589,7 @@ struct rpc_procinfo nfs4_procedures[] = {
PROC(ACCESS, enc_access, dec_access),
PROC(GETATTR, enc_getattr, dec_getattr),
PROC(LOOKUP, enc_lookup, dec_lookup),
+ PROC(LOOKUPP, enc_lookupp, dec_lookupp),
PROC(LOOKUP_ROOT, enc_lookup_root, dec_lookup_root),
PROC(REMOVE, enc_remove, dec_remove),
PROC(RENAME, enc_rename, dec_rename),
diff --git a/include/linux/nfs4.h b/include/linux/nfs4.h
index 1b1ca04820a3..47239c336688 100644
--- a/include/linux/nfs4.h
+++ b/include/linux/nfs4.h
@@ -479,6 +479,7 @@ enum {
NFSPROC4_CLNT_ACCESS,
NFSPROC4_CLNT_GETATTR,
NFSPROC4_CLNT_LOOKUP,
+ NFSPROC4_CLNT_LOOKUPP,
NFSPROC4_CLNT_LOOKUP_ROOT,
NFSPROC4_CLNT_REMOVE,
NFSPROC4_CLNT_RENAME,
diff --git a/include/linux/nfs_xdr.h b/include/linux/nfs_xdr.h
index b28c83475ee8..7a664a5fcc25 100644
--- a/include/linux/nfs_xdr.h
+++ b/include/linux/nfs_xdr.h
@@ -1012,7 +1012,6 @@ struct nfs4_link_res {
struct nfs_fattr * dir_attr;
};

-
struct nfs4_lookup_arg {
struct nfs4_sequence_args seq_args;
const struct nfs_fh * dir_fh;
@@ -1028,6 +1027,20 @@ struct nfs4_lookup_res {
struct nfs4_label *label;
};

+struct nfs4_lookupp_arg {
+ struct nfs4_sequence_args seq_args;
+ const struct nfs_fh *fh;
+ const u32 *bitmask;
+};
+
+struct nfs4_lookupp_res {
+ struct nfs4_sequence_res seq_res;
+ const struct nfs_server *server;
+ struct nfs_fattr *fattr;
+ struct nfs_fh *fh;
+ struct nfs4_label *label;
+};
+
struct nfs4_lookup_root_arg {
struct nfs4_sequence_args seq_args;
const u32 * bitmask;
@@ -1567,6 +1580,8 @@ struct nfs_rpc_ops {
int (*lookup) (struct inode *, const struct qstr *,
struct nfs_fh *, struct nfs_fattr *,
struct nfs4_label *);
+ int (*lookupp) (struct inode *, struct nfs_fh *,
+ struct nfs_fattr *, struct nfs4_label *);
int (*access) (struct inode *, struct nfs_access_entry *);
int (*readlink)(struct inode *, struct page *, unsigned int,
unsigned int);
--
2.11.0


2017-06-28 14:55:44

by Anna Schumaker

[permalink] [raw]
Subject: Re: [PATCH 3/4] nfs4: add NFSv4 LOOKUPP handlers

Hi Christoph,

On 06/27/2017 11:44 AM, Christoph Hellwig wrote:
> From: Jeff Layton <[email protected]>
>
> This will be needed in order to implement the get_parent export op
> for nfsd.

I think this patch conflicts with your constify and function pointer cleanups from a few weeks ago, and it may need to be updated.

Just double checking: Bruce, are you taking the constify series for 4.13?

Thanks,
Anna

>
> Signed-off-by: Jeff Layton <[email protected]>
> ---
> fs/nfs/nfs4proc.c | 49 +++++++++++++++++++++++++++++++++
> fs/nfs/nfs4trace.h | 29 ++++++++++++++++++++
> fs/nfs/nfs4xdr.c | 73 +++++++++++++++++++++++++++++++++++++++++++++++++
> include/linux/nfs4.h | 1 +
> include/linux/nfs_xdr.h | 17 +++++++++++-
> 5 files changed, 168 insertions(+), 1 deletion(-)
>
> diff --git a/fs/nfs/nfs4proc.c b/fs/nfs/nfs4proc.c
> index c08c46a3b8cd..6fd9eee8e4ee 100644
> --- a/fs/nfs/nfs4proc.c
> +++ b/fs/nfs/nfs4proc.c
> @@ -3802,6 +3802,54 @@ nfs4_proc_lookup_mountpoint(struct inode *dir, const struct qstr *name,
> return (client == NFS_CLIENT(dir)) ? rpc_clone_client(client) : client;
> }
>
> +static int _nfs4_proc_lookupp(struct inode *inode,
> + struct nfs_fh *fhandle, struct nfs_fattr *fattr,
> + struct nfs4_label *label)
> +{
> + struct rpc_clnt *clnt = NFS_CLIENT(inode);
> + struct nfs_server *server = NFS_SERVER(inode);
> + int status;
> + struct nfs4_lookupp_arg args = {
> + .bitmask = server->attr_bitmask,
> + .fh = NFS_FH(inode),
> + };
> + struct nfs4_lookupp_res res = {
> + .server = server,
> + .fattr = fattr,
> + .label = label,
> + .fh = fhandle,
> + };
> + struct rpc_message msg = {
> + .rpc_proc = &nfs4_procedures[NFSPROC4_CLNT_LOOKUPP],
> + .rpc_argp = &args,
> + .rpc_resp = &res,
> + };
> +
> + args.bitmask = nfs4_bitmask(server, label);
> +
> + nfs_fattr_init(fattr);
> +
> + dprintk("NFS call lookupp ino=0x%lx\n", inode->i_ino);
> + status = nfs4_call_sync(clnt, server, &msg, &args.seq_args,
> + &res.seq_res, 0);
> + dprintk("NFS reply lookupp: %d\n", status);
> + return status;
> +}
> +
> +static int nfs4_proc_lookupp(struct inode *inode, struct nfs_fh *fhandle,
> + struct nfs_fattr *fattr, struct nfs4_label *label)
> +{
> + struct nfs4_exception exception = { };
> + int err;
> + do {
> + err = _nfs4_proc_lookupp(inode, fhandle, fattr, label);
> + trace_nfs4_lookupp(inode, err);
> + err = nfs4_handle_exception(NFS_SERVER(inode), err,
> + &exception);
> + } while (exception.retry);
> + return err;
> +}
> +
> static int _nfs4_proc_access(struct inode *inode, struct nfs_access_entry *entry)
> {
> struct nfs_server *server = NFS_SERVER(inode);
> @@ -9312,6 +9360,7 @@ const struct nfs_rpc_ops nfs_v4_clientops = {
> .getattr = nfs4_proc_getattr,
> .setattr = nfs4_proc_setattr,
> .lookup = nfs4_proc_lookup,
> + .lookupp = nfs4_proc_lookupp,
> .access = nfs4_proc_access,
> .readlink = nfs4_proc_readlink,
> .create = nfs4_proc_create,
> diff --git a/fs/nfs/nfs4trace.h b/fs/nfs/nfs4trace.h
> index 845d0eadefc9..be1da19c65d6 100644
> --- a/fs/nfs/nfs4trace.h
> +++ b/fs/nfs/nfs4trace.h
> @@ -891,6 +891,35 @@ DEFINE_NFS4_LOOKUP_EVENT(nfs4_remove);
> DEFINE_NFS4_LOOKUP_EVENT(nfs4_get_fs_locations);
> DEFINE_NFS4_LOOKUP_EVENT(nfs4_secinfo);
>
> +TRACE_EVENT(nfs4_lookupp,
> + TP_PROTO(
> + const struct inode *inode,
> + int error
> + ),
> +
> + TP_ARGS(inode, error),
> +
> + TP_STRUCT__entry(
> + __field(dev_t, dev)
> + __field(u64, ino)
> + __field(int, error)
> + ),
> +
> + TP_fast_assign(
> + __entry->dev = inode->i_sb->s_dev;
> + __entry->ino = NFS_FILEID(inode);
> + __entry->error = error;
> + ),
> +
> + TP_printk(
> + "error=%d (%s) inode=%02x:%02x:%llu",
> + __entry->error,
> + show_nfsv4_errors(__entry->error),
> + MAJOR(__entry->dev), MINOR(__entry->dev),
> + (unsigned long long)__entry->ino
> + )
> +);
> +
> TRACE_EVENT(nfs4_rename,
> TP_PROTO(
> const struct inode *olddir,
> diff --git a/fs/nfs/nfs4xdr.c b/fs/nfs/nfs4xdr.c
> index 3aebfdc82b30..b55017987dcd 100644
> --- a/fs/nfs/nfs4xdr.c
> +++ b/fs/nfs/nfs4xdr.c
> @@ -159,6 +159,8 @@ static int nfs4_stat_to_errno(int);
> (op_decode_hdr_maxsz)
> #define encode_lookup_maxsz (op_encode_hdr_maxsz + nfs4_name_maxsz)
> #define decode_lookup_maxsz (op_decode_hdr_maxsz)
> +#define encode_lookupp_maxsz (op_encode_hdr_maxsz)
> +#define decode_lookupp_maxsz (op_decode_hdr_maxsz)
> #define encode_share_access_maxsz \
> (2)
> #define encode_createmode_maxsz (1 + encode_attrs_maxsz + encode_verifier_maxsz)
> @@ -618,6 +620,18 @@ static int nfs4_stat_to_errno(int);
> decode_lookup_maxsz + \
> decode_getattr_maxsz + \
> decode_getfh_maxsz)
> +#define NFS4_enc_lookupp_sz (compound_encode_hdr_maxsz + \
> + encode_sequence_maxsz + \
> + encode_putfh_maxsz + \
> + encode_lookupp_maxsz + \
> + encode_getattr_maxsz + \
> + encode_getfh_maxsz)
> +#define NFS4_dec_lookupp_sz (compound_decode_hdr_maxsz + \
> + decode_sequence_maxsz + \
> + decode_putfh_maxsz + \
> + decode_lookupp_maxsz + \
> + decode_getattr_maxsz + \
> + decode_getfh_maxsz)
> #define NFS4_enc_lookup_root_sz (compound_encode_hdr_maxsz + \
> encode_sequence_maxsz + \
> encode_putrootfh_maxsz + \
> @@ -1368,6 +1382,11 @@ static void encode_lookup(struct xdr_stream *xdr, const struct qstr *name, struc
> encode_string(xdr, name->len, name->name);
> }
>
> +static void encode_lookupp(struct xdr_stream *xdr, struct compound_hdr *hdr)
> +{
> + encode_op_hdr(xdr, OP_LOOKUPP, decode_lookupp_maxsz, hdr);
> +}
> +
> static void encode_share_access(struct xdr_stream *xdr, u32 share_access)
> {
> __be32 *p;
> @@ -2120,6 +2139,25 @@ static void nfs4_xdr_enc_lookup(struct rpc_rqst *req, struct xdr_stream *xdr,
> }
>
> /*
> + * Encode LOOKUPP request
> + */
> +static void nfs4_xdr_enc_lookupp(struct rpc_rqst *req, struct xdr_stream *xdr,
> + const struct nfs4_lookupp_arg *args)
> +{
> + struct compound_hdr hdr = {
> + .minorversion = nfs4_xdr_minorversion(&args->seq_args),
> + };
> +
> + encode_compound_hdr(xdr, req, &hdr);
> + encode_sequence(xdr, &args->seq_args, &hdr);
> + encode_putfh(xdr, args->fh, &hdr);
> + encode_lookupp(xdr, &hdr);
> + encode_getfh(xdr, &hdr);
> + encode_getfattr(xdr, args->bitmask, &hdr);
> + encode_nops(&hdr);
> +}
> +
> +/*
> * Encode LOOKUP_ROOT request
> */
> static void nfs4_xdr_enc_lookup_root(struct rpc_rqst *req,
> @@ -5005,6 +5043,11 @@ static int decode_lookup(struct xdr_stream *xdr)
> return decode_op_hdr(xdr, OP_LOOKUP);
> }
>
> +static int decode_lookupp(struct xdr_stream *xdr)
> +{
> + return decode_op_hdr(xdr, OP_LOOKUPP);
> +}
> +
> /* This is too sick! */
> static int decode_space_limit(struct xdr_stream *xdr,
> unsigned long *pagemod_limit)
> @@ -6182,6 +6225,35 @@ static int nfs4_xdr_dec_lookup(struct rpc_rqst *rqstp, struct xdr_stream *xdr,
> }
>
> /*
> + * Decode LOOKUPP response
> + */
> +static int nfs4_xdr_dec_lookupp(struct rpc_rqst *rqstp, struct xdr_stream *xdr,
> + struct nfs4_lookupp_res *res)
> +{
> + struct compound_hdr hdr;
> + int status;
> +
> + status = decode_compound_hdr(xdr, &hdr);
> + if (status)
> + goto out;
> + status = decode_sequence(xdr, &res->seq_res, rqstp);
> + if (status)
> + goto out;
> + status = decode_putfh(xdr);
> + if (status)
> + goto out;
> + status = decode_lookupp(xdr);
> + if (status)
> + goto out;
> + status = decode_getfh(xdr, res->fh);
> + if (status)
> + goto out;
> + status = decode_getfattr_label(xdr, res->fattr, res->label, res->server);
> +out:
> + return status;
> +}
> +
> +/*
> * Decode LOOKUP_ROOT response
> */
> static int nfs4_xdr_dec_lookup_root(struct rpc_rqst *rqstp,
> @@ -7517,6 +7589,7 @@ struct rpc_procinfo nfs4_procedures[] = {
> PROC(ACCESS, enc_access, dec_access),
> PROC(GETATTR, enc_getattr, dec_getattr),
> PROC(LOOKUP, enc_lookup, dec_lookup),
> + PROC(LOOKUPP, enc_lookupp, dec_lookupp),
> PROC(LOOKUP_ROOT, enc_lookup_root, dec_lookup_root),
> PROC(REMOVE, enc_remove, dec_remove),
> PROC(RENAME, enc_rename, dec_rename),
> diff --git a/include/linux/nfs4.h b/include/linux/nfs4.h
> index 1b1ca04820a3..47239c336688 100644
> --- a/include/linux/nfs4.h
> +++ b/include/linux/nfs4.h
> @@ -479,6 +479,7 @@ enum {
> NFSPROC4_CLNT_ACCESS,
> NFSPROC4_CLNT_GETATTR,
> NFSPROC4_CLNT_LOOKUP,
> + NFSPROC4_CLNT_LOOKUPP,
> NFSPROC4_CLNT_LOOKUP_ROOT,
> NFSPROC4_CLNT_REMOVE,
> NFSPROC4_CLNT_RENAME,
> diff --git a/include/linux/nfs_xdr.h b/include/linux/nfs_xdr.h
> index b28c83475ee8..7a664a5fcc25 100644
> --- a/include/linux/nfs_xdr.h
> +++ b/include/linux/nfs_xdr.h
> @@ -1012,7 +1012,6 @@ struct nfs4_link_res {
> struct nfs_fattr * dir_attr;
> };
>
> -
> struct nfs4_lookup_arg {
> struct nfs4_sequence_args seq_args;
> const struct nfs_fh * dir_fh;
> @@ -1028,6 +1027,20 @@ struct nfs4_lookup_res {
> struct nfs4_label *label;
> };
>
> +struct nfs4_lookupp_arg {
> + struct nfs4_sequence_args seq_args;
> + const struct nfs_fh *fh;
> + const u32 *bitmask;
> +};
> +
> +struct nfs4_lookupp_res {
> + struct nfs4_sequence_res seq_res;
> + const struct nfs_server *server;
> + struct nfs_fattr *fattr;
> + struct nfs_fh *fh;
> + struct nfs4_label *label;
> +};
> +
> struct nfs4_lookup_root_arg {
> struct nfs4_sequence_args seq_args;
> const u32 * bitmask;
> @@ -1567,6 +1580,8 @@ struct nfs_rpc_ops {
> int (*lookup) (struct inode *, const struct qstr *,
> struct nfs_fh *, struct nfs_fattr *,
> struct nfs4_label *);
> + int (*lookupp) (struct inode *, struct nfs_fh *,
> + struct nfs_fattr *, struct nfs4_label *);
> int (*access) (struct inode *, struct nfs_access_entry *);
> int (*readlink)(struct inode *, struct page *, unsigned int,
> unsigned int);
>

2017-06-28 15:13:36

by J. Bruce Fields

[permalink] [raw]
Subject: Re: [PATCH 3/4] nfs4: add NFSv4 LOOKUPP handlers

On Wed, Jun 28, 2017 at 10:55:35AM -0400, Anna Schumaker wrote:
> Hi Christoph,
>
> On 06/27/2017 11:44 AM, Christoph Hellwig wrote:
> > From: Jeff Layton <[email protected]>
> >
> > This will be needed in order to implement the get_parent export op
> > for nfsd.
>
> I think this patch conflicts with your constify and function pointer cleanups from a few weeks ago, and it may need to be updated.
>
> Just double checking: Bruce, are you taking the constify series for 4.13?

Sorry, I haven't been paying attention--what constify series?

--b.

2017-06-28 15:17:49

by Anna Schumaker

[permalink] [raw]
Subject: Re: [PATCH 3/4] nfs4: add NFSv4 LOOKUPP handlers



On 06/28/2017 11:13 AM, J. Bruce Fields wrote:
> On Wed, Jun 28, 2017 at 10:55:35AM -0400, Anna Schumaker wrote:
>> Hi Christoph,
>>
>> On 06/27/2017 11:44 AM, Christoph Hellwig wrote:
>>> From: Jeff Layton <[email protected]>
>>>
>>> This will be needed in order to implement the get_parent export op
>>> for nfsd.
>>
>> I think this patch conflicts with your constify and function pointer cleanups from a few weeks ago, and it may need to be updated.
>>
>> Just double checking: Bruce, are you taking the constify series for 4.13?
>
> Sorry, I haven't been paying attention--what constify series?

The one Christoph sent out in May that touched all of nfs, nfsd, and sunrpc. I wasn't sure if we had come to a decision about who is sending that in or not :)

>
> --b.
>

2017-06-28 15:22:51

by J. Bruce Fields

[permalink] [raw]
Subject: Re: [PATCH 3/4] nfs4: add NFSv4 LOOKUPP handlers

On Wed, Jun 28, 2017 at 11:17:41AM -0400, Anna Schumaker wrote:
>
>
> On 06/28/2017 11:13 AM, J. Bruce Fields wrote:
> > On Wed, Jun 28, 2017 at 10:55:35AM -0400, Anna Schumaker wrote:
> >> Hi Christoph,
> >>
> >> On 06/27/2017 11:44 AM, Christoph Hellwig wrote:
> >>> From: Jeff Layton <[email protected]>
> >>>
> >>> This will be needed in order to implement the get_parent export op
> >>> for nfsd.
> >>
> >> I think this patch conflicts with your constify and function pointer cleanups from a few weeks ago, and it may need to be updated.
> >>
> >> Just double checking: Bruce, are you taking the constify series for 4.13?
> >
> > Sorry, I haven't been paying attention--what constify series?
>
> The one Christoph sent out in May that touched all of nfs, nfsd, and sunrpc. I wasn't sure if we had come to a decision about who is sending that in or not :)

Gah, right, sorry. I still intend to just pull his nfs-ops branch, but
I think I got distracted by test failures caused by an unrelated vm
networking issues. I'll take a look....

--b.

2017-06-28 16:45:37

by Christoph Hellwig

[permalink] [raw]
Subject: Re: [PATCH 3/4] nfs4: add NFSv4 LOOKUPP handlers

On Wed, Jun 28, 2017 at 10:55:35AM -0400, Anna Schumaker wrote:
> Hi Christoph,
>
> On 06/27/2017 11:44 AM, Christoph Hellwig wrote:
> > From: Jeff Layton <[email protected]>
> >
> > This will be needed in order to implement the get_parent export op
> > for nfsd.
>
> I think this patch conflicts with your constify and function pointer cleanups from a few weeks ago, and it may need to be updated.
>
> Just double checking: Bruce, are you taking the constify series for 4.13?

Seems like it's in linux-next through Bruce's tree.

I can respin these patches against it. Anna, Trond: are you fine
with just basing the nfs tree on top of the nfsd one? Or do we want
to take this series through the nfsd tree?

2017-06-28 17:30:51

by J. Bruce Fields

[permalink] [raw]
Subject: Re: [PATCH 3/4] nfs4: add NFSv4 LOOKUPP handlers

On Wed, Jun 28, 2017 at 06:45:35PM +0200, Christoph Hellwig wrote:
> On Wed, Jun 28, 2017 at 10:55:35AM -0400, Anna Schumaker wrote:
> > Hi Christoph,
> >
> > On 06/27/2017 11:44 AM, Christoph Hellwig wrote:
> > > From: Jeff Layton <[email protected]>
> > >
> > > This will be needed in order to implement the get_parent export op
> > > for nfsd.
> >
> > I think this patch conflicts with your constify and function pointer cleanups from a few weeks ago, and it may need to be updated.
> >
> > Just double checking: Bruce, are you taking the constify series for 4.13?
>
> Seems like it's in linux-next through Bruce's tree.

That's literally just your nfs-ops branch. I was assuming that's what
we'd both work on top of.

--b.

> I can respin these patches against it. Anna, Trond: are you fine
> with just basing the nfs tree on top of the nfsd one? Or do we want
> to take this series through the nfsd tree?