Groups | Search | Server Info | Keyboard shortcuts | Login | Register [http] [https] [nntp] [nntps]


Groups > linux.kernel > #1202036

[PATCH 3.13.y-ckt 13/53] Btrfs: fix fsync data loss after append write

From Kamal Mostafa <kamal@canonical.com>
Newsgroups linux.kernel
Subject [PATCH 3.13.y-ckt 13/53] Btrfs: fix fsync data loss after append write
Date 2015-08-06 22:50 +0200
Message-ID <pUAgX-3gz-33@gated-at.bofh.it> (permalink)
References <pUA7f-34H-5@gated-at.bofh.it>
Organization linux.* mail to news gateway

Show all headers | View raw


3.13.11-ckt25 -stable review patch.  If anyone has any objections, please let me know.

------------------

From: Filipe Manana <fdmanana@suse.com>

commit e4545de5b035c7debb73d260c78377dbb69cbfb5 upstream.

If we do an append write to a file (which increases its inode's i_size)
that does not have the flag BTRFS_INODE_NEEDS_FULL_SYNC set in its inode,
and the previous transaction added a new hard link to the file, which sets
the flag BTRFS_INODE_COPY_EVERYTHING in the file's inode, and then fsync
the file, the inode's new i_size isn't logged. This has the consequence
that after the fsync log is replayed, the file size remains what it was
before the append write operation, which means users/applications will
not be able to read the data that was successsfully fsync'ed before.

This happens because neither the inode item nor the delayed inode get
their i_size updated when the append write is made - doing so would
require starting a transaction in the buffered write path, something that
we do not do intentionally for performance reasons.

Fix this by making sure that when the flag BTRFS_INODE_COPY_EVERYTHING is
set the inode is logged with its current i_size (log the in-memory inode
into the log tree).

This issue is not a recent regression and is easy to reproduce with the
following test case for fstests:

  seq=`basename $0`
  seqres=$RESULT_DIR/$seq
  echo "QA output created by $seq"

  here=`pwd`
  tmp=/tmp/$$
  status=1	# failure is the default!

  _cleanup()
  {
          _cleanup_flakey
          rm -f $tmp.*
  }
  trap "_cleanup; exit \$status" 0 1 2 3 15

  # get standard environment, filters and checks
  . ./common/rc
  . ./common/filter
  . ./common/dmflakey

  # real QA test starts here
  _supported_fs generic
  _supported_os Linux
  _need_to_be_root
  _require_scratch
  _require_dm_flakey
  _require_metadata_journaling $SCRATCH_DEV

  _crash_and_mount()
  {
          # Simulate a crash/power loss.
          _load_flakey_table $FLAKEY_DROP_WRITES
          _unmount_flakey
          # Allow writes again and mount. This makes the fs replay its fsync log.
          _load_flakey_table $FLAKEY_ALLOW_WRITES
          _mount_flakey
  }

  rm -f $seqres.full

  _scratch_mkfs >> $seqres.full 2>&1
  _init_flakey
  _mount_flakey

  # Create the test file with some initial data and then fsync it.
  # The fsync here is only needed to trigger the issue in btrfs, as it causes the
  # the flag BTRFS_INODE_NEEDS_FULL_SYNC to be removed from the btrfs inode.
  $XFS_IO_PROG -f -c "pwrite -S 0xaa 0 32k" \
                  -c "fsync" \
                  $SCRATCH_MNT/foo | _filter_xfs_io
  sync

  # Add a hard link to our file.
  # On btrfs this sets the flag BTRFS_INODE_COPY_EVERYTHING on the btrfs inode,
  # which is a necessary condition to trigger the issue.
  ln $SCRATCH_MNT/foo $SCRATCH_MNT/bar

  # Sync the filesystem to force a commit of the current btrfs transaction, this
  # is a necessary condition to trigger the bug on btrfs.
  sync

  # Now append more data to our file, increasing its size, and fsync the file.
  # In btrfs because the inode flag BTRFS_INODE_COPY_EVERYTHING was set and the
  # write path did not update the inode item in the btree nor the delayed inode
  # item (in memory struture) in the current transaction (created by the fsync
  # handler), the fsync did not record the inode's new i_size in the fsync
  # log/journal. This made the data unavailable after the fsync log/journal is
  # replayed.
  $XFS_IO_PROG -c "pwrite -S 0xbb 32K 32K" \
               -c "fsync" \
               $SCRATCH_MNT/foo | _filter_xfs_io

  echo "File content after fsync and before crash:"
  od -t x1 $SCRATCH_MNT/foo

  _crash_and_mount

  echo "File content after crash and log replay:"
  od -t x1 $SCRATCH_MNT/foo

  status=0
  exit

The expected file output before and after the crash/power failure expects the
appended data to be available, which is:

  0000000 aa aa aa aa aa aa aa aa aa aa aa aa aa aa aa aa
  *
  0100000 bb bb bb bb bb bb bb bb bb bb bb bb bb bb bb bb
  *
  0200000

Signed-off-by: Filipe Manana <fdmanana@suse.com>
Reviewed-by: Liu Bo <bo.li.liu@oracle.com>
Signed-off-by: Chris Mason <clm@fb.com>
[ luis: backported to 3.16: adjusted context ]
Signed-off-by: Luis Henriques <luis.henriques@canonical.com>

Signed-off-by: Kamal Mostafa <kamal@canonical.com>
---
 fs/btrfs/tree-log.c | 14 +++++++++-----
 1 file changed, 9 insertions(+), 5 deletions(-)

diff --git a/fs/btrfs/tree-log.c b/fs/btrfs/tree-log.c
index 29f3a9b..6e9d26f 100644
--- a/fs/btrfs/tree-log.c
+++ b/fs/btrfs/tree-log.c
@@ -3680,6 +3680,7 @@ static int btrfs_log_inode(struct btrfs_trans_handle *trans,
 	bool fast_search = false;
 	u64 ino = btrfs_ino(inode);
 	u64 logged_isize = 0;
+	bool need_log_inode_item = true;
 
 	path = btrfs_alloc_path();
 	if (!path)
@@ -3769,11 +3770,6 @@ static int btrfs_log_inode(struct btrfs_trans_handle *trans,
 		} else {
 			if (inode_only == LOG_INODE_ALL)
 				fast_search = true;
-			ret = log_inode_item(trans, log, dst_path, inode);
-			if (ret) {
-				err = ret;
-				goto out_unlock;
-			}
 			goto log_extents;
 		}
 
@@ -3797,6 +3793,9 @@ again:
 		if (min_key.type > max_key.type)
 			break;
 
+		if (min_key.type == BTRFS_INODE_ITEM_KEY)
+			need_log_inode_item = false;
+
 		src = path->nodes[0];
 		if (ins_nr && ins_start_slot + ins_nr == path->slots[0]) {
 			ins_nr++;
@@ -3858,6 +3857,11 @@ next_slot:
 log_extents:
 	btrfs_release_path(path);
 	btrfs_release_path(dst_path);
+	if (need_log_inode_item) {
+		err = log_inode_item(trans, log, dst_path, inode);
+		if (err)
+			goto out_unlock;
+	}
 	if (fast_search) {
 		ret = btrfs_log_changed_extents(trans, root, inode, dst_path);
 		if (ret) {
-- 
1.9.1

--
To unsubscribe from this list: send the line "unsubscribe linux-kernel" in
the body of a message to majordomo@vger.kernel.org
More majordomo info at  http://vger.kernel.org/majordomo-info.html
Please read the FAQ at  http://www.tux.org/lkml/

Back to linux.kernel | Previous | NextPrevious in thread | Next in thread | Find similar | Unroll thread


Thread

[3.13.y-ckt stable] Linux 3.13.11-ckt25 stable review Kamal Mostafa <kamal@canonical.com> - 2015-08-06 22:40 +0200
  [PATCH 3.13.y-ckt 37/53] USB: serial: Destroy serial_minors IDR on module exit Kamal Mostafa <kamal@canonical.com> - 2015-08-06 22:50 +0200
  [PATCH 3.13.y-ckt 44/53] genirq: Prevent resend to interrupts marked IRQ_NESTED_THREAD Kamal Mostafa <kamal@canonical.com> - 2015-08-06 22:50 +0200
  [PATCH 3.13.y-ckt 01/53] x86/asm/entry/64: Fold the 'test_in_nmi' macro into its only user Kamal Mostafa <kamal@canonical.com> - 2015-08-06 22:50 +0200
  [PATCH 3.13.y-ckt 47/53] bridge: mdb: zero out the local br_ip variable before use Kamal Mostafa <kamal@canonical.com> - 2015-08-06 22:50 +0200
  [PATCH 3.13.y-ckt 49/53] net: graceful exit from netif_alloc_netdev_queues() Kamal Mostafa <kamal@canonical.com> - 2015-08-06 22:50 +0200
  [PATCH 3.13.y-ckt 45/53] ip_tunnel: fix ipv4 pmtu check to honor inner ip header df Kamal Mostafa <kamal@canonical.com> - 2015-08-06 22:50 +0200
  [PATCH 3.13.y-ckt 24/53] iio: adc: at91_adc: allow to use full range of startup time Kamal Mostafa <kamal@canonical.com> - 2015-08-06 22:50 +0200
  [PATCH 3.13.y-ckt 29/53] USB: cp210x: add ID for Aruba Networks controllers Kamal Mostafa <kamal@canonical.com> - 2015-08-06 22:50 +0200
  [PATCH 3.13.y-ckt 28/53] USB: option: add 2020:4000 ID Kamal Mostafa <kamal@canonical.com> - 2015-08-06 22:50 +0200
  [PATCH 3.13.y-ckt 11/53] Btrfs: use kmem_cache_free when freeing entry in inode cache Kamal Mostafa <kamal@canonical.com> - 2015-08-06 22:50 +0200
  [PATCH 3.13.y-ckt 50/53] net: dsa: Fix off-by-one in switch address parsing Kamal Mostafa <kamal@canonical.com> - 2015-08-06 22:50 +0200
  [PATCH 3.13.y-ckt 10/53] sg_start_req(): make sure that there's not too many elements in iovec Kamal Mostafa <kamal@canonical.com> - 2015-08-06 22:50 +0200
  [PATCH 3.13.y-ckt 25/53] ALSA: usb-audio: Add MIDI support for Steinberg MI2/MI4 Kamal Mostafa <kamal@canonical.com> - 2015-08-06 22:50 +0200
  [PATCH 3.13.y-ckt 38/53] Btrfs: fix memory leak in the extent_same ioctl Kamal Mostafa <kamal@canonical.com> - 2015-08-06 22:50 +0200
  [PATCH 3.13.y-ckt 13/53] Btrfs: fix fsync data loss after append write Kamal Mostafa <kamal@canonical.com> - 2015-08-06 22:50 +0200
  [PATCH 3.13.y-ckt 19/53] hpfs: kstrdup() out of memory handling Kamal Mostafa <kamal@canonical.com> - 2015-08-06 22:50 +0200
  [PATCH 3.13.y-ckt 34/53] ARM: dts: mx23: fix iio-hwmon support Kamal Mostafa <kamal@canonical.com> - 2015-08-06 22:50 +0200
  [PATCH 3.13.y-ckt 46/53] bridge: mdb: start delete timer for temp static entries Kamal Mostafa <kamal@canonical.com> - 2015-08-06 22:50 +0200
  [PATCH 3.13.y-ckt 41/53] st: null pointer dereference panic caused by use after kref_put by st_open Kamal Mostafa <kamal@canonical.com> - 2015-08-06 22:50 +0200
  [PATCH 3.13.y-ckt 40/53] s390/process: fix sfpc inline assembly Kamal Mostafa <kamal@canonical.com> - 2015-08-06 22:50 +0200
  [PATCH 3.13.y-ckt 33/53] drm: add a check for x/y in drm_mode_setcrtc Kamal Mostafa <kamal@canonical.com> - 2015-08-06 22:50 +0200
  [PATCH 3.13.y-ckt 15/53] ext4: be more strict when migrating to non-extent based file Kamal Mostafa <kamal@canonical.com> - 2015-08-06 22:50 +0200
  [PATCH 3.13.y-ckt 02/53] x86/asm/entry/64: Remove a redundant jump Kamal Mostafa <kamal@canonical.com> - 2015-08-06 22:50 +0200
  [PATCH 3.13.y-ckt 35/53] tracing: Have branch tracer use recursive field of task struct Kamal Mostafa <kamal@canonical.com> - 2015-08-06 22:50 +0200
  [PATCH 3.13.y-ckt 27/53] dm btree remove: fix bug in redistribute3 Kamal Mostafa <kamal@canonical.com> - 2015-08-06 22:50 +0200
  [PATCH 3.13.y-ckt 32/53] s390/sclp: clear upper register halves in _sclp_print_early Kamal Mostafa <kamal@canonical.com> - 2015-08-06 22:50 +0200
  [PATCH 3.13.y-ckt 30/53] dm btree: silence lockdep lock inversion in dm_btree_del() Kamal Mostafa <kamal@canonical.com> - 2015-08-06 22:50 +0200
  [PATCH 3.13.y-ckt 26/53] iio: tmp006: Check channel info on write Kamal Mostafa <kamal@canonical.com> - 2015-08-06 22:50 +0200
  [PATCH 3.13.y-ckt 36/53] drivers: net: cpsw: fix crash while accessing second slave ethernet interface Kamal Mostafa <kamal@canonical.com> - 2015-08-06 22:50 +0200
  [PATCH 3.13.y-ckt 31/53] usb: musb: host: rely on port_mode to call musb_start() Kamal Mostafa <kamal@canonical.com> - 2015-08-06 22:50 +0200
  [PATCH 3.13.y-ckt 22/53] iio: inv-mpu: Specify the expected format/precision for write channels Kamal Mostafa <kamal@canonical.com> - 2015-08-06 22:50 +0200
  [PATCH 3.13.y-ckt 42/53] drm/radeon: add a dpm quirk for Sapphire Radeon R9 270X 2GB GDDR5 Kamal Mostafa <kamal@canonical.com> - 2015-08-06 22:50 +0200
  [PATCH 3.13.y-ckt 39/53] ARC: make sure instruction_pointer() returns unsigned value Kamal Mostafa <kamal@canonical.com> - 2015-08-06 22:50 +0200
  [PATCH 3.13.y-ckt 23/53] iio: DAC: ad5624r_spi: fix bit shift of output data value Kamal Mostafa <kamal@canonical.com> - 2015-08-06 22:50 +0200
  [PATCH 3.13.y-ckt 14/53] ext4: fix reservation release on invalidatepage for delalloc fs Kamal Mostafa <kamal@canonical.com> - 2015-08-06 22:50 +0200
  [PATCH 3.13.y-ckt 07/53] x86/nmi/64: Reorder nested NMI checks Kamal Mostafa <kamal@canonical.com> - 2015-08-06 23:00 +0200
  [PATCH 3.13.y-ckt 21/53] freeing unlinked file indefinitely delayed Kamal Mostafa <kamal@canonical.com> - 2015-08-06 23:00 +0200
  [PATCH 3.13.y-ckt 08/53] x86/nmi/64: Use DF to avoid userspace RSP confusing nested NMI detection Kamal Mostafa <kamal@canonical.com> - 2015-08-06 23:00 +0200
  [PATCH 3.13.y-ckt 16/53] ext4: correctly migrate a file with a hole at the beginning Kamal Mostafa <kamal@canonical.com> - 2015-08-06 23:00 +0200
  [PATCH 3.13.y-ckt 06/53] x86/nmi/64: Improve nested NMI comments Kamal Mostafa <kamal@canonical.com> - 2015-08-06 23:00 +0200
  [PATCH 3.13.y-ckt 05/53] x86/nmi/64: Switch stacks on userspace NMI entry Kamal Mostafa <kamal@canonical.com> - 2015-08-06 23:00 +0200
  [PATCH 3.13.y-ckt 20/53] 9p: don't leave a half-initialized inode sitting around Kamal Mostafa <kamal@canonical.com> - 2015-08-06 23:00 +0200
  [PATCH 3.13.y-ckt 12/53] Btrfs: fix race between caching kthread and returning inode to inode cache Kamal Mostafa <kamal@canonical.com> - 2015-08-06 23:00 +0200
  [PATCH 3.13.y-ckt 03/53] x86/nmi: Enable nested do_nmi handling for 64-bit kernels Kamal Mostafa <kamal@canonical.com> - 2015-08-06 23:00 +0200
  [PATCH 3.13.y-ckt 18/53] ACPI / PNP: Reserve ACPI resources at the fs_initcall_sync stage Kamal Mostafa <kamal@canonical.com> - 2015-08-06 23:00 +0200
  [PATCH 3.13.y-ckt 17/53] ext4: replace open coded nofail allocation in ext4_free_blocks() Kamal Mostafa <kamal@canonical.com> - 2015-08-06 23:00 +0200
  [PATCH 3.13.y-ckt 09/53] KEYS: ensure we free the assoc array edit if edit is valid Kamal Mostafa <kamal@canonical.com> - 2015-08-06 23:00 +0200

csiph-web