On Wed, Nov 06, 2024 at 02:09:58PM +1100, Aleksa Sarai wrote: > overlayfs helpfully provides a lot of of information when setting up a > mount, but unfortunately when using the fsopen(2) API, a lot of this > information is mixed in with the general kernel log. > > In addition, some of the logs can become a source of spam if programs > are creating many internal overlayfs mounts (in runc we use an internal > overlayfs mount to protect the runc binary against container breakout > attacks like CVE-2019-5736, and xino_auto=on caused a lot of spam in > dmesg because we didn't explicitly disable xino[1]). > > By logging to the fs_context, userspace can get more accurate > information when using fsopen(2) and there is less dmesg spam for > systems where a lot of programs are using fsopen("overlay"). Legacy > mount(2) users will still see the same errors in dmesg as they did > before (though the prefix of the log messages will now be "overlay" > rather than "overlayfs"). > > [1]: https://bbs.archlinux.org/viewtopic.php?pid=2206551 > > Signed-off-by: Aleksa Sarai <cyphar@xxxxxxxxxx> > --- To me this sounds inherently useful! So I'm all for it. > In order to avoid passing fs_context everywhere, I opted to pass p_log > instead to functions that only did some ancilliary logging and only pass > fs_context to functions that already took ovl_fs_context. While I feel > this makes it clearer which functions are just using fs_context for > logging purposes, this makes overlayfs the first real user of p_log, and > I'm not sure how you folks might feel about that. > > I've also tried to unify the layout of log messages (with some > exceptions) but I guess it's possible that keeping the existing > formatting might be important for programs that parse dmesg. Let me know > if you'd like to keep the existing (inconsistent) formatting. > > Since this isn't explicitly documented, I aught to mention that the > fc_context logs are available even after *_fill_super is completed and > the superblock has been created, so logging info/warn messages in > *_fill_super is still fine and userspace will still be able to get the > logs after doing fsconfig(FSCONFIG_CREATE). > --- > fs/overlayfs/params.c | 151 ++++++++++++++------------------ > fs/overlayfs/params.h | 3 +- > fs/overlayfs/super.c | 232 ++++++++++++++++++++++++++------------------------ > 3 files changed, 183 insertions(+), 203 deletions(-) > > diff --git a/fs/overlayfs/params.c b/fs/overlayfs/params.c > index e42546c6c5df..d72f642df38e 100644 > --- a/fs/overlayfs/params.c > +++ b/fs/overlayfs/params.c > @@ -186,7 +186,7 @@ static int ovl_parse_monolithic(struct fs_context *fc, void *data) > return vfs_parse_monolithic_sep(fc, data, ovl_next_opt); > } > > -static ssize_t ovl_parse_param_split_lowerdirs(char *str) > +static ssize_t ovl_parse_param_split_lowerdirs(struct p_log *log, char *str) > { > ssize_t nr_layers = 1, nr_colons = 0; > char *s, *d; > @@ -199,10 +199,8 @@ static ssize_t ovl_parse_param_split_lowerdirs(char *str) > bool next_colon = (*(s + 1) == ':'); > > nr_colons++; > - if (nr_colons == 2 && next_colon) { > - pr_err("only single ':' or double '::' sequences of unescaped colons in lowerdir mount option allowed.\n"); > - return -EINVAL; > - } > + if (nr_colons == 2 && next_colon) > + return inval_plog(log, "only single ':' or double '::' sequences of unescaped colons in lowerdir mount option allowed"); > /* count layers, not colons */ > if (!next_colon) > nr_layers++; > @@ -214,10 +212,8 @@ static ssize_t ovl_parse_param_split_lowerdirs(char *str) > *d = *s; > if (!*s) { > /* trailing colons */ > - if (nr_colons) { > - pr_err("unescaped trailing colons in lowerdir mount option.\n"); > - return -EINVAL; > - } > + if (nr_colons) > + return inval_plog(log, "unescaped trailing colons in lowerdir mount option"); > break; > } > nr_colons = 0; > @@ -226,22 +222,17 @@ static ssize_t ovl_parse_param_split_lowerdirs(char *str) > return nr_layers; > } > > -static int ovl_mount_dir_noesc(const char *name, struct path *path) > +static int ovl_mount_dir_noesc(struct p_log *log, const char *name, > + struct path *path) > { > int err = -EINVAL; > > - if (!*name) { > - pr_err("empty lowerdir\n"); > - goto out; > - } > - err = kern_path(name, LOOKUP_FOLLOW, path); > - if (err) { > - pr_err("failed to resolve '%s': %i\n", name, err); > - goto out; > - } > - return 0; > + if (!*name) > + return inval_plog(log, "empty lowerdir"); > > -out: > + err = kern_path(name, LOOKUP_FOLLOW, path); > + if (err) > + error_plog(log, "failed to resolve '%s': %i", name, err); > return err; > } > > @@ -258,14 +249,15 @@ static void ovl_unescape(char *s) > } > } > > -static int ovl_mount_dir(const char *name, struct path *path) > +static int ovl_mount_dir(struct p_log *log, const char *name, > + struct path *path) > { > int err = -ENOMEM; > char *tmp = kstrdup(name, GFP_KERNEL); > > if (tmp) { > ovl_unescape(tmp); > - err = ovl_mount_dir_noesc(tmp, path); > + err = ovl_mount_dir_noesc(log, tmp, path); > kfree(tmp); > } > return err; > @@ -378,9 +370,9 @@ static int ovl_parse_layer(struct fs_context *fc, const char *layer_name, enum o > return -ENOMEM; > > if (upper || layer == Opt_lowerdir) > - err = ovl_mount_dir(name, &path); > + err = ovl_mount_dir(&fc->log, name, &path); > else > - err = ovl_mount_dir_noesc(name, &path); > + err = ovl_mount_dir_noesc(&fc->log, name, &path); > if (err) > goto out_free; > > @@ -448,10 +440,8 @@ static int ovl_parse_param_lowerdir(const char *name, struct fs_context *fc) > if (!*name) > return 0; > > - if (*name == ':') { > - pr_err("cannot append lower layer\n"); > - return -EINVAL; > - } > + if (*name == ':') > + return invalfc(fc, "cannot append lower layer"); > > // Store user provided lowerdir string to show in mount options > ctx->lowerdir_all = kstrdup(name, GFP_KERNEL); > @@ -463,12 +453,12 @@ static int ovl_parse_param_lowerdir(const char *name, struct fs_context *fc) > return -ENOMEM; > > err = -EINVAL; > - nr_lower = ovl_parse_param_split_lowerdirs(dup); > + nr_lower = ovl_parse_param_split_lowerdirs(&fc->log, dup); > if (nr_lower < 0) > goto out_err; > > if (nr_lower > OVL_MAX_STACK) { > - pr_err("too many lower directories, limit is %d\n", OVL_MAX_STACK); > + errorfc(fc, "too many lower directories, limit is %d", OVL_MAX_STACK); > goto out_err; > } > > @@ -493,7 +483,7 @@ static int ovl_parse_param_lowerdir(const char *name, struct fs_context *fc) > * there are no data layers. > */ > if (ctx->nr_data > 0) { > - pr_err("regular lower layers cannot follow data lower layers\n"); > + errorfc(fc, "regular lower layers cannot follow data lower layers"); > goto out_err; > } > > @@ -597,9 +587,8 @@ static int ovl_parse_param(struct fs_context *fc, struct fs_parameter *param) > config->userxattr = true; > break; > default: > - pr_err("unrecognized mount option \"%s\" or missing value\n", > - param->key); > - return -EINVAL; > + return invalfc(fc, "unrecognized mount option \"%s\" or missing value", > + param->key); > } > > return err; > @@ -750,44 +739,43 @@ void ovl_free_fs(struct ovl_fs *ofs) > kfree(ofs); > } > > -int ovl_fs_params_verify(const struct ovl_fs_context *ctx, > +int ovl_fs_params_verify(struct fs_context *fc, > struct ovl_config *config) > { > + const struct ovl_fs_context *ctx = fc->fs_private; > struct ovl_opt_set set = ctx->set; > > /* Workdir/index are useless in non-upper mount */ > if (!config->upperdir) { > if (config->workdir) { > - pr_info("option \"workdir=%s\" is useless in a non-upper mount, ignore\n", > - config->workdir); > + infofc(fc, "option \"workdir=%s\" is useless in a non-upper mount, ignore", > + config->workdir); > kfree(config->workdir); > config->workdir = NULL; > } > if (config->index && set.index) { > - pr_info("option \"index=on\" is useless in a non-upper mount, ignore\n"); > + infofc(fc, "option \"index=on\" is useless in a non-upper mount, ignore"); > set.index = false; > } > config->index = false; > } > > if (!config->upperdir && config->ovl_volatile) { > - pr_info("option \"volatile\" is meaningless in a non-upper mount, ignoring it.\n"); > + infofc(fc, "option \"volatile\" is meaningless in a non-upper mount, ignoring it"); > config->ovl_volatile = false; > } > > if (!config->upperdir && config->uuid == OVL_UUID_ON) { > - pr_info("option \"uuid=on\" requires an upper fs, falling back to uuid=null.\n"); > + infofc(fc, "option \"uuid=on\" requires an upper fs, falling back to uuid=null"); > config->uuid = OVL_UUID_NULL; > } > > /* Resolve verity -> metacopy dependency */ > if (config->verity_mode && !config->metacopy) { > /* Don't allow explicit specified conflicting combinations */ > - if (set.metacopy) { > - pr_err("conflicting options: metacopy=off,verity=%s\n", > - ovl_verity_mode(config)); > - return -EINVAL; > - } > + if (set.metacopy) > + return invalfc(fc, "conflicting options: metacopy=off,verity=%s", > + ovl_verity_mode(config)); > /* Otherwise automatically enable metacopy. */ > config->metacopy = true; > } > @@ -801,23 +789,21 @@ int ovl_fs_params_verify(const struct ovl_fs_context *ctx, > > /* Resolve verity -> metacopy -> redirect_dir dependency */ > if (config->metacopy && config->redirect_mode != OVL_REDIRECT_ON) { > - if (set.metacopy && set.redirect) { > - pr_err("conflicting options: metacopy=on,redirect_dir=%s\n", > - ovl_redirect_mode(config)); > - return -EINVAL; > - } > - if (config->verity_mode && set.redirect) { > - pr_err("conflicting options: verity=%s,redirect_dir=%s\n", > - ovl_verity_mode(config), ovl_redirect_mode(config)); > - return -EINVAL; > - } > + if (set.metacopy && set.redirect) > + return invalfc(fc, "conflicting options: metacopy=on,redirect_dir=%s", > + ovl_redirect_mode(config)); > + if (config->verity_mode && set.redirect) > + return invalfc(fc, "conflicting options: verity=%s,redirect_dir=%s", > + ovl_verity_mode(config), > + ovl_redirect_mode(config)); > + > if (set.redirect) { > /* > * There was an explicit redirect_dir=... that resulted > * in this conflict. > */ > - pr_info("disabling metacopy due to redirect_dir=%s\n", > - ovl_redirect_mode(config)); > + infofc(fc, "disabling metacopy due to redirect_dir=%s", > + ovl_redirect_mode(config)); > config->metacopy = false; > } else { > /* Automatically enable redirect otherwise. */ > @@ -829,17 +815,16 @@ int ovl_fs_params_verify(const struct ovl_fs_context *ctx, > if (config->nfs_export && !config->index) { > if (!config->upperdir && > config->redirect_mode != OVL_REDIRECT_NOFOLLOW) { > - pr_info("NFS export requires \"redirect_dir=nofollow\" on non-upper mount, falling back to nfs_export=off.\n"); > + infofc(fc, "NFS export requires \"redirect_dir=nofollow\" on non-upper mount, falling back to nfs_export=off"); > config->nfs_export = false; > } else if (set.nfs_export && set.index) { > - pr_err("conflicting options: nfs_export=on,index=off\n"); > - return -EINVAL; > + return invalfc(fc, "conflicting options: nfs_export=on,index=off"); > } else if (set.index) { > /* > * There was an explicit index=off that resulted > * in this conflict. > */ > - pr_info("disabling nfs_export due to index=off\n"); > + infofc(fc, "disabling nfs_export due to index=off"); > config->nfs_export = false; > } else { > /* Automatically enable index otherwise. */ > @@ -849,31 +834,29 @@ int ovl_fs_params_verify(const struct ovl_fs_context *ctx, > > /* Resolve nfs_export -> !metacopy && !verity dependency */ > if (config->nfs_export && config->metacopy) { > - if (set.nfs_export && set.metacopy) { > - pr_err("conflicting options: nfs_export=on,metacopy=on\n"); > - return -EINVAL; > - } > + if (set.nfs_export && set.metacopy) > + return invalfc(fc, "conflicting options: nfs_export=on,metacopy=on"); > if (set.metacopy) { > /* > * There was an explicit metacopy=on that resulted > * in this conflict. > */ > - pr_info("disabling nfs_export due to metacopy=on\n"); > + infofc(fc, "disabling nfs_export due to metacopy=on"); > config->nfs_export = false; > } else if (config->verity_mode) { > /* > * There was an explicit verity=.. that resulted > * in this conflict. > */ > - pr_info("disabling nfs_export due to verity=%s\n", > - ovl_verity_mode(config)); > + infofc(fc, "disabling nfs_export due to verity=%s", > + ovl_verity_mode(config)); > config->nfs_export = false; > } else { > /* > * There was an explicit nfs_export=on that resulted > * in this conflict. > */ > - pr_info("disabling metacopy due to nfs_export=on\n"); > + infofc(fc, "disabling metacopy due to nfs_export=on"); > config->metacopy = false; > } > } > @@ -882,20 +865,14 @@ int ovl_fs_params_verify(const struct ovl_fs_context *ctx, > /* Resolve userxattr -> !redirect && !metacopy && !verity dependency */ > if (config->userxattr) { > if (set.redirect && > - config->redirect_mode != OVL_REDIRECT_NOFOLLOW) { > - pr_err("conflicting options: userxattr,redirect_dir=%s\n", > - ovl_redirect_mode(config)); > - return -EINVAL; > - } > - if (config->metacopy && set.metacopy) { > - pr_err("conflicting options: userxattr,metacopy=on\n"); > - return -EINVAL; > - } > - if (config->verity_mode) { > - pr_err("conflicting options: userxattr,verity=%s\n", > - ovl_verity_mode(config)); > - return -EINVAL; > - } > + config->redirect_mode != OVL_REDIRECT_NOFOLLOW) > + return invalfc(fc, "conflicting options: userxattr,redirect_dir=%s", > + ovl_redirect_mode(config)); > + if (config->metacopy && set.metacopy) > + return invalfc(fc, "conflicting options: userxattr,metacopy=on"); > + if (config->verity_mode) > + return invalfc(fc, "conflicting options: userxattr,verity=%s", > + ovl_verity_mode(config)); > /* > * Silently disable default setting of redirect and metacopy. > * This shall be the default in the future as well: these > @@ -934,10 +911,8 @@ int ovl_fs_params_verify(const struct ovl_fs_context *ctx, > */ > } > > - if (ctx->nr_data > 0 && !config->metacopy) { > - pr_err("lower data-only dirs require metacopy support.\n"); > - return -EINVAL; > - } > + if (ctx->nr_data > 0 && !config->metacopy) > + return invalfc(fc, "lower data-only dirs require metacopy support"); > > return 0; > } > diff --git a/fs/overlayfs/params.h b/fs/overlayfs/params.h > index c96d93982021..0ffe64277134 100644 > --- a/fs/overlayfs/params.h > +++ b/fs/overlayfs/params.h > @@ -37,7 +37,6 @@ struct ovl_fs_context { > > int ovl_init_fs_context(struct fs_context *fc); > void ovl_free_fs(struct ovl_fs *ofs); > -int ovl_fs_params_verify(const struct ovl_fs_context *ctx, > - struct ovl_config *config); > +int ovl_fs_params_verify(struct fs_context *fc, struct ovl_config *config); > int ovl_show_options(struct seq_file *m, struct dentry *dentry); > const char *ovl_xino_mode(struct ovl_config *config); > diff --git a/fs/overlayfs/super.c b/fs/overlayfs/super.c > index fe511192f83c..69c6c25990ac 100644 > --- a/fs/overlayfs/super.c > +++ b/fs/overlayfs/super.c > @@ -272,7 +272,7 @@ static const struct super_operations ovl_super_operations = { > #define OVL_WORKDIR_NAME "work" > #define OVL_INDEXDIR_NAME "index" > > -static struct dentry *ovl_workdir_create(struct ovl_fs *ofs, > +static struct dentry *ovl_workdir_create(struct p_log *log, struct ovl_fs *ofs, > const char *name, bool persist) > { > struct inode *dir = ofs->workbasedir->d_inode; > @@ -356,33 +356,33 @@ static struct dentry *ovl_workdir_create(struct ovl_fs *ofs, > out_dput: > dput(work); > out_err: > - pr_warn("failed to create directory %s/%s (errno: %i); mounting read-only\n", > - ofs->config.workdir, name, -err); > + warn_plog(log, "failed to create directory %s/%s (errno: %i); mounting read-only", > + ofs->config.workdir, name, -err); > work = NULL; > goto out_unlock; > } > > -static int ovl_check_namelen(const struct path *path, struct ovl_fs *ofs, > - const char *name) > +static int ovl_check_namelen(struct p_log *log, const struct path *path, > + struct ovl_fs *ofs, const char *name) > { > struct kstatfs statfs; > int err = vfs_statfs(path, &statfs); > > if (err) > - pr_err("statfs failed on '%s'\n", name); > + error_plog(log, "statfs failed on '%s'", name); > else > ofs->namelen = max(ofs->namelen, statfs.f_namelen); > > return err; > } > > -static int ovl_lower_dir(const char *name, struct path *path, > +static int ovl_lower_dir(struct p_log *log, const char *name, struct path *path, > struct ovl_fs *ofs, int *stack_depth) > { > int fh_type; > int err; > > - err = ovl_check_namelen(path, ofs, name); > + err = ovl_check_namelen(log, path, ofs, name); > if (err) > return err; > > @@ -397,8 +397,8 @@ static int ovl_lower_dir(const char *name, struct path *path, > (ofs->config.index && ofs->config.upperdir)) && !fh_type) { > ofs->config.index = false; > ofs->config.nfs_export = false; > - pr_warn("fs on '%s' does not support file handles, falling back to index=off,nfs_export=off.\n", > - name); > + warn_plog(log, "fs on '%s' does not support file handles, falling back to index=off,nfs_export=off", > + name); > } > ofs->nofh |= !fh_type; > /* > @@ -408,8 +408,8 @@ static int ovl_lower_dir(const char *name, struct path *path, > if (ofs->config.xino == OVL_XINO_AUTO && > ofs->config.upperdir && !fh_type) { > ofs->config.xino = OVL_XINO_OFF; > - pr_warn("fs on '%s' does not support file handles, falling back to xino=off.\n", > - name); > + warn_plog(log, "fs on '%s' does not support file handles, falling back to xino=off", > + name); > } > > /* Check if lower fs has 32bit inode numbers */ > @@ -433,8 +433,9 @@ static bool ovl_workdir_ok(struct dentry *workdir, struct dentry *upperdir) > return ok; > } > > -static int ovl_setup_trap(struct super_block *sb, struct dentry *dir, > - struct inode **ptrap, const char *name) > +static int ovl_setup_trap(struct p_log *log, struct super_block *sb, > + struct dentry *dir, struct inode **ptrap, > + const char *name) > { > struct inode *trap; > int err; > @@ -443,7 +444,7 @@ static int ovl_setup_trap(struct super_block *sb, struct dentry *dir, > err = PTR_ERR_OR_ZERO(trap); > if (err) { > if (err == -ELOOP) > - pr_err("conflicting %s path\n", name); > + error_plog(log, "conflicting %s path", name); > return err; > } > > @@ -457,21 +458,22 @@ static int ovl_setup_trap(struct super_block *sb, struct dentry *dir, > * for example, an old overlay mount is leaked and now its upperdir is > * attempted to be used as a lower layer in a new overlay mount. > */ > -static int ovl_report_in_use(struct ovl_fs *ofs, const char *name) > +static int ovl_report_in_use(struct p_log *log, struct ovl_fs *ofs, > + const char *name) > { > if (ofs->config.index) { > - pr_err("%s is in-use as upperdir/workdir of another mount, mount with '-o index=off' to override exclusive upperdir protection.\n", > - name); > + error_plog(log, "%s is in-use as upperdir/workdir of another mount, mount with '-o index=off' to override exclusive upperdir protection.", > + name); > return -EBUSY; > } else { > - pr_warn("%s is in-use as upperdir/workdir of another mount, accessing files from both mounts will result in undefined behavior.\n", > - name); > + warn_plog(log, "%s is in-use as upperdir/workdir of another mount, accessing files from both mounts will result in undefined behavior.", > + name); > return 0; > } > } > > -static int ovl_get_upper(struct super_block *sb, struct ovl_fs *ofs, > - struct ovl_layer *upper_layer, > +static int ovl_get_upper(struct p_log *log, struct super_block *sb, > + struct ovl_fs *ofs, struct ovl_layer *upper_layer, > const struct path *upperpath) > { > struct vfsmount *upper_mnt; > @@ -479,16 +481,16 @@ static int ovl_get_upper(struct super_block *sb, struct ovl_fs *ofs, > > /* Upperdir path should not be r/o */ > if (__mnt_is_readonly(upperpath->mnt)) { > - pr_err("upper fs is r/o, try multi-lower layers mount\n"); > + error_plog(log, "upper fs is r/o, try multi-lower layers mount"); > err = -EINVAL; > goto out; > } > > - err = ovl_check_namelen(upperpath, ofs, ofs->config.upperdir); > + err = ovl_check_namelen(log, upperpath, ofs, ofs->config.upperdir); > if (err) > goto out; > > - err = ovl_setup_trap(sb, upperpath->dentry, &upper_layer->trap, > + err = ovl_setup_trap(log, sb, upperpath->dentry, &upper_layer->trap, > "upperdir"); > if (err) > goto out; > @@ -496,7 +498,7 @@ static int ovl_get_upper(struct super_block *sb, struct ovl_fs *ofs, > upper_mnt = clone_private_mount(upperpath); > err = PTR_ERR(upper_mnt); > if (IS_ERR(upper_mnt)) { > - pr_err("failed to clone upperpath\n"); > + error_plog(log, "failed to clone upperpath"); > goto out; > } > > @@ -521,7 +523,7 @@ static int ovl_get_upper(struct super_block *sb, struct ovl_fs *ofs, > if (ovl_inuse_trylock(ovl_upper_mnt(ofs)->mnt_root)) { > ofs->upperdir_locked = true; > } else { > - err = ovl_report_in_use(ofs, "upperdir"); > + err = ovl_report_in_use(log, ofs, "upperdir"); > if (err) > goto out; > } > @@ -632,8 +634,8 @@ static int ovl_create_volatile_dirty(struct ovl_fs *ofs) > return 0; > } > > -static int ovl_make_workdir(struct super_block *sb, struct ovl_fs *ofs, > - const struct path *workpath) > +static int ovl_make_workdir(struct p_log *log, struct super_block *sb, > + struct ovl_fs *ofs, const struct path *workpath) > { > struct vfsmount *mnt = ovl_upper_mnt(ofs); > struct dentry *workdir; > @@ -647,14 +649,15 @@ static int ovl_make_workdir(struct super_block *sb, struct ovl_fs *ofs, > if (err) > return err; > > - workdir = ovl_workdir_create(ofs, OVL_WORKDIR_NAME, false); > + workdir = ovl_workdir_create(log, ofs, OVL_WORKDIR_NAME, false); > err = PTR_ERR(workdir); > if (IS_ERR_OR_NULL(workdir)) > goto out; > > ofs->workdir = workdir; > > - err = ovl_setup_trap(sb, ofs->workdir, &ofs->workdir_trap, "workdir"); > + err = ovl_setup_trap(log, sb, ofs->workdir, &ofs->workdir_trap, > + "workdir"); > if (err) > goto out; > > @@ -670,7 +673,7 @@ static int ovl_make_workdir(struct super_block *sb, struct ovl_fs *ofs, > > d_type = err; > if (!d_type) > - pr_warn("upper fs needs to support d_type.\n"); > + warn_plog(log, "upper fs needs to support d_type"); > > /* Check if upper/work fs supports O_TMPFILE */ > tmpfile = ovl_do_tmpfile(ofs, ofs->workdir, S_IFREG | 0); > @@ -678,7 +681,7 @@ static int ovl_make_workdir(struct super_block *sb, struct ovl_fs *ofs, > if (ofs->tmpfile) > fput(tmpfile); > else > - pr_warn("upper fs does not support tmpfile.\n"); > + warn_plog(log, "upper fs does not support tmpfile"); > > > /* Check if upper/work fs supports RENAME_WHITEOUT */ > @@ -688,30 +691,30 @@ static int ovl_make_workdir(struct super_block *sb, struct ovl_fs *ofs, > > rename_whiteout = err; > if (!rename_whiteout) > - pr_warn("upper fs does not support RENAME_WHITEOUT.\n"); > + warn_plog(log, "upper fs does not support RENAME_WHITEOUT"); > > /* > * Check if upper/work fs supports (trusted|user).overlay.* xattr > */ > err = ovl_setxattr(ofs, ofs->workdir, OVL_XATTR_OPAQUE, "0", 1); > if (err) { > - pr_warn("failed to set xattr on upper\n"); > + warn_plog(log, "failed to set xattr on upper"); > ofs->noxattr = true; > if (ovl_redirect_follow(ofs)) { > ofs->config.redirect_mode = OVL_REDIRECT_NOFOLLOW; > - pr_warn("...falling back to redirect_dir=nofollow.\n"); > + warn_plog(log, "...falling back to redirect_dir=nofollow"); > } > if (ofs->config.metacopy) { > ofs->config.metacopy = false; > - pr_warn("...falling back to metacopy=off.\n"); > + warn_plog(log, "...falling back to metacopy=off"); > } > if (ofs->config.index) { > ofs->config.index = false; > - pr_warn("...falling back to index=off.\n"); > + warn_plog(log, "...falling back to index=off"); > } > if (ovl_has_fsid(ofs)) { > ofs->config.uuid = OVL_UUID_NULL; > - pr_warn("...falling back to uuid=null.\n"); > + warn_plog(log, "...falling back to uuid=null"); > } > /* > * xattr support is required for persistent st_ino. > @@ -719,10 +722,10 @@ static int ovl_make_workdir(struct super_block *sb, struct ovl_fs *ofs, > */ > if (ofs->config.xino == OVL_XINO_AUTO) { > ofs->config.xino = OVL_XINO_OFF; > - pr_warn("...falling back to xino=off.\n"); > + warn_plog(log, "...falling back to xino=off"); > } > if (err == -EPERM && !ofs->config.userxattr) > - pr_info("try mounting with 'userxattr' option\n"); > + info_plog(log, "try mounting with 'userxattr' option"); > err = 0; > } else { > ovl_removexattr(ofs, ofs->workdir, OVL_XATTR_OPAQUE); > @@ -735,7 +738,7 @@ static int ovl_make_workdir(struct super_block *sb, struct ovl_fs *ofs, > */ > if (ovl_dentry_remote(ofs->workdir) && > (!d_type || !rename_whiteout || ofs->noxattr)) { > - pr_err("upper fs missing required features.\n"); > + error_plog(log, "upper fs missing required features"); > err = -EINVAL; > goto out; > } > @@ -747,7 +750,7 @@ static int ovl_make_workdir(struct super_block *sb, struct ovl_fs *ofs, > if (ofs->config.ovl_volatile) { > err = ovl_create_volatile_dirty(ofs); > if (err < 0) { > - pr_err("Failed to create volatile/dirty file.\n"); > + error_plog(log, "failed to create volatile/dirty file"); > goto out; > } > } > @@ -756,7 +759,7 @@ static int ovl_make_workdir(struct super_block *sb, struct ovl_fs *ofs, > fh_type = ovl_can_decode_fh(ofs->workdir->d_sb); > if (ofs->config.index && !fh_type) { > ofs->config.index = false; > - pr_warn("upper fs does not support file handles, falling back to index=off.\n"); > + warn_plog(log, "upper fs does not support file handles, falling back to index=off"); > } > ofs->nofh |= !fh_type; > > @@ -766,7 +769,7 @@ static int ovl_make_workdir(struct super_block *sb, struct ovl_fs *ofs, > > /* NFS export of r/w mount depends on index */ > if (ofs->config.nfs_export && !ofs->config.index) { > - pr_warn("NFS export requires \"index=on\", falling back to nfs_export=off.\n"); > + warn_plog(log, "NFS export requires \"index=on\", falling back to nfs_export=off."); > ofs->config.nfs_export = false; > } > out: > @@ -774,42 +777,38 @@ static int ovl_make_workdir(struct super_block *sb, struct ovl_fs *ofs, > return err; > } > > -static int ovl_get_workdir(struct super_block *sb, struct ovl_fs *ofs, > - const struct path *upperpath, > +static int ovl_get_workdir(struct p_log *log, struct super_block *sb, > + struct ovl_fs *ofs, const struct path *upperpath, > const struct path *workpath) > { > int err; > > - err = -EINVAL; > - if (upperpath->mnt != workpath->mnt) { > - pr_err("workdir and upperdir must reside under the same mount\n"); > - return err; > - } > - if (!ovl_workdir_ok(workpath->dentry, upperpath->dentry)) { > - pr_err("workdir and upperdir must be separate subtrees\n"); > - return err; > - } > + if (upperpath->mnt != workpath->mnt) > + return inval_plog(log, "workdir and upperdir must reside under the same mount"); > + if (!ovl_workdir_ok(workpath->dentry, upperpath->dentry)) > + return inval_plog(log, "workdir and upperdir must be separate subtrees"); > > ofs->workbasedir = dget(workpath->dentry); > > if (ovl_inuse_trylock(ofs->workbasedir)) { > ofs->workdir_locked = true; > } else { > - err = ovl_report_in_use(ofs, "workdir"); > + err = ovl_report_in_use(log, ofs, "workdir"); > if (err) > return err; > } > > - err = ovl_setup_trap(sb, ofs->workbasedir, &ofs->workbasedir_trap, > + err = ovl_setup_trap(log, sb, ofs->workbasedir, &ofs->workbasedir_trap, > "workdir"); > if (err) > return err; > > - return ovl_make_workdir(sb, ofs, workpath); > + return ovl_make_workdir(log, sb, ofs, workpath); > } > > -static int ovl_get_indexdir(struct super_block *sb, struct ovl_fs *ofs, > - struct ovl_entry *oe, const struct path *upperpath) > +static int ovl_get_indexdir(struct p_log *log, struct super_block *sb, > + struct ovl_fs *ofs, struct ovl_entry *oe, > + const struct path *upperpath) > { > struct vfsmount *mnt = ovl_upper_mnt(ofs); > struct dentry *indexdir; > @@ -828,7 +827,7 @@ static int ovl_get_indexdir(struct super_block *sb, struct ovl_fs *ofs, > /* Verify lower root is upper root origin */ > err = ovl_verify_origin_fh(ofs, upperpath->dentry, fh, true); > if (err) { > - pr_err("failed to verify upper root origin\n"); > + error_plog(log, "failed to verify upper root origin"); > goto out; > } > > @@ -837,12 +836,12 @@ static int ovl_get_indexdir(struct super_block *sb, struct ovl_fs *ofs, > ofs->workdir_trap = NULL; > dput(ofs->workdir); > ofs->workdir = NULL; > - indexdir = ovl_workdir_create(ofs, OVL_INDEXDIR_NAME, true); > + indexdir = ovl_workdir_create(log, ofs, OVL_INDEXDIR_NAME, true); > if (IS_ERR(indexdir)) { > err = PTR_ERR(indexdir); > } else if (indexdir) { > ofs->workdir = indexdir; > - err = ovl_setup_trap(sb, indexdir, &ofs->workdir_trap, > + err = ovl_setup_trap(log, sb, indexdir, &ofs->workdir_trap, > "indexdir"); > if (err) > goto out; > @@ -861,18 +860,18 @@ static int ovl_get_indexdir(struct super_block *sb, struct ovl_fs *ofs, > upperpath->dentry, true, > false); > if (err) > - pr_err("failed to verify index dir 'origin' xattr\n"); > + error_plog(log, "failed to verify index dir 'origin' xattr"); > } > err = ovl_verify_upper(ofs, indexdir, upperpath->dentry, true); > if (err) > - pr_err("failed to verify index dir 'upper' xattr\n"); > + error_plog(log, "failed to verify index dir 'upper' xattr"); > > /* Cleanup bad/stale/orphan index entries */ > if (!err) > err = ovl_indexdir_cleanup(ofs); > } > if (err || !indexdir) > - pr_warn("try deleting index dir or mounting with '-o index=off' to disable inodes index.\n"); > + error_plog(log, "try deleting index dir or mounting with '-o index=off' to disable inodes index"); > > out: > mnt_drop_write(mnt); > @@ -917,7 +916,8 @@ static bool ovl_lower_uuid_ok(struct ovl_fs *ofs, const uuid_t *uuid) > } > > /* Get a unique fsid for the layer */ > -static int ovl_get_fsid(struct ovl_fs *ofs, const struct path *path) > +static int ovl_get_fsid(struct p_log *log, struct ovl_fs *ofs, > + const struct path *path) > { > struct super_block *sb = path->mnt->mnt_sb; > unsigned int i; > @@ -943,16 +943,17 @@ static int ovl_get_fsid(struct ovl_fs *ofs, const struct path *path) > warn = true; > } > if (warn) { > - pr_warn("%s uuid detected in lower fs '%pd2', falling back to xino=%s,index=off,nfs_export=off.\n", > - uuid_is_null(&sb->s_uuid) ? "null" : > - "conflicting", > - path->dentry, ovl_xino_mode(&ofs->config)); > + warn_plog(log, > + "%s uuid detected in lower fs '%pd2', falling back to xino=%s,index=off,nfs_export=off", > + uuid_is_null(&sb->s_uuid) ? "null" : > + "conflicting", > + path->dentry, ovl_xino_mode(&ofs->config)); > } > } > > err = get_anon_bdev(&dev); > if (err) { > - pr_err("failed to get anonymous bdev for lowerpath\n"); > + error_plog(log, "failed to get anonymous bdev for lowerpath"); > return err; > } > > @@ -974,11 +975,12 @@ static int ovl_get_data_fsid(struct ovl_fs *ofs) > > > static int ovl_get_layers(struct super_block *sb, struct ovl_fs *ofs, > - struct ovl_fs_context *ctx, struct ovl_layer *layers) > + struct fs_context *fc, struct ovl_layer *layers) > { > int err; > unsigned int i; > size_t nr_merged_lower; > + struct ovl_fs_context *ctx = fc->fs_private; > > ofs->fs = kcalloc(ctx->nr + 2, sizeof(struct ovl_sb), GFP_KERNEL); > if (ofs->fs == NULL) > @@ -998,7 +1000,7 @@ static int ovl_get_layers(struct super_block *sb, struct ovl_fs *ofs, > */ > err = get_anon_bdev(&ofs->fs[0].pseudo_dev); > if (err) { > - pr_err("failed to get anonymous bdev for upper fs\n"); > + errorfc(fc, "failed to get anonymous bdev for upper fs"); > return err; > } > > @@ -1015,7 +1017,7 @@ static int ovl_get_layers(struct super_block *sb, struct ovl_fs *ofs, > int fsid; > > if (i < nr_merged_lower) > - fsid = ovl_get_fsid(ofs, &l->path); > + fsid = ovl_get_fsid(&fc->log, ofs, &l->path); > else > fsid = ovl_get_data_fsid(ofs); > if (fsid < 0) > @@ -1028,12 +1030,13 @@ static int ovl_get_layers(struct super_block *sb, struct ovl_fs *ofs, > * the upperdir/workdir is in fact in-use by our > * upperdir/workdir. > */ > - err = ovl_setup_trap(sb, l->path.dentry, &trap, "lowerdir"); > + err = ovl_setup_trap(&fc->log, sb, l->path.dentry, &trap, > + "lowerdir"); > if (err) > return err; > > if (ovl_is_inuse(l->path.dentry)) { > - err = ovl_report_in_use(ofs, "lowerdir"); > + err = ovl_report_in_use(&fc->log, ofs, "lowerdir"); > if (err) { > iput(trap); > return err; > @@ -1043,7 +1046,7 @@ static int ovl_get_layers(struct super_block *sb, struct ovl_fs *ofs, > mnt = clone_private_mount(&l->path); > err = PTR_ERR(mnt); > if (IS_ERR(mnt)) { > - pr_err("failed to clone lowerpath\n"); > + errorfc(fc, "failed to clone lowerpath"); > iput(trap); > return err; > } > @@ -1077,7 +1080,7 @@ static int ovl_get_layers(struct super_block *sb, struct ovl_fs *ofs, > */ > if (ofs->numfs - !ovl_upper_mnt(ofs) == 1) { > if (ofs->config.xino == OVL_XINO_ON) > - pr_info("\"xino=on\" is useless with all layers on same fs, ignore.\n"); > + infofc(fc, "\"xino=on\" is useless with all layers on same fs, ignore"); > ofs->xino_mode = 0; > } else if (ofs->config.xino == OVL_XINO_OFF) { > ofs->xino_mode = -1; > @@ -1094,15 +1097,15 @@ static int ovl_get_layers(struct super_block *sb, struct ovl_fs *ofs, > } > > if (ofs->xino_mode > 0) { > - pr_info("\"xino\" feature enabled using %d upper inode bits.\n", > - ofs->xino_mode); > + infofc(fc, "\"xino\" feature enabled using %d upper inode bits", > + ofs->xino_mode); > } > > return 0; > } > > static struct ovl_entry *ovl_get_lowerstack(struct super_block *sb, > - struct ovl_fs_context *ctx, > + struct fs_context *fc, > struct ovl_fs *ofs, > struct ovl_layer *layers) > { > @@ -1111,19 +1114,19 @@ static struct ovl_entry *ovl_get_lowerstack(struct super_block *sb, > size_t nr_merged_lower; > struct ovl_entry *oe; > struct ovl_path *lowerstack; > + struct ovl_fs_context *ctx = fc->fs_private; > > struct ovl_fs_context_layer *l; > > - if (!ofs->config.upperdir && ctx->nr == 1) { > - pr_err("at least 2 lowerdir are needed while upperdir nonexistent\n"); > - return ERR_PTR(-EINVAL); > - } > + if (!ofs->config.upperdir && ctx->nr == 1) > + return ERR_PTR(invalfc(fc, "at least 2 lowerdir are needed while upperdir nonexistent")); > > err = -EINVAL; > for (i = 0; i < ctx->nr; i++) { > l = &ctx->lower[i]; > > - err = ovl_lower_dir(l->name, &l->path, ofs, &sb->s_stack_depth); > + err = ovl_lower_dir(&fc->log, l->name, &l->path, ofs, > + &sb->s_stack_depth); > if (err) > return ERR_PTR(err); > } > @@ -1131,11 +1134,11 @@ static struct ovl_entry *ovl_get_lowerstack(struct super_block *sb, > err = -EINVAL; > sb->s_stack_depth++; > if (sb->s_stack_depth > FILESYSTEM_MAX_STACK_DEPTH) { > - pr_err("maximum fs stacking depth exceeded\n"); > + errorfc(fc, "maximum fs stacking depth exceeded"); > return ERR_PTR(err); > } > > - err = ovl_get_layers(sb, ofs, ctx, layers); > + err = ovl_get_layers(sb, ofs, fc, layers); > if (err) > return ERR_PTR(err); > > @@ -1162,9 +1165,9 @@ static struct ovl_entry *ovl_get_lowerstack(struct super_block *sb, > * - another layer of this overlayfs instance > * - upper/work dir of any overlayfs instance > */ > -static int ovl_check_layer(struct super_block *sb, struct ovl_fs *ofs, > - struct dentry *dentry, const char *name, > - bool is_lower) > +static int ovl_check_layer(struct p_log *log, struct super_block *sb, > + struct ovl_fs *ofs, struct dentry *dentry, > + const char *name, bool is_lower) > { > struct dentry *next = dentry, *parent; > int err = 0; > @@ -1178,9 +1181,9 @@ static int ovl_check_layer(struct super_block *sb, struct ovl_fs *ofs, > while (!err && parent != next) { > if (is_lower && ovl_lookup_trap_inode(sb, parent)) { > err = -ELOOP; > - pr_err("overlapping %s path\n", name); > + error_plog(log, "overlapping %s path", name); > } else if (ovl_is_inuse(parent)) { > - err = ovl_report_in_use(ofs, name); > + err = ovl_report_in_use(log, ofs, name); > } > next = parent; > parent = dget_parent(next); > @@ -1195,13 +1198,15 @@ static int ovl_check_layer(struct super_block *sb, struct ovl_fs *ofs, > /* > * Check if any of the layers or work dirs overlap. > */ > -static int ovl_check_overlapping_layers(struct super_block *sb, > +static int ovl_check_overlapping_layers(struct p_log *log, > + struct super_block *sb, > struct ovl_fs *ofs) > { > int i, err; > > if (ovl_upper_mnt(ofs)) { > - err = ovl_check_layer(sb, ofs, ovl_upper_mnt(ofs)->mnt_root, > + err = ovl_check_layer(log, sb, ofs, > + ovl_upper_mnt(ofs)->mnt_root, > "upperdir", false); > if (err) > return err; > @@ -1213,14 +1218,14 @@ static int ovl_check_overlapping_layers(struct super_block *sb, > * workbasedir. In that case, we already have their traps in > * inode cache and we will catch that case on lookup. > */ > - err = ovl_check_layer(sb, ofs, ofs->workbasedir, "workdir", > - false); > + err = ovl_check_layer(log, sb, ofs, ofs->workbasedir, > + "workdir", false); > if (err) > return err; > } > > for (i = 1; i < ofs->numlayer; i++) { > - err = ovl_check_layer(sb, ofs, > + err = ovl_check_layer(log, sb, ofs, > ofs->layers[i].mnt->mnt_root, > "lowerdir", true); > if (err) > @@ -1304,14 +1309,14 @@ int ovl_fill_super(struct super_block *sb, struct fs_context *fc) > if (!cred) > goto out_err; > > - err = ovl_fs_params_verify(ctx, &ofs->config); > + err = ovl_fs_params_verify(fc, &ofs->config); > if (err) > goto out_err; > > err = -EINVAL; > if (ctx->nr == 0) { > if (!(fc->sb_flags & SB_SILENT)) > - pr_err("missing 'lowerdir'\n"); > + errorfc(fc, "missing 'lowerdir'"); > goto out_err; > } > > @@ -1342,7 +1347,7 @@ int ovl_fill_super(struct super_block *sb, struct fs_context *fc) > if (ofs->config.xino != OVL_XINO_OFF) { > ofs->xino_mode = BITS_PER_LONG - 32; > if (!ofs->xino_mode) { > - pr_warn("xino not supported on 32bit kernel, falling back to xino=off.\n"); > + warnfc(fc, "xino not supported on 32bit kernel, falling back to xino=off"); > ofs->config.xino = OVL_XINO_OFF; > } > } > @@ -1355,11 +1360,11 @@ int ovl_fill_super(struct super_block *sb, struct fs_context *fc) > > err = -EINVAL; > if (!ofs->config.workdir) { > - pr_err("missing 'workdir'\n"); > + errorfc(fc, "missing 'workdir'"); > goto out_err; > } > > - err = ovl_get_upper(sb, ofs, &layers[0], &ctx->upper); > + err = ovl_get_upper(&fc->log, sb, ofs, &layers[0], &ctx->upper); > if (err) > goto out_err; > > @@ -1368,12 +1373,13 @@ int ovl_fill_super(struct super_block *sb, struct fs_context *fc) > ofs->errseq = errseq_sample(&upper_sb->s_wb_err); > if (errseq_check(&upper_sb->s_wb_err, ofs->errseq)) { > err = -EIO; > - pr_err("Cannot mount volatile when upperdir has an unseen error. Sync upperdir fs to clear state.\n"); > + errorfc(fc, "Cannot mount volatile when upperdir has an unseen error. Sync upperdir fs to clear state."); > goto out_err; > } > } > > - err = ovl_get_workdir(sb, ofs, &ctx->upper, &ctx->work); > + err = ovl_get_workdir(&fc->log, sb, ofs, > + &ctx->upper, &ctx->work); > if (err) > goto out_err; > > @@ -1383,7 +1389,7 @@ int ovl_fill_super(struct super_block *sb, struct fs_context *fc) > sb->s_stack_depth = upper_sb->s_stack_depth; > sb->s_time_gran = upper_sb->s_time_gran; > } > - oe = ovl_get_lowerstack(sb, ctx, ofs, layers); > + oe = ovl_get_lowerstack(sb, fc, ofs, layers); > err = PTR_ERR(oe); > if (IS_ERR(oe)) > goto out_err; > @@ -1393,7 +1399,7 @@ int ovl_fill_super(struct super_block *sb, struct fs_context *fc) > sb->s_flags |= SB_RDONLY; > > if (!ovl_origin_uuid(ofs) && ofs->numfs > 1) { > - pr_warn("The uuid=off requires a single fs for lower and upper, falling back to uuid=null.\n"); > + warnfc(fc, "The uuid=off requires a single fs for lower and upper, falling back to uuid=null."); > ofs->config.uuid = OVL_UUID_NULL; > } else if (ovl_has_fsid(ofs) && ovl_upper_mnt(ofs)) { > /* Use per instance persistent uuid/fsid */ > @@ -1401,7 +1407,7 @@ int ovl_fill_super(struct super_block *sb, struct fs_context *fc) > } > > if (!ovl_force_readonly(ofs) && ofs->config.index) { > - err = ovl_get_indexdir(sb, ofs, oe, &ctx->upper); > + err = ovl_get_indexdir(&fc->log, sb, ofs, oe, &ctx->upper); > if (err) > goto out_free_oe; > > @@ -1410,7 +1416,7 @@ int ovl_fill_super(struct super_block *sb, struct fs_context *fc) > sb->s_flags |= SB_RDONLY; > } > > - err = ovl_check_overlapping_layers(sb, ofs); > + err = ovl_check_overlapping_layers(&fc->log, sb, ofs); > if (err) > goto out_free_oe; > > @@ -1418,13 +1424,13 @@ int ovl_fill_super(struct super_block *sb, struct fs_context *fc) > if (!ofs->workdir) { > ofs->config.index = false; > if (ovl_upper_mnt(ofs) && ofs->config.nfs_export) { > - pr_warn("NFS export requires an index dir, falling back to nfs_export=off.\n"); > + warnfc(fc, "NFS export requires an index dir, falling back to nfs_export=off."); > ofs->config.nfs_export = false; > } > } > > if (ofs->config.metacopy && ofs->config.nfs_export) { > - pr_warn("NFS export is not supported with metadata only copy up, falling back to nfs_export=off.\n"); > + warnfc(fc, "NFS export is not supported with metadata only copy up, falling back to nfs_export=off."); > ofs->config.nfs_export = false; > } > > > --- > base-commit: 59b723cd2adbac2a34fc8e12c74ae26ae45bf230 > change-id: 20241106-overlayfs-fsopen-log-e64f175203ba > > Best regards, > -- > Aleksa Sarai <cyphar@xxxxxxxxxx> >