Skip to contentSkip to conversation

Patch "btrfs: statfs: report zero available if metadata are exhausted" has been added to the 4.4-stable tree

PATCH [email protected] 1 participant 1 message Mar 1, 2016

Subsystems (2)
lore
Share & tools
lore

[email protected]

author maintainer Applied
#0 lore raw

This is a note to let you know that I've just added the patch titled

btrfs: statfs: report zero available if metadata are exhausted

to the 4.4-stable tree which can be found at:
http://www.kernel.org/git/?p=linux/kernel/git/stable/stable-queue.git;a=summary

The filename of the patch is:
btrfs-statfs-report-zero-available-if-metadata-are-exhausted.patch
and it can be found in the queue-4.4 subdirectory.

If you, or anyone else, feels it should not be added to the stable tree, please let <[email protected]> know about it.

Quoted 1 line

From ca8a51b3a979d57b082b14eda38602b7f52d81d1 Mon Sep 17 00:00:00 2001

From: David Sterba <[email protected]>
Date: Sat, 10 Oct 2015 17:59:53 +0200
Subject: btrfs: statfs: report zero available if metadata are exhausted

From: David Sterba <[email protected]>

commit ca8a51b3a979d57b082b14eda38602b7f52d81d1 upstream.

There is one ENOSPC case that's very confusing. There's Available greater than zero but no file operation succeds (besides removing files). This happens when the metadata are exhausted and there's no possibility to allocate another chunk.

In this scenario it's normal that there's still some space in the data chunk and the calculation in df reflects that in the Avail value.

To at least give some clue about the ENOSPC situation, let statfs report zero value in Avail, even if there's still data space available.

Current:
/dev/sdb1 4.0G 3.3G 719M 83% /mnt/test

New:
/dev/sdb1 4.0G 3.3G 0 100% /mnt/test

We calculate the remaining metadata space minus global reserve. If this is (supposedly) smaller than zero, there's no space. But this does not hold in practice, the exhausted state happens where's still some positive delta. So we apply some guesswork and compare the delta to a 4M threshold. (Practically observed delta was 2M.)

We probably cannot calculate the exact threshold value because this depends on the internal reservations requested by various operations, so some operations that consume a few metadata will succeed even if the Avail is zero. But this is better than the other way around.

---
 fs/btrfs/super.c |   24 ++++++++++++++++++++++++
 1 file changed, 24 insertions(+)
fs/btrfs/super.c +24 -0
@@ -1956,6 +1956,8 @@ static int btrfs_calc_avail_data_space(s
  * there are other factors that may change the result (like a new metadata
  * chunk).
  *
+ * If metadata is exhausted, f_bavail will be 0.
+ *
  * FIXME: not accurate for mixed block groups, total and free/used are ok,
  * available appears slightly larger.
  */
@@ -1967,11 +1969,13 @@ static int btrfs_statfs(struct dentry *d
 	struct btrfs_space_info *found;
 	u64 total_used = 0;
 	u64 total_free_data = 0;
+	u64 total_free_meta = 0;
 	int bits = dentry->d_sb->s_blocksize_bits;
 	__be32 *fsid = (__be32 *)fs_info->fsid;
 	unsigned factor = 1;
 	struct btrfs_block_rsv *block_rsv = &fs_info->global_block_rsv;
 	int ret;
+	u64 thresh = 0;
 
 	/*
 	 * holding chunk_muext to avoid allocating new chunks, holding
@@ -1997,6 +2001,8 @@ static int btrfs_statfs(struct dentry *d
 				}
 			}
 		}
+		if (found->flags & BTRFS_BLOCK_GROUP_METADATA)
+			total_free_meta += found->disk_total - found->disk_used;
 
 		total_used += found->disk_used;
 	}
@@ -2019,6 +2025,24 @@ static int btrfs_statfs(struct dentry *d
 	buf->f_bavail += div_u64(total_free_data, factor);
 	buf->f_bavail = buf->f_bavail >> bits;
 
+	/*
+	 * We calculate the remaining metadata space minus global reserve. If
+	 * this is (supposedly) smaller than zero, there's no space. But this
+	 * does not hold in practice, the exhausted state happens where's still
+	 * some positive delta. So we apply some guesswork and compare the
+	 * delta to a 4M threshold.  (Practically observed delta was ~2M.)
+	 *
+	 * We probably cannot calculate the exact threshold value because this
+	 * depends on the internal reservations requested by various
+	 * operations, so some operations that consume a few metadata will
+	 * succeed even if the Avail is zero. But this is better than the other
+	 * way around.
+	 */
+	thresh = 4 * 1024 * 1024;
+
+	if (total_free_meta - thresh < block_rsv->size)
+		buf->f_bavail = 0;
+
 	buf->f_type = BTRFS_SUPER_MAGIC;
 	buf->f_bsize = dentry->d_sb->s_blocksize;
 	buf->f_namelen = BTRFS_NAME_LEN;

Patches currently in stable-queue which might be from [email protected] are

queue-4.4/btrfs-add-missing-brelse-when-superblock-checksum-fails.patch queue-4.4/btrfs-statfs-report-zero-available-if-metadata-are-exhausted.patch queue-4.4/btrfs-igrab-inode-in-writepage.patch queue-4.4/btrfs-initialize-the-seq-counter-in-struct-btrfs_device.patch queue-4.4/btrfs-initialize-btrfs_root-highest_objectid-when-loading-tree-root-and-subvolume-roots.patch