Linux kernel mirror (for testing) git.kernel.org/pub/scm/linux/kernel/git/torvalds/linux.git
kernel os linux

NFSD: Cleanup for nfsd4_path()

The current code is sort of hackish in that it assumes a referral is always
matched to an export. When we add support for junctions that may not be the
case.
We can replace nfsd4_path() with a function that encodes the components
directly from the dentries. Since nfsd4_path is currently the only user of
the 'ex_pathname' field in struct svc_export, this has the added benefit
of allowing us to get rid of that.

Signed-off-by: Trond Myklebust <Trond.Myklebust@netapp.com>
Reviewed-by: Jeff Layton <jlayton@redhat.com>
Signed-off-by: J. Bruce Fields <bfields@redhat.com>

authored by

Trond Myklebust and committed by
J. Bruce Fields
ed748aac ee626a77

+82 -31
+2 -2
fs/nfsd/export.c
··· 1009 1009 return exp; 1010 1010 } 1011 1011 1012 - static struct svc_export *find_fsidzero_export(struct svc_rqst *rqstp) 1012 + struct svc_export *rqst_find_fsidzero_export(struct svc_rqst *rqstp) 1013 1013 { 1014 1014 u32 fsidv[2]; 1015 1015 ··· 1029 1029 struct svc_export *exp; 1030 1030 __be32 rv; 1031 1031 1032 - exp = find_fsidzero_export(rqstp); 1032 + exp = rqst_find_fsidzero_export(rqstp); 1033 1033 if (IS_ERR(exp)) 1034 1034 return nfserrno(PTR_ERR(exp)); 1035 1035 rv = fh_compose(fhp, exp, exp->ex_path.dentry, NULL);
+79 -29
fs/nfsd/nfs4xdr.c
··· 1696 1696 } 1697 1697 1698 1698 /* 1699 - * Return the path to an export point in the pseudo filesystem namespace 1700 - * Returned string is safe to use as long as the caller holds a reference 1701 - * to @exp. 1699 + * Encode a path in RFC3530 'pathname4' format 1702 1700 */ 1703 - static char *nfsd4_path(struct svc_rqst *rqstp, struct svc_export *exp, __be32 *stat) 1701 + static __be32 nfsd4_encode_path(const struct path *root, 1702 + const struct path *path, __be32 **pp, int *buflen) 1704 1703 { 1705 - struct svc_fh tmp_fh; 1706 - char *path = NULL, *rootpath; 1707 - size_t rootlen; 1704 + struct path cur = { 1705 + .mnt = path->mnt, 1706 + .dentry = path->dentry, 1707 + }; 1708 + __be32 *p = *pp; 1709 + struct dentry **components = NULL; 1710 + unsigned int ncomponents = 0; 1711 + __be32 err = nfserr_jukebox; 1708 1712 1709 - fh_init(&tmp_fh, NFS4_FHSIZE); 1710 - *stat = exp_pseudoroot(rqstp, &tmp_fh); 1711 - if (*stat) 1712 - return NULL; 1713 - rootpath = tmp_fh.fh_export->ex_pathname; 1713 + dprintk("nfsd4_encode_components("); 1714 1714 1715 - path = exp->ex_pathname; 1716 - 1717 - rootlen = strlen(rootpath); 1718 - if (strncmp(path, rootpath, rootlen)) { 1719 - dprintk("nfsd: fs_locations failed;" 1720 - "%s is not contained in %s\n", path, rootpath); 1721 - *stat = nfserr_notsupp; 1722 - path = NULL; 1723 - goto out; 1715 + path_get(&cur); 1716 + /* First walk the path up to the nfsd root, and store the 1717 + * dentries/path components in an array. 1718 + */ 1719 + for (;;) { 1720 + if (cur.dentry == root->dentry && cur.mnt == root->mnt) 1721 + break; 1722 + if (cur.dentry == cur.mnt->mnt_root) { 1723 + if (follow_up(&cur)) 1724 + continue; 1725 + goto out_free; 1726 + } 1727 + if ((ncomponents & 15) == 0) { 1728 + struct dentry **new; 1729 + new = krealloc(components, 1730 + sizeof(*new) * (ncomponents + 16), 1731 + GFP_KERNEL); 1732 + if (!new) 1733 + goto out_free; 1734 + components = new; 1735 + } 1736 + components[ncomponents++] = cur.dentry; 1737 + cur.dentry = dget_parent(cur.dentry); 1724 1738 } 1725 - path += rootlen; 1726 - out: 1727 - fh_put(&tmp_fh); 1728 - return path; 1739 + 1740 + *buflen -= 4; 1741 + if (*buflen < 0) 1742 + goto out_free; 1743 + WRITE32(ncomponents); 1744 + 1745 + while (ncomponents) { 1746 + struct dentry *dentry = components[ncomponents - 1]; 1747 + unsigned int len = dentry->d_name.len; 1748 + 1749 + *buflen -= 4 + (XDR_QUADLEN(len) << 2); 1750 + if (*buflen < 0) 1751 + goto out_free; 1752 + WRITE32(len); 1753 + WRITEMEM(dentry->d_name.name, len); 1754 + dprintk("/%s", dentry->d_name.name); 1755 + dput(dentry); 1756 + ncomponents--; 1757 + } 1758 + 1759 + *pp = p; 1760 + err = 0; 1761 + out_free: 1762 + dprintk(")\n"); 1763 + while (ncomponents) 1764 + dput(components[--ncomponents]); 1765 + kfree(components); 1766 + path_put(&cur); 1767 + return err; 1768 + } 1769 + 1770 + static __be32 nfsd4_encode_fsloc_fsroot(struct svc_rqst *rqstp, 1771 + const struct path *path, __be32 **pp, int *buflen) 1772 + { 1773 + struct svc_export *exp_ps; 1774 + __be32 res; 1775 + 1776 + exp_ps = rqst_find_fsidzero_export(rqstp); 1777 + if (IS_ERR(exp_ps)) 1778 + return nfserrno(PTR_ERR(exp_ps)); 1779 + res = nfsd4_encode_path(&exp_ps->ex_path, path, pp, buflen); 1780 + exp_put(exp_ps); 1781 + return res; 1729 1782 } 1730 1783 1731 1784 /* ··· 1792 1739 int i; 1793 1740 __be32 *p = *pp; 1794 1741 struct nfsd4_fs_locations *fslocs = &exp->ex_fslocs; 1795 - char *root = nfsd4_path(rqstp, exp, &status); 1796 1742 1797 - if (status) 1798 - return status; 1799 - status = nfsd4_encode_components('/', root, &p, buflen); 1743 + status = nfsd4_encode_fsloc_fsroot(rqstp, &exp->ex_path, &p, buflen); 1800 1744 if (status) 1801 1745 return status; 1802 1746 if ((*buflen -= 4) < 0)
+1
include/linux/nfsd/export.h
··· 137 137 struct path *); 138 138 struct svc_export * rqst_exp_parent(struct svc_rqst *, 139 139 struct path *); 140 + struct svc_export * rqst_find_fsidzero_export(struct svc_rqst *); 140 141 int exp_rootfh(struct auth_domain *, 141 142 char *path, struct knfsd_fh *, int maxsize); 142 143 __be32 exp_pseudoroot(struct svc_rqst *, struct svc_fh *);