[Date Prev][Date Next][Thread Prev][Thread Next][Date Index][Thread Index]

[RFC][PATCH] Btrfs: Fix the write error into tiny space



reproduce:
dd if=/dev/zero of=tmpfile bs=4K count=1
dd if=/dev/zero of=tmpfile1 bs=1M
dd if=/dev/zero of=tmpfile2 bs=4K
rm -f tmpfile
sync
dd if=/dev/zero of=tmpfile bs=8K count=1

We try to create a 8K file when there is only 4K space left, btrfs will write no
data into a file, but under EXT4 it will still write the first 4K data. Also the 
POSIX hopes we writting as much as possible.

quote the POSIX:
If a write() requests that more bytes be written than there is room for(for example, 
[XSI] [Option Start]  the process' file size limit or [Option End] the physical end 
of a medium), only as many bytes as there is room for shall be written. For example,
suppose there is space for 20 bytes more in a file before reaching a limit. A write 
of 512 bytes will return 20. The next write of a non-zero number of bytes would give
a failure return (except as noted below).

Signed-off-by: Wu Bo <wu.bo@xxxxxxxxxxxxxx>
---
 fs/btrfs/file.c |   18 ++++++++++++++++--
 1 files changed, 16 insertions(+), 2 deletions(-)

diff --git a/fs/btrfs/file.c b/fs/btrfs/file.c
index 15e5a1c..b364f05 100644
--- a/fs/btrfs/file.c
+++ b/fs/btrfs/file.c
@@ -1179,11 +1179,14 @@ static noinline ssize_t __btrfs_buffered_write(struct file *file,
 		size_t write_bytes = min(iov_iter_count(i),
 					 nrptrs * (size_t)PAGE_CACHE_SIZE -
 					 offset);
-		size_t num_pages = (write_bytes + offset +
-				    PAGE_CACHE_SIZE - 1) >> PAGE_CACHE_SHIFT;
+		size_t num_pages;
 		size_t dirty_pages;
 		size_t copied;
 
+again:
+		num_pages = (write_bytes + offset +
+			     PAGE_CACHE_SIZE - 1) >> PAGE_CACHE_SHIFT;
+
 		WARN_ON(num_pages > nrptrs);
 
 		/*
@@ -1197,6 +1200,17 @@ static noinline ssize_t __btrfs_buffered_write(struct file *file,
 
 		ret = btrfs_delalloc_reserve_space(inode,
 					num_pages << PAGE_CACHE_SHIFT);
+
+		/* try to reserve smaller space for write */
+		if (ret == -ENOSPC) {
+			if (num_pages > 1) {
+				write_bytes >>= 1;
+				goto again;
+			} else {
+				break;
+			}
+		}
+
 		if (ret)
 			break;
 
-- 
1.7.3.1
--
To unsubscribe from this list: send the line "unsubscribe linux-btrfs" in
the body of a message to majordomo@xxxxxxxxxxxxxxx
More majordomo info at  http://vger.kernel.org/majordomo-info.html


[Linux NFS]     [Linux NILFS]     [Linux USB Devel]     [Video for Linux]     [Linux Audio Users]     [Photo]     [Yosemite News]    [Yosemite Photos]    [Free Online Dating]     [Linux Kernel]     [Linux SCSI]     [XFree86]

Add to Google Powered by Linux