diff options
Diffstat (limited to 'fs/nfs')
-rw-r--r-- | fs/nfs/dir.c | 16 | ||||
-rw-r--r-- | fs/nfs/nfs4proc.c | 52 | ||||
-rw-r--r-- | fs/nfs/nfs4xdr.c | 16 |
3 files changed, 71 insertions, 13 deletions
diff --git a/fs/nfs/dir.c b/fs/nfs/dir.c index 627f108ede23..ce8cb926526b 100644 --- a/fs/nfs/dir.c +++ b/fs/nfs/dir.c | |||
@@ -2072,7 +2072,7 @@ found: | |||
2072 | nfs_access_free_entry(entry); | 2072 | nfs_access_free_entry(entry); |
2073 | } | 2073 | } |
2074 | 2074 | ||
2075 | static void nfs_access_add_cache(struct inode *inode, struct nfs_access_entry *set) | 2075 | void nfs_access_add_cache(struct inode *inode, struct nfs_access_entry *set) |
2076 | { | 2076 | { |
2077 | struct nfs_access_entry *cache = kmalloc(sizeof(*cache), GFP_KERNEL); | 2077 | struct nfs_access_entry *cache = kmalloc(sizeof(*cache), GFP_KERNEL); |
2078 | if (cache == NULL) | 2078 | if (cache == NULL) |
@@ -2098,6 +2098,20 @@ static void nfs_access_add_cache(struct inode *inode, struct nfs_access_entry *s | |||
2098 | spin_unlock(&nfs_access_lru_lock); | 2098 | spin_unlock(&nfs_access_lru_lock); |
2099 | } | 2099 | } |
2100 | } | 2100 | } |
2101 | EXPORT_SYMBOL_GPL(nfs_access_add_cache); | ||
2102 | |||
2103 | void nfs_access_set_mask(struct nfs_access_entry *entry, u32 access_result) | ||
2104 | { | ||
2105 | entry->mask = 0; | ||
2106 | if (access_result & NFS4_ACCESS_READ) | ||
2107 | entry->mask |= MAY_READ; | ||
2108 | if (access_result & | ||
2109 | (NFS4_ACCESS_MODIFY | NFS4_ACCESS_EXTEND | NFS4_ACCESS_DELETE)) | ||
2110 | entry->mask |= MAY_WRITE; | ||
2111 | if (access_result & (NFS4_ACCESS_LOOKUP|NFS4_ACCESS_EXECUTE)) | ||
2112 | entry->mask |= MAY_EXEC; | ||
2113 | } | ||
2114 | EXPORT_SYMBOL_GPL(nfs_access_set_mask); | ||
2101 | 2115 | ||
2102 | static int nfs_do_access(struct inode *inode, struct rpc_cred *cred, int mask) | 2116 | static int nfs_do_access(struct inode *inode, struct rpc_cred *cred, int mask) |
2103 | { | 2117 | { |
diff --git a/fs/nfs/nfs4proc.c b/fs/nfs/nfs4proc.c index 471a75f11ea2..5b3207f557d9 100644 --- a/fs/nfs/nfs4proc.c +++ b/fs/nfs/nfs4proc.c | |||
@@ -104,6 +104,8 @@ static int nfs4_map_errors(int err) | |||
104 | return -EACCES; | 104 | return -EACCES; |
105 | case -NFS4ERR_MINOR_VERS_MISMATCH: | 105 | case -NFS4ERR_MINOR_VERS_MISMATCH: |
106 | return -EPROTONOSUPPORT; | 106 | return -EPROTONOSUPPORT; |
107 | case -NFS4ERR_ACCESS: | ||
108 | return -EACCES; | ||
107 | default: | 109 | default: |
108 | dprintk("%s could not handle NFSv4 error %d\n", | 110 | dprintk("%s could not handle NFSv4 error %d\n", |
109 | __func__, -err); | 111 | __func__, -err); |
@@ -860,6 +862,9 @@ static struct nfs4_opendata *nfs4_opendata_alloc(struct dentry *dentry, | |||
860 | p->o_arg.fh = NFS_FH(dir); | 862 | p->o_arg.fh = NFS_FH(dir); |
861 | p->o_arg.open_flags = flags; | 863 | p->o_arg.open_flags = flags; |
862 | p->o_arg.fmode = fmode & (FMODE_READ|FMODE_WRITE); | 864 | p->o_arg.fmode = fmode & (FMODE_READ|FMODE_WRITE); |
865 | /* ask server to check for all possible rights as results are cached */ | ||
866 | p->o_arg.access = NFS4_ACCESS_READ | NFS4_ACCESS_MODIFY | | ||
867 | NFS4_ACCESS_EXTEND | NFS4_ACCESS_EXECUTE; | ||
863 | p->o_arg.clientid = server->nfs_client->cl_clientid; | 868 | p->o_arg.clientid = server->nfs_client->cl_clientid; |
864 | p->o_arg.id.create_time = ktime_to_ns(sp->so_seqid.create_time); | 869 | p->o_arg.id.create_time = ktime_to_ns(sp->so_seqid.create_time); |
865 | p->o_arg.id.uniquifier = sp->so_seqid.owner_id; | 870 | p->o_arg.id.uniquifier = sp->so_seqid.owner_id; |
@@ -1643,6 +1648,39 @@ static int _nfs4_recover_proc_open(struct nfs4_opendata *data) | |||
1643 | return status; | 1648 | return status; |
1644 | } | 1649 | } |
1645 | 1650 | ||
1651 | static int nfs4_opendata_access(struct rpc_cred *cred, | ||
1652 | struct nfs4_opendata *opendata, | ||
1653 | struct nfs4_state *state, fmode_t fmode) | ||
1654 | { | ||
1655 | struct nfs_access_entry cache; | ||
1656 | u32 mask; | ||
1657 | |||
1658 | /* access call failed or for some reason the server doesn't | ||
1659 | * support any access modes -- defer access call until later */ | ||
1660 | if (opendata->o_res.access_supported == 0) | ||
1661 | return 0; | ||
1662 | |||
1663 | mask = 0; | ||
1664 | if (fmode & FMODE_READ) | ||
1665 | mask |= MAY_READ; | ||
1666 | if (fmode & FMODE_WRITE) | ||
1667 | mask |= MAY_WRITE; | ||
1668 | if (fmode & FMODE_EXEC) | ||
1669 | mask |= MAY_EXEC; | ||
1670 | |||
1671 | cache.cred = cred; | ||
1672 | cache.jiffies = jiffies; | ||
1673 | nfs_access_set_mask(&cache, opendata->o_res.access_result); | ||
1674 | nfs_access_add_cache(state->inode, &cache); | ||
1675 | |||
1676 | if ((mask & ~cache.mask & (MAY_READ | MAY_WRITE | MAY_EXEC)) == 0) | ||
1677 | return 0; | ||
1678 | |||
1679 | /* even though OPEN succeeded, access is denied. Close the file */ | ||
1680 | nfs4_close_state(state, fmode); | ||
1681 | return -NFS4ERR_ACCESS; | ||
1682 | } | ||
1683 | |||
1646 | /* | 1684 | /* |
1647 | * Note: On error, nfs4_proc_open will free the struct nfs4_opendata | 1685 | * Note: On error, nfs4_proc_open will free the struct nfs4_opendata |
1648 | */ | 1686 | */ |
@@ -1900,6 +1938,10 @@ static int _nfs4_do_open(struct inode *dir, | |||
1900 | if (server->caps & NFS_CAP_POSIX_LOCK) | 1938 | if (server->caps & NFS_CAP_POSIX_LOCK) |
1901 | set_bit(NFS_STATE_POSIX_LOCKS, &state->flags); | 1939 | set_bit(NFS_STATE_POSIX_LOCKS, &state->flags); |
1902 | 1940 | ||
1941 | status = nfs4_opendata_access(cred, opendata, state, fmode); | ||
1942 | if (status != 0) | ||
1943 | goto err_opendata_put; | ||
1944 | |||
1903 | if (opendata->o_arg.open_flags & O_EXCL) { | 1945 | if (opendata->o_arg.open_flags & O_EXCL) { |
1904 | nfs4_exclusive_attrset(opendata, sattr); | 1946 | nfs4_exclusive_attrset(opendata, sattr); |
1905 | 1947 | ||
@@ -1945,7 +1987,7 @@ static struct nfs4_state *nfs4_do_open(struct inode *dir, | |||
1945 | struct nfs4_state *res; | 1987 | struct nfs4_state *res; |
1946 | int status; | 1988 | int status; |
1947 | 1989 | ||
1948 | fmode &= FMODE_READ|FMODE_WRITE; | 1990 | fmode &= FMODE_READ|FMODE_WRITE|FMODE_EXEC; |
1949 | do { | 1991 | do { |
1950 | status = _nfs4_do_open(dir, dentry, fmode, flags, sattr, cred, | 1992 | status = _nfs4_do_open(dir, dentry, fmode, flags, sattr, cred, |
1951 | &res, ctx_th); | 1993 | &res, ctx_th); |
@@ -2771,13 +2813,7 @@ static int _nfs4_proc_access(struct inode *inode, struct nfs_access_entry *entry | |||
2771 | 2813 | ||
2772 | status = nfs4_call_sync(server->client, server, &msg, &args.seq_args, &res.seq_res, 0); | 2814 | status = nfs4_call_sync(server->client, server, &msg, &args.seq_args, &res.seq_res, 0); |
2773 | if (!status) { | 2815 | if (!status) { |
2774 | entry->mask = 0; | 2816 | nfs_access_set_mask(entry, res.access); |
2775 | if (res.access & NFS4_ACCESS_READ) | ||
2776 | entry->mask |= MAY_READ; | ||
2777 | if (res.access & (NFS4_ACCESS_MODIFY | NFS4_ACCESS_EXTEND | NFS4_ACCESS_DELETE)) | ||
2778 | entry->mask |= MAY_WRITE; | ||
2779 | if (res.access & (NFS4_ACCESS_LOOKUP|NFS4_ACCESS_EXECUTE)) | ||
2780 | entry->mask |= MAY_EXEC; | ||
2781 | nfs_refresh_inode(inode, res.fattr); | 2817 | nfs_refresh_inode(inode, res.fattr); |
2782 | } | 2818 | } |
2783 | nfs_free_fattr(res.fattr); | 2819 | nfs_free_fattr(res.fattr); |
diff --git a/fs/nfs/nfs4xdr.c b/fs/nfs/nfs4xdr.c index 7ab29abb3160..657483c34e28 100644 --- a/fs/nfs/nfs4xdr.c +++ b/fs/nfs/nfs4xdr.c | |||
@@ -447,12 +447,14 @@ static int nfs4_stat_to_errno(int); | |||
447 | encode_sequence_maxsz + \ | 447 | encode_sequence_maxsz + \ |
448 | encode_putfh_maxsz + \ | 448 | encode_putfh_maxsz + \ |
449 | encode_open_maxsz + \ | 449 | encode_open_maxsz + \ |
450 | encode_access_maxsz + \ | ||
450 | encode_getfh_maxsz + \ | 451 | encode_getfh_maxsz + \ |
451 | encode_getattr_maxsz) | 452 | encode_getattr_maxsz) |
452 | #define NFS4_dec_open_sz (compound_decode_hdr_maxsz + \ | 453 | #define NFS4_dec_open_sz (compound_decode_hdr_maxsz + \ |
453 | decode_sequence_maxsz + \ | 454 | decode_sequence_maxsz + \ |
454 | decode_putfh_maxsz + \ | 455 | decode_putfh_maxsz + \ |
455 | decode_open_maxsz + \ | 456 | decode_open_maxsz + \ |
457 | decode_access_maxsz + \ | ||
456 | decode_getfh_maxsz + \ | 458 | decode_getfh_maxsz + \ |
457 | decode_getattr_maxsz) | 459 | decode_getattr_maxsz) |
458 | #define NFS4_enc_open_confirm_sz \ | 460 | #define NFS4_enc_open_confirm_sz \ |
@@ -467,11 +469,13 @@ static int nfs4_stat_to_errno(int); | |||
467 | encode_sequence_maxsz + \ | 469 | encode_sequence_maxsz + \ |
468 | encode_putfh_maxsz + \ | 470 | encode_putfh_maxsz + \ |
469 | encode_open_maxsz + \ | 471 | encode_open_maxsz + \ |
472 | encode_access_maxsz + \ | ||
470 | encode_getattr_maxsz) | 473 | encode_getattr_maxsz) |
471 | #define NFS4_dec_open_noattr_sz (compound_decode_hdr_maxsz + \ | 474 | #define NFS4_dec_open_noattr_sz (compound_decode_hdr_maxsz + \ |
472 | decode_sequence_maxsz + \ | 475 | decode_sequence_maxsz + \ |
473 | decode_putfh_maxsz + \ | 476 | decode_putfh_maxsz + \ |
474 | decode_open_maxsz + \ | 477 | decode_open_maxsz + \ |
478 | decode_access_maxsz + \ | ||
475 | decode_getattr_maxsz) | 479 | decode_getattr_maxsz) |
476 | #define NFS4_enc_open_downgrade_sz \ | 480 | #define NFS4_enc_open_downgrade_sz \ |
477 | (compound_encode_hdr_maxsz + \ | 481 | (compound_encode_hdr_maxsz + \ |
@@ -2220,6 +2224,7 @@ static void nfs4_xdr_enc_open(struct rpc_rqst *req, struct xdr_stream *xdr, | |||
2220 | encode_putfh(xdr, args->fh, &hdr); | 2224 | encode_putfh(xdr, args->fh, &hdr); |
2221 | encode_open(xdr, args, &hdr); | 2225 | encode_open(xdr, args, &hdr); |
2222 | encode_getfh(xdr, &hdr); | 2226 | encode_getfh(xdr, &hdr); |
2227 | encode_access(xdr, args->access, &hdr); | ||
2223 | encode_getfattr_open(xdr, args->bitmask, args->open_bitmap, &hdr); | 2228 | encode_getfattr_open(xdr, args->bitmask, args->open_bitmap, &hdr); |
2224 | encode_nops(&hdr); | 2229 | encode_nops(&hdr); |
2225 | } | 2230 | } |
@@ -2256,6 +2261,7 @@ static void nfs4_xdr_enc_open_noattr(struct rpc_rqst *req, | |||
2256 | encode_sequence(xdr, &args->seq_args, &hdr); | 2261 | encode_sequence(xdr, &args->seq_args, &hdr); |
2257 | encode_putfh(xdr, args->fh, &hdr); | 2262 | encode_putfh(xdr, args->fh, &hdr); |
2258 | encode_open(xdr, args, &hdr); | 2263 | encode_open(xdr, args, &hdr); |
2264 | encode_access(xdr, args->access, &hdr); | ||
2259 | encode_getfattr(xdr, args->bitmask, &hdr); | 2265 | encode_getfattr(xdr, args->bitmask, &hdr); |
2260 | encode_nops(&hdr); | 2266 | encode_nops(&hdr); |
2261 | } | 2267 | } |
@@ -4099,7 +4105,7 @@ out_overflow: | |||
4099 | return -EIO; | 4105 | return -EIO; |
4100 | } | 4106 | } |
4101 | 4107 | ||
4102 | static int decode_access(struct xdr_stream *xdr, struct nfs4_accessres *access) | 4108 | static int decode_access(struct xdr_stream *xdr, u32 *supported, u32 *access) |
4103 | { | 4109 | { |
4104 | __be32 *p; | 4110 | __be32 *p; |
4105 | uint32_t supp, acc; | 4111 | uint32_t supp, acc; |
@@ -4113,8 +4119,8 @@ static int decode_access(struct xdr_stream *xdr, struct nfs4_accessres *access) | |||
4113 | goto out_overflow; | 4119 | goto out_overflow; |
4114 | supp = be32_to_cpup(p++); | 4120 | supp = be32_to_cpup(p++); |
4115 | acc = be32_to_cpup(p); | 4121 | acc = be32_to_cpup(p); |
4116 | access->supported = supp; | 4122 | *supported = supp; |
4117 | access->access = acc; | 4123 | *access = acc; |
4118 | return 0; | 4124 | return 0; |
4119 | out_overflow: | 4125 | out_overflow: |
4120 | print_overflow_msg(__func__, xdr); | 4126 | print_overflow_msg(__func__, xdr); |
@@ -5892,7 +5898,7 @@ static int nfs4_xdr_dec_access(struct rpc_rqst *rqstp, struct xdr_stream *xdr, | |||
5892 | status = decode_putfh(xdr); | 5898 | status = decode_putfh(xdr); |
5893 | if (status != 0) | 5899 | if (status != 0) |
5894 | goto out; | 5900 | goto out; |
5895 | status = decode_access(xdr, res); | 5901 | status = decode_access(xdr, &res->supported, &res->access); |
5896 | if (status != 0) | 5902 | if (status != 0) |
5897 | goto out; | 5903 | goto out; |
5898 | decode_getfattr(xdr, res->fattr, res->server); | 5904 | decode_getfattr(xdr, res->fattr, res->server); |
@@ -6233,6 +6239,7 @@ static int nfs4_xdr_dec_open(struct rpc_rqst *rqstp, struct xdr_stream *xdr, | |||
6233 | status = decode_getfh(xdr, &res->fh); | 6239 | status = decode_getfh(xdr, &res->fh); |
6234 | if (status) | 6240 | if (status) |
6235 | goto out; | 6241 | goto out; |
6242 | decode_access(xdr, &res->access_supported, &res->access_result); | ||
6236 | decode_getfattr(xdr, res->f_attr, res->server); | 6243 | decode_getfattr(xdr, res->f_attr, res->server); |
6237 | out: | 6244 | out: |
6238 | return status; | 6245 | return status; |
@@ -6281,6 +6288,7 @@ static int nfs4_xdr_dec_open_noattr(struct rpc_rqst *rqstp, | |||
6281 | status = decode_open(xdr, res); | 6288 | status = decode_open(xdr, res); |
6282 | if (status) | 6289 | if (status) |
6283 | goto out; | 6290 | goto out; |
6291 | decode_access(xdr, &res->access_supported, &res->access_result); | ||
6284 | decode_getfattr(xdr, res->f_attr, res->server); | 6292 | decode_getfattr(xdr, res->f_attr, res->server); |
6285 | out: | 6293 | out: |
6286 | return status; | 6294 | return status; |