Skip to content

Commit 6df7cc2

Browse files
committed
Merge tag 'ovl-update-6.2' of git://git.kernel.org/pub/scm/linux/kernel/git/mszeredi/vfs
Pull overlayfs update from Miklos Szeredi: - Fix a couple of bugs found by syzbot - Don't ingore some open flags set by fcntl(F_SETFL) - Fix failure to create a hard link in certain cases - Use type safe helpers for some mnt_userns transformations - Improve performance of mount - Misc cleanups * tag 'ovl-update-6.2' of git://git.kernel.org/pub/scm/linux/kernel/git/mszeredi/vfs: ovl: Kconfig: Fix spelling mistake "undelying" -> "underlying" ovl: use inode instead of dentry where possible ovl: Add comment on upperredirect reassignment ovl: use plain list filler in indexdir and workdir cleanup ovl: do not reconnect upper index records in ovl_indexdir_cleanup() ovl: fix comment typos ovl: port to vfs{g,u}id_t and associated helpers ovl: Use ovl mounter's fsuid and fsgid in ovl_link() ovl: Use "buf" flexible array for memcpy() destination ovl: update ->f_iocb_flags when ovl_change_flags() modifies ->f_flags ovl: fix use inode directly in rcu-walk mode
2 parents 4a6bff1 + 637d13b commit 6df7cc2

File tree

9 files changed

+86
-67
lines changed

9 files changed

+86
-67
lines changed

fs/overlayfs/Kconfig

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -96,7 +96,7 @@ config OVERLAY_FS_XINO_AUTO
9696
depends on 64BIT
9797
help
9898
If this config option is enabled then overlay filesystems will use
99-
unused high bits in undelying filesystem inode numbers to map all
99+
unused high bits in underlying filesystem inode numbers to map all
100100
inodes to a unified address space. The mapped 64bit inode numbers
101101
might not be compatible with applications that expect 32bit inodes.
102102

fs/overlayfs/dir.c

Lines changed: 30 additions & 16 deletions
Original file line numberDiff line numberDiff line change
@@ -576,28 +576,42 @@ static int ovl_create_or_link(struct dentry *dentry, struct inode *inode,
576576
goto out_revert_creds;
577577
}
578578

579-
err = -ENOMEM;
580-
override_cred = prepare_creds();
581-
if (override_cred) {
579+
if (!attr->hardlink) {
580+
err = -ENOMEM;
581+
override_cred = prepare_creds();
582+
if (!override_cred)
583+
goto out_revert_creds;
584+
/*
585+
* In the creation cases(create, mkdir, mknod, symlink),
586+
* ovl should transfer current's fs{u,g}id to underlying
587+
* fs. Because underlying fs want to initialize its new
588+
* inode owner using current's fs{u,g}id. And in this
589+
* case, the @inode is a new inode that is initialized
590+
* in inode_init_owner() to current's fs{u,g}id. So use
591+
* the inode's i_{u,g}id to override the cred's fs{u,g}id.
592+
*
593+
* But in the other hardlink case, ovl_link() does not
594+
* create a new inode, so just use the ovl mounter's
595+
* fs{u,g}id.
596+
*/
582597
override_cred->fsuid = inode->i_uid;
583598
override_cred->fsgid = inode->i_gid;
584-
if (!attr->hardlink) {
585-
err = security_dentry_create_files_as(dentry,
586-
attr->mode, &dentry->d_name, old_cred,
587-
override_cred);
588-
if (err) {
589-
put_cred(override_cred);
590-
goto out_revert_creds;
591-
}
599+
err = security_dentry_create_files_as(dentry,
600+
attr->mode, &dentry->d_name, old_cred,
601+
override_cred);
602+
if (err) {
603+
put_cred(override_cred);
604+
goto out_revert_creds;
592605
}
593606
put_cred(override_creds(override_cred));
594607
put_cred(override_cred);
595-
596-
if (!ovl_dentry_is_whiteout(dentry))
597-
err = ovl_create_upper(dentry, inode, attr);
598-
else
599-
err = ovl_create_over_whiteout(dentry, inode, attr);
600608
}
609+
610+
if (!ovl_dentry_is_whiteout(dentry))
611+
err = ovl_create_upper(dentry, inode, attr);
612+
else
613+
err = ovl_create_over_whiteout(dentry, inode, attr);
614+
601615
out_revert_creds:
602616
revert_creds(old_cred);
603617
return err;

fs/overlayfs/export.c

Lines changed: 4 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -339,7 +339,7 @@ static struct dentry *ovl_obtain_alias(struct super_block *sb,
339339
return dentry;
340340
}
341341

342-
/* Get the upper or lower dentry in stach whose on layer @idx */
342+
/* Get the upper or lower dentry in stack whose on layer @idx */
343343
static struct dentry *ovl_dentry_real_at(struct dentry *dentry, int idx)
344344
{
345345
struct ovl_entry *oe = dentry->d_fsdata;
@@ -463,7 +463,7 @@ static struct dentry *ovl_lookup_real_inode(struct super_block *sb,
463463

464464
/* Get connected upper overlay dir from index */
465465
if (index) {
466-
struct dentry *upper = ovl_index_upper(ofs, index);
466+
struct dentry *upper = ovl_index_upper(ofs, index, true);
467467

468468
dput(index);
469469
if (IS_ERR_OR_NULL(upper))
@@ -739,7 +739,7 @@ static struct dentry *ovl_lower_fh_to_d(struct super_block *sb,
739739

740740
/* Then try to get a connected upper dir by index */
741741
if (index && d_is_dir(index)) {
742-
struct dentry *upper = ovl_index_upper(ofs, index);
742+
struct dentry *upper = ovl_index_upper(ofs, index, true);
743743

744744
err = PTR_ERR(upper);
745745
if (IS_ERR_OR_NULL(upper))
@@ -796,7 +796,7 @@ static struct ovl_fh *ovl_fid_to_fh(struct fid *fid, int buflen, int fh_type)
796796
return ERR_PTR(-ENOMEM);
797797

798798
/* Copy unaligned inner fh into aligned buffer */
799-
memcpy(&fh->fb, fid, buflen - OVL_FH_WIRE_OFFSET);
799+
memcpy(fh->buf, fid, buflen - OVL_FH_WIRE_OFFSET);
800800
return fh;
801801
}
802802

fs/overlayfs/file.c

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -34,7 +34,7 @@ static char ovl_whatisit(struct inode *inode, struct inode *realinode)
3434
return 'm';
3535
}
3636

37-
/* No atime modificaton nor notify on underlying */
37+
/* No atime modification nor notify on underlying */
3838
#define OVL_OPEN_FLAGS (O_NOATIME | FMODE_NONOTIFY)
3939

4040
static struct file *ovl_open_realfile(const struct file *file,
@@ -96,6 +96,7 @@ static int ovl_change_flags(struct file *file, unsigned int flags)
9696

9797
spin_lock(&file->f_lock);
9898
file->f_flags = (file->f_flags & ~OVL_SETFL_MASK) | flags;
99+
file->f_iocb_flags = iocb_flags(file);
99100
spin_unlock(&file->f_lock);
100101

101102
return 0;

fs/overlayfs/namei.c

Lines changed: 9 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -487,7 +487,8 @@ int ovl_verify_set_fh(struct ovl_fs *ofs, struct dentry *dentry,
487487
}
488488

489489
/* Get upper dentry from index */
490-
struct dentry *ovl_index_upper(struct ovl_fs *ofs, struct dentry *index)
490+
struct dentry *ovl_index_upper(struct ovl_fs *ofs, struct dentry *index,
491+
bool connected)
491492
{
492493
struct ovl_fh *fh;
493494
struct dentry *upper;
@@ -499,7 +500,7 @@ struct dentry *ovl_index_upper(struct ovl_fs *ofs, struct dentry *index)
499500
if (IS_ERR_OR_NULL(fh))
500501
return ERR_CAST(fh);
501502

502-
upper = ovl_decode_real_fh(ofs, fh, ovl_upper_mnt(ofs), true);
503+
upper = ovl_decode_real_fh(ofs, fh, ovl_upper_mnt(ofs), connected);
503504
kfree(fh);
504505

505506
if (IS_ERR_OR_NULL(upper))
@@ -572,7 +573,7 @@ int ovl_verify_index(struct ovl_fs *ofs, struct dentry *index)
572573
* directly from the index dentry, but for dir index we first need to
573574
* decode the upper directory.
574575
*/
575-
upper = ovl_index_upper(ofs, index);
576+
upper = ovl_index_upper(ofs, index, false);
576577
if (IS_ERR_OR_NULL(upper)) {
577578
err = PTR_ERR(upper);
578579
/*
@@ -1085,6 +1086,11 @@ struct dentry *ovl_lookup(struct inode *dir, struct dentry *dentry,
10851086
.mnt = ovl_upper_mnt(ofs),
10861087
};
10871088

1089+
/*
1090+
* It's safe to assign upperredirect here: the previous
1091+
* assignment of happens only if upperdentry is non-NULL, and
1092+
* this one only if upperdentry is NULL.
1093+
*/
10881094
upperredirect = ovl_get_redirect_xattr(ofs, &upperpath, 0);
10891095
if (IS_ERR(upperredirect)) {
10901096
err = PTR_ERR(upperredirect);

fs/overlayfs/overlayfs.h

Lines changed: 6 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -110,7 +110,7 @@ struct ovl_fh {
110110
u8 padding[3]; /* make sure fb.fid is 32bit aligned */
111111
union {
112112
struct ovl_fb fb;
113-
u8 buf[0];
113+
DECLARE_FLEX_ARRAY(u8, buf);
114114
};
115115
} __packed;
116116

@@ -415,7 +415,7 @@ const char *ovl_dentry_get_redirect(struct dentry *dentry);
415415
void ovl_dentry_set_redirect(struct dentry *dentry, const char *redirect);
416416
void ovl_inode_update(struct inode *inode, struct dentry *upperdentry);
417417
void ovl_dir_modified(struct dentry *dentry, bool impurity);
418-
u64 ovl_dentry_version_get(struct dentry *dentry);
418+
u64 ovl_inode_version_get(struct inode *inode);
419419
bool ovl_is_whiteout(struct dentry *dentry);
420420
struct file *ovl_path_open(const struct path *path, int flags);
421421
int ovl_copy_up_start(struct dentry *dentry, int flags);
@@ -539,7 +539,8 @@ int ovl_check_origin_fh(struct ovl_fs *ofs, struct ovl_fh *fh, bool connected,
539539
int ovl_verify_set_fh(struct ovl_fs *ofs, struct dentry *dentry,
540540
enum ovl_xattr ox, struct dentry *real, bool is_upper,
541541
bool set);
542-
struct dentry *ovl_index_upper(struct ovl_fs *ofs, struct dentry *index);
542+
struct dentry *ovl_index_upper(struct ovl_fs *ofs, struct dentry *index,
543+
bool connected);
543544
int ovl_verify_index(struct ovl_fs *ofs, struct dentry *index);
544545
int ovl_get_index_name(struct ovl_fs *ofs, struct dentry *origin,
545546
struct qstr *name);
@@ -584,9 +585,9 @@ int ovl_indexdir_cleanup(struct ovl_fs *ofs);
584585
* lower dir was removed under it and possibly before it was rotated from upper
585586
* to lower layer.
586587
*/
587-
static inline bool ovl_dir_is_real(struct dentry *dir)
588+
static inline bool ovl_dir_is_real(struct inode *dir)
588589
{
589-
return !ovl_test_flag(OVL_WHITEOUTS, d_inode(dir));
590+
return !ovl_test_flag(OVL_WHITEOUTS, dir);
590591
}
591592

592593
/* inode.c */

fs/overlayfs/readdir.c

Lines changed: 26 additions & 32 deletions
Original file line numberDiff line numberDiff line change
@@ -235,15 +235,15 @@ void ovl_dir_cache_free(struct inode *inode)
235235
}
236236
}
237237

238-
static void ovl_cache_put(struct ovl_dir_file *od, struct dentry *dentry)
238+
static void ovl_cache_put(struct ovl_dir_file *od, struct inode *inode)
239239
{
240240
struct ovl_dir_cache *cache = od->cache;
241241

242242
WARN_ON(cache->refcount <= 0);
243243
cache->refcount--;
244244
if (!cache->refcount) {
245-
if (ovl_dir_cache(d_inode(dentry)) == cache)
246-
ovl_set_dir_cache(d_inode(dentry), NULL);
245+
if (ovl_dir_cache(inode) == cache)
246+
ovl_set_dir_cache(inode, NULL);
247247

248248
ovl_cache_free(&cache->entries);
249249
kfree(cache);
@@ -323,15 +323,15 @@ static void ovl_dir_reset(struct file *file)
323323
{
324324
struct ovl_dir_file *od = file->private_data;
325325
struct ovl_dir_cache *cache = od->cache;
326-
struct dentry *dentry = file->f_path.dentry;
326+
struct inode *inode = file_inode(file);
327327
bool is_real;
328328

329-
if (cache && ovl_dentry_version_get(dentry) != cache->version) {
330-
ovl_cache_put(od, dentry);
329+
if (cache && ovl_inode_version_get(inode) != cache->version) {
330+
ovl_cache_put(od, inode);
331331
od->cache = NULL;
332332
od->cursor = NULL;
333333
}
334-
is_real = ovl_dir_is_real(dentry);
334+
is_real = ovl_dir_is_real(inode);
335335
if (od->is_real != is_real) {
336336
/* is_real can only become false when dir is copied up */
337337
if (WARN_ON(is_real))
@@ -394,9 +394,10 @@ static struct ovl_dir_cache *ovl_cache_get(struct dentry *dentry)
394394
{
395395
int res;
396396
struct ovl_dir_cache *cache;
397+
struct inode *inode = d_inode(dentry);
397398

398-
cache = ovl_dir_cache(d_inode(dentry));
399-
if (cache && ovl_dentry_version_get(dentry) == cache->version) {
399+
cache = ovl_dir_cache(inode);
400+
if (cache && ovl_inode_version_get(inode) == cache->version) {
400401
WARN_ON(!cache->refcount);
401402
cache->refcount++;
402403
return cache;
@@ -418,8 +419,8 @@ static struct ovl_dir_cache *ovl_cache_get(struct dentry *dentry)
418419
return ERR_PTR(res);
419420
}
420421

421-
cache->version = ovl_dentry_version_get(dentry);
422-
ovl_set_dir_cache(d_inode(dentry), cache);
422+
cache->version = ovl_inode_version_get(inode);
423+
ovl_set_dir_cache(inode, cache);
423424

424425
return cache;
425426
}
@@ -596,16 +597,17 @@ static struct ovl_dir_cache *ovl_cache_get_impure(const struct path *path)
596597
{
597598
int res;
598599
struct dentry *dentry = path->dentry;
600+
struct inode *inode = d_inode(dentry);
599601
struct ovl_fs *ofs = OVL_FS(dentry->d_sb);
600602
struct ovl_dir_cache *cache;
601603

602-
cache = ovl_dir_cache(d_inode(dentry));
603-
if (cache && ovl_dentry_version_get(dentry) == cache->version)
604+
cache = ovl_dir_cache(inode);
605+
if (cache && ovl_inode_version_get(inode) == cache->version)
604606
return cache;
605607

606608
/* Impure cache is not refcounted, free it here */
607-
ovl_dir_cache_free(d_inode(dentry));
608-
ovl_set_dir_cache(d_inode(dentry), NULL);
609+
ovl_dir_cache_free(inode);
610+
ovl_set_dir_cache(inode, NULL);
609611

610612
cache = kzalloc(sizeof(struct ovl_dir_cache), GFP_KERNEL);
611613
if (!cache)
@@ -627,13 +629,13 @@ static struct ovl_dir_cache *ovl_cache_get_impure(const struct path *path)
627629
OVL_XATTR_IMPURE);
628630
ovl_drop_write(dentry);
629631
}
630-
ovl_clear_flag(OVL_IMPURE, d_inode(dentry));
632+
ovl_clear_flag(OVL_IMPURE, inode);
631633
kfree(cache);
632634
return NULL;
633635
}
634636

635-
cache->version = ovl_dentry_version_get(dentry);
636-
ovl_set_dir_cache(d_inode(dentry), cache);
637+
cache->version = ovl_inode_version_get(inode);
638+
ovl_set_dir_cache(inode, cache);
637639

638640
return cache;
639641
}
@@ -675,7 +677,7 @@ static bool ovl_fill_real(struct dir_context *ctx, const char *name,
675677
static bool ovl_is_impure_dir(struct file *file)
676678
{
677679
struct ovl_dir_file *od = file->private_data;
678-
struct inode *dir = d_inode(file->f_path.dentry);
680+
struct inode *dir = file_inode(file);
679681

680682
/*
681683
* Only upper dir can be impure, but if we are in the middle of
@@ -893,7 +895,7 @@ static int ovl_dir_fsync(struct file *file, loff_t start, loff_t end,
893895
struct file *realfile;
894896
int err;
895897

896-
err = ovl_sync_status(OVL_FS(file->f_path.dentry->d_sb));
898+
err = ovl_sync_status(OVL_FS(file_inode(file)->i_sb));
897899
if (err <= 0)
898900
return err;
899901

@@ -913,7 +915,7 @@ static int ovl_dir_release(struct inode *inode, struct file *file)
913915

914916
if (od->cache) {
915917
inode_lock(inode);
916-
ovl_cache_put(od, file->f_path.dentry);
918+
ovl_cache_put(od, inode);
917919
inode_unlock(inode);
918920
}
919921
fput(od->realfile);
@@ -942,7 +944,7 @@ static int ovl_dir_open(struct inode *inode, struct file *file)
942944
return PTR_ERR(realfile);
943945
}
944946
od->realfile = realfile;
945-
od->is_real = ovl_dir_is_real(file->f_path.dentry);
947+
od->is_real = ovl_dir_is_real(inode);
946948
od->is_upper = OVL_TYPE_UPPER(type);
947949
file->private_data = od;
948950

@@ -1071,14 +1073,10 @@ static int ovl_workdir_cleanup_recurse(struct ovl_fs *ofs, const struct path *pa
10711073
int err;
10721074
struct inode *dir = path->dentry->d_inode;
10731075
LIST_HEAD(list);
1074-
struct rb_root root = RB_ROOT;
10751076
struct ovl_cache_entry *p;
10761077
struct ovl_readdir_data rdd = {
1077-
.ctx.actor = ovl_fill_merge,
1078-
.dentry = NULL,
1078+
.ctx.actor = ovl_fill_plain,
10791079
.list = &list,
1080-
.root = &root,
1081-
.is_lowest = false,
10821080
};
10831081
bool incompat = false;
10841082

@@ -1159,14 +1157,10 @@ int ovl_indexdir_cleanup(struct ovl_fs *ofs)
11591157
struct inode *dir = indexdir->d_inode;
11601158
struct path path = { .mnt = ovl_upper_mnt(ofs), .dentry = indexdir };
11611159
LIST_HEAD(list);
1162-
struct rb_root root = RB_ROOT;
11631160
struct ovl_cache_entry *p;
11641161
struct ovl_readdir_data rdd = {
1165-
.ctx.actor = ovl_fill_merge,
1166-
.dentry = NULL,
1162+
.ctx.actor = ovl_fill_plain,
11671163
.list = &list,
1168-
.root = &root,
1169-
.is_lowest = false,
11701164
};
11711165

11721166
err = ovl_dir_read(&path, &rdd);

fs/overlayfs/super.c

Lines changed: 6 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -139,11 +139,16 @@ static int ovl_dentry_revalidate_common(struct dentry *dentry,
139139
unsigned int flags, bool weak)
140140
{
141141
struct ovl_entry *oe = dentry->d_fsdata;
142+
struct inode *inode = d_inode_rcu(dentry);
142143
struct dentry *upper;
143144
unsigned int i;
144145
int ret = 1;
145146

146-
upper = ovl_dentry_upper(dentry);
147+
/* Careful in RCU mode */
148+
if (!inode)
149+
return -ECHILD;
150+
151+
upper = ovl_i_dentry_upper(inode);
147152
if (upper)
148153
ret = ovl_revalidate_real(upper, flags, weak);
149154

0 commit comments

Comments
 (0)