diff options
| -rw-r--r-- | fs/btrfs/file.c | 9 | ||||
| -rw-r--r-- | fs/btrfs/inode.c | 18 | ||||
| -rw-r--r-- | fs/btrfs/ioctl.c | 14 |
3 files changed, 30 insertions, 11 deletions
diff --git a/fs/btrfs/file.c b/fs/btrfs/file.c index 3c3abff731a7..a381cd22f518 100644 --- a/fs/btrfs/file.c +++ b/fs/btrfs/file.c | |||
| @@ -1817,6 +1817,11 @@ static loff_t btrfs_file_llseek(struct file *file, loff_t offset, int origin) | |||
| 1817 | goto out; | 1817 | goto out; |
| 1818 | case SEEK_DATA: | 1818 | case SEEK_DATA: |
| 1819 | case SEEK_HOLE: | 1819 | case SEEK_HOLE: |
| 1820 | if (offset >= i_size_read(inode)) { | ||
| 1821 | mutex_unlock(&inode->i_mutex); | ||
| 1822 | return -ENXIO; | ||
| 1823 | } | ||
| 1824 | |||
| 1820 | ret = find_desired_extent(inode, &offset, origin); | 1825 | ret = find_desired_extent(inode, &offset, origin); |
| 1821 | if (ret) { | 1826 | if (ret) { |
| 1822 | mutex_unlock(&inode->i_mutex); | 1827 | mutex_unlock(&inode->i_mutex); |
| @@ -1825,11 +1830,11 @@ static loff_t btrfs_file_llseek(struct file *file, loff_t offset, int origin) | |||
| 1825 | } | 1830 | } |
| 1826 | 1831 | ||
| 1827 | if (offset < 0 && !(file->f_mode & FMODE_UNSIGNED_OFFSET)) { | 1832 | if (offset < 0 && !(file->f_mode & FMODE_UNSIGNED_OFFSET)) { |
| 1828 | ret = -EINVAL; | 1833 | offset = -EINVAL; |
| 1829 | goto out; | 1834 | goto out; |
| 1830 | } | 1835 | } |
| 1831 | if (offset > inode->i_sb->s_maxbytes) { | 1836 | if (offset > inode->i_sb->s_maxbytes) { |
| 1832 | ret = -EINVAL; | 1837 | offset = -EINVAL; |
| 1833 | goto out; | 1838 | goto out; |
| 1834 | } | 1839 | } |
| 1835 | 1840 | ||
diff --git a/fs/btrfs/inode.c b/fs/btrfs/inode.c index 4d14de6d121b..b2d004ad66a0 100644 --- a/fs/btrfs/inode.c +++ b/fs/btrfs/inode.c | |||
| @@ -4018,7 +4018,8 @@ struct inode *btrfs_lookup_dentry(struct inode *dir, struct dentry *dentry) | |||
| 4018 | memcpy(&location, dentry->d_fsdata, sizeof(struct btrfs_key)); | 4018 | memcpy(&location, dentry->d_fsdata, sizeof(struct btrfs_key)); |
| 4019 | kfree(dentry->d_fsdata); | 4019 | kfree(dentry->d_fsdata); |
| 4020 | dentry->d_fsdata = NULL; | 4020 | dentry->d_fsdata = NULL; |
| 4021 | d_clear_need_lookup(dentry); | 4021 | /* This thing is hashed, drop it for now */ |
| 4022 | d_drop(dentry); | ||
| 4022 | } else { | 4023 | } else { |
| 4023 | ret = btrfs_inode_by_name(dir, dentry, &location); | 4024 | ret = btrfs_inode_by_name(dir, dentry, &location); |
| 4024 | } | 4025 | } |
| @@ -4085,7 +4086,15 @@ static void btrfs_dentry_release(struct dentry *dentry) | |||
| 4085 | static struct dentry *btrfs_lookup(struct inode *dir, struct dentry *dentry, | 4086 | static struct dentry *btrfs_lookup(struct inode *dir, struct dentry *dentry, |
| 4086 | struct nameidata *nd) | 4087 | struct nameidata *nd) |
| 4087 | { | 4088 | { |
| 4088 | return d_splice_alias(btrfs_lookup_dentry(dir, dentry), dentry); | 4089 | struct dentry *ret; |
| 4090 | |||
| 4091 | ret = d_splice_alias(btrfs_lookup_dentry(dir, dentry), dentry); | ||
| 4092 | if (unlikely(d_need_lookup(dentry))) { | ||
| 4093 | spin_lock(&dentry->d_lock); | ||
| 4094 | dentry->d_flags &= ~DCACHE_NEED_LOOKUP; | ||
| 4095 | spin_unlock(&dentry->d_lock); | ||
| 4096 | } | ||
| 4097 | return ret; | ||
| 4089 | } | 4098 | } |
| 4090 | 4099 | ||
| 4091 | unsigned char btrfs_filetype_table[] = { | 4100 | unsigned char btrfs_filetype_table[] = { |
| @@ -4125,7 +4134,8 @@ static int btrfs_real_readdir(struct file *filp, void *dirent, | |||
| 4125 | 4134 | ||
| 4126 | /* special case for "." */ | 4135 | /* special case for "." */ |
| 4127 | if (filp->f_pos == 0) { | 4136 | if (filp->f_pos == 0) { |
| 4128 | over = filldir(dirent, ".", 1, 1, btrfs_ino(inode), DT_DIR); | 4137 | over = filldir(dirent, ".", 1, |
| 4138 | filp->f_pos, btrfs_ino(inode), DT_DIR); | ||
| 4129 | if (over) | 4139 | if (over) |
| 4130 | return 0; | 4140 | return 0; |
| 4131 | filp->f_pos = 1; | 4141 | filp->f_pos = 1; |
| @@ -4134,7 +4144,7 @@ static int btrfs_real_readdir(struct file *filp, void *dirent, | |||
| 4134 | if (filp->f_pos == 1) { | 4144 | if (filp->f_pos == 1) { |
| 4135 | u64 pino = parent_ino(filp->f_path.dentry); | 4145 | u64 pino = parent_ino(filp->f_path.dentry); |
| 4136 | over = filldir(dirent, "..", 2, | 4146 | over = filldir(dirent, "..", 2, |
| 4137 | 2, pino, DT_DIR); | 4147 | filp->f_pos, pino, DT_DIR); |
| 4138 | if (over) | 4148 | if (over) |
| 4139 | return 0; | 4149 | return 0; |
| 4140 | filp->f_pos = 2; | 4150 | filp->f_pos = 2; |
diff --git a/fs/btrfs/ioctl.c b/fs/btrfs/ioctl.c index 3351b1b24574..d11fd28efa6a 100644 --- a/fs/btrfs/ioctl.c +++ b/fs/btrfs/ioctl.c | |||
| @@ -2177,6 +2177,11 @@ static noinline long btrfs_ioctl_clone(struct file *file, unsigned long srcfd, | |||
| 2177 | if (!(src_file->f_mode & FMODE_READ)) | 2177 | if (!(src_file->f_mode & FMODE_READ)) |
| 2178 | goto out_fput; | 2178 | goto out_fput; |
| 2179 | 2179 | ||
| 2180 | /* don't make the dst file partly checksummed */ | ||
| 2181 | if ((BTRFS_I(src)->flags & BTRFS_INODE_NODATASUM) != | ||
| 2182 | (BTRFS_I(inode)->flags & BTRFS_INODE_NODATASUM)) | ||
| 2183 | goto out_fput; | ||
| 2184 | |||
| 2180 | ret = -EISDIR; | 2185 | ret = -EISDIR; |
| 2181 | if (S_ISDIR(src->i_mode) || S_ISDIR(inode->i_mode)) | 2186 | if (S_ISDIR(src->i_mode) || S_ISDIR(inode->i_mode)) |
| 2182 | goto out_fput; | 2187 | goto out_fput; |
| @@ -2226,6 +2231,10 @@ static noinline long btrfs_ioctl_clone(struct file *file, unsigned long srcfd, | |||
| 2226 | goto out_unlock; | 2231 | goto out_unlock; |
| 2227 | } | 2232 | } |
| 2228 | 2233 | ||
| 2234 | /* truncate page cache pages from target inode range */ | ||
| 2235 | truncate_inode_pages_range(&inode->i_data, destoff, | ||
| 2236 | PAGE_CACHE_ALIGN(destoff + len) - 1); | ||
| 2237 | |||
| 2229 | /* do any pending delalloc/csum calc on src, one way or | 2238 | /* do any pending delalloc/csum calc on src, one way or |
| 2230 | another, and lock file content */ | 2239 | another, and lock file content */ |
| 2231 | while (1) { | 2240 | while (1) { |
| @@ -2242,10 +2251,6 @@ static noinline long btrfs_ioctl_clone(struct file *file, unsigned long srcfd, | |||
| 2242 | btrfs_wait_ordered_range(src, off, len); | 2251 | btrfs_wait_ordered_range(src, off, len); |
| 2243 | } | 2252 | } |
| 2244 | 2253 | ||
| 2245 | /* truncate page cache pages from target inode range */ | ||
| 2246 | truncate_inode_pages_range(&inode->i_data, off, | ||
| 2247 | ALIGN(off + len, PAGE_CACHE_SIZE) - 1); | ||
| 2248 | |||
| 2249 | /* clone data */ | 2254 | /* clone data */ |
| 2250 | key.objectid = btrfs_ino(src); | 2255 | key.objectid = btrfs_ino(src); |
| 2251 | key.type = BTRFS_EXTENT_DATA_KEY; | 2256 | key.type = BTRFS_EXTENT_DATA_KEY; |
| @@ -2442,7 +2447,6 @@ static noinline long btrfs_ioctl_clone(struct file *file, unsigned long srcfd, | |||
| 2442 | if (endoff > inode->i_size) | 2447 | if (endoff > inode->i_size) |
| 2443 | btrfs_i_size_write(inode, endoff); | 2448 | btrfs_i_size_write(inode, endoff); |
| 2444 | 2449 | ||
| 2445 | BTRFS_I(inode)->flags = BTRFS_I(src)->flags; | ||
| 2446 | ret = btrfs_update_inode(trans, root, inode); | 2450 | ret = btrfs_update_inode(trans, root, inode); |
| 2447 | BUG_ON(ret); | 2451 | BUG_ON(ret); |
| 2448 | btrfs_end_transaction(trans, root); | 2452 | btrfs_end_transaction(trans, root); |
