diff options
Diffstat (limited to 'fs/nfs/nfs4proc.c')
| -rw-r--r-- | fs/nfs/nfs4proc.c | 438 |
1 files changed, 286 insertions, 152 deletions
diff --git a/fs/nfs/nfs4proc.c b/fs/nfs/nfs4proc.c index d86c0db7b1e8..47c7e6e3910d 100644 --- a/fs/nfs/nfs4proc.c +++ b/fs/nfs/nfs4proc.c | |||
| @@ -55,7 +55,7 @@ | |||
| 55 | 55 | ||
| 56 | #define NFSDBG_FACILITY NFSDBG_PROC | 56 | #define NFSDBG_FACILITY NFSDBG_PROC |
| 57 | 57 | ||
| 58 | #define NFS4_POLL_RETRY_MIN (1*HZ) | 58 | #define NFS4_POLL_RETRY_MIN (HZ/10) |
| 59 | #define NFS4_POLL_RETRY_MAX (15*HZ) | 59 | #define NFS4_POLL_RETRY_MAX (15*HZ) |
| 60 | 60 | ||
| 61 | struct nfs4_opendata; | 61 | struct nfs4_opendata; |
| @@ -64,9 +64,7 @@ static int nfs4_do_fsinfo(struct nfs_server *, struct nfs_fh *, struct nfs_fsinf | |||
| 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); | 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); | 66 | 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 nfs4_client *clp); | 67 | static int nfs4_wait_clnt_recover(struct rpc_clnt *clnt, struct nfs_client *clp); |
| 68 | extern u32 *nfs4_decode_dirent(u32 *p, struct nfs_entry *entry, int plus); | ||
| 69 | extern struct rpc_procinfo nfs4_procedures[]; | ||
| 70 | 68 | ||
| 71 | /* Prevent leaks of NFSv4 errors into userland */ | 69 | /* Prevent leaks of NFSv4 errors into userland */ |
| 72 | int nfs4_map_errors(int err) | 70 | int nfs4_map_errors(int err) |
| @@ -121,6 +119,25 @@ const u32 nfs4_fsinfo_bitmap[2] = { FATTR4_WORD0_MAXFILESIZE | |||
| 121 | 0 | 119 | 0 |
| 122 | }; | 120 | }; |
| 123 | 121 | ||
| 122 | const u32 nfs4_fs_locations_bitmap[2] = { | ||
| 123 | FATTR4_WORD0_TYPE | ||
| 124 | | FATTR4_WORD0_CHANGE | ||
| 125 | | FATTR4_WORD0_SIZE | ||
| 126 | | FATTR4_WORD0_FSID | ||
| 127 | | FATTR4_WORD0_FILEID | ||
| 128 | | FATTR4_WORD0_FS_LOCATIONS, | ||
| 129 | FATTR4_WORD1_MODE | ||
| 130 | | FATTR4_WORD1_NUMLINKS | ||
| 131 | | FATTR4_WORD1_OWNER | ||
| 132 | | FATTR4_WORD1_OWNER_GROUP | ||
| 133 | | FATTR4_WORD1_RAWDEV | ||
| 134 | | FATTR4_WORD1_SPACE_USED | ||
| 135 | | FATTR4_WORD1_TIME_ACCESS | ||
| 136 | | FATTR4_WORD1_TIME_METADATA | ||
| 137 | | FATTR4_WORD1_TIME_MODIFY | ||
| 138 | | FATTR4_WORD1_MOUNTED_ON_FILEID | ||
| 139 | }; | ||
| 140 | |||
| 124 | static void nfs4_setup_readdir(u64 cookie, u32 *verifier, struct dentry *dentry, | 141 | static void nfs4_setup_readdir(u64 cookie, u32 *verifier, struct dentry *dentry, |
| 125 | struct nfs4_readdir_arg *readdir) | 142 | struct nfs4_readdir_arg *readdir) |
| 126 | { | 143 | { |
| @@ -178,22 +195,22 @@ static void nfs4_setup_readdir(u64 cookie, u32 *verifier, struct dentry *dentry, | |||
| 178 | 195 | ||
| 179 | static void renew_lease(const struct nfs_server *server, unsigned long timestamp) | 196 | static void renew_lease(const struct nfs_server *server, unsigned long timestamp) |
| 180 | { | 197 | { |
| 181 | struct nfs4_client *clp = server->nfs4_state; | 198 | struct nfs_client *clp = server->nfs_client; |
| 182 | spin_lock(&clp->cl_lock); | 199 | spin_lock(&clp->cl_lock); |
| 183 | if (time_before(clp->cl_last_renewal,timestamp)) | 200 | if (time_before(clp->cl_last_renewal,timestamp)) |
| 184 | clp->cl_last_renewal = timestamp; | 201 | clp->cl_last_renewal = timestamp; |
| 185 | spin_unlock(&clp->cl_lock); | 202 | spin_unlock(&clp->cl_lock); |
| 186 | } | 203 | } |
| 187 | 204 | ||
| 188 | static void update_changeattr(struct inode *inode, struct nfs4_change_info *cinfo) | 205 | static void update_changeattr(struct inode *dir, struct nfs4_change_info *cinfo) |
| 189 | { | 206 | { |
| 190 | struct nfs_inode *nfsi = NFS_I(inode); | 207 | struct nfs_inode *nfsi = NFS_I(dir); |
| 191 | 208 | ||
| 192 | spin_lock(&inode->i_lock); | 209 | spin_lock(&dir->i_lock); |
| 193 | nfsi->cache_validity |= NFS_INO_INVALID_ATTR; | 210 | nfsi->cache_validity |= NFS_INO_INVALID_ATTR|NFS_INO_REVAL_PAGECACHE|NFS_INO_INVALID_DATA; |
| 194 | if (cinfo->before == nfsi->change_attr && cinfo->atomic) | 211 | if (cinfo->before == nfsi->change_attr && cinfo->atomic) |
| 195 | nfsi->change_attr = cinfo->after; | 212 | nfsi->change_attr = cinfo->after; |
| 196 | spin_unlock(&inode->i_lock); | 213 | spin_unlock(&dir->i_lock); |
| 197 | } | 214 | } |
| 198 | 215 | ||
| 199 | struct nfs4_opendata { | 216 | struct nfs4_opendata { |
| @@ -235,7 +252,7 @@ static struct nfs4_opendata *nfs4_opendata_alloc(struct dentry *dentry, | |||
| 235 | atomic_inc(&sp->so_count); | 252 | atomic_inc(&sp->so_count); |
| 236 | p->o_arg.fh = NFS_FH(dir); | 253 | p->o_arg.fh = NFS_FH(dir); |
| 237 | p->o_arg.open_flags = flags, | 254 | p->o_arg.open_flags = flags, |
| 238 | p->o_arg.clientid = server->nfs4_state->cl_clientid; | 255 | p->o_arg.clientid = server->nfs_client->cl_clientid; |
| 239 | p->o_arg.id = sp->so_id; | 256 | p->o_arg.id = sp->so_id; |
| 240 | p->o_arg.name = &dentry->d_name; | 257 | p->o_arg.name = &dentry->d_name; |
| 241 | p->o_arg.server = server; | 258 | p->o_arg.server = server; |
| @@ -533,7 +550,7 @@ int nfs4_open_delegation_recall(struct dentry *dentry, struct nfs4_state *state) | |||
| 533 | case -NFS4ERR_STALE_STATEID: | 550 | case -NFS4ERR_STALE_STATEID: |
| 534 | case -NFS4ERR_EXPIRED: | 551 | case -NFS4ERR_EXPIRED: |
| 535 | /* Don't recall a delegation if it was lost */ | 552 | /* Don't recall a delegation if it was lost */ |
| 536 | nfs4_schedule_state_recovery(server->nfs4_state); | 553 | nfs4_schedule_state_recovery(server->nfs_client); |
| 537 | return err; | 554 | return err; |
| 538 | } | 555 | } |
| 539 | err = nfs4_handle_exception(server, err, &exception); | 556 | err = nfs4_handle_exception(server, err, &exception); |
| @@ -741,7 +758,7 @@ static int _nfs4_proc_open(struct nfs4_opendata *data) | |||
| 741 | } | 758 | } |
| 742 | nfs_confirm_seqid(&data->owner->so_seqid, 0); | 759 | nfs_confirm_seqid(&data->owner->so_seqid, 0); |
| 743 | if (!(o_res->f_attr->valid & NFS_ATTR_FATTR)) | 760 | if (!(o_res->f_attr->valid & NFS_ATTR_FATTR)) |
| 744 | return server->rpc_ops->getattr(server, &o_res->fh, o_res->f_attr); | 761 | return server->nfs_client->rpc_ops->getattr(server, &o_res->fh, o_res->f_attr); |
| 745 | return 0; | 762 | return 0; |
| 746 | } | 763 | } |
| 747 | 764 | ||
| @@ -775,11 +792,18 @@ out: | |||
| 775 | 792 | ||
| 776 | int nfs4_recover_expired_lease(struct nfs_server *server) | 793 | int nfs4_recover_expired_lease(struct nfs_server *server) |
| 777 | { | 794 | { |
| 778 | struct nfs4_client *clp = server->nfs4_state; | 795 | struct nfs_client *clp = server->nfs_client; |
| 796 | int ret; | ||
| 779 | 797 | ||
| 780 | if (test_and_clear_bit(NFS4CLNT_LEASE_EXPIRED, &clp->cl_state)) | 798 | for (;;) { |
| 799 | ret = nfs4_wait_clnt_recover(server->client, clp); | ||
| 800 | if (ret != 0) | ||
| 801 | return ret; | ||
| 802 | if (!test_and_clear_bit(NFS4CLNT_LEASE_EXPIRED, &clp->cl_state)) | ||
| 803 | break; | ||
| 781 | nfs4_schedule_state_recovery(clp); | 804 | nfs4_schedule_state_recovery(clp); |
| 782 | return nfs4_wait_clnt_recover(server->client, clp); | 805 | } |
| 806 | return 0; | ||
| 783 | } | 807 | } |
| 784 | 808 | ||
| 785 | /* | 809 | /* |
| @@ -850,7 +874,7 @@ static int _nfs4_open_delegated(struct inode *inode, int flags, struct rpc_cred | |||
| 850 | { | 874 | { |
| 851 | struct nfs_delegation *delegation; | 875 | struct nfs_delegation *delegation; |
| 852 | struct nfs_server *server = NFS_SERVER(inode); | 876 | struct nfs_server *server = NFS_SERVER(inode); |
| 853 | struct nfs4_client *clp = server->nfs4_state; | 877 | struct nfs_client *clp = server->nfs_client; |
| 854 | struct nfs_inode *nfsi = NFS_I(inode); | 878 | struct nfs_inode *nfsi = NFS_I(inode); |
| 855 | struct nfs4_state_owner *sp = NULL; | 879 | struct nfs4_state_owner *sp = NULL; |
| 856 | struct nfs4_state *state = NULL; | 880 | struct nfs4_state *state = NULL; |
| @@ -936,7 +960,7 @@ static int _nfs4_do_open(struct inode *dir, struct dentry *dentry, int flags, st | |||
| 936 | struct nfs4_state_owner *sp; | 960 | struct nfs4_state_owner *sp; |
| 937 | struct nfs4_state *state = NULL; | 961 | struct nfs4_state *state = NULL; |
| 938 | struct nfs_server *server = NFS_SERVER(dir); | 962 | struct nfs_server *server = NFS_SERVER(dir); |
| 939 | struct nfs4_client *clp = server->nfs4_state; | 963 | struct nfs_client *clp = server->nfs_client; |
| 940 | struct nfs4_opendata *opendata; | 964 | struct nfs4_opendata *opendata; |
| 941 | int status; | 965 | int status; |
| 942 | 966 | ||
| @@ -953,7 +977,7 @@ static int _nfs4_do_open(struct inode *dir, struct dentry *dentry, int flags, st | |||
| 953 | status = -ENOMEM; | 977 | status = -ENOMEM; |
| 954 | opendata = nfs4_opendata_alloc(dentry, sp, flags, sattr); | 978 | opendata = nfs4_opendata_alloc(dentry, sp, flags, sattr); |
| 955 | if (opendata == NULL) | 979 | if (opendata == NULL) |
| 956 | goto err_put_state_owner; | 980 | goto err_release_rwsem; |
| 957 | 981 | ||
| 958 | status = _nfs4_proc_open(opendata); | 982 | status = _nfs4_proc_open(opendata); |
| 959 | if (status != 0) | 983 | if (status != 0) |
| @@ -972,11 +996,11 @@ static int _nfs4_do_open(struct inode *dir, struct dentry *dentry, int flags, st | |||
| 972 | return 0; | 996 | return 0; |
| 973 | err_opendata_free: | 997 | err_opendata_free: |
| 974 | nfs4_opendata_free(opendata); | 998 | nfs4_opendata_free(opendata); |
| 999 | err_release_rwsem: | ||
| 1000 | up_read(&clp->cl_sem); | ||
| 975 | err_put_state_owner: | 1001 | err_put_state_owner: |
| 976 | nfs4_put_state_owner(sp); | 1002 | nfs4_put_state_owner(sp); |
| 977 | out_err: | 1003 | out_err: |
| 978 | /* Note: clp->cl_sem must be released before nfs4_put_open_state()! */ | ||
| 979 | up_read(&clp->cl_sem); | ||
| 980 | *res = NULL; | 1004 | *res = NULL; |
| 981 | return status; | 1005 | return status; |
| 982 | } | 1006 | } |
| @@ -1116,7 +1140,7 @@ static void nfs4_close_done(struct rpc_task *task, void *data) | |||
| 1116 | break; | 1140 | break; |
| 1117 | case -NFS4ERR_STALE_STATEID: | 1141 | case -NFS4ERR_STALE_STATEID: |
| 1118 | case -NFS4ERR_EXPIRED: | 1142 | case -NFS4ERR_EXPIRED: |
| 1119 | nfs4_schedule_state_recovery(server->nfs4_state); | 1143 | nfs4_schedule_state_recovery(server->nfs_client); |
| 1120 | break; | 1144 | break; |
| 1121 | default: | 1145 | default: |
| 1122 | if (nfs4_async_handle_error(task, server) == -EAGAIN) { | 1146 | if (nfs4_async_handle_error(task, server) == -EAGAIN) { |
| @@ -1251,7 +1275,7 @@ nfs4_atomic_open(struct inode *dir, struct dentry *dentry, struct nameidata *nd) | |||
| 1251 | BUG_ON(nd->intent.open.flags & O_CREAT); | 1275 | BUG_ON(nd->intent.open.flags & O_CREAT); |
| 1252 | } | 1276 | } |
| 1253 | 1277 | ||
| 1254 | cred = rpcauth_lookupcred(NFS_SERVER(dir)->client->cl_auth, 0); | 1278 | cred = rpcauth_lookupcred(NFS_CLIENT(dir)->cl_auth, 0); |
| 1255 | if (IS_ERR(cred)) | 1279 | if (IS_ERR(cred)) |
| 1256 | return (struct dentry *)cred; | 1280 | return (struct dentry *)cred; |
| 1257 | state = nfs4_do_open(dir, dentry, nd->intent.open.flags, &attr, cred); | 1281 | state = nfs4_do_open(dir, dentry, nd->intent.open.flags, &attr, cred); |
| @@ -1274,7 +1298,7 @@ nfs4_open_revalidate(struct inode *dir, struct dentry *dentry, int openflags, st | |||
| 1274 | struct rpc_cred *cred; | 1298 | struct rpc_cred *cred; |
| 1275 | struct nfs4_state *state; | 1299 | struct nfs4_state *state; |
| 1276 | 1300 | ||
| 1277 | cred = rpcauth_lookupcred(NFS_SERVER(dir)->client->cl_auth, 0); | 1301 | cred = rpcauth_lookupcred(NFS_CLIENT(dir)->cl_auth, 0); |
| 1278 | if (IS_ERR(cred)) | 1302 | if (IS_ERR(cred)) |
| 1279 | return PTR_ERR(cred); | 1303 | return PTR_ERR(cred); |
| 1280 | state = nfs4_open_delegated(dentry->d_inode, openflags, cred); | 1304 | state = nfs4_open_delegated(dentry->d_inode, openflags, cred); |
| @@ -1331,7 +1355,7 @@ static int _nfs4_server_capabilities(struct nfs_server *server, struct nfs_fh *f | |||
| 1331 | return status; | 1355 | return status; |
| 1332 | } | 1356 | } |
| 1333 | 1357 | ||
| 1334 | static int nfs4_server_capabilities(struct nfs_server *server, struct nfs_fh *fhandle) | 1358 | int nfs4_server_capabilities(struct nfs_server *server, struct nfs_fh *fhandle) |
| 1335 | { | 1359 | { |
| 1336 | struct nfs4_exception exception = { }; | 1360 | struct nfs4_exception exception = { }; |
| 1337 | int err; | 1361 | int err; |
| @@ -1376,73 +1400,66 @@ static int nfs4_lookup_root(struct nfs_server *server, struct nfs_fh *fhandle, | |||
| 1376 | return err; | 1400 | return err; |
| 1377 | } | 1401 | } |
| 1378 | 1402 | ||
| 1403 | /* | ||
| 1404 | * get the file handle for the "/" directory on the server | ||
| 1405 | */ | ||
| 1379 | static int nfs4_proc_get_root(struct nfs_server *server, struct nfs_fh *fhandle, | 1406 | static int nfs4_proc_get_root(struct nfs_server *server, struct nfs_fh *fhandle, |
| 1380 | struct nfs_fsinfo *info) | 1407 | struct nfs_fsinfo *info) |
| 1381 | { | 1408 | { |
| 1382 | struct nfs_fattr * fattr = info->fattr; | ||
| 1383 | unsigned char * p; | ||
| 1384 | struct qstr q; | ||
| 1385 | struct nfs4_lookup_arg args = { | ||
| 1386 | .dir_fh = fhandle, | ||
| 1387 | .name = &q, | ||
| 1388 | .bitmask = nfs4_fattr_bitmap, | ||
| 1389 | }; | ||
| 1390 | struct nfs4_lookup_res res = { | ||
| 1391 | .server = server, | ||
| 1392 | .fattr = fattr, | ||
| 1393 | .fh = fhandle, | ||
| 1394 | }; | ||
| 1395 | struct rpc_message msg = { | ||
| 1396 | .rpc_proc = &nfs4_procedures[NFSPROC4_CLNT_LOOKUP], | ||
| 1397 | .rpc_argp = &args, | ||
| 1398 | .rpc_resp = &res, | ||
| 1399 | }; | ||
| 1400 | int status; | 1409 | int status; |
| 1401 | 1410 | ||
| 1402 | /* | ||
| 1403 | * Now we do a separate LOOKUP for each component of the mount path. | ||
| 1404 | * The LOOKUPs are done separately so that we can conveniently | ||
| 1405 | * catch an ERR_WRONGSEC if it occurs along the way... | ||
| 1406 | */ | ||
| 1407 | status = nfs4_lookup_root(server, fhandle, info); | 1411 | status = nfs4_lookup_root(server, fhandle, info); |
| 1408 | if (status) | ||
| 1409 | goto out; | ||
| 1410 | |||
| 1411 | p = server->mnt_path; | ||
| 1412 | for (;;) { | ||
| 1413 | struct nfs4_exception exception = { }; | ||
| 1414 | |||
| 1415 | while (*p == '/') | ||
| 1416 | p++; | ||
| 1417 | if (!*p) | ||
| 1418 | break; | ||
| 1419 | q.name = p; | ||
| 1420 | while (*p && (*p != '/')) | ||
| 1421 | p++; | ||
| 1422 | q.len = p - q.name; | ||
| 1423 | |||
| 1424 | do { | ||
| 1425 | nfs_fattr_init(fattr); | ||
| 1426 | status = nfs4_handle_exception(server, | ||
| 1427 | rpc_call_sync(server->client, &msg, 0), | ||
| 1428 | &exception); | ||
| 1429 | } while (exception.retry); | ||
| 1430 | if (status == 0) | ||
| 1431 | continue; | ||
| 1432 | if (status == -ENOENT) { | ||
| 1433 | printk(KERN_NOTICE "NFS: mount path %s does not exist!\n", server->mnt_path); | ||
| 1434 | printk(KERN_NOTICE "NFS: suggestion: try mounting '/' instead.\n"); | ||
| 1435 | } | ||
| 1436 | break; | ||
| 1437 | } | ||
| 1438 | if (status == 0) | 1412 | if (status == 0) |
| 1439 | status = nfs4_server_capabilities(server, fhandle); | 1413 | status = nfs4_server_capabilities(server, fhandle); |
| 1440 | if (status == 0) | 1414 | if (status == 0) |
| 1441 | status = nfs4_do_fsinfo(server, fhandle, info); | 1415 | status = nfs4_do_fsinfo(server, fhandle, info); |
| 1442 | out: | ||
| 1443 | return nfs4_map_errors(status); | 1416 | return nfs4_map_errors(status); |
| 1444 | } | 1417 | } |
| 1445 | 1418 | ||
| 1419 | /* | ||
| 1420 | * Get locations and (maybe) other attributes of a referral. | ||
| 1421 | * Note that we'll actually follow the referral later when | ||
| 1422 | * we detect fsid mismatch in inode revalidation | ||
| 1423 | */ | ||
| 1424 | static int nfs4_get_referral(struct inode *dir, struct qstr *name, struct nfs_fattr *fattr, struct nfs_fh *fhandle) | ||
| 1425 | { | ||
| 1426 | int status = -ENOMEM; | ||
| 1427 | struct page *page = NULL; | ||
| 1428 | struct nfs4_fs_locations *locations = NULL; | ||
| 1429 | struct dentry dentry = {}; | ||
| 1430 | |||
| 1431 | page = alloc_page(GFP_KERNEL); | ||
| 1432 | if (page == NULL) | ||
| 1433 | goto out; | ||
| 1434 | locations = kmalloc(sizeof(struct nfs4_fs_locations), GFP_KERNEL); | ||
| 1435 | if (locations == NULL) | ||
| 1436 | goto out; | ||
| 1437 | |||
| 1438 | dentry.d_name.name = name->name; | ||
| 1439 | dentry.d_name.len = name->len; | ||
| 1440 | status = nfs4_proc_fs_locations(dir, &dentry, locations, page); | ||
| 1441 | if (status != 0) | ||
| 1442 | goto out; | ||
| 1443 | /* Make sure server returned a different fsid for the referral */ | ||
| 1444 | if (nfs_fsid_equal(&NFS_SERVER(dir)->fsid, &locations->fattr.fsid)) { | ||
| 1445 | dprintk("%s: server did not return a different fsid for a referral at %s\n", __FUNCTION__, name->name); | ||
| 1446 | status = -EIO; | ||
| 1447 | goto out; | ||
| 1448 | } | ||
| 1449 | |||
| 1450 | memcpy(fattr, &locations->fattr, sizeof(struct nfs_fattr)); | ||
| 1451 | fattr->valid |= NFS_ATTR_FATTR_V4_REFERRAL; | ||
| 1452 | if (!fattr->mode) | ||
| 1453 | fattr->mode = S_IFDIR; | ||
| 1454 | memset(fhandle, 0, sizeof(struct nfs_fh)); | ||
| 1455 | out: | ||
| 1456 | if (page) | ||
| 1457 | __free_page(page); | ||
| 1458 | if (locations) | ||
| 1459 | kfree(locations); | ||
| 1460 | return status; | ||
| 1461 | } | ||
| 1462 | |||
| 1446 | static int _nfs4_proc_getattr(struct nfs_server *server, struct nfs_fh *fhandle, struct nfs_fattr *fattr) | 1463 | static int _nfs4_proc_getattr(struct nfs_server *server, struct nfs_fh *fhandle, struct nfs_fattr *fattr) |
| 1447 | { | 1464 | { |
| 1448 | struct nfs4_getattr_arg args = { | 1465 | struct nfs4_getattr_arg args = { |
| @@ -1504,7 +1521,7 @@ nfs4_proc_setattr(struct dentry *dentry, struct nfs_fattr *fattr, | |||
| 1504 | 1521 | ||
| 1505 | nfs_fattr_init(fattr); | 1522 | nfs_fattr_init(fattr); |
| 1506 | 1523 | ||
| 1507 | cred = rpcauth_lookupcred(NFS_SERVER(inode)->client->cl_auth, 0); | 1524 | cred = rpcauth_lookupcred(NFS_CLIENT(inode)->cl_auth, 0); |
| 1508 | if (IS_ERR(cred)) | 1525 | if (IS_ERR(cred)) |
| 1509 | return PTR_ERR(cred); | 1526 | return PTR_ERR(cred); |
| 1510 | 1527 | ||
| @@ -1522,6 +1539,52 @@ nfs4_proc_setattr(struct dentry *dentry, struct nfs_fattr *fattr, | |||
| 1522 | return status; | 1539 | return status; |
| 1523 | } | 1540 | } |
| 1524 | 1541 | ||
| 1542 | static int _nfs4_proc_lookupfh(struct nfs_server *server, struct nfs_fh *dirfh, | ||
| 1543 | struct qstr *name, struct nfs_fh *fhandle, | ||
| 1544 | struct nfs_fattr *fattr) | ||
| 1545 | { | ||
| 1546 | int status; | ||
| 1547 | struct nfs4_lookup_arg args = { | ||
| 1548 | .bitmask = server->attr_bitmask, | ||
| 1549 | .dir_fh = dirfh, | ||
| 1550 | .name = name, | ||
| 1551 | }; | ||
| 1552 | struct nfs4_lookup_res res = { | ||
| 1553 | .server = server, | ||
| 1554 | .fattr = fattr, | ||
| 1555 | .fh = fhandle, | ||
| 1556 | }; | ||
| 1557 | struct rpc_message msg = { | ||
| 1558 | .rpc_proc = &nfs4_procedures[NFSPROC4_CLNT_LOOKUP], | ||
| 1559 | .rpc_argp = &args, | ||
| 1560 | .rpc_resp = &res, | ||
| 1561 | }; | ||
| 1562 | |||
| 1563 | nfs_fattr_init(fattr); | ||
| 1564 | |||
| 1565 | dprintk("NFS call lookupfh %s\n", name->name); | ||
| 1566 | status = rpc_call_sync(server->client, &msg, 0); | ||
| 1567 | dprintk("NFS reply lookupfh: %d\n", status); | ||
| 1568 | if (status == -NFS4ERR_MOVED) | ||
| 1569 | status = -EREMOTE; | ||
| 1570 | return status; | ||
| 1571 | } | ||
| 1572 | |||
| 1573 | static int nfs4_proc_lookupfh(struct nfs_server *server, struct nfs_fh *dirfh, | ||
| 1574 | struct qstr *name, struct nfs_fh *fhandle, | ||
| 1575 | struct nfs_fattr *fattr) | ||
| 1576 | { | ||
| 1577 | struct nfs4_exception exception = { }; | ||
| 1578 | int err; | ||
| 1579 | do { | ||
| 1580 | err = nfs4_handle_exception(server, | ||
| 1581 | _nfs4_proc_lookupfh(server, dirfh, name, | ||
| 1582 | fhandle, fattr), | ||
| 1583 | &exception); | ||
| 1584 | } while (exception.retry); | ||
| 1585 | return err; | ||
| 1586 | } | ||
| 1587 | |||
| 1525 | static int _nfs4_proc_lookup(struct inode *dir, struct qstr *name, | 1588 | static int _nfs4_proc_lookup(struct inode *dir, struct qstr *name, |
| 1526 | struct nfs_fh *fhandle, struct nfs_fattr *fattr) | 1589 | struct nfs_fh *fhandle, struct nfs_fattr *fattr) |
| 1527 | { | 1590 | { |
| @@ -1547,6 +1610,8 @@ static int _nfs4_proc_lookup(struct inode *dir, struct qstr *name, | |||
| 1547 | 1610 | ||
| 1548 | dprintk("NFS call lookup %s\n", name->name); | 1611 | dprintk("NFS call lookup %s\n", name->name); |
| 1549 | status = rpc_call_sync(NFS_CLIENT(dir), &msg, 0); | 1612 | status = rpc_call_sync(NFS_CLIENT(dir), &msg, 0); |
| 1613 | if (status == -NFS4ERR_MOVED) | ||
| 1614 | status = nfs4_get_referral(dir, name, fattr, fhandle); | ||
| 1550 | dprintk("NFS reply lookup: %d\n", status); | 1615 | dprintk("NFS reply lookup: %d\n", status); |
| 1551 | return status; | 1616 | return status; |
| 1552 | } | 1617 | } |
| @@ -1818,7 +1883,7 @@ nfs4_proc_create(struct inode *dir, struct dentry *dentry, struct iattr *sattr, | |||
| 1818 | struct rpc_cred *cred; | 1883 | struct rpc_cred *cred; |
| 1819 | int status = 0; | 1884 | int status = 0; |
| 1820 | 1885 | ||
| 1821 | cred = rpcauth_lookupcred(NFS_SERVER(dir)->client->cl_auth, 0); | 1886 | cred = rpcauth_lookupcred(NFS_CLIENT(dir)->cl_auth, 0); |
| 1822 | if (IS_ERR(cred)) { | 1887 | if (IS_ERR(cred)) { |
| 1823 | status = PTR_ERR(cred); | 1888 | status = PTR_ERR(cred); |
| 1824 | goto out; | 1889 | goto out; |
| @@ -2008,7 +2073,7 @@ static int _nfs4_proc_link(struct inode *inode, struct inode *dir, struct qstr * | |||
| 2008 | if (!status) { | 2073 | if (!status) { |
| 2009 | update_changeattr(dir, &res.cinfo); | 2074 | update_changeattr(dir, &res.cinfo); |
| 2010 | nfs_post_op_update_inode(dir, res.dir_attr); | 2075 | nfs_post_op_update_inode(dir, res.dir_attr); |
| 2011 | nfs_refresh_inode(inode, res.fattr); | 2076 | nfs_post_op_update_inode(inode, res.fattr); |
| 2012 | } | 2077 | } |
| 2013 | 2078 | ||
| 2014 | return status; | 2079 | return status; |
| @@ -2026,24 +2091,24 @@ static int nfs4_proc_link(struct inode *inode, struct inode *dir, struct qstr *n | |||
| 2026 | return err; | 2091 | return err; |
| 2027 | } | 2092 | } |
| 2028 | 2093 | ||
| 2029 | static int _nfs4_proc_symlink(struct inode *dir, struct qstr *name, | 2094 | static int _nfs4_proc_symlink(struct inode *dir, struct dentry *dentry, |
| 2030 | struct qstr *path, struct iattr *sattr, struct nfs_fh *fhandle, | 2095 | struct page *page, unsigned int len, struct iattr *sattr) |
| 2031 | struct nfs_fattr *fattr) | ||
| 2032 | { | 2096 | { |
| 2033 | struct nfs_server *server = NFS_SERVER(dir); | 2097 | struct nfs_server *server = NFS_SERVER(dir); |
| 2034 | struct nfs_fattr dir_fattr; | 2098 | struct nfs_fh fhandle; |
| 2099 | struct nfs_fattr fattr, dir_fattr; | ||
| 2035 | struct nfs4_create_arg arg = { | 2100 | struct nfs4_create_arg arg = { |
| 2036 | .dir_fh = NFS_FH(dir), | 2101 | .dir_fh = NFS_FH(dir), |
| 2037 | .server = server, | 2102 | .server = server, |
| 2038 | .name = name, | 2103 | .name = &dentry->d_name, |
| 2039 | .attrs = sattr, | 2104 | .attrs = sattr, |
| 2040 | .ftype = NF4LNK, | 2105 | .ftype = NF4LNK, |
| 2041 | .bitmask = server->attr_bitmask, | 2106 | .bitmask = server->attr_bitmask, |
| 2042 | }; | 2107 | }; |
| 2043 | struct nfs4_create_res res = { | 2108 | struct nfs4_create_res res = { |
| 2044 | .server = server, | 2109 | .server = server, |
| 2045 | .fh = fhandle, | 2110 | .fh = &fhandle, |
| 2046 | .fattr = fattr, | 2111 | .fattr = &fattr, |
| 2047 | .dir_fattr = &dir_fattr, | 2112 | .dir_fattr = &dir_fattr, |
| 2048 | }; | 2113 | }; |
| 2049 | struct rpc_message msg = { | 2114 | struct rpc_message msg = { |
| @@ -2053,29 +2118,32 @@ static int _nfs4_proc_symlink(struct inode *dir, struct qstr *name, | |||
| 2053 | }; | 2118 | }; |
| 2054 | int status; | 2119 | int status; |
| 2055 | 2120 | ||
| 2056 | if (path->len > NFS4_MAXPATHLEN) | 2121 | if (len > NFS4_MAXPATHLEN) |
| 2057 | return -ENAMETOOLONG; | 2122 | return -ENAMETOOLONG; |
| 2058 | arg.u.symlink = path; | 2123 | |
| 2059 | nfs_fattr_init(fattr); | 2124 | arg.u.symlink.pages = &page; |
| 2125 | arg.u.symlink.len = len; | ||
| 2126 | nfs_fattr_init(&fattr); | ||
| 2060 | nfs_fattr_init(&dir_fattr); | 2127 | nfs_fattr_init(&dir_fattr); |
| 2061 | 2128 | ||
| 2062 | status = rpc_call_sync(NFS_CLIENT(dir), &msg, 0); | 2129 | status = rpc_call_sync(NFS_CLIENT(dir), &msg, 0); |
| 2063 | if (!status) | 2130 | if (!status) { |
| 2064 | update_changeattr(dir, &res.dir_cinfo); | 2131 | update_changeattr(dir, &res.dir_cinfo); |
| 2065 | nfs_post_op_update_inode(dir, res.dir_fattr); | 2132 | nfs_post_op_update_inode(dir, res.dir_fattr); |
| 2133 | status = nfs_instantiate(dentry, &fhandle, &fattr); | ||
| 2134 | } | ||
| 2066 | return status; | 2135 | return status; |
| 2067 | } | 2136 | } |
| 2068 | 2137 | ||
| 2069 | static int nfs4_proc_symlink(struct inode *dir, struct qstr *name, | 2138 | static int nfs4_proc_symlink(struct inode *dir, struct dentry *dentry, |
| 2070 | struct qstr *path, struct iattr *sattr, struct nfs_fh *fhandle, | 2139 | struct page *page, unsigned int len, struct iattr *sattr) |
| 2071 | struct nfs_fattr *fattr) | ||
| 2072 | { | 2140 | { |
| 2073 | struct nfs4_exception exception = { }; | 2141 | struct nfs4_exception exception = { }; |
| 2074 | int err; | 2142 | int err; |
| 2075 | do { | 2143 | do { |
| 2076 | err = nfs4_handle_exception(NFS_SERVER(dir), | 2144 | err = nfs4_handle_exception(NFS_SERVER(dir), |
| 2077 | _nfs4_proc_symlink(dir, name, path, sattr, | 2145 | _nfs4_proc_symlink(dir, dentry, page, |
| 2078 | fhandle, fattr), | 2146 | len, sattr), |
| 2079 | &exception); | 2147 | &exception); |
| 2080 | } while (exception.retry); | 2148 | } while (exception.retry); |
| 2081 | return err; | 2149 | return err; |
| @@ -2458,7 +2526,7 @@ static void nfs4_proc_commit_setup(struct nfs_write_data *data, int how) | |||
| 2458 | */ | 2526 | */ |
| 2459 | static void nfs4_renew_done(struct rpc_task *task, void *data) | 2527 | static void nfs4_renew_done(struct rpc_task *task, void *data) |
| 2460 | { | 2528 | { |
| 2461 | struct nfs4_client *clp = (struct nfs4_client *)task->tk_msg.rpc_argp; | 2529 | struct nfs_client *clp = (struct nfs_client *)task->tk_msg.rpc_argp; |
| 2462 | unsigned long timestamp = (unsigned long)data; | 2530 | unsigned long timestamp = (unsigned long)data; |
| 2463 | 2531 | ||
| 2464 | if (task->tk_status < 0) { | 2532 | if (task->tk_status < 0) { |
| @@ -2480,7 +2548,7 @@ static const struct rpc_call_ops nfs4_renew_ops = { | |||
| 2480 | .rpc_call_done = nfs4_renew_done, | 2548 | .rpc_call_done = nfs4_renew_done, |
| 2481 | }; | 2549 | }; |
| 2482 | 2550 | ||
| 2483 | int nfs4_proc_async_renew(struct nfs4_client *clp, struct rpc_cred *cred) | 2551 | int nfs4_proc_async_renew(struct nfs_client *clp, struct rpc_cred *cred) |
| 2484 | { | 2552 | { |
| 2485 | struct rpc_message msg = { | 2553 | struct rpc_message msg = { |
| 2486 | .rpc_proc = &nfs4_procedures[NFSPROC4_CLNT_RENEW], | 2554 | .rpc_proc = &nfs4_procedures[NFSPROC4_CLNT_RENEW], |
| @@ -2492,7 +2560,7 @@ int nfs4_proc_async_renew(struct nfs4_client *clp, struct rpc_cred *cred) | |||
| 2492 | &nfs4_renew_ops, (void *)jiffies); | 2560 | &nfs4_renew_ops, (void *)jiffies); |
| 2493 | } | 2561 | } |
| 2494 | 2562 | ||
| 2495 | int nfs4_proc_renew(struct nfs4_client *clp, struct rpc_cred *cred) | 2563 | int nfs4_proc_renew(struct nfs_client *clp, struct rpc_cred *cred) |
| 2496 | { | 2564 | { |
| 2497 | struct rpc_message msg = { | 2565 | struct rpc_message msg = { |
| 2498 | .rpc_proc = &nfs4_procedures[NFSPROC4_CLNT_RENEW], | 2566 | .rpc_proc = &nfs4_procedures[NFSPROC4_CLNT_RENEW], |
| @@ -2605,7 +2673,7 @@ out: | |||
| 2605 | nfs4_set_cached_acl(inode, acl); | 2673 | nfs4_set_cached_acl(inode, acl); |
| 2606 | } | 2674 | } |
| 2607 | 2675 | ||
| 2608 | static inline ssize_t nfs4_get_acl_uncached(struct inode *inode, void *buf, size_t buflen) | 2676 | static ssize_t __nfs4_get_acl_uncached(struct inode *inode, void *buf, size_t buflen) |
| 2609 | { | 2677 | { |
| 2610 | struct page *pages[NFS4ACL_MAXPAGES]; | 2678 | struct page *pages[NFS4ACL_MAXPAGES]; |
| 2611 | struct nfs_getaclargs args = { | 2679 | struct nfs_getaclargs args = { |
| @@ -2658,6 +2726,19 @@ out_free: | |||
| 2658 | return ret; | 2726 | return ret; |
| 2659 | } | 2727 | } |
| 2660 | 2728 | ||
| 2729 | static ssize_t nfs4_get_acl_uncached(struct inode *inode, void *buf, size_t buflen) | ||
| 2730 | { | ||
| 2731 | struct nfs4_exception exception = { }; | ||
| 2732 | ssize_t ret; | ||
| 2733 | do { | ||
| 2734 | ret = __nfs4_get_acl_uncached(inode, buf, buflen); | ||
| 2735 | if (ret >= 0) | ||
| 2736 | break; | ||
| 2737 | ret = nfs4_handle_exception(NFS_SERVER(inode), ret, &exception); | ||
| 2738 | } while (exception.retry); | ||
| 2739 | return ret; | ||
| 2740 | } | ||
| 2741 | |||
| 2661 | static ssize_t nfs4_proc_get_acl(struct inode *inode, void *buf, size_t buflen) | 2742 | static ssize_t nfs4_proc_get_acl(struct inode *inode, void *buf, size_t buflen) |
| 2662 | { | 2743 | { |
| 2663 | struct nfs_server *server = NFS_SERVER(inode); | 2744 | struct nfs_server *server = NFS_SERVER(inode); |
| @@ -2674,7 +2755,7 @@ static ssize_t nfs4_proc_get_acl(struct inode *inode, void *buf, size_t buflen) | |||
| 2674 | return nfs4_get_acl_uncached(inode, buf, buflen); | 2755 | return nfs4_get_acl_uncached(inode, buf, buflen); |
| 2675 | } | 2756 | } |
| 2676 | 2757 | ||
| 2677 | static int nfs4_proc_set_acl(struct inode *inode, const void *buf, size_t buflen) | 2758 | static int __nfs4_proc_set_acl(struct inode *inode, const void *buf, size_t buflen) |
| 2678 | { | 2759 | { |
| 2679 | struct nfs_server *server = NFS_SERVER(inode); | 2760 | struct nfs_server *server = NFS_SERVER(inode); |
| 2680 | struct page *pages[NFS4ACL_MAXPAGES]; | 2761 | struct page *pages[NFS4ACL_MAXPAGES]; |
| @@ -2694,16 +2775,28 @@ static int nfs4_proc_set_acl(struct inode *inode, const void *buf, size_t buflen | |||
| 2694 | return -EOPNOTSUPP; | 2775 | return -EOPNOTSUPP; |
| 2695 | nfs_inode_return_delegation(inode); | 2776 | nfs_inode_return_delegation(inode); |
| 2696 | buf_to_pages(buf, buflen, arg.acl_pages, &arg.acl_pgbase); | 2777 | buf_to_pages(buf, buflen, arg.acl_pages, &arg.acl_pgbase); |
| 2697 | ret = rpc_call_sync(NFS_SERVER(inode)->client, &msg, 0); | 2778 | ret = rpc_call_sync(NFS_CLIENT(inode), &msg, 0); |
| 2698 | if (ret == 0) | 2779 | if (ret == 0) |
| 2699 | nfs4_write_cached_acl(inode, buf, buflen); | 2780 | nfs4_write_cached_acl(inode, buf, buflen); |
| 2700 | return ret; | 2781 | return ret; |
| 2701 | } | 2782 | } |
| 2702 | 2783 | ||
| 2784 | static int nfs4_proc_set_acl(struct inode *inode, const void *buf, size_t buflen) | ||
| 2785 | { | ||
| 2786 | struct nfs4_exception exception = { }; | ||
| 2787 | int err; | ||
| 2788 | do { | ||
| 2789 | err = nfs4_handle_exception(NFS_SERVER(inode), | ||
| 2790 | __nfs4_proc_set_acl(inode, buf, buflen), | ||
| 2791 | &exception); | ||
| 2792 | } while (exception.retry); | ||
| 2793 | return err; | ||
| 2794 | } | ||
| 2795 | |||
| 2703 | static int | 2796 | static int |
| 2704 | nfs4_async_handle_error(struct rpc_task *task, const struct nfs_server *server) | 2797 | nfs4_async_handle_error(struct rpc_task *task, const struct nfs_server *server) |
| 2705 | { | 2798 | { |
| 2706 | struct nfs4_client *clp = server->nfs4_state; | 2799 | struct nfs_client *clp = server->nfs_client; |
| 2707 | 2800 | ||
| 2708 | if (!clp || task->tk_status >= 0) | 2801 | if (!clp || task->tk_status >= 0) |
| 2709 | return 0; | 2802 | return 0; |
| @@ -2740,7 +2833,7 @@ static int nfs4_wait_bit_interruptible(void *word) | |||
| 2740 | return 0; | 2833 | return 0; |
| 2741 | } | 2834 | } |
| 2742 | 2835 | ||
| 2743 | static int nfs4_wait_clnt_recover(struct rpc_clnt *clnt, struct nfs4_client *clp) | 2836 | static int nfs4_wait_clnt_recover(struct rpc_clnt *clnt, struct nfs_client *clp) |
| 2744 | { | 2837 | { |
| 2745 | sigset_t oldset; | 2838 | sigset_t oldset; |
| 2746 | int res; | 2839 | int res; |
| @@ -2783,7 +2876,7 @@ static int nfs4_delay(struct rpc_clnt *clnt, long *timeout) | |||
| 2783 | */ | 2876 | */ |
| 2784 | int nfs4_handle_exception(const struct nfs_server *server, int errorcode, struct nfs4_exception *exception) | 2877 | int nfs4_handle_exception(const struct nfs_server *server, int errorcode, struct nfs4_exception *exception) |
| 2785 | { | 2878 | { |
| 2786 | struct nfs4_client *clp = server->nfs4_state; | 2879 | struct nfs_client *clp = server->nfs_client; |
| 2787 | int ret = errorcode; | 2880 | int ret = errorcode; |
| 2788 | 2881 | ||
| 2789 | exception->retry = 0; | 2882 | exception->retry = 0; |
| @@ -2798,6 +2891,7 @@ int nfs4_handle_exception(const struct nfs_server *server, int errorcode, struct | |||
| 2798 | if (ret == 0) | 2891 | if (ret == 0) |
| 2799 | exception->retry = 1; | 2892 | exception->retry = 1; |
| 2800 | break; | 2893 | break; |
| 2894 | case -NFS4ERR_FILE_OPEN: | ||
| 2801 | case -NFS4ERR_GRACE: | 2895 | case -NFS4ERR_GRACE: |
| 2802 | case -NFS4ERR_DELAY: | 2896 | case -NFS4ERR_DELAY: |
| 2803 | ret = nfs4_delay(server->client, &exception->timeout); | 2897 | ret = nfs4_delay(server->client, &exception->timeout); |
| @@ -2810,7 +2904,7 @@ int nfs4_handle_exception(const struct nfs_server *server, int errorcode, struct | |||
| 2810 | return nfs4_map_errors(ret); | 2904 | return nfs4_map_errors(ret); |
| 2811 | } | 2905 | } |
| 2812 | 2906 | ||
| 2813 | int nfs4_proc_setclientid(struct nfs4_client *clp, u32 program, unsigned short port, struct rpc_cred *cred) | 2907 | int nfs4_proc_setclientid(struct nfs_client *clp, u32 program, unsigned short port, struct rpc_cred *cred) |
| 2814 | { | 2908 | { |
| 2815 | nfs4_verifier sc_verifier; | 2909 | nfs4_verifier sc_verifier; |
| 2816 | struct nfs4_setclientid setclientid = { | 2910 | struct nfs4_setclientid setclientid = { |
| @@ -2834,7 +2928,7 @@ int nfs4_proc_setclientid(struct nfs4_client *clp, u32 program, unsigned short p | |||
| 2834 | for(;;) { | 2928 | for(;;) { |
| 2835 | setclientid.sc_name_len = scnprintf(setclientid.sc_name, | 2929 | setclientid.sc_name_len = scnprintf(setclientid.sc_name, |
| 2836 | sizeof(setclientid.sc_name), "%s/%u.%u.%u.%u %s %u", | 2930 | sizeof(setclientid.sc_name), "%s/%u.%u.%u.%u %s %u", |
| 2837 | clp->cl_ipaddr, NIPQUAD(clp->cl_addr.s_addr), | 2931 | clp->cl_ipaddr, NIPQUAD(clp->cl_addr.sin_addr), |
| 2838 | cred->cr_ops->cr_name, | 2932 | cred->cr_ops->cr_name, |
| 2839 | clp->cl_id_uniquifier); | 2933 | clp->cl_id_uniquifier); |
| 2840 | setclientid.sc_netid_len = scnprintf(setclientid.sc_netid, | 2934 | setclientid.sc_netid_len = scnprintf(setclientid.sc_netid, |
| @@ -2857,7 +2951,7 @@ int nfs4_proc_setclientid(struct nfs4_client *clp, u32 program, unsigned short p | |||
| 2857 | return status; | 2951 | return status; |
| 2858 | } | 2952 | } |
| 2859 | 2953 | ||
| 2860 | static int _nfs4_proc_setclientid_confirm(struct nfs4_client *clp, struct rpc_cred *cred) | 2954 | static int _nfs4_proc_setclientid_confirm(struct nfs_client *clp, struct rpc_cred *cred) |
| 2861 | { | 2955 | { |
| 2862 | struct nfs_fsinfo fsinfo; | 2956 | struct nfs_fsinfo fsinfo; |
| 2863 | struct rpc_message msg = { | 2957 | struct rpc_message msg = { |
| @@ -2881,7 +2975,7 @@ static int _nfs4_proc_setclientid_confirm(struct nfs4_client *clp, struct rpc_cr | |||
| 2881 | return status; | 2975 | return status; |
| 2882 | } | 2976 | } |
| 2883 | 2977 | ||
| 2884 | int nfs4_proc_setclientid_confirm(struct nfs4_client *clp, struct rpc_cred *cred) | 2978 | int nfs4_proc_setclientid_confirm(struct nfs_client *clp, struct rpc_cred *cred) |
| 2885 | { | 2979 | { |
| 2886 | long timeout; | 2980 | long timeout; |
| 2887 | int err; | 2981 | int err; |
| @@ -2989,7 +3083,7 @@ int nfs4_proc_delegreturn(struct inode *inode, struct rpc_cred *cred, const nfs4 | |||
| 2989 | switch (err) { | 3083 | switch (err) { |
| 2990 | case -NFS4ERR_STALE_STATEID: | 3084 | case -NFS4ERR_STALE_STATEID: |
| 2991 | case -NFS4ERR_EXPIRED: | 3085 | case -NFS4ERR_EXPIRED: |
| 2992 | nfs4_schedule_state_recovery(server->nfs4_state); | 3086 | nfs4_schedule_state_recovery(server->nfs_client); |
| 2993 | case 0: | 3087 | case 0: |
| 2994 | return 0; | 3088 | return 0; |
| 2995 | } | 3089 | } |
| @@ -3018,7 +3112,7 @@ static int _nfs4_proc_getlk(struct nfs4_state *state, int cmd, struct file_lock | |||
| 3018 | { | 3112 | { |
| 3019 | struct inode *inode = state->inode; | 3113 | struct inode *inode = state->inode; |
| 3020 | struct nfs_server *server = NFS_SERVER(inode); | 3114 | struct nfs_server *server = NFS_SERVER(inode); |
| 3021 | struct nfs4_client *clp = server->nfs4_state; | 3115 | struct nfs_client *clp = server->nfs_client; |
| 3022 | struct nfs_lockt_args arg = { | 3116 | struct nfs_lockt_args arg = { |
| 3023 | .fh = NFS_FH(inode), | 3117 | .fh = NFS_FH(inode), |
| 3024 | .fl = request, | 3118 | .fl = request, |
| @@ -3081,9 +3175,6 @@ static int do_vfs_lock(struct file *file, struct file_lock *fl) | |||
| 3081 | default: | 3175 | default: |
| 3082 | BUG(); | 3176 | BUG(); |
| 3083 | } | 3177 | } |
| 3084 | if (res < 0) | ||
| 3085 | printk(KERN_WARNING "%s: VFS is out of sync with lock manager!\n", | ||
| 3086 | __FUNCTION__); | ||
| 3087 | return res; | 3178 | return res; |
| 3088 | } | 3179 | } |
| 3089 | 3180 | ||
| @@ -3146,7 +3237,7 @@ static void nfs4_locku_done(struct rpc_task *task, void *data) | |||
| 3146 | break; | 3237 | break; |
| 3147 | case -NFS4ERR_STALE_STATEID: | 3238 | case -NFS4ERR_STALE_STATEID: |
| 3148 | case -NFS4ERR_EXPIRED: | 3239 | case -NFS4ERR_EXPIRED: |
| 3149 | nfs4_schedule_state_recovery(calldata->server->nfs4_state); | 3240 | nfs4_schedule_state_recovery(calldata->server->nfs_client); |
| 3150 | break; | 3241 | break; |
| 3151 | default: | 3242 | default: |
| 3152 | if (nfs4_async_handle_error(task, calldata->server) == -EAGAIN) { | 3243 | if (nfs4_async_handle_error(task, calldata->server) == -EAGAIN) { |
| @@ -3195,8 +3286,6 @@ static struct rpc_task *nfs4_do_unlck(struct file_lock *fl, | |||
| 3195 | return ERR_PTR(-ENOMEM); | 3286 | return ERR_PTR(-ENOMEM); |
| 3196 | } | 3287 | } |
| 3197 | 3288 | ||
| 3198 | /* Unlock _before_ we do the RPC call */ | ||
| 3199 | do_vfs_lock(fl->fl_file, fl); | ||
| 3200 | return rpc_run_task(NFS_CLIENT(lsp->ls_state->inode), RPC_TASK_ASYNC, &nfs4_locku_ops, data); | 3289 | return rpc_run_task(NFS_CLIENT(lsp->ls_state->inode), RPC_TASK_ASYNC, &nfs4_locku_ops, data); |
| 3201 | } | 3290 | } |
| 3202 | 3291 | ||
| @@ -3207,30 +3296,28 @@ static int nfs4_proc_unlck(struct nfs4_state *state, int cmd, struct file_lock * | |||
| 3207 | struct rpc_task *task; | 3296 | struct rpc_task *task; |
| 3208 | int status = 0; | 3297 | int status = 0; |
| 3209 | 3298 | ||
| 3210 | /* Is this a delegated lock? */ | ||
| 3211 | if (test_bit(NFS_DELEGATED_STATE, &state->flags)) | ||
| 3212 | goto out_unlock; | ||
| 3213 | /* Is this open_owner holding any locks on the server? */ | ||
| 3214 | if (test_bit(LK_STATE_IN_USE, &state->flags) == 0) | ||
| 3215 | goto out_unlock; | ||
| 3216 | |||
| 3217 | status = nfs4_set_lock_state(state, request); | 3299 | status = nfs4_set_lock_state(state, request); |
| 3300 | /* Unlock _before_ we do the RPC call */ | ||
| 3301 | request->fl_flags |= FL_EXISTS; | ||
| 3302 | if (do_vfs_lock(request->fl_file, request) == -ENOENT) | ||
| 3303 | goto out; | ||
| 3218 | if (status != 0) | 3304 | if (status != 0) |
| 3219 | goto out_unlock; | 3305 | goto out; |
| 3306 | /* Is this a delegated lock? */ | ||
| 3307 | if (test_bit(NFS_DELEGATED_STATE, &state->flags)) | ||
| 3308 | goto out; | ||
| 3220 | lsp = request->fl_u.nfs4_fl.owner; | 3309 | lsp = request->fl_u.nfs4_fl.owner; |
| 3221 | status = -ENOMEM; | ||
| 3222 | seqid = nfs_alloc_seqid(&lsp->ls_seqid); | 3310 | seqid = nfs_alloc_seqid(&lsp->ls_seqid); |
| 3311 | status = -ENOMEM; | ||
| 3223 | if (seqid == NULL) | 3312 | if (seqid == NULL) |
| 3224 | goto out_unlock; | 3313 | goto out; |
| 3225 | task = nfs4_do_unlck(request, request->fl_file->private_data, lsp, seqid); | 3314 | task = nfs4_do_unlck(request, request->fl_file->private_data, lsp, seqid); |
| 3226 | status = PTR_ERR(task); | 3315 | status = PTR_ERR(task); |
| 3227 | if (IS_ERR(task)) | 3316 | if (IS_ERR(task)) |
| 3228 | goto out_unlock; | 3317 | goto out; |
| 3229 | status = nfs4_wait_for_completion_rpc_task(task); | 3318 | status = nfs4_wait_for_completion_rpc_task(task); |
| 3230 | rpc_release_task(task); | 3319 | rpc_release_task(task); |
| 3231 | return status; | 3320 | out: |
| 3232 | out_unlock: | ||
| 3233 | do_vfs_lock(request->fl_file, request); | ||
| 3234 | return status; | 3321 | return status; |
| 3235 | } | 3322 | } |
| 3236 | 3323 | ||
| @@ -3262,7 +3349,7 @@ static struct nfs4_lockdata *nfs4_alloc_lockdata(struct file_lock *fl, | |||
| 3262 | if (p->arg.lock_seqid == NULL) | 3349 | if (p->arg.lock_seqid == NULL) |
| 3263 | goto out_free; | 3350 | goto out_free; |
| 3264 | p->arg.lock_stateid = &lsp->ls_stateid; | 3351 | p->arg.lock_stateid = &lsp->ls_stateid; |
| 3265 | p->arg.lock_owner.clientid = server->nfs4_state->cl_clientid; | 3352 | p->arg.lock_owner.clientid = server->nfs_client->cl_clientid; |
| 3266 | p->arg.lock_owner.id = lsp->ls_id; | 3353 | p->arg.lock_owner.id = lsp->ls_id; |
| 3267 | p->lsp = lsp; | 3354 | p->lsp = lsp; |
| 3268 | atomic_inc(&lsp->ls_count); | 3355 | atomic_inc(&lsp->ls_count); |
| @@ -3398,10 +3485,10 @@ static int nfs4_lock_reclaim(struct nfs4_state *state, struct file_lock *request | |||
| 3398 | struct nfs4_exception exception = { }; | 3485 | struct nfs4_exception exception = { }; |
| 3399 | int err; | 3486 | int err; |
| 3400 | 3487 | ||
| 3401 | /* Cache the lock if possible... */ | ||
| 3402 | if (test_bit(NFS_DELEGATED_STATE, &state->flags)) | ||
| 3403 | return 0; | ||
| 3404 | do { | 3488 | do { |
| 3489 | /* Cache the lock if possible... */ | ||
| 3490 | if (test_bit(NFS_DELEGATED_STATE, &state->flags) != 0) | ||
| 3491 | return 0; | ||
| 3405 | err = _nfs4_do_setlk(state, F_SETLK, request, 1); | 3492 | err = _nfs4_do_setlk(state, F_SETLK, request, 1); |
| 3406 | if (err != -NFS4ERR_DELAY) | 3493 | if (err != -NFS4ERR_DELAY) |
| 3407 | break; | 3494 | break; |
| @@ -3420,6 +3507,8 @@ static int nfs4_lock_expired(struct nfs4_state *state, struct file_lock *request | |||
| 3420 | if (err != 0) | 3507 | if (err != 0) |
| 3421 | return err; | 3508 | return err; |
| 3422 | do { | 3509 | do { |
| 3510 | if (test_bit(NFS_DELEGATED_STATE, &state->flags) != 0) | ||
| 3511 | return 0; | ||
| 3423 | err = _nfs4_do_setlk(state, F_SETLK, request, 0); | 3512 | err = _nfs4_do_setlk(state, F_SETLK, request, 0); |
| 3424 | if (err != -NFS4ERR_DELAY) | 3513 | if (err != -NFS4ERR_DELAY) |
| 3425 | break; | 3514 | break; |
| @@ -3430,30 +3519,43 @@ static int nfs4_lock_expired(struct nfs4_state *state, struct file_lock *request | |||
| 3430 | 3519 | ||
| 3431 | static int _nfs4_proc_setlk(struct nfs4_state *state, int cmd, struct file_lock *request) | 3520 | static int _nfs4_proc_setlk(struct nfs4_state *state, int cmd, struct file_lock *request) |
| 3432 | { | 3521 | { |
| 3433 | struct nfs4_client *clp = state->owner->so_client; | 3522 | struct nfs_client *clp = state->owner->so_client; |
| 3523 | unsigned char fl_flags = request->fl_flags; | ||
| 3434 | int status; | 3524 | int status; |
| 3435 | 3525 | ||
| 3436 | /* Is this a delegated open? */ | 3526 | /* Is this a delegated open? */ |
| 3437 | if (NFS_I(state->inode)->delegation_state != 0) { | ||
| 3438 | /* Yes: cache locks! */ | ||
| 3439 | status = do_vfs_lock(request->fl_file, request); | ||
| 3440 | /* ...but avoid races with delegation recall... */ | ||
| 3441 | if (status < 0 || test_bit(NFS_DELEGATED_STATE, &state->flags)) | ||
| 3442 | return status; | ||
| 3443 | } | ||
| 3444 | down_read(&clp->cl_sem); | ||
| 3445 | status = nfs4_set_lock_state(state, request); | 3527 | status = nfs4_set_lock_state(state, request); |
| 3446 | if (status != 0) | 3528 | if (status != 0) |
| 3447 | goto out; | 3529 | goto out; |
| 3530 | request->fl_flags |= FL_ACCESS; | ||
| 3531 | status = do_vfs_lock(request->fl_file, request); | ||
| 3532 | if (status < 0) | ||
| 3533 | goto out; | ||
| 3534 | down_read(&clp->cl_sem); | ||
| 3535 | if (test_bit(NFS_DELEGATED_STATE, &state->flags)) { | ||
| 3536 | struct nfs_inode *nfsi = NFS_I(state->inode); | ||
| 3537 | /* Yes: cache locks! */ | ||
| 3538 | down_read(&nfsi->rwsem); | ||
| 3539 | /* ...but avoid races with delegation recall... */ | ||
| 3540 | if (test_bit(NFS_DELEGATED_STATE, &state->flags)) { | ||
| 3541 | request->fl_flags = fl_flags & ~FL_SLEEP; | ||
| 3542 | status = do_vfs_lock(request->fl_file, request); | ||
| 3543 | up_read(&nfsi->rwsem); | ||
| 3544 | goto out_unlock; | ||
| 3545 | } | ||
| 3546 | up_read(&nfsi->rwsem); | ||
| 3547 | } | ||
| 3448 | status = _nfs4_do_setlk(state, cmd, request, 0); | 3548 | status = _nfs4_do_setlk(state, cmd, request, 0); |
| 3449 | if (status != 0) | 3549 | if (status != 0) |
| 3450 | goto out; | 3550 | goto out_unlock; |
| 3451 | /* Note: we always want to sleep here! */ | 3551 | /* Note: we always want to sleep here! */ |
| 3452 | request->fl_flags |= FL_SLEEP; | 3552 | request->fl_flags = fl_flags | FL_SLEEP; |
| 3453 | if (do_vfs_lock(request->fl_file, request) < 0) | 3553 | if (do_vfs_lock(request->fl_file, request) < 0) |
| 3454 | printk(KERN_WARNING "%s: VFS is out of sync with lock manager!\n", __FUNCTION__); | 3554 | printk(KERN_WARNING "%s: VFS is out of sync with lock manager!\n", __FUNCTION__); |
| 3455 | out: | 3555 | out_unlock: |
| 3456 | up_read(&clp->cl_sem); | 3556 | up_read(&clp->cl_sem); |
| 3557 | out: | ||
| 3558 | request->fl_flags = fl_flags; | ||
| 3457 | return status; | 3559 | return status; |
| 3458 | } | 3560 | } |
| 3459 | 3561 | ||
| @@ -3570,6 +3672,36 @@ ssize_t nfs4_listxattr(struct dentry *dentry, char *buf, size_t buflen) | |||
| 3570 | return len; | 3672 | return len; |
| 3571 | } | 3673 | } |
| 3572 | 3674 | ||
| 3675 | int nfs4_proc_fs_locations(struct inode *dir, struct dentry *dentry, | ||
| 3676 | struct nfs4_fs_locations *fs_locations, struct page *page) | ||
| 3677 | { | ||
| 3678 | struct nfs_server *server = NFS_SERVER(dir); | ||
| 3679 | u32 bitmask[2] = { | ||
| 3680 | [0] = FATTR4_WORD0_FSID | FATTR4_WORD0_FS_LOCATIONS, | ||
| 3681 | [1] = FATTR4_WORD1_MOUNTED_ON_FILEID, | ||
| 3682 | }; | ||
| 3683 | struct nfs4_fs_locations_arg args = { | ||
| 3684 | .dir_fh = NFS_FH(dir), | ||
| 3685 | .name = &dentry->d_name, | ||
| 3686 | .page = page, | ||
| 3687 | .bitmask = bitmask, | ||
| 3688 | }; | ||
| 3689 | struct rpc_message msg = { | ||
| 3690 | .rpc_proc = &nfs4_procedures[NFSPROC4_CLNT_FS_LOCATIONS], | ||
| 3691 | .rpc_argp = &args, | ||
| 3692 | .rpc_resp = fs_locations, | ||
| 3693 | }; | ||
| 3694 | int status; | ||
| 3695 | |||
| 3696 | dprintk("%s: start\n", __FUNCTION__); | ||
| 3697 | fs_locations->fattr.valid = 0; | ||
| 3698 | fs_locations->server = server; | ||
| 3699 | fs_locations->nlocations = 0; | ||
| 3700 | status = rpc_call_sync(server->client, &msg, 0); | ||
| 3701 | dprintk("%s: returned status = %d\n", __FUNCTION__, status); | ||
| 3702 | return status; | ||
| 3703 | } | ||
| 3704 | |||
| 3573 | struct nfs4_state_recovery_ops nfs4_reboot_recovery_ops = { | 3705 | struct nfs4_state_recovery_ops nfs4_reboot_recovery_ops = { |
| 3574 | .recover_open = nfs4_open_reclaim, | 3706 | .recover_open = nfs4_open_reclaim, |
| 3575 | .recover_lock = nfs4_lock_reclaim, | 3707 | .recover_lock = nfs4_lock_reclaim, |
| @@ -3589,7 +3721,7 @@ static struct inode_operations nfs4_file_inode_operations = { | |||
| 3589 | .listxattr = nfs4_listxattr, | 3721 | .listxattr = nfs4_listxattr, |
| 3590 | }; | 3722 | }; |
| 3591 | 3723 | ||
| 3592 | struct nfs_rpc_ops nfs_v4_clientops = { | 3724 | const struct nfs_rpc_ops nfs_v4_clientops = { |
| 3593 | .version = 4, /* protocol version */ | 3725 | .version = 4, /* protocol version */ |
| 3594 | .dentry_ops = &nfs4_dentry_operations, | 3726 | .dentry_ops = &nfs4_dentry_operations, |
| 3595 | .dir_inode_ops = &nfs4_dir_inode_operations, | 3727 | .dir_inode_ops = &nfs4_dir_inode_operations, |
| @@ -3597,6 +3729,7 @@ struct nfs_rpc_ops nfs_v4_clientops = { | |||
| 3597 | .getroot = nfs4_proc_get_root, | 3729 | .getroot = nfs4_proc_get_root, |
| 3598 | .getattr = nfs4_proc_getattr, | 3730 | .getattr = nfs4_proc_getattr, |
| 3599 | .setattr = nfs4_proc_setattr, | 3731 | .setattr = nfs4_proc_setattr, |
| 3732 | .lookupfh = nfs4_proc_lookupfh, | ||
| 3600 | .lookup = nfs4_proc_lookup, | 3733 | .lookup = nfs4_proc_lookup, |
| 3601 | .access = nfs4_proc_access, | 3734 | .access = nfs4_proc_access, |
| 3602 | .readlink = nfs4_proc_readlink, | 3735 | .readlink = nfs4_proc_readlink, |
| @@ -3617,6 +3750,7 @@ struct nfs_rpc_ops nfs_v4_clientops = { | |||
| 3617 | .statfs = nfs4_proc_statfs, | 3750 | .statfs = nfs4_proc_statfs, |
| 3618 | .fsinfo = nfs4_proc_fsinfo, | 3751 | .fsinfo = nfs4_proc_fsinfo, |
| 3619 | .pathconf = nfs4_proc_pathconf, | 3752 | .pathconf = nfs4_proc_pathconf, |
| 3753 | .set_capabilities = nfs4_server_capabilities, | ||
| 3620 | .decode_dirent = nfs4_decode_dirent, | 3754 | .decode_dirent = nfs4_decode_dirent, |
| 3621 | .read_setup = nfs4_proc_read_setup, | 3755 | .read_setup = nfs4_proc_read_setup, |
| 3622 | .read_done = nfs4_read_done, | 3756 | .read_done = nfs4_read_done, |
