aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
-rw-r--r--fs/nfs/nfs4_fs.h2
-rw-r--r--fs/nfs/nfs4proc.c29
-rw-r--r--fs/nfs/nfs4xdr.c112
-rw-r--r--include/linux/nfs4.h1
-rw-r--r--include/linux/nfs_xdr.h24
5 files changed, 166 insertions, 2 deletions
diff --git a/fs/nfs/nfs4_fs.h b/fs/nfs/nfs4_fs.h
index 307832fd1a49..5b7651171215 100644
--- a/fs/nfs/nfs4_fs.h
+++ b/fs/nfs/nfs4_fs.h
@@ -218,6 +218,8 @@ extern int nfs4_do_close(struct inode *inode, struct nfs4_state *state);
218extern struct dentry *nfs4_atomic_open(struct inode *, struct dentry *, struct nameidata *); 218extern struct dentry *nfs4_atomic_open(struct inode *, struct dentry *, struct nameidata *);
219extern int nfs4_open_revalidate(struct inode *, struct dentry *, int, struct nameidata *); 219extern int nfs4_open_revalidate(struct inode *, struct dentry *, int, struct nameidata *);
220extern int nfs4_server_capabilities(struct nfs_server *server, struct nfs_fh *fhandle); 220extern int nfs4_server_capabilities(struct nfs_server *server, struct nfs_fh *fhandle);
221extern int nfs4_proc_fs_locations(struct inode *dir, struct dentry *dentry,
222 struct nfs_fs_locations *fs_locations, struct page *page);
221 223
222extern struct nfs4_state_recovery_ops nfs4_reboot_recovery_ops; 224extern struct nfs4_state_recovery_ops nfs4_reboot_recovery_ops;
223extern struct nfs4_state_recovery_ops nfs4_network_partition_recovery_ops; 225extern struct nfs4_state_recovery_ops nfs4_network_partition_recovery_ops;
diff --git a/fs/nfs/nfs4proc.c b/fs/nfs/nfs4proc.c
index 308407205e6c..768514dc0c4c 100644
--- a/fs/nfs/nfs4proc.c
+++ b/fs/nfs/nfs4proc.c
@@ -3570,6 +3570,35 @@ ssize_t nfs4_listxattr(struct dentry *dentry, char *buf, size_t buflen)
3570 return len; 3570 return len;
3571} 3571}
3572 3572
3573int nfs4_proc_fs_locations(struct inode *dir, struct dentry *dentry,
3574 struct nfs_fs_locations *fs_locations, struct page *page)
3575{
3576 struct nfs_server *server = NFS_SERVER(dir);
3577 u32 bitmask[2] = {
3578 [0] = server->attr_bitmask[0] | FATTR4_WORD0_FS_LOCATIONS,
3579 [1] = server->attr_bitmask[1],
3580 };
3581 struct nfs4_fs_locations_arg args = {
3582 .dir_fh = NFS_FH(dir),
3583 .name = &dentry->d_name,
3584 .page = page,
3585 .bitmask = bitmask,
3586 };
3587 struct rpc_message msg = {
3588 .rpc_proc = &nfs4_procedures[NFSPROC4_CLNT_FS_LOCATIONS],
3589 .rpc_argp = &args,
3590 .rpc_resp = &fs_locations,
3591 };
3592 int status;
3593
3594 dprintk("%s: start\n", __FUNCTION__);
3595 fs_locations->fattr.valid = 0;
3596 fs_locations->server = server;
3597 status = rpc_call_sync(server->client, &msg, 0);
3598 dprintk("%s: returned status = %d\n", __FUNCTION__, status);
3599 return status;
3600}
3601
3573struct nfs4_state_recovery_ops nfs4_reboot_recovery_ops = { 3602struct nfs4_state_recovery_ops nfs4_reboot_recovery_ops = {
3574 .recover_open = nfs4_open_reclaim, 3603 .recover_open = nfs4_open_reclaim,
3575 .recover_lock = nfs4_lock_reclaim, 3604 .recover_lock = nfs4_lock_reclaim,
diff --git a/fs/nfs/nfs4xdr.c b/fs/nfs/nfs4xdr.c
index 0d5794675944..7add3137b6b6 100644
--- a/fs/nfs/nfs4xdr.c
+++ b/fs/nfs/nfs4xdr.c
@@ -411,6 +411,15 @@ static int nfs_stat_to_errno(int);
411#define NFS4_dec_setacl_sz (compound_decode_hdr_maxsz + \ 411#define NFS4_dec_setacl_sz (compound_decode_hdr_maxsz + \
412 decode_putfh_maxsz + \ 412 decode_putfh_maxsz + \
413 op_decode_hdr_maxsz + nfs4_fattr_bitmap_maxsz) 413 op_decode_hdr_maxsz + nfs4_fattr_bitmap_maxsz)
414#define NFS4_enc_fs_locations_sz \
415 (compound_encode_hdr_maxsz + \
416 encode_putfh_maxsz + \
417 encode_getattr_maxsz)
418#define NFS4_dec_fs_locations_sz \
419 (compound_decode_hdr_maxsz + \
420 decode_putfh_maxsz + \
421 op_decode_hdr_maxsz + \
422 nfs4_fattr_bitmap_maxsz)
414 423
415static struct { 424static struct {
416 unsigned int mode; 425 unsigned int mode;
@@ -2003,6 +2012,38 @@ out:
2003} 2012}
2004 2013
2005/* 2014/*
2015 * Encode FS_LOCATIONS request
2016 */
2017static int nfs4_xdr_enc_fs_locations(struct rpc_rqst *req, uint32_t *p, struct nfs4_fs_locations_arg *args)
2018{
2019 struct xdr_stream xdr;
2020 struct compound_hdr hdr = {
2021 .nops = 3,
2022 };
2023 struct rpc_auth *auth = req->rq_task->tk_auth;
2024 int replen;
2025 int status;
2026
2027 xdr_init_encode(&xdr, &req->rq_snd_buf, p);
2028 encode_compound_hdr(&xdr, &hdr);
2029 if ((status = encode_putfh(&xdr, args->dir_fh)) != 0)
2030 goto out;
2031 if ((status = encode_lookup(&xdr, args->name)) != 0)
2032 goto out;
2033 if ((status = encode_getfattr(&xdr, args->bitmask)) != 0)
2034 goto out;
2035 /* set up reply
2036 * toplevel_status + taglen + rescount + OP_PUTFH + status
2037 * + OP_LOOKUP + status + OP_GETATTR + status = 7
2038 */
2039 replen = (RPC_REPHDRSIZE + auth->au_rslack + 7) << 2;
2040 xdr_inline_pages(&req->rq_rcv_buf, replen, &args->page,
2041 0, PAGE_SIZE);
2042out:
2043 return status;
2044}
2045
2046/*
2006 * START OF "GENERIC" DECODE ROUTINES. 2047 * START OF "GENERIC" DECODE ROUTINES.
2007 * These may look a little ugly since they are imported from a "generic" 2048 * These may look a little ugly since they are imported from a "generic"
2008 * set of XDR encode/decode routines which are intended to be shared by 2049 * set of XDR encode/decode routines which are intended to be shared by
@@ -2036,7 +2077,7 @@ out:
2036 } \ 2077 } \
2037} while (0) 2078} while (0)
2038 2079
2039static int decode_opaque_inline(struct xdr_stream *xdr, uint32_t *len, char **string) 2080static int decode_opaque_inline(struct xdr_stream *xdr, unsigned int *len, char **string)
2040{ 2081{
2041 uint32_t *p; 2082 uint32_t *p;
2042 2083
@@ -2087,7 +2128,7 @@ static int decode_op_hdr(struct xdr_stream *xdr, enum nfs_opnum4 expected)
2087static int decode_ace(struct xdr_stream *xdr, void *ace, struct nfs4_client *clp) 2128static int decode_ace(struct xdr_stream *xdr, void *ace, struct nfs4_client *clp)
2088{ 2129{
2089 uint32_t *p; 2130 uint32_t *p;
2090 uint32_t strlen; 2131 unsigned int strlen;
2091 char *str; 2132 char *str;
2092 2133
2093 READ_BUF(12); 2134 READ_BUF(12);
@@ -2336,6 +2377,45 @@ static int decode_attr_files_total(struct xdr_stream *xdr, uint32_t *bitmap, uin
2336 return status; 2377 return status;
2337} 2378}
2338 2379
2380static int decode_attr_fs_locations(struct xdr_stream *xdr, uint32_t *bitmap, struct nfs_fs_locations *res)
2381{
2382 int n;
2383 uint32_t *p;
2384 int status = -EIO;
2385
2386 if (unlikely(bitmap[0] & (FATTR4_WORD0_FS_LOCATIONS -1U)))
2387 goto out;
2388 status = 0;
2389 if (unlikely(!(bitmap[0] & FATTR4_WORD0_FS_LOCATIONS)))
2390 goto out;
2391 status = decode_opaque_inline(xdr, &res->fs_pathlen, &res->fs_path);
2392 if (unlikely(status != 0))
2393 goto out;
2394 READ_BUF(4);
2395 READ32(n);
2396 if (n <= 0)
2397 goto out_eio;
2398 res->nlocations = 0;
2399 while (res->nlocations < n) {
2400 struct nfs_fs_location *loc = &res->locations[res->nlocations];
2401
2402 status = decode_opaque_inline(xdr, &loc->serverlen, &loc->server);
2403 if (unlikely(status != 0))
2404 goto out_eio;
2405 status = decode_opaque_inline(xdr, &loc->rootpathlen, &loc->rootpath);
2406 if (unlikely(status != 0))
2407 goto out_eio;
2408 if (res->nlocations < NFS_FS_LOCATIONS_MAXENTRIES)
2409 res->nlocations++;
2410 }
2411out:
2412 dprintk("%s: fs_locations done, error = %d\n", __FUNCTION__, status);
2413 return status;
2414out_eio:
2415 status = -EIO;
2416 goto out;
2417}
2418
2339static int decode_attr_maxfilesize(struct xdr_stream *xdr, uint32_t *bitmap, uint64_t *res) 2419static int decode_attr_maxfilesize(struct xdr_stream *xdr, uint32_t *bitmap, uint64_t *res)
2340{ 2420{
2341 uint32_t *p; 2421 uint32_t *p;
@@ -2867,6 +2947,10 @@ static int decode_getfattr(struct xdr_stream *xdr, struct nfs_fattr *fattr, cons
2867 goto xdr_error; 2947 goto xdr_error;
2868 if ((status = decode_attr_fileid(xdr, bitmap, &fattr->fileid)) != 0) 2948 if ((status = decode_attr_fileid(xdr, bitmap, &fattr->fileid)) != 0)
2869 goto xdr_error; 2949 goto xdr_error;
2950 if ((status = decode_attr_fs_locations(xdr, bitmap, container_of(fattr,
2951 struct nfs_fs_locations,
2952 fattr))) != 0)
2953 goto xdr_error;
2870 if ((status = decode_attr_mode(xdr, bitmap, &fattr->mode)) != 0) 2954 if ((status = decode_attr_mode(xdr, bitmap, &fattr->mode)) != 0)
2871 goto xdr_error; 2955 goto xdr_error;
2872 fattr->mode |= fmode; 2956 fattr->mode |= fmode;
@@ -4210,6 +4294,29 @@ out:
4210 return status; 4294 return status;
4211} 4295}
4212 4296
4297/*
4298 * FS_LOCATIONS request
4299 */
4300static int nfs4_xdr_dec_fs_locations(struct rpc_rqst *req, uint32_t *p, struct nfs_fs_locations *res)
4301{
4302 struct xdr_stream xdr;
4303 struct compound_hdr hdr;
4304 int status;
4305
4306 xdr_init_decode(&xdr, &req->rq_rcv_buf, p);
4307 status = decode_compound_hdr(&xdr, &hdr);
4308 if (status != 0)
4309 goto out;
4310 if ((status = decode_putfh(&xdr)) != 0)
4311 goto out;
4312 if ((status = decode_lookup(&xdr)) != 0)
4313 goto out;
4314 xdr_enter_page(&xdr, PAGE_SIZE);
4315 status = decode_getfattr(&xdr, &res->fattr, res->server);
4316out:
4317 return status;
4318}
4319
4213uint32_t *nfs4_decode_dirent(uint32_t *p, struct nfs_entry *entry, int plus) 4320uint32_t *nfs4_decode_dirent(uint32_t *p, struct nfs_entry *entry, int plus)
4214{ 4321{
4215 uint32_t bitmap[2] = {0}; 4322 uint32_t bitmap[2] = {0};
@@ -4381,6 +4488,7 @@ struct rpc_procinfo nfs4_procedures[] = {
4381 PROC(DELEGRETURN, enc_delegreturn, dec_delegreturn), 4488 PROC(DELEGRETURN, enc_delegreturn, dec_delegreturn),
4382 PROC(GETACL, enc_getacl, dec_getacl), 4489 PROC(GETACL, enc_getacl, dec_getacl),
4383 PROC(SETACL, enc_setacl, dec_setacl), 4490 PROC(SETACL, enc_setacl, dec_setacl),
4491 PROC(FS_LOCATIONS, enc_fs_locations, dec_fs_locations),
4384}; 4492};
4385 4493
4386struct rpc_version nfs_version4 = { 4494struct rpc_version nfs_version4 = {
diff --git a/include/linux/nfs4.h b/include/linux/nfs4.h
index 0c1c306cdaec..1477fc857f6b 100644
--- a/include/linux/nfs4.h
+++ b/include/linux/nfs4.h
@@ -384,6 +384,7 @@ enum {
384 NFSPROC4_CLNT_DELEGRETURN, 384 NFSPROC4_CLNT_DELEGRETURN,
385 NFSPROC4_CLNT_GETACL, 385 NFSPROC4_CLNT_GETACL,
386 NFSPROC4_CLNT_SETACL, 386 NFSPROC4_CLNT_SETACL,
387 NFSPROC4_CLNT_FS_LOCATIONS,
387}; 388};
388 389
389#endif 390#endif
diff --git a/include/linux/nfs_xdr.h b/include/linux/nfs_xdr.h
index 95682f7d738a..15a20b815302 100644
--- a/include/linux/nfs_xdr.h
+++ b/include/linux/nfs_xdr.h
@@ -679,6 +679,30 @@ struct nfs4_server_caps_res {
679 u32 has_symlinks; 679 u32 has_symlinks;
680}; 680};
681 681
682struct nfs_fs_location {
683 unsigned int serverlen;
684 char * server;
685 unsigned int rootpathlen;
686 char * rootpath;
687};
688
689#define NFS_FS_LOCATIONS_MAXENTRIES 10
690struct nfs_fs_locations {
691 struct nfs_fattr fattr;
692 const struct nfs_server *server;
693 unsigned int fs_pathlen;
694 char * fs_path;
695 int nlocations;
696 struct nfs_fs_location locations[NFS_FS_LOCATIONS_MAXENTRIES];
697};
698
699struct nfs4_fs_locations_arg {
700 const struct nfs_fh *dir_fh;
701 const struct qstr *name;
702 struct page *page;
703 const u32 *bitmask;
704};
705
682#endif /* CONFIG_NFS_V4 */ 706#endif /* CONFIG_NFS_V4 */
683 707
684struct nfs_page; 708struct nfs_page;