Skip to content

Commit

Permalink
NFSv4: Implement the fs_locations function call
Browse files Browse the repository at this point in the history
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: Trond Myklebust <Trond.Myklebust@netapp.com>
  • Loading branch information
Trond Myklebust authored and Trond Myklebust committed Jun 9, 2006
1 parent 8b23ea7 commit 683b57b
Show file tree
Hide file tree
Showing 5 changed files with 166 additions and 2 deletions.
2 changes: 2 additions & 0 deletions fs/nfs/nfs4_fs.h
Original file line number Diff line number Diff line change
Expand Up @@ -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;
Expand Down
29 changes: 29 additions & 0 deletions fs/nfs/nfs4proc.c
Original file line number Diff line number Diff line change
Expand Up @@ -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,
Expand Down
112 changes: 110 additions & 2 deletions fs/nfs/nfs4xdr.c
Original file line number Diff line number Diff line change
Expand Up @@ -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;
Expand Down Expand Up @@ -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"
Expand Down Expand Up @@ -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;

Expand Down Expand Up @@ -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);
Expand Down Expand Up @@ -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;
Expand Down Expand Up @@ -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;
Expand Down Expand Up @@ -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};
Expand Down Expand Up @@ -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 = {
Expand Down
1 change: 1 addition & 0 deletions include/linux/nfs4.h
Original file line number Diff line number Diff line change
Expand Up @@ -384,6 +384,7 @@ enum {
NFSPROC4_CLNT_DELEGRETURN,
NFSPROC4_CLNT_GETACL,
NFSPROC4_CLNT_SETACL,
NFSPROC4_CLNT_FS_LOCATIONS,
};

#endif
Expand Down
24 changes: 24 additions & 0 deletions include/linux/nfs_xdr.h
Original file line number Diff line number Diff line change
Expand Up @@ -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;
Expand Down

0 comments on commit 683b57b

Please sign in to comment.