diff options
Diffstat (limited to 'fs/nfs/nfs4proc.c')
-rw-r--r-- | fs/nfs/nfs4proc.c | 85 |
1 files changed, 36 insertions, 49 deletions
diff --git a/fs/nfs/nfs4proc.c b/fs/nfs/nfs4proc.c index 4b90e17555a9..cb99fd90a9ac 100644 --- a/fs/nfs/nfs4proc.c +++ b/fs/nfs/nfs4proc.c | |||
@@ -62,10 +62,8 @@ struct nfs4_opendata; | |||
62 | static int _nfs4_proc_open(struct nfs4_opendata *data); | 62 | static int _nfs4_proc_open(struct nfs4_opendata *data); |
63 | static int nfs4_do_fsinfo(struct nfs_server *, struct nfs_fh *, struct nfs_fsinfo *); | 63 | static int nfs4_do_fsinfo(struct nfs_server *, struct nfs_fh *, struct nfs_fsinfo *); |
64 | static int nfs4_async_handle_error(struct rpc_task *, const struct nfs_server *); | 64 | static int nfs4_async_handle_error(struct rpc_task *, const struct nfs_server *); |
65 | static int _nfs4_proc_access(struct inode *inode, struct nfs_access_entry *entry); | ||
66 | static int nfs4_handle_exception(const struct nfs_server *server, int errorcode, struct nfs4_exception *exception); | 65 | static int nfs4_handle_exception(const struct nfs_server *server, int errorcode, struct nfs4_exception *exception); |
67 | static int nfs4_wait_clnt_recover(struct rpc_clnt *clnt, struct nfs_client *clp); | 66 | static int nfs4_wait_clnt_recover(struct rpc_clnt *clnt, struct nfs_client *clp); |
68 | static int _nfs4_do_access(struct inode *inode, struct rpc_cred *cred, int openflags); | ||
69 | static int _nfs4_proc_lookup(struct inode *dir, const struct qstr *name, struct nfs_fh *fhandle, struct nfs_fattr *fattr); | 67 | static int _nfs4_proc_lookup(struct inode *dir, const struct qstr *name, struct nfs_fh *fhandle, struct nfs_fattr *fattr); |
70 | static int _nfs4_proc_getattr(struct nfs_server *server, struct nfs_fh *fhandle, struct nfs_fattr *fattr); | 68 | static int _nfs4_proc_getattr(struct nfs_server *server, struct nfs_fh *fhandle, struct nfs_fattr *fattr); |
71 | 69 | ||
@@ -177,7 +175,7 @@ static void nfs4_setup_readdir(u64 cookie, __be32 *verifier, struct dentry *dent | |||
177 | *p++ = xdr_one; /* bitmap length */ | 175 | *p++ = xdr_one; /* bitmap length */ |
178 | *p++ = htonl(FATTR4_WORD0_FILEID); /* bitmap */ | 176 | *p++ = htonl(FATTR4_WORD0_FILEID); /* bitmap */ |
179 | *p++ = htonl(8); /* attribute buffer length */ | 177 | *p++ = htonl(8); /* attribute buffer length */ |
180 | p = xdr_encode_hyper(p, dentry->d_inode->i_ino); | 178 | p = xdr_encode_hyper(p, NFS_FILEID(dentry->d_inode)); |
181 | } | 179 | } |
182 | 180 | ||
183 | *p++ = xdr_one; /* next */ | 181 | *p++ = xdr_one; /* next */ |
@@ -189,7 +187,7 @@ static void nfs4_setup_readdir(u64 cookie, __be32 *verifier, struct dentry *dent | |||
189 | *p++ = xdr_one; /* bitmap length */ | 187 | *p++ = xdr_one; /* bitmap length */ |
190 | *p++ = htonl(FATTR4_WORD0_FILEID); /* bitmap */ | 188 | *p++ = htonl(FATTR4_WORD0_FILEID); /* bitmap */ |
191 | *p++ = htonl(8); /* attribute buffer length */ | 189 | *p++ = htonl(8); /* attribute buffer length */ |
192 | p = xdr_encode_hyper(p, dentry->d_parent->d_inode->i_ino); | 190 | p = xdr_encode_hyper(p, NFS_FILEID(dentry->d_parent->d_inode)); |
193 | 191 | ||
194 | readdir->pgbase = (char *)p - (char *)start; | 192 | readdir->pgbase = (char *)p - (char *)start; |
195 | readdir->count -= readdir->pgbase; | 193 | readdir->count -= readdir->pgbase; |
@@ -211,8 +209,9 @@ static void update_changeattr(struct inode *dir, struct nfs4_change_info *cinfo) | |||
211 | 209 | ||
212 | spin_lock(&dir->i_lock); | 210 | spin_lock(&dir->i_lock); |
213 | nfsi->cache_validity |= NFS_INO_INVALID_ATTR|NFS_INO_REVAL_PAGECACHE|NFS_INO_INVALID_DATA; | 211 | nfsi->cache_validity |= NFS_INO_INVALID_ATTR|NFS_INO_REVAL_PAGECACHE|NFS_INO_INVALID_DATA; |
214 | if (cinfo->before == nfsi->change_attr && cinfo->atomic) | 212 | if (!cinfo->atomic || cinfo->before != nfsi->change_attr) |
215 | nfsi->change_attr = cinfo->after; | 213 | nfsi->cache_change_attribute = jiffies; |
214 | nfsi->change_attr = cinfo->after; | ||
216 | spin_unlock(&dir->i_lock); | 215 | spin_unlock(&dir->i_lock); |
217 | } | 216 | } |
218 | 217 | ||
@@ -454,7 +453,7 @@ static struct nfs4_state *nfs4_try_open_cached(struct nfs4_opendata *opendata) | |||
454 | memcpy(stateid.data, delegation->stateid.data, sizeof(stateid.data)); | 453 | memcpy(stateid.data, delegation->stateid.data, sizeof(stateid.data)); |
455 | rcu_read_unlock(); | 454 | rcu_read_unlock(); |
456 | lock_kernel(); | 455 | lock_kernel(); |
457 | ret = _nfs4_do_access(state->inode, state->owner->so_cred, open_mode); | 456 | ret = nfs_may_open(state->inode, state->owner->so_cred, open_mode); |
458 | unlock_kernel(); | 457 | unlock_kernel(); |
459 | if (ret != 0) | 458 | if (ret != 0) |
460 | goto out; | 459 | goto out; |
@@ -948,36 +947,6 @@ static int _nfs4_proc_open(struct nfs4_opendata *data) | |||
948 | return 0; | 947 | return 0; |
949 | } | 948 | } |
950 | 949 | ||
951 | static int _nfs4_do_access(struct inode *inode, struct rpc_cred *cred, int openflags) | ||
952 | { | ||
953 | struct nfs_access_entry cache; | ||
954 | int mask = 0; | ||
955 | int status; | ||
956 | |||
957 | if (openflags & FMODE_READ) | ||
958 | mask |= MAY_READ; | ||
959 | if (openflags & FMODE_WRITE) | ||
960 | mask |= MAY_WRITE; | ||
961 | if (openflags & FMODE_EXEC) | ||
962 | mask |= MAY_EXEC; | ||
963 | status = nfs_access_get_cached(inode, cred, &cache); | ||
964 | if (status == 0) | ||
965 | goto out; | ||
966 | |||
967 | /* Be clever: ask server to check for all possible rights */ | ||
968 | cache.mask = MAY_EXEC | MAY_WRITE | MAY_READ; | ||
969 | cache.cred = cred; | ||
970 | cache.jiffies = jiffies; | ||
971 | status = _nfs4_proc_access(inode, &cache); | ||
972 | if (status != 0) | ||
973 | return status; | ||
974 | nfs_access_add_cache(inode, &cache); | ||
975 | out: | ||
976 | if ((cache.mask & mask) == mask) | ||
977 | return 0; | ||
978 | return -EACCES; | ||
979 | } | ||
980 | |||
981 | static int nfs4_recover_expired_lease(struct nfs_server *server) | 950 | static int nfs4_recover_expired_lease(struct nfs_server *server) |
982 | { | 951 | { |
983 | struct nfs_client *clp = server->nfs_client; | 952 | struct nfs_client *clp = server->nfs_client; |
@@ -1381,7 +1350,7 @@ static int nfs4_intent_set_file(struct nameidata *nd, struct path *path, struct | |||
1381 | 1350 | ||
1382 | /* If the open_intent is for execute, we have an extra check to make */ | 1351 | /* If the open_intent is for execute, we have an extra check to make */ |
1383 | if (nd->intent.open.flags & FMODE_EXEC) { | 1352 | if (nd->intent.open.flags & FMODE_EXEC) { |
1384 | ret = _nfs4_do_access(state->inode, | 1353 | ret = nfs_may_open(state->inode, |
1385 | state->owner->so_cred, | 1354 | state->owner->so_cred, |
1386 | nd->intent.open.flags); | 1355 | nd->intent.open.flags); |
1387 | if (ret < 0) | 1356 | if (ret < 0) |
@@ -1390,7 +1359,7 @@ static int nfs4_intent_set_file(struct nameidata *nd, struct path *path, struct | |||
1390 | filp = lookup_instantiate_filp(nd, path->dentry, NULL); | 1359 | filp = lookup_instantiate_filp(nd, path->dentry, NULL); |
1391 | if (!IS_ERR(filp)) { | 1360 | if (!IS_ERR(filp)) { |
1392 | struct nfs_open_context *ctx; | 1361 | struct nfs_open_context *ctx; |
1393 | ctx = (struct nfs_open_context *)filp->private_data; | 1362 | ctx = nfs_file_open_context(filp); |
1394 | ctx->state = state; | 1363 | ctx->state = state; |
1395 | return 0; | 1364 | return 0; |
1396 | } | 1365 | } |
@@ -1428,13 +1397,16 @@ nfs4_atomic_open(struct inode *dir, struct dentry *dentry, struct nameidata *nd) | |||
1428 | state = nfs4_do_open(dir, &path, nd->intent.open.flags, &attr, cred); | 1397 | state = nfs4_do_open(dir, &path, nd->intent.open.flags, &attr, cred); |
1429 | put_rpccred(cred); | 1398 | put_rpccred(cred); |
1430 | if (IS_ERR(state)) { | 1399 | if (IS_ERR(state)) { |
1431 | if (PTR_ERR(state) == -ENOENT) | 1400 | if (PTR_ERR(state) == -ENOENT) { |
1432 | d_add(dentry, NULL); | 1401 | d_add(dentry, NULL); |
1402 | nfs_set_verifier(dentry, nfs_save_change_attribute(dir)); | ||
1403 | } | ||
1433 | return (struct dentry *)state; | 1404 | return (struct dentry *)state; |
1434 | } | 1405 | } |
1435 | res = d_add_unique(dentry, igrab(state->inode)); | 1406 | res = d_add_unique(dentry, igrab(state->inode)); |
1436 | if (res != NULL) | 1407 | if (res != NULL) |
1437 | path.dentry = res; | 1408 | path.dentry = res; |
1409 | nfs_set_verifier(path.dentry, nfs_save_change_attribute(dir)); | ||
1438 | nfs4_intent_set_file(nd, &path, state); | 1410 | nfs4_intent_set_file(nd, &path, state); |
1439 | return res; | 1411 | return res; |
1440 | } | 1412 | } |
@@ -1468,6 +1440,7 @@ nfs4_open_revalidate(struct inode *dir, struct dentry *dentry, int openflags, st | |||
1468 | } | 1440 | } |
1469 | } | 1441 | } |
1470 | if (state->inode == dentry->d_inode) { | 1442 | if (state->inode == dentry->d_inode) { |
1443 | nfs_set_verifier(dentry, nfs_save_change_attribute(dir)); | ||
1471 | nfs4_intent_set_file(nd, &path, state); | 1444 | nfs4_intent_set_file(nd, &path, state); |
1472 | return 1; | 1445 | return 1; |
1473 | } | 1446 | } |
@@ -1757,10 +1730,16 @@ static int nfs4_proc_lookup(struct inode *dir, struct qstr *name, struct nfs_fh | |||
1757 | 1730 | ||
1758 | static int _nfs4_proc_access(struct inode *inode, struct nfs_access_entry *entry) | 1731 | static int _nfs4_proc_access(struct inode *inode, struct nfs_access_entry *entry) |
1759 | { | 1732 | { |
1733 | struct nfs_server *server = NFS_SERVER(inode); | ||
1734 | struct nfs_fattr fattr; | ||
1760 | struct nfs4_accessargs args = { | 1735 | struct nfs4_accessargs args = { |
1761 | .fh = NFS_FH(inode), | 1736 | .fh = NFS_FH(inode), |
1737 | .bitmask = server->attr_bitmask, | ||
1738 | }; | ||
1739 | struct nfs4_accessres res = { | ||
1740 | .server = server, | ||
1741 | .fattr = &fattr, | ||
1762 | }; | 1742 | }; |
1763 | struct nfs4_accessres res = { 0 }; | ||
1764 | struct rpc_message msg = { | 1743 | struct rpc_message msg = { |
1765 | .rpc_proc = &nfs4_procedures[NFSPROC4_CLNT_ACCESS], | 1744 | .rpc_proc = &nfs4_procedures[NFSPROC4_CLNT_ACCESS], |
1766 | .rpc_argp = &args, | 1745 | .rpc_argp = &args, |
@@ -1786,6 +1765,7 @@ static int _nfs4_proc_access(struct inode *inode, struct nfs_access_entry *entry | |||
1786 | if (mode & MAY_EXEC) | 1765 | if (mode & MAY_EXEC) |
1787 | args.access |= NFS4_ACCESS_EXECUTE; | 1766 | args.access |= NFS4_ACCESS_EXECUTE; |
1788 | } | 1767 | } |
1768 | nfs_fattr_init(&fattr); | ||
1789 | status = rpc_call_sync(NFS_CLIENT(inode), &msg, 0); | 1769 | status = rpc_call_sync(NFS_CLIENT(inode), &msg, 0); |
1790 | if (!status) { | 1770 | if (!status) { |
1791 | entry->mask = 0; | 1771 | entry->mask = 0; |
@@ -1795,6 +1775,7 @@ static int _nfs4_proc_access(struct inode *inode, struct nfs_access_entry *entry | |||
1795 | entry->mask |= MAY_WRITE; | 1775 | entry->mask |= MAY_WRITE; |
1796 | if (res.access & (NFS4_ACCESS_LOOKUP|NFS4_ACCESS_EXECUTE)) | 1776 | if (res.access & (NFS4_ACCESS_LOOKUP|NFS4_ACCESS_EXECUTE)) |
1797 | entry->mask |= MAY_EXEC; | 1777 | entry->mask |= MAY_EXEC; |
1778 | nfs_refresh_inode(inode, &fattr); | ||
1798 | } | 1779 | } |
1799 | return status; | 1780 | return status; |
1800 | } | 1781 | } |
@@ -1900,11 +1881,13 @@ nfs4_proc_create(struct inode *dir, struct dentry *dentry, struct iattr *sattr, | |||
1900 | } | 1881 | } |
1901 | state = nfs4_do_open(dir, &path, flags, sattr, cred); | 1882 | state = nfs4_do_open(dir, &path, flags, sattr, cred); |
1902 | put_rpccred(cred); | 1883 | put_rpccred(cred); |
1884 | d_drop(dentry); | ||
1903 | if (IS_ERR(state)) { | 1885 | if (IS_ERR(state)) { |
1904 | status = PTR_ERR(state); | 1886 | status = PTR_ERR(state); |
1905 | goto out; | 1887 | goto out; |
1906 | } | 1888 | } |
1907 | d_instantiate(dentry, igrab(state->inode)); | 1889 | d_add(dentry, igrab(state->inode)); |
1890 | nfs_set_verifier(dentry, nfs_save_change_attribute(dir)); | ||
1908 | if (flags & O_EXCL) { | 1891 | if (flags & O_EXCL) { |
1909 | struct nfs_fattr fattr; | 1892 | struct nfs_fattr fattr; |
1910 | status = nfs4_do_setattr(state->inode, &fattr, sattr, state); | 1893 | status = nfs4_do_setattr(state->inode, &fattr, sattr, state); |
@@ -2218,6 +2201,9 @@ static int _nfs4_proc_readdir(struct dentry *dentry, struct rpc_cred *cred, | |||
2218 | status = rpc_call_sync(NFS_CLIENT(dir), &msg, 0); | 2201 | status = rpc_call_sync(NFS_CLIENT(dir), &msg, 0); |
2219 | if (status == 0) | 2202 | if (status == 0) |
2220 | memcpy(NFS_COOKIEVERF(dir), res.verifier.data, NFS4_VERIFIER_SIZE); | 2203 | memcpy(NFS_COOKIEVERF(dir), res.verifier.data, NFS4_VERIFIER_SIZE); |
2204 | |||
2205 | nfs_invalidate_atime(dir); | ||
2206 | |||
2221 | dprintk("%s: returns %d\n", __FUNCTION__, status); | 2207 | dprintk("%s: returns %d\n", __FUNCTION__, status); |
2222 | return status; | 2208 | return status; |
2223 | } | 2209 | } |
@@ -2414,6 +2400,8 @@ static int nfs4_read_done(struct rpc_task *task, struct nfs_read_data *data) | |||
2414 | rpc_restart_call(task); | 2400 | rpc_restart_call(task); |
2415 | return -EAGAIN; | 2401 | return -EAGAIN; |
2416 | } | 2402 | } |
2403 | |||
2404 | nfs_invalidate_atime(data->inode); | ||
2417 | if (task->tk_status > 0) | 2405 | if (task->tk_status > 0) |
2418 | renew_lease(server, data->timestamp); | 2406 | renew_lease(server, data->timestamp); |
2419 | return 0; | 2407 | return 0; |
@@ -2443,7 +2431,7 @@ static int nfs4_write_done(struct rpc_task *task, struct nfs_write_data *data) | |||
2443 | } | 2431 | } |
2444 | if (task->tk_status >= 0) { | 2432 | if (task->tk_status >= 0) { |
2445 | renew_lease(NFS_SERVER(inode), data->timestamp); | 2433 | renew_lease(NFS_SERVER(inode), data->timestamp); |
2446 | nfs_post_op_update_inode(inode, data->res.fattr); | 2434 | nfs_post_op_update_inode_force_wcc(inode, data->res.fattr); |
2447 | } | 2435 | } |
2448 | return 0; | 2436 | return 0; |
2449 | } | 2437 | } |
@@ -2485,8 +2473,7 @@ static int nfs4_commit_done(struct rpc_task *task, struct nfs_write_data *data) | |||
2485 | rpc_restart_call(task); | 2473 | rpc_restart_call(task); |
2486 | return -EAGAIN; | 2474 | return -EAGAIN; |
2487 | } | 2475 | } |
2488 | if (task->tk_status >= 0) | 2476 | nfs_refresh_inode(inode, data->res.fattr); |
2489 | nfs_post_op_update_inode(inode, data->res.fattr); | ||
2490 | return 0; | 2477 | return 0; |
2491 | } | 2478 | } |
2492 | 2479 | ||
@@ -3056,7 +3043,7 @@ static int _nfs4_proc_delegreturn(struct inode *inode, struct rpc_cred *cred, co | |||
3056 | if (status == 0) { | 3043 | if (status == 0) { |
3057 | status = data->rpc_status; | 3044 | status = data->rpc_status; |
3058 | if (status == 0) | 3045 | if (status == 0) |
3059 | nfs_post_op_update_inode(inode, &data->fattr); | 3046 | nfs_refresh_inode(inode, &data->fattr); |
3060 | } | 3047 | } |
3061 | rpc_put_task(task); | 3048 | rpc_put_task(task); |
3062 | return status; | 3049 | return status; |
@@ -3303,7 +3290,7 @@ static int nfs4_proc_unlck(struct nfs4_state *state, int cmd, struct file_lock * | |||
3303 | status = -ENOMEM; | 3290 | status = -ENOMEM; |
3304 | if (seqid == NULL) | 3291 | if (seqid == NULL) |
3305 | goto out; | 3292 | goto out; |
3306 | task = nfs4_do_unlck(request, request->fl_file->private_data, lsp, seqid); | 3293 | task = nfs4_do_unlck(request, nfs_file_open_context(request->fl_file), lsp, seqid); |
3307 | status = PTR_ERR(task); | 3294 | status = PTR_ERR(task); |
3308 | if (IS_ERR(task)) | 3295 | if (IS_ERR(task)) |
3309 | goto out; | 3296 | goto out; |
@@ -3447,7 +3434,7 @@ static int _nfs4_do_setlk(struct nfs4_state *state, int cmd, struct file_lock *f | |||
3447 | int ret; | 3434 | int ret; |
3448 | 3435 | ||
3449 | dprintk("%s: begin!\n", __FUNCTION__); | 3436 | dprintk("%s: begin!\n", __FUNCTION__); |
3450 | data = nfs4_alloc_lockdata(fl, fl->fl_file->private_data, | 3437 | data = nfs4_alloc_lockdata(fl, nfs_file_open_context(fl->fl_file), |
3451 | fl->fl_u.nfs4_fl.owner); | 3438 | fl->fl_u.nfs4_fl.owner); |
3452 | if (data == NULL) | 3439 | if (data == NULL) |
3453 | return -ENOMEM; | 3440 | return -ENOMEM; |
@@ -3573,7 +3560,7 @@ nfs4_proc_lock(struct file *filp, int cmd, struct file_lock *request) | |||
3573 | int status; | 3560 | int status; |
3574 | 3561 | ||
3575 | /* verify open state */ | 3562 | /* verify open state */ |
3576 | ctx = (struct nfs_open_context *)filp->private_data; | 3563 | ctx = nfs_file_open_context(filp); |
3577 | state = ctx->state; | 3564 | state = ctx->state; |
3578 | 3565 | ||
3579 | if (request->fl_start < 0 || request->fl_end < 0) | 3566 | if (request->fl_start < 0 || request->fl_end < 0) |