]> git.karo-electronics.de Git - linux-beck.git/commitdiff
f2fs: avoid memory allocation failure due to a long length
authorJaegeuk Kim <jaegeuk@kernel.org>
Sun, 17 Jul 2016 04:59:22 +0000 (21:59 -0700)
committerJaegeuk Kim <jaegeuk@kernel.org>
Mon, 18 Jul 2016 17:20:44 +0000 (10:20 -0700)
We need to avoid ENOMEM due to unexpected long length.

Signed-off-by: Jaegeuk Kim <jaegeuk@kernel.org>
fs/f2fs/file.c

index 47f1f5e36d1c801a1b09181e0b7b16424c23917d..9f9cb6489997626657795c8ed8c829543228fb5b 100644 (file)
@@ -1000,33 +1000,43 @@ static int __clone_blkaddrs(struct inode *src_inode, struct inode *dst_inode,
 
 static int __exchange_data_block(struct inode *src_inode,
                        struct inode *dst_inode, pgoff_t src, pgoff_t dst,
-                       int len, bool full)
+                       pgoff_t len, bool full)
 {
        block_t *src_blkaddr;
        int *do_replace;
+       pgoff_t olen;
        int ret;
 
-       src_blkaddr = f2fs_kvzalloc(sizeof(block_t) * len, GFP_KERNEL);
-       if (!src_blkaddr)
-               return -ENOMEM;
+       while (len) {
+               olen = min((pgoff_t)4 * ADDRS_PER_BLOCK, len);
 
-       do_replace = f2fs_kvzalloc(sizeof(int) * len, GFP_KERNEL);
-       if (!do_replace) {
-               kvfree(src_blkaddr);
-               return -ENOMEM;
-       }
+               src_blkaddr = f2fs_kvzalloc(sizeof(block_t) * olen, GFP_KERNEL);
+               if (!src_blkaddr)
+                       return -ENOMEM;
 
-       ret = __read_out_blkaddrs(src_inode, src_blkaddr, do_replace, src, len);
-       if (ret)
-               goto roll_back;
+               do_replace = f2fs_kvzalloc(sizeof(int) * olen, GFP_KERNEL);
+               if (!do_replace) {
+                       kvfree(src_blkaddr);
+                       return -ENOMEM;
+               }
 
-       ret = __clone_blkaddrs(src_inode, dst_inode, src_blkaddr,
-                                       do_replace, src, dst, len, full);
-       if (ret)
-               goto roll_back;
+               ret = __read_out_blkaddrs(src_inode, src_blkaddr,
+                                       do_replace, src, olen);
+               if (ret)
+                       goto roll_back;
 
-       kvfree(src_blkaddr);
-       kvfree(do_replace);
+               ret = __clone_blkaddrs(src_inode, dst_inode, src_blkaddr,
+                                       do_replace, src, dst, olen, full);
+               if (ret)
+                       goto roll_back;
+
+               src += olen;
+               dst += olen;
+               len -= olen;
+
+               kvfree(src_blkaddr);
+               kvfree(do_replace);
+       }
        return 0;
 
 roll_back: