diff --git a/fs/dcache.c b/fs/dcache.c index b7787822512f..409f841e058e 100644 --- a/fs/dcache.c +++ b/fs/dcache.c @@ -359,7 +359,8 @@ static inline int dname_external(const struct dentry *dentry) return dentry->d_name.name != dentry->d_shortname.string; } -void take_dentry_name_snapshot(struct name_snapshot *name, struct dentry *dentry) +static bool __take_dentry_name_snapshot(struct name_snapshot *name, + struct dentry *dentry, bool retry) { unsigned seq; const unsigned char *s; @@ -376,8 +377,12 @@ void take_dentry_name_snapshot(struct name_snapshot *name, struct dentry *dentry struct external_name *p; p = container_of(s, struct external_name, name[0]); // get a valid reference - if (unlikely(!atomic_inc_not_zero(&p->count))) - goto retry; + if (unlikely(!atomic_inc_not_zero(&p->count))) { + if (retry) + goto retry; + rcu_read_unlock(); + return false; + } name->name.name = s; } if (read_seqcount_retry(&dentry->d_seq, seq)) { @@ -385,9 +390,27 @@ void take_dentry_name_snapshot(struct name_snapshot *name, struct dentry *dentry goto retry; } rcu_read_unlock(); + return true; +} + +void take_dentry_name_snapshot(struct name_snapshot *name, struct dentry *dentry) +{ + __take_dentry_name_snapshot(name, dentry, true); } EXPORT_SYMBOL(take_dentry_name_snapshot); +/* + * For a caller that holds no reference on @dentry, e.g. in RCU walk. + * The external name of a dead dentry has a zero refcount forever, so + * take_dentry_name_snapshot() would retry without end. Fail instead. + */ +bool try_take_dentry_name_snapshot(struct name_snapshot *name, + struct dentry *dentry) +{ + return __take_dentry_name_snapshot(name, dentry, false); +} +EXPORT_SYMBOL(try_take_dentry_name_snapshot); + void release_dentry_name_snapshot(struct name_snapshot *name) { if (unlikely(name->name.name != name->inline_name.string)) { diff --git a/fs/overlayfs/copy_up.c b/fs/overlayfs/copy_up.c index e963701b4c87..c147ad155b79 100644 --- a/fs/overlayfs/copy_up.c +++ b/fs/overlayfs/copy_up.c @@ -72,6 +72,18 @@ static int ovl_copy_acl(struct ovl_fs *ofs, const struct path *path, return err; } +static ssize_t ovl_getxattr_value(const struct path *path, char *name, + char **value, ssize_t *value_size); + +/* + * Any user can store an empty security.capability, which fails to read with + * -EINVAL. It grants no capability, so treat it as none, like no xattr. + */ +static bool ovl_no_fscap(ssize_t err) +{ + return err == -ENODATA || err == -EOPNOTSUPP || err == -EINVAL; +} + int ovl_copy_xattr(struct super_block *sb, const struct path *oldpath, struct dentry *new) { struct dentry *old = oldpath->dentry; @@ -129,30 +141,16 @@ int ovl_copy_xattr(struct super_block *sb, const struct path *oldpath, struct de break; } -retry: - size = ovl_do_getxattr(oldpath, name, value, value_size); - if (size == -ERANGE) - size = ovl_do_getxattr(oldpath, name, NULL, 0); - + size = ovl_getxattr_value(oldpath, name, &value, &value_size); if (size < 0) { + if (!strcmp(name, XATTR_NAME_CAPS) && ovl_no_fscap(size)) { + error = 0; + continue; + } error = size; break; } - if (size > value_size) { - void *new; - - new = kvmalloc(size, GFP_KERNEL); - if (!new) { - error = -ENOMEM; - break; - } - kvfree(value); - value = new; - value_size = size; - goto retry; - } - error = ovl_do_setxattr(OVL_FS(sb), new, name, value, size, 0); if (error) { if (error != -EOPNOTSUPP || ovl_must_copy_xattr(name)) @@ -476,8 +474,12 @@ struct ovl_fh *ovl_get_origin_fh(struct ovl_fs *ofs, struct dentry *origin) * When lower layer doesn't support export operations store a 'null' fh, * so we can use the overlay.origin xattr to distignuish between a copy * up and a pure upper inode. + * + * With index enabled, mount already found that all layers can decode + * file handles. Do not ask again, because an LSM may change its answer + * about CAP_DAC_READ_SEARCH and index users cannot cope with a 'null' fh. */ - if (!ovl_can_decode_fh(origin->d_sb)) + if (!ofs->config.index && !ovl_can_decode_fh(origin->d_sb)) return NULL; return ovl_encode_real_fh(ofs, d_inode(origin), false); @@ -808,9 +810,10 @@ static int ovl_copy_up_workdir(struct ovl_copy_up_ctx *c) rd.old_parent = c->workdir; rd.new_parent = c->destdir; rd.flags = 0; - err = start_renaming_dentry(&rd, 0, temp, + /* The name may have been taken since lookup, never replace it */ + err = start_renaming_dentry(&rd, LOOKUP_EXCL, temp, &QSTR_LEN(c->destname.name, c->destname.len)); - if (err) { + if (err && err != -EEXIST) { /* temp or workdir moved underneath us? map to -EIO */ err = -EIO; } @@ -834,9 +837,9 @@ static int ovl_copy_up_workdir(struct ovl_copy_up_ctx *c) if (!c->metacopy) ovl_set_upperdata(inode); - ovl_inode_update(inode, temp); if (S_ISDIR(inode->i_mode)) ovl_set_flag(OVL_WHITEOUTS, inode); + ovl_inode_update(inode, temp); out: ovl_end_write(c->dentry); @@ -935,6 +938,7 @@ static int ovl_do_copy_up(struct ovl_copy_up_ctx *c) struct ovl_fs *ofs = OVL_FS(c->dentry->d_sb); struct dentry *origin = c->lowerpath.dentry; struct ovl_fh *fh = NULL; + struct name_snapshot name; bool to_index = false; /* @@ -972,12 +976,15 @@ static int ovl_do_copy_up(struct ovl_copy_up_ctx *c) goto out_free_fh; } else { /* - * c->dentry->d_name is stabilzed by ovl_copy_up_start(), - * because if we got here, it means that c->dentry has no upper - * alias and changing ->d_name means going through ovl_rename() - * that will call ovl_copy_up() on source and target dentry. + * ovl_copy_up_start() keeps ovl_rename() away from c->dentry, + * because ovl_rename() calls ovl_copy_up() on source and target + * dentry. It does not stop d_splice_alias() from moving a + * directory that a lookup found under another name after a + * change to the lower layer. That move frees an external name, + * so take a snapshot. */ - c->destname = c->dentry->d_name; + take_dentry_name_snapshot(&name, c->dentry); + c->destname = name.name; /* * Mark parent "impure" because it may now contain non-pure * upper @@ -986,7 +993,7 @@ static int ovl_do_copy_up(struct ovl_copy_up_ctx *c) err = ovl_set_impure(c->parent, c->destdir); ovl_end_write(c->dentry); if (err) - goto out_free_fh; + goto out; } /* Should we copyup with O_TMPFILE or with workdir? */ @@ -1020,6 +1027,8 @@ static int ovl_do_copy_up(struct ovl_copy_up_ctx *c) out: if (to_index) kfree(c->destname.name); + else + release_dentry_name_snapshot(&name); out_free_fh: kfree(fh); return err; @@ -1055,26 +1064,39 @@ static bool ovl_need_meta_copy_up(struct dentry *dentry, umode_t mode, return true; } -static ssize_t ovl_getxattr_value(const struct path *path, char *name, char **value) +static ssize_t ovl_getxattr_value(const struct path *path, char *name, + char **value, ssize_t *value_size) { ssize_t res; char *buf; - res = ovl_do_getxattr(path, name, NULL, 0); - if (res == -ENODATA || res == -EOPNOTSUPP) - res = 0; + res = ovl_do_getxattr(path, name, *value, *value_size); + if (res == -ERANGE) { + res = ovl_do_getxattr(path, name, NULL, 0); + /* Xattr changed underneath us? */ + if (res >= 0 && res <= *value_size) + return -EIO; + } - if (res > 0) { - buf = kzalloc(res, GFP_KERNEL); + if (res > *value_size) { + buf = kvmalloc(res, GFP_KERNEL); if (!buf) return -ENOMEM; res = ovl_do_getxattr(path, name, buf, res); - if (res < 0) - kfree(buf); - else - *value = buf; + if (res < 0) { + kvfree(buf); + /* Xattr changed underneath us? */ + if (res == -ERANGE) + return -EIO; + return res; + } + + kvfree(*value); + *value = buf; + *value_size = res; } + return res; } @@ -1085,7 +1107,7 @@ static int ovl_copy_up_meta_inode_data(struct ovl_copy_up_ctx *c) struct path upperpath; int err; char *capability = NULL; - ssize_t cap_size; + ssize_t cap_size = 0; ovl_path_upper(c->dentry, &upperpath); if (WARN_ON(upperpath.dentry == NULL)) @@ -1093,8 +1115,10 @@ static int ovl_copy_up_meta_inode_data(struct ovl_copy_up_ctx *c) if (c->stat.size) { err = cap_size = ovl_getxattr_value(&upperpath, XATTR_NAME_CAPS, - &capability); - if (cap_size < 0) + &capability, &cap_size); + if (ovl_no_fscap(cap_size)) + cap_size = 0; + else if (cap_size < 0) goto out; } @@ -1123,7 +1147,7 @@ static int ovl_copy_up_meta_inode_data(struct ovl_copy_up_ctx *c) ovl_clear_flag(OVL_VERIFIED_DIGEST, d_inode(c->dentry)); ovl_set_upperdata(d_inode(c->dentry)); out_free: - kfree(capability); + kvfree(capability); out: return err; } diff --git a/fs/overlayfs/dir.c b/fs/overlayfs/dir.c index 1194ccf981c3..1792e4114621 100644 --- a/fs/overlayfs/dir.c +++ b/fs/overlayfs/dir.c @@ -304,7 +304,6 @@ static int ovl_instantiate(struct dentry *dentry, struct inode *inode, }; ovl_dentry_set_upper_alias(dentry); - ovl_dentry_init_reval(dentry, newdentry, NULL); if (!hardlink) { /* @@ -335,6 +334,13 @@ static int ovl_instantiate(struct dentry *dentry, struct inode *inode, d_mark_tmpfile(tmpfile, inode); d_instantiate(dentry, inode); + /* + * Unless it is a tmpfile, the dentry is hashed and a path walk can find + * it at any time. Set the revalidate flags only now, because + * ovl_dentry_revalidate_common() does not expect them on a negative + * dentry. + */ + ovl_dentry_init_reval(dentry, ovl_dentry_upper(dentry), NULL); if (inode != oip.newinode) { pr_warn_ratelimited("newly created inode found in cache (%pd2)\n", dentry); @@ -1027,7 +1033,19 @@ static char *ovl_get_redirect(struct dentry *dentry, bool abs_redirect) const char *name; int thislen; + /* + * A rename can move d to another directory at any time. Hold + * d_lock to copy the name that d has in this very parent, or + * else the path mixes the old name with the new parent. + */ + tmp = dget_parent(d); spin_lock(&d->d_lock); + if (unlikely(tmp != d->d_parent)) { + spin_unlock(&d->d_lock); + dput(tmp); + continue; + } + name = ovl_dentry_get_redirect(d); if (name) { thislen = strlen(name); @@ -1040,13 +1058,13 @@ static char *ovl_get_redirect(struct dentry *dentry, bool abs_redirect) if (thislen + (name[0] != '/') > buflen) { ret = ERR_PTR(-EXDEV); spin_unlock(&d->d_lock); + dput(tmp); goto out_put; } buflen -= thislen; memcpy(&buf[buflen], name, thislen); spin_unlock(&d->d_lock); - tmp = dget_parent(d); dput(d); d = tmp; diff --git a/fs/overlayfs/inode.c b/fs/overlayfs/inode.c index 63906b3dafcb..a11564e90751 100644 --- a/fs/overlayfs/inode.c +++ b/fs/overlayfs/inode.c @@ -998,7 +998,7 @@ int ovl_set_nlink_lower(struct dentry *dentry) } unsigned int ovl_get_nlink(struct ovl_fs *ofs, struct dentry *lowerdentry, - struct dentry *upperdentry, + struct dentry *upperdentry, bool indexed, unsigned int fallback) { int nlink_diff; @@ -1006,7 +1006,15 @@ unsigned int ovl_get_nlink(struct ovl_fs *ofs, struct dentry *lowerdentry, char buf[13]; int err; - if (!lowerdentry || !upperdentry || d_inode(lowerdentry)->i_nlink == 1) + if (!lowerdentry || !upperdentry) + return fallback; + + /* + * A lower inode with one link is not indexed on copy up, unless all + * files are indexed for NFS export. If the caller found an index entry, + * then the xattr holds the union nlink, whatever the lower nlink is. + */ + if (!indexed && d_inode(lowerdentry)->i_nlink == 1) return fallback; err = ovl_getxattr_upper(ofs, upperdentry, OVL_XATTR_NLINK, @@ -1263,7 +1271,7 @@ struct inode *ovl_get_inode(struct super_block *sb, /* Recalculate nlink for non-dir due to indexing */ if (!is_dir) nlink = ovl_get_nlink(ofs, lowerdentry, upperdentry, - nlink); + oip->index, nlink); set_nlink(inode, nlink); ino = key->i_ino; } else { @@ -1278,7 +1286,7 @@ struct inode *ovl_get_inode(struct super_block *sb, } ovl_fill_inode(inode, realinode->i_mode, realinode->i_rdev); ovl_inode_init(inode, oip, ino, fsid); - WARN_ON_ONCE(!!IS_CASEFOLDED(inode) != ofs->casefold); + WARN_ON_ONCE(is_dir && !!IS_CASEFOLDED(inode) != ofs->casefold); if (upperdentry && ovl_is_impuredir(sb, upperdentry)) ovl_set_flag(OVL_IMPURE, inode); diff --git a/fs/overlayfs/namei.c b/fs/overlayfs/namei.c index ca899fdfaafd..c6127edb9be9 100644 --- a/fs/overlayfs/namei.c +++ b/fs/overlayfs/namei.c @@ -266,7 +266,8 @@ static int ovl_lookup_single(struct dentry *base, struct ovl_lookup_data *d, goto out_err; } - if (ofs->casefold != ovl_dentry_casefolded(this)) { + /* Filesystems set the casefold flag only on directories */ + if (d_is_dir(this) && ofs->casefold != ovl_dentry_casefolded(this)) { warn = "child wrong casefold"; err = -EREMOTE; goto out_warn; @@ -712,7 +713,7 @@ int ovl_verify_index(struct ovl_fs *ofs, struct dentry *index) if (err) goto fail; - if (ovl_get_nlink(ofs, origin.dentry, index, 0) == 0) + if (ovl_get_nlink(ofs, origin.dentry, index, true, 0) == 0) goto orphan; } @@ -942,8 +943,10 @@ static int ovl_fix_origin(struct ovl_fs *ofs, struct dentry *dentry, goto out; err = ovl_set_origin_fh(ofs, fh, upper); - if (!err) - err = ovl_set_impure(dentry->d_parent, upper->d_parent); + if (!err) { + /* upper->d_parent is not stable, use the overlay parent */ + err = ovl_set_impure_dir(dentry->d_parent); + } ovl_drop_write(dentry); out: diff --git a/fs/overlayfs/overlayfs.h b/fs/overlayfs/overlayfs.h index 92da556598da..901335026a20 100644 --- a/fs/overlayfs/overlayfs.h +++ b/fs/overlayfs/overlayfs.h @@ -574,6 +574,12 @@ int ovl_check_setxattr(struct ovl_fs *ofs, struct dentry *upperdentry, enum ovl_xattr ox, const void *value, size_t size, int xerr); int ovl_set_impure(struct dentry *dentry, struct dentry *upperdentry); + +static inline int ovl_set_impure_dir(struct dentry *dentry) +{ + return ovl_set_impure(dentry, ovl_dentry_upper(dentry)); +} + bool ovl_inuse_trylock(struct dentry *dentry); void ovl_inuse_unlock(struct dentry *dentry); bool ovl_is_inuse(struct dentry *dentry); @@ -804,7 +810,7 @@ static inline bool ovl_dir_is_real(struct inode *dir) int ovl_set_nlink_upper(struct dentry *dentry); int ovl_set_nlink_lower(struct dentry *dentry); unsigned int ovl_get_nlink(struct ovl_fs *ofs, struct dentry *lowerdentry, - struct dentry *upperdentry, + struct dentry *upperdentry, bool indexed, unsigned int fallback); int ovl_permission(const struct mnt_idmap *idmap, struct inode *inode, int mask); diff --git a/fs/overlayfs/readdir.c b/fs/overlayfs/readdir.c index 7d6f7f6022eb..2018e3114655 100644 --- a/fs/overlayfs/readdir.c +++ b/fs/overlayfs/readdir.c @@ -36,6 +36,7 @@ struct ovl_cache_entry { struct ovl_dir_cache { long refcount; u64 version; + bool is_refcounted; struct list_head entries; struct rb_root root; }; @@ -81,13 +82,13 @@ static int ovl_casefold(struct ovl_readdir_data *rdd, const char *str, int len, name_is_dot_dotdot(str, len)) return 0; - cf_name = kmalloc(NAME_MAX, GFP_KERNEL); + cf_name = kmalloc(NAME_MAX + 1, GFP_KERNEL); if (!cf_name) { rdd->err = -ENOMEM; return -ENOMEM; } - cf_len = utf8_casefold(rdd->map, &qstr, cf_name, NAME_MAX); + cf_len = utf8_casefold(rdd->map, &qstr, cf_name, NAME_MAX + 1); if (cf_len > 0) *dst = cf_name; else @@ -479,13 +480,31 @@ static void ovl_seek_cursor(struct ovl_dir_file *od, loff_t pos) od->cursor = p; } +/* + * Merged (refcounted) and impure (not refcounted) caches are never + * expected to be mixed. On mismatch, detach the cache from the inode + * and leak it rather than misuse it. A merged cache is still freed by + * its last ovl_cache_put(). + */ +static struct ovl_dir_cache *ovl_dir_cache_check(struct inode *inode, + bool is_refcounted) +{ + struct ovl_dir_cache *cache = ovl_dir_cache(inode); + + if (cache && WARN_ON(cache->is_refcounted != is_refcounted)) { + ovl_set_dir_cache(inode, NULL); + return NULL; + } + return cache; +} + static struct ovl_dir_cache *ovl_cache_get(struct dentry *dentry) { int res; struct ovl_dir_cache *cache; struct inode *inode = d_inode(dentry); - cache = ovl_dir_cache(inode); + cache = ovl_dir_cache_check(inode, true); if (cache && ovl_inode_version_get(inode) == cache->version) { WARN_ON(!cache->refcount); cache->refcount++; @@ -498,6 +517,7 @@ static struct ovl_dir_cache *ovl_cache_get(struct dentry *dentry) return ERR_PTR(-ENOMEM); cache->refcount = 1; + cache->is_refcounted = true; INIT_LIST_HEAD(&cache->entries); cache->root = RB_ROOT; @@ -568,8 +588,8 @@ static int ovl_cache_update(const struct path *path, struct ovl_cache_entry *p, goto get; } if (p->len == 2) { - /* we shall not be moved */ - this = dget(dir->d_parent); + /* d_splice_alias() can move even a locked dir */ + this = dget_parent(dir); goto get; } } @@ -698,7 +718,7 @@ static struct ovl_dir_cache *ovl_cache_get_impure(const struct path *path) struct ovl_fs *ofs = OVL_FS(dentry->d_sb); struct ovl_dir_cache *cache; - cache = ovl_dir_cache(inode); + cache = ovl_dir_cache_check(inode, false); if (cache && ovl_inode_version_get(inode) == cache->version) return cache; @@ -710,6 +730,7 @@ static struct ovl_dir_cache *ovl_cache_get_impure(const struct path *path) if (!cache) return ERR_PTR(-ENOMEM); + cache->is_refcounted = false; res = ovl_dir_read_impure(path, &cache->entries, &cache->root); if (res) { ovl_cache_free(&cache->entries); @@ -797,6 +818,7 @@ static int ovl_iterate_real(struct file *file, struct dir_context *ctx) struct dentry *dir = file->f_path.dentry; struct ovl_fs *ofs = OVL_FS(dir->d_sb); const struct ovl_layer *lower_layer = ovl_layer_lower(dir); + struct dentry *parent; struct ovl_readdir_translate rdt = { .ctx.actor = ovl_fill_real, .ctx.count = ctx->count, @@ -808,18 +830,26 @@ static int ovl_iterate_real(struct file *file, struct dir_context *ctx) if (rdt.xinobits && lower_layer) rdt.fsid = lower_layer->fsid; - if (OVL_TYPE_MERGE(ovl_path_type(dir->d_parent))) { + /* + * The lock on dir does not stop d_splice_alias() from moving it to + * another parent, which drops the reference dir holds on this one. + */ + parent = dget_parent(dir); + if (OVL_TYPE_MERGE(ovl_path_type(parent))) { struct kstat stat; struct path statpath = file->f_path; - statpath.dentry = dir->d_parent; + statpath.dentry = parent; err = vfs_getattr(&statpath, &stat, STATX_INO, 0); - if (err) + if (err) { + dput(parent); return err; + } WARN_ON_ONCE(dir->d_sb->s_dev != stat.dev); rdt.parent_ino = stat.ino; } + dput(parent); if (ovl_is_impure_dir(file)) { rdt.cache = ovl_cache_get_impure(&file->f_path); @@ -875,8 +905,10 @@ static bool ovl_need_adjust_d_ino(struct file *file) { struct dentry *dentry = file->f_path.dentry; struct ovl_fs *ofs = OVL_FS(dentry->d_sb); + struct dentry *parent; + enum ovl_path_type type; - /* If parent is merge, then need to adjust d_ino for '..' */ + /* With xino, need to map real d_ino to the unified overlay ino space */ if (ovl_xino_bits(ofs)) return true; @@ -885,8 +917,14 @@ static bool ovl_need_adjust_d_ino(struct file *file) return false; /* If dir is impure then need to adjust d_ino for copied up entries */ - if (ovl_is_impure_dir(file) || - OVL_TYPE_MERGE(ovl_path_type(dentry->d_parent))) + if (ovl_is_impure_dir(file)) + return true; + + /* If parent is merge, then need to adjust d_ino for '..' */ + parent = dget_parent(dentry); + type = ovl_path_type(parent); + dput(parent); + if (OVL_TYPE_MERGE(type)) return true; /* Pure: no need to adjust d_ino */ @@ -1055,7 +1093,8 @@ static int ovl_dir_open(struct inode *inode, struct file *file) return PTR_ERR(realfile); } od->realfile = realfile; - od->is_real = ovl_dir_is_real(inode); + od->is_real = !OVL_TYPE_MERGE(type) && + !ovl_test_flag(OVL_WHITEOUTS, inode); od->is_upper = OVL_TYPE_UPPER(type); file->private_data = od; diff --git a/fs/overlayfs/super.c b/fs/overlayfs/super.c index 19b6d54c4500..08695a99f4f9 100644 --- a/fs/overlayfs/super.c +++ b/fs/overlayfs/super.c @@ -100,11 +100,17 @@ static int ovl_revalidate_real(struct dentry *d, unsigned int flags, bool weak) dir = d_inode_rcu(parent); if (!dir) return -ECHILD; + /* + * Nothing pins d in RCU walk: eviction of the overlay + * inode may drop the last reference at any time. + */ + if (!try_take_dentry_name_snapshot(&n, d)) + return -ECHILD; } else { parent = dget_parent(d); dir = d_inode(parent); + take_dentry_name_snapshot(&n, d); } - take_dentry_name_snapshot(&n, d); ret = d->d_op->d_revalidate(dir, &n.name, d, flags); release_dentry_name_snapshot(&n); if (!(flags & LOOKUP_RCU)) @@ -516,6 +522,20 @@ static int ovl_report_in_use(struct ovl_fs *ofs, const char *name) } } +/* + * clone_private_mount() checks CAP_SYS_ADMIN in current->cred. + * ovl_fill_super_creds() runs under the stashed creator cred, which + * override_creds may have dropped. + * The task that issued FSCONFIG_CMD_CREATE is still current->real_cred, so + * use that only for the clone. creator_cred stays in effect for every other + * backing-fs operation. + */ +static struct vfsmount *ovl_clone_private_mount(const struct path *path) +{ + scoped_with_creds(current_real_cred()) + return clone_private_mount(path); +} + static int ovl_get_upper(struct super_block *sb, struct ovl_fs *ofs, struct ovl_layer *upper_layer, const struct path *upperpath) @@ -539,7 +559,7 @@ static int ovl_get_upper(struct super_block *sb, struct ovl_fs *ofs, if (err) goto out; - upper_mnt = clone_private_mount(upperpath); + upper_mnt = ovl_clone_private_mount(upperpath); err = PTR_ERR(upper_mnt); if (IS_ERR(upper_mnt)) { pr_err("failed to clone upperpath\n"); @@ -640,16 +660,21 @@ static int ovl_check_rename_whiteout(struct ovl_fs *ofs) static struct dentry *ovl_lookup_or_create(struct ovl_fs *ofs, struct dentry *parent, - const char *name, umode_t mode) + const char *name, bool is_dir) { struct dentry *child; child = ovl_start_creating_upper(ofs, parent, &QSTR(name)); if (!IS_ERR(child)) { - if (!child->d_inode) + if (!child->d_inode) { child = ovl_create_real(ofs, parent, child, &QSTR(name), - OVL_CATTR(mode)); + OVL_CATTR(is_dir ? S_IFDIR : + S_IFREG)); + } else if (is_dir && !d_can_lookup(child)) { + end_creating(child); + child = ERR_PTR(-ENOTDIR); + } end_creating_keep(child); } dput(parent); @@ -671,7 +696,7 @@ static int ovl_create_volatile_dirty(struct ovl_fs *ofs) const char *const *name = volatile_path; for (ctr = ARRAY_SIZE(volatile_path); ctr; ctr--, name++) { - d = ovl_lookup_or_create(ofs, d, *name, ctr > 1 ? S_IFDIR : S_IFREG); + d = ovl_lookup_or_create(ofs, d, *name, ctr > 1); if (IS_ERR(d)) return PTR_ERR(d); } @@ -1112,7 +1137,7 @@ static int ovl_get_layers(struct super_block *sb, struct ovl_fs *ofs, } } - mnt = clone_private_mount(&l->path); + mnt = ovl_clone_private_mount(&l->path); err = PTR_ERR(mnt); if (IS_ERR(mnt)) { pr_err("failed to clone lowerpath\n"); diff --git a/include/linux/dcache.h b/include/linux/dcache.h index 796282817181..84b0cfe4ed0e 100644 --- a/include/linux/dcache.h +++ b/include/linux/dcache.h @@ -665,6 +665,7 @@ struct name_snapshot { union shortname_store inline_name; }; void take_dentry_name_snapshot(struct name_snapshot *, struct dentry *); +bool try_take_dentry_name_snapshot(struct name_snapshot *, struct dentry *); void release_dentry_name_snapshot(struct name_snapshot *); static inline struct dentry *d_first_child(const struct dentry *dentry)