diff options
author | Steven Whitehouse <swhiteho@redhat.com> | 2008-10-14 09:43:29 -0400 |
---|---|---|
committer | Steven Whitehouse <swhiteho@redhat.com> | 2009-01-05 02:38:46 -0500 |
commit | e9079cce201784632aed4b1a3121ee38c1ced0b6 (patch) | |
tree | 6d99fc45afb3889e5835d713948226d7548d6750 /fs/ioctl.c | |
parent | fe0bdec68b77020281dc814805edfe594ae89e0f (diff) |
GFS2: Support for FIEMAP ioctl
This patch implements the FIEMAP ioctl for GFS2. We can use the generic
code (aside from a lock order issue, solved as per Ted Tso's suggestion)
for which I've introduced a new variant of the generic function. We also
have one exception to deal with, namely stuffed files, so we do that
"by hand", setting all the required flags.
This has been tested with a modified (I could only find an old version) of
Eric's test program, and appears to work correctly.
This patch does not currently support FIEMAP of xattrs, but the plan is to add
that feature at some future point.
Signed-off-by: Steven Whitehouse <swhiteho@redhat.com>
Cc: Theodore Tso <tytso@mit.edu>
Cc: Eric Sandeen <sandeen@redhat.com>
Diffstat (limited to 'fs/ioctl.c')
-rw-r--r-- | fs/ioctl.c | 44 |
1 files changed, 34 insertions, 10 deletions
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 */ |