diff options
Diffstat (limited to 'fs/nfs/nfs4proc.c')
-rw-r--r-- | fs/nfs/nfs4proc.c | 111 |
1 files changed, 102 insertions, 9 deletions
diff --git a/fs/nfs/nfs4proc.c b/fs/nfs/nfs4proc.c index d86c0db7b1e8..b4916b092194 100644 --- a/fs/nfs/nfs4proc.c +++ b/fs/nfs/nfs4proc.c | |||
@@ -65,8 +65,6 @@ 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 nfs4_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 | { |
@@ -185,15 +202,15 @@ static void renew_lease(const struct nfs_server *server, unsigned long 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 { |
@@ -1331,7 +1348,7 @@ static int _nfs4_server_capabilities(struct nfs_server *server, struct nfs_fh *f | |||
1331 | return status; | 1348 | return status; |
1332 | } | 1349 | } |
1333 | 1350 | ||
1334 | static int nfs4_server_capabilities(struct nfs_server *server, struct nfs_fh *fhandle) | 1351 | int nfs4_server_capabilities(struct nfs_server *server, struct nfs_fh *fhandle) |
1335 | { | 1352 | { |
1336 | struct nfs4_exception exception = { }; | 1353 | struct nfs4_exception exception = { }; |
1337 | int err; | 1354 | int err; |
@@ -1443,6 +1460,50 @@ out: | |||
1443 | return nfs4_map_errors(status); | 1460 | return nfs4_map_errors(status); |
1444 | } | 1461 | } |
1445 | 1462 | ||
1463 | /* | ||
1464 | * Get locations and (maybe) other attributes of a referral. | ||
1465 | * Note that we'll actually follow the referral later when | ||
1466 | * we detect fsid mismatch in inode revalidation | ||
1467 | */ | ||
1468 | static int nfs4_get_referral(struct inode *dir, struct qstr *name, struct nfs_fattr *fattr, struct nfs_fh *fhandle) | ||
1469 | { | ||
1470 | int status = -ENOMEM; | ||
1471 | struct page *page = NULL; | ||
1472 | struct nfs4_fs_locations *locations = NULL; | ||
1473 | struct dentry dentry = {}; | ||
1474 | |||
1475 | page = alloc_page(GFP_KERNEL); | ||
1476 | if (page == NULL) | ||
1477 | goto out; | ||
1478 | locations = kmalloc(sizeof(struct nfs4_fs_locations), GFP_KERNEL); | ||
1479 | if (locations == NULL) | ||
1480 | goto out; | ||
1481 | |||
1482 | dentry.d_name.name = name->name; | ||
1483 | dentry.d_name.len = name->len; | ||
1484 | status = nfs4_proc_fs_locations(dir, &dentry, locations, page); | ||
1485 | if (status != 0) | ||
1486 | goto out; | ||
1487 | /* Make sure server returned a different fsid for the referral */ | ||
1488 | if (nfs_fsid_equal(&NFS_SERVER(dir)->fsid, &locations->fattr.fsid)) { | ||
1489 | dprintk("%s: server did not return a different fsid for a referral at %s\n", __FUNCTION__, name->name); | ||
1490 | status = -EIO; | ||
1491 | goto out; | ||
1492 | } | ||
1493 | |||
1494 | memcpy(fattr, &locations->fattr, sizeof(struct nfs_fattr)); | ||
1495 | fattr->valid |= NFS_ATTR_FATTR_V4_REFERRAL; | ||
1496 | if (!fattr->mode) | ||
1497 | fattr->mode = S_IFDIR; | ||
1498 | memset(fhandle, 0, sizeof(struct nfs_fh)); | ||
1499 | out: | ||
1500 | if (page) | ||
1501 | __free_page(page); | ||
1502 | if (locations) | ||
1503 | kfree(locations); | ||
1504 | return status; | ||
1505 | } | ||
1506 | |||
1446 | static int _nfs4_proc_getattr(struct nfs_server *server, struct nfs_fh *fhandle, struct nfs_fattr *fattr) | 1507 | static int _nfs4_proc_getattr(struct nfs_server *server, struct nfs_fh *fhandle, struct nfs_fattr *fattr) |
1447 | { | 1508 | { |
1448 | struct nfs4_getattr_arg args = { | 1509 | struct nfs4_getattr_arg args = { |
@@ -1547,6 +1608,8 @@ static int _nfs4_proc_lookup(struct inode *dir, struct qstr *name, | |||
1547 | 1608 | ||
1548 | dprintk("NFS call lookup %s\n", name->name); | 1609 | dprintk("NFS call lookup %s\n", name->name); |
1549 | status = rpc_call_sync(NFS_CLIENT(dir), &msg, 0); | 1610 | status = rpc_call_sync(NFS_CLIENT(dir), &msg, 0); |
1611 | if (status == -NFS4ERR_MOVED) | ||
1612 | status = nfs4_get_referral(dir, name, fattr, fhandle); | ||
1550 | dprintk("NFS reply lookup: %d\n", status); | 1613 | dprintk("NFS reply lookup: %d\n", status); |
1551 | return status; | 1614 | return status; |
1552 | } | 1615 | } |
@@ -2008,7 +2071,7 @@ static int _nfs4_proc_link(struct inode *inode, struct inode *dir, struct qstr * | |||
2008 | if (!status) { | 2071 | if (!status) { |
2009 | update_changeattr(dir, &res.cinfo); | 2072 | update_changeattr(dir, &res.cinfo); |
2010 | nfs_post_op_update_inode(dir, res.dir_attr); | 2073 | nfs_post_op_update_inode(dir, res.dir_attr); |
2011 | nfs_refresh_inode(inode, res.fattr); | 2074 | nfs_post_op_update_inode(inode, res.fattr); |
2012 | } | 2075 | } |
2013 | 2076 | ||
2014 | return status; | 2077 | return status; |
@@ -3570,6 +3633,36 @@ ssize_t nfs4_listxattr(struct dentry *dentry, char *buf, size_t buflen) | |||
3570 | return len; | 3633 | return len; |
3571 | } | 3634 | } |
3572 | 3635 | ||
3636 | int nfs4_proc_fs_locations(struct inode *dir, struct dentry *dentry, | ||
3637 | struct nfs4_fs_locations *fs_locations, struct page *page) | ||
3638 | { | ||
3639 | struct nfs_server *server = NFS_SERVER(dir); | ||
3640 | u32 bitmask[2] = { | ||
3641 | [0] = FATTR4_WORD0_FSID | FATTR4_WORD0_FS_LOCATIONS, | ||
3642 | [1] = FATTR4_WORD1_MOUNTED_ON_FILEID, | ||
3643 | }; | ||
3644 | struct nfs4_fs_locations_arg args = { | ||
3645 | .dir_fh = NFS_FH(dir), | ||
3646 | .name = &dentry->d_name, | ||
3647 | .page = page, | ||
3648 | .bitmask = bitmask, | ||
3649 | }; | ||
3650 | struct rpc_message msg = { | ||
3651 | .rpc_proc = &nfs4_procedures[NFSPROC4_CLNT_FS_LOCATIONS], | ||
3652 | .rpc_argp = &args, | ||
3653 | .rpc_resp = fs_locations, | ||
3654 | }; | ||
3655 | int status; | ||
3656 | |||
3657 | dprintk("%s: start\n", __FUNCTION__); | ||
3658 | fs_locations->fattr.valid = 0; | ||
3659 | fs_locations->server = server; | ||
3660 | fs_locations->nlocations = 0; | ||
3661 | status = rpc_call_sync(server->client, &msg, 0); | ||
3662 | dprintk("%s: returned status = %d\n", __FUNCTION__, status); | ||
3663 | return status; | ||
3664 | } | ||
3665 | |||
3573 | struct nfs4_state_recovery_ops nfs4_reboot_recovery_ops = { | 3666 | struct nfs4_state_recovery_ops nfs4_reboot_recovery_ops = { |
3574 | .recover_open = nfs4_open_reclaim, | 3667 | .recover_open = nfs4_open_reclaim, |
3575 | .recover_lock = nfs4_lock_reclaim, | 3668 | .recover_lock = nfs4_lock_reclaim, |