|
@@ -145,6 +145,9 @@ int ovl_getattr(const struct path *path, struct kstat *stat,
|
|
|
bool samefs = ovl_same_sb(dentry->d_sb);
|
|
|
struct ovl_layer *lower_layer = NULL;
|
|
|
int err;
|
|
|
+ bool metacopy_blocks = false;
|
|
|
+
|
|
|
+ metacopy_blocks = ovl_is_metacopy_dentry(dentry);
|
|
|
|
|
|
type = ovl_path_real(dentry, &realpath);
|
|
|
old_cred = ovl_override_creds(dentry->d_sb);
|
|
@@ -166,7 +169,8 @@ int ovl_getattr(const struct path *path, struct kstat *stat,
|
|
|
lower_layer = ovl_layer_lower(dentry);
|
|
|
} else if (OVL_TYPE_ORIGIN(type)) {
|
|
|
struct kstat lowerstat;
|
|
|
- u32 lowermask = STATX_INO | (!is_dir ? STATX_NLINK : 0);
|
|
|
+ u32 lowermask = STATX_INO | STATX_BLOCKS |
|
|
|
+ (!is_dir ? STATX_NLINK : 0);
|
|
|
|
|
|
ovl_path_lower(dentry, &realpath);
|
|
|
err = vfs_getattr(&realpath, &lowerstat,
|
|
@@ -195,6 +199,35 @@ int ovl_getattr(const struct path *path, struct kstat *stat,
|
|
|
stat->ino = lowerstat.ino;
|
|
|
lower_layer = ovl_layer_lower(dentry);
|
|
|
}
|
|
|
+
|
|
|
+ /*
|
|
|
+ * If we are querying a metacopy dentry and lower
|
|
|
+ * dentry is data dentry, then use the blocks we
|
|
|
+ * queried just now. We don't have to do additional
|
|
|
+ * vfs_getattr(). If lower itself is metacopy, then
|
|
|
+ * additional vfs_getattr() is unavoidable.
|
|
|
+ */
|
|
|
+ if (metacopy_blocks &&
|
|
|
+ realpath.dentry == ovl_dentry_lowerdata(dentry)) {
|
|
|
+ stat->blocks = lowerstat.blocks;
|
|
|
+ metacopy_blocks = false;
|
|
|
+ }
|
|
|
+ }
|
|
|
+
|
|
|
+ if (metacopy_blocks) {
|
|
|
+ /*
|
|
|
+ * If lower is not same as lowerdata or if there was
|
|
|
+ * no origin on upper, we can end up here.
|
|
|
+ */
|
|
|
+ struct kstat lowerdatastat;
|
|
|
+ u32 lowermask = STATX_BLOCKS;
|
|
|
+
|
|
|
+ ovl_path_lowerdata(dentry, &realpath);
|
|
|
+ err = vfs_getattr(&realpath, &lowerdatastat,
|
|
|
+ lowermask, flags);
|
|
|
+ if (err)
|
|
|
+ goto out;
|
|
|
+ stat->blocks = lowerdatastat.blocks;
|
|
|
}
|
|
|
}
|
|
|
|