[<prev] [next>] [thread-next>] [day] [month] [year] [list]
Message-Id: <1383435930-29295-1-git-send-email-tytso@mit.edu>
Date: Sat, 2 Nov 2013 19:45:30 -0400
From: Theodore Ts'o <tytso@....edu>
To: linux-fsdevel@...r.kernel.org
Cc: Ext4 Developers List <linux-ext4@...r.kernel.org>,
Theodore Ts'o <tytso@....edu>
Subject: [PATCH RFC] fs: add FIEMAP_FLAG_DISCARD support
Add the ability for a user who has write access to a file to issue a
discard request for blocks belonging to a file. This can be done via
a new flag to the FIEMAP ioctl, or via the BLKDISCARD ioctl (which
previously only worked on block devices).
Signed-off-by: "Theodore Ts'o" <tytso@....edu>
---
fs/ext4/extents.c | 3 +-
fs/ioctl.c | 99 +++++++++++++++++++++++++++++++++++++++++++++
include/linux/fs.h | 3 ++
include/uapi/linux/fiemap.h | 4 +-
4 files changed, 107 insertions(+), 2 deletions(-)
diff --git a/fs/ext4/extents.c b/fs/ext4/extents.c
index c639f51..1e0744f 100644
--- a/fs/ext4/extents.c
+++ b/fs/ext4/extents.c
@@ -4797,7 +4797,8 @@ static int ext4_find_delayed_extent(struct inode *inode,
return next_del;
}
/* fiemap flags we can handle specified here */
-#define EXT4_FIEMAP_FLAGS (FIEMAP_FLAG_SYNC|FIEMAP_FLAG_XATTR)
+#define EXT4_FIEMAP_FLAGS (FIEMAP_FLAG_SYNC | FIEMAP_FLAG_XATTR |\
+ FIEMAP_FLAG_CACHE | FIEMAP_FLAG_DISCARD)
static int ext4_xattr_fiemap(struct inode *inode,
struct fiemap_extent_info *fieinfo)
diff --git a/fs/ioctl.c b/fs/ioctl.c
index fd507fb..d7698d1 100644
--- a/fs/ioctl.c
+++ b/fs/ioctl.c
@@ -15,6 +15,7 @@
#include <linux/writeback.h>
#include <linux/buffer_head.h>
#include <linux/falloc.h>
+#include <linux/blkdev.h>
#include <asm/ioctls.h>
@@ -64,6 +65,57 @@ static int ioctl_fibmap(struct file *filp, int __user *p)
return put_user(res, p);
}
+/*
+ * fiemap_discuard - handle the FIEMAP_FLAG_DISCARD flagg
+ */
+static int fiemap_discard(struct fiemap_extent_info *fieinfo, u64 logical,
+ u64 phys, u64 len, u32 flags)
+{
+ struct super_block *sb = fieinfo->fi_sb;
+ int align;
+
+ /* pr_notice("fiemap_discard: %llu %llu %llu\n", logical, phys, len); */
+ if (flags & (FIEMAP_EXTENT_UNKNOWN |
+ FIEMAP_EXTENT_ENCODED |
+ FIEMAP_EXTENT_DATA_ENCRYPTED |
+ FIEMAP_EXTENT_DELALLOC |
+ FIEMAP_EXTENT_DATA_TAIL |
+ FIEMAP_EXTENT_DATA_INLINE |
+ FIEMAP_EXTENT_NOT_ALIGNED |
+ FIEMAP_EXTENT_SHARED))
+ return 0;
+
+ if (logical < fieinfo->fi_logical_start) {
+ u64 d = fieinfo->fi_logical_start - logical;
+ if (d > len)
+ return 0;
+ logical += d;
+ phys += d;
+ len -= d;
+ }
+
+ if (logical + len > fieinfo->fi_logical_end)
+ len -= logical + len - fieinfo->fi_logical_end;
+
+ align = logical & (sb->s_blocksize - 1);
+ if ((phys < align) || (len < align))
+ return 0;
+ logical -= align;
+ phys -= align;
+ len -= align;
+ len &= ~(sb->s_blocksize - 1);
+ if (len == 0)
+ return 0;
+
+ /* pr_notice("fiemap_discard adjusted: %llu %llu %llu\n", logical, phys, len); */
+ /* pr_notice("Issuing discard: %llu %llu\n", phys >> sb->s_blocksize_bits,
+ len >> sb->s_blocksize_bits); */
+
+ return sb_issue_discard(sb, phys >> sb->s_blocksize_bits,
+ len >> sb->s_blocksize_bits,
+ GFP_KERNEL, 0);
+}
+
/**
* fiemap_fill_next_extent - Fiemap helper function
* @fieinfo: Fiemap context passed into ->fiemap
@@ -88,6 +140,12 @@ int fiemap_fill_next_extent(struct fiemap_extent_info *fieinfo, u64 logical,
struct fiemap_extent extent;
struct fiemap_extent __user *dest = fieinfo->fi_extents_start;
+ if (fieinfo->fi_flags & FIEMAP_FLAG_DISCARD) {
+ int r = fiemap_discard(fieinfo, logical, phys, len, flags);
+ if (r)
+ return r;
+ }
+
/* only count the extents */
if (fieinfo->fi_extents_max == 0) {
fieinfo->fi_extents_mapped++;
@@ -197,6 +255,13 @@ static int ioctl_fiemap(struct file *filp, unsigned long arg)
fieinfo.fi_flags = fiemap.fm_flags;
fieinfo.fi_extents_max = fiemap.fm_extent_count;
fieinfo.fi_extents_start = ufiemap->fm_extents;
+ fieinfo.fi_sb = sb;
+ fieinfo.fi_logical_start = fiemap.fm_start;
+ fieinfo.fi_logical_end = fiemap.fm_start + len;
+
+ if ((fiemap.fm_flags & FIEMAP_FLAG_DISCARD) &&
+ !(filp->f_mode & FMODE_WRITE))
+ return -EBADF;
if (fiemap.fm_extent_count != 0 &&
!access_ok(VERIFY_WRITE, fieinfo.fi_extents_start,
@@ -588,6 +653,40 @@ int do_vfs_ioctl(struct file *filp, unsigned int fd, unsigned int cmd,
case FS_IOC_FIEMAP:
return ioctl_fiemap(filp, arg);
+ case BLKDISCARD: {
+ struct fiemap_extent_info fieinfo = { 0, };
+ struct inode *inode = file_inode(filp);
+ struct super_block *sb = inode->i_sb;
+ uint64_t range[2];
+ u64 len;
+ int error;
+
+ if (!inode->i_op->fiemap)
+ return -EOPNOTSUPP;
+
+ if (!(filp->f_mode & FMODE_WRITE))
+ return -EBADF;
+
+ if (copy_from_user(range, (void __user *)arg, sizeof(range)))
+ return -EFAULT;
+
+ error = fiemap_check_ranges(sb, range[0], range[1], &len);
+ if (error) {
+ if (error == -EBADF)
+ error = -ENOTTY;
+ return error;
+ }
+
+ fieinfo.fi_flags = FIEMAP_FLAG_DISCARD;
+ fieinfo.fi_extents_max = 0;
+ fieinfo.fi_extents_start = NULL;
+ fieinfo.fi_sb = inode->i_sb;
+ fieinfo.fi_logical_start = range[0];
+ fieinfo.fi_logical_end = range[0] + len;
+
+ error = inode->i_op->fiemap(inode, &fieinfo, range[0], len);
+ }
+
case FIGETBSZ:
return put_user(inode->i_sb->s_blocksize, argp);
diff --git a/include/linux/fs.h b/include/linux/fs.h
index 3f40547..fec07ee 100644
--- a/include/linux/fs.h
+++ b/include/linux/fs.h
@@ -1480,6 +1480,9 @@ struct fiemap_extent_info {
unsigned int fi_flags; /* Flags as passed from user */
unsigned int fi_extents_mapped; /* Number of mapped extents */
unsigned int fi_extents_max; /* Size of fiemap_extent array */
+ struct super_block *fi_sb;
+ u64 fi_logical_start;
+ u64 fi_logical_end;
struct fiemap_extent __user *fi_extents_start; /* Start of
fiemap_extent array */
};
diff --git a/include/uapi/linux/fiemap.h b/include/uapi/linux/fiemap.h
index 0c51d61..849d57f 100644
--- a/include/uapi/linux/fiemap.h
+++ b/include/uapi/linux/fiemap.h
@@ -41,8 +41,10 @@ struct fiemap {
#define FIEMAP_FLAG_SYNC 0x00000001 /* sync file data before map */
#define FIEMAP_FLAG_XATTR 0x00000002 /* map extended attribute tree */
#define FIEMAP_FLAG_CACHE 0x00000004 /* request caching of the extents */
+#define FIEMAP_FLAG_DISCARD 0x00000008 /* issue discard */
-#define FIEMAP_FLAGS_COMPAT (FIEMAP_FLAG_SYNC | FIEMAP_FLAG_XATTR)
+#define FIEMAP_FLAGS_COMPAT (FIEMAP_FLAG_SYNC | FIEMAP_FLAG_XATTR |\
+ FIEMAP_FLAG_CACHE | FIEMAP_FLAG_DISCARD)
#define FIEMAP_EXTENT_LAST 0x00000001 /* Last extent in file. */
#define FIEMAP_EXTENT_UNKNOWN 0x00000002 /* Data location unknown. */
--
1.7.12.rc0.22.gcdd159b
--
To unsubscribe from this list: send the line "unsubscribe linux-ext4" in
the body of a message to majordomo@...r.kernel.org
More majordomo info at http://vger.kernel.org/majordomo-info.html
Powered by blists - more mailing lists