aboutsummaryrefslogtreecommitdiffstats
path: root/fs/nfs/nfs4proc.c
diff options
context:
space:
mode:
Diffstat (limited to 'fs/nfs/nfs4proc.c')
-rw-r--r--fs/nfs/nfs4proc.c46
1 files changed, 46 insertions, 0 deletions
diff --git a/fs/nfs/nfs4proc.c b/fs/nfs/nfs4proc.c
index 90ee21a07b3e..3300e35d74ad 100644
--- a/fs/nfs/nfs4proc.c
+++ b/fs/nfs/nfs4proc.c
@@ -1462,6 +1462,50 @@ out:
1462 return nfs4_map_errors(status); 1462 return nfs4_map_errors(status);
1463} 1463}
1464 1464
1465/*
1466 * Get locations and (maybe) other attributes of a referral.
1467 * Note that we'll actually follow the referral later when
1468 * we detect fsid mismatch in inode revalidation
1469 */
1470static int nfs4_get_referral(struct inode *dir, struct qstr *name, struct nfs_fattr *fattr, struct nfs_fh *fhandle)
1471{
1472 int status = -ENOMEM;
1473 struct page *page = NULL;
1474 struct nfs4_fs_locations *locations = NULL;
1475 struct dentry dentry = {};
1476
1477 page = alloc_page(GFP_KERNEL);
1478 if (page == NULL)
1479 goto out;
1480 locations = kmalloc(sizeof(struct nfs4_fs_locations), GFP_KERNEL);
1481 if (locations == NULL)
1482 goto out;
1483
1484 dentry.d_name.name = name->name;
1485 dentry.d_name.len = name->len;
1486 status = nfs4_proc_fs_locations(dir, &dentry, locations, page);
1487 if (status != 0)
1488 goto out;
1489 /* Make sure server returned a different fsid for the referral */
1490 if (nfs_fsid_equal(&NFS_SERVER(dir)->fsid, &locations->fattr.fsid)) {
1491 dprintk("%s: server did not return a different fsid for a referral at %s\n", __FUNCTION__, name->name);
1492 status = -EIO;
1493 goto out;
1494 }
1495
1496 memcpy(fattr, &locations->fattr, sizeof(struct nfs_fattr));
1497 fattr->valid |= NFS_ATTR_FATTR_V4_REFERRAL;
1498 if (!fattr->mode)
1499 fattr->mode = S_IFDIR;
1500 memset(fhandle, 0, sizeof(struct nfs_fh));
1501out:
1502 if (page)
1503 __free_page(page);
1504 if (locations)
1505 kfree(locations);
1506 return status;
1507}
1508
1465static int _nfs4_proc_getattr(struct nfs_server *server, struct nfs_fh *fhandle, struct nfs_fattr *fattr) 1509static int _nfs4_proc_getattr(struct nfs_server *server, struct nfs_fh *fhandle, struct nfs_fattr *fattr)
1466{ 1510{
1467 struct nfs4_getattr_arg args = { 1511 struct nfs4_getattr_arg args = {
@@ -1566,6 +1610,8 @@ static int _nfs4_proc_lookup(struct inode *dir, struct qstr *name,
1566 1610
1567 dprintk("NFS call lookup %s\n", name->name); 1611 dprintk("NFS call lookup %s\n", name->name);
1568 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);
1569 dprintk("NFS reply lookup: %d\n", status); 1615 dprintk("NFS reply lookup: %d\n", status);
1570 return status; 1616 return status;
1571} 1617}