aboutsummaryrefslogtreecommitdiffstats
path: root/fs
diff options
context:
space:
mode:
authorSteven Whitehouse <swhiteho@redhat.com>2008-10-14 09:43:29 -0400
committerSteven Whitehouse <swhiteho@redhat.com>2009-01-05 02:38:46 -0500
commite9079cce201784632aed4b1a3121ee38c1ced0b6 (patch)
tree6d99fc45afb3889e5835d713948226d7548d6750 /fs
parentfe0bdec68b77020281dc814805edfe594ae89e0f (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')
-rw-r--r--fs/gfs2/ops_inode.c46
-rw-r--r--fs/ioctl.c44
2 files changed, 80 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
1216static 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);
1253out:
1254 mutex_unlock(&inode->i_mutex);
1255 return ret;
1256}
1257
1215const struct inode_operations gfs2_file_iops = { 1258const 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
1225const struct inode_operations gfs2_dir_iops = { 1269const 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
1244const struct inode_operations gfs2_symlink_iops = { 1289const 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 */
247int generic_block_fiemap(struct inode *inode, 251
248 struct fiemap_extent_info *fieinfo, u64 start, 252int __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}
345EXPORT_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
359int 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}
345EXPORT_SYMBOL(generic_block_fiemap); 369EXPORT_SYMBOL(generic_block_fiemap);
346 370
347#endif /* CONFIG_BLOCK */ 371#endif /* CONFIG_BLOCK */