diff options
-rw-r--r-- | fs/gfs2/ops_inode.c | 46 | ||||
-rw-r--r-- | fs/ioctl.c | 44 | ||||
-rw-r--r-- | include/linux/fs.h | 3 |
3 files changed, 83 insertions, 10 deletions
diff --git a/fs/gfs2/ops_inode.c b/fs/gfs2/ops_inode.c index d232991b9046..1e24b65e1d23 100644 --- a/fs/gfs2/ops_inode.c +++ b/fs/gfs2/ops_inode.c | |||
@@ -19,6 +19,7 @@ | |||
19 | #include <linux/gfs2_ondisk.h> | 19 | #include <linux/gfs2_ondisk.h> |
20 | #include <linux/crc32.h> | 20 | #include <linux/crc32.h> |
21 | #include <linux/lm_interface.h> | 21 | #include <linux/lm_interface.h> |
22 | #include <linux/fiemap.h> | ||
22 | #include <asm/uaccess.h> | 23 | #include <asm/uaccess.h> |
23 | 24 | ||
24 | #include "gfs2.h" | 25 | #include "gfs2.h" |
@@ -1212,6 +1213,48 @@ static int gfs2_removexattr(struct dentry *dentry, const char *name) | |||
1212 | return gfs2_ea_remove(GFS2_I(dentry->d_inode), &er); | 1213 | return gfs2_ea_remove(GFS2_I(dentry->d_inode), &er); |
1213 | } | 1214 | } |
1214 | 1215 | ||
1216 | static int gfs2_fiemap(struct inode *inode, struct fiemap_extent_info *fieinfo, | ||
1217 | u64 start, u64 len) | ||
1218 | { | ||
1219 | struct gfs2_inode *ip = GFS2_I(inode); | ||
1220 | struct gfs2_holder gh; | ||
1221 | int ret; | ||
1222 | |||
1223 | ret = fiemap_check_flags(fieinfo, FIEMAP_FLAG_SYNC); | ||
1224 | if (ret) | ||
1225 | return ret; | ||
1226 | |||
1227 | mutex_lock(&inode->i_mutex); | ||
1228 | |||
1229 | ret = gfs2_glock_nq_init(ip->i_gl, LM_ST_SHARED, 0, &gh); | ||
1230 | if (ret) | ||
1231 | goto out; | ||
1232 | |||
1233 | if (gfs2_is_stuffed(ip)) { | ||
1234 | u64 phys = ip->i_no_addr << inode->i_blkbits; | ||
1235 | u64 size = i_size_read(inode); | ||
1236 | u32 flags = FIEMAP_EXTENT_LAST|FIEMAP_EXTENT_NOT_ALIGNED| | ||
1237 | FIEMAP_EXTENT_DATA_INLINE; | ||
1238 | phys += sizeof(struct gfs2_dinode); | ||
1239 | phys += start; | ||
1240 | if (start + len > size) | ||
1241 | len = size - start; | ||
1242 | if (start < size) | ||
1243 | ret = fiemap_fill_next_extent(fieinfo, start, phys, | ||
1244 | len, flags); | ||
1245 | if (ret == 1) | ||
1246 | ret = 0; | ||
1247 | } else { | ||
1248 | ret = __generic_block_fiemap(inode, fieinfo, start, len, | ||
1249 | gfs2_block_map); | ||
1250 | } | ||
1251 | |||
1252 | gfs2_glock_dq_uninit(&gh); | ||
1253 | out: | ||
1254 | mutex_unlock(&inode->i_mutex); | ||
1255 | return ret; | ||
1256 | } | ||
1257 | |||
1215 | const struct inode_operations gfs2_file_iops = { | 1258 | const struct inode_operations gfs2_file_iops = { |
1216 | .permission = gfs2_permission, | 1259 | .permission = gfs2_permission, |
1217 | .setattr = gfs2_setattr, | 1260 | .setattr = gfs2_setattr, |
@@ -1220,6 +1263,7 @@ const struct inode_operations gfs2_file_iops = { | |||
1220 | .getxattr = gfs2_getxattr, | 1263 | .getxattr = gfs2_getxattr, |
1221 | .listxattr = gfs2_listxattr, | 1264 | .listxattr = gfs2_listxattr, |
1222 | .removexattr = gfs2_removexattr, | 1265 | .removexattr = gfs2_removexattr, |
1266 | .fiemap = gfs2_fiemap, | ||
1223 | }; | 1267 | }; |
1224 | 1268 | ||
1225 | const struct inode_operations gfs2_dir_iops = { | 1269 | const struct inode_operations gfs2_dir_iops = { |
@@ -1239,6 +1283,7 @@ const struct inode_operations gfs2_dir_iops = { | |||
1239 | .getxattr = gfs2_getxattr, | 1283 | .getxattr = gfs2_getxattr, |
1240 | .listxattr = gfs2_listxattr, | 1284 | .listxattr = gfs2_listxattr, |
1241 | .removexattr = gfs2_removexattr, | 1285 | .removexattr = gfs2_removexattr, |
1286 | .fiemap = gfs2_fiemap, | ||
1242 | }; | 1287 | }; |
1243 | 1288 | ||
1244 | const struct inode_operations gfs2_symlink_iops = { | 1289 | const struct inode_operations gfs2_symlink_iops = { |
@@ -1251,5 +1296,6 @@ const struct inode_operations gfs2_symlink_iops = { | |||
1251 | .getxattr = gfs2_getxattr, | 1296 | .getxattr = gfs2_getxattr, |
1252 | .listxattr = gfs2_listxattr, | 1297 | .listxattr = gfs2_listxattr, |
1253 | .removexattr = gfs2_removexattr, | 1298 | .removexattr = gfs2_removexattr, |
1299 | .fiemap = gfs2_fiemap, | ||
1254 | }; | 1300 | }; |
1255 | 1301 | ||
diff --git a/fs/ioctl.c b/fs/ioctl.c index 43e8b2c0664b..cc3f1aa1cf7b 100644 --- a/fs/ioctl.c +++ b/fs/ioctl.c | |||
@@ -231,7 +231,8 @@ static int ioctl_fiemap(struct file *filp, unsigned long arg) | |||
231 | #define blk_to_logical(inode, blk) (blk << (inode)->i_blkbits) | 231 | #define blk_to_logical(inode, blk) (blk << (inode)->i_blkbits) |
232 | #define logical_to_blk(inode, offset) (offset >> (inode)->i_blkbits); | 232 | #define logical_to_blk(inode, offset) (offset >> (inode)->i_blkbits); |
233 | 233 | ||
234 | /* | 234 | /** |
235 | * __generic_block_fiemap - FIEMAP for block based inodes (no locking) | ||
235 | * @inode - the inode to map | 236 | * @inode - the inode to map |
236 | * @arg - the pointer to userspace where we copy everything to | 237 | * @arg - the pointer to userspace where we copy everything to |
237 | * @get_block - the fs's get_block function | 238 | * @get_block - the fs's get_block function |
@@ -242,11 +243,15 @@ static int ioctl_fiemap(struct file *filp, unsigned long arg) | |||
242 | * | 243 | * |
243 | * If it is possible to have data blocks beyond a hole past @inode->i_size, then | 244 | * If it is possible to have data blocks beyond a hole past @inode->i_size, then |
244 | * please do not use this function, it will stop at the first unmapped block | 245 | * please do not use this function, it will stop at the first unmapped block |
245 | * beyond i_size | 246 | * beyond i_size. |
247 | * | ||
248 | * If you use this function directly, you need to do your own locking. Use | ||
249 | * generic_block_fiemap if you want the locking done for you. | ||
246 | */ | 250 | */ |
247 | int generic_block_fiemap(struct inode *inode, | 251 | |
248 | struct fiemap_extent_info *fieinfo, u64 start, | 252 | int __generic_block_fiemap(struct inode *inode, |
249 | u64 len, get_block_t *get_block) | 253 | struct fiemap_extent_info *fieinfo, u64 start, |
254 | u64 len, get_block_t *get_block) | ||
250 | { | 255 | { |
251 | struct buffer_head tmp; | 256 | struct buffer_head tmp; |
252 | unsigned int start_blk; | 257 | unsigned int start_blk; |
@@ -260,9 +265,6 @@ int generic_block_fiemap(struct inode *inode, | |||
260 | 265 | ||
261 | start_blk = logical_to_blk(inode, start); | 266 | start_blk = logical_to_blk(inode, start); |
262 | 267 | ||
263 | /* guard against change */ | ||
264 | mutex_lock(&inode->i_mutex); | ||
265 | |||
266 | length = (long long)min_t(u64, len, i_size_read(inode)); | 268 | length = (long long)min_t(u64, len, i_size_read(inode)); |
267 | map_len = length; | 269 | map_len = length; |
268 | 270 | ||
@@ -334,14 +336,36 @@ int generic_block_fiemap(struct inode *inode, | |||
334 | cond_resched(); | 336 | cond_resched(); |
335 | } while (1); | 337 | } while (1); |
336 | 338 | ||
337 | mutex_unlock(&inode->i_mutex); | ||
338 | |||
339 | /* if ret is 1 then we just hit the end of the extent array */ | 339 | /* if ret is 1 then we just hit the end of the extent array */ |
340 | if (ret == 1) | 340 | if (ret == 1) |
341 | ret = 0; | 341 | ret = 0; |
342 | 342 | ||
343 | return ret; | 343 | return ret; |
344 | } | 344 | } |
345 | EXPORT_SYMBOL(__generic_block_fiemap); | ||
346 | |||
347 | /** | ||
348 | * generic_block_fiemap - FIEMAP for block based inodes | ||
349 | * @inode: The inode to map | ||
350 | * @fieinfo: The mapping information | ||
351 | * @start: The initial block to map | ||
352 | * @len: The length of the extect to attempt to map | ||
353 | * @get_block: The block mapping function for the fs | ||
354 | * | ||
355 | * Calls __generic_block_fiemap to map the inode, after taking | ||
356 | * the inode's mutex lock. | ||
357 | */ | ||
358 | |||
359 | int generic_block_fiemap(struct inode *inode, | ||
360 | struct fiemap_extent_info *fieinfo, u64 start, | ||
361 | u64 len, get_block_t *get_block) | ||
362 | { | ||
363 | int ret; | ||
364 | mutex_lock(&inode->i_mutex); | ||
365 | ret = __generic_block_fiemap(inode, fieinfo, start, len, get_block); | ||
366 | mutex_unlock(&inode->i_mutex); | ||
367 | return ret; | ||
368 | } | ||
345 | EXPORT_SYMBOL(generic_block_fiemap); | 369 | EXPORT_SYMBOL(generic_block_fiemap); |
346 | 370 | ||
347 | #endif /* CONFIG_BLOCK */ | 371 | #endif /* CONFIG_BLOCK */ |
diff --git a/include/linux/fs.h b/include/linux/fs.h index f2a3010140e3..e34bc6925fdf 100644 --- a/include/linux/fs.h +++ b/include/linux/fs.h | |||
@@ -2059,6 +2059,9 @@ extern int vfs_fstat(unsigned int, struct kstat *); | |||
2059 | 2059 | ||
2060 | extern int do_vfs_ioctl(struct file *filp, unsigned int fd, unsigned int cmd, | 2060 | extern int do_vfs_ioctl(struct file *filp, unsigned int fd, unsigned int cmd, |
2061 | unsigned long arg); | 2061 | unsigned long arg); |
2062 | extern int __generic_block_fiemap(struct inode *inode, | ||
2063 | struct fiemap_extent_info *fieinfo, u64 start, | ||
2064 | u64 len, get_block_t *get_block); | ||
2062 | extern int generic_block_fiemap(struct inode *inode, | 2065 | extern int generic_block_fiemap(struct inode *inode, |
2063 | struct fiemap_extent_info *fieinfo, u64 start, | 2066 | struct fiemap_extent_info *fieinfo, u64 start, |
2064 | u64 len, get_block_t *get_block); | 2067 | u64 len, get_block_t *get_block); |