Skip to content

Commit cf06d79

Browse files
committed
Merge tag 'ovl-update-6.18' of git://git.kernel.org/pub/scm/linux/kernel/git/overlayfs/vfs
Pull overlayfs updates from Amir Goldstein: - Work by André Almeida to support case-insensitive overlayfs Underlying case-insensitive filesystems casefolding is per directory, but for overlayfs it is all-or-nothing. It supports layers where all directories are casefolded (with same encoding) or layers where no directories are casefolded. - A fix for a "bug" in Neil's ovl directory lock changes, which only manifested itself with casefold enabled layers which may return an unhashed negative dentry from lookup. * tag 'ovl-update-6.18' of git://git.kernel.org/pub/scm/linux/kernel/git/overlayfs/vfs: ovl: make sure that ovl_create_real() returns a hashed dentry ovl: Support mounting case-insensitive enabled layers ovl: Check for casefold consistency when creating new dentries ovl: Add S_CASEFOLD as part of the inode flag to be copied ovl: Set case-insensitive dentry operations for ovl sb ovl: Ensure that all layers have the same encoding ovl: Create ovl_casefold() to support casefolded strncmp() ovl: Prepare for mounting case-insensitive enabled layers fs: Create sb_same_encoding() helper fs: Create sb_encoding() helper
2 parents 9b0d551 + ad14239 commit cf06d79

12 files changed

Lines changed: 254 additions & 43 deletions

File tree

fs/overlayfs/copy_up.c

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -670,7 +670,7 @@ static int ovl_copy_up_metadata(struct ovl_copy_up_ctx *c, struct dentry *temp)
670670
if (err)
671671
return err;
672672

673-
if (inode->i_flags & OVL_COPY_I_FLAGS_MASK &&
673+
if (inode->i_flags & OVL_FATTR_I_FLAGS_MASK &&
674674
(S_ISREG(c->stat.mode) || S_ISDIR(c->stat.mode))) {
675675
/*
676676
* Copy the fileattr inode flags that are the source of already

fs/overlayfs/dir.c

Lines changed: 28 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -187,6 +187,13 @@ struct dentry *ovl_create_real(struct ovl_fs *ofs, struct dentry *parent,
187187
/* mkdir is special... */
188188
newdentry = ovl_do_mkdir(ofs, dir, newdentry, attr->mode);
189189
err = PTR_ERR_OR_ZERO(newdentry);
190+
/* expect to inherit casefolding from workdir/upperdir */
191+
if (!err && ofs->casefold != ovl_dentry_casefolded(newdentry)) {
192+
pr_warn_ratelimited("wrong inherited casefold (%pd2)\n",
193+
newdentry);
194+
dput(newdentry);
195+
err = -EINVAL;
196+
}
190197
break;
191198

192199
case S_IFCHR:
@@ -205,12 +212,32 @@ struct dentry *ovl_create_real(struct ovl_fs *ofs, struct dentry *parent,
205212
err = -EPERM;
206213
}
207214
}
208-
if (!err && WARN_ON(!newdentry->d_inode)) {
215+
if (err)
216+
goto out;
217+
218+
if (WARN_ON(!newdentry->d_inode)) {
209219
/*
210220
* Not quite sure if non-instantiated dentry is legal or not.
211221
* VFS doesn't seem to care so check and warn here.
212222
*/
213223
err = -EIO;
224+
} else if (d_unhashed(newdentry)) {
225+
struct dentry *d;
226+
/*
227+
* Some filesystems (i.e. casefolded) may return an unhashed
228+
* negative dentry from the ovl_lookup_upper() call before
229+
* ovl_create_real().
230+
* In that case, lookup again after making the newdentry
231+
* positive, so ovl_create_upper() always returns a hashed
232+
* positive dentry.
233+
*/
234+
d = ovl_lookup_upper(ofs, newdentry->d_name.name, parent,
235+
newdentry->d_name.len);
236+
dput(newdentry);
237+
if (IS_ERR_OR_NULL(d))
238+
err = d ? PTR_ERR(d) : -ENOENT;
239+
else
240+
return d;
214241
}
215242
out:
216243
if (err) {

fs/overlayfs/inode.c

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1277,6 +1277,7 @@ struct inode *ovl_get_inode(struct super_block *sb,
12771277
}
12781278
ovl_fill_inode(inode, realinode->i_mode, realinode->i_rdev);
12791279
ovl_inode_init(inode, oip, ino, fsid);
1280+
WARN_ON_ONCE(!!IS_CASEFOLDED(inode) != ofs->casefold);
12801281

12811282
if (upperdentry && ovl_is_impuredir(sb, upperdentry))
12821283
ovl_set_flag(OVL_IMPURE, inode);

fs/overlayfs/namei.c

Lines changed: 9 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -239,13 +239,14 @@ static int ovl_lookup_single(struct dentry *base, struct ovl_lookup_data *d,
239239
char val;
240240

241241
/*
242-
* We allow filesystems that are case-folding capable but deny composing
243-
* ovl stack from case-folded directories. If someone has enabled case
244-
* folding on a directory on underlying layer, the warranty of the ovl
245-
* stack is voided.
242+
* We allow filesystems that are case-folding capable as long as the
243+
* layers are consistently enabled in the stack, enabled for every dir
244+
* or disabled in all dirs. If someone has modified case folding on a
245+
* directory on underlying layer, the warranty of the ovl stack is
246+
* voided.
246247
*/
247-
if (ovl_dentry_casefolded(base)) {
248-
warn = "case folded parent";
248+
if (ofs->casefold != ovl_dentry_casefolded(base)) {
249+
warn = "parent wrong casefold";
249250
err = -ESTALE;
250251
goto out_warn;
251252
}
@@ -259,8 +260,8 @@ static int ovl_lookup_single(struct dentry *base, struct ovl_lookup_data *d,
259260
goto out_err;
260261
}
261262

262-
if (ovl_dentry_casefolded(this)) {
263-
warn = "case folded child";
263+
if (ofs->casefold != ovl_dentry_casefolded(this)) {
264+
warn = "child wrong casefold";
264265
err = -EREMOTE;
265266
goto out_warn;
266267
}

fs/overlayfs/overlayfs.h

Lines changed: 5 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -820,10 +820,12 @@ struct inode *ovl_get_inode(struct super_block *sb,
820820
struct ovl_inode_params *oip);
821821
void ovl_copyattr(struct inode *to);
822822

823+
/* vfs fileattr flags read from overlay.protattr xattr to ovl inode */
824+
#define OVL_PROT_I_FLAGS_MASK (S_APPEND | S_IMMUTABLE)
825+
/* vfs fileattr flags copied from real to ovl inode */
826+
#define OVL_FATTR_I_FLAGS_MASK (OVL_PROT_I_FLAGS_MASK | S_SYNC | S_NOATIME)
823827
/* vfs inode flags copied from real to ovl inode */
824-
#define OVL_COPY_I_FLAGS_MASK (S_SYNC | S_NOATIME | S_APPEND | S_IMMUTABLE)
825-
/* vfs inode flags read from overlay.protattr xattr to ovl inode */
826-
#define OVL_PROT_I_FLAGS_MASK (S_APPEND | S_IMMUTABLE)
828+
#define OVL_COPY_I_FLAGS_MASK (OVL_FATTR_I_FLAGS_MASK | S_CASEFOLD)
827829

828830
/*
829831
* fileattr flags copied from lower to upper inode on copy up.

fs/overlayfs/ovl_entry.h

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -91,6 +91,7 @@ struct ovl_fs {
9191
struct mutex whiteout_lock;
9292
/* r/o snapshot of upperdir sb's only taken on volatile mounts */
9393
errseq_t errseq;
94+
bool casefold;
9495
};
9596

9697
/* Number of lower layers, not including data-only layers */

fs/overlayfs/params.c

Lines changed: 12 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -276,17 +276,26 @@ static int ovl_mount_dir(const char *name, struct path *path)
276276
static int ovl_mount_dir_check(struct fs_context *fc, const struct path *path,
277277
enum ovl_opt layer, const char *name, bool upper)
278278
{
279+
bool is_casefolded = ovl_dentry_casefolded(path->dentry);
279280
struct ovl_fs_context *ctx = fc->fs_private;
281+
struct ovl_fs *ofs = fc->s_fs_info;
280282

281283
if (!d_is_dir(path->dentry))
282284
return invalfc(fc, "%s is not a directory", name);
283285

284286
/*
285287
* Allow filesystems that are case-folding capable but deny composing
286-
* ovl stack from case-folded directories.
288+
* ovl stack from inconsistent case-folded directories.
287289
*/
288-
if (ovl_dentry_casefolded(path->dentry))
289-
return invalfc(fc, "case-insensitive directory on %s not supported", name);
290+
if (!ctx->casefold_set) {
291+
ofs->casefold = is_casefolded;
292+
ctx->casefold_set = true;
293+
}
294+
295+
if (ofs->casefold != is_casefolded) {
296+
return invalfc(fc, "case-%ssensitive directory on %s is inconsistent",
297+
is_casefolded ? "in" : "", name);
298+
}
290299

291300
if (ovl_dentry_weird(path->dentry))
292301
return invalfc(fc, "filesystem on %s not supported", name);

fs/overlayfs/params.h

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -33,6 +33,7 @@ struct ovl_fs_context {
3333
struct ovl_opt_set set;
3434
struct ovl_fs_context_layer *lower;
3535
char *lowerdir_all; /* user provided lowerdir string */
36+
bool casefold_set;
3637
};
3738

3839
int ovl_init_fs_context(struct fs_context *fc);

0 commit comments

Comments
 (0)