[Devel] [PATCH vz9 v2 1/2] overlayfs: fix lowerpaths handling in dynamic path resolving

Konstantin Khorenko khorenko at virtuozzo.com
Sat Jul 20 01:07:56 MSK 2024


RedHat in RHEL9.4 has backported overlayfs data-only lower layers
feature (ms commit 37ebf056d6cf ("ovl: introduce data-only lower
layers")), so we have to adjust our dynamic path resolving feature.

Additionally store number of lowerpaths as it now differs from saved
number of lowerstacks due to data-only lower layers presence.

Fixes: 5f2c7b5e4d33 ("overlayfs: add dynamic path resolving in mount
options")
https://virtuozzo.atlassian.net/browse/PSBM-157244

Signed-off-by: Konstantin Khorenko <khorenko at virtuozzo.com>
---
 fs/overlayfs/overlayfs.h |  2 +-
 fs/overlayfs/ovl_entry.h | 13 ++++++++++++-
 fs/overlayfs/super.c     |  9 ++++++---
 fs/overlayfs/util.c      | 21 ++++++++++++++++++---
 4 files changed, 37 insertions(+), 8 deletions(-)

v2 changes:
 * ovl_free_entry() appeared to be not the only way to free ovl_entry,
   the second function is ovl_free_inode(), so include the kfree() there
   as well
 * create a single function ovl_stacks_put() for both lowerstack and
   lowerpaths put and rename ovl_stack_put() to prevent desync in the
   future

diff --git a/fs/overlayfs/overlayfs.h b/fs/overlayfs/overlayfs.h
index 163858e97e89..2e7aa23eb755 100644
--- a/fs/overlayfs/overlayfs.h
+++ b/fs/overlayfs/overlayfs.h
@@ -402,7 +402,7 @@ bool ovl_index_all(struct super_block *sb);
 bool ovl_verify_lower(struct super_block *sb);
 struct ovl_path *ovl_stack_alloc(unsigned int n);
 void ovl_stack_cpy(struct ovl_path *dst, struct ovl_path *src, unsigned int n);
-void ovl_stack_put(struct ovl_path *stack, unsigned int n);
+void ovl_stacks_put(struct ovl_entry *oe);
 void ovl_stack_free(struct ovl_path *stack, unsigned int n);
 struct ovl_entry *ovl_alloc_entry(unsigned int numlower);
 void ovl_free_entry(struct ovl_entry *oe);
diff --git a/fs/overlayfs/ovl_entry.h b/fs/overlayfs/ovl_entry.h
index f30de89e1f72..9d95ccdb3e3f 100644
--- a/fs/overlayfs/ovl_entry.h
+++ b/fs/overlayfs/ovl_entry.h
@@ -52,8 +52,9 @@ struct ovl_path {
 };
 
 struct ovl_entry {
+	unsigned int __numlowerpaths;
 	unsigned int __numlower;
-	struct path *lowerpaths;
+	struct path *__lowerpaths;
 	struct ovl_path __lowerstack[];
 };
 
@@ -125,6 +126,16 @@ static inline bool ovl_should_sync(struct ovl_fs *ofs)
 	return !ofs->config.ovl_volatile;
 }
 
+static inline unsigned int ovl_numlowerpaths(struct ovl_entry *oe)
+{
+	return oe ? oe->__numlowerpaths : 0;
+}
+
+static inline struct path *ovl_lowerpaths(struct ovl_entry *oe)
+{
+	return ovl_numlowerpaths(oe) ? oe->__lowerpaths : NULL;
+}
+
 static inline unsigned int ovl_numlower(struct ovl_entry *oe)
 {
 	return oe ? oe->__numlower : 0;
diff --git a/fs/overlayfs/super.c b/fs/overlayfs/super.c
index e9e8602291e0..2aeec05c1a34 100644
--- a/fs/overlayfs/super.c
+++ b/fs/overlayfs/super.c
@@ -213,6 +213,7 @@ static void ovl_free_inode(struct inode *inode)
 	struct ovl_inode *oi = OVL_I(inode);
 
 	kfree(oi->redirect);
+	kfree(ovl_lowerpaths(oi->oe));
 	kfree(oi->oe);
 	mutex_destroy(&oi->lock);
 	kmem_cache_free(ovl_inode_cachep, oi);
@@ -223,7 +224,7 @@ static void ovl_destroy_inode(struct inode *inode)
 	struct ovl_inode *oi = OVL_I(inode);
 
 	dput(oi->__upperdentry);
-	ovl_stack_put(ovl_lowerstack(oi->oe), ovl_numlower(oi->oe));
+	ovl_stacks_put(oi->oe);
 	if (S_ISDIR(inode->i_mode))
 		ovl_dir_cache_free(inode);
 	else
@@ -386,7 +387,8 @@ static int ovl_show_options(struct seq_file *m, struct dentry *dentry)
 	struct ovl_entry *oe = OVL_E(sb->s_root);
 
 	if (ovl_dyn_path_opts) {
-		print_paths_option(m, "lowerdir", oe->lowerpaths, ovl_numlower(oe));
+		print_paths_option(m, "lowerdir", ovl_lowerpaths(oe),
+				   ovl_numlowerpaths(oe));
 		if (ofs->config.upperdir) {
 			print_path_option(m, "upperdir", &ofs->upperpath);
 			print_path_option(m, "workdir", &ofs->workbasepath);
@@ -1854,7 +1856,8 @@ static struct ovl_entry *ovl_get_lowerstack(struct super_block *sb,
 		lowerstack[i].dentry = dget(stack[i].dentry);
 		lowerstack[i].layer = &ofs->layers[i+1];
 	}
-	oe->lowerpaths = stack;
+	oe->__numlowerpaths = numlower;
+	oe->__lowerpaths = stack;
 
 out:
 	return oe;
diff --git a/fs/overlayfs/util.c b/fs/overlayfs/util.c
index 3676eaa83f7d..21acc780ebfc 100644
--- a/fs/overlayfs/util.c
+++ b/fs/overlayfs/util.c
@@ -100,7 +100,7 @@ void ovl_stack_cpy(struct ovl_path *dst, struct ovl_path *src, unsigned int n)
 		dget(src[i].dentry);
 }
 
-void ovl_stack_put(struct ovl_path *stack, unsigned int n)
+void __ovl_stack_put(struct ovl_path *stack, unsigned int n)
 {
 	unsigned int i;
 
@@ -110,10 +110,24 @@ void ovl_stack_put(struct ovl_path *stack, unsigned int n)
 
 void ovl_stack_free(struct ovl_path *stack, unsigned int n)
 {
-	ovl_stack_put(stack, n);
+	__ovl_stack_put(stack, n);
 	kfree(stack);
 }
 
+void __ovl_lowerpaths_put(struct path *lowerpaths, unsigned int n)
+{
+	unsigned int i;
+
+	for (i = 0; i < n; i++)
+		path_put(&lowerpaths[i]);
+}
+
+void ovl_stacks_put(struct ovl_entry *oe)
+{
+	__ovl_stack_put(ovl_lowerstack(oe), ovl_numlower(oe));
+	__ovl_lowerpaths_put(ovl_lowerpaths(oe), ovl_numlowerpaths(oe));
+}
+
 struct ovl_entry *ovl_alloc_entry(unsigned int numlower)
 {
 	size_t size = offsetof(struct ovl_entry, __lowerstack[numlower]);
@@ -127,7 +141,8 @@ struct ovl_entry *ovl_alloc_entry(unsigned int numlower)
 
 void ovl_free_entry(struct ovl_entry *oe)
 {
-	ovl_stack_put(ovl_lowerstack(oe), ovl_numlower(oe));
+	ovl_stacks_put(oe);
+	kfree(ovl_lowerpaths(oe));
 	kfree(oe);
 }
 
-- 
2.43.5



More information about the Devel mailing list