All of lore.kernel.org
 help / color / mirror / Atom feed
* [PATCH v3 2/6] fat: add fat_fallocate operation
@ 2013-12-25  6:31 Namjae Jeon
  2014-02-03  4:14 ` OGAWA Hirofumi
  0 siblings, 1 reply; 6+ messages in thread
From: Namjae Jeon @ 2013-12-25  6:31 UTC (permalink / raw)
  To: hirofumi, akpm
  Cc: linux-fsdevel, linux-kernel, Namjae Jeon, Namjae Jeon, Amit Sahrawat

From: Namjae Jeon <namjae.jeon@samsung.com>

Implement preallocation via the fallocate syscall on VFAT partitions.
This patch is based on an earlier patch of the same name which had some
issues detailed below and did not get accepted.
Refer https://lkml.org/lkml/2007/12/22/130.

a) The preallocated space was not persistent when the
FALLOC_FL_KEEP_SIZE flag was set. It will deallocate cluster at evict time.

b) There was no need to zero out the clusters when the flag was set
Instead of doing an expanding truncate, just allocate clusters and add
them to the fat chain. This reduces preallocation time.

Compatibility with windows:
There are no issues when FALLOC_FL_KEEP_SIZE is not set
because it just does an expanding truncate. Thus reading from the
preallocated area on windows returns null until data is written to it.

When a file with preallocated area using the FALLOC_FL_KEEP_SIZE was
written to on windows, the windows driver freed-up the preallocated
clusters and allocated new clusters for the new data. The freed up
clusters gets reflected in the free space available for the partition
which can be seen from the Volume properties.

The windows chkdsk tool also does not report any errors on a
disk containing files with preallocated space.

And there is also no issue using linux fat fsck.
because discard preallocated clusters at repair time.

Signed-off-by: Namjae Jeon <namjae.jeon@samsung.com>
Signed-off-by: Amit Sahrawat <a.sahrawat@samsung.com>
---
 fs/fat/file.c  |   74 ++++++++++++++++++++++++++++++++++++++++++++++++++++++++
 fs/fat/inode.c |   19 +++++++++++++++
 2 files changed, 93 insertions(+)

diff --git a/fs/fat/file.c b/fs/fat/file.c
index 0bf0d28..79db8b6 100644
--- a/fs/fat/file.c
+++ b/fs/fat/file.c
@@ -17,8 +17,12 @@
 #include <linux/blkdev.h>
 #include <linux/fsnotify.h>
 #include <linux/security.h>
+#include <linux/falloc.h>
 #include "fat.h"
 
+static long fat_fallocate(struct file *file, int mode,
+			  loff_t offset, loff_t len);
+
 static int fat_ioctl_get_attributes(struct inode *inode, u32 __user *user_attr)
 {
 	u32 attr;
@@ -182,6 +186,7 @@ const struct file_operations fat_file_operations = {
 #endif
 	.fsync		= fat_file_fsync,
 	.splice_read	= generic_file_splice_read,
+	.fallocate	= fat_fallocate,
 };
 
 static int fat_cont_expand(struct inode *inode, loff_t size)
@@ -220,6 +225,75 @@ out:
 	return err;
 }
 
+/*
+ * Preallocate space for a file. This implements fat's fallocate file
+ * operation, which gets called from sys_fallocate system call. User
+ * space requests len bytes at offset. If FALLOC_FL_KEEP_SIZE is set
+ * we just allocate clusters without zeroing them out. Otherwise we
+ * allocate and zero out clusters via an expanding truncate.
+ */
+static long fat_fallocate(struct file *file, int mode,
+			  loff_t offset, loff_t len)
+{
+	int cluster;
+	int nr_cluster; /* Number of clusters to be allocated */
+	loff_t mm_bytes; /* Number of bytes to be allocated for file */
+	struct inode *inode = file->f_mapping->host;
+	struct super_block *sb = inode->i_sb;
+	struct msdos_sb_info *sbi = MSDOS_SB(sb);
+	int err = 0;
+
+	/* No support for hole punch or other fallocate flags. */
+	if (mode & ~FALLOC_FL_KEEP_SIZE)
+		return -EOPNOTSUPP;
+
+	/* No support for dir */
+	if (!S_ISREG(inode->i_mode))
+		return -EOPNOTSUPP;
+
+	mutex_lock(&inode->i_mutex);
+	if ((offset + len) <= MSDOS_I(inode)->i_disksize)
+		goto error;
+
+	err = inode_newsize_ok(inode, (len + offset));
+	if (err)
+		goto error;
+
+	if (mode & FALLOC_FL_KEEP_SIZE) {
+		/* First compute the number of clusters to be allocated */
+		mm_bytes = offset + len - round_up(MSDOS_I(inode)->mmu_private,
+			sbi->cluster_size);
+		nr_cluster = (mm_bytes + (sbi->cluster_size - 1)) >>
+			sbi->cluster_bits;
+
+		/* Start the allocation.We are not zeroing out the clusters */
+		while (nr_cluster-- > 0) {
+			err = fat_alloc_clusters(inode, &cluster, 1);
+			if (err) {
+				fat_msg(sb, KERN_ERR,
+					"fat_fallocate(): fat_alloc_clusters() error");
+				goto error;
+			}
+			err = fat_chain_add(inode, cluster, 1);
+			if (err) {
+				fat_free_clusters(inode, cluster);
+				goto error;
+			}
+			MSDOS_I(inode)->i_disksize += sbi->cluster_size;
+		}
+	} else {
+		/* This is just an expanding truncate */
+		err = fat_cont_expand(inode, (offset + len));
+		if (err)
+			fat_msg(sb, KERN_ERR,
+				"fat_fallocate(): fat_cont_expand() error");
+	}
+
+error:
+	mutex_unlock(&inode->i_mutex);
+	return err;
+}
+
 /* Free all clusters after the skip'th cluster. */
 static int fat_free(struct inode *inode, int skip)
 {
diff --git a/fs/fat/inode.c b/fs/fat/inode.c
index 7e5531a..2674c57 100644
--- a/fs/fat/inode.c
+++ b/fs/fat/inode.c
@@ -497,6 +497,25 @@ static void fat_evict_inode(struct inode *inode)
 	if (!inode->i_nlink) {
 		inode->i_size = 0;
 		fat_truncate_blocks(inode, 0);
+	} else {
+		/* Release unwritten fallocated blocks on inode eviction. */
+		if (MSDOS_I(inode)->mmu_private < MSDOS_I(inode)->i_disksize) {
+			int err;
+			fat_truncate_blocks(inode, MSDOS_I(inode)->mmu_private);
+			/* Fallocate results in updating the i_start/iogstart
+			 * for the zero byte file. So, make it return to
+			 * original state during evict and commit it
+			 * synchrnously to avoid any corruption on the next
+			 * access to the cluster chain for the file.
+			 */
+			err = fat_sync_inode(inode);
+			if (err) {
+				fat_msg(inode->i_sb, KERN_WARNING, "Failed to "
+				"update on disk inode for unused fallocated "
+				"blocks, inode could be corrupted. Please run "
+				"fsck");
+			}
+		}
 	}
 	invalidate_inode_buffers(inode);
 	clear_inode(inode);
-- 
1.7.9.5


^ permalink raw reply related	[flat|nested] 6+ messages in thread

* Re: [PATCH v3 2/6] fat: add fat_fallocate operation
  2013-12-25  6:31 [PATCH v3 2/6] fat: add fat_fallocate operation Namjae Jeon
@ 2014-02-03  4:14 ` OGAWA Hirofumi
  2014-02-03 23:04   ` Namjae Jeon
  0 siblings, 1 reply; 6+ messages in thread
From: OGAWA Hirofumi @ 2014-02-03  4:14 UTC (permalink / raw)
  To: Namjae Jeon; +Cc: akpm, linux-fsdevel, linux-kernel, Namjae Jeon, Amit Sahrawat


Sorry for long delay.

Namjae Jeon <linkinjeon@gmail.com> writes:

> +	if (mode & FALLOC_FL_KEEP_SIZE) {
> +		/* First compute the number of clusters to be allocated */
> +		mm_bytes = offset + len - round_up(MSDOS_I(inode)->mmu_private,
> +			sbi->cluster_size);

This should use ->i_disksize?

[...]

> +		/* Release unwritten fallocated blocks on inode eviction. */
> +		if (MSDOS_I(inode)->mmu_private < MSDOS_I(inode)->i_disksize) {
> +			int err;
> +			fat_truncate_blocks(inode, MSDOS_I(inode)->mmu_private);
> +			/* Fallocate results in updating the i_start/iogstart
> +			 * for the zero byte file. So, make it return to
> +			 * original state during evict and commit it
> +			 * synchrnously to avoid any corruption on the next
> +			 * access to the cluster chain for the file.
> +			 */
> +			err = fat_sync_inode(inode);

Ah, good catch. We have to update i_size. I was forgetting about this.
Well, sync inode unconditionally would not be good. Maybe, we better to
use __fat_write_inode() with inode_needs_sync() or such.
-- 
OGAWA Hirofumi <hirofumi@mail.parknet.co.jp>

^ permalink raw reply	[flat|nested] 6+ messages in thread

* Re: [PATCH v3 2/6] fat: add fat_fallocate operation
  2014-02-03  4:14 ` OGAWA Hirofumi
@ 2014-02-03 23:04   ` Namjae Jeon
  2014-02-14  4:53     ` Namjae Jeon
  0 siblings, 1 reply; 6+ messages in thread
From: Namjae Jeon @ 2014-02-03 23:04 UTC (permalink / raw)
  To: OGAWA Hirofumi
  Cc: akpm, linux-fsdevel, linux-kernel, Namjae Jeon, Amit Sahrawat

2014-02-03, OGAWA Hirofumi <hirofumi@mail.parknet.co.jp>:
>
> Sorry for long delay.
>
> Namjae Jeon <linkinjeon@gmail.com> writes:
>
>> +	if (mode & FALLOC_FL_KEEP_SIZE) {
>> +		/* First compute the number of clusters to be allocated */
>> +		mm_bytes = offset + len - round_up(MSDOS_I(inode)->mmu_private,
>> +			sbi->cluster_size);
>
Hi OGAWA.
> This should use ->i_disksize?
Right, I will fix it.
>
> [...]
>
>> +		/* Release unwritten fallocated blocks on inode eviction. */
>> +		if (MSDOS_I(inode)->mmu_private < MSDOS_I(inode)->i_disksize) {
>> +			int err;
>> +			fat_truncate_blocks(inode, MSDOS_I(inode)->mmu_private);
>> +			/* Fallocate results in updating the i_start/iogstart
>> +			 * for the zero byte file. So, make it return to
>> +			 * original state during evict and commit it
>> +			 * synchrnously to avoid any corruption on the next
>> +			 * access to the cluster chain for the file.
>> +			 */
>> +			err = fat_sync_inode(inode);
>
> Ah, good catch. We have to update i_size. I was forgetting about this.
> Well, sync inode unconditionally would not be good. Maybe, we better to
> use __fat_write_inode() with inode_needs_sync() or such.
Okay, I will change it.

Thanks.
> --
> OGAWA Hirofumi <hirofumi@mail.parknet.co.jp>
>

^ permalink raw reply	[flat|nested] 6+ messages in thread

* Re: [PATCH v3 2/6] fat: add fat_fallocate operation
  2014-02-03 23:04   ` Namjae Jeon
@ 2014-02-14  4:53     ` Namjae Jeon
  2014-02-14  7:30       ` OGAWA Hirofumi
  0 siblings, 1 reply; 6+ messages in thread
From: Namjae Jeon @ 2014-02-14  4:53 UTC (permalink / raw)
  To: OGAWA Hirofumi
  Cc: akpm, linux-fsdevel, linux-kernel, Namjae Jeon, Amit Sahrawat

>> [...]
>>
>>> +		/* Release unwritten fallocated blocks on inode eviction. */
>>> +		if (MSDOS_I(inode)->mmu_private < MSDOS_I(inode)->i_disksize) {
>>> +			int err;
>>> +			fat_truncate_blocks(inode, MSDOS_I(inode)->mmu_private);
>>> +			/* Fallocate results in updating the i_start/iogstart
>>> +			 * for the zero byte file. So, make it return to
>>> +			 * original state during evict and commit it
>>> +			 * synchrnously to avoid any corruption on the next
>>> +			 * access to the cluster chain for the file.
>>> +			 */
>>> +			err = fat_sync_inode(inode);
>>
>> Ah, good catch. We have to update i_size. I was forgetting about this.
>> Well, sync inode unconditionally would not be good. Maybe, we better to
>> use __fat_write_inode() with inode_needs_sync() or such.
> Okay, I will change it.
Hi OGAWA

When I checked more, we should wait till inode is sync. Because in the
eviction it will leave the inode/buffers being marked dirty.
Not waiting for it get sync over here. It will leave cluster chain
corrupted when remounting.
It mean we cannot use __fat_write_inode with inode_needs_sync() conditionally.

Thanks.
>
> Thanks.
>> --
>> OGAWA Hirofumi <hirofumi@mail.parknet.co.jp>
>>
>

^ permalink raw reply	[flat|nested] 6+ messages in thread

* Re: [PATCH v3 2/6] fat: add fat_fallocate operation
  2014-02-14  4:53     ` Namjae Jeon
@ 2014-02-14  7:30       ` OGAWA Hirofumi
  2014-02-14 10:16         ` Namjae Jeon
  0 siblings, 1 reply; 6+ messages in thread
From: OGAWA Hirofumi @ 2014-02-14  7:30 UTC (permalink / raw)
  To: Namjae Jeon; +Cc: akpm, linux-fsdevel, linux-kernel, Namjae Jeon, Amit Sahrawat

Namjae Jeon <linkinjeon@gmail.com> writes:

>>> [...]
>>>
>>>> +		/* Release unwritten fallocated blocks on inode eviction. */
>>>> +		if (MSDOS_I(inode)->mmu_private < MSDOS_I(inode)->i_disksize) {
>>>> +			int err;
>>>> +			fat_truncate_blocks(inode, MSDOS_I(inode)->mmu_private);
>>>> +			/* Fallocate results in updating the i_start/iogstart
>>>> +			 * for the zero byte file. So, make it return to
>>>> +			 * original state during evict and commit it
>>>> +			 * synchrnously to avoid any corruption on the next
>>>> +			 * access to the cluster chain for the file.
>>>> +			 */
>>>> +			err = fat_sync_inode(inode);
>>>
>>> Ah, good catch. We have to update i_size. I was forgetting about this.
>>> Well, sync inode unconditionally would not be good. Maybe, we better to
>>> use __fat_write_inode() with inode_needs_sync() or such.
>> Okay, I will change it.
> Hi OGAWA
>
> When I checked more, we should wait till inode is sync. Because in the
> eviction it will leave the inode/buffers being marked dirty.
> Not waiting for it get sync over here. It will leave cluster chain
> corrupted when remounting.
> It mean we cannot use __fat_write_inode with inode_needs_sync() conditionally.

Yeah, this situation bothers us. However, the inode is not marked as
dirty after I_FREEING. And in fatfs case, all related dirty buffers
should goes into blockdev inode buffers (i.e. metadata only), right?

So, I thought sync is not necessary.

Thanks.
-- 
OGAWA Hirofumi <hirofumi@mail.parknet.co.jp>

^ permalink raw reply	[flat|nested] 6+ messages in thread

* Re: [PATCH v3 2/6] fat: add fat_fallocate operation
  2014-02-14  7:30       ` OGAWA Hirofumi
@ 2014-02-14 10:16         ` Namjae Jeon
  0 siblings, 0 replies; 6+ messages in thread
From: Namjae Jeon @ 2014-02-14 10:16 UTC (permalink / raw)
  To: OGAWA Hirofumi
  Cc: akpm, linux-fsdevel, linux-kernel, Namjae Jeon, Amit Sahrawat

2014-02-14 16:30 GMT+09:00, OGAWA Hirofumi <hirofumi@mail.parknet.co.jp>:
> Namjae Jeon <linkinjeon@gmail.com> writes:
>
>>>> [...]
>>>>
>>>>> +		/* Release unwritten fallocated blocks on inode eviction. */
>>>>> +		if (MSDOS_I(inode)->mmu_private < MSDOS_I(inode)->i_disksize) {
>>>>> +			int err;
>>>>> +			fat_truncate_blocks(inode, MSDOS_I(inode)->mmu_private);
>>>>> +			/* Fallocate results in updating the i_start/iogstart
>>>>> +			 * for the zero byte file. So, make it return to
>>>>> +			 * original state during evict and commit it
>>>>> +			 * synchrnously to avoid any corruption on the next
>>>>> +			 * access to the cluster chain for the file.
>>>>> +			 */
>>>>> +			err = fat_sync_inode(inode);
>>>>
>>>> Ah, good catch. We have to update i_size. I was forgetting about this.
>>>> Well, sync inode unconditionally would not be good. Maybe, we better to
>>>> use __fat_write_inode() with inode_needs_sync() or such.
>>> Okay, I will change it.
>> Hi OGAWA
>>
>> When I checked more, we should wait till inode is sync. Because in the
>> eviction it will leave the inode/buffers being marked dirty.
>> Not waiting for it get sync over here. It will leave cluster chain
>> corrupted when remounting.
>> It mean we cannot use __fat_write_inode with inode_needs_sync()
>> conditionally.
>
> Yeah, this situation bothers us. However, the inode is not marked as
> dirty after I_FREEING. And in fatfs case, all related dirty buffers
> should goes into blockdev inode buffers (i.e. metadata only), right?
Right.
>
> So, I thought sync is not necessary.
Yes, I will add it as you pointed.

Thanks for review!
>
> Thanks.
> --
> OGAWA Hirofumi <hirofumi@mail.parknet.co.jp>
>

^ permalink raw reply	[flat|nested] 6+ messages in thread

end of thread, other threads:[~2014-02-14 10:16 UTC | newest]

Thread overview: 6+ messages (download: mbox.gz / follow: Atom feed)
-- links below jump to the message on this page --
2013-12-25  6:31 [PATCH v3 2/6] fat: add fat_fallocate operation Namjae Jeon
2014-02-03  4:14 ` OGAWA Hirofumi
2014-02-03 23:04   ` Namjae Jeon
2014-02-14  4:53     ` Namjae Jeon
2014-02-14  7:30       ` OGAWA Hirofumi
2014-02-14 10:16         ` Namjae Jeon

This is an external index of several public inboxes,
see mirroring instructions on how to clone and mirror
all data and code used by this external index.