Skip to content

Commit

Permalink
ovl: stack file ops
Browse files Browse the repository at this point in the history
Implement file operations on a regular overlay file.  The underlying file
is opened separately and cached in ->private_data.

It might be worth making an exception for such files when accounting in
nr_file to confirm to userspace expectations.  We are only adding a small
overhead (248bytes for the struct file) since the real inode and dentry are
pinned by overlayfs anyway.

This patch doesn't have any effect, since the vfs will use d_real() to find
the real underlying file to open.  The patch at the end of the series will
actually enable this functionality.

AV: make it use open_with_fake_path(), don't mess with override_creds

SzM: still need to mess with override_creds() until no fs uses
current_cred() in their open method.

Signed-off-by: Miklos Szeredi <mszeredi@redhat.com>
Signed-off-by: Al Viro <viro@zeniv.linux.org.uk>
  • Loading branch information
Miklos Szeredi committed Jul 18, 2018
1 parent e8c985b commit d1d04ef
Show file tree
Hide file tree
Showing 4 changed files with 82 additions and 2 deletions.
4 changes: 2 additions & 2 deletions fs/overlayfs/Makefile
Original file line number Diff line number Diff line change
Expand Up @@ -4,5 +4,5 @@

obj-$(CONFIG_OVERLAY_FS) += overlay.o

overlay-objs := super.o namei.o util.o inode.o dir.o readdir.o copy_up.o \
export.o
overlay-objs := super.o namei.o util.o inode.o file.o dir.o readdir.o \
copy_up.o export.o
76 changes: 76 additions & 0 deletions fs/overlayfs/file.c
Original file line number Diff line number Diff line change
@@ -0,0 +1,76 @@
/*
* Copyright (C) 2017 Red Hat, Inc.
*
* This program is free software; you can redistribute it and/or modify it
* under the terms of the GNU General Public License version 2 as published by
* the Free Software Foundation.
*/

#include <linux/cred.h>
#include <linux/file.h>
#include <linux/xattr.h>
#include "overlayfs.h"

static struct file *ovl_open_realfile(const struct file *file)
{
struct inode *inode = file_inode(file);
struct inode *upperinode = ovl_inode_upper(inode);
struct inode *realinode = upperinode ?: ovl_inode_lower(inode);
struct file *realfile;
const struct cred *old_cred;

old_cred = ovl_override_creds(inode->i_sb);
realfile = open_with_fake_path(&file->f_path, file->f_flags | O_NOATIME,
realinode, current_cred());
revert_creds(old_cred);

pr_debug("open(%p[%pD2/%c], 0%o) -> (%p, 0%o)\n",
file, file, upperinode ? 'u' : 'l', file->f_flags,
realfile, IS_ERR(realfile) ? 0 : realfile->f_flags);

return realfile;
}

static int ovl_open(struct inode *inode, struct file *file)
{
struct dentry *dentry = file_dentry(file);
struct file *realfile;
int err;

err = ovl_open_maybe_copy_up(dentry, file->f_flags);
if (err)
return err;

/* No longer need these flags, so don't pass them on to underlying fs */
file->f_flags &= ~(O_CREAT | O_EXCL | O_NOCTTY | O_TRUNC);

realfile = ovl_open_realfile(file);
if (IS_ERR(realfile))
return PTR_ERR(realfile);

file->private_data = realfile;

return 0;
}

static int ovl_release(struct inode *inode, struct file *file)
{
fput(file->private_data);

return 0;
}

static loff_t ovl_llseek(struct file *file, loff_t offset, int whence)
{
struct inode *realinode = ovl_inode_real(file_inode(file));

return generic_file_llseek_size(file, offset, whence,
realinode->i_sb->s_maxbytes,
i_size_read(realinode));
}

const struct file_operations ovl_file_operations = {
.open = ovl_open,
.release = ovl_release,
.llseek = ovl_llseek,
};
1 change: 1 addition & 0 deletions fs/overlayfs/inode.c
Original file line number Diff line number Diff line change
Expand Up @@ -535,6 +535,7 @@ static void ovl_fill_inode(struct inode *inode, umode_t mode, dev_t rdev,
switch (mode & S_IFMT) {
case S_IFREG:
inode->i_op = &ovl_file_inode_operations;
inode->i_fop = &ovl_file_operations;
break;

case S_IFDIR:
Expand Down
3 changes: 3 additions & 0 deletions fs/overlayfs/overlayfs.h
Original file line number Diff line number Diff line change
Expand Up @@ -377,6 +377,9 @@ struct dentry *ovl_create_real(struct inode *dir, struct dentry *newdentry,
int ovl_cleanup(struct inode *dir, struct dentry *dentry);
struct dentry *ovl_create_temp(struct dentry *workdir, struct ovl_cattr *attr);

/* file.c */
extern const struct file_operations ovl_file_operations;

/* copy_up.c */
int ovl_copy_up(struct dentry *dentry);
int ovl_copy_up_flags(struct dentry *dentry, int flags);
Expand Down

0 comments on commit d1d04ef

Please sign in to comment.