aboutsummaryrefslogtreecommitdiffstats
path: root/fs/nfsd/vfs.c
diff options
context:
space:
mode:
Diffstat (limited to 'fs/nfsd/vfs.c')
-rw-r--r--fs/nfsd/vfs.c108
1 files changed, 93 insertions, 15 deletions
diff --git a/fs/nfsd/vfs.c b/fs/nfsd/vfs.c
index 14eda20cc291..93b22f661d9d 100644
--- a/fs/nfsd/vfs.c
+++ b/fs/nfsd/vfs.c
@@ -1813,27 +1813,105 @@ out:
1813 return err; 1813 return err;
1814} 1814}
1815 1815
1816static int nfsd_do_readdir(struct file *file, filldir_t func, 1816/*
1817 struct readdir_cd *cdp, loff_t *offsetp) 1817 * We do this buffering because we must not call back into the file
1818 * system's ->lookup() method from the filldir callback. That may well
1819 * deadlock a number of file systems.
1820 *
1821 * This is based heavily on the implementation of same in XFS.
1822 */
1823struct buffered_dirent {
1824 u64 ino;
1825 loff_t offset;
1826 int namlen;
1827 unsigned int d_type;
1828 char name[];
1829};
1830
1831struct readdir_data {
1832 char *dirent;
1833 size_t used;
1834};
1835
1836static int nfsd_buffered_filldir(void *__buf, const char *name, int namlen,
1837 loff_t offset, u64 ino, unsigned int d_type)
1838{
1839 struct readdir_data *buf = __buf;
1840 struct buffered_dirent *de = (void *)(buf->dirent + buf->used);
1841 unsigned int reclen;
1842
1843 reclen = ALIGN(sizeof(struct buffered_dirent) + namlen, sizeof(u64));
1844 if (buf->used + reclen > PAGE_SIZE)
1845 return -EINVAL;
1846
1847 de->namlen = namlen;
1848 de->offset = offset;
1849 de->ino = ino;
1850 de->d_type = d_type;
1851 memcpy(de->name, name, namlen);
1852 buf->used += reclen;
1853
1854 return 0;
1855}
1856
1857static int nfsd_buffered_readdir(struct file *file, filldir_t func,
1858 struct readdir_cd *cdp, loff_t *offsetp)
1818{ 1859{
1860 struct readdir_data buf;
1861 struct buffered_dirent *de;
1819 int host_err; 1862 int host_err;
1863 int size;
1864 loff_t offset;
1820 1865
1821 /* 1866 buf.dirent = (void *)__get_free_page(GFP_KERNEL);
1822 * Read the directory entries. This silly loop is necessary because 1867 if (!buf.dirent)
1823 * readdir() is not guaranteed to fill up the entire buffer, but 1868 return -ENOMEM;
1824 * may choose to do less. 1869
1825 */ 1870 offset = *offsetp;
1826 do { 1871 cdp->err = nfserr_eof; /* will be cleared on successful read */
1827 cdp->err = nfserr_eof; /* will be cleared on successful read */
1828 host_err = vfs_readdir(file, func, cdp);
1829 } while (host_err >=0 && cdp->err == nfs_ok);
1830 1872
1831 *offsetp = vfs_llseek(file, 0, 1); 1873 while (1) {
1874 unsigned int reclen;
1875
1876 buf.used = 0;
1877
1878 host_err = vfs_readdir(file, nfsd_buffered_filldir, &buf);
1879 if (host_err)
1880 break;
1881
1882 size = buf.used;
1883
1884 if (!size)
1885 break;
1886
1887
1888 de = (struct buffered_dirent *)buf.dirent;
1889 while (size > 0) {
1890 offset = de->offset;
1891
1892 if (func(cdp, de->name, de->namlen, de->offset,
1893 de->ino, de->d_type))
1894 goto done;
1895
1896 if (cdp->err != nfs_ok)
1897 goto done;
1898
1899 reclen = ALIGN(sizeof(*de) + de->namlen,
1900 sizeof(u64));
1901 size -= reclen;
1902 de = (struct buffered_dirent *)((char *)de + reclen);
1903 }
1904 offset = vfs_llseek(file, 0, 1);
1905 }
1906
1907 done:
1908 free_page((unsigned long)(buf.dirent));
1832 1909
1833 if (host_err) 1910 if (host_err)
1834 return nfserrno(host_err); 1911 return nfserrno(host_err);
1835 else 1912
1836 return cdp->err; 1913 *offsetp = offset;
1914 return cdp->err;
1837} 1915}
1838 1916
1839/* 1917/*
@@ -1858,7 +1936,7 @@ nfsd_readdir(struct svc_rqst *rqstp, struct svc_fh *fhp, loff_t *offsetp,
1858 goto out_close; 1936 goto out_close;
1859 } 1937 }
1860 1938
1861 err = nfsd_do_readdir(file, func, cdp, offsetp); 1939 err = nfsd_buffered_readdir(file, func, cdp, offsetp);
1862 1940
1863 if (err == nfserr_eof || err == nfserr_toosmall) 1941 if (err == nfserr_eof || err == nfserr_toosmall)
1864 err = nfs_ok; /* can still be found in ->err */ 1942 err = nfs_ok; /* can still be found in ->err */