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

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
......@@ -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;
......
......@@ -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,
......
......@@ -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 = {
......
......@@ -384,6 +384,7 @@ enum {
NFSPROC4_CLNT_DELEGRETURN,
NFSPROC4_CLNT_GETACL,
NFSPROC4_CLNT_SETACL,
NFSPROC4_CLNT_FS_LOCATIONS,
};
#endif
......
......@@ -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;
......
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