Skip to contentSkip to conversation

overlayfs: v13 port attempt to kernel 3.5

overlayfs/port Andrew Watts 3 participants 6 messages Aug 16, 2012 – Aug 20, 2012 VFS

lore
Share & tools
lore
#0 lore raw

Hi.

I am trying to port the recent work of Andy Whitcroft (for kernel 3.4) to kernel 3.5.

Due to changes in *__dentry_open in fs/open.c and to the inode_operations struct, overlayfs v13 doesn't apply cleanly.

I am attaching consolidated diffs for both fs/open.c and include/linux/fs.h, which contain the substantive changes I made to Andy's work, for review.

Please point out any errors I might have made.

I've not attached the changes I made to the patches against the Locking and vfs.txt documentation as those weren't substantive.

Many thanks,

~ Andy

overlayfs2/fs/open.c +41 -23
@@ -667,7 +667,7 @@ int open_check_o_direct(struct file *f)
 	return 0;
 }
 
-static struct file *do_dentry_open(struct dentry *dentry, struct vfsmount *mnt,
+static struct file *do_dentry_open(struct path *path,
 				   struct file *f,
 				   int (*open)(struct inode *, struct file *),
 				   const struct cred *cred)
@@ -676,15 +676,16 @@ static struct file *do_dentry_open(struc
 	struct inode *inode;
 	int error;
 
+	path_get(path);
 	f->f_mode = OPEN_FMODE(f->f_flags) | FMODE_LSEEK |
 				FMODE_PREAD | FMODE_PWRITE;
 
 	if (unlikely(f->f_flags & O_PATH))
 		f->f_mode = FMODE_PATH;
 
-	inode = dentry->d_inode;
+	inode = path->dentry->d_inode;
 	if (f->f_mode & FMODE_WRITE) {
-		error = __get_file_write_access(inode, mnt);
+		error = __get_file_write_access(inode, path->mnt);
 		if (error)
 			goto cleanup_file;
 		if (!special_file(inode->i_mode))
@@ -692,8 +693,7 @@ static struct file *do_dentry_open(struc
 	}
 
 	f->f_mapping = inode->i_mapping;
-	f->f_path.dentry = dentry;
-	f->f_path.mnt = mnt;
+	f->f_path = *path;
 	f->f_pos = 0;
 	file_sb_list_add(f, inode->i_sb);
 
@@ -740,24 +740,23 @@ cleanup_all:
 			 * here, so just reset the state.
 			 */
 			file_reset_write(f);
-			mnt_drop_write(mnt);
+			mnt_drop_write(path->mnt);
 		}
 	}
 	file_sb_list_del(f);
 	f->f_path.dentry = NULL;
 	f->f_path.mnt = NULL;
 cleanup_file:
-	dput(dentry);
-	mntput(mnt);
+	path_put(path);
 	return ERR_PTR(error);
 }
 
-static struct file *__dentry_open(struct dentry *dentry, struct vfsmount *mnt,
+static struct file *__dentry_open(struct path *path,
 				struct file *f,
 				int (*open)(struct inode *, struct file *),
 				const struct cred *cred)
 {
-	struct file *res = do_dentry_open(dentry, mnt, f, open, cred);
+	struct file *res = do_dentry_open(path, mnt, f, open, cred);
 	if (!IS_ERR(res)) {
 		int error = open_check_o_direct(f);
 		if (error) {
@@ -792,14 +791,14 @@ static struct file *__dentry_open(struct
 struct file *lookup_instantiate_filp(struct nameidata *nd, struct dentry *dentry,
 		int (*open)(struct inode *, struct file *))
 {
+	struct path path = { .dentry = dentry, .mnt = nd->path.mnt };
 	const struct cred *cred = current_cred();
 
 	if (IS_ERR(nd->intent.open.file))
 		goto out;
 	if (IS_ERR(dentry))
 		goto out_err;
-	nd->intent.open.file = __dentry_open(dget(dentry), mntget(nd->path.mnt),
-					     nd->intent.open.file,
+	nd->intent.open.file = __dentry_open(&path, nd->intent.open.file,
 					     open, cred);
 out:
 	return nd->intent.open.file;
@@ -831,9 +830,7 @@ struct file *nameidata_to_filp(struct na
 	} else {
 		struct file *res;
 
-		path_get(&nd->path);
-		res = do_dentry_open(nd->path.dentry, nd->path.mnt,
-				     filp, NULL, cred);
+		res = vfs_open(&nd->path, filp, cred);
 		if (!IS_ERR(res)) {
 			int error;
 
@@ -860,27 +857,48 @@ struct file *nameidata_to_filp(struct na
 struct file *dentry_open(struct dentry *dentry, struct vfsmount *mnt, int flags,
 			 const struct cred *cred)
 {
-	int error;
 	struct file *f;
+	struct file *ret;
+	struct path path = { .dentry = dentry, .mnt = mnt };
 
 	validate_creds(cred);
 
 	/* We must always pass in a valid mount pointer. */
 	BUG_ON(!mnt);
 
-	error = -ENFILE;
+	ret = ERR_PTR(-ENFILE);
 	f = get_empty_filp();
-	if (f == NULL) {
-		dput(dentry);
-		mntput(mnt);
-		return ERR_PTR(error);
+	if (f != NULL) {
+		f->f_flags = flags;
+		ret = vfs_open(&path, f, cred);
 	}
+	path_put(&path);
 
-	f->f_flags = flags;
-	return __dentry_open(dentry, mnt, f, NULL, cred);
+	return ret;
 }
 EXPORT_SYMBOL(dentry_open);
 
+/**
+ * vfs_open - open the file at the given path
+ * @path: path to open
+ * @filp: newly allocated file with f_flag initialized
+ * @cred: credentials to use
+ *
+ * Open the file.  If successful, the returned file will have acquired
+ * an additional reference for path.
+ */
+struct file *vfs_open(struct path *path, struct file *filp,
+		      const struct cred *cred)
+{
+	struct inode *inode = path->dentry->d_inode;
+
+	if (inode->i_op->open)
+		return inode->i_op->open(path->dentry, filp, cred);
+	else
+		return __dentry_open(path, filp, NULL, cred);
+}
+EXPORT_SYMBOL(vfs_open);
+
 static void __put_unused_fd(struct files_struct *files, unsigned int fd)
 {
 	struct fdtable *fdt = files_fdtable(files);
overlayfs2/include/linux/fs.h +15 -0
@@ -499,6 +499,12 @@ struct iattr {
  */
 #include <linux/quota.h>
 
+/*
+ * Maximum number of layers of fs stack.  Needs to be limited to
+ * prevent kernel stack overflow
+ */
+#define FILESYSTEM_MAX_STACK_DEPTH 2
+
 /** 
  * enum positive_aop_returns - aop return codes with specific semantics
  *
@@ -1542,6 +1548,11 @@ struct super_block {
 
 	/* Being remounted read-only */
 	int s_readonly_remount;
+
+	/*
+	 * Indicates how deep in a filesystem stack this SB is
+	 */
+	int s_stack_depth;
 };
 
 /* superblock cache pruning functions */
@@ -1693,6 +1704,8 @@ struct inode_operations {
 	int (*fiemap)(struct inode *, struct fiemap_extent_info *, u64 start,
 		      u64 len);
 	int (*update_time)(struct inode *, struct timespec *, int);
+	struct file *(*open) (struct dentry *, struct file *,
+			      const struct cred *);
 } ____cacheline_aligned;
 
 struct seq_file;
@@ -2057,6 +2070,7 @@ extern long do_sys_open(int dfd, const c
 extern struct file *filp_open(const char *, int, umode_t);
 extern struct file *file_open_root(struct dentry *, struct vfsmount *,
 				   const char *, int);
+extern struct file *vfs_open(struct path *, struct file *, const struct cred *);
 extern struct file * dentry_open(struct dentry *, struct vfsmount *, int,
 				 const struct cred *);
 extern int filp_close(struct file *, fl_owner_t id);
@@ -2249,6 +2263,7 @@ extern sector_t bmap(struct inode *, sec
 #endif
 extern int notify_change(struct dentry *, struct iattr *);
 extern int inode_permission(struct inode *, int);
+extern int inode_only_permission(struct inode *, int);
 extern int generic_permission(struct inode *, int);
 
 static inline bool execute_ok(struct inode *inode)
#1 lore raw
Quoted 11 lines · Andrew Watts

Hi.

I am trying to port the recent work of Andy Whitcroft (for kernel 3.4) to kernel 3.5.

Due to changes in *__dentry_open in fs/open.c and to the inode_operations struct, overlayfs v13 doesn't apply cleanly.

I am attaching consolidated diffs for both fs/open.c and include/linux/fs.h, which contain the substantive changes I made to Andy's work, for review.

Quoted 7 lines

Please point out any errors I might have made.

I've not attached the changes I made to the patches against the Locking and vfs.txt documentation as those weren't substantive.

Many thanks,

Might be easier to collect/extract commits listed in [1]?

If you are on Ubuntu: Check mainline kernels in [2] (quantal) and [3] (precise).

- Sedat -

[1] http://kernel.ubuntu.com/git?p=ubuntu/ubuntu-quantal.git&a=search&h=refs/tags/Ubuntu-3.5.0-11.11&st=commit&s=overlayfs
[2] http://kernel.ubuntu.com/~kernel-ppa/mainline/v3.5.2-quantal/
[3] https://launchpad.net/~ubuntu-x-swat/+archive/q-lts-backport/+packages

Quoted 2 lines

~ Andy

#2 lore raw
Quoted 6 lines · Sedat Dilek

Might be easier to collect/extract commits listed in [1]?

If you are on Ubuntu: Check mainline kernels in [2] (quantal) and [3] (precise).

- Sedat -

That indeed was much easier and I have it working great on 3.5.2. Many thanks for the link to the git repo.

It would be nice to see overlayfs ack'd into mainline at some point. Is there any chance of this?

~ Andy

#3 lore raw
Quoted 4 lines · Andrew Watts
Quoted 4 lines

Might be easier to collect/extract commits listed in [1]?

If you are on Ubuntu: Check mainline kernels in [2] (quantal) and [3] (precise).

Quoted 9 lines
Quoted 2 lines

- Sedat -

That indeed was much easier and I have it working great on 3.5.2. Many thanks for the link to the git repo.

It would be nice to see overlayfs ack'd into mainline at some point. Is there any chance of this?

[ TO Linus and CC LKML and Daniel (maintainer of debian-live project) ] ( I could or should CC even more folks... )

Hi,

There exists a lot of threads on LKML and here on linux-fsdevel ML about the topic "Union FileSystems".
In some of these discussions you will read about pros and cons about "OverlayFS".
More precisely: Endless or even fruitless(?) discussions as after so many years there is no upstream solution in sight.

Unfortunately, some kernel developers still didn't realize that ***Linux live-systems*** and ***Embedded Linux*** are IMHO two examples for great "success stories" of Linux!

To run both successfully, you need this fundamental filesystem components:

(1) a "Compressed Read-Only File System" (like SquashFS)
(2) a "Union FileSystem" (like AUFS, OverlayFS, "Union Mounts", etc.)

Someday we got all happy with SquashFS accepted in upstream - this was the first success!

The other part to run a Linux live-system is a "Union FileSystem" - this part is missing (speaking of upstream).

Since years AUFS seems to be the choice #1 in a lot of distros to workaround the problem.
NOTE: AUFS was rejected from upstream (to say not accepted).

I talked with so many distro kernel-teams and especially with Daniel Baumann (maintainer of debian-live project):
The responsibles say if OverlayFS is upstreamed we will take it else NOPE followed by an "OkThxBye" from impolite people!
[Q] So, why the hell do you include AUFS (not upstreamed) but not OverlayFS (also not upstreamed) :-)?

As a sidenote, Linux-v3.6-rc1 got some first bits of "Union Mounts" which was chosen as the ***preferred*** (longterm!) upstream solution. But this special topic seems to me to get a ***never-ending story***. Maintainers changed - new developers carried (or not?) - patchsets were sent to MLs but got never really reviewed or finished. YES, ***finished***!
I remember the "nVidia, F*** you!" video, not because of the famous(?) F-word, but the part where Linus talks about "visions" VS. "I like to see/get stuff finished".

One thing is a bit strange to me: Where does the development of "Union Mounts" happen?
Normally, someone would assume - as this is gonna be a part of the Linux kernel - this happens in the public.
I don't know of a repository - do you know?

Personally, I would like to see OverlayFS as a or the "small" solution besides $union-filesystem-preferred-by-upstream.
OverlayFS is pretty small - a very good choice for embedded Linux systems.

After looking into the pile #1 of VFS pull-request for Linux-v3.6-rc1, I noticed this...

"* preparatory bits from unionmount series (from dhowells)."

So, I talked with some responsibles on #ubuntu-kernel and this was appreciated (and lead to some adaptation of the OverlayFS code and resulted in v14).
On the one hand it is nice to see that something happens in upstream, on the other no one knows when "Union Mounts" will get a "working" solution (to say "finished").

Just to name two projects:
Ubuntu (Linux distribution) and OpenWrt (Linux embedded system) use OverlayFS in their live-system and build-system environments.

But... I am a person which is *not* in charge or responsible for the development in the (near) future - nor in the position to decide.

I did some early testing (against linux-next) and contributed a few lines. After that I am regularly testing OverlayFS since v11 till present.

Anyway, I would be really happy to see any working ***upstream solution***!

It might be worth to escalate this topic to Linus directly (Oops, I did?).

I hope people rest calm and do NOT throw me S*** and F*** words - be always a Gentleman :-)!

My 0.02EUR.

- Sedat -

Quoted 1 line

~ Andy

#4 lore raw

Sedat Dilek:

Quoted 6 lines

The other part to run a Linux live-system is a "Union FileSystem" - this part is missing (speaking of upstream).

Since years AUFS seems to be the choice #1 in a lot of distros to workaround the problem.
NOTE: AUFS was rejected from upstream (to say not accepted).

Exactly.
The reason was that linux rejects all union-type filesystems but UnionMount (which is union-type mount).
Later, the development of UnionMount seems to be almost stopped. The essential design of overlayfs is based upon UnionMount, and I have pointed out several issues such as
- for users, the inode number may change silently. eg. copy-up.
- hardlinks may break by copy-up.
- read(2) may get an obsoleted filedata (fstat(2) for metadata too).
- fcntl(F_SETLK) may be broken by copy-up.
- unnecessary copy-up may happen, for example mmap(MAP_PRIVATE) after open(O_RDWR).
- Later I noticed one more thing. /proc/PID/{fd/,exe} may not work correctly for overlayfs ...
- etc...
They are called "unPOSIXy behavior", and unforunately many of them are NOT seem to be addressed in recent patches either.

Also I have posted
If the development of UnionMount is really stopped, then I'd ask people to consider merging aufs as well as overlayfs.
but I am not sure whether LKML people are still waiting for UnionMount and rejecting aufs.

J. R. Okajima

#5 lore raw
Quoted 27 lines · J. R. Okajima

Sedat Dilek:

Quoted 6 lines

The other part to run a Linux live-system is a "Union FileSystem" - this part is missing (speaking of upstream).

Since years AUFS seems to be the choice #1 in a lot of distros to workaround the problem.
NOTE: AUFS was rejected from upstream (to say not accepted).

Exactly.
The reason was that linux rejects all union-type filesystems but UnionMount (which is union-type mount).
Later, the development of UnionMount seems to be almost stopped. The essential design of overlayfs is based upon UnionMount, and I have pointed out several issues such as
- for users, the inode number may change silently. eg. copy-up.
- hardlinks may break by copy-up.
- read(2) may get an obsoleted filedata (fstat(2) for metadata too).
- fcntl(F_SETLK) may be broken by copy-up.
- unnecessary copy-up may happen, for example mmap(MAP_PRIVATE) after open(O_RDWR).
- Later I noticed one more thing. /proc/PID/{fd/,exe} may not work correctly for overlayfs ...
- etc...
They are called "unPOSIXy behavior", and unforunately many of them are NOT seem to be addressed in recent patches either.

Quoted 6 lines

Also I have posted
If the development of UnionMount is really stopped, then I'd ask people to consider merging aufs as well as overlayfs.
but I am not sure whether LKML people are still waiting for UnionMount and rejecting aufs.

Okajima san /o\,

thanks for the short summary of history, quick overview of AUFS features and OverlayFS design.
I can't say much about AUFS, I just simply used it for so long.

But it looks like you agree with me that something should happen in case of Union Filesystem's.
Anyway, as said I would like to see an upstream solution in the near future. If this will be AUFS, I am OK with that decision.

Regards,
- Sedat -

Quoted 1 line

J. R. Okajima