diff options
-rw-r--r-- | fs/nfs/nfs4_fs.h | 2 | ||||
-rw-r--r-- | fs/nfs/nfs4proc.c | 29 | ||||
-rw-r--r-- | fs/nfs/nfs4xdr.c | 112 | ||||
-rw-r--r-- | include/linux/nfs4.h | 1 | ||||
-rw-r--r-- | include/linux/nfs_xdr.h | 24 |
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); | |||
218 | extern struct dentry *nfs4_atomic_open(struct inode *, struct dentry *, struct nameidata *); | 218 | extern struct dentry *nfs4_atomic_open(struct inode *, struct dentry *, struct nameidata *); |
219 | extern int nfs4_open_revalidate(struct inode *, struct dentry *, int, struct nameidata *); | 219 | extern int nfs4_open_revalidate(struct inode *, struct dentry *, int, struct nameidata *); |
220 | extern int nfs4_server_capabilities(struct nfs_server *server, struct nfs_fh *fhandle); | 220 | extern int nfs4_server_capabilities(struct nfs_server *server, struct nfs_fh *fhandle); |
221 | extern int nfs4_proc_fs_locations(struct inode *dir, struct dentry *dentry, | ||
222 | struct nfs_fs_locations *fs_locations, struct page *page); | ||
221 | 223 | ||
222 | extern struct nfs4_state_recovery_ops nfs4_reboot_recovery_ops; | 224 | extern struct nfs4_state_recovery_ops nfs4_reboot_recovery_ops; |
223 | extern struct nfs4_state_recovery_ops nfs4_network_partition_recovery_ops; | 225 | extern 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 | ||
3573 | int 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 | |||
3573 | struct nfs4_state_recovery_ops nfs4_reboot_recovery_ops = { | 3602 | struct 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 | ||
415 | static struct { | 424 | static 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 | */ | ||
2017 | static 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); | ||
2042 | out: | ||
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 | ||
2039 | static int decode_opaque_inline(struct xdr_stream *xdr, uint32_t *len, char **string) | 2080 | static 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) | |||
2087 | static int decode_ace(struct xdr_stream *xdr, void *ace, struct nfs4_client *clp) | 2128 | static 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 | ||
2380 | static 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 | } | ||
2411 | out: | ||
2412 | dprintk("%s: fs_locations done, error = %d\n", __FUNCTION__, status); | ||
2413 | return status; | ||
2414 | out_eio: | ||
2415 | status = -EIO; | ||
2416 | goto out; | ||
2417 | } | ||
2418 | |||
2339 | static int decode_attr_maxfilesize(struct xdr_stream *xdr, uint32_t *bitmap, uint64_t *res) | 2419 | static 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 | */ | ||
4300 | static 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); | ||
4316 | out: | ||
4317 | return status; | ||
4318 | } | ||
4319 | |||
4213 | uint32_t *nfs4_decode_dirent(uint32_t *p, struct nfs_entry *entry, int plus) | 4320 | uint32_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 | ||
4386 | struct rpc_version nfs_version4 = { | 4494 | struct 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 | ||
682 | struct 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 | ||
690 | struct 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 | |||
699 | struct 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 | ||
684 | struct nfs_page; | 708 | struct nfs_page; |