|
@@ -1956,6 +1956,8 @@ static int btrfs_calc_avail_data_space(struct btrfs_root *root, u64 *free_bytes)
|
|
|
* 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 *dentry, struct kstatfs *buf)
|
|
|
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 *dentry, struct kstatfs *buf)
|
|
|
}
|
|
|
}
|
|
|
}
|
|
|
+ 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 *dentry, struct kstatfs *buf)
|
|
|
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;
|