Skip to content

Commit 9902af7

Browse files
author
Al Viro
committed
parallel lookups: actual switch to rwsem
ta-da! The main issue is the lack of down_write_killable(), so the places like readdir.c switched to plain inode_lock(); once killable variants of rwsem primitives appear, that'll be dealt with. lockdep side also might need more work Signed-off-by: Al Viro <viro@zeniv.linux.org.uk>
1 parent d9171b9 commit 9902af7

File tree

11 files changed

+73
-32
lines changed

11 files changed

+73
-32
lines changed

Documentation/filesystems/porting

Lines changed: 18 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -539,3 +539,21 @@ in your dentry operations instead.
539539
it's a symlink. Checking ->i_mode is really needed now. In-tree we had
540540
to fix shmem_destroy_callback() that used to take that kind of shortcut;
541541
watch out, since that shortcut is no longer valid.
542+
--
543+
[mandatory]
544+
->i_mutex is replaced with ->i_rwsem now. inode_lock() et.al. work as
545+
they used to - they just take it exclusive. However, ->lookup() may be
546+
called with parent locked shared. Its instances must not
547+
* use d_instantiate) and d_rehash() separately - use d_add() or
548+
d_splice_alias() instead.
549+
* use d_rehash() alone - call d_add(new_dentry, NULL) instead.
550+
* in the unlikely case when (read-only) access to filesystem
551+
data structures needs exclusion for some reason, arrange it
552+
yourself. None of the in-tree filesystems needed that.
553+
* rely on ->d_parent and ->d_name not changing after dentry has
554+
been fed to d_add() or d_splice_alias(). Again, none of the
555+
in-tree instances relied upon that.
556+
We are guaranteed that lookups of the same name in the same directory
557+
will not happen in parallel ("same" in the sense of your ->d_compare()).
558+
Lookups on different names in the same directory can and do happen in
559+
parallel now.

fs/btrfs/ioctl.c

Lines changed: 11 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -837,9 +837,11 @@ static noinline int btrfs_mksubvol(struct path *parent,
837837
struct dentry *dentry;
838838
int error;
839839

840-
error = mutex_lock_killable_nested(&dir->i_mutex, I_MUTEX_PARENT);
841-
if (error == -EINTR)
842-
return error;
840+
inode_lock_nested(dir, I_MUTEX_PARENT);
841+
// XXX: should've been
842+
// mutex_lock_killable_nested(&dir->i_mutex, I_MUTEX_PARENT);
843+
// if (error == -EINTR)
844+
// return error;
843845

844846
dentry = lookup_one_len(name, parent->dentry, namelen);
845847
error = PTR_ERR(dentry);
@@ -2366,9 +2368,11 @@ static noinline int btrfs_ioctl_snap_destroy(struct file *file,
23662368
goto out;
23672369

23682370

2369-
err = mutex_lock_killable_nested(&dir->i_mutex, I_MUTEX_PARENT);
2370-
if (err == -EINTR)
2371-
goto out_drop_write;
2371+
inode_lock_nested(dir, I_MUTEX_PARENT);
2372+
// XXX: should've been
2373+
// err = mutex_lock_killable_nested(&dir->i_mutex, I_MUTEX_PARENT);
2374+
// if (err == -EINTR)
2375+
// goto out_drop_write;
23722376
dentry = lookup_one_len(vol_args->name, parent, namelen);
23732377
if (IS_ERR(dentry)) {
23742378
err = PTR_ERR(dentry);
@@ -2558,7 +2562,7 @@ static noinline int btrfs_ioctl_snap_destroy(struct file *file,
25582562
dput(dentry);
25592563
out_unlock_dir:
25602564
inode_unlock(dir);
2561-
out_drop_write:
2565+
//out_drop_write:
25622566
mnt_drop_write_file(file);
25632567
out:
25642568
kfree(vol_args);

fs/configfs/inode.c

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -156,7 +156,7 @@ static void configfs_set_inode_lock_class(struct configfs_dirent *sd,
156156

157157
if (depth > 0) {
158158
if (depth <= ARRAY_SIZE(default_group_class)) {
159-
lockdep_set_class(&inode->i_mutex,
159+
lockdep_set_class(&inode->i_rwsem,
160160
&default_group_class[depth - 1]);
161161
} else {
162162
/*

fs/dcache.c

Lines changed: 5 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -2932,7 +2932,8 @@ struct dentry *d_ancestor(struct dentry *p1, struct dentry *p2)
29322932
static int __d_unalias(struct inode *inode,
29332933
struct dentry *dentry, struct dentry *alias)
29342934
{
2935-
struct mutex *m1 = NULL, *m2 = NULL;
2935+
struct mutex *m1 = NULL;
2936+
struct rw_semaphore *m2 = NULL;
29362937
int ret = -ESTALE;
29372938

29382939
/* If alias and dentry share a parent, then no extra locks required */
@@ -2943,15 +2944,15 @@ static int __d_unalias(struct inode *inode,
29432944
if (!mutex_trylock(&dentry->d_sb->s_vfs_rename_mutex))
29442945
goto out_err;
29452946
m1 = &dentry->d_sb->s_vfs_rename_mutex;
2946-
if (!inode_trylock(alias->d_parent->d_inode))
2947+
if (!inode_trylock_shared(alias->d_parent->d_inode))
29472948
goto out_err;
2948-
m2 = &alias->d_parent->d_inode->i_mutex;
2949+
m2 = &alias->d_parent->d_inode->i_rwsem;
29492950
out_unalias:
29502951
__d_move(alias, dentry, false);
29512952
ret = 0;
29522953
out_err:
29532954
if (m2)
2954-
mutex_unlock(m2);
2955+
up_read(m2);
29552956
if (m1)
29562957
mutex_unlock(m1);
29572958
return ret;

fs/gfs2/ops_fstype.c

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -824,7 +824,7 @@ static int init_inodes(struct gfs2_sbd *sdp, int undo)
824824
* i_mutex on quota files is special. Since this inode is hidden system
825825
* file, we are safe to define locking ourselves.
826826
*/
827-
lockdep_set_class(&sdp->sd_quota_inode->i_mutex,
827+
lockdep_set_class(&sdp->sd_quota_inode->i_rwsem,
828828
&gfs2_quota_imutex_key);
829829

830830
error = gfs2_rindex_update(sdp);

fs/inode.c

Lines changed: 6 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -166,8 +166,8 @@ int inode_init_always(struct super_block *sb, struct inode *inode)
166166
spin_lock_init(&inode->i_lock);
167167
lockdep_set_class(&inode->i_lock, &sb->s_type->i_lock_key);
168168

169-
mutex_init(&inode->i_mutex);
170-
lockdep_set_class(&inode->i_mutex, &sb->s_type->i_mutex_key);
169+
init_rwsem(&inode->i_rwsem);
170+
lockdep_set_class(&inode->i_rwsem, &sb->s_type->i_mutex_key);
171171

172172
atomic_set(&inode->i_dio_count, 0);
173173

@@ -925,13 +925,13 @@ void lockdep_annotate_inode_mutex_key(struct inode *inode)
925925
struct file_system_type *type = inode->i_sb->s_type;
926926

927927
/* Set new key only if filesystem hasn't already changed it */
928-
if (lockdep_match_class(&inode->i_mutex, &type->i_mutex_key)) {
928+
if (lockdep_match_class(&inode->i_rwsem, &type->i_mutex_key)) {
929929
/*
930930
* ensure nobody is actually holding i_mutex
931931
*/
932-
mutex_destroy(&inode->i_mutex);
933-
mutex_init(&inode->i_mutex);
934-
lockdep_set_class(&inode->i_mutex,
932+
// mutex_destroy(&inode->i_mutex);
933+
init_rwsem(&inode->i_rwsem);
934+
lockdep_set_class(&inode->i_rwsem,
935935
&type->i_mutex_dir_key);
936936
}
937937
}

fs/namei.c

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1607,7 +1607,7 @@ static struct dentry *lookup_slow(const struct qstr *name,
16071607
struct inode *inode = dir->d_inode;
16081608
DECLARE_WAIT_QUEUE_HEAD_ONSTACK(wq);
16091609

1610-
inode_lock(inode);
1610+
inode_lock_shared(inode);
16111611
/* Don't go there if it's already dead */
16121612
if (unlikely(IS_DEADDIR(inode)))
16131613
goto out;
@@ -1638,7 +1638,7 @@ static struct dentry *lookup_slow(const struct qstr *name,
16381638
}
16391639
}
16401640
out:
1641-
inode_unlock(inode);
1641+
inode_unlock_shared(inode);
16421642
return dentry;
16431643
}
16441644

fs/ocfs2/inode.c

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -262,7 +262,7 @@ static int ocfs2_init_locked_inode(struct inode *inode, void *opaque)
262262
inode->i_ino = args->fi_ino;
263263
OCFS2_I(inode)->ip_blkno = args->fi_blkno;
264264
if (args->fi_sysfile_type != 0)
265-
lockdep_set_class(&inode->i_mutex,
265+
lockdep_set_class(&inode->i_rwsem,
266266
&ocfs2_sysfile_lock_key[args->fi_sysfile_type]);
267267
if (args->fi_sysfile_type == USER_QUOTA_SYSTEM_INODE ||
268268
args->fi_sysfile_type == GROUP_QUOTA_SYSTEM_INODE ||

fs/overlayfs/readdir.c

Lines changed: 3 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -218,7 +218,9 @@ static int ovl_check_whiteouts(struct dentry *dir, struct ovl_readdir_data *rdd)
218218
cap_raise(override_cred->cap_effective, CAP_DAC_OVERRIDE);
219219
old_cred = override_creds(override_cred);
220220

221-
err = mutex_lock_killable(&dir->d_inode->i_mutex);
221+
inode_lock(dir->d_inode);
222+
err = 0;
223+
// XXX: err = mutex_lock_killable(&dir->d_inode->i_mutex);
222224
if (!err) {
223225
while (rdd->first_maybe_whiteout) {
224226
p = rdd->first_maybe_whiteout;

fs/readdir.c

Lines changed: 4 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -32,9 +32,10 @@ int iterate_dir(struct file *file, struct dir_context *ctx)
3232
if (res)
3333
goto out;
3434

35-
res = mutex_lock_killable(&inode->i_mutex);
36-
if (res)
37-
goto out;
35+
inode_lock(inode);
36+
// res = mutex_lock_killable(&inode->i_mutex);
37+
// if (res)
38+
// goto out;
3839

3940
res = -ENOENT;
4041
if (!IS_DEADDIR(inode)) {

include/linux/fs.h

Lines changed: 21 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -647,7 +647,7 @@ struct inode {
647647

648648
/* Misc */
649649
unsigned long i_state;
650-
struct mutex i_mutex;
650+
struct rw_semaphore i_rwsem;
651651

652652
unsigned long dirtied_when; /* jiffies of first dirtying */
653653
unsigned long dirtied_time_when;
@@ -734,27 +734,42 @@ enum inode_i_mutex_lock_class
734734

735735
static inline void inode_lock(struct inode *inode)
736736
{
737-
mutex_lock(&inode->i_mutex);
737+
down_write(&inode->i_rwsem);
738738
}
739739

740740
static inline void inode_unlock(struct inode *inode)
741741
{
742-
mutex_unlock(&inode->i_mutex);
742+
up_write(&inode->i_rwsem);
743+
}
744+
745+
static inline void inode_lock_shared(struct inode *inode)
746+
{
747+
down_read(&inode->i_rwsem);
748+
}
749+
750+
static inline void inode_unlock_shared(struct inode *inode)
751+
{
752+
up_read(&inode->i_rwsem);
743753
}
744754

745755
static inline int inode_trylock(struct inode *inode)
746756
{
747-
return mutex_trylock(&inode->i_mutex);
757+
return down_write_trylock(&inode->i_rwsem);
758+
}
759+
760+
static inline int inode_trylock_shared(struct inode *inode)
761+
{
762+
return down_read_trylock(&inode->i_rwsem);
748763
}
749764

750765
static inline int inode_is_locked(struct inode *inode)
751766
{
752-
return mutex_is_locked(&inode->i_mutex);
767+
return rwsem_is_locked(&inode->i_rwsem);
753768
}
754769

755770
static inline void inode_lock_nested(struct inode *inode, unsigned subclass)
756771
{
757-
mutex_lock_nested(&inode->i_mutex, subclass);
772+
down_write_nested(&inode->i_rwsem, subclass);
758773
}
759774

760775
void lock_two_nondirectories(struct inode *, struct inode*);

0 commit comments

Comments
 (0)