diff options
Diffstat (limited to 'fs/nfs/nfs4proc.c')
-rw-r--r-- | fs/nfs/nfs4proc.c | 429 |
1 files changed, 339 insertions, 90 deletions
diff --git a/fs/nfs/nfs4proc.c b/fs/nfs/nfs4proc.c index 1d5cb3e80c3e..1b76f80aedb9 100644 --- a/fs/nfs/nfs4proc.c +++ b/fs/nfs/nfs4proc.c | |||
@@ -48,6 +48,7 @@ | |||
48 | #include <linux/smp_lock.h> | 48 | #include <linux/smp_lock.h> |
49 | #include <linux/namei.h> | 49 | #include <linux/namei.h> |
50 | 50 | ||
51 | #include "nfs4_fs.h" | ||
51 | #include "delegation.h" | 52 | #include "delegation.h" |
52 | 53 | ||
53 | #define NFSDBG_FACILITY NFSDBG_PROC | 54 | #define NFSDBG_FACILITY NFSDBG_PROC |
@@ -62,8 +63,6 @@ static int nfs4_handle_exception(struct nfs_server *server, int errorcode, struc | |||
62 | extern u32 *nfs4_decode_dirent(u32 *p, struct nfs_entry *entry, int plus); | 63 | extern u32 *nfs4_decode_dirent(u32 *p, struct nfs_entry *entry, int plus); |
63 | extern struct rpc_procinfo nfs4_procedures[]; | 64 | extern struct rpc_procinfo nfs4_procedures[]; |
64 | 65 | ||
65 | extern nfs4_stateid zero_stateid; | ||
66 | |||
67 | /* Prevent leaks of NFSv4 errors into userland */ | 66 | /* Prevent leaks of NFSv4 errors into userland */ |
68 | int nfs4_map_errors(int err) | 67 | int nfs4_map_errors(int err) |
69 | { | 68 | { |
@@ -104,7 +103,7 @@ const u32 nfs4_statfs_bitmap[2] = { | |||
104 | | FATTR4_WORD1_SPACE_TOTAL | 103 | | FATTR4_WORD1_SPACE_TOTAL |
105 | }; | 104 | }; |
106 | 105 | ||
107 | u32 nfs4_pathconf_bitmap[2] = { | 106 | const u32 nfs4_pathconf_bitmap[2] = { |
108 | FATTR4_WORD0_MAXLINK | 107 | FATTR4_WORD0_MAXLINK |
109 | | FATTR4_WORD0_MAXNAME, | 108 | | FATTR4_WORD0_MAXNAME, |
110 | 0 | 109 | 0 |
@@ -124,7 +123,7 @@ static void nfs4_setup_readdir(u64 cookie, u32 *verifier, struct dentry *dentry, | |||
124 | 123 | ||
125 | BUG_ON(readdir->count < 80); | 124 | BUG_ON(readdir->count < 80); |
126 | if (cookie > 2) { | 125 | if (cookie > 2) { |
127 | readdir->cookie = (cookie > 2) ? cookie : 0; | 126 | readdir->cookie = cookie; |
128 | memcpy(&readdir->verifier, verifier, sizeof(readdir->verifier)); | 127 | memcpy(&readdir->verifier, verifier, sizeof(readdir->verifier)); |
129 | return; | 128 | return; |
130 | } | 129 | } |
@@ -270,14 +269,9 @@ static int nfs4_open_reclaim(struct nfs4_state_owner *sp, struct nfs4_state *sta | |||
270 | int err; | 269 | int err; |
271 | do { | 270 | do { |
272 | err = _nfs4_open_reclaim(sp, state); | 271 | err = _nfs4_open_reclaim(sp, state); |
273 | switch (err) { | 272 | if (err != -NFS4ERR_DELAY) |
274 | case 0: | 273 | break; |
275 | case -NFS4ERR_STALE_CLIENTID: | 274 | nfs4_handle_exception(server, err, &exception); |
276 | case -NFS4ERR_STALE_STATEID: | ||
277 | case -NFS4ERR_EXPIRED: | ||
278 | return err; | ||
279 | } | ||
280 | err = nfs4_handle_exception(server, err, &exception); | ||
281 | } while (exception.retry); | 275 | } while (exception.retry); |
282 | return err; | 276 | return err; |
283 | } | 277 | } |
@@ -509,6 +503,20 @@ out_stale: | |||
509 | goto out_nodeleg; | 503 | goto out_nodeleg; |
510 | } | 504 | } |
511 | 505 | ||
506 | static inline int nfs4_do_open_expired(struct nfs4_state_owner *sp, struct nfs4_state *state, struct dentry *dentry) | ||
507 | { | ||
508 | struct nfs_server *server = NFS_SERVER(dentry->d_inode); | ||
509 | struct nfs4_exception exception = { }; | ||
510 | int err; | ||
511 | |||
512 | do { | ||
513 | err = _nfs4_open_expired(sp, state, dentry); | ||
514 | if (err == -NFS4ERR_DELAY) | ||
515 | nfs4_handle_exception(server, err, &exception); | ||
516 | } while (exception.retry); | ||
517 | return err; | ||
518 | } | ||
519 | |||
512 | static int nfs4_open_expired(struct nfs4_state_owner *sp, struct nfs4_state *state) | 520 | static int nfs4_open_expired(struct nfs4_state_owner *sp, struct nfs4_state *state) |
513 | { | 521 | { |
514 | struct nfs_inode *nfsi = NFS_I(state->inode); | 522 | struct nfs_inode *nfsi = NFS_I(state->inode); |
@@ -521,7 +529,7 @@ static int nfs4_open_expired(struct nfs4_state_owner *sp, struct nfs4_state *sta | |||
521 | continue; | 529 | continue; |
522 | get_nfs_open_context(ctx); | 530 | get_nfs_open_context(ctx); |
523 | spin_unlock(&state->inode->i_lock); | 531 | spin_unlock(&state->inode->i_lock); |
524 | status = _nfs4_open_expired(sp, state, ctx->dentry); | 532 | status = nfs4_do_open_expired(sp, state, ctx->dentry); |
525 | put_nfs_open_context(ctx); | 533 | put_nfs_open_context(ctx); |
526 | return status; | 534 | return status; |
527 | } | 535 | } |
@@ -748,11 +756,10 @@ static int _nfs4_do_setattr(struct nfs_server *server, struct nfs_fattr *fattr, | |||
748 | 756 | ||
749 | fattr->valid = 0; | 757 | fattr->valid = 0; |
750 | 758 | ||
751 | if (state != NULL) | 759 | if (state != NULL) { |
752 | msg.rpc_cred = state->owner->so_cred; | 760 | msg.rpc_cred = state->owner->so_cred; |
753 | if (sattr->ia_valid & ATTR_SIZE) | 761 | nfs4_copy_stateid(&arg.stateid, state, current->files); |
754 | nfs4_copy_stateid(&arg.stateid, state, NULL); | 762 | } else |
755 | else | ||
756 | memcpy(&arg.stateid, &zero_stateid, sizeof(arg.stateid)); | 763 | memcpy(&arg.stateid, &zero_stateid, sizeof(arg.stateid)); |
757 | 764 | ||
758 | return rpc_call_sync(server->client, &msg, 0); | 765 | return rpc_call_sync(server->client, &msg, 0); |
@@ -1116,47 +1123,31 @@ static int | |||
1116 | nfs4_proc_setattr(struct dentry *dentry, struct nfs_fattr *fattr, | 1123 | nfs4_proc_setattr(struct dentry *dentry, struct nfs_fattr *fattr, |
1117 | struct iattr *sattr) | 1124 | struct iattr *sattr) |
1118 | { | 1125 | { |
1119 | struct inode * inode = dentry->d_inode; | 1126 | struct rpc_cred *cred; |
1120 | int size_change = sattr->ia_valid & ATTR_SIZE; | 1127 | struct inode *inode = dentry->d_inode; |
1121 | struct nfs4_state *state = NULL; | 1128 | struct nfs4_state *state; |
1122 | int need_iput = 0; | ||
1123 | int status; | 1129 | int status; |
1124 | 1130 | ||
1125 | fattr->valid = 0; | 1131 | fattr->valid = 0; |
1126 | 1132 | ||
1127 | if (size_change) { | 1133 | cred = rpcauth_lookupcred(NFS_SERVER(inode)->client->cl_auth, 0); |
1128 | struct rpc_cred *cred = rpcauth_lookupcred(NFS_SERVER(inode)->client->cl_auth, 0); | 1134 | if (IS_ERR(cred)) |
1129 | if (IS_ERR(cred)) | 1135 | return PTR_ERR(cred); |
1130 | return PTR_ERR(cred); | 1136 | /* Search for an existing WRITE delegation first */ |
1137 | state = nfs4_open_delegated(inode, FMODE_WRITE, cred); | ||
1138 | if (!IS_ERR(state)) { | ||
1139 | /* NB: nfs4_open_delegated() bumps the inode->i_count */ | ||
1140 | iput(inode); | ||
1141 | } else { | ||
1142 | /* Search for an existing open(O_WRITE) stateid */ | ||
1131 | state = nfs4_find_state(inode, cred, FMODE_WRITE); | 1143 | state = nfs4_find_state(inode, cred, FMODE_WRITE); |
1132 | if (state == NULL) { | ||
1133 | state = nfs4_open_delegated(dentry->d_inode, | ||
1134 | FMODE_WRITE, cred); | ||
1135 | if (IS_ERR(state)) | ||
1136 | state = nfs4_do_open(dentry->d_parent->d_inode, | ||
1137 | dentry, FMODE_WRITE, | ||
1138 | NULL, cred); | ||
1139 | need_iput = 1; | ||
1140 | } | ||
1141 | put_rpccred(cred); | ||
1142 | if (IS_ERR(state)) | ||
1143 | return PTR_ERR(state); | ||
1144 | |||
1145 | if (state->inode != inode) { | ||
1146 | printk(KERN_WARNING "nfs: raced in setattr (%p != %p), returning -EIO\n", inode, state->inode); | ||
1147 | status = -EIO; | ||
1148 | goto out; | ||
1149 | } | ||
1150 | } | 1144 | } |
1145 | |||
1151 | status = nfs4_do_setattr(NFS_SERVER(inode), fattr, | 1146 | status = nfs4_do_setattr(NFS_SERVER(inode), fattr, |
1152 | NFS_FH(inode), sattr, state); | 1147 | NFS_FH(inode), sattr, state); |
1153 | out: | 1148 | if (state != NULL) |
1154 | if (state) { | ||
1155 | inode = state->inode; | ||
1156 | nfs4_close_state(state, FMODE_WRITE); | 1149 | nfs4_close_state(state, FMODE_WRITE); |
1157 | if (need_iput) | 1150 | put_rpccred(cred); |
1158 | iput(inode); | ||
1159 | } | ||
1160 | return status; | 1151 | return status; |
1161 | } | 1152 | } |
1162 | 1153 | ||
@@ -1731,6 +1722,10 @@ static int _nfs4_proc_readdir(struct dentry *dentry, struct rpc_cred *cred, | |||
1731 | }; | 1722 | }; |
1732 | int status; | 1723 | int status; |
1733 | 1724 | ||
1725 | dprintk("%s: dentry = %s/%s, cookie = %Lu\n", __FUNCTION__, | ||
1726 | dentry->d_parent->d_name.name, | ||
1727 | dentry->d_name.name, | ||
1728 | (unsigned long long)cookie); | ||
1734 | lock_kernel(); | 1729 | lock_kernel(); |
1735 | nfs4_setup_readdir(cookie, NFS_COOKIEVERF(dir), dentry, &args); | 1730 | nfs4_setup_readdir(cookie, NFS_COOKIEVERF(dir), dentry, &args); |
1736 | res.pgbase = args.pgbase; | 1731 | res.pgbase = args.pgbase; |
@@ -1738,6 +1733,7 @@ static int _nfs4_proc_readdir(struct dentry *dentry, struct rpc_cred *cred, | |||
1738 | if (status == 0) | 1733 | if (status == 0) |
1739 | memcpy(NFS_COOKIEVERF(dir), res.verifier.data, NFS4_VERIFIER_SIZE); | 1734 | memcpy(NFS_COOKIEVERF(dir), res.verifier.data, NFS4_VERIFIER_SIZE); |
1740 | unlock_kernel(); | 1735 | unlock_kernel(); |
1736 | dprintk("%s: returns %d\n", __FUNCTION__, status); | ||
1741 | return status; | 1737 | return status; |
1742 | } | 1738 | } |
1743 | 1739 | ||
@@ -2163,6 +2159,193 @@ nfs4_proc_file_release(struct inode *inode, struct file *filp) | |||
2163 | return 0; | 2159 | return 0; |
2164 | } | 2160 | } |
2165 | 2161 | ||
2162 | static inline int nfs4_server_supports_acls(struct nfs_server *server) | ||
2163 | { | ||
2164 | return (server->caps & NFS_CAP_ACLS) | ||
2165 | && (server->acl_bitmask & ACL4_SUPPORT_ALLOW_ACL) | ||
2166 | && (server->acl_bitmask & ACL4_SUPPORT_DENY_ACL); | ||
2167 | } | ||
2168 | |||
2169 | /* Assuming that XATTR_SIZE_MAX is a multiple of PAGE_CACHE_SIZE, and that | ||
2170 | * it's OK to put sizeof(void) * (XATTR_SIZE_MAX/PAGE_CACHE_SIZE) bytes on | ||
2171 | * the stack. | ||
2172 | */ | ||
2173 | #define NFS4ACL_MAXPAGES (XATTR_SIZE_MAX >> PAGE_CACHE_SHIFT) | ||
2174 | |||
2175 | static void buf_to_pages(const void *buf, size_t buflen, | ||
2176 | struct page **pages, unsigned int *pgbase) | ||
2177 | { | ||
2178 | const void *p = buf; | ||
2179 | |||
2180 | *pgbase = offset_in_page(buf); | ||
2181 | p -= *pgbase; | ||
2182 | while (p < buf + buflen) { | ||
2183 | *(pages++) = virt_to_page(p); | ||
2184 | p += PAGE_CACHE_SIZE; | ||
2185 | } | ||
2186 | } | ||
2187 | |||
2188 | struct nfs4_cached_acl { | ||
2189 | int cached; | ||
2190 | size_t len; | ||
2191 | char data[0]; | ||
2192 | }; | ||
2193 | |||
2194 | static void nfs4_set_cached_acl(struct inode *inode, struct nfs4_cached_acl *acl) | ||
2195 | { | ||
2196 | struct nfs_inode *nfsi = NFS_I(inode); | ||
2197 | |||
2198 | spin_lock(&inode->i_lock); | ||
2199 | kfree(nfsi->nfs4_acl); | ||
2200 | nfsi->nfs4_acl = acl; | ||
2201 | spin_unlock(&inode->i_lock); | ||
2202 | } | ||
2203 | |||
2204 | static void nfs4_zap_acl_attr(struct inode *inode) | ||
2205 | { | ||
2206 | nfs4_set_cached_acl(inode, NULL); | ||
2207 | } | ||
2208 | |||
2209 | static inline ssize_t nfs4_read_cached_acl(struct inode *inode, char *buf, size_t buflen) | ||
2210 | { | ||
2211 | struct nfs_inode *nfsi = NFS_I(inode); | ||
2212 | struct nfs4_cached_acl *acl; | ||
2213 | int ret = -ENOENT; | ||
2214 | |||
2215 | spin_lock(&inode->i_lock); | ||
2216 | acl = nfsi->nfs4_acl; | ||
2217 | if (acl == NULL) | ||
2218 | goto out; | ||
2219 | if (buf == NULL) /* user is just asking for length */ | ||
2220 | goto out_len; | ||
2221 | if (acl->cached == 0) | ||
2222 | goto out; | ||
2223 | ret = -ERANGE; /* see getxattr(2) man page */ | ||
2224 | if (acl->len > buflen) | ||
2225 | goto out; | ||
2226 | memcpy(buf, acl->data, acl->len); | ||
2227 | out_len: | ||
2228 | ret = acl->len; | ||
2229 | out: | ||
2230 | spin_unlock(&inode->i_lock); | ||
2231 | return ret; | ||
2232 | } | ||
2233 | |||
2234 | static void nfs4_write_cached_acl(struct inode *inode, const char *buf, size_t acl_len) | ||
2235 | { | ||
2236 | struct nfs4_cached_acl *acl; | ||
2237 | |||
2238 | if (buf && acl_len <= PAGE_SIZE) { | ||
2239 | acl = kmalloc(sizeof(*acl) + acl_len, GFP_KERNEL); | ||
2240 | if (acl == NULL) | ||
2241 | goto out; | ||
2242 | acl->cached = 1; | ||
2243 | memcpy(acl->data, buf, acl_len); | ||
2244 | } else { | ||
2245 | acl = kmalloc(sizeof(*acl), GFP_KERNEL); | ||
2246 | if (acl == NULL) | ||
2247 | goto out; | ||
2248 | acl->cached = 0; | ||
2249 | } | ||
2250 | acl->len = acl_len; | ||
2251 | out: | ||
2252 | nfs4_set_cached_acl(inode, acl); | ||
2253 | } | ||
2254 | |||
2255 | static inline ssize_t nfs4_get_acl_uncached(struct inode *inode, void *buf, size_t buflen) | ||
2256 | { | ||
2257 | struct page *pages[NFS4ACL_MAXPAGES]; | ||
2258 | struct nfs_getaclargs args = { | ||
2259 | .fh = NFS_FH(inode), | ||
2260 | .acl_pages = pages, | ||
2261 | .acl_len = buflen, | ||
2262 | }; | ||
2263 | size_t resp_len = buflen; | ||
2264 | void *resp_buf; | ||
2265 | struct rpc_message msg = { | ||
2266 | .rpc_proc = &nfs4_procedures[NFSPROC4_CLNT_GETACL], | ||
2267 | .rpc_argp = &args, | ||
2268 | .rpc_resp = &resp_len, | ||
2269 | }; | ||
2270 | struct page *localpage = NULL; | ||
2271 | int ret; | ||
2272 | |||
2273 | if (buflen < PAGE_SIZE) { | ||
2274 | /* As long as we're doing a round trip to the server anyway, | ||
2275 | * let's be prepared for a page of acl data. */ | ||
2276 | localpage = alloc_page(GFP_KERNEL); | ||
2277 | resp_buf = page_address(localpage); | ||
2278 | if (localpage == NULL) | ||
2279 | return -ENOMEM; | ||
2280 | args.acl_pages[0] = localpage; | ||
2281 | args.acl_pgbase = 0; | ||
2282 | args.acl_len = PAGE_SIZE; | ||
2283 | } else { | ||
2284 | resp_buf = buf; | ||
2285 | buf_to_pages(buf, buflen, args.acl_pages, &args.acl_pgbase); | ||
2286 | } | ||
2287 | ret = rpc_call_sync(NFS_CLIENT(inode), &msg, 0); | ||
2288 | if (ret) | ||
2289 | goto out_free; | ||
2290 | if (resp_len > args.acl_len) | ||
2291 | nfs4_write_cached_acl(inode, NULL, resp_len); | ||
2292 | else | ||
2293 | nfs4_write_cached_acl(inode, resp_buf, resp_len); | ||
2294 | if (buf) { | ||
2295 | ret = -ERANGE; | ||
2296 | if (resp_len > buflen) | ||
2297 | goto out_free; | ||
2298 | if (localpage) | ||
2299 | memcpy(buf, resp_buf, resp_len); | ||
2300 | } | ||
2301 | ret = resp_len; | ||
2302 | out_free: | ||
2303 | if (localpage) | ||
2304 | __free_page(localpage); | ||
2305 | return ret; | ||
2306 | } | ||
2307 | |||
2308 | static ssize_t nfs4_proc_get_acl(struct inode *inode, void *buf, size_t buflen) | ||
2309 | { | ||
2310 | struct nfs_server *server = NFS_SERVER(inode); | ||
2311 | int ret; | ||
2312 | |||
2313 | if (!nfs4_server_supports_acls(server)) | ||
2314 | return -EOPNOTSUPP; | ||
2315 | ret = nfs_revalidate_inode(server, inode); | ||
2316 | if (ret < 0) | ||
2317 | return ret; | ||
2318 | ret = nfs4_read_cached_acl(inode, buf, buflen); | ||
2319 | if (ret != -ENOENT) | ||
2320 | return ret; | ||
2321 | return nfs4_get_acl_uncached(inode, buf, buflen); | ||
2322 | } | ||
2323 | |||
2324 | static int nfs4_proc_set_acl(struct inode *inode, const void *buf, size_t buflen) | ||
2325 | { | ||
2326 | struct nfs_server *server = NFS_SERVER(inode); | ||
2327 | struct page *pages[NFS4ACL_MAXPAGES]; | ||
2328 | struct nfs_setaclargs arg = { | ||
2329 | .fh = NFS_FH(inode), | ||
2330 | .acl_pages = pages, | ||
2331 | .acl_len = buflen, | ||
2332 | }; | ||
2333 | struct rpc_message msg = { | ||
2334 | .rpc_proc = &nfs4_procedures[NFSPROC4_CLNT_SETACL], | ||
2335 | .rpc_argp = &arg, | ||
2336 | .rpc_resp = NULL, | ||
2337 | }; | ||
2338 | int ret; | ||
2339 | |||
2340 | if (!nfs4_server_supports_acls(server)) | ||
2341 | return -EOPNOTSUPP; | ||
2342 | buf_to_pages(buf, buflen, arg.acl_pages, &arg.acl_pgbase); | ||
2343 | ret = rpc_call_sync(NFS_SERVER(inode)->client, &msg, 0); | ||
2344 | if (ret == 0) | ||
2345 | nfs4_write_cached_acl(inode, buf, buflen); | ||
2346 | return ret; | ||
2347 | } | ||
2348 | |||
2166 | static int | 2349 | static int |
2167 | nfs4_async_handle_error(struct rpc_task *task, struct nfs_server *server) | 2350 | nfs4_async_handle_error(struct rpc_task *task, struct nfs_server *server) |
2168 | { | 2351 | { |
@@ -2448,14 +2631,11 @@ static int _nfs4_proc_getlk(struct nfs4_state *state, int cmd, struct file_lock | |||
2448 | down_read(&clp->cl_sem); | 2631 | down_read(&clp->cl_sem); |
2449 | nlo.clientid = clp->cl_clientid; | 2632 | nlo.clientid = clp->cl_clientid; |
2450 | down(&state->lock_sema); | 2633 | down(&state->lock_sema); |
2451 | lsp = nfs4_find_lock_state(state, request->fl_owner); | 2634 | status = nfs4_set_lock_state(state, request); |
2452 | if (lsp) | 2635 | if (status != 0) |
2453 | nlo.id = lsp->ls_id; | 2636 | goto out; |
2454 | else { | 2637 | lsp = request->fl_u.nfs4_fl.owner; |
2455 | spin_lock(&clp->cl_lock); | 2638 | nlo.id = lsp->ls_id; |
2456 | nlo.id = nfs4_alloc_lockowner_id(clp); | ||
2457 | spin_unlock(&clp->cl_lock); | ||
2458 | } | ||
2459 | arg.u.lockt = &nlo; | 2639 | arg.u.lockt = &nlo; |
2460 | status = rpc_call_sync(server->client, &msg, 0); | 2640 | status = rpc_call_sync(server->client, &msg, 0); |
2461 | if (!status) { | 2641 | if (!status) { |
@@ -2476,8 +2656,7 @@ static int _nfs4_proc_getlk(struct nfs4_state *state, int cmd, struct file_lock | |||
2476 | request->fl_pid = 0; | 2656 | request->fl_pid = 0; |
2477 | status = 0; | 2657 | status = 0; |
2478 | } | 2658 | } |
2479 | if (lsp) | 2659 | out: |
2480 | nfs4_put_lock_state(lsp); | ||
2481 | up(&state->lock_sema); | 2660 | up(&state->lock_sema); |
2482 | up_read(&clp->cl_sem); | 2661 | up_read(&clp->cl_sem); |
2483 | return status; | 2662 | return status; |
@@ -2537,28 +2716,26 @@ static int _nfs4_proc_unlck(struct nfs4_state *state, int cmd, struct file_lock | |||
2537 | }; | 2716 | }; |
2538 | struct nfs4_lock_state *lsp; | 2717 | struct nfs4_lock_state *lsp; |
2539 | struct nfs_locku_opargs luargs; | 2718 | struct nfs_locku_opargs luargs; |
2540 | int status = 0; | 2719 | int status; |
2541 | 2720 | ||
2542 | down_read(&clp->cl_sem); | 2721 | down_read(&clp->cl_sem); |
2543 | down(&state->lock_sema); | 2722 | down(&state->lock_sema); |
2544 | lsp = nfs4_find_lock_state(state, request->fl_owner); | 2723 | status = nfs4_set_lock_state(state, request); |
2545 | if (!lsp) | 2724 | if (status != 0) |
2546 | goto out; | 2725 | goto out; |
2726 | lsp = request->fl_u.nfs4_fl.owner; | ||
2547 | /* We might have lost the locks! */ | 2727 | /* We might have lost the locks! */ |
2548 | if ((lsp->ls_flags & NFS_LOCK_INITIALIZED) != 0) { | 2728 | if ((lsp->ls_flags & NFS_LOCK_INITIALIZED) == 0) |
2549 | luargs.seqid = lsp->ls_seqid; | 2729 | goto out; |
2550 | memcpy(&luargs.stateid, &lsp->ls_stateid, sizeof(luargs.stateid)); | 2730 | luargs.seqid = lsp->ls_seqid; |
2551 | arg.u.locku = &luargs; | 2731 | memcpy(&luargs.stateid, &lsp->ls_stateid, sizeof(luargs.stateid)); |
2552 | status = rpc_call_sync(server->client, &msg, RPC_TASK_NOINTR); | 2732 | arg.u.locku = &luargs; |
2553 | nfs4_increment_lock_seqid(status, lsp); | 2733 | status = rpc_call_sync(server->client, &msg, RPC_TASK_NOINTR); |
2554 | } | 2734 | nfs4_increment_lock_seqid(status, lsp); |
2555 | 2735 | ||
2556 | if (status == 0) { | 2736 | if (status == 0) |
2557 | memcpy(&lsp->ls_stateid, &res.u.stateid, | 2737 | memcpy(&lsp->ls_stateid, &res.u.stateid, |
2558 | sizeof(lsp->ls_stateid)); | 2738 | sizeof(lsp->ls_stateid)); |
2559 | nfs4_notify_unlck(state, request, lsp); | ||
2560 | } | ||
2561 | nfs4_put_lock_state(lsp); | ||
2562 | out: | 2739 | out: |
2563 | up(&state->lock_sema); | 2740 | up(&state->lock_sema); |
2564 | if (status == 0) | 2741 | if (status == 0) |
@@ -2584,7 +2761,7 @@ static int _nfs4_do_setlk(struct nfs4_state *state, int cmd, struct file_lock *r | |||
2584 | { | 2761 | { |
2585 | struct inode *inode = state->inode; | 2762 | struct inode *inode = state->inode; |
2586 | struct nfs_server *server = NFS_SERVER(inode); | 2763 | struct nfs_server *server = NFS_SERVER(inode); |
2587 | struct nfs4_lock_state *lsp; | 2764 | struct nfs4_lock_state *lsp = request->fl_u.nfs4_fl.owner; |
2588 | struct nfs_lockargs arg = { | 2765 | struct nfs_lockargs arg = { |
2589 | .fh = NFS_FH(inode), | 2766 | .fh = NFS_FH(inode), |
2590 | .type = nfs4_lck_type(cmd, request), | 2767 | .type = nfs4_lck_type(cmd, request), |
@@ -2606,9 +2783,6 @@ static int _nfs4_do_setlk(struct nfs4_state *state, int cmd, struct file_lock *r | |||
2606 | }; | 2783 | }; |
2607 | int status; | 2784 | int status; |
2608 | 2785 | ||
2609 | lsp = nfs4_get_lock_state(state, request->fl_owner); | ||
2610 | if (lsp == NULL) | ||
2611 | return -ENOMEM; | ||
2612 | if (!(lsp->ls_flags & NFS_LOCK_INITIALIZED)) { | 2786 | if (!(lsp->ls_flags & NFS_LOCK_INITIALIZED)) { |
2613 | struct nfs4_state_owner *owner = state->owner; | 2787 | struct nfs4_state_owner *owner = state->owner; |
2614 | struct nfs_open_to_lock otl = { | 2788 | struct nfs_open_to_lock otl = { |
@@ -2630,38 +2804,57 @@ static int _nfs4_do_setlk(struct nfs4_state *state, int cmd, struct file_lock *r | |||
2630 | * seqid mutating errors */ | 2804 | * seqid mutating errors */ |
2631 | nfs4_increment_seqid(status, owner); | 2805 | nfs4_increment_seqid(status, owner); |
2632 | up(&owner->so_sema); | 2806 | up(&owner->so_sema); |
2807 | if (status == 0) { | ||
2808 | lsp->ls_flags |= NFS_LOCK_INITIALIZED; | ||
2809 | lsp->ls_seqid++; | ||
2810 | } | ||
2633 | } else { | 2811 | } else { |
2634 | struct nfs_exist_lock el = { | 2812 | struct nfs_exist_lock el = { |
2635 | .seqid = lsp->ls_seqid, | 2813 | .seqid = lsp->ls_seqid, |
2636 | }; | 2814 | }; |
2637 | memcpy(&el.stateid, &lsp->ls_stateid, sizeof(el.stateid)); | 2815 | memcpy(&el.stateid, &lsp->ls_stateid, sizeof(el.stateid)); |
2638 | largs.u.exist_lock = ⪙ | 2816 | largs.u.exist_lock = ⪙ |
2639 | largs.new_lock_owner = 0; | ||
2640 | arg.u.lock = &largs; | 2817 | arg.u.lock = &largs; |
2641 | status = rpc_call_sync(server->client, &msg, RPC_TASK_NOINTR); | 2818 | status = rpc_call_sync(server->client, &msg, RPC_TASK_NOINTR); |
2819 | /* increment seqid on success, and * seqid mutating errors*/ | ||
2820 | nfs4_increment_lock_seqid(status, lsp); | ||
2642 | } | 2821 | } |
2643 | /* increment seqid on success, and * seqid mutating errors*/ | ||
2644 | nfs4_increment_lock_seqid(status, lsp); | ||
2645 | /* save the returned stateid. */ | 2822 | /* save the returned stateid. */ |
2646 | if (status == 0) { | 2823 | if (status == 0) |
2647 | memcpy(&lsp->ls_stateid, &res.u.stateid, sizeof(nfs4_stateid)); | 2824 | memcpy(&lsp->ls_stateid, &res.u.stateid, sizeof(nfs4_stateid)); |
2648 | lsp->ls_flags |= NFS_LOCK_INITIALIZED; | 2825 | else if (status == -NFS4ERR_DENIED) |
2649 | if (!reclaim) | ||
2650 | nfs4_notify_setlk(state, request, lsp); | ||
2651 | } else if (status == -NFS4ERR_DENIED) | ||
2652 | status = -EAGAIN; | 2826 | status = -EAGAIN; |
2653 | nfs4_put_lock_state(lsp); | ||
2654 | return status; | 2827 | return status; |
2655 | } | 2828 | } |
2656 | 2829 | ||
2657 | static int nfs4_lock_reclaim(struct nfs4_state *state, struct file_lock *request) | 2830 | static int nfs4_lock_reclaim(struct nfs4_state *state, struct file_lock *request) |
2658 | { | 2831 | { |
2659 | return _nfs4_do_setlk(state, F_SETLK, request, 1); | 2832 | struct nfs_server *server = NFS_SERVER(state->inode); |
2833 | struct nfs4_exception exception = { }; | ||
2834 | int err; | ||
2835 | |||
2836 | do { | ||
2837 | err = _nfs4_do_setlk(state, F_SETLK, request, 1); | ||
2838 | if (err != -NFS4ERR_DELAY) | ||
2839 | break; | ||
2840 | nfs4_handle_exception(server, err, &exception); | ||
2841 | } while (exception.retry); | ||
2842 | return err; | ||
2660 | } | 2843 | } |
2661 | 2844 | ||
2662 | static int nfs4_lock_expired(struct nfs4_state *state, struct file_lock *request) | 2845 | static int nfs4_lock_expired(struct nfs4_state *state, struct file_lock *request) |
2663 | { | 2846 | { |
2664 | return _nfs4_do_setlk(state, F_SETLK, request, 0); | 2847 | struct nfs_server *server = NFS_SERVER(state->inode); |
2848 | struct nfs4_exception exception = { }; | ||
2849 | int err; | ||
2850 | |||
2851 | do { | ||
2852 | err = _nfs4_do_setlk(state, F_SETLK, request, 0); | ||
2853 | if (err != -NFS4ERR_DELAY) | ||
2854 | break; | ||
2855 | nfs4_handle_exception(server, err, &exception); | ||
2856 | } while (exception.retry); | ||
2857 | return err; | ||
2665 | } | 2858 | } |
2666 | 2859 | ||
2667 | static int _nfs4_proc_setlk(struct nfs4_state *state, int cmd, struct file_lock *request) | 2860 | static int _nfs4_proc_setlk(struct nfs4_state *state, int cmd, struct file_lock *request) |
@@ -2671,7 +2864,9 @@ static int _nfs4_proc_setlk(struct nfs4_state *state, int cmd, struct file_lock | |||
2671 | 2864 | ||
2672 | down_read(&clp->cl_sem); | 2865 | down_read(&clp->cl_sem); |
2673 | down(&state->lock_sema); | 2866 | down(&state->lock_sema); |
2674 | status = _nfs4_do_setlk(state, cmd, request, 0); | 2867 | status = nfs4_set_lock_state(state, request); |
2868 | if (status == 0) | ||
2869 | status = _nfs4_do_setlk(state, cmd, request, 0); | ||
2675 | up(&state->lock_sema); | 2870 | up(&state->lock_sema); |
2676 | if (status == 0) { | 2871 | if (status == 0) { |
2677 | /* Note: we always want to sleep here! */ | 2872 | /* Note: we always want to sleep here! */ |
@@ -2729,10 +2924,53 @@ nfs4_proc_lock(struct file *filp, int cmd, struct file_lock *request) | |||
2729 | if (signalled()) | 2924 | if (signalled()) |
2730 | break; | 2925 | break; |
2731 | } while(status < 0); | 2926 | } while(status < 0); |
2732 | |||
2733 | return status; | 2927 | return status; |
2734 | } | 2928 | } |
2735 | 2929 | ||
2930 | |||
2931 | #define XATTR_NAME_NFSV4_ACL "system.nfs4_acl" | ||
2932 | |||
2933 | int nfs4_setxattr(struct dentry *dentry, const char *key, const void *buf, | ||
2934 | size_t buflen, int flags) | ||
2935 | { | ||
2936 | struct inode *inode = dentry->d_inode; | ||
2937 | |||
2938 | if (strcmp(key, XATTR_NAME_NFSV4_ACL) != 0) | ||
2939 | return -EOPNOTSUPP; | ||
2940 | |||
2941 | if (!S_ISREG(inode->i_mode) && | ||
2942 | (!S_ISDIR(inode->i_mode) || inode->i_mode & S_ISVTX)) | ||
2943 | return -EPERM; | ||
2944 | |||
2945 | return nfs4_proc_set_acl(inode, buf, buflen); | ||
2946 | } | ||
2947 | |||
2948 | /* The getxattr man page suggests returning -ENODATA for unknown attributes, | ||
2949 | * and that's what we'll do for e.g. user attributes that haven't been set. | ||
2950 | * But we'll follow ext2/ext3's lead by returning -EOPNOTSUPP for unsupported | ||
2951 | * attributes in kernel-managed attribute namespaces. */ | ||
2952 | ssize_t nfs4_getxattr(struct dentry *dentry, const char *key, void *buf, | ||
2953 | size_t buflen) | ||
2954 | { | ||
2955 | struct inode *inode = dentry->d_inode; | ||
2956 | |||
2957 | if (strcmp(key, XATTR_NAME_NFSV4_ACL) != 0) | ||
2958 | return -EOPNOTSUPP; | ||
2959 | |||
2960 | return nfs4_proc_get_acl(inode, buf, buflen); | ||
2961 | } | ||
2962 | |||
2963 | ssize_t nfs4_listxattr(struct dentry *dentry, char *buf, size_t buflen) | ||
2964 | { | ||
2965 | size_t len = strlen(XATTR_NAME_NFSV4_ACL) + 1; | ||
2966 | |||
2967 | if (buf && buflen < len) | ||
2968 | return -ERANGE; | ||
2969 | if (buf) | ||
2970 | memcpy(buf, XATTR_NAME_NFSV4_ACL, len); | ||
2971 | return len; | ||
2972 | } | ||
2973 | |||
2736 | struct nfs4_state_recovery_ops nfs4_reboot_recovery_ops = { | 2974 | struct nfs4_state_recovery_ops nfs4_reboot_recovery_ops = { |
2737 | .recover_open = nfs4_open_reclaim, | 2975 | .recover_open = nfs4_open_reclaim, |
2738 | .recover_lock = nfs4_lock_reclaim, | 2976 | .recover_lock = nfs4_lock_reclaim, |
@@ -2743,10 +2981,20 @@ struct nfs4_state_recovery_ops nfs4_network_partition_recovery_ops = { | |||
2743 | .recover_lock = nfs4_lock_expired, | 2981 | .recover_lock = nfs4_lock_expired, |
2744 | }; | 2982 | }; |
2745 | 2983 | ||
2984 | static struct inode_operations nfs4_file_inode_operations = { | ||
2985 | .permission = nfs_permission, | ||
2986 | .getattr = nfs_getattr, | ||
2987 | .setattr = nfs_setattr, | ||
2988 | .getxattr = nfs4_getxattr, | ||
2989 | .setxattr = nfs4_setxattr, | ||
2990 | .listxattr = nfs4_listxattr, | ||
2991 | }; | ||
2992 | |||
2746 | struct nfs_rpc_ops nfs_v4_clientops = { | 2993 | struct nfs_rpc_ops nfs_v4_clientops = { |
2747 | .version = 4, /* protocol version */ | 2994 | .version = 4, /* protocol version */ |
2748 | .dentry_ops = &nfs4_dentry_operations, | 2995 | .dentry_ops = &nfs4_dentry_operations, |
2749 | .dir_inode_ops = &nfs4_dir_inode_operations, | 2996 | .dir_inode_ops = &nfs4_dir_inode_operations, |
2997 | .file_inode_ops = &nfs4_file_inode_operations, | ||
2750 | .getroot = nfs4_proc_get_root, | 2998 | .getroot = nfs4_proc_get_root, |
2751 | .getattr = nfs4_proc_getattr, | 2999 | .getattr = nfs4_proc_getattr, |
2752 | .setattr = nfs4_proc_setattr, | 3000 | .setattr = nfs4_proc_setattr, |
@@ -2777,6 +3025,7 @@ struct nfs_rpc_ops nfs_v4_clientops = { | |||
2777 | .file_open = nfs4_proc_file_open, | 3025 | .file_open = nfs4_proc_file_open, |
2778 | .file_release = nfs4_proc_file_release, | 3026 | .file_release = nfs4_proc_file_release, |
2779 | .lock = nfs4_proc_lock, | 3027 | .lock = nfs4_proc_lock, |
3028 | .clear_acl_cache = nfs4_zap_acl_attr, | ||
2780 | }; | 3029 | }; |
2781 | 3030 | ||
2782 | /* | 3031 | /* |