Donate to e Foundation | Murena handsets with /e/OS | Own a part of Murena! Learn more

Commit b1c839bb authored by Frederic Weisbecker's avatar Frederic Weisbecker
Browse files

kill-the-bkl/reiserfs: don't hold the write recursively in reiserfs_lookup()



The write lock can be acquired recursively in reiserfs_lookup(). But we may
want to *really* release the lock before possible rescheduling from a
reiserfs_lookup() callee.

Hence we want to only acquire the lock once (ie: not recursively).

[ Impact: prevent from possible false unreleased write lock on sleeping ]

Cc: Jeff Mahoney <jeffm@suse.com>
Cc: Chris Mason <chris.mason@oracle.com>
Cc: Ingo Molnar <mingo@elte.hu>
Cc: Alexander Beregalov <a.beregalov@gmail.com>
Signed-off-by: default avatarFrederic Weisbecker <fweisbec@gmail.com>
parent 26931309
Loading
Loading
Loading
Loading
+10 −3
Original line number Original line Diff line number Diff line
@@ -324,6 +324,7 @@ static struct dentry *reiserfs_lookup(struct inode *dir, struct dentry *dentry,
				      struct nameidata *nd)
				      struct nameidata *nd)
{
{
	int retval;
	int retval;
	int lock_depth;
	struct inode *inode = NULL;
	struct inode *inode = NULL;
	struct reiserfs_dir_entry de;
	struct reiserfs_dir_entry de;
	INITIALIZE_PATH(path_to_entry);
	INITIALIZE_PATH(path_to_entry);
@@ -331,7 +332,13 @@ static struct dentry *reiserfs_lookup(struct inode *dir, struct dentry *dentry,
	if (REISERFS_MAX_NAME(dir->i_sb->s_blocksize) < dentry->d_name.len)
	if (REISERFS_MAX_NAME(dir->i_sb->s_blocksize) < dentry->d_name.len)
		return ERR_PTR(-ENAMETOOLONG);
		return ERR_PTR(-ENAMETOOLONG);


	reiserfs_write_lock(dir->i_sb);
	/*
	 * Might be called with or without the write lock, must be careful
	 * to not recursively hold it in case we want to release the lock
	 * before rescheduling.
	 */
	lock_depth = reiserfs_write_lock_once(dir->i_sb);

	de.de_gen_number_bit_string = NULL;
	de.de_gen_number_bit_string = NULL;
	retval =
	retval =
	    reiserfs_find_entry(dir, dentry->d_name.name, dentry->d_name.len,
	    reiserfs_find_entry(dir, dentry->d_name.name, dentry->d_name.len,
@@ -341,7 +348,7 @@ static struct dentry *reiserfs_lookup(struct inode *dir, struct dentry *dentry,
		inode = reiserfs_iget(dir->i_sb,
		inode = reiserfs_iget(dir->i_sb,
				      (struct cpu_key *)&(de.de_dir_id));
				      (struct cpu_key *)&(de.de_dir_id));
		if (!inode || IS_ERR(inode)) {
		if (!inode || IS_ERR(inode)) {
			reiserfs_write_unlock(dir->i_sb);
			reiserfs_write_unlock_once(dir->i_sb, lock_depth);
			return ERR_PTR(-EACCES);
			return ERR_PTR(-EACCES);
		}
		}


@@ -350,7 +357,7 @@ static struct dentry *reiserfs_lookup(struct inode *dir, struct dentry *dentry,
		if (IS_PRIVATE(dir))
		if (IS_PRIVATE(dir))
			inode->i_flags |= S_PRIVATE;
			inode->i_flags |= S_PRIVATE;
	}
	}
	reiserfs_write_unlock(dir->i_sb);
	reiserfs_write_unlock_once(dir->i_sb, lock_depth);
	if (retval == IO_ERROR) {
	if (retval == IO_ERROR) {
		return ERR_PTR(-EIO);
		return ERR_PTR(-EIO);
	}
	}