static int ovl_get_indexdir(struct ovl_fs *ofs, struct ovl_entry *oe, struct path *upperpath) { struct vfsmount *mnt = ofs->upper_mnt; int err; err = mnt_want_write(mnt); if (err) return err; /* Verify lower root is upper root origin */ err = ovl_verify_origin(upperpath->dentry, oe->lowerstack[0].dentry, true); if (err) { pr_err("overlayfs: failed to verify upper root origin\n"); goto out; } ofs->indexdir = ovl_workdir_create(ofs, OVL_INDEXDIR_NAME, true); if (ofs->indexdir) { /* * Verify upper root is exclusively associated with index dir. * Older kernels stored upper fh in "trusted.overlay.origin" * xattr. If that xattr exists, verify that it is a match to * upper dir file handle. In any case, verify or set xattr * "trusted.overlay.upper" to indicate that index may have * directory entries. */ if (ovl_check_origin_xattr(ofs->indexdir)) { err = ovl_verify_set_fh(ofs->indexdir, OVL_XATTR_ORIGIN, upperpath->dentry, true, false); if (err) pr_err("overlayfs: failed to verify index dir 'origin' xattr\n"); } err = ovl_verify_upper(ofs->indexdir, upperpath->dentry, true); if (err) pr_err("overlayfs: failed to verify index dir 'upper' xattr\n"); /* Cleanup bad/stale/orphan index entries */ if (!err) err = ovl_indexdir_cleanup(ofs); } if (err || !ofs->indexdir) pr_warn("overlayfs: try deleting index dir or mounting with '-o index=off' to disable inodes index.\n"); out: mnt_drop_write(mnt); return err; }
static int ovl_fill_super(struct super_block *sb, void *data, int silent) { struct path lowerpath; struct path upperpath; struct path workpath; struct inode *root_inode; struct dentry *root_dentry; struct ovl_entry *oe; struct ovl_fs *ufs; struct kstatfs statfs; int err; err = -ENOMEM; ufs = kmalloc(sizeof(struct ovl_fs), GFP_KERNEL); if (!ufs) goto out; err = ovl_parse_opt((char *) data, &ufs->config); if (err) goto out_free_ufs; /* FIXME: workdir is not needed for a R/O mount */ err = -EINVAL; if (!ufs->config.upperdir || !ufs->config.lowerdir || !ufs->config.workdir) { pr_err("overlayfs: missing upperdir or lowerdir or workdir\n"); goto out_free_config; } oe = ovl_alloc_entry(); if (oe == NULL) goto out_free_config; err = ovl_mount_dir(ufs->config.upperdir, &upperpath); if (err) goto out_free_oe; err = ovl_mount_dir(ufs->config.lowerdir, &lowerpath); if (err) goto out_put_upperpath; err = ovl_mount_dir(ufs->config.workdir, &workpath); if (err) goto out_put_lowerpath; err = -EINVAL; if (!S_ISDIR(upperpath.dentry->d_inode->i_mode) || !S_ISDIR(lowerpath.dentry->d_inode->i_mode) || !S_ISDIR(workpath.dentry->d_inode->i_mode)) { pr_err("overlayfs: upperdir or lowerdir or workdir not a directory\n"); goto out_put_workpath; } if (upperpath.mnt != workpath.mnt) { pr_err("overlayfs: workdir and upperdir must reside under the same mount\n"); goto out_put_workpath; } if (upperpath.dentry == workpath.dentry || d_ancestor(upperpath.dentry, workpath.dentry) || d_ancestor(workpath.dentry, upperpath.dentry)) { pr_err("overlayfs: workdir and upperdir must be separate subtrees\n"); goto out_put_workpath; } err = vfs_statfs(&lowerpath, &statfs); if (err) { pr_err("overlayfs: statfs failed on lowerpath\n"); goto out_put_workpath; } ufs->lower_namelen = statfs.f_namelen; sb->s_stack_depth = max(upperpath.mnt->mnt_sb->s_stack_depth, lowerpath.mnt->mnt_sb->s_stack_depth) + 1; err = -EINVAL; if (sb->s_stack_depth > FILESYSTEM_MAX_STACK_DEPTH) { pr_err("overlayfs: maximum fs stacking depth exceeded\n"); goto out_put_lowerpath; } ufs->upper_mnt = clone_private_mount(&upperpath); err = PTR_ERR(ufs->upper_mnt); if (IS_ERR(ufs->upper_mnt)) { pr_err("overlayfs: failed to clone upperpath\n"); goto out_put_workpath; } ufs->lower_mnt = clone_private_mount(&lowerpath); err = PTR_ERR(ufs->lower_mnt); if (IS_ERR(ufs->lower_mnt)) { pr_err("overlayfs: failed to clone lowerpath\n"); goto out_put_upper_mnt; } ufs->workdir = ovl_workdir_create(ufs->upper_mnt, workpath.dentry); err = PTR_ERR(ufs->workdir); if (IS_ERR(ufs->workdir)) { pr_err("overlayfs: failed to create directory %s/%s\n", ufs->config.workdir, OVL_WORKDIR_NAME); goto out_put_lower_mnt; } /* * Make lower_mnt R/O. That way fchmod/fchown on lower file * will fail instead of modifying lower fs. */ ufs->lower_mnt->mnt_flags |= MNT_READONLY; /* If the upper fs is r/o, we mark overlayfs r/o too */ if (ufs->upper_mnt->mnt_sb->s_flags & MS_RDONLY) sb->s_flags |= MS_RDONLY; err = -ENOMEM; root_inode = ovl_new_inode(sb, S_IFDIR, oe); if (!root_inode) goto out_put_workdir; root_dentry = d_make_root(root_inode); if (!root_dentry) goto out_put_workdir; mntput(upperpath.mnt); mntput(lowerpath.mnt); path_put(&workpath); oe->__upperdentry = dget(upperpath.dentry); oe->lowerdentry = lowerpath.dentry; root_dentry->d_fsdata = oe; root_dentry->d_op = &ovl_dentry_operations; sb->s_magic = OVERLAYFS_SUPER_MAGIC; sb->s_op = &ovl_super_operations; sb->s_root = root_dentry; sb->s_fs_info = ufs; return 0; out_put_workdir: dput(ufs->workdir); out_put_lower_mnt: mntput(ufs->lower_mnt); out_put_upper_mnt: mntput(ufs->upper_mnt); out_put_workpath: path_put(&workpath); out_put_lowerpath: path_put(&lowerpath); out_put_upperpath: path_put(&upperpath); out_free_oe: kfree(oe); out_free_config: kfree(ufs->config.lowerdir); kfree(ufs->config.upperdir); kfree(ufs->config.workdir); out_free_ufs: kfree(ufs); out: return err; }
static int ovl_make_workdir(struct ovl_fs *ofs, struct path *workpath) { struct vfsmount *mnt = ofs->upper_mnt; struct dentry *temp; int fh_type; int err; err = mnt_want_write(mnt); if (err) return err; ofs->workdir = ovl_workdir_create(ofs, OVL_WORKDIR_NAME, false); if (!ofs->workdir) goto out; /* * Upper should support d_type, else whiteouts are visible. Given * workdir and upper are on same fs, we can do iterate_dir() on * workdir. This check requires successful creation of workdir in * previous step. */ err = ovl_check_d_type_supported(workpath); if (err < 0) goto out; /* * We allowed this configuration and don't want to break users over * kernel upgrade. So warn instead of erroring out. */ if (!err) pr_warn("overlayfs: upper fs needs to support d_type.\n"); /* Check if upper/work fs supports O_TMPFILE */ temp = ovl_do_tmpfile(ofs->workdir, S_IFREG | 0); ofs->tmpfile = !IS_ERR(temp); if (ofs->tmpfile) dput(temp); else pr_warn("overlayfs: upper fs does not support tmpfile.\n"); /* * Check if upper/work fs supports trusted.overlay.* xattr */ err = ovl_do_setxattr(ofs->workdir, OVL_XATTR_OPAQUE, "0", 1, 0); if (err) { ofs->noxattr = true; ofs->config.index = false; ofs->config.metacopy = false; pr_warn("overlayfs: upper fs does not support xattr, falling back to index=off and metacopy=off.\n"); err = 0; } else { vfs_removexattr(ofs->workdir, OVL_XATTR_OPAQUE); } /* Check if upper/work fs supports file handles */ fh_type = ovl_can_decode_fh(ofs->workdir->d_sb); if (ofs->config.index && !fh_type) { ofs->config.index = false; pr_warn("overlayfs: upper fs does not support file handles, falling back to index=off.\n"); } /* Check if upper fs has 32bit inode numbers */ if (fh_type != FILEID_INO32_GEN) ofs->xino_bits = 0; /* NFS export of r/w mount depends on index */ if (ofs->config.nfs_export && !ofs->config.index) { pr_warn("overlayfs: NFS export requires \"index=on\", falling back to nfs_export=off.\n"); ofs->config.nfs_export = false; } out: mnt_drop_write(mnt); return err; }