aboutsummaryrefslogtreecommitdiffstats
path: root/fs/btrfs/inode.c
diff options
context:
space:
mode:
authorDavid Woodhouse <David.Woodhouse@intel.com>2008-08-06 14:42:33 -0400
committerChris Mason <chris.mason@oracle.com>2008-09-25 11:04:06 -0400
commitcbdf5a2442330102c08f5a2ad3058e29e90a43a9 (patch)
treeb41e0da448591f22e00afdda4f6e68b85baad030 /fs/btrfs/inode.c
parentbe6e8dc0ba84029997075a1ec77b4ddb863cbe15 (diff)
Btrfs: Implement our own copy of the nfsd readdir hack, for older kernels
Date: Wed, 6 Aug 2008 19:42:33 +0100 Signed-off-by: David Woodhouse <David.Woodhouse@intel.com> Signed-off-by: Chris Mason <chris.mason@oracle.com>
Diffstat (limited to 'fs/btrfs/inode.c')
-rw-r--r--fs/btrfs/inode.c104
1 files changed, 102 insertions, 2 deletions
diff --git a/fs/btrfs/inode.c b/fs/btrfs/inode.c
index 266ca5514b33..0da1ae4ee407 100644
--- a/fs/btrfs/inode.c
+++ b/fs/btrfs/inode.c
@@ -1915,7 +1915,8 @@ static unsigned char btrfs_filetype_table[] = {
1915 DT_UNKNOWN, DT_REG, DT_DIR, DT_CHR, DT_BLK, DT_FIFO, DT_SOCK, DT_LNK 1915 DT_UNKNOWN, DT_REG, DT_DIR, DT_CHR, DT_BLK, DT_FIFO, DT_SOCK, DT_LNK
1916}; 1916};
1917 1917
1918static int btrfs_readdir(struct file *filp, void *dirent, filldir_t filldir) 1918static int btrfs_real_readdir(struct file *filp, void *dirent,
1919 filldir_t filldir)
1919{ 1920{
1920 struct inode *inode = filp->f_dentry->d_inode; 1921 struct inode *inode = filp->f_dentry->d_inode;
1921 struct btrfs_root *root = BTRFS_I(inode)->root; 1922 struct btrfs_root *root = BTRFS_I(inode)->root;
@@ -2064,6 +2065,101 @@ err:
2064 return ret; 2065 return ret;
2065} 2066}
2066 2067
2068/* Kernels earlier than 2.6.28 still have the NFS deadlock where nfsd
2069 will call the file system's ->lookup() method from within its
2070 filldir callback, which in turn was called from the file system's
2071 ->readdir() method. And will deadlock for many file systems. */
2072#if LINUX_VERSION_CODE < KERNEL_VERSION(2,6,28)
2073
2074struct nfshack_dirent {
2075 u64 ino;
2076 loff_t offset;
2077 int namlen;
2078 unsigned int d_type;
2079 char name[];
2080};
2081
2082struct nfshack_readdir {
2083 char *dirent;
2084 size_t used;
2085};
2086
2087
2088
2089static int btrfs_nfshack_filldir(void *__buf, const char *name, int namlen,
2090 loff_t offset, u64 ino, unsigned int d_type)
2091{
2092 struct nfshack_readdir *buf = __buf;
2093 struct nfshack_dirent *de = (void *)(buf->dirent + buf->used);
2094 unsigned int reclen;
2095
2096 reclen = ALIGN(sizeof(struct nfshack_dirent) + namlen, sizeof(u64));
2097 if (buf->used + reclen > PAGE_SIZE)
2098 return -EINVAL;
2099
2100 de->namlen = namlen;
2101 de->offset = offset;
2102 de->ino = ino;
2103 de->d_type = d_type;
2104 memcpy(de->name, name, namlen);
2105 buf->used += reclen;
2106
2107 return 0;
2108}
2109
2110static int btrfs_nfshack_readdir(struct file *file, void *dirent,
2111 filldir_t filldir)
2112{
2113 struct nfshack_readdir buf;
2114 struct nfshack_dirent *de;
2115 int err;
2116 int size;
2117 loff_t offset;
2118
2119 buf.dirent = (void *)__get_free_page(GFP_KERNEL);
2120 if (!buf.dirent)
2121 return -ENOMEM;
2122
2123 offset = file->f_pos;
2124
2125 while (1) {
2126 unsigned int reclen;
2127
2128 buf.used = 0;
2129
2130 err = btrfs_real_readdir(file, &buf, btrfs_nfshack_filldir);
2131 if (err)
2132 break;
2133
2134 size = buf.used;
2135
2136 if (!size)
2137 break;
2138
2139 de = (struct nfshack_dirent *)buf.dirent;
2140 while (size > 0) {
2141 offset = de->offset;
2142
2143 if (filldir(dirent, de->name, de->namlen, de->offset,
2144 de->ino, de->d_type))
2145 goto done;
2146 offset = file->f_pos;
2147
2148 reclen = ALIGN(sizeof(*de) + de->namlen,
2149 sizeof(u64));
2150 size -= reclen;
2151 de = (struct nfshack_dirent *)((char *)de + reclen);
2152 }
2153 }
2154
2155 done:
2156 free_page((unsigned long)buf.dirent);
2157 file->f_pos = offset;
2158
2159 return err;
2160}
2161#endif
2162
2067int btrfs_write_inode(struct inode *inode, int wait) 2163int btrfs_write_inode(struct inode *inode, int wait)
2068{ 2164{
2069 struct btrfs_root *root = BTRFS_I(inode)->root; 2165 struct btrfs_root *root = BTRFS_I(inode)->root;
@@ -3623,7 +3719,11 @@ static struct inode_operations btrfs_dir_ro_inode_operations = {
3623static struct file_operations btrfs_dir_file_operations = { 3719static struct file_operations btrfs_dir_file_operations = {
3624 .llseek = generic_file_llseek, 3720 .llseek = generic_file_llseek,
3625 .read = generic_read_dir, 3721 .read = generic_read_dir,
3626 .readdir = btrfs_readdir, 3722#if LINUX_VERSION_CODE < KERNEL_VERSION(2,6,28)
3723 .readdir = btrfs_nfshack_readdir,
3724#else /* NFSd readdir/lookup deadlock is fixed */
3725 .readdir = btrfs_real_readdir,
3726#endif
3627 .unlocked_ioctl = btrfs_ioctl, 3727 .unlocked_ioctl = btrfs_ioctl,
3628#ifdef CONFIG_COMPAT 3728#ifdef CONFIG_COMPAT
3629 .compat_ioctl = btrfs_ioctl, 3729 .compat_ioctl = btrfs_ioctl,