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
--- a/overlayfs2/fs/open.c 2012-08-16 +++ b/overlayfs2/fs/open.c 2012-08-16 @@ -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); --- a/overlayfs2/include/linux/fs.h 2012-08-16 +++ b/overlayfs2/include/linux/fs.h 2012-08-16 @@ -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)