case S_IFDIR: /* mkdir is special... */
newdentry = ovl_do_mkdir(ofs, dir, newdentry, attr->mode);
err = PTR_ERR_OR_ZERO(newdentry); break;
case S_IFCHR: case S_IFBLK: case S_IFIFO: case S_IFSOCK:
err = ovl_do_mknod(ofs, dir, newdentry, attr->mode,
attr->rdev); break;
case S_IFLNK:
err = ovl_do_symlink(ofs, dir, newdentry, attr->link); break;
default:
err = -EPERM;
}
} if (err) goto out;
if (WARN_ON(!newdentry->d_inode)) { /* * Not quite sure if non-instantiated dentry is legal or not. * VFS doesn't seem to care so check and warn here.
*/
err = -EIO;
} elseif (d_unhashed(newdentry)) { struct dentry *d; /* * Some filesystems (i.e. casefolded) may return an unhashed * negative dentry from the ovl_lookup_upper() call before * ovl_create_real(). * In that case, lookup again after making the newdentry * positive, so ovl_create_upper() always returns a hashed * positive dentry.
*/
d = ovl_lookup_upper(ofs, newdentry->d_name.name, parent,
newdentry->d_name.len);
dput(newdentry); if (IS_ERR_OR_NULL(d))
err = d ? PTR_ERR(d) : -ENOENT; else return d;
}
out: if (err) { if (!IS_ERR(newdentry))
dput(newdentry); return ERR_PTR(err);
} return newdentry;
}
staticint ovl_set_opaque(struct dentry *dentry, struct dentry *upperdentry)
{ /* * Fail with -EIO when trying to create opaque dir and upper doesn't * support xattrs. ovl_rename() calls ovl_set_opaque_xerr(-EXDEV) to * return a specific error for noxattr case.
*/ return ovl_set_opaque_xerr(dentry, upperdentry, -EIO);
}
/* * Common operations required to be done after creation of file on upper. * If @hardlink is false, then @inode is a pre-allocated inode, we may or * may not use to instantiate the new dentry.
*/ staticint ovl_instantiate(struct dentry *dentry, struct inode *inode, struct dentry *newdentry, bool hardlink, struct file *tmpfile)
{ struct ovl_inode_params oip = {
.upperdentry = newdentry,
.newinode = inode,
};
if (!hardlink) { /* * ovl_obtain_alias() can be called after ovl_create_real() * and before we get here, so we may get an inode from cache * with the same real upperdentry that is not the inode we * pre-allocated. In this case we will use the cached inode * to instantiate the new dentry. * * XXX: if we ever use ovl_obtain_alias() to decode directory * file handles, need to use ovl_get_inode_locked() and * d_instantiate_new() here to prevent from creating two * hashed directory inode aliases. We then need to return * the obtained alias to ovl_mkdir().
*/
inode = ovl_get_inode(dentry->d_sb, &oip); if (IS_ERR(inode)) return PTR_ERR(inode); if (inode == oip.newinode)
ovl_set_flag(OVL_UPPERDATA, inode);
} else {
WARN_ON(ovl_inode_real(inode) != d_inode(newdentry));
dput(newdentry);
inc_nlink(inode);
}
if (tmpfile)
d_mark_tmpfile(tmpfile, inode);
d_instantiate(dentry, inode); if (inode != oip.newinode) {
pr_warn_ratelimited("newly created inode found in cache (%pd2)\n",
dentry);
}
/* Force lookup of new upper hardlink to find its lower */ if (hardlink)
d_drop(dentry);
if (ovl_type_merge(dentry->d_parent) && d_is_dir(newdentry) &&
!ovl_allow_offline_changes(ofs)) { /* Setting opaque here is just an optimization, allow to fail */
ovl_set_opaque(dentry, newdentry);
}
/* * Caller is going to match this with revert_creds() and drop * referenec on the returned creds. * We must be called with creator creds already, otherwise we risk * leaking creds.
*/
old_cred = override_creds(override_cred);
WARN_ON_ONCE(old_cred != ovl_creds(dentry->d_sb));
/* * When linking a file with copy up origin into a new parent, mark the * new parent dir "impure".
*/ if (origin) {
err = ovl_set_impure(parent, ovl_dentry_upper(parent)); if (err) goto out_revert_creds;
}
if (!attr->hardlink) { /* * In the creation cases(create, mkdir, mknod, symlink), * ovl should transfer current's fs{u,g}id to underlying * fs. Because underlying fs want to initialize its new * inode owner using current's fs{u,g}id. And in this * case, the @inode is a new inode that is initialized * in inode_init_owner() to current's fs{u,g}id. So use * the inode's i_{u,g}id to override the cred's fs{u,g}id. * * But in the other hardlink case, ovl_link() does not * create a new inode, so just use the ovl mounter's * fs{u,g}id.
*/
new_cred = ovl_setup_cred_for_create(dentry, inode, attr->mode,
old_cred);
err = PTR_ERR(new_cred); if (IS_ERR(new_cred)) {
new_cred = NULL; goto out_revert_creds;
}
}
/* * Keeping this dentry hashed would mean having to release * upperpath/lowerpath, which could only be done if we are the * sole user of this dentry. Too tricky... Just unhash for * now.
*/ if (!err)
d_drop(dentry);
out_dput_upper:
dput(upper);
out_unlock:
inode_unlock(dir);
dput(opaquedir);
out: return err;
}
/* Try to find another, hashed alias */
spin_lock(&inode->i_lock);
hlist_for_each_entry(alias, &inode->i_dentry, d_u.d_alias) { if (alias != dentry && !d_unhashed(alias)) break;
}
spin_unlock(&inode->i_lock);
/* * Changes to underlying layers may cause i_nlink to lose sync with * reality. In this case prevent the link count from going to zero * prematurely.
*/ if (inode->i_nlink > !!alias)
drop_nlink(inode);
}
/* No need to clean pure upper removed by vfs_rmdir() */ if (is_dir && (lower_positive || !ovl_pure_upper(dentry))) {
err = ovl_check_empty_dir(dentry, &list); if (err) goto out;
}
err = ovl_copy_up(dentry->d_parent); if (err) goto out;
err = ovl_nlink_start(dentry); if (err) goto out;
old_cred = ovl_override_creds(dentry->d_sb); if (!lower_positive)
err = ovl_remove_upper(dentry, is_dir, &list); else
err = ovl_remove_and_whiteout(dentry, &list);
ovl_revert_creds(old_cred); if (!err) { if (is_dir)
clear_nlink(dentry->d_inode); else
ovl_drop_nlink(dentry);
}
ovl_nlink_end(dentry);
/* * Copy ctime * * Note: we fail to update ctime if there was no copy-up, only a * whiteout
*/ if (ovl_dentry_upper(dentry))
ovl_copyattr(d_inode(dentry));
if (!abs_redirect) {
ret = kstrndup(dentry->d_name.name, dentry->d_name.len,
GFP_KERNEL); goto out;
}
buf = ret = kmalloc(buflen, GFP_KERNEL); if (!buf) goto out;
buflen--;
buf[buflen] = '\0'; for (d = dget(dentry); !IS_ROOT(d);) { constchar *name; int thislen;
spin_lock(&d->d_lock);
name = ovl_dentry_get_redirect(d); if (name) {
thislen = strlen(name);
} else {
name = d->d_name.name;
thislen = d->d_name.len;
}
/* If path is too long, fall back to userspace move */ if (thislen + (name[0] != '/') > buflen) {
ret = ERR_PTR(-EXDEV);
spin_unlock(&d->d_lock); goto out_put;
}
/* * For non-dir hardlinked files, we need absolute redirects * in general as two upper hardlinks could be in different * dirs. We could put a relative redirect now and convert * it to absolute redirect later. But when nlink > 1 and * indexing is on, that means relative redirect needs to be * converted to absolute during copy up of another lower * hardllink as well. * * So without optimizing too much, just check if lower is * a hard link or not. If lower is hard link, put absolute * redirect.
*/
lowerdentry = ovl_dentry_lower(dentry); return (d_inode(lowerdentry)->i_nlink > 1);
}
if (!samedir) { /* * When moving a merge dir or non-dir with copy up origin into * a new parent, we are marking the new parent dir "impure". * When ovl_iterate() iterates an "impure" upper dir, it will * lookup the origin inodes of the entries to fill d_ino.
*/ if (ovl_type_origin(old)) {
err = ovl_set_impure(new->d_parent, new_upperdir); if (err) goto out_revert_creds;
} if (!overwrite && ovl_type_origin(new)) {
err = ovl_set_impure(old->d_parent, old_upperdir); if (err) goto out_revert_creds;
}
}
/* * Check if the preallocated inode was actually used. Having something * else assigned to the dentry shouldn't happen as that would indicate * that the backing tmpfile "leaked" out of overlayfs.
*/
err = -EIO; if (WARN_ON(inode != d_inode(dentry))) goto put_realfile;
/* inode reference was transferred to dentry */
inode = NULL;
err = finish_open(file, dentry, ovl_dummy_open);
put_realfile: /* Without FMODE_OPENED ->release() won't be called on @file */ if (!(file->f_mode & FMODE_OPENED))
ovl_file_free(file->private_data);
put_inode:
iput(inode);
drop_write:
ovl_drop_write(dentry); return err;
}
Die Informationen auf dieser Webseite wurden
nach bestem Wissen sorgfältig zusammengestellt. Es wird jedoch weder Vollständigkeit, noch Richtigkeit,
noch Qualität der bereit gestellten Informationen zugesichert.
Bemerkung:
Die farbliche Syntaxdarstellung und die Messung sind noch experimentell.