Donate to e Foundation | Murena handsets with /e/OS | Own a part of Murena! Learn more

Commit c353f88f authored by Linus Torvalds's avatar Linus Torvalds
Browse files
Pull overlayfs updates from Miklos Szeredi:
 "This fixes d_ino correctness in readdir, which brings overlayfs on par
  with normal filesystems regarding inode number semantics, as long as
  all layers are on the same filesystem.

  There are also some bug fixes, one in particular (random ioctl's
  shouldn't be able to modify lower layers) that touches some vfs code,
  but of course no-op for non-overlay fs"

* 'overlayfs-linus' of git://git.kernel.org/pub/scm/linux/kernel/git/mszeredi/vfs:
  ovl: fix false positive ESTALE on lookup
  ovl: don't allow writing ioctl on lower layer
  ovl: fix relatime for directories
  vfs: add flags to d_real()
  ovl: cleanup d_real for negative
  ovl: constant d_ino for non-merge dirs
  ovl: constant d_ino across copy up
  ovl: fix readdir error value
  ovl: check snprintf return
parents 6d8ef53e 939ae4ef
Loading
Loading
Loading
Loading
+1 −1
Original line number Diff line number Diff line
@@ -22,7 +22,7 @@ prototypes:
	struct vfsmount *(*d_automount)(struct path *path);
	int (*d_manage)(const struct path *, bool);
	struct dentry *(*d_real)(struct dentry *, const struct inode *,
				 unsigned int);
				 unsigned int, unsigned int);

locking rules:
		rename_lock	->d_lock	may block	rcu-walk
+1 −1
Original line number Diff line number Diff line
@@ -988,7 +988,7 @@ struct dentry_operations {
	struct vfsmount *(*d_automount)(struct path *);
	int (*d_manage)(const struct path *, bool);
	struct dentry *(*d_real)(struct dentry *, const struct inode *,
				 unsigned int);
				 unsigned int, unsigned int);
};

  d_revalidate: called when the VFS needs to revalidate a dentry. This
+17 −4
Original line number Diff line number Diff line
@@ -1570,11 +1570,24 @@ EXPORT_SYMBOL(bmap);
static void update_ovl_inode_times(struct dentry *dentry, struct inode *inode,
			       bool rcu)
{
	if (!rcu) {
		struct inode *realinode = d_real_inode(dentry);
	struct dentry *upperdentry;

		if (unlikely(inode != realinode) &&
		    (!timespec_equal(&inode->i_mtime, &realinode->i_mtime) ||
	/*
	 * Nothing to do if in rcu or if non-overlayfs
	 */
	if (rcu || likely(!(dentry->d_flags & DCACHE_OP_REAL)))
		return;

	upperdentry = d_real(dentry, NULL, 0, D_REAL_UPPER);

	/*
	 * If file is on lower then we can't update atime, so no worries about
	 * stale mtime/ctime.
	 */
	if (upperdentry) {
		struct inode *realinode = d_inode(upperdentry);

		if ((!timespec_equal(&inode->i_mtime, &realinode->i_mtime) ||
		     !timespec_equal(&inode->i_ctime, &realinode->i_ctime))) {
			inode->i_mtime = realinode->i_mtime;
			inode->i_ctime = realinode->i_ctime;
+2 −0
Original line number Diff line number Diff line
@@ -71,8 +71,10 @@ extern void __init mnt_init(void);

extern int __mnt_want_write(struct vfsmount *);
extern int __mnt_want_write_file(struct file *);
extern int mnt_want_write_file_path(struct file *);
extern void __mnt_drop_write(struct vfsmount *);
extern void __mnt_drop_write_file(struct file *);
extern void mnt_drop_write_file_path(struct file *);

/*
 * fs_struct.c
+61 −3
Original line number Diff line number Diff line
@@ -431,13 +431,18 @@ int __mnt_want_write_file(struct file *file)
}

/**
 * mnt_want_write_file - get write access to a file's mount
 * mnt_want_write_file_path - get write access to a file's mount
 * @file: the file who's mount on which to take a write
 *
 * This is like mnt_want_write, but it takes a file and can
 * do some optimisations if the file is open for write already
 *
 * Called by the vfs for cases when we have an open file at hand, but will do an
 * inode operation on it (important distinction for files opened on overlayfs,
 * since the file operations will come from the real underlying file, while
 * inode operations come from the overlay).
 */
int mnt_want_write_file(struct file *file)
int mnt_want_write_file_path(struct file *file)
{
	int ret;

@@ -447,6 +452,53 @@ int mnt_want_write_file(struct file *file)
		sb_end_write(file->f_path.mnt->mnt_sb);
	return ret;
}

static inline int may_write_real(struct file *file)
{
	struct dentry *dentry = file->f_path.dentry;
	struct dentry *upperdentry;

	/* Writable file? */
	if (file->f_mode & FMODE_WRITER)
		return 0;

	/* Not overlayfs? */
	if (likely(!(dentry->d_flags & DCACHE_OP_REAL)))
		return 0;

	/* File refers to upper, writable layer? */
	upperdentry = d_real(dentry, NULL, 0, D_REAL_UPPER);
	if (upperdentry && file_inode(file) == d_inode(upperdentry))
		return 0;

	/* Lower layer: can't write to real file, sorry... */
	return -EPERM;
}

/**
 * mnt_want_write_file - get write access to a file's mount
 * @file: the file who's mount on which to take a write
 *
 * This is like mnt_want_write, but it takes a file and can
 * do some optimisations if the file is open for write already
 *
 * Mostly called by filesystems from their ioctl operation before performing
 * modification.  On overlayfs this needs to check if the file is on a read-only
 * lower layer and deny access in that case.
 */
int mnt_want_write_file(struct file *file)
{
	int ret;

	ret = may_write_real(file);
	if (!ret) {
		sb_start_write(file_inode(file)->i_sb);
		ret = __mnt_want_write_file(file);
		if (ret)
			sb_end_write(file_inode(file)->i_sb);
	}
	return ret;
}
EXPORT_SYMBOL_GPL(mnt_want_write_file);

/**
@@ -484,10 +536,16 @@ void __mnt_drop_write_file(struct file *file)
	__mnt_drop_write(file->f_path.mnt);
}

void mnt_drop_write_file(struct file *file)
void mnt_drop_write_file_path(struct file *file)
{
	mnt_drop_write(file->f_path.mnt);
}

void mnt_drop_write_file(struct file *file)
{
	__mnt_drop_write(file->f_path.mnt);
	sb_end_write(file_inode(file)->i_sb);
}
EXPORT_SYMBOL(mnt_drop_write_file);

static int mnt_make_readonly(struct mount *mnt)
Loading