Skip to content

Commit c353f88

Browse files
committed
Merge branch 'overlayfs-linus' of git://git.kernel.org/pub/scm/linux/kernel/git/mszeredi/vfs
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
2 parents 6d8ef53 + 939ae4e commit c353f88

File tree

15 files changed

+496
-79
lines changed

15 files changed

+496
-79
lines changed

Documentation/filesystems/Locking

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -22,7 +22,7 @@ prototypes:
2222
struct vfsmount *(*d_automount)(struct path *path);
2323
int (*d_manage)(const struct path *, bool);
2424
struct dentry *(*d_real)(struct dentry *, const struct inode *,
25-
unsigned int);
25+
unsigned int, unsigned int);
2626

2727
locking rules:
2828
rename_lock ->d_lock may block rcu-walk

Documentation/filesystems/vfs.txt

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -988,7 +988,7 @@ struct dentry_operations {
988988
struct vfsmount *(*d_automount)(struct path *);
989989
int (*d_manage)(const struct path *, bool);
990990
struct dentry *(*d_real)(struct dentry *, const struct inode *,
991-
unsigned int);
991+
unsigned int, unsigned int);
992992
};
993993

994994
d_revalidate: called when the VFS needs to revalidate a dentry. This

fs/inode.c

Lines changed: 17 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -1570,11 +1570,24 @@ EXPORT_SYMBOL(bmap);
15701570
static void update_ovl_inode_times(struct dentry *dentry, struct inode *inode,
15711571
bool rcu)
15721572
{
1573-
if (!rcu) {
1574-
struct inode *realinode = d_real_inode(dentry);
1573+
struct dentry *upperdentry;
15751574

1576-
if (unlikely(inode != realinode) &&
1577-
(!timespec_equal(&inode->i_mtime, &realinode->i_mtime) ||
1575+
/*
1576+
* Nothing to do if in rcu or if non-overlayfs
1577+
*/
1578+
if (rcu || likely(!(dentry->d_flags & DCACHE_OP_REAL)))
1579+
return;
1580+
1581+
upperdentry = d_real(dentry, NULL, 0, D_REAL_UPPER);
1582+
1583+
/*
1584+
* If file is on lower then we can't update atime, so no worries about
1585+
* stale mtime/ctime.
1586+
*/
1587+
if (upperdentry) {
1588+
struct inode *realinode = d_inode(upperdentry);
1589+
1590+
if ((!timespec_equal(&inode->i_mtime, &realinode->i_mtime) ||
15781591
!timespec_equal(&inode->i_ctime, &realinode->i_ctime))) {
15791592
inode->i_mtime = realinode->i_mtime;
15801593
inode->i_ctime = realinode->i_ctime;

fs/internal.h

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -71,8 +71,10 @@ extern void __init mnt_init(void);
7171

7272
extern int __mnt_want_write(struct vfsmount *);
7373
extern int __mnt_want_write_file(struct file *);
74+
extern int mnt_want_write_file_path(struct file *);
7475
extern void __mnt_drop_write(struct vfsmount *);
7576
extern void __mnt_drop_write_file(struct file *);
77+
extern void mnt_drop_write_file_path(struct file *);
7678

7779
/*
7880
* fs_struct.c

fs/namespace.c

Lines changed: 61 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -431,13 +431,18 @@ int __mnt_want_write_file(struct file *file)
431431
}
432432

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

@@ -447,6 +452,53 @@ int mnt_want_write_file(struct file *file)
447452
sb_end_write(file->f_path.mnt->mnt_sb);
448453
return ret;
449454
}
455+
456+
static inline int may_write_real(struct file *file)
457+
{
458+
struct dentry *dentry = file->f_path.dentry;
459+
struct dentry *upperdentry;
460+
461+
/* Writable file? */
462+
if (file->f_mode & FMODE_WRITER)
463+
return 0;
464+
465+
/* Not overlayfs? */
466+
if (likely(!(dentry->d_flags & DCACHE_OP_REAL)))
467+
return 0;
468+
469+
/* File refers to upper, writable layer? */
470+
upperdentry = d_real(dentry, NULL, 0, D_REAL_UPPER);
471+
if (upperdentry && file_inode(file) == d_inode(upperdentry))
472+
return 0;
473+
474+
/* Lower layer: can't write to real file, sorry... */
475+
return -EPERM;
476+
}
477+
478+
/**
479+
* mnt_want_write_file - get write access to a file's mount
480+
* @file: the file who's mount on which to take a write
481+
*
482+
* This is like mnt_want_write, but it takes a file and can
483+
* do some optimisations if the file is open for write already
484+
*
485+
* Mostly called by filesystems from their ioctl operation before performing
486+
* modification. On overlayfs this needs to check if the file is on a read-only
487+
* lower layer and deny access in that case.
488+
*/
489+
int mnt_want_write_file(struct file *file)
490+
{
491+
int ret;
492+
493+
ret = may_write_real(file);
494+
if (!ret) {
495+
sb_start_write(file_inode(file)->i_sb);
496+
ret = __mnt_want_write_file(file);
497+
if (ret)
498+
sb_end_write(file_inode(file)->i_sb);
499+
}
500+
return ret;
501+
}
450502
EXPORT_SYMBOL_GPL(mnt_want_write_file);
451503

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

487-
void mnt_drop_write_file(struct file *file)
539+
void mnt_drop_write_file_path(struct file *file)
488540
{
489541
mnt_drop_write(file->f_path.mnt);
490542
}
543+
544+
void mnt_drop_write_file(struct file *file)
545+
{
546+
__mnt_drop_write(file->f_path.mnt);
547+
sb_end_write(file_inode(file)->i_sb);
548+
}
491549
EXPORT_SYMBOL(mnt_drop_write_file);
492550

493551
static int mnt_make_readonly(struct mount *mnt)

fs/open.c

Lines changed: 4 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -96,7 +96,7 @@ long vfs_truncate(const struct path *path, loff_t length)
9696
* write access on the upper inode, not on the overlay inode. For
9797
* non-overlay filesystems d_real() is an identity function.
9898
*/
99-
upperdentry = d_real(path->dentry, NULL, O_WRONLY);
99+
upperdentry = d_real(path->dentry, NULL, O_WRONLY, 0);
100100
error = PTR_ERR(upperdentry);
101101
if (IS_ERR(upperdentry))
102102
goto mnt_drop_write_and_out;
@@ -670,12 +670,12 @@ SYSCALL_DEFINE3(fchown, unsigned int, fd, uid_t, user, gid_t, group)
670670
if (!f.file)
671671
goto out;
672672

673-
error = mnt_want_write_file(f.file);
673+
error = mnt_want_write_file_path(f.file);
674674
if (error)
675675
goto out_fput;
676676
audit_file(f.file);
677677
error = chown_common(&f.file->f_path, user, group);
678-
mnt_drop_write_file(f.file);
678+
mnt_drop_write_file_path(f.file);
679679
out_fput:
680680
fdput(f);
681681
out:
@@ -857,7 +857,7 @@ EXPORT_SYMBOL(file_path);
857857
int vfs_open(const struct path *path, struct file *file,
858858
const struct cred *cred)
859859
{
860-
struct dentry *dentry = d_real(path->dentry, NULL, file->f_flags);
860+
struct dentry *dentry = d_real(path->dentry, NULL, file->f_flags, 0);
861861

862862
if (IS_ERR(dentry))
863863
return PTR_ERR(dentry);

fs/overlayfs/dir.c

Lines changed: 6 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -155,7 +155,7 @@ static int ovl_set_opaque(struct dentry *dentry, struct dentry *upperdentry)
155155
static void ovl_instantiate(struct dentry *dentry, struct inode *inode,
156156
struct dentry *newdentry, bool hardlink)
157157
{
158-
ovl_dentry_version_inc(dentry->d_parent);
158+
ovl_dentry_version_inc(dentry->d_parent, false);
159159
ovl_dentry_set_upper_alias(dentry);
160160
if (!hardlink) {
161161
ovl_inode_update(inode, newdentry);
@@ -692,7 +692,7 @@ static int ovl_remove_and_whiteout(struct dentry *dentry, bool is_dir)
692692
if (flags)
693693
ovl_cleanup(wdir, upper);
694694

695-
ovl_dentry_version_inc(dentry->d_parent);
695+
ovl_dentry_version_inc(dentry->d_parent, true);
696696
out_d_drop:
697697
d_drop(dentry);
698698
dput(whiteout);
@@ -742,7 +742,7 @@ static int ovl_remove_upper(struct dentry *dentry, bool is_dir)
742742
err = vfs_rmdir(dir, upper);
743743
else
744744
err = vfs_unlink(dir, upper, NULL);
745-
ovl_dentry_version_inc(dentry->d_parent);
745+
ovl_dentry_version_inc(dentry->d_parent, ovl_type_origin(dentry));
746746

747747
/*
748748
* Keeping this dentry hashed would mean having to release
@@ -1089,8 +1089,9 @@ static int ovl_rename(struct inode *olddir, struct dentry *old,
10891089
drop_nlink(d_inode(new));
10901090
}
10911091

1092-
ovl_dentry_version_inc(old->d_parent);
1093-
ovl_dentry_version_inc(new->d_parent);
1092+
ovl_dentry_version_inc(old->d_parent,
1093+
!overwrite && ovl_type_origin(new));
1094+
ovl_dentry_version_inc(new->d_parent, ovl_type_origin(old));
10941095

10951096
out_dput:
10961097
dput(newdentry);

fs/overlayfs/inode.c

Lines changed: 10 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -498,6 +498,9 @@ static int ovl_set_nlink_common(struct dentry *dentry,
498498
len = snprintf(buf, sizeof(buf), format,
499499
(int) (inode->i_nlink - realinode->i_nlink));
500500

501+
if (WARN_ON(len >= sizeof(buf)))
502+
return -EIO;
503+
501504
return ovl_do_setxattr(ovl_dentry_upper(dentry),
502505
OVL_XATTR_NLINK, buf, len, 0);
503506
}
@@ -576,10 +579,13 @@ static int ovl_inode_set(struct inode *inode, void *data)
576579
static bool ovl_verify_inode(struct inode *inode, struct dentry *lowerdentry,
577580
struct dentry *upperdentry)
578581
{
579-
struct inode *lowerinode = lowerdentry ? d_inode(lowerdentry) : NULL;
580-
581-
/* Lower (origin) inode must match, even if NULL */
582-
if (ovl_inode_lower(inode) != lowerinode)
582+
/*
583+
* Allow non-NULL lower inode in ovl_inode even if lowerdentry is NULL.
584+
* This happens when finding a copied up overlay inode for a renamed
585+
* or hardlinked overlay dentry and lower dentry cannot be followed
586+
* by origin because lower fs does not support file handles.
587+
*/
588+
if (lowerdentry && ovl_inode_lower(inode) != d_inode(lowerdentry))
583589
return false;
584590

585591
/*

fs/overlayfs/overlayfs.h

Lines changed: 5 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -204,8 +204,8 @@ struct dentry *ovl_i_dentry_upper(struct inode *inode);
204204
struct inode *ovl_inode_upper(struct inode *inode);
205205
struct inode *ovl_inode_lower(struct inode *inode);
206206
struct inode *ovl_inode_real(struct inode *inode);
207-
struct ovl_dir_cache *ovl_dir_cache(struct dentry *dentry);
208-
void ovl_set_dir_cache(struct dentry *dentry, struct ovl_dir_cache *cache);
207+
struct ovl_dir_cache *ovl_dir_cache(struct inode *inode);
208+
void ovl_set_dir_cache(struct inode *inode, struct ovl_dir_cache *cache);
209209
bool ovl_dentry_is_opaque(struct dentry *dentry);
210210
bool ovl_dentry_is_whiteout(struct dentry *dentry);
211211
void ovl_dentry_set_opaque(struct dentry *dentry);
@@ -217,7 +217,7 @@ void ovl_dentry_set_redirect(struct dentry *dentry, const char *redirect);
217217
void ovl_inode_init(struct inode *inode, struct dentry *upperdentry,
218218
struct dentry *lowerdentry);
219219
void ovl_inode_update(struct inode *inode, struct dentry *upperdentry);
220-
void ovl_dentry_version_inc(struct dentry *dentry);
220+
void ovl_dentry_version_inc(struct dentry *dentry, bool impurity);
221221
u64 ovl_dentry_version_get(struct dentry *dentry);
222222
bool ovl_is_whiteout(struct dentry *dentry);
223223
struct file *ovl_path_open(struct path *path, int flags);
@@ -229,6 +229,7 @@ int ovl_check_setxattr(struct dentry *dentry, struct dentry *upperdentry,
229229
int xerr);
230230
int ovl_set_impure(struct dentry *dentry, struct dentry *upperdentry);
231231
void ovl_set_flag(unsigned long flag, struct inode *inode);
232+
void ovl_clear_flag(unsigned long flag, struct inode *inode);
232233
bool ovl_test_flag(unsigned long flag, struct inode *inode);
233234
bool ovl_inuse_trylock(struct dentry *dentry);
234235
void ovl_inuse_unlock(struct dentry *dentry);
@@ -256,6 +257,7 @@ extern const struct file_operations ovl_dir_operations;
256257
int ovl_check_empty_dir(struct dentry *dentry, struct list_head *list);
257258
void ovl_cleanup_whiteouts(struct dentry *upper, struct list_head *list);
258259
void ovl_cache_free(struct list_head *list);
260+
void ovl_dir_cache_free(struct inode *inode);
259261
int ovl_check_d_type_supported(struct path *realpath);
260262
void ovl_workdir_cleanup(struct inode *dir, struct vfsmount *mnt,
261263
struct dentry *dentry, int level);

0 commit comments

Comments
 (0)