static int ovl_get_upper(struct ovl_fs *ofs, struct path *upperpath) { struct vfsmount *upper_mnt; int err; err = ovl_mount_dir(ofs->config.upperdir, upperpath); if (err) goto out; /* Upper fs should not be r/o */ if (sb_rdonly(upperpath->mnt->mnt_sb)) { pr_err("overlayfs: upper fs is r/o, try multi-lower layers mount\n"); err = -EINVAL; goto out; } err = ovl_check_namelen(upperpath, ofs, ofs->config.upperdir); if (err) goto out; upper_mnt = clone_private_mount(upperpath); err = PTR_ERR(upper_mnt); if (IS_ERR(upper_mnt)) { pr_err("overlayfs: failed to clone upperpath\n"); goto out; } /* Don't inherit atime flags */ upper_mnt->mnt_flags &= ~(MNT_NOATIME | MNT_NODIRATIME | MNT_RELATIME); ofs->upper_mnt = upper_mnt; err = -EBUSY; if (ovl_inuse_trylock(ofs->upper_mnt->mnt_root)) { ofs->upperdir_locked = true; } else if (ofs->config.index) { pr_err("overlayfs: upperdir is in-use by another mount, mount with '-o index=off' to override exclusive upperdir protection.\n"); goto out; } else { pr_warn("overlayfs: upperdir is in-use by another mount, accessing files from both mounts will result in undefined behavior.\n"); } err = 0; out: return err; }
static int ovl_fill_super(struct super_block *sb, void *data, int silent) { struct path lowerpath; struct path upperpath; 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; err = -EINVAL; if (!ufs->config.upperdir || !ufs->config.lowerdir) { pr_err("overlayfs: missing upperdir or lowerdir\n"); goto out_free_config; } oe = ovl_alloc_entry(); if (oe == NULL) goto out_free_config; err = kern_path(ufs->config.upperdir, LOOKUP_FOLLOW, &upperpath); if (err) goto out_free_oe; err = kern_path(ufs->config.lowerdir, LOOKUP_FOLLOW, &lowerpath); if (err) goto out_put_upperpath; err = -ENOTDIR; if (!S_ISDIR(upperpath.dentry->d_inode->i_mode) || !S_ISDIR(lowerpath.dentry->d_inode->i_mode)) goto out_put_lowerpath; err = vfs_statfs(&lowerpath, &statfs); if (err) { pr_err("overlayfs: statfs failed on lowerpath\n"); goto out_put_lowerpath; } 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_lowerpath; } 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; } /* * 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; if (!(sb->s_flags & MS_RDONLY)) { err = mnt_want_write(ufs->upper_mnt); if (err) goto out_put_lower_mnt; } err = -ENOMEM; root_inode = ovl_new_inode(sb, S_IFDIR, oe); if (!root_inode) goto out_drop_write; root_dentry = d_make_root(root_inode); if (!root_dentry) goto out_drop_write; mntput(upperpath.mnt); mntput(lowerpath.mnt); 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_drop_write: if (!(sb->s_flags & MS_RDONLY)) mnt_drop_write(ufs->upper_mnt); out_put_lower_mnt: mntput(ufs->lower_mnt); out_put_upper_mnt: mntput(ufs->upper_mnt); 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); out_free_ufs: kfree(ufs); out: 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_get_lower_layers(struct ovl_fs *ofs, struct path *stack, unsigned int numlower) { int err; unsigned int i; err = -ENOMEM; ofs->lower_layers = kcalloc(numlower, sizeof(struct ovl_layer), GFP_KERNEL); if (ofs->lower_layers == NULL) goto out; ofs->lower_fs = kcalloc(numlower, sizeof(struct ovl_sb), GFP_KERNEL); if (ofs->lower_fs == NULL) goto out; for (i = 0; i < numlower; i++) { struct vfsmount *mnt; int fsid; err = fsid = ovl_get_fsid(ofs, &stack[i]); if (err < 0) goto out; mnt = clone_private_mount(&stack[i]); err = PTR_ERR(mnt); if (IS_ERR(mnt)) { pr_err("overlayfs: failed to clone lowerpath\n"); goto out; } /* * Make lower layers R/O. That way fchmod/fchown on lower file * will fail instead of modifying lower fs. */ mnt->mnt_flags |= MNT_READONLY | MNT_NOATIME; ofs->lower_layers[ofs->numlower].mnt = mnt; ofs->lower_layers[ofs->numlower].idx = i + 1; ofs->lower_layers[ofs->numlower].fsid = fsid; if (fsid) { ofs->lower_layers[ofs->numlower].fs = &ofs->lower_fs[fsid - 1]; } ofs->numlower++; } /* * When all layers on same fs, overlay can use real inode numbers. * With mount option "xino=on", mounter declares that there are enough * free high bits in underlying fs to hold the unique fsid. * If overlayfs does encounter underlying inodes using the high xino * bits reserved for fsid, it emits a warning and uses the original * inode number. */ if (!ofs->numlowerfs || (ofs->numlowerfs == 1 && !ofs->upper_mnt)) { ofs->xino_bits = 0; ofs->config.xino = OVL_XINO_OFF; } else if (ofs->config.xino == OVL_XINO_ON && !ofs->xino_bits) { /* * This is a roundup of number of bits needed for numlowerfs+1 * (i.e. ilog2(numlowerfs+1 - 1) + 1). fsid 0 is reserved for * upper fs even with non upper overlay. */ BUILD_BUG_ON(ilog2(OVL_MAX_STACK) > 31); ofs->xino_bits = ilog2(ofs->numlowerfs) + 1; } if (ofs->xino_bits) { pr_info("overlayfs: \"xino\" feature enabled using %d upper inode bits.\n", ofs->xino_bits); } err = 0; out: return err; }