diff mbox series

[v3] loop: don't print warnings if the underlying filesystem doesn't support discard

Message ID alpine.LRH.2.02.2110121516440.21015@file01.intranet.prod.int.rdu2.redhat.com (mailing list archive)
State New, archived
Headers show
Series [v3] loop: don't print warnings if the underlying filesystem doesn't support discard | expand

Commit Message

Mikulas Patocka Oct. 12, 2021, 8:25 p.m. UTC
On Tue, 12 Oct 2021, Christoph Hellwig wrote:

> On Mon, Oct 04, 2021 at 09:01:33AM -0400, Mikulas Patocka wrote:
> > Do you want this patch?
> 
> Yes, this looks like what I want.  Minor nitpicks below:
> 
> > +	.fallocate_flags = BLKDEV_FALLOC_FL_SUPPORTED,
> 
> I'd probably call this fallocate_supported_flags.
> 
> > +	.fallocate_flags = FALLOC_FL_KEEP_SIZE | FALLOC_FL_PUNCH_HOLE | FALLOC_FL_ZERO_RANGE,
> 
> Please avoid over 80 lines for a plain list of flags.

OK. Here I'm sending a new version of the patch.

BTW. for some filesystems (cifs, ext4, fuse, ...), the supported falloc 
flags vary dynamically - for example, ext4 can do COLLAPSE_RANGE and 
INSERT_RANGE operations only if the filesystem is not ext2 or ext3 and if 
the file is not encrypted.

Should we add a new flag FALLOC_FL_RETURN_SUPORTED_FLAGS that will return 
the supported flags instead of using a static field in the file_operations 
structure?

Mikulas



From: Mikulas Patocka <mpatocka@redhat.com>

The loop driver checks for the fallocate method and if it is present, it 
assumes that the filesystem can do FALLOC_FL_ZERO_RANGE and 
FALLOC_FL_PUNCH_HOLE requests. However, some filesystems (such as fat, or 
tmpfs) have the fallocate method, but lack the capability to do 
FALLOC_FL_ZERO_RANGE and/or FALLOC_FL_PUNCH_HOLE.

This results in syslog warnings "blk_update_request: operation not 
supported error, dev loop0, sector 0 op 0x9:(WRITE_ZEROES) flags 0x800800 
phys_seg 0 prio class 0". The error can be reproduced with this command:
"truncate -s 1GiB /tmp/file; losetup /dev/loop0 /tmp/file; blkdiscard -z 
/dev/loop0"

This patch introduces a field "fallocate_supported_flags" in struct 
file_operations that specifies the flags that are supported by the 
fallocate methods. The loopback driver will check this field to determine 
if FALLOC_FL_PUNCH_HOLE or FALLOC_FL_ZERO_RANGE is supported

Signed-off-by: Mikulas Patocka <mpatocka@redhat.com>

Comments

kernel test robot Oct. 13, 2021, 2:56 a.m. UTC | #1
Hi Mikulas,

I love your patch! Yet something to improve:

[auto build test ERROR on axboe-block/for-next]
[also build test ERROR on kdave/for-next ceph-client/for-linus cifs/for-next tytso-ext4/dev jaegeuk-f2fs/dev-test mszeredi-fuse/for-next linus/master v5.15-rc5 next-20211012]
[cannot apply to hch-configfs/for-next gfs2/for-next]
[If your patch is applied to the wrong git tree, kindly drop us a note.
And when submitting patch, we suggest to use '--base' as documented in
https://git-scm.com/docs/git-format-patch]

url:    https://github.com/0day-ci/linux/commits/Mikulas-Patocka/loop-don-t-print-warnings-if-the-underlying-filesystem-doesn-t-support-discard/20211013-042727
base:   https://git.kernel.org/pub/scm/linux/kernel/git/axboe/linux-block.git for-next
config: arc-randconfig-r043-20211012 (attached as .config)
compiler: arc-elf-gcc (GCC) 11.2.0
reproduce (this is a W=1 build):
        wget https://raw.githubusercontent.com/intel/lkp-tests/master/sbin/make.cross -O ~/bin/make.cross
        chmod +x ~/bin/make.cross
        # https://github.com/0day-ci/linux/commit/c381403746bc0dc3eb5db4b157408430febd6ecf
        git remote add linux-review https://github.com/0day-ci/linux
        git fetch --no-tags linux-review Mikulas-Patocka/loop-don-t-print-warnings-if-the-underlying-filesystem-doesn-t-support-discard/20211013-042727
        git checkout c381403746bc0dc3eb5db4b157408430febd6ecf
        # save the attached .config to linux build tree
        mkdir build_dir
        COMPILER_INSTALL_PATH=$HOME/0day COMPILER=gcc-11.2.0 make.cross O=build_dir ARCH=arc SHELL=/bin/bash fs/fuse/ fs/overlayfs/

If you fix the issue, kindly add following tag as appropriate
Reported-by: kernel test robot <lkp@intel.com>

All errors (new ones prefixed by >>):

>> fs/overlayfs/file.c:661:38: error: 'FALLOC_FL_SUPPORTED_MASK' undeclared here (not in a function)
     661 |         .fallocate_supported_flags = FALLOC_FL_SUPPORTED_MASK,
         |                                      ^~~~~~~~~~~~~~~~~~~~~~~~


vim +/FALLOC_FL_SUPPORTED_MASK +661 fs/overlayfs/file.c

   651	
   652	const struct file_operations ovl_file_operations = {
   653		.open		= ovl_open,
   654		.release	= ovl_release,
   655		.llseek		= ovl_llseek,
   656		.read_iter	= ovl_read_iter,
   657		.write_iter	= ovl_write_iter,
   658		.fsync		= ovl_fsync,
   659		.mmap		= ovl_mmap,
   660		.fallocate	= ovl_fallocate,
 > 661		.fallocate_supported_flags = FALLOC_FL_SUPPORTED_MASK,
   662		.fadvise	= ovl_fadvise,
   663		.flush		= ovl_flush,
   664		.splice_read    = generic_file_splice_read,
   665		.splice_write   = ovl_splice_write,
   666	
   667		.copy_file_range	= ovl_copy_file_range,
   668		.remap_file_range	= ovl_remap_file_range,
   669	};
   670	

---
0-DAY CI Kernel Test Service, Intel Corporation
https://lists.01.org/hyperkitty/list/kbuild-all@lists.01.org
kernel test robot Oct. 13, 2021, 5:06 a.m. UTC | #2
Hi Mikulas,

I love your patch! Yet something to improve:

[auto build test ERROR on axboe-block/for-next]
[also build test ERROR on kdave/for-next ceph-client/for-linus cifs/for-next tytso-ext4/dev jaegeuk-f2fs/dev-test mszeredi-fuse/for-next linus/master v5.15-rc5 next-20211012]
[cannot apply to hch-configfs/for-next gfs2/for-next]
[If your patch is applied to the wrong git tree, kindly drop us a note.
And when submitting patch, we suggest to use '--base' as documented in
https://git-scm.com/docs/git-format-patch]

url:    https://github.com/0day-ci/linux/commits/Mikulas-Patocka/loop-don-t-print-warnings-if-the-underlying-filesystem-doesn-t-support-discard/20211013-042727
base:   https://git.kernel.org/pub/scm/linux/kernel/git/axboe/linux-block.git for-next
config: x86_64-randconfig-a015-20211012 (attached as .config)
compiler: clang version 14.0.0 (https://github.com/llvm/llvm-project adf55ac6657693f7bfbe3087b599b4031a765a44)
reproduce (this is a W=1 build):
        wget https://raw.githubusercontent.com/intel/lkp-tests/master/sbin/make.cross -O ~/bin/make.cross
        chmod +x ~/bin/make.cross
        # https://github.com/0day-ci/linux/commit/c381403746bc0dc3eb5db4b157408430febd6ecf
        git remote add linux-review https://github.com/0day-ci/linux
        git fetch --no-tags linux-review Mikulas-Patocka/loop-don-t-print-warnings-if-the-underlying-filesystem-doesn-t-support-discard/20211013-042727
        git checkout c381403746bc0dc3eb5db4b157408430febd6ecf
        # save the attached .config to linux build tree
        mkdir build_dir
        COMPILER_INSTALL_PATH=$HOME/0day COMPILER=clang make.cross W=1 O=build_dir ARCH=x86_64 SHELL=/bin/bash fs/cifs/

If you fix the issue, kindly add following tag as appropriate
Reported-by: kernel test robot <lkp@intel.com>

All errors (new ones prefixed by >>):

>> fs/cifs/cifsfs.c:1284:31: error: use of undeclared identifier 'FALLOC_FL_PUNCH_HOLE'
           .fallocate_supported_flags = FALLOC_FL_PUNCH_HOLE |
                                        ^
>> fs/cifs/cifsfs.c:1285:3: error: use of undeclared identifier 'FALLOC_FL_ZERO_RANGE'
                   FALLOC_FL_ZERO_RANGE | FALLOC_FL_KEEP_SIZE |
                   ^
>> fs/cifs/cifsfs.c:1285:26: error: use of undeclared identifier 'FALLOC_FL_KEEP_SIZE'
                   FALLOC_FL_ZERO_RANGE | FALLOC_FL_KEEP_SIZE |
                                          ^
>> fs/cifs/cifsfs.c:1286:3: error: use of undeclared identifier 'FALLOC_FL_COLLAPSE_RANGE'
                   FALLOC_FL_COLLAPSE_RANGE | FALLOC_FL_INSERT_RANGE,
                   ^
>> fs/cifs/cifsfs.c:1286:30: error: use of undeclared identifier 'FALLOC_FL_INSERT_RANGE'
                   FALLOC_FL_COLLAPSE_RANGE | FALLOC_FL_INSERT_RANGE,
                                              ^
   fs/cifs/cifsfs.c:1307:31: error: use of undeclared identifier 'FALLOC_FL_PUNCH_HOLE'
           .fallocate_supported_flags = FALLOC_FL_PUNCH_HOLE |
                                        ^
   fs/cifs/cifsfs.c:1308:3: error: use of undeclared identifier 'FALLOC_FL_ZERO_RANGE'
                   FALLOC_FL_ZERO_RANGE | FALLOC_FL_KEEP_SIZE |
                   ^
   fs/cifs/cifsfs.c:1308:26: error: use of undeclared identifier 'FALLOC_FL_KEEP_SIZE'
                   FALLOC_FL_ZERO_RANGE | FALLOC_FL_KEEP_SIZE |
                                          ^
   fs/cifs/cifsfs.c:1309:3: error: use of undeclared identifier 'FALLOC_FL_COLLAPSE_RANGE'
                   FALLOC_FL_COLLAPSE_RANGE | FALLOC_FL_INSERT_RANGE,
                   ^
   fs/cifs/cifsfs.c:1309:30: error: use of undeclared identifier 'FALLOC_FL_INSERT_RANGE'
                   FALLOC_FL_COLLAPSE_RANGE | FALLOC_FL_INSERT_RANGE,
                                              ^
   fs/cifs/cifsfs.c:1330:31: error: use of undeclared identifier 'FALLOC_FL_PUNCH_HOLE'
           .fallocate_supported_flags = FALLOC_FL_PUNCH_HOLE |
                                        ^
   fs/cifs/cifsfs.c:1331:3: error: use of undeclared identifier 'FALLOC_FL_ZERO_RANGE'
                   FALLOC_FL_ZERO_RANGE | FALLOC_FL_KEEP_SIZE |
                   ^
   fs/cifs/cifsfs.c:1331:26: error: use of undeclared identifier 'FALLOC_FL_KEEP_SIZE'
                   FALLOC_FL_ZERO_RANGE | FALLOC_FL_KEEP_SIZE |
                                          ^
   fs/cifs/cifsfs.c:1332:3: error: use of undeclared identifier 'FALLOC_FL_COLLAPSE_RANGE'
                   FALLOC_FL_COLLAPSE_RANGE | FALLOC_FL_INSERT_RANGE,
                   ^
   fs/cifs/cifsfs.c:1332:30: error: use of undeclared identifier 'FALLOC_FL_INSERT_RANGE'
                   FALLOC_FL_COLLAPSE_RANGE | FALLOC_FL_INSERT_RANGE,
                                              ^
   fs/cifs/cifsfs.c:1351:31: error: use of undeclared identifier 'FALLOC_FL_PUNCH_HOLE'
           .fallocate_supported_flags = FALLOC_FL_PUNCH_HOLE |
                                        ^
   fs/cifs/cifsfs.c:1352:3: error: use of undeclared identifier 'FALLOC_FL_ZERO_RANGE'
                   FALLOC_FL_ZERO_RANGE | FALLOC_FL_KEEP_SIZE |
                   ^
   fs/cifs/cifsfs.c:1352:26: error: use of undeclared identifier 'FALLOC_FL_KEEP_SIZE'
                   FALLOC_FL_ZERO_RANGE | FALLOC_FL_KEEP_SIZE |
                                          ^
   fs/cifs/cifsfs.c:1353:3: error: use of undeclared identifier 'FALLOC_FL_COLLAPSE_RANGE'
                   FALLOC_FL_COLLAPSE_RANGE | FALLOC_FL_INSERT_RANGE,
                   ^
   fatal error: too many errors emitted, stopping now [-ferror-limit=]
   20 errors generated.


vim +/FALLOC_FL_PUNCH_HOLE +1284 fs/cifs/cifsfs.c

  1265	
  1266	const struct file_operations cifs_file_ops = {
  1267		.read_iter = cifs_loose_read_iter,
  1268		.write_iter = cifs_file_write_iter,
  1269		.open = cifs_open,
  1270		.release = cifs_close,
  1271		.lock = cifs_lock,
  1272		.flock = cifs_flock,
  1273		.fsync = cifs_fsync,
  1274		.flush = cifs_flush,
  1275		.mmap  = cifs_file_mmap,
  1276		.splice_read = generic_file_splice_read,
  1277		.splice_write = iter_file_splice_write,
  1278		.llseek = cifs_llseek,
  1279		.unlocked_ioctl	= cifs_ioctl,
  1280		.copy_file_range = cifs_copy_file_range,
  1281		.remap_file_range = cifs_remap_file_range,
  1282		.setlease = cifs_setlease,
  1283		.fallocate = cifs_fallocate,
> 1284		.fallocate_supported_flags = FALLOC_FL_PUNCH_HOLE |
> 1285			FALLOC_FL_ZERO_RANGE | FALLOC_FL_KEEP_SIZE |
> 1286			FALLOC_FL_COLLAPSE_RANGE | FALLOC_FL_INSERT_RANGE,
  1287	};
  1288	

---
0-DAY CI Kernel Test Service, Intel Corporation
https://lists.01.org/hyperkitty/list/kbuild-all@lists.01.org
diff mbox series

Patch

Index: linux-2.6/block/fops.c
===================================================================
--- linux-2.6.orig/block/fops.c
+++ linux-2.6/block/fops.c
@@ -628,6 +628,7 @@  const struct file_operations def_blk_fop
 	.splice_read	= generic_file_splice_read,
 	.splice_write	= iter_file_splice_write,
 	.fallocate	= blkdev_fallocate,
+	.fallocate_supported_flags = BLKDEV_FALLOC_FL_SUPPORTED,
 };
 
 static __init int blkdev_init(void)
Index: linux-2.6/fs/btrfs/file.c
===================================================================
--- linux-2.6.orig/fs/btrfs/file.c
+++ linux-2.6/fs/btrfs/file.c
@@ -3688,6 +3688,8 @@  const struct file_operations btrfs_file_
 	.release	= btrfs_release_file,
 	.fsync		= btrfs_sync_file,
 	.fallocate	= btrfs_fallocate,
+	.fallocate_supported_flags = FALLOC_FL_KEEP_SIZE |
+		FALLOC_FL_PUNCH_HOLE | FALLOC_FL_ZERO_RANGE,
 	.unlocked_ioctl	= btrfs_ioctl,
 #ifdef CONFIG_COMPAT
 	.compat_ioctl	= btrfs_compat_ioctl,
Index: linux-2.6/fs/ceph/file.c
===================================================================
--- linux-2.6.orig/fs/ceph/file.c
+++ linux-2.6/fs/ceph/file.c
@@ -2492,5 +2492,6 @@  const struct file_operations ceph_file_f
 	.unlocked_ioctl = ceph_ioctl,
 	.compat_ioctl = compat_ptr_ioctl,
 	.fallocate	= ceph_fallocate,
+	.fallocate_supported_flags = FALLOC_FL_KEEP_SIZE | FALLOC_FL_PUNCH_HOLE,
 	.copy_file_range = ceph_copy_file_range,
 };
Index: linux-2.6/fs/cifs/cifsfs.c
===================================================================
--- linux-2.6.orig/fs/cifs/cifsfs.c
+++ linux-2.6/fs/cifs/cifsfs.c
@@ -1281,6 +1281,9 @@  const struct file_operations cifs_file_o
 	.remap_file_range = cifs_remap_file_range,
 	.setlease = cifs_setlease,
 	.fallocate = cifs_fallocate,
+	.fallocate_supported_flags = FALLOC_FL_PUNCH_HOLE |
+		FALLOC_FL_ZERO_RANGE | FALLOC_FL_KEEP_SIZE |
+		FALLOC_FL_COLLAPSE_RANGE | FALLOC_FL_INSERT_RANGE,
 };
 
 const struct file_operations cifs_file_strict_ops = {
@@ -1301,6 +1304,9 @@  const struct file_operations cifs_file_s
 	.remap_file_range = cifs_remap_file_range,
 	.setlease = cifs_setlease,
 	.fallocate = cifs_fallocate,
+	.fallocate_supported_flags = FALLOC_FL_PUNCH_HOLE |
+		FALLOC_FL_ZERO_RANGE | FALLOC_FL_KEEP_SIZE |
+		FALLOC_FL_COLLAPSE_RANGE | FALLOC_FL_INSERT_RANGE,
 };
 
 const struct file_operations cifs_file_direct_ops = {
@@ -1321,6 +1327,9 @@  const struct file_operations cifs_file_d
 	.llseek = cifs_llseek,
 	.setlease = cifs_setlease,
 	.fallocate = cifs_fallocate,
+	.fallocate_supported_flags = FALLOC_FL_PUNCH_HOLE |
+		FALLOC_FL_ZERO_RANGE | FALLOC_FL_KEEP_SIZE |
+		FALLOC_FL_COLLAPSE_RANGE | FALLOC_FL_INSERT_RANGE,
 };
 
 const struct file_operations cifs_file_nobrl_ops = {
@@ -1339,6 +1348,9 @@  const struct file_operations cifs_file_n
 	.remap_file_range = cifs_remap_file_range,
 	.setlease = cifs_setlease,
 	.fallocate = cifs_fallocate,
+	.fallocate_supported_flags = FALLOC_FL_PUNCH_HOLE |
+		FALLOC_FL_ZERO_RANGE | FALLOC_FL_KEEP_SIZE |
+		FALLOC_FL_COLLAPSE_RANGE | FALLOC_FL_INSERT_RANGE,
 };
 
 const struct file_operations cifs_file_strict_nobrl_ops = {
@@ -1357,6 +1369,9 @@  const struct file_operations cifs_file_s
 	.remap_file_range = cifs_remap_file_range,
 	.setlease = cifs_setlease,
 	.fallocate = cifs_fallocate,
+	.fallocate_supported_flags = FALLOC_FL_PUNCH_HOLE |
+		FALLOC_FL_ZERO_RANGE | FALLOC_FL_KEEP_SIZE |
+		FALLOC_FL_COLLAPSE_RANGE | FALLOC_FL_INSERT_RANGE,
 };
 
 const struct file_operations cifs_file_direct_nobrl_ops = {
@@ -1375,6 +1390,9 @@  const struct file_operations cifs_file_d
 	.llseek = cifs_llseek,
 	.setlease = cifs_setlease,
 	.fallocate = cifs_fallocate,
+	.fallocate_supported_flags = FALLOC_FL_PUNCH_HOLE |
+		FALLOC_FL_ZERO_RANGE | FALLOC_FL_KEEP_SIZE |
+		FALLOC_FL_COLLAPSE_RANGE | FALLOC_FL_INSERT_RANGE,
 };
 
 const struct file_operations cifs_dir_ops = {
Index: linux-2.6/fs/ext4/file.c
===================================================================
--- linux-2.6.orig/fs/ext4/file.c
+++ linux-2.6/fs/ext4/file.c
@@ -929,6 +929,9 @@  const struct file_operations ext4_file_o
 	.splice_read	= generic_file_splice_read,
 	.splice_write	= iter_file_splice_write,
 	.fallocate	= ext4_fallocate,
+	.fallocate_supported_flags = FALLOC_FL_KEEP_SIZE |
+		FALLOC_FL_PUNCH_HOLE | FALLOC_FL_COLLAPSE_RANGE |
+		FALLOC_FL_ZERO_RANGE | FALLOC_FL_INSERT_RANGE,
 };
 
 const struct inode_operations ext4_file_inode_operations = {
Index: linux-2.6/fs/f2fs/file.c
===================================================================
--- linux-2.6.orig/fs/f2fs/file.c
+++ linux-2.6/fs/f2fs/file.c
@@ -4499,6 +4499,9 @@  const struct file_operations f2fs_file_o
 	.flush		= f2fs_file_flush,
 	.fsync		= f2fs_sync_file,
 	.fallocate	= f2fs_fallocate,
+	.fallocate_supported_flags = FALLOC_FL_KEEP_SIZE |
+		FALLOC_FL_PUNCH_HOLE | FALLOC_FL_COLLAPSE_RANGE |
+		FALLOC_FL_ZERO_RANGE | FALLOC_FL_INSERT_RANGE,
 	.unlocked_ioctl	= f2fs_ioctl,
 #ifdef CONFIG_COMPAT
 	.compat_ioctl	= f2fs_compat_ioctl,
Index: linux-2.6/fs/fat/file.c
===================================================================
--- linux-2.6.orig/fs/fat/file.c
+++ linux-2.6/fs/fat/file.c
@@ -211,6 +211,7 @@  const struct file_operations fat_file_op
 	.splice_read	= generic_file_splice_read,
 	.splice_write	= iter_file_splice_write,
 	.fallocate	= fat_fallocate,
+	.fallocate_supported_flags = FALLOC_FL_KEEP_SIZE,
 };
 
 static int fat_cont_expand(struct inode *inode, loff_t size)
Index: linux-2.6/fs/fuse/file.c
===================================================================
--- linux-2.6.orig/fs/fuse/file.c
+++ linux-2.6/fs/fuse/file.c
@@ -3147,6 +3147,8 @@  static const struct file_operations fuse
 	.compat_ioctl	= fuse_file_compat_ioctl,
 	.poll		= fuse_file_poll,
 	.fallocate	= fuse_file_fallocate,
+	.fallocate_supported_flags = FALLOC_FL_KEEP_SIZE |
+		FALLOC_FL_PUNCH_HOLE | FALLOC_FL_ZERO_RANGE,
 	.copy_file_range = fuse_copy_file_range,
 };
 
Index: linux-2.6/fs/gfs2/file.c
===================================================================
--- linux-2.6.orig/fs/gfs2/file.c
+++ linux-2.6/fs/gfs2/file.c
@@ -1366,6 +1366,7 @@  const struct file_operations gfs2_file_f
 	.splice_write	= gfs2_file_splice_write,
 	.setlease	= simple_nosetlease,
 	.fallocate	= gfs2_fallocate,
+	.fallocate_supported_flags = FALLOC_FL_PUNCH_HOLE | FALLOC_FL_KEEP_SIZE,
 };
 
 const struct file_operations gfs2_dir_fops = {
Index: linux-2.6/fs/hugetlbfs/inode.c
===================================================================
--- linux-2.6.orig/fs/hugetlbfs/inode.c
+++ linux-2.6/fs/hugetlbfs/inode.c
@@ -1163,6 +1163,7 @@  const struct file_operations hugetlbfs_f
 	.get_unmapped_area	= hugetlb_get_unmapped_area,
 	.llseek			= default_llseek,
 	.fallocate		= hugetlbfs_fallocate,
+	.fallocate_supported_flags = FALLOC_FL_KEEP_SIZE | FALLOC_FL_PUNCH_HOLE,
 };
 
 static const struct inode_operations hugetlbfs_dir_inode_operations = {
Index: linux-2.6/fs/nfs/nfs4file.c
===================================================================
--- linux-2.6.orig/fs/nfs/nfs4file.c
+++ linux-2.6/fs/nfs/nfs4file.c
@@ -457,6 +457,7 @@  const struct file_operations nfs4_file_o
 	.copy_file_range = nfs4_copy_file_range,
 	.llseek		= nfs4_file_llseek,
 	.fallocate	= nfs42_fallocate,
+	.fallocate_supported_flags = FALLOC_FL_PUNCH_HOLE | FALLOC_FL_KEEP_SIZE,
 	.remap_file_range = nfs42_remap_file_range,
 #else
 	.llseek		= nfs_file_llseek,
Index: linux-2.6/fs/ntfs3/file.c
===================================================================
--- linux-2.6.orig/fs/ntfs3/file.c
+++ linux-2.6/fs/ntfs3/file.c
@@ -1246,6 +1246,8 @@  const struct file_operations ntfs_file_o
 	.fsync		= generic_file_fsync,
 	.splice_write	= iter_file_splice_write,
 	.fallocate	= ntfs_fallocate,
+	.fallocate_supported_flags = FALLOC_FL_KEEP_SIZE |
+		FALLOC_FL_PUNCH_HOLE | FALLOC_FL_COLLAPSE_RANGE,
 	.release	= ntfs_file_release,
 };
 // clang-format on
Index: linux-2.6/fs/ocfs2/file.c
===================================================================
--- linux-2.6.orig/fs/ocfs2/file.c
+++ linux-2.6/fs/ocfs2/file.c
@@ -2746,6 +2746,7 @@  const struct file_operations ocfs2_fops
 	.splice_read	= generic_file_splice_read,
 	.splice_write	= iter_file_splice_write,
 	.fallocate	= ocfs2_fallocate,
+	.fallocate_supported_flags = FALLOC_FL_KEEP_SIZE | FALLOC_FL_PUNCH_HOLE,
 	.remap_file_range = ocfs2_remap_file_range,
 };
 
@@ -2792,6 +2793,7 @@  const struct file_operations ocfs2_fops_
 	.splice_read	= generic_file_splice_read,
 	.splice_write	= iter_file_splice_write,
 	.fallocate	= ocfs2_fallocate,
+	.fallocate_supported_flags = FALLOC_FL_KEEP_SIZE | FALLOC_FL_PUNCH_HOLE,
 	.remap_file_range = ocfs2_remap_file_range,
 };
 
Index: linux-2.6/fs/overlayfs/file.c
===================================================================
--- linux-2.6.orig/fs/overlayfs/file.c
+++ linux-2.6/fs/overlayfs/file.c
@@ -658,6 +658,7 @@  const struct file_operations ovl_file_op
 	.fsync		= ovl_fsync,
 	.mmap		= ovl_mmap,
 	.fallocate	= ovl_fallocate,
+	.fallocate_supported_flags = FALLOC_FL_SUPPORTED_MASK,
 	.fadvise	= ovl_fadvise,
 	.flush		= ovl_flush,
 	.splice_read    = generic_file_splice_read,
Index: linux-2.6/fs/xfs/xfs_file.c
===================================================================
--- linux-2.6.orig/fs/xfs/xfs_file.c
+++ linux-2.6/fs/xfs/xfs_file.c
@@ -1464,6 +1464,7 @@  const struct file_operations xfs_file_op
 	.fsync		= xfs_file_fsync,
 	.get_unmapped_area = thp_get_unmapped_area,
 	.fallocate	= xfs_file_fallocate,
+	.fallocate_supported_flags = XFS_FALLOC_FL_SUPPORTED,
 	.fadvise	= xfs_file_fadvise,
 	.remap_file_range = xfs_file_remap_range,
 };
Index: linux-2.6/include/linux/fs.h
===================================================================
--- linux-2.6.orig/include/linux/fs.h
+++ linux-2.6/include/linux/fs.h
@@ -2098,6 +2098,7 @@  struct file_operations {
 	int (*setlease)(struct file *, long, struct file_lock **, void **);
 	long (*fallocate)(struct file *file, int mode, loff_t offset,
 			  loff_t len);
+	unsigned fallocate_supported_flags;
 	void (*show_fdinfo)(struct seq_file *m, struct file *f);
 #ifndef CONFIG_MMU
 	unsigned (*mmap_capabilities)(struct file *);
Index: linux-2.6/ipc/shm.c
===================================================================
--- linux-2.6.orig/ipc/shm.c
+++ linux-2.6/ipc/shm.c
@@ -44,6 +44,7 @@ 
 #include <linux/mount.h>
 #include <linux/ipc_namespace.h>
 #include <linux/rhashtable.h>
+#include <linux/falloc.h>
 
 #include <linux/uaccess.h>
 
@@ -558,6 +559,7 @@  static const struct file_operations shm_
 	.get_unmapped_area	= shm_get_unmapped_area,
 	.llseek		= noop_llseek,
 	.fallocate	= shm_fallocate,
+	.fallocate_supported_flags = FALLOC_FL_KEEP_SIZE | FALLOC_FL_PUNCH_HOLE,
 };
 
 /*
@@ -571,6 +573,7 @@  static const struct file_operations shm_
 	.get_unmapped_area	= shm_get_unmapped_area,
 	.llseek		= noop_llseek,
 	.fallocate	= shm_fallocate,
+	.fallocate_supported_flags = FALLOC_FL_KEEP_SIZE | FALLOC_FL_PUNCH_HOLE,
 };
 
 bool is_file_shm_hugepages(struct file *file)
Index: linux-2.6/mm/shmem.c
===================================================================
--- linux-2.6.orig/mm/shmem.c
+++ linux-2.6/mm/shmem.c
@@ -3797,6 +3797,7 @@  static const struct file_operations shme
 	.splice_read	= generic_file_splice_read,
 	.splice_write	= iter_file_splice_write,
 	.fallocate	= shmem_fallocate,
+	.fallocate_supported_flags = FALLOC_FL_KEEP_SIZE | FALLOC_FL_PUNCH_HOLE,
 #endif
 };
 
Index: linux-2.6/drivers/block/loop.c
===================================================================
--- linux-2.6.orig/drivers/block/loop.c
+++ linux-2.6/drivers/block/loop.c
@@ -947,7 +947,10 @@  static void loop_config_discard(struct l
 	 * encryption is enabled, because it may give an attacker
 	 * useful information.
 	 */
-	} else if (!file->f_op->fallocate || lo->lo_encrypt_key_size) {
+	} else if ((file->f_op->fallocate_supported_flags &
+			(FALLOC_FL_PUNCH_HOLE | FALLOC_FL_KEEP_SIZE)) !=
+			(FALLOC_FL_PUNCH_HOLE | FALLOC_FL_KEEP_SIZE) ||
+		   lo->lo_encrypt_key_size) {
 		max_discard_sectors = 0;
 		granularity = 0;
 
@@ -959,7 +962,10 @@  static void loop_config_discard(struct l
 	if (max_discard_sectors) {
 		q->limits.discard_granularity = granularity;
 		blk_queue_max_discard_sectors(q, max_discard_sectors);
-		blk_queue_max_write_zeroes_sectors(q, max_discard_sectors);
+		if (file->f_op->fallocate_supported_flags & FALLOC_FL_ZERO_RANGE)
+			blk_queue_max_write_zeroes_sectors(q, max_discard_sectors);
+		else
+			blk_queue_max_write_zeroes_sectors(q, 0);
 		blk_queue_flag_set(QUEUE_FLAG_DISCARD, q);
 	} else {
 		q->limits.discard_granularity = 0;