diff options
| author | Mikulas Patocka <mikulas@artax.karlin.mff.cuni.cz> | 2011-05-08 14:42:54 -0400 |
|---|---|---|
| committer | Linus Torvalds <torvalds@linux-foundation.org> | 2011-05-09 12:04:23 -0400 |
| commit | 7dd29d8d865efdb00c0542a5d2c87af8c52ea6c7 (patch) | |
| tree | 71f404ed317e2d1b689af088ece1c32c3b1535c8 | |
| parent | 637b424bf8747e50bab6648ab919632d6efd6c28 (diff) | |
HPFS: Introduce a global mutex and lock it on every callback from VFS.
Introduce a global mutex and lock it on every callback from VFS.
Performance doesn't matter, reviewing the whole code for locking correctness
would be too complicated, so simply lock it all.
Signed-off-by: Mikulas Patocka <mikulas@artax.karlin.mff.cuni.cz>
Signed-off-by: Linus Torvalds <torvalds@linux-foundation.org>
| -rw-r--r-- | fs/hpfs/buffer.c | 8 | ||||
| -rw-r--r-- | fs/hpfs/file.c | 27 | ||||
| -rw-r--r-- | fs/hpfs/hpfs_fn.h | 24 | ||||
| -rw-r--r-- | fs/hpfs/super.c | 10 |
4 files changed, 51 insertions, 18 deletions
diff --git a/fs/hpfs/buffer.c b/fs/hpfs/buffer.c index 793cb9d943d2..7cef5d5c3608 100644 --- a/fs/hpfs/buffer.c +++ b/fs/hpfs/buffer.c | |||
| @@ -32,6 +32,8 @@ void *hpfs_map_sector(struct super_block *s, unsigned secno, struct buffer_head | |||
| 32 | { | 32 | { |
| 33 | struct buffer_head *bh; | 33 | struct buffer_head *bh; |
| 34 | 34 | ||
| 35 | hpfs_lock_assert(s); | ||
| 36 | |||
| 35 | cond_resched(); | 37 | cond_resched(); |
| 36 | 38 | ||
| 37 | *bhp = bh = sb_bread(s, secno); | 39 | *bhp = bh = sb_bread(s, secno); |
| @@ -50,6 +52,8 @@ void *hpfs_get_sector(struct super_block *s, unsigned secno, struct buffer_head | |||
| 50 | struct buffer_head *bh; | 52 | struct buffer_head *bh; |
| 51 | /*return hpfs_map_sector(s, secno, bhp, 0);*/ | 53 | /*return hpfs_map_sector(s, secno, bhp, 0);*/ |
| 52 | 54 | ||
| 55 | hpfs_lock_assert(s); | ||
| 56 | |||
| 53 | cond_resched(); | 57 | cond_resched(); |
| 54 | 58 | ||
| 55 | if ((*bhp = bh = sb_getblk(s, secno)) != NULL) { | 59 | if ((*bhp = bh = sb_getblk(s, secno)) != NULL) { |
| @@ -70,6 +74,8 @@ void *hpfs_map_4sectors(struct super_block *s, unsigned secno, struct quad_buffe | |||
| 70 | struct buffer_head *bh; | 74 | struct buffer_head *bh; |
| 71 | char *data; | 75 | char *data; |
| 72 | 76 | ||
| 77 | hpfs_lock_assert(s); | ||
| 78 | |||
| 73 | cond_resched(); | 79 | cond_resched(); |
| 74 | 80 | ||
| 75 | if (secno & 3) { | 81 | if (secno & 3) { |
| @@ -125,6 +131,8 @@ void *hpfs_get_4sectors(struct super_block *s, unsigned secno, | |||
| 125 | { | 131 | { |
| 126 | cond_resched(); | 132 | cond_resched(); |
| 127 | 133 | ||
| 134 | hpfs_lock_assert(s); | ||
| 135 | |||
| 128 | if (secno & 3) { | 136 | if (secno & 3) { |
| 129 | printk("HPFS: hpfs_get_4sectors: unaligned read\n"); | 137 | printk("HPFS: hpfs_get_4sectors: unaligned read\n"); |
| 130 | return NULL; | 138 | return NULL; |
diff --git a/fs/hpfs/file.c b/fs/hpfs/file.c index 9b9eb6933e43..09a642f853e1 100644 --- a/fs/hpfs/file.c +++ b/fs/hpfs/file.c | |||
| @@ -48,38 +48,46 @@ static secno hpfs_bmap(struct inode *inode, unsigned file_secno) | |||
| 48 | static void hpfs_truncate(struct inode *i) | 48 | static void hpfs_truncate(struct inode *i) |
| 49 | { | 49 | { |
| 50 | if (IS_IMMUTABLE(i)) return /*-EPERM*/; | 50 | if (IS_IMMUTABLE(i)) return /*-EPERM*/; |
| 51 | hpfs_lock(i->i_sb); | 51 | hpfs_lock_assert(i->i_sb); |
| 52 | |||
| 52 | hpfs_i(i)->i_n_secs = 0; | 53 | hpfs_i(i)->i_n_secs = 0; |
| 53 | i->i_blocks = 1 + ((i->i_size + 511) >> 9); | 54 | i->i_blocks = 1 + ((i->i_size + 511) >> 9); |
| 54 | hpfs_i(i)->mmu_private = i->i_size; | 55 | hpfs_i(i)->mmu_private = i->i_size; |
| 55 | hpfs_truncate_btree(i->i_sb, i->i_ino, 1, ((i->i_size + 511) >> 9)); | 56 | hpfs_truncate_btree(i->i_sb, i->i_ino, 1, ((i->i_size + 511) >> 9)); |
| 56 | hpfs_write_inode(i); | 57 | hpfs_write_inode(i); |
| 57 | hpfs_i(i)->i_n_secs = 0; | 58 | hpfs_i(i)->i_n_secs = 0; |
| 58 | hpfs_unlock(i->i_sb); | ||
| 59 | } | 59 | } |
| 60 | 60 | ||
| 61 | static int hpfs_get_block(struct inode *inode, sector_t iblock, struct buffer_head *bh_result, int create) | 61 | static int hpfs_get_block(struct inode *inode, sector_t iblock, struct buffer_head *bh_result, int create) |
| 62 | { | 62 | { |
| 63 | int r; | ||
| 63 | secno s; | 64 | secno s; |
| 65 | hpfs_lock(inode->i_sb); | ||
| 64 | s = hpfs_bmap(inode, iblock); | 66 | s = hpfs_bmap(inode, iblock); |
| 65 | if (s) { | 67 | if (s) { |
| 66 | map_bh(bh_result, inode->i_sb, s); | 68 | map_bh(bh_result, inode->i_sb, s); |
| 67 | return 0; | 69 | goto ret_0; |
| 68 | } | 70 | } |
| 69 | if (!create) return 0; | 71 | if (!create) goto ret_0; |
| 70 | if (iblock<<9 != hpfs_i(inode)->mmu_private) { | 72 | if (iblock<<9 != hpfs_i(inode)->mmu_private) { |
| 71 | BUG(); | 73 | BUG(); |
| 72 | return -EIO; | 74 | r = -EIO; |
| 75 | goto ret_r; | ||
| 73 | } | 76 | } |
| 74 | if ((s = hpfs_add_sector_to_btree(inode->i_sb, inode->i_ino, 1, inode->i_blocks - 1)) == -1) { | 77 | if ((s = hpfs_add_sector_to_btree(inode->i_sb, inode->i_ino, 1, inode->i_blocks - 1)) == -1) { |
| 75 | hpfs_truncate_btree(inode->i_sb, inode->i_ino, 1, inode->i_blocks - 1); | 78 | hpfs_truncate_btree(inode->i_sb, inode->i_ino, 1, inode->i_blocks - 1); |
| 76 | return -ENOSPC; | 79 | r = -ENOSPC; |
| 80 | goto ret_r; | ||
| 77 | } | 81 | } |
| 78 | inode->i_blocks++; | 82 | inode->i_blocks++; |
| 79 | hpfs_i(inode)->mmu_private += 512; | 83 | hpfs_i(inode)->mmu_private += 512; |
| 80 | set_buffer_new(bh_result); | 84 | set_buffer_new(bh_result); |
| 81 | map_bh(bh_result, inode->i_sb, s); | 85 | map_bh(bh_result, inode->i_sb, s); |
| 82 | return 0; | 86 | ret_0: |
| 87 | r = 0; | ||
| 88 | ret_r: | ||
| 89 | hpfs_unlock(inode->i_sb); | ||
| 90 | return r; | ||
| 83 | } | 91 | } |
| 84 | 92 | ||
| 85 | static int hpfs_writepage(struct page *page, struct writeback_control *wbc) | 93 | static int hpfs_writepage(struct page *page, struct writeback_control *wbc) |
| @@ -130,8 +138,11 @@ static ssize_t hpfs_file_write(struct file *file, const char __user *buf, | |||
| 130 | ssize_t retval; | 138 | ssize_t retval; |
| 131 | 139 | ||
| 132 | retval = do_sync_write(file, buf, count, ppos); | 140 | retval = do_sync_write(file, buf, count, ppos); |
| 133 | if (retval > 0) | 141 | if (retval > 0) { |
| 142 | hpfs_lock(file->f_path.dentry->d_sb); | ||
| 134 | hpfs_i(file->f_path.dentry->d_inode)->i_dirty = 1; | 143 | hpfs_i(file->f_path.dentry->d_inode)->i_dirty = 1; |
| 144 | hpfs_unlock(file->f_path.dentry->d_sb); | ||
| 145 | } | ||
| 135 | return retval; | 146 | return retval; |
| 136 | } | 147 | } |
| 137 | 148 | ||
diff --git a/fs/hpfs/hpfs_fn.h b/fs/hpfs/hpfs_fn.h index c15adbca07ff..89a4714b44c7 100644 --- a/fs/hpfs/hpfs_fn.h +++ b/fs/hpfs/hpfs_fn.h | |||
| @@ -63,6 +63,7 @@ struct hpfs_inode_info { | |||
| 63 | }; | 63 | }; |
| 64 | 64 | ||
| 65 | struct hpfs_sb_info { | 65 | struct hpfs_sb_info { |
| 66 | struct mutex hpfs_mutex; /* global hpfs lock */ | ||
| 66 | ino_t sb_root; /* inode number of root dir */ | 67 | ino_t sb_root; /* inode number of root dir */ |
| 67 | unsigned sb_fs_size; /* file system size, sectors */ | 68 | unsigned sb_fs_size; /* file system size, sectors */ |
| 68 | unsigned sb_bitmaps; /* sector number of bitmap list */ | 69 | unsigned sb_bitmaps; /* sector number of bitmap list */ |
| @@ -346,21 +347,26 @@ static inline time32_t gmt_to_local(struct super_block *s, time_t t) | |||
| 346 | /* | 347 | /* |
| 347 | * Locking: | 348 | * Locking: |
| 348 | * | 349 | * |
| 349 | * hpfs_lock() is a leftover from the big kernel lock. | 350 | * hpfs_lock() locks the whole filesystem. It must be taken |
| 350 | * Right now, these functions are empty and only left | 351 | * on any method called by the VFS. |
| 351 | * for documentation purposes. The file system no longer | ||
| 352 | * works on SMP systems, so the lock is not needed | ||
| 353 | * any more. | ||
| 354 | * | 352 | * |
| 355 | * If someone is interested in making it work again, this | 353 | * We don't do any per-file locking anymore, it is hard to |
| 356 | * would be the place to start by adding a per-superblock | 354 | * review and HPFS is not performance-sensitive anyway. |
| 357 | * mutex and fixing all the bugs and performance issues | ||
| 358 | * caused by that. | ||
| 359 | */ | 355 | */ |
| 360 | static inline void hpfs_lock(struct super_block *s) | 356 | static inline void hpfs_lock(struct super_block *s) |
| 361 | { | 357 | { |
| 358 | struct hpfs_sb_info *sbi = hpfs_sb(s); | ||
| 359 | mutex_lock(&sbi->hpfs_mutex); | ||
| 362 | } | 360 | } |
| 363 | 361 | ||
| 364 | static inline void hpfs_unlock(struct super_block *s) | 362 | static inline void hpfs_unlock(struct super_block *s) |
| 365 | { | 363 | { |
| 364 | struct hpfs_sb_info *sbi = hpfs_sb(s); | ||
| 365 | mutex_unlock(&sbi->hpfs_mutex); | ||
| 366 | } | ||
| 367 | |||
| 368 | static inline void hpfs_lock_assert(struct super_block *s) | ||
| 369 | { | ||
| 370 | struct hpfs_sb_info *sbi = hpfs_sb(s); | ||
| 371 | WARN_ON(!mutex_is_locked(&sbi->hpfs_mutex)); | ||
| 366 | } | 372 | } |
diff --git a/fs/hpfs/super.c b/fs/hpfs/super.c index 501ea86e40a4..41232c2d60dc 100644 --- a/fs/hpfs/super.c +++ b/fs/hpfs/super.c | |||
| @@ -102,9 +102,12 @@ static void hpfs_put_super(struct super_block *s) | |||
| 102 | { | 102 | { |
| 103 | struct hpfs_sb_info *sbi = hpfs_sb(s); | 103 | struct hpfs_sb_info *sbi = hpfs_sb(s); |
| 104 | 104 | ||
| 105 | hpfs_lock(s); | ||
| 106 | unmark_dirty(s); | ||
| 107 | hpfs_unlock(s); | ||
| 108 | |||
| 105 | kfree(sbi->sb_cp_table); | 109 | kfree(sbi->sb_cp_table); |
| 106 | kfree(sbi->sb_bmp_dir); | 110 | kfree(sbi->sb_bmp_dir); |
| 107 | unmark_dirty(s); | ||
| 108 | s->s_fs_info = NULL; | 111 | s->s_fs_info = NULL; |
| 109 | kfree(sbi); | 112 | kfree(sbi); |
| 110 | } | 113 | } |
| @@ -490,6 +493,9 @@ static int hpfs_fill_super(struct super_block *s, void *options, int silent) | |||
| 490 | sbi->sb_bmp_dir = NULL; | 493 | sbi->sb_bmp_dir = NULL; |
| 491 | sbi->sb_cp_table = NULL; | 494 | sbi->sb_cp_table = NULL; |
| 492 | 495 | ||
| 496 | mutex_init(&sbi->hpfs_mutex); | ||
| 497 | hpfs_lock(s); | ||
| 498 | |||
| 493 | mutex_init(&sbi->hpfs_creation_de); | 499 | mutex_init(&sbi->hpfs_creation_de); |
| 494 | 500 | ||
| 495 | uid = current_uid(); | 501 | uid = current_uid(); |
| @@ -669,6 +675,7 @@ static int hpfs_fill_super(struct super_block *s, void *options, int silent) | |||
| 669 | root->i_blocks = 5; | 675 | root->i_blocks = 5; |
| 670 | hpfs_brelse4(&qbh); | 676 | hpfs_brelse4(&qbh); |
| 671 | } | 677 | } |
| 678 | hpfs_unlock(s); | ||
| 672 | return 0; | 679 | return 0; |
| 673 | 680 | ||
| 674 | bail4: brelse(bh2); | 681 | bail4: brelse(bh2); |
| @@ -676,6 +683,7 @@ bail3: brelse(bh1); | |||
| 676 | bail2: brelse(bh0); | 683 | bail2: brelse(bh0); |
| 677 | bail1: | 684 | bail1: |
| 678 | bail0: | 685 | bail0: |
| 686 | hpfs_unlock(s); | ||
| 679 | kfree(sbi->sb_bmp_dir); | 687 | kfree(sbi->sb_bmp_dir); |
| 680 | kfree(sbi->sb_cp_table); | 688 | kfree(sbi->sb_cp_table); |
| 681 | s->s_fs_info = NULL; | 689 | s->s_fs_info = NULL; |
