Skip to content

Commit dc39778

Browse files
committed
Merge patch series "ovl: narrow regions protected by i_rw_sem"
NeilBrown <[email protected]> says: This series of patches for overlayfs is primarily focussed on preparing for some proposed changes to directory locking. In the new scheme we will lock individual dentries in a directory rather than the whole directory. ovl currently will sometimes lock a directory on the upper filesystem and do a few different things while holding the lock. This is incompatible with the new scheme. This series narrows the region of code protected by the directory lock, taking it multiple times when necessary. This theoretically open up the possibilty of other changes happening on the upper filesytem between the unlock and the lock. To some extent the patches guard against that by checking the dentries still have the expect parent after retaking the lock. In general, I think ovl would have trouble if upperfs were being changed independantly, and I don't think the changes here increase the problem in any important way. After this series (with any needed changes) lands I will resubmit my change to vfs_rmdir() behaviour to have it drop the lock on error. ovl will be much better positioned to handle that change. It will come with the new "lookup_and_lock" API that I am proposing. * patches from https://lore.kernel.org/[email protected]: (21 commits) ovl: rename ovl_cleanup_unlocked() to ovl_cleanup() ovl: change ovl_create_real() to receive dentry parent ovl: narrow locking in ovl_check_rename_whiteout() ovl: narrow locking in ovl_whiteout() ovl: change ovl_cleanup_and_whiteout() to take rename lock as needed ovl: narrow locking on ovl_remove_and_whiteout() ovl: change ovl_workdir_cleanup() to take dir lock as needed. ovl: narrow locking in ovl_workdir_cleanup_recurse() ovl: narrow locking in ovl_indexdir_cleanup() ovl: narrow locking in ovl_workdir_create() ovl: narrow locking in ovl_cleanup_index() ovl: narrow locking in ovl_cleanup_whiteouts() ovl: narrow locking in ovl_rename() ovl: simplify gotos in ovl_rename() ovl: narrow locking in ovl_create_over_whiteout() ovl: narrow locking in ovl_clear_empty() ovl: narrow locking in ovl_create_upper() ovl: narrow the locked region in ovl_copy_up_workdir() ovl: Call ovl_create_temp() without lock held. ovl: change ovl_create_index() to take dir locks ... Link: https://lore.kernel.org/[email protected] Signed-off-by: Christian Brauner <[email protected]>
2 parents 083957f + fe4d336 commit dc39778

File tree

8 files changed

+235
-199
lines changed

8 files changed

+235
-199
lines changed

fs/overlayfs/copy_up.c

Lines changed: 24 additions & 24 deletions
Original file line numberDiff line numberDiff line change
@@ -517,15 +517,12 @@ static int ovl_set_upper_fh(struct ovl_fs *ofs, struct dentry *upper,
517517

518518
/*
519519
* Create and install index entry.
520-
*
521-
* Caller must hold i_mutex on indexdir.
522520
*/
523521
static int ovl_create_index(struct dentry *dentry, const struct ovl_fh *fh,
524522
struct dentry *upper)
525523
{
526524
struct ovl_fs *ofs = OVL_FS(dentry->d_sb);
527525
struct dentry *indexdir = ovl_indexdir(dentry->d_sb);
528-
struct inode *dir = d_inode(indexdir);
529526
struct dentry *index = NULL;
530527
struct dentry *temp = NULL;
531528
struct qstr name = { };
@@ -559,16 +556,20 @@ static int ovl_create_index(struct dentry *dentry, const struct ovl_fh *fh,
559556
if (err)
560557
goto out;
561558

559+
err = ovl_parent_lock(indexdir, temp);
560+
if (err)
561+
goto out;
562562
index = ovl_lookup_upper(ofs, name.name, indexdir, name.len);
563563
if (IS_ERR(index)) {
564564
err = PTR_ERR(index);
565565
} else {
566566
err = ovl_do_rename(ofs, indexdir, temp, indexdir, index, 0);
567567
dput(index);
568568
}
569+
ovl_parent_unlock(indexdir);
569570
out:
570571
if (err)
571-
ovl_cleanup(ofs, dir, temp);
572+
ovl_cleanup(ofs, indexdir, temp);
572573
dput(temp);
573574
free_name:
574575
kfree(name.name);
@@ -762,7 +763,6 @@ static int ovl_copy_up_workdir(struct ovl_copy_up_ctx *c)
762763
{
763764
struct ovl_fs *ofs = OVL_FS(c->dentry->d_sb);
764765
struct inode *inode;
765-
struct inode *wdir = d_inode(c->workdir);
766766
struct path path = { .mnt = ovl_upper_mnt(ofs) };
767767
struct dentry *temp, *upper, *trap;
768768
struct ovl_cu_creds cc;
@@ -779,9 +779,7 @@ static int ovl_copy_up_workdir(struct ovl_copy_up_ctx *c)
779779
return err;
780780

781781
ovl_start_write(c->dentry);
782-
inode_lock(wdir);
783782
temp = ovl_create_temp(ofs, c->workdir, &cattr);
784-
inode_unlock(wdir);
785783
ovl_end_write(c->dentry);
786784
ovl_revert_cu_creds(&cc);
787785

@@ -794,45 +792,47 @@ static int ovl_copy_up_workdir(struct ovl_copy_up_ctx *c)
794792
*/
795793
path.dentry = temp;
796794
err = ovl_copy_up_data(c, &path);
795+
ovl_start_write(c->dentry);
796+
if (err)
797+
goto cleanup_unlocked;
798+
799+
if (S_ISDIR(c->stat.mode) && c->indexed) {
800+
err = ovl_create_index(c->dentry, c->origin_fh, temp);
801+
if (err)
802+
goto cleanup_unlocked;
803+
}
804+
797805
/*
798806
* We cannot hold lock_rename() throughout this helper, because of
799807
* lock ordering with sb_writers, which shouldn't be held when calling
800808
* ovl_copy_up_data(), so lock workdir and destdir and make sure that
801809
* temp wasn't moved before copy up completion or cleanup.
802810
*/
803-
ovl_start_write(c->dentry);
804811
trap = lock_rename(c->workdir, c->destdir);
805812
if (trap || temp->d_parent != c->workdir) {
806813
/* temp or workdir moved underneath us? abort without cleanup */
807814
dput(temp);
808815
err = -EIO;
809-
if (IS_ERR(trap))
810-
goto out;
811-
goto unlock;
812-
} else if (err) {
813-
goto cleanup;
816+
if (!IS_ERR(trap))
817+
unlock_rename(c->workdir, c->destdir);
818+
goto out;
814819
}
815820

816821
err = ovl_copy_up_metadata(c, temp);
817822
if (err)
818823
goto cleanup;
819824

820-
if (S_ISDIR(c->stat.mode) && c->indexed) {
821-
err = ovl_create_index(c->dentry, c->origin_fh, temp);
822-
if (err)
823-
goto cleanup;
824-
}
825-
826825
upper = ovl_lookup_upper(ofs, c->destname.name, c->destdir,
827826
c->destname.len);
828827
err = PTR_ERR(upper);
829828
if (IS_ERR(upper))
830829
goto cleanup;
831830

832831
err = ovl_do_rename(ofs, c->workdir, temp, c->destdir, upper, 0);
832+
unlock_rename(c->workdir, c->destdir);
833833
dput(upper);
834834
if (err)
835-
goto cleanup;
835+
goto cleanup_unlocked;
836836

837837
inode = d_inode(c->dentry);
838838
if (c->metacopy_digest)
@@ -846,17 +846,17 @@ static int ovl_copy_up_workdir(struct ovl_copy_up_ctx *c)
846846
ovl_inode_update(inode, temp);
847847
if (S_ISDIR(inode->i_mode))
848848
ovl_set_flag(OVL_WHITEOUTS, inode);
849-
unlock:
850-
unlock_rename(c->workdir, c->destdir);
851849
out:
852850
ovl_end_write(c->dentry);
853851

854852
return err;
855853

856854
cleanup:
857-
ovl_cleanup(ofs, wdir, temp);
855+
unlock_rename(c->workdir, c->destdir);
856+
cleanup_unlocked:
857+
ovl_cleanup(ofs, c->workdir, temp);
858858
dput(temp);
859-
goto unlock;
859+
goto out;
860860
}
861861

862862
/* Copyup using O_TMPFILE which does not require cross dir locking */

0 commit comments

Comments
 (0)