Donate to e Foundation | Murena handsets with /e/OS | Own a part of Murena! Learn more

Commit 683b57b4 authored by Trond Myklebust's avatar Trond Myklebust
Browse files

NFSv4: Implement the fs_locations function call



NFSv4 allows for the fact that filesystems may be replicated across
several servers or that they may be migrated to a backup server in case of
failure of the primary server.
fs_locations is an NFSv4 operation for retrieving information about the
location of migrated and/or replicated filesystems.

Based on an initial implementation by Jiaying Zhang <jiayingz@citi.umich.edu>
Signed-off-by: default avatarTrond Myklebust <Trond.Myklebust@netapp.com>
parent 8b23ea7b
Loading
Loading
Loading
Loading
+2 −0
Original line number Diff line number Diff line
@@ -218,6 +218,8 @@ extern int nfs4_do_close(struct inode *inode, struct nfs4_state *state);
extern struct dentry *nfs4_atomic_open(struct inode *, struct dentry *, struct nameidata *);
extern int nfs4_open_revalidate(struct inode *, struct dentry *, int, struct nameidata *);
extern int nfs4_server_capabilities(struct nfs_server *server, struct nfs_fh *fhandle);
extern int nfs4_proc_fs_locations(struct inode *dir, struct dentry *dentry,
		struct nfs_fs_locations *fs_locations, struct page *page);

extern struct nfs4_state_recovery_ops nfs4_reboot_recovery_ops;
extern struct nfs4_state_recovery_ops nfs4_network_partition_recovery_ops;
+29 −0
Original line number Diff line number Diff line
@@ -3570,6 +3570,35 @@ ssize_t nfs4_listxattr(struct dentry *dentry, char *buf, size_t buflen)
	return len;
}

int nfs4_proc_fs_locations(struct inode *dir, struct dentry *dentry,
		struct nfs_fs_locations *fs_locations, struct page *page)
{
	struct nfs_server *server = NFS_SERVER(dir);
	u32 bitmask[2] = {
		[0] = server->attr_bitmask[0] | FATTR4_WORD0_FS_LOCATIONS,
		[1] = server->attr_bitmask[1],
	};
	struct nfs4_fs_locations_arg args = {
		.dir_fh = NFS_FH(dir),
		.name = &dentry->d_name,
		.page = page,
		.bitmask = bitmask,
	};
	struct rpc_message msg = {
		.rpc_proc = &nfs4_procedures[NFSPROC4_CLNT_FS_LOCATIONS],
		.rpc_argp = &args,
		.rpc_resp = &fs_locations,
	};
	int status;

	dprintk("%s: start\n", __FUNCTION__);
	fs_locations->fattr.valid = 0;
	fs_locations->server = server;
	status = rpc_call_sync(server->client, &msg, 0);
	dprintk("%s: returned status = %d\n", __FUNCTION__, status);
	return status;
}

struct nfs4_state_recovery_ops nfs4_reboot_recovery_ops = {
	.recover_open	= nfs4_open_reclaim,
	.recover_lock	= nfs4_lock_reclaim,
+110 −2
Original line number Diff line number Diff line
@@ -411,6 +411,15 @@ static int nfs_stat_to_errno(int);
#define NFS4_dec_setacl_sz	(compound_decode_hdr_maxsz + \
				decode_putfh_maxsz + \
				op_decode_hdr_maxsz + nfs4_fattr_bitmap_maxsz)
#define NFS4_enc_fs_locations_sz \
				(compound_encode_hdr_maxsz + \
				 encode_putfh_maxsz + \
				 encode_getattr_maxsz)
#define NFS4_dec_fs_locations_sz \
				(compound_decode_hdr_maxsz + \
				 decode_putfh_maxsz + \
				 op_decode_hdr_maxsz + \
				 nfs4_fattr_bitmap_maxsz)

static struct {
	unsigned int	mode;
@@ -2002,6 +2011,38 @@ static int nfs4_xdr_enc_delegreturn(struct rpc_rqst *req, uint32_t *p, const str
	return status;
}

/*
 * Encode FS_LOCATIONS request
 */
static int nfs4_xdr_enc_fs_locations(struct rpc_rqst *req, uint32_t *p, struct nfs4_fs_locations_arg *args)
{
	struct xdr_stream xdr;
	struct compound_hdr hdr = {
		.nops = 3,
	};
	struct rpc_auth *auth = req->rq_task->tk_auth;
	int replen;
	int status;

	xdr_init_encode(&xdr, &req->rq_snd_buf, p);
	encode_compound_hdr(&xdr, &hdr);
	if ((status = encode_putfh(&xdr, args->dir_fh)) != 0)
		goto out;
	if ((status = encode_lookup(&xdr, args->name)) != 0)
		goto out;
	if ((status = encode_getfattr(&xdr, args->bitmask)) != 0)
		goto out;
	/* set up reply
	 *   toplevel_status + taglen + rescount + OP_PUTFH + status
	 *   + OP_LOOKUP + status + OP_GETATTR + status = 7
	 */
	replen = (RPC_REPHDRSIZE + auth->au_rslack + 7) << 2;
	xdr_inline_pages(&req->rq_rcv_buf, replen, &args->page,
			0, PAGE_SIZE);
out:
	return status;
}

/*
 * START OF "GENERIC" DECODE ROUTINES.
 *   These may look a little ugly since they are imported from a "generic"
@@ -2036,7 +2077,7 @@ static int nfs4_xdr_enc_delegreturn(struct rpc_rqst *req, uint32_t *p, const str
	} \
} while (0)

static int decode_opaque_inline(struct xdr_stream *xdr, uint32_t *len, char **string)
static int decode_opaque_inline(struct xdr_stream *xdr, unsigned int *len, char **string)
{
	uint32_t *p;

@@ -2087,7 +2128,7 @@ static int decode_op_hdr(struct xdr_stream *xdr, enum nfs_opnum4 expected)
static int decode_ace(struct xdr_stream *xdr, void *ace, struct nfs4_client *clp)
{
	uint32_t *p;
	uint32_t strlen;
	unsigned int strlen;
	char *str;

	READ_BUF(12);
@@ -2336,6 +2377,45 @@ static int decode_attr_files_total(struct xdr_stream *xdr, uint32_t *bitmap, uin
	return status;
}

static int decode_attr_fs_locations(struct xdr_stream *xdr, uint32_t *bitmap, struct nfs_fs_locations *res)
{
	int n;
	uint32_t *p;
	int status = -EIO;

	if (unlikely(bitmap[0] & (FATTR4_WORD0_FS_LOCATIONS -1U)))
		goto out;
	status = 0;
	if (unlikely(!(bitmap[0] & FATTR4_WORD0_FS_LOCATIONS)))
		goto out;
	status = decode_opaque_inline(xdr, &res->fs_pathlen, &res->fs_path);
	if (unlikely(status != 0))
		goto out;
	READ_BUF(4);
	READ32(n);
	if (n <= 0)
		goto out_eio;
	res->nlocations = 0;
	while (res->nlocations < n) {
		struct nfs_fs_location *loc = &res->locations[res->nlocations];

		status = decode_opaque_inline(xdr, &loc->serverlen, &loc->server);
		if (unlikely(status != 0))
			goto out_eio;
		status = decode_opaque_inline(xdr, &loc->rootpathlen, &loc->rootpath);
		if (unlikely(status != 0))
			goto out_eio;
		if (res->nlocations < NFS_FS_LOCATIONS_MAXENTRIES)
			res->nlocations++;
	}
out:
	dprintk("%s: fs_locations done, error = %d\n", __FUNCTION__, status);
	return status;
out_eio:
	status = -EIO;
	goto out;
}

static int decode_attr_maxfilesize(struct xdr_stream *xdr, uint32_t *bitmap, uint64_t *res)
{
	uint32_t *p;
@@ -2867,6 +2947,10 @@ static int decode_getfattr(struct xdr_stream *xdr, struct nfs_fattr *fattr, cons
		goto xdr_error;
	if ((status = decode_attr_fileid(xdr, bitmap, &fattr->fileid)) != 0)
		goto xdr_error;
	if ((status = decode_attr_fs_locations(xdr, bitmap, container_of(fattr,
						struct nfs_fs_locations,
						fattr))) != 0)
		goto xdr_error;
	if ((status = decode_attr_mode(xdr, bitmap, &fattr->mode)) != 0)
		goto xdr_error;
	fattr->mode |= fmode;
@@ -4210,6 +4294,29 @@ static int nfs4_xdr_dec_delegreturn(struct rpc_rqst *rqstp, uint32_t *p, struct
	return status;
}

/*
 * FS_LOCATIONS request
 */
static int nfs4_xdr_dec_fs_locations(struct rpc_rqst *req, uint32_t *p, struct nfs_fs_locations *res)
{
	struct xdr_stream xdr;
	struct compound_hdr hdr;
	int status;

	xdr_init_decode(&xdr, &req->rq_rcv_buf, p);
	status = decode_compound_hdr(&xdr, &hdr);
	if (status != 0)
		goto out;
	if ((status = decode_putfh(&xdr)) != 0)
		goto out;
	if ((status = decode_lookup(&xdr)) != 0)
		goto out;
	xdr_enter_page(&xdr, PAGE_SIZE);
	status = decode_getfattr(&xdr, &res->fattr, res->server);
out:
	return status;
}

uint32_t *nfs4_decode_dirent(uint32_t *p, struct nfs_entry *entry, int plus)
{
	uint32_t bitmap[2] = {0};
@@ -4381,6 +4488,7 @@ struct rpc_procinfo nfs4_procedures[] = {
  PROC(DELEGRETURN,	enc_delegreturn, dec_delegreturn),
  PROC(GETACL,		enc_getacl,	dec_getacl),
  PROC(SETACL,		enc_setacl,	dec_setacl),
  PROC(FS_LOCATIONS,	enc_fs_locations, dec_fs_locations),
};

struct rpc_version		nfs_version4 = {
+1 −0
Original line number Diff line number Diff line
@@ -384,6 +384,7 @@ enum {
	NFSPROC4_CLNT_DELEGRETURN,
	NFSPROC4_CLNT_GETACL,
	NFSPROC4_CLNT_SETACL,
	NFSPROC4_CLNT_FS_LOCATIONS,
};

#endif
+24 −0
Original line number Diff line number Diff line
@@ -679,6 +679,30 @@ struct nfs4_server_caps_res {
	u32				has_symlinks;
};

struct nfs_fs_location {
	unsigned int serverlen;
	char * server;
	unsigned int rootpathlen;
	char * rootpath;
};

#define NFS_FS_LOCATIONS_MAXENTRIES 10
struct nfs_fs_locations {
	struct nfs_fattr fattr;
	const struct nfs_server *server;
	unsigned int fs_pathlen;
	char * fs_path;
	int nlocations;
	struct nfs_fs_location locations[NFS_FS_LOCATIONS_MAXENTRIES];
};

struct nfs4_fs_locations_arg {
	const struct nfs_fh *dir_fh;
	const struct qstr *name;
	struct page *page;
	const u32 *bitmask;
};

#endif /* CONFIG_NFS_V4 */

struct nfs_page;