The Linux Kernel Mailing List
 help / color / mirror / Atom feed
* Remove BKL from FAT/VFAT/MSDOS (v1) (was Re: Fw: Regression caused by bf726e "semaphore: fix,")
       [not found]                               ` <alpine.LFD.1.10.0805160950180.2941@woody.linux-foundation.org>
@ 2008-05-16 22:36                                 ` Linus Torvalds
  2008-05-16 22:58                                   ` Linus Torvalds
  2008-05-17  0:25                                   ` OGAWA Hirofumi
  0 siblings, 2 replies; 8+ messages in thread
From: Linus Torvalds @ 2008-05-16 22:36 UTC (permalink / raw)
  To: Thomas Gleixner
  Cc: Ingo Molnar, Andrew Morton, OGAWA Hirofumi,
	Linux Kernel Mailing List



On Fri, 16 May 2008, Linus Torvalds wrote:
> 
> In fact, some of the lock_kernel() calls looked like they could even be 
> dropped:
> 
>  - fat_clear_inode already gets the real spinlocks (inode_hash_lock and 
>    cache_lru_lock), and the kernel lock looks pointless.

Ok, this was also the only one that was called under the superblock lock 
(sys_umount->deactivate_super->invalidate_inodes->clear_inode), and 
everything else could be directly converted to use the superblock lock, so 
here's a trial balloon patch that does exactly that: just blindly convert 
all the "lock_kernel()" calls to "lock_super(sb)", except for the one in 
fat_clear_inode(), which is dropped entirely.

NOTE! There's no way in hell I'll actually commit this, but I did test it 
a bit with a vfat filesystem. I did *not* test extensively, but I did 
various "generate a directory tree, read it, write it, an remove it", so 
the basics do work. But I didn't test an old 8+3 plaim MSDOS filesystem, 
nor did I run any real filesystem stress test, but I do think this is at 
least an interesting starting point, and it's at least not "totally 
obviously broken".

Linux-kernel added to Cc list in case some random person is interested in 
looking at FAT/VFAT/MSDOS lock_kernel removal. 

ANOTHER NOTE! I didn't change this to use .unlocked_ioctl(), and I didn't 
even really look at it. It still takes the BKL, but obviously doesn't help 
any. It didn't look like it should really need it, because it seems to do 
the right locking as-is (ie it gets the inode mutex, and it calls 
__fat_readdir() which now does the lock_super()).

So afaik, those things should just be changed to ".unlocked_ioctl" 
instead, but that also drops the inode as an argument, so then you need to 
also add that "struct inode *inode = filp->f_dentry->d_inode" thing. And 
I'm hoping that other people are interested and will look at this more 
anyway!

		Linus

---
 fs/fat/cache.c   |    2 +-
 fs/fat/dir.c     |    4 ++--
 fs/fat/file.c    |   12 +++++++-----
 fs/fat/inode.c   |   26 ++++++++++++++++----------
 fs/msdos/namei.c |   35 +++++++++++++++++++----------------
 fs/vfat/namei.c  |   35 +++++++++++++++++++----------------
 6 files changed, 64 insertions(+), 50 deletions(-)

diff --git a/fs/fat/cache.c b/fs/fat/cache.c
index fda2547..3a9ecac 100644
--- a/fs/fat/cache.c
+++ b/fs/fat/cache.c
@@ -61,7 +61,7 @@ void fat_cache_destroy(void)
 
 static inline struct fat_cache *fat_cache_alloc(struct inode *inode)
 {
-	return kmem_cache_alloc(fat_cache_cachep, GFP_KERNEL);
+	return kmem_cache_alloc(fat_cache_cachep, GFP_NOFS);
 }
 
 static inline void fat_cache_free(struct fat_cache *cache)
diff --git a/fs/fat/dir.c b/fs/fat/dir.c
index 486725e..34541d0 100644
--- a/fs/fat/dir.c
+++ b/fs/fat/dir.c
@@ -472,7 +472,7 @@ static int __fat_readdir(struct inode *inode, struct file *filp, void *dirent,
 	loff_t cpos;
 	int ret = 0;
 
-	lock_kernel();
+	lock_super(sb);
 
 	cpos = filp->f_pos;
 	/* Fake . and .. for the root directory. */
@@ -654,7 +654,7 @@ FillFailed:
 	if (unicode)
 		__putname(unicode);
 out:
-	unlock_kernel();
+	unlock_super(sb);
 	return ret;
 }
 
diff --git a/fs/fat/file.c b/fs/fat/file.c
index 27cc116..7059928 100644
--- a/fs/fat/file.c
+++ b/fs/fat/file.c
@@ -229,7 +229,8 @@ static int fat_free(struct inode *inode, int skip)
 
 void fat_truncate(struct inode *inode)
 {
-	struct msdos_sb_info *sbi = MSDOS_SB(inode->i_sb);
+	struct super_block *sb = inode->i_sb;
+	struct msdos_sb_info *sbi = MSDOS_SB(sb);
 	const unsigned int cluster_size = sbi->cluster_size;
 	int nr_clusters;
 
@@ -242,9 +243,9 @@ void fat_truncate(struct inode *inode)
 
 	nr_clusters = (inode->i_size + (cluster_size - 1)) >> sbi->cluster_bits;
 
-	lock_kernel();
+	lock_super(sb);
 	fat_free(inode, nr_clusters);
-	unlock_kernel();
+	unlock_super(sb);
 	fat_flush_inodes(inode->i_sb, inode, NULL);
 }
 
@@ -297,12 +298,13 @@ static int fat_allow_set_time(struct msdos_sb_info *sbi, struct inode *inode)
 
 int fat_setattr(struct dentry *dentry, struct iattr *attr)
 {
+	struct super_block *sb = dentry->d_sb;
 	struct msdos_sb_info *sbi = MSDOS_SB(dentry->d_sb);
 	struct inode *inode = dentry->d_inode;
 	int mask, error = 0;
 	unsigned int ia_valid;
 
-	lock_kernel();
+	lock_super(sb);
 
 	/*
 	 * Expand the file. Since inode_setattr() updates ->i_size
@@ -356,7 +358,7 @@ int fat_setattr(struct dentry *dentry, struct iattr *attr)
 		mask = sbi->options.fs_fmask;
 	inode->i_mode &= S_IFMT | (S_IRWXUGO & ~mask);
 out:
-	unlock_kernel();
+	unlock_super(sb);
 	return error;
 }
 EXPORT_SYMBOL_GPL(fat_setattr);
diff --git a/fs/fat/inode.c b/fs/fat/inode.c
index 4e0a3dd..46a4508 100644
--- a/fs/fat/inode.c
+++ b/fs/fat/inode.c
@@ -440,14 +440,13 @@ static void fat_delete_inode(struct inode *inode)
 
 static void fat_clear_inode(struct inode *inode)
 {
-	struct msdos_sb_info *sbi = MSDOS_SB(inode->i_sb);
+	struct super_block *sb = inode->i_sb;
+	struct msdos_sb_info *sbi = MSDOS_SB(sb);
 
-	lock_kernel();
 	spin_lock(&sbi->inode_hash_lock);
 	fat_cache_inval_inode(inode);
 	hlist_del_init(&MSDOS_I(inode)->i_fat_hash);
 	spin_unlock(&sbi->inode_hash_lock);
-	unlock_kernel();
 }
 
 static void fat_write_super(struct super_block *sb)
@@ -485,7 +484,7 @@ static struct kmem_cache *fat_inode_cachep;
 static struct inode *fat_alloc_inode(struct super_block *sb)
 {
 	struct msdos_inode_info *ei;
-	ei = kmem_cache_alloc(fat_inode_cachep, GFP_KERNEL);
+	ei = kmem_cache_alloc(fat_inode_cachep, GFP_NOFS);
 	if (!ei)
 		return NULL;
 	return &ei->vfs_inode;
@@ -567,7 +566,7 @@ retry:
 	if (inode->i_ino == MSDOS_ROOT_INO || !i_pos)
 		return 0;
 
-	lock_kernel();
+	lock_super(sb);
 	bh = sb_bread(sb, i_pos >> sbi->dir_per_block_bits);
 	if (!bh) {
 		printk(KERN_ERR "FAT: unable to read inode block "
@@ -579,7 +578,7 @@ retry:
 	if (i_pos != MSDOS_I(inode)->i_pos) {
 		spin_unlock(&sbi->inode_hash_lock);
 		brelse(bh);
-		unlock_kernel();
+		unlock_super(sb);
 		goto retry;
 	}
 
@@ -606,7 +605,7 @@ retry:
 		err = sync_dirty_buffer(bh);
 	brelse(bh);
 out:
-	unlock_kernel();
+	unlock_super(sb);
 	return err;
 }
 
@@ -736,6 +735,7 @@ fat_encode_fh(struct dentry *de, __u32 *fh, int *lenp, int connectable)
 
 static struct dentry *fat_get_parent(struct dentry *child)
 {
+	struct super_block *sb = child->d_sb;
 	struct buffer_head *bh;
 	struct msdos_dir_entry *de;
 	loff_t i_pos;
@@ -743,14 +743,14 @@ static struct dentry *fat_get_parent(struct dentry *child)
 	struct inode *inode;
 	int err;
 
-	lock_kernel();
+	lock_super(sb);
 
 	err = fat_get_dotdot_entry(child->d_inode, &bh, &de, &i_pos);
 	if (err) {
 		parent = ERR_PTR(err);
 		goto out;
 	}
-	inode = fat_build_inode(child->d_sb, de, i_pos);
+	inode = fat_build_inode(sb, de, i_pos);
 	brelse(bh);
 	if (IS_ERR(inode)) {
 		parent = ERR_CAST(inode);
@@ -762,7 +762,7 @@ static struct dentry *fat_get_parent(struct dentry *child)
 		parent = ERR_PTR(-ENOMEM);
 	}
 out:
-	unlock_kernel();
+	unlock_super(sb);
 
 	return parent;
 }
@@ -1172,6 +1172,12 @@ int fat_fill_super(struct super_block *sb, void *data, int silent,
 	long error;
 	char buf[50];
 
+	/*
+	 * GFP_KERNEL is ok here, because while we do hold the
+	 * supeblock lock, memory pressure can't call back into
+	 * the filesystem, since we're only just about to mount
+	 * it and have no inodes etc active!
+	 */
 	sbi = kzalloc(sizeof(struct msdos_sb_info), GFP_KERNEL);
 	if (!sbi)
 		return -ENOMEM;
diff --git a/fs/msdos/namei.c b/fs/msdos/namei.c
index 05ff4f1..1f7f295 100644
--- a/fs/msdos/namei.c
+++ b/fs/msdos/namei.c
@@ -214,7 +214,7 @@ static struct dentry *msdos_lookup(struct inode *dir, struct dentry *dentry,
 
 	dentry->d_op = &msdos_dentry_operations;
 
-	lock_kernel();
+	lock_super(sb);
 	res = msdos_find(dir, dentry->d_name.name, dentry->d_name.len, &sinfo);
 	if (res == -ENOENT)
 		goto add;
@@ -232,7 +232,7 @@ add:
 	if (dentry)
 		dentry->d_op = &msdos_dentry_operations;
 out:
-	unlock_kernel();
+	unlock_super(sb);
 	if (!res)
 		return dentry;
 	return ERR_PTR(res);
@@ -286,7 +286,7 @@ static int msdos_create(struct inode *dir, struct dentry *dentry, int mode,
 	unsigned char msdos_name[MSDOS_NAME];
 	int err, is_hid;
 
-	lock_kernel();
+	lock_super(sb);
 
 	err = msdos_format_name(dentry->d_name.name, dentry->d_name.len,
 				msdos_name, &MSDOS_SB(sb)->options);
@@ -315,7 +315,7 @@ static int msdos_create(struct inode *dir, struct dentry *dentry, int mode,
 
 	d_instantiate(dentry, inode);
 out:
-	unlock_kernel();
+	unlock_super(sb);
 	if (!err)
 		err = fat_flush_inodes(sb, dir, inode);
 	return err;
@@ -324,11 +324,12 @@ out:
 /***** Remove a directory */
 static int msdos_rmdir(struct inode *dir, struct dentry *dentry)
 {
+	struct super_block *sb = dir->i_sb;
 	struct inode *inode = dentry->d_inode;
 	struct fat_slot_info sinfo;
 	int err;
 
-	lock_kernel();
+	lock_super(sb);
 	/*
 	 * Check whether the directory is not in use, then check
 	 * whether it is empty.
@@ -349,9 +350,9 @@ static int msdos_rmdir(struct inode *dir, struct dentry *dentry)
 	inode->i_ctime = CURRENT_TIME_SEC;
 	fat_detach(inode);
 out:
-	unlock_kernel();
+	unlock_super(sb);
 	if (!err)
-		err = fat_flush_inodes(inode->i_sb, dir, inode);
+		err = fat_flush_inodes(sb, dir, inode);
 
 	return err;
 }
@@ -366,7 +367,7 @@ static int msdos_mkdir(struct inode *dir, struct dentry *dentry, int mode)
 	struct timespec ts;
 	int err, is_hid, cluster;
 
-	lock_kernel();
+	lock_super(sb);
 
 	err = msdos_format_name(dentry->d_name.name, dentry->d_name.len,
 				msdos_name, &MSDOS_SB(sb)->options);
@@ -404,14 +405,14 @@ static int msdos_mkdir(struct inode *dir, struct dentry *dentry, int mode)
 
 	d_instantiate(dentry, inode);
 
-	unlock_kernel();
+	unlock_super(sb);
 	fat_flush_inodes(sb, dir, inode);
 	return 0;
 
 out_free:
 	fat_free_clusters(dir, cluster);
 out:
-	unlock_kernel();
+	unlock_super(sb);
 	return err;
 }
 
@@ -419,10 +420,11 @@ out:
 static int msdos_unlink(struct inode *dir, struct dentry *dentry)
 {
 	struct inode *inode = dentry->d_inode;
+	struct super_block *sb= inode->i_sb;
 	struct fat_slot_info sinfo;
 	int err;
 
-	lock_kernel();
+	lock_super(sb);
 	err = msdos_find(dir, dentry->d_name.name, dentry->d_name.len, &sinfo);
 	if (err)
 		goto out;
@@ -434,9 +436,9 @@ static int msdos_unlink(struct inode *dir, struct dentry *dentry)
 	inode->i_ctime = CURRENT_TIME_SEC;
 	fat_detach(inode);
 out:
-	unlock_kernel();
+	unlock_super(sb);
 	if (!err)
-		err = fat_flush_inodes(inode->i_sb, dir, inode);
+		err = fat_flush_inodes(sb, dir, inode);
 
 	return err;
 }
@@ -618,10 +620,11 @@ error_inode:
 static int msdos_rename(struct inode *old_dir, struct dentry *old_dentry,
 			struct inode *new_dir, struct dentry *new_dentry)
 {
+	struct super_block *sb = old_dir->i_sb;
 	unsigned char old_msdos_name[MSDOS_NAME], new_msdos_name[MSDOS_NAME];
 	int err, is_hid;
 
-	lock_kernel();
+	lock_super(sb);
 
 	err = msdos_format_name(old_dentry->d_name.name,
 				old_dentry->d_name.len, old_msdos_name,
@@ -640,9 +643,9 @@ static int msdos_rename(struct inode *old_dir, struct dentry *old_dentry,
 	err = do_msdos_rename(old_dir, old_msdos_name, old_dentry,
 			      new_dir, new_msdos_name, new_dentry, is_hid);
 out:
-	unlock_kernel();
+	unlock_super(sb);
 	if (!err)
-		err = fat_flush_inodes(old_dir->i_sb, old_dir, new_dir);
+		err = fat_flush_inodes(sb, old_dir, new_dir);
 	return err;
 }
 
diff --git a/fs/vfat/namei.c b/fs/vfat/namei.c
index a352272..b546ba6 100644
--- a/fs/vfat/namei.c
+++ b/fs/vfat/namei.c
@@ -645,7 +645,7 @@ static int vfat_add_entry(struct inode *dir, struct qstr *qname, int is_dir,
 	if (len == 0)
 		return -ENOENT;
 
-	slots = kmalloc(sizeof(*slots) * MSDOS_SLOTS, GFP_KERNEL);
+	slots = kmalloc(sizeof(*slots) * MSDOS_SLOTS, GFP_NOFS);
 	if (slots == NULL)
 		return -ENOMEM;
 
@@ -687,7 +687,7 @@ static struct dentry *vfat_lookup(struct inode *dir, struct dentry *dentry,
 	struct dentry *alias;
 	int err, table;
 
-	lock_kernel();
+	lock_super(sb);
 	table = (MSDOS_SB(sb)->options.name_check == 's') ? 2 : 0;
 	dentry->d_op = &vfat_dentry_ops[table];
 
@@ -699,7 +699,7 @@ static struct dentry *vfat_lookup(struct inode *dir, struct dentry *dentry,
 	inode = fat_build_inode(sb, sinfo.de, sinfo.i_pos);
 	brelse(sinfo.bh);
 	if (IS_ERR(inode)) {
-		unlock_kernel();
+		unlock_super(sb);
 		return ERR_CAST(inode);
 	}
 	alias = d_find_alias(inode);
@@ -708,13 +708,13 @@ static struct dentry *vfat_lookup(struct inode *dir, struct dentry *dentry,
 			dput(alias);
 		else {
 			iput(inode);
-			unlock_kernel();
+			unlock_super(sb);
 			return alias;
 		}
 
 	}
 error:
-	unlock_kernel();
+	unlock_super(sb);
 	dentry->d_op = &vfat_dentry_ops[table];
 	dentry->d_time = dentry->d_parent->d_inode->i_version;
 	dentry = d_splice_alias(inode, dentry);
@@ -734,7 +734,7 @@ static int vfat_create(struct inode *dir, struct dentry *dentry, int mode,
 	struct timespec ts;
 	int err;
 
-	lock_kernel();
+	lock_super(sb);
 
 	ts = CURRENT_TIME_SEC;
 	err = vfat_add_entry(dir, &dentry->d_name, 0, 0, &ts, &sinfo);
@@ -755,17 +755,18 @@ static int vfat_create(struct inode *dir, struct dentry *dentry, int mode,
 	dentry->d_time = dentry->d_parent->d_inode->i_version;
 	d_instantiate(dentry, inode);
 out:
-	unlock_kernel();
+	unlock_super(sb);
 	return err;
 }
 
 static int vfat_rmdir(struct inode *dir, struct dentry *dentry)
 {
 	struct inode *inode = dentry->d_inode;
+	struct super_block *sb = dir->i_sb;
 	struct fat_slot_info sinfo;
 	int err;
 
-	lock_kernel();
+	lock_super(sb);
 
 	err = fat_dir_empty(inode);
 	if (err)
@@ -783,7 +784,7 @@ static int vfat_rmdir(struct inode *dir, struct dentry *dentry)
 	inode->i_mtime = inode->i_atime = CURRENT_TIME_SEC;
 	fat_detach(inode);
 out:
-	unlock_kernel();
+	unlock_super(sb);
 
 	return err;
 }
@@ -791,10 +792,11 @@ out:
 static int vfat_unlink(struct inode *dir, struct dentry *dentry)
 {
 	struct inode *inode = dentry->d_inode;
+	struct super_block *sb = dir->i_sb;
 	struct fat_slot_info sinfo;
 	int err;
 
-	lock_kernel();
+	lock_super(sb);
 
 	err = vfat_find(dir, &dentry->d_name, &sinfo);
 	if (err)
@@ -807,7 +809,7 @@ static int vfat_unlink(struct inode *dir, struct dentry *dentry)
 	inode->i_mtime = inode->i_atime = CURRENT_TIME_SEC;
 	fat_detach(inode);
 out:
-	unlock_kernel();
+	unlock_super(sb);
 
 	return err;
 }
@@ -820,7 +822,7 @@ static int vfat_mkdir(struct inode *dir, struct dentry *dentry, int mode)
 	struct timespec ts;
 	int err, cluster;
 
-	lock_kernel();
+	lock_super(sb);
 
 	ts = CURRENT_TIME_SEC;
 	cluster = fat_alloc_new_dir(dir, &ts);
@@ -849,13 +851,13 @@ static int vfat_mkdir(struct inode *dir, struct dentry *dentry, int mode)
 	dentry->d_time = dentry->d_parent->d_inode->i_version;
 	d_instantiate(dentry, inode);
 
-	unlock_kernel();
+	unlock_super(sb);
 	return 0;
 
 out_free:
 	fat_free_clusters(dir, cluster);
 out:
-	unlock_kernel();
+	unlock_super(sb);
 	return err;
 }
 
@@ -869,11 +871,12 @@ static int vfat_rename(struct inode *old_dir, struct dentry *old_dentry,
 	struct timespec ts;
 	loff_t dotdot_i_pos, new_i_pos;
 	int err, is_dir, update_dotdot, corrupt = 0;
+	struct super_block *sb = old_dir->i_sb;
 
 	old_sinfo.bh = sinfo.bh = dotdot_bh = NULL;
 	old_inode = old_dentry->d_inode;
 	new_inode = new_dentry->d_inode;
-	lock_kernel();
+	lock_super(sb);
 	err = vfat_find(old_dir, &old_dentry->d_name, &old_sinfo);
 	if (err)
 		goto out;
@@ -951,7 +954,7 @@ out:
 	brelse(sinfo.bh);
 	brelse(dotdot_bh);
 	brelse(old_sinfo.bh);
-	unlock_kernel();
+	unlock_super(sb);
 
 	return err;
 

^ permalink raw reply related	[flat|nested] 8+ messages in thread

* Re: Remove BKL from FAT/VFAT/MSDOS (v1) (was Re: Fw: Regression caused by bf726e "semaphore: fix,")
  2008-05-16 22:36                                 ` Remove BKL from FAT/VFAT/MSDOS (v1) (was Re: Fw: Regression caused by bf726e "semaphore: fix,") Linus Torvalds
@ 2008-05-16 22:58                                   ` Linus Torvalds
  2008-05-17  0:25                                   ` OGAWA Hirofumi
  1 sibling, 0 replies; 8+ messages in thread
From: Linus Torvalds @ 2008-05-16 22:58 UTC (permalink / raw)
  To: Thomas Gleixner
  Cc: Ingo Molnar, Andrew Morton, OGAWA Hirofumi,
	Linux Kernel Mailing List



On Fri, 16 May 2008, Linus Torvalds wrote:
>
> 				[...] but I do think this is at 
> least an interesting starting point, and it's at least not "totally 
> obviously broken".

To clarify: lock_super() is actually a much *stronger* lock than 
lock_kernel(), which is why testing is actually interesting: the locking 
hasn't been weakened, it's actually become much stricter (because unlike 
the kernel lock, the superblock lock is kept over scheduling events, and 
doesn't silently nest).

So the most likely failure case is not that some locking went away and 
you'd race on the data structures, it's that something deadlocks on itself 
if the locking isn't right.

There could be some implicit kernel lock I missed (ie something that acts 
like the "ioctl" callback I already mentioned), of course, so I'm not 
going to swear myself blue in the face that there isn't a new race, but on 
the whole this patch should be pretty safe from the angle that at least 
the obvious locking bugs should cause deadlocks, not race conditions.

And if you enable lockdep, the deadlocks aren't silent deaths, but clear 
"this is where you took it, and here is where you deadlocked due to 
nesting" reports in dmesg. So this should be eminently debuggable even by 
almost total newbies that are just interested in BKL removal.

		Linus

^ permalink raw reply	[flat|nested] 8+ messages in thread

* Re: Remove BKL from FAT/VFAT/MSDOS (v1) (was Re: Fw: Regression caused by bf726e "semaphore: fix,")
  2008-05-16 22:36                                 ` Remove BKL from FAT/VFAT/MSDOS (v1) (was Re: Fw: Regression caused by bf726e "semaphore: fix,") Linus Torvalds
  2008-05-16 22:58                                   ` Linus Torvalds
@ 2008-05-17  0:25                                   ` OGAWA Hirofumi
  2008-05-17  1:31                                     ` Linus Torvalds
  1 sibling, 1 reply; 8+ messages in thread
From: OGAWA Hirofumi @ 2008-05-17  0:25 UTC (permalink / raw)
  To: Linus Torvalds
  Cc: Thomas Gleixner, Ingo Molnar, Andrew Morton,
	Linux Kernel Mailing List

Linus Torvalds <torvalds@linux-foundation.org> writes:

> On Fri, 16 May 2008, Linus Torvalds wrote:
>> 
>> In fact, some of the lock_kernel() calls looked like they could even be 
>> dropped:
>> 
>>  - fat_clear_inode already gets the real spinlocks (inode_hash_lock and 
>>    cache_lru_lock), and the kernel lock looks pointless.
>
> Ok, this was also the only one that was called under the superblock lock 
> (sys_umount->deactivate_super->invalidate_inodes->clear_inode), and 
> everything else could be directly converted to use the superblock lock, so 
> here's a trial balloon patch that does exactly that: just blindly convert 
> all the "lock_kernel()" calls to "lock_super(sb)", except for the one in 
> fat_clear_inode(), which is dropped entirely.

IIRC, when I looked this lastly, almost BKLs was just tossed from VFS,
and FAT taked the needed locks anymore, but I'm not sure NFS related
stuff.  Basically, we can just drop BKLs and I tested it repeatedly.

I attached the tested patch by me (but nfs stuff is not tested, it
triggers -ESTALE easily). But, I can't say, "I'm very sure, this patch
is safe", so, I didn't submit the patch yet...

> ANOTHER NOTE! I didn't change this to use .unlocked_ioctl(), and I didn't 
> even really look at it. It still takes the BKL, but obviously doesn't help 
> any. It didn't look like it should really need it, because it seems to do 
> the right locking as-is (ie it gets the inode mutex, and it calls 
> __fat_readdir() which now does the lock_super()).

Ah, I didn't notice about this. But we should be able to just use it.

>  static inline struct fat_cache *fat_cache_alloc(struct inode *inode)
>  {
> -	return kmem_cache_alloc(fat_cache_cachep, GFP_KERNEL);
> +	return kmem_cache_alloc(fat_cache_cachep, GFP_NOFS);
>  }

Yes.

>  static struct inode *fat_alloc_inode(struct super_block *sb)
>  {
>  	struct msdos_inode_info *ei;
> -	ei = kmem_cache_alloc(fat_inode_cachep, GFP_KERNEL);
> +	ei = kmem_cache_alloc(fat_inode_cachep, GFP_NOFS);
>  	if (!ei)
>  		return NULL;
>  	return &ei->vfs_inode;

Um... do we need this? I think this path is not called from memory
allocation path...
-- 
OGAWA Hirofumi <hirofumi@mail.parknet.co.jp>



Signed-off-by: OGAWA Hirofumi <hirofumi@mail.parknet.co.jp>
---

 fs/fat/dir.c     |    6 +++---
 fs/fat/file.c    |   10 +++++-----
 fs/fat/inode.c   |   16 ++++++++--------
 fs/msdos/namei.c |   28 ++++++++++++++--------------
 fs/vfat/namei.c  |   32 ++++++++++++++++----------------
 5 files changed, 46 insertions(+), 46 deletions(-)

diff -puN fs/fat/dir.c~fat_kill-bkl fs/fat/dir.c
--- linux-2.6/fs/fat/dir.c~fat_kill-bkl	2008-04-23 04:40:10.000000000 +0900
+++ linux-2.6-hirofumi/fs/fat/dir.c	2008-04-23 04:40:10.000000000 +0900
@@ -18,7 +18,7 @@
 #include <linux/time.h>
 #include <linux/msdos_fs.h>
 #include <linux/dirent.h>
-#include <linux/smp_lock.h>
+//#include <linux/smp_lock.h>
 #include <linux/buffer_head.h>
 #include <linux/compat.h>
 #include <asm/uaccess.h>
@@ -472,7 +472,7 @@ static int __fat_readdir(struct inode *i
 	loff_t cpos;
 	int ret = 0;
 
-	lock_kernel();
+//	lock_kernel();
 
 	cpos = filp->f_pos;
 	/* Fake . and .. for the root directory. */
@@ -654,7 +654,7 @@ FillFailed:
 	if (unicode)
 		__putname(unicode);
 out:
-	unlock_kernel();
+//	unlock_kernel();
 	return ret;
 }
 
diff -puN fs/fat/file.c~fat_kill-bkl fs/fat/file.c
--- linux-2.6/fs/fat/file.c~fat_kill-bkl	2008-04-23 04:40:10.000000000 +0900
+++ linux-2.6-hirofumi/fs/fat/file.c	2008-04-23 04:40:10.000000000 +0900
@@ -11,7 +11,7 @@
 #include <linux/mount.h>
 #include <linux/time.h>
 #include <linux/msdos_fs.h>
-#include <linux/smp_lock.h>
+//#include <linux/smp_lock.h>
 #include <linux/buffer_head.h>
 #include <linux/writeback.h>
 #include <linux/backing-dev.h>
@@ -244,9 +244,9 @@ void fat_truncate(struct inode *inode)
 
 	nr_clusters = (inode->i_size + (cluster_size - 1)) >> sbi->cluster_bits;
 
-	lock_kernel();
+//	lock_kernel();
 	fat_free(inode, nr_clusters);
-	unlock_kernel();
+//	unlock_kernel();
 	fat_flush_inodes(inode->i_sb, inode, NULL);
 	fs_mark_flush(sb);
 }
@@ -305,7 +305,7 @@ int fat_setattr(struct dentry *dentry, s
 	int mask, error = 0;
 	unsigned int ia_valid;
 
-	lock_kernel();
+//	lock_kernel();
 
 	/*
 	 * Expand the file. Since inode_setattr() updates ->i_size
@@ -359,7 +359,7 @@ int fat_setattr(struct dentry *dentry, s
 		mask = sbi->options.fs_fmask;
 	inode->i_mode &= S_IFMT | (S_IRWXUGO & ~mask);
 out:
-	unlock_kernel();
+//	unlock_kernel();
 	return error;
 }
 EXPORT_SYMBOL_GPL(fat_setattr);
diff -puN fs/fat/inode.c~fat_kill-bkl fs/fat/inode.c
--- linux-2.6/fs/fat/inode.c~fat_kill-bkl	2008-04-23 04:40:10.000000000 +0900
+++ linux-2.6-hirofumi/fs/fat/inode.c	2008-04-23 04:40:10.000000000 +0900
@@ -14,7 +14,7 @@
 #include <linux/init.h>
 #include <linux/time.h>
 #include <linux/slab.h>
-#include <linux/smp_lock.h>
+//#include <linux/smp_lock.h>
 #include <linux/seq_file.h>
 #include <linux/msdos_fs.h>
 #include <linux/pagemap.h>
@@ -442,12 +442,12 @@ static void fat_clear_inode(struct inode
 {
 	struct msdos_sb_info *sbi = MSDOS_SB(inode->i_sb);
 
-	lock_kernel();
+//	lock_kernel();
 	spin_lock(&sbi->inode_hash_lock);
 	fat_cache_inval_inode(inode);
 	hlist_del_init(&MSDOS_I(inode)->i_fat_hash);
 	spin_unlock(&sbi->inode_hash_lock);
-	unlock_kernel();
+//	unlock_kernel();
 }
 
 static void fat_write_super(struct super_block *sb)
@@ -567,7 +567,7 @@ retry:
 	if (inode->i_ino == MSDOS_ROOT_INO || !i_pos)
 		return 0;
 
-	lock_kernel();
+//	lock_kernel();
 	bh = sb_bread(sb, i_pos >> sbi->dir_per_block_bits);
 	if (!bh) {
 		printk(KERN_ERR "FAT: unable to read inode block "
@@ -579,7 +579,7 @@ retry:
 	if (i_pos != MSDOS_I(inode)->i_pos) {
 		spin_unlock(&sbi->inode_hash_lock);
 		brelse(bh);
-		unlock_kernel();
+//		unlock_kernel();
 		goto retry;
 	}
 
@@ -606,7 +606,7 @@ retry:
 		err = sync_dirty_buffer(bh);
 	brelse(bh);
 out:
-	unlock_kernel();
+//	unlock_kernel();
 	return err;
 }
 
@@ -743,7 +743,7 @@ static struct dentry *fat_get_parent(str
 	struct inode *inode;
 	int err;
 
-	lock_kernel();
+//	lock_kernel();
 
 	err = fat_get_dotdot_entry(child->d_inode, &bh, &de, &i_pos);
 	if (err) {
@@ -762,7 +762,7 @@ static struct dentry *fat_get_parent(str
 		parent = ERR_PTR(-ENOMEM);
 	}
 out:
-	unlock_kernel();
+//	unlock_kernel();
 
 	return parent;
 }
diff -puN fs/msdos/namei.c~fat_kill-bkl fs/msdos/namei.c
--- linux-2.6/fs/msdos/namei.c~fat_kill-bkl	2008-04-23 04:40:10.000000000 +0900
+++ linux-2.6-hirofumi/fs/msdos/namei.c	2008-04-23 04:40:10.000000000 +0900
@@ -10,7 +10,7 @@
 #include <linux/time.h>
 #include <linux/buffer_head.h>
 #include <linux/msdos_fs.h>
-#include <linux/smp_lock.h>
+//#include <linux/smp_lock.h>
 
 /* Characters that are undesirable in an MS-DOS file name */
 static unsigned char bad_chars[] = "*?<>|\"";
@@ -214,7 +214,7 @@ static struct dentry *msdos_lookup(struc
 
 	dentry->d_op = &msdos_dentry_operations;
 
-	lock_kernel();
+//	lock_kernel();
 	res = msdos_find(dir, dentry->d_name.name, dentry->d_name.len, &sinfo);
 	if (res == -ENOENT)
 		goto add;
@@ -232,7 +232,7 @@ add:
 	if (dentry)
 		dentry->d_op = &msdos_dentry_operations;
 out:
-	unlock_kernel();
+//	unlock_kernel();
 	if (!res)
 		return dentry;
 	return ERR_PTR(res);
@@ -286,7 +286,7 @@ static int msdos_create(struct inode *di
 	unsigned char msdos_name[MSDOS_NAME];
 	int err, is_hid;
 
-	lock_kernel();
+//	lock_kernel();
 
 	err = msdos_format_name(dentry->d_name.name, dentry->d_name.len,
 				msdos_name, &MSDOS_SB(sb)->options);
@@ -315,7 +315,7 @@ static int msdos_create(struct inode *di
 
 	d_instantiate(dentry, inode);
 out:
-	unlock_kernel();
+//	unlock_kernel();
 	if (!err)
 		err = fat_flush_inodes(sb, dir, inode);
 	return err;
@@ -328,7 +328,7 @@ static int msdos_rmdir(struct inode *dir
 	struct fat_slot_info sinfo;
 	int err;
 
-	lock_kernel();
+//	lock_kernel();
 	/*
 	 * Check whether the directory is not in use, then check
 	 * whether it is empty.
@@ -349,7 +349,7 @@ static int msdos_rmdir(struct inode *dir
 	inode->i_ctime = CURRENT_TIME_SEC;
 	fat_detach(inode);
 out:
-	unlock_kernel();
+//	unlock_kernel();
 	if (!err)
 		err = fat_flush_inodes(inode->i_sb, dir, inode);
 
@@ -366,7 +366,7 @@ static int msdos_mkdir(struct inode *dir
 	struct timespec ts;
 	int err, is_hid, cluster;
 
-	lock_kernel();
+//	lock_kernel();
 
 	err = msdos_format_name(dentry->d_name.name, dentry->d_name.len,
 				msdos_name, &MSDOS_SB(sb)->options);
@@ -404,14 +404,14 @@ static int msdos_mkdir(struct inode *dir
 
 	d_instantiate(dentry, inode);
 
-	unlock_kernel();
+//	unlock_kernel();
 	fat_flush_inodes(sb, dir, inode);
 	return 0;
 
 out_free:
 	fat_free_clusters(dir, cluster);
 out:
-	unlock_kernel();
+//	unlock_kernel();
 	return err;
 }
 
@@ -422,7 +422,7 @@ static int msdos_unlink(struct inode *di
 	struct fat_slot_info sinfo;
 	int err;
 
-	lock_kernel();
+//	lock_kernel();
 	err = msdos_find(dir, dentry->d_name.name, dentry->d_name.len, &sinfo);
 	if (err)
 		goto out;
@@ -434,7 +434,7 @@ static int msdos_unlink(struct inode *di
 	inode->i_ctime = CURRENT_TIME_SEC;
 	fat_detach(inode);
 out:
-	unlock_kernel();
+//	unlock_kernel();
 	if (!err)
 		err = fat_flush_inodes(inode->i_sb, dir, inode);
 
@@ -621,7 +621,7 @@ static int msdos_rename(struct inode *ol
 	unsigned char old_msdos_name[MSDOS_NAME], new_msdos_name[MSDOS_NAME];
 	int err, is_hid;
 
-	lock_kernel();
+//	lock_kernel();
 
 	err = msdos_format_name(old_dentry->d_name.name,
 				old_dentry->d_name.len, old_msdos_name,
@@ -640,7 +640,7 @@ static int msdos_rename(struct inode *ol
 	err = do_msdos_rename(old_dir, old_msdos_name, old_dentry,
 			      new_dir, new_msdos_name, new_dentry, is_hid);
 out:
-	unlock_kernel();
+//	unlock_kernel();
 	if (!err)
 		err = fat_flush_inodes(old_dir->i_sb, old_dir, new_dir);
 	return err;
diff -puN fs/vfat/namei.c~fat_kill-bkl fs/vfat/namei.c
--- linux-2.6/fs/vfat/namei.c~fat_kill-bkl	2008-04-23 04:40:10.000000000 +0900
+++ linux-2.6-hirofumi/fs/vfat/namei.c	2008-04-23 04:40:10.000000000 +0900
@@ -21,7 +21,7 @@
 #include <linux/msdos_fs.h>
 #include <linux/ctype.h>
 #include <linux/slab.h>
-#include <linux/smp_lock.h>
+//#include <linux/smp_lock.h>
 #include <linux/buffer_head.h>
 #include <linux/namei.h>
 
@@ -687,7 +687,7 @@ static struct dentry *vfat_lookup(struct
 	struct dentry *alias;
 	int err, table;
 
-	lock_kernel();
+//	lock_kernel();
 	table = (MSDOS_SB(sb)->options.name_check == 's') ? 2 : 0;
 	dentry->d_op = &vfat_dentry_ops[table];
 
@@ -699,7 +699,7 @@ static struct dentry *vfat_lookup(struct
 	inode = fat_build_inode(sb, sinfo.de, sinfo.i_pos);
 	brelse(sinfo.bh);
 	if (IS_ERR(inode)) {
-		unlock_kernel();
+//		unlock_kernel();
 		return ERR_CAST(inode);
 	}
 	alias = d_find_alias(inode);
@@ -708,13 +708,13 @@ static struct dentry *vfat_lookup(struct
 			dput(alias);
 		else {
 			iput(inode);
-			unlock_kernel();
+//			unlock_kernel();
 			return alias;
 		}
 
 	}
 error:
-	unlock_kernel();
+//	unlock_kernel();
 	dentry->d_op = &vfat_dentry_ops[table];
 	dentry->d_time = dentry->d_parent->d_inode->i_version;
 	dentry = d_splice_alias(inode, dentry);
@@ -734,7 +734,7 @@ static int vfat_create(struct inode *dir
 	struct timespec ts;
 	int err;
 
-	lock_kernel();
+//	lock_kernel();
 
 	ts = CURRENT_TIME_SEC;
 	err = vfat_add_entry(dir, &dentry->d_name, 0, 0, &ts, &sinfo);
@@ -755,7 +755,7 @@ static int vfat_create(struct inode *dir
 	dentry->d_time = dentry->d_parent->d_inode->i_version;
 	d_instantiate(dentry, inode);
 out:
-	unlock_kernel();
+//	unlock_kernel();
 	return err;
 }
 
@@ -765,7 +765,7 @@ static int vfat_rmdir(struct inode *dir,
 	struct fat_slot_info sinfo;
 	int err;
 
-	lock_kernel();
+//	lock_kernel();
 
 	err = fat_dir_empty(inode);
 	if (err)
@@ -783,7 +783,7 @@ static int vfat_rmdir(struct inode *dir,
 	inode->i_mtime = inode->i_atime = CURRENT_TIME_SEC;
 	fat_detach(inode);
 out:
-	unlock_kernel();
+//	unlock_kernel();
 
 	return err;
 }
@@ -794,7 +794,7 @@ static int vfat_unlink(struct inode *dir
 	struct fat_slot_info sinfo;
 	int err;
 
-	lock_kernel();
+//	lock_kernel();
 
 	err = vfat_find(dir, &dentry->d_name, &sinfo);
 	if (err)
@@ -807,7 +807,7 @@ static int vfat_unlink(struct inode *dir
 	inode->i_mtime = inode->i_atime = CURRENT_TIME_SEC;
 	fat_detach(inode);
 out:
-	unlock_kernel();
+//	unlock_kernel();
 
 	return err;
 }
@@ -820,7 +820,7 @@ static int vfat_mkdir(struct inode *dir,
 	struct timespec ts;
 	int err, cluster;
 
-	lock_kernel();
+//	lock_kernel();
 
 	ts = CURRENT_TIME_SEC;
 	cluster = fat_alloc_new_dir(dir, &ts);
@@ -849,13 +849,13 @@ static int vfat_mkdir(struct inode *dir,
 	dentry->d_time = dentry->d_parent->d_inode->i_version;
 	d_instantiate(dentry, inode);
 
-	unlock_kernel();
+//	unlock_kernel();
 	return 0;
 
 out_free:
 	fat_free_clusters(dir, cluster);
 out:
-	unlock_kernel();
+//	unlock_kernel();
 	return err;
 }
 
@@ -873,7 +873,7 @@ static int vfat_rename(struct inode *old
 	old_sinfo.bh = sinfo.bh = dotdot_bh = NULL;
 	old_inode = old_dentry->d_inode;
 	new_inode = new_dentry->d_inode;
-	lock_kernel();
+//	lock_kernel();
 	err = vfat_find(old_dir, &old_dentry->d_name, &old_sinfo);
 	if (err)
 		goto out;
@@ -951,7 +951,7 @@ out:
 	brelse(sinfo.bh);
 	brelse(dotdot_bh);
 	brelse(old_sinfo.bh);
-	unlock_kernel();
+//	unlock_kernel();
 
 	return err;
 
_

^ permalink raw reply	[flat|nested] 8+ messages in thread

* Re: Remove BKL from FAT/VFAT/MSDOS (v1) (was Re: Fw: Regression caused by bf726e "semaphore: fix,")
  2008-05-17  0:25                                   ` OGAWA Hirofumi
@ 2008-05-17  1:31                                     ` Linus Torvalds
  2008-05-29 20:45                                       ` Tony Luck
  0 siblings, 1 reply; 8+ messages in thread
From: Linus Torvalds @ 2008-05-17  1:31 UTC (permalink / raw)
  To: OGAWA Hirofumi
  Cc: Thomas Gleixner, Ingo Molnar, Andrew Morton,
	Linux Kernel Mailing List



On Sat, 17 May 2008, OGAWA Hirofumi wrote:
> >  static struct inode *fat_alloc_inode(struct super_block *sb)
> >  {
> >  	struct msdos_inode_info *ei;
> > -	ei = kmem_cache_alloc(fat_inode_cachep, GFP_KERNEL);
> > +	ei = kmem_cache_alloc(fat_inode_cachep, GFP_NOFS);
> >  	if (!ei)
> >  		return NULL;
> >  	return &ei->vfs_inode;
> 
> Um... do we need this? I think this path is not called from memory
> allocation path...

The issue isn't that *this* is called by memory allocation paths, but 
whether this can hold the lock and then some memory allocation path calls 
back to the filesystem two write something out - and deadlock.

In other words, the chain is something like this:

	msdos_lookup
	  lock_super()			****
	  fat_build_inode ->
	    new_inode() ->
	      s->s_ops->alloc_inode = fat_alloc_inode ->
	        kmem_cache_alloc() ->
	          .. pageout ..
	            sync_inodes ->
	            (or any other writeout)
	              lock_super()	****

and now it deadlocks.

In other words, the kmem_cache_alloc() must _not_ be allowed to actually 
cause a filesystem writeout, and that's what GFP_NOFS is all about.

That said, just removing the lock-kernel entirely obviously would not have 
that problem either, but I feel safer at least keeping the same locking it 
had, rather than removing locking entirely.

		Linus

^ permalink raw reply	[flat|nested] 8+ messages in thread

* Re: Remove BKL from FAT/VFAT/MSDOS (v1) (was Re: Fw: Regression caused by bf726e "semaphore: fix,")
  2008-05-17  1:31                                     ` Linus Torvalds
@ 2008-05-29 20:45                                       ` Tony Luck
  2008-05-29 21:37                                         ` Linus Torvalds
  0 siblings, 1 reply; 8+ messages in thread
From: Tony Luck @ 2008-05-29 20:45 UTC (permalink / raw)
  To: Linus Torvalds
  Cc: OGAWA Hirofumi, Thomas Gleixner, Ingo Molnar, Andrew Morton,
	Linux Kernel Mailing List, corbet

I'm seeing a process hang running a kernel built from the linux-next tree
with tag next-20080529 The problem commit looks to be:
35e447fc2fa408df8af2c8735f83a90cafe651ff

"Replace BKL with superblock lock in fat/msdos/vfat"

This causes a lockup when overwriting an existing file
on a vfat filesystem.  E.g. for me (where there already
exists a vmlinux.gz file in the target directory):

# cp --force vmlinux.gz /boot/efi/efi/redhat/

Stack trace looks like this:
Call Trace:
 [<a000000100712550>] schedule+0x11f0/0x1380
                                sp=e0000001bd55fc30 bsp=e0000001bd5510b8
 [<a000000100714cb0>] __mutex_lock_slowpath+0x2d0/0x520
                                sp=e0000001bd55fc50 bsp=e0000001bd551060
 [<a000000100714f20>] mutex_lock+0x20/0x40
                                sp=e0000001bd55fc80 bsp=e0000001bd551040
 [<a0000001001367d0>] lock_super+0x30/0x60
                                sp=e0000001bd55fc80 bsp=e0000001bd551020
 [<a00000010028ca30>] fat_truncate+0xb0/0x640^M
                                sp=e0000001bd55fc80 bsp=e0000001bd550fa0
 [<a0000001000fd930>] vmtruncate+0x1f0/0x260
                                sp=e0000001bd55fce0 bsp=e0000001bd550f70
 [<a000000100164250>] inode_setattr+0x50/0x320
                                sp=e0000001bd55fcf0 bsp=e0000001bd550f38
 [<a00000010028d520>] fat_setattr+0x4c0/0x580
                                sp=e0000001bd55fcf0 bsp=e0000001bd550ed0
 [<a0000001001648e0>] notify_change+0x3c0/0x620
                                sp=e0000001bd55fd10 bsp=e0000001bd550e70
 [<a00000010012fe00>] do_truncate+0xc0/0x120
                                sp=e0000001bd55fd30 bsp=e0000001bd550e30
 [<a0000001001494c0>] may_open+0x340/0x3a0
                                sp=e0000001bd55fd80 bsp=e0000001bd550de0
 [<a000000100149c60>] do_filp_open+0x740/0x11c0
                                sp=e0000001bd55fd80 bsp=e0000001bd550d18
 [<a000000100132470>] do_sys_open+0x90/0x1c0
                                sp=e0000001bd55fe30 bsp=e0000001bd550cc8
 [<a0000001001325f0>] sys_open+0x50/0x80
                                sp=e0000001bd55fe30 bsp=e0000001bd550c70

Looking at fat_setattr() I see it calls lock_super() at the start and releases
it at the end.  In between is the call to inode_setattr() ... which calls
down through inode_setattr() and vmtruncate() to fat_truncate() ...
which calls lock_super() again. Deadlock.

-Tony

^ permalink raw reply	[flat|nested] 8+ messages in thread

* Re: Remove BKL from FAT/VFAT/MSDOS (v1) (was Re: Fw: Regression caused by bf726e "semaphore: fix,")
  2008-05-29 20:45                                       ` Tony Luck
@ 2008-05-29 21:37                                         ` Linus Torvalds
  2008-05-29 23:13                                           ` Jonathan Corbet
  0 siblings, 1 reply; 8+ messages in thread
From: Linus Torvalds @ 2008-05-29 21:37 UTC (permalink / raw)
  To: Tony Luck
  Cc: OGAWA Hirofumi, Thomas Gleixner, Ingo Molnar, Andrew Morton,
	Linux Kernel Mailing List, corbet



On Thu, 29 May 2008, Tony Luck wrote:
> 
> This causes a lockup when overwriting an existing file
> on a vfat filesystem.  E.g. for me (where there already
> exists a vmlinux.gz file in the target directory):

Thanks, that was something I didn't test. I just tested various simple 
file create/delete/read/write.

> Looking at fat_setattr() I see it calls lock_super() at the start and releases
> it at the end.  In between is the call to inode_setattr() ... which calls
> down through inode_setattr() and vmtruncate() to fat_truncate() ...
> which calls lock_super() again. Deadlock.

Yup.

And as far as I can tell there is absolutely nothing in fat_setattr() that 
we actually want to protect - it calls things like fat_cont_expand(), but 
that just calls down to the generic VFS layer that uses the pagecache 
functions, and those need to handle the locking correctly for other 
reasons (totally unrelated to setattr - they get called without locking 
for regular writes, after all).

So it looks like the correct fix is to just remove the lock_super() in 
fat_setattr() entirely (along with the "sb" variable that is then no 
longer used).

It *also* turns out that we should remove the lock_super() from 
fat_truncate: all the truncate paths already hold the inode mutex from the 
VFS layer, so the inode data structures themselves would be serialized for 
other reasons. And it only protects the call to "fat_free()", which in 
turn calls the FAT cluster routines ("fatent") that already are protected 
by the fatent spinlock.

More importantly, if it's a filesystem marked DIRSYNC, it will call 
"fat_sync_inode()", which takes the superblock lock (and needs it, because 
it's called frm the VFS layer too) and would deadlock there.

So the end result of that is all the "lock_kernel()" calls in 
fs/fat/file.c should actually just go away - not be replaced by 
lock_super() at alL!

Jonathan, do you want an updated replacement patch, or an incremental one, 
or will you just do that trivial fix yourself?

			Linus

^ permalink raw reply	[flat|nested] 8+ messages in thread

* Re: Remove BKL from FAT/VFAT/MSDOS (v1) (was Re: Fw: Regression caused by bf726e "semaphore: fix,")
  2008-05-29 21:37                                         ` Linus Torvalds
@ 2008-05-29 23:13                                           ` Jonathan Corbet
  2008-05-29 23:17                                             ` Linus Torvalds
  0 siblings, 1 reply; 8+ messages in thread
From: Jonathan Corbet @ 2008-05-29 23:13 UTC (permalink / raw)
  To: Linus Torvalds
  Cc: OGAWA Hirofumi, Thomas Gleixner, Ingo Molnar, Andrew Morton,
	Tony Luck, Linux Kernel Mailing List

Linus Torvalds <torvalds@linux-foundation.org> wrote:

> Jonathan, do you want an updated replacement patch, or an incremental one, 
> or will you just do that trivial fix yourself?

Something like the attached?  Seems to work for me.  If nobody gripes
I'll stick it into the bkl-removal tree.

jon

Remove deadlocking lock_super() calls from FAT

Linus sez:

	So the end result of that is all the "lock_kernel()" calls in
	fs/fat/file.c should actually just go away - not be replaced by
	lock_super() at alL!

This patch causes that to be.

Signed-off-by: Jonathan Corbet <corbet@lwn.net>


diff --git a/fs/fat/file.c b/fs/fat/file.c
index 7059928..bdf91e9 100644
--- a/fs/fat/file.c
+++ b/fs/fat/file.c
@@ -11,7 +11,6 @@
 #include <linux/mount.h>
 #include <linux/time.h>
 #include <linux/msdos_fs.h>
-#include <linux/smp_lock.h>
 #include <linux/buffer_head.h>
 #include <linux/writeback.h>
 #include <linux/backing-dev.h>
@@ -229,8 +228,7 @@ static int fat_free(struct inode *inode, int skip)
 
 void fat_truncate(struct inode *inode)
 {
-	struct super_block *sb = inode->i_sb;
-	struct msdos_sb_info *sbi = MSDOS_SB(sb);
+	struct msdos_sb_info *sbi = MSDOS_SB(inode->i_sb);
 	const unsigned int cluster_size = sbi->cluster_size;
 	int nr_clusters;
 
@@ -243,9 +241,7 @@ void fat_truncate(struct inode *inode)
 
 	nr_clusters = (inode->i_size + (cluster_size - 1)) >> sbi->cluster_bits;
 
-	lock_super(sb);
 	fat_free(inode, nr_clusters);
-	unlock_super(sb);
 	fat_flush_inodes(inode->i_sb, inode, NULL);
 }
 
@@ -298,14 +294,11 @@ static int fat_allow_set_time(struct msdos_sb_info *sbi, struct inode *inode)
 
 int fat_setattr(struct dentry *dentry, struct iattr *attr)
 {
-	struct super_block *sb = dentry->d_sb;
 	struct msdos_sb_info *sbi = MSDOS_SB(dentry->d_sb);
 	struct inode *inode = dentry->d_inode;
 	int mask, error = 0;
 	unsigned int ia_valid;
 
-	lock_super(sb);
-
 	/*
 	 * Expand the file. Since inode_setattr() updates ->i_size
 	 * before calling the ->truncate(), but FAT needs to fill the
@@ -358,7 +351,6 @@ int fat_setattr(struct dentry *dentry, struct iattr *attr)
 		mask = sbi->options.fs_fmask;
 	inode->i_mode &= S_IFMT | (S_IRWXUGO & ~mask);
 out:
-	unlock_super(sb);
 	return error;
 }
 EXPORT_SYMBOL_GPL(fat_setattr);

^ permalink raw reply related	[flat|nested] 8+ messages in thread

* Re: Remove BKL from FAT/VFAT/MSDOS (v1) (was Re: Fw: Regression caused by bf726e "semaphore: fix,")
  2008-05-29 23:13                                           ` Jonathan Corbet
@ 2008-05-29 23:17                                             ` Linus Torvalds
  0 siblings, 0 replies; 8+ messages in thread
From: Linus Torvalds @ 2008-05-29 23:17 UTC (permalink / raw)
  To: Jonathan Corbet
  Cc: OGAWA Hirofumi, Thomas Gleixner, Ingo Molnar, Andrew Morton,
	Tony Luck, Linux Kernel Mailing List



On Thu, 29 May 2008, Jonathan Corbet wrote:
> 
> Something like the attached?

Ack. And good of you to notice the <linux/smp_lock.h> include. Although 
there's a few others that should go away too.

		Linus

^ permalink raw reply	[flat|nested] 8+ messages in thread

end of thread, other threads:[~2008-05-29 23:18 UTC | newest]

Thread overview: 8+ messages (download: mbox.gz follow: Atom feed
-- links below jump to the message on this page --
     [not found] <20080510121020.f33c83f7.akpm@linux-foundation.org>
     [not found] ` <20080511073338.GA17137@elte.hu>
     [not found]   ` <20080511075522.GA18214@elte.hu>
     [not found]     ` <Pine.LNX.4.64.0805111150250.32758@titan.stealer.net>
     [not found]       ` <20080511125731.GA28174@elte.hu>
     [not found]         ` <alpine.LFD.1.10.0805110941540.3330@woody.linux-foundation.org>
     [not found]           ` <20080511111210.77858eb4.akpm@linux-foundation.org>
     [not found]             ` <alpine.LFD.1.10.0805111221070.3188@woody.linux-foundation.org>
     [not found]               ` <alpine.LFD.1.10.0805111243250.3188@woody.linux-foundation.org>
     [not found]                 ` <20080511235112.GA16101@elte.hu>
     [not found]                   ` <alpine.LFD.1.10.0805120155490.3514@apollo.tec.linutronix.de>
     [not found]                     ` <alpine.LFD.1.10.0805120723440.3188@woody.linux-foundation.org>
     [not found]                       ` <alpine.LFD.1.10.0805121659470.3514@apollo.tec.linutronix.de>
     [not found]                         ` <alpine.LFD.1.10.0805121324410.3019@woody.linux-foundation.org>
     [not found]                           ` <alpine.LFD.1.10.0805161025510.3255@apollo.tec.linutronix.de>
     [not found]                             ` <alpine.LFD.1.10.0805160906580.2941@woody.linux-foundation.org>
     [not found]                               ` <alpine.LFD.1.10.0805160950180.2941@woody.linux-foundation.org>
2008-05-16 22:36                                 ` Remove BKL from FAT/VFAT/MSDOS (v1) (was Re: Fw: Regression caused by bf726e "semaphore: fix,") Linus Torvalds
2008-05-16 22:58                                   ` Linus Torvalds
2008-05-17  0:25                                   ` OGAWA Hirofumi
2008-05-17  1:31                                     ` Linus Torvalds
2008-05-29 20:45                                       ` Tony Luck
2008-05-29 21:37                                         ` Linus Torvalds
2008-05-29 23:13                                           ` Jonathan Corbet
2008-05-29 23:17                                             ` Linus Torvalds

This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox