diff options
author | Alessio Igor Bogani <abogani@texware.it> | 2010-11-16 12:40:47 -0500 |
---|---|---|
committer | Jan Kara <jack@suse.cz> | 2011-01-06 11:03:56 -0500 |
commit | 4d0fb621d35007c19a396f2bb629e5aeaacef2d0 (patch) | |
tree | 92f6e0d3c38c15b0af507bd4b6d3353e34a337a9 /fs | |
parent | d1668fe390c1e84580575965684a8fa7e4626dee (diff) |
udf: Replace bkl with the UDF_I(inode)->i_data_sem for protect udf_inode_info struct
Replace bkl with the UDF_I(inode)->i_data_sem rw semaphore in
udf_release_file(), udf_symlink(), udf_symlink_filler(), udf_get_block(),
udf_block_map(), and udf_setattr(). The rule now is that any operation
on regular file's or symlink's extents (or generally allocation information
including goal block) needs to hold i_data_sem.
This work was supported by a hardware donation from the CE Linux Forum.
Signed-off-by: Alessio Igor Bogani <abogani@texware.it>
Signed-off-by: Jan Kara <jack@suse.cz>
Diffstat (limited to 'fs')
-rw-r--r-- | fs/udf/file.c | 4 | ||||
-rw-r--r-- | fs/udf/inode.c | 19 | ||||
-rw-r--r-- | fs/udf/namei.c | 7 | ||||
-rw-r--r-- | fs/udf/super.c | 1 | ||||
-rw-r--r-- | fs/udf/symlink.c | 12 | ||||
-rw-r--r-- | fs/udf/udf_i.h | 13 |
6 files changed, 37 insertions, 19 deletions
diff --git a/fs/udf/file.c b/fs/udf/file.c index 66b9e7e7e4c5..df0c5561cc7e 100644 --- a/fs/udf/file.c +++ b/fs/udf/file.c | |||
@@ -204,10 +204,10 @@ static int udf_release_file(struct inode *inode, struct file *filp) | |||
204 | { | 204 | { |
205 | if (filp->f_mode & FMODE_WRITE) { | 205 | if (filp->f_mode & FMODE_WRITE) { |
206 | mutex_lock(&inode->i_mutex); | 206 | mutex_lock(&inode->i_mutex); |
207 | lock_kernel(); | 207 | down_write(&UDF_I(inode)->i_data_sem); |
208 | udf_discard_prealloc(inode); | 208 | udf_discard_prealloc(inode); |
209 | udf_truncate_tail_extent(inode); | 209 | udf_truncate_tail_extent(inode); |
210 | unlock_kernel(); | 210 | up_write(&UDF_I(inode)->i_data_sem); |
211 | mutex_unlock(&inode->i_mutex); | 211 | mutex_unlock(&inode->i_mutex); |
212 | } | 212 | } |
213 | return 0; | 213 | return 0; |
diff --git a/fs/udf/inode.c b/fs/udf/inode.c index fa3c1541151c..b2fe4d7f20eb 100644 --- a/fs/udf/inode.c +++ b/fs/udf/inode.c | |||
@@ -301,10 +301,9 @@ static int udf_get_block(struct inode *inode, sector_t block, | |||
301 | err = -EIO; | 301 | err = -EIO; |
302 | new = 0; | 302 | new = 0; |
303 | bh = NULL; | 303 | bh = NULL; |
304 | |||
305 | lock_kernel(); | ||
306 | |||
307 | iinfo = UDF_I(inode); | 304 | iinfo = UDF_I(inode); |
305 | |||
306 | down_write(&iinfo->i_data_sem); | ||
308 | if (block == iinfo->i_next_alloc_block + 1) { | 307 | if (block == iinfo->i_next_alloc_block + 1) { |
309 | iinfo->i_next_alloc_block++; | 308 | iinfo->i_next_alloc_block++; |
310 | iinfo->i_next_alloc_goal++; | 309 | iinfo->i_next_alloc_goal++; |
@@ -323,7 +322,7 @@ static int udf_get_block(struct inode *inode, sector_t block, | |||
323 | map_bh(bh_result, inode->i_sb, phys); | 322 | map_bh(bh_result, inode->i_sb, phys); |
324 | 323 | ||
325 | abort: | 324 | abort: |
326 | unlock_kernel(); | 325 | up_write(&iinfo->i_data_sem); |
327 | return err; | 326 | return err; |
328 | } | 327 | } |
329 | 328 | ||
@@ -1021,16 +1020,16 @@ void udf_truncate(struct inode *inode) | |||
1021 | if (IS_APPEND(inode) || IS_IMMUTABLE(inode)) | 1020 | if (IS_APPEND(inode) || IS_IMMUTABLE(inode)) |
1022 | return; | 1021 | return; |
1023 | 1022 | ||
1024 | lock_kernel(); | ||
1025 | iinfo = UDF_I(inode); | 1023 | iinfo = UDF_I(inode); |
1026 | if (iinfo->i_alloc_type == ICBTAG_FLAG_AD_IN_ICB) { | 1024 | if (iinfo->i_alloc_type == ICBTAG_FLAG_AD_IN_ICB) { |
1025 | down_write(&iinfo->i_data_sem); | ||
1027 | if (inode->i_sb->s_blocksize < | 1026 | if (inode->i_sb->s_blocksize < |
1028 | (udf_file_entry_alloc_offset(inode) + | 1027 | (udf_file_entry_alloc_offset(inode) + |
1029 | inode->i_size)) { | 1028 | inode->i_size)) { |
1030 | udf_expand_file_adinicb(inode, inode->i_size, &err); | 1029 | udf_expand_file_adinicb(inode, inode->i_size, &err); |
1031 | if (iinfo->i_alloc_type == ICBTAG_FLAG_AD_IN_ICB) { | 1030 | if (iinfo->i_alloc_type == ICBTAG_FLAG_AD_IN_ICB) { |
1032 | inode->i_size = iinfo->i_lenAlloc; | 1031 | inode->i_size = iinfo->i_lenAlloc; |
1033 | unlock_kernel(); | 1032 | up_write(&iinfo->i_data_sem); |
1034 | return; | 1033 | return; |
1035 | } else | 1034 | } else |
1036 | udf_truncate_extents(inode); | 1035 | udf_truncate_extents(inode); |
@@ -1041,10 +1040,13 @@ void udf_truncate(struct inode *inode) | |||
1041 | offset - udf_file_entry_alloc_offset(inode)); | 1040 | offset - udf_file_entry_alloc_offset(inode)); |
1042 | iinfo->i_lenAlloc = inode->i_size; | 1041 | iinfo->i_lenAlloc = inode->i_size; |
1043 | } | 1042 | } |
1043 | up_write(&iinfo->i_data_sem); | ||
1044 | } else { | 1044 | } else { |
1045 | block_truncate_page(inode->i_mapping, inode->i_size, | 1045 | block_truncate_page(inode->i_mapping, inode->i_size, |
1046 | udf_get_block); | 1046 | udf_get_block); |
1047 | down_write(&iinfo->i_data_sem); | ||
1047 | udf_truncate_extents(inode); | 1048 | udf_truncate_extents(inode); |
1049 | up_write(&iinfo->i_data_sem); | ||
1048 | } | 1050 | } |
1049 | 1051 | ||
1050 | inode->i_mtime = inode->i_ctime = current_fs_time(inode->i_sb); | 1052 | inode->i_mtime = inode->i_ctime = current_fs_time(inode->i_sb); |
@@ -1052,7 +1054,6 @@ void udf_truncate(struct inode *inode) | |||
1052 | udf_sync_inode(inode); | 1054 | udf_sync_inode(inode); |
1053 | else | 1055 | else |
1054 | mark_inode_dirty(inode); | 1056 | mark_inode_dirty(inode); |
1055 | unlock_kernel(); | ||
1056 | } | 1057 | } |
1057 | 1058 | ||
1058 | static void __udf_read_inode(struct inode *inode) | 1059 | static void __udf_read_inode(struct inode *inode) |
@@ -2043,7 +2044,7 @@ long udf_block_map(struct inode *inode, sector_t block) | |||
2043 | struct extent_position epos = {}; | 2044 | struct extent_position epos = {}; |
2044 | int ret; | 2045 | int ret; |
2045 | 2046 | ||
2046 | lock_kernel(); | 2047 | down_read(&UDF_I(inode)->i_data_sem); |
2047 | 2048 | ||
2048 | if (inode_bmap(inode, block, &epos, &eloc, &elen, &offset) == | 2049 | if (inode_bmap(inode, block, &epos, &eloc, &elen, &offset) == |
2049 | (EXT_RECORDED_ALLOCATED >> 30)) | 2050 | (EXT_RECORDED_ALLOCATED >> 30)) |
@@ -2051,7 +2052,7 @@ long udf_block_map(struct inode *inode, sector_t block) | |||
2051 | else | 2052 | else |
2052 | ret = 0; | 2053 | ret = 0; |
2053 | 2054 | ||
2054 | unlock_kernel(); | 2055 | up_read(&UDF_I(inode)->i_data_sem); |
2055 | brelse(epos.bh); | 2056 | brelse(epos.bh); |
2056 | 2057 | ||
2057 | if (UDF_QUERY_FLAG(inode->i_sb, UDF_FLAG_VARCONV)) | 2058 | if (UDF_QUERY_FLAG(inode->i_sb, UDF_FLAG_VARCONV)) |
diff --git a/fs/udf/namei.c b/fs/udf/namei.c index 701fcda18415..d5eb000ddddd 100644 --- a/fs/udf/namei.c +++ b/fs/udf/namei.c | |||
@@ -893,18 +893,18 @@ static int udf_symlink(struct inode *dir, struct dentry *dentry, | |||
893 | struct udf_inode_info *iinfo; | 893 | struct udf_inode_info *iinfo; |
894 | struct super_block *sb = dir->i_sb; | 894 | struct super_block *sb = dir->i_sb; |
895 | 895 | ||
896 | lock_kernel(); | ||
897 | inode = udf_new_inode(dir, S_IFLNK | S_IRWXUGO, &err); | 896 | inode = udf_new_inode(dir, S_IFLNK | S_IRWXUGO, &err); |
898 | if (!inode) | 897 | if (!inode) |
899 | goto out; | 898 | goto out; |
900 | 899 | ||
900 | iinfo = UDF_I(inode); | ||
901 | down_write(&iinfo->i_data_sem); | ||
901 | name = kmalloc(UDF_NAME_LEN, GFP_NOFS); | 902 | name = kmalloc(UDF_NAME_LEN, GFP_NOFS); |
902 | if (!name) { | 903 | if (!name) { |
903 | err = -ENOMEM; | 904 | err = -ENOMEM; |
904 | goto out_no_entry; | 905 | goto out_no_entry; |
905 | } | 906 | } |
906 | 907 | ||
907 | iinfo = UDF_I(inode); | ||
908 | inode->i_data.a_ops = &udf_symlink_aops; | 908 | inode->i_data.a_ops = &udf_symlink_aops; |
909 | inode->i_op = &udf_symlink_inode_operations; | 909 | inode->i_op = &udf_symlink_inode_operations; |
910 | 910 | ||
@@ -1024,6 +1024,7 @@ static int udf_symlink(struct inode *dir, struct dentry *dentry, | |||
1024 | udf_write_fi(dir, &cfi, fi, &fibh, NULL, NULL); | 1024 | udf_write_fi(dir, &cfi, fi, &fibh, NULL, NULL); |
1025 | if (UDF_I(dir)->i_alloc_type == ICBTAG_FLAG_AD_IN_ICB) | 1025 | if (UDF_I(dir)->i_alloc_type == ICBTAG_FLAG_AD_IN_ICB) |
1026 | mark_inode_dirty(dir); | 1026 | mark_inode_dirty(dir); |
1027 | up_write(&iinfo->i_data_sem); | ||
1027 | if (fibh.sbh != fibh.ebh) | 1028 | if (fibh.sbh != fibh.ebh) |
1028 | brelse(fibh.ebh); | 1029 | brelse(fibh.ebh); |
1029 | brelse(fibh.sbh); | 1030 | brelse(fibh.sbh); |
@@ -1032,10 +1033,10 @@ static int udf_symlink(struct inode *dir, struct dentry *dentry, | |||
1032 | 1033 | ||
1033 | out: | 1034 | out: |
1034 | kfree(name); | 1035 | kfree(name); |
1035 | unlock_kernel(); | ||
1036 | return err; | 1036 | return err; |
1037 | 1037 | ||
1038 | out_no_entry: | 1038 | out_no_entry: |
1039 | up_write(&iinfo->i_data_sem); | ||
1039 | inode_dec_link_count(inode); | 1040 | inode_dec_link_count(inode); |
1040 | iput(inode); | 1041 | iput(inode); |
1041 | goto out; | 1042 | goto out; |
diff --git a/fs/udf/super.c b/fs/udf/super.c index d2ec9f31e843..441b892cf85e 100644 --- a/fs/udf/super.c +++ b/fs/udf/super.c | |||
@@ -135,6 +135,7 @@ static struct inode *udf_alloc_inode(struct super_block *sb) | |||
135 | ei->i_next_alloc_block = 0; | 135 | ei->i_next_alloc_block = 0; |
136 | ei->i_next_alloc_goal = 0; | 136 | ei->i_next_alloc_goal = 0; |
137 | ei->i_strat4096 = 0; | 137 | ei->i_strat4096 = 0; |
138 | init_rwsem(&ei->i_data_sem); | ||
138 | 139 | ||
139 | return &ei->vfs_inode; | 140 | return &ei->vfs_inode; |
140 | } | 141 | } |
diff --git a/fs/udf/symlink.c b/fs/udf/symlink.c index 16064787d2b7..b1d4488b0f14 100644 --- a/fs/udf/symlink.c +++ b/fs/udf/symlink.c | |||
@@ -27,7 +27,6 @@ | |||
27 | #include <linux/mm.h> | 27 | #include <linux/mm.h> |
28 | #include <linux/stat.h> | 28 | #include <linux/stat.h> |
29 | #include <linux/pagemap.h> | 29 | #include <linux/pagemap.h> |
30 | #include <linux/smp_lock.h> | ||
31 | #include <linux/buffer_head.h> | 30 | #include <linux/buffer_head.h> |
32 | #include "udf_i.h" | 31 | #include "udf_i.h" |
33 | 32 | ||
@@ -78,13 +77,16 @@ static int udf_symlink_filler(struct file *file, struct page *page) | |||
78 | int err = -EIO; | 77 | int err = -EIO; |
79 | unsigned char *p = kmap(page); | 78 | unsigned char *p = kmap(page); |
80 | struct udf_inode_info *iinfo; | 79 | struct udf_inode_info *iinfo; |
80 | uint32_t pos; | ||
81 | 81 | ||
82 | lock_kernel(); | ||
83 | iinfo = UDF_I(inode); | 82 | iinfo = UDF_I(inode); |
83 | pos = udf_block_map(inode, 0); | ||
84 | |||
85 | down_read(&iinfo->i_data_sem); | ||
84 | if (iinfo->i_alloc_type == ICBTAG_FLAG_AD_IN_ICB) { | 86 | if (iinfo->i_alloc_type == ICBTAG_FLAG_AD_IN_ICB) { |
85 | symlink = iinfo->i_ext.i_data + iinfo->i_lenEAttr; | 87 | symlink = iinfo->i_ext.i_data + iinfo->i_lenEAttr; |
86 | } else { | 88 | } else { |
87 | bh = sb_bread(inode->i_sb, udf_block_map(inode, 0)); | 89 | bh = sb_bread(inode->i_sb, pos); |
88 | 90 | ||
89 | if (!bh) | 91 | if (!bh) |
90 | goto out; | 92 | goto out; |
@@ -95,14 +97,14 @@ static int udf_symlink_filler(struct file *file, struct page *page) | |||
95 | udf_pc_to_char(inode->i_sb, symlink, inode->i_size, p); | 97 | udf_pc_to_char(inode->i_sb, symlink, inode->i_size, p); |
96 | brelse(bh); | 98 | brelse(bh); |
97 | 99 | ||
98 | unlock_kernel(); | 100 | up_read(&iinfo->i_data_sem); |
99 | SetPageUptodate(page); | 101 | SetPageUptodate(page); |
100 | kunmap(page); | 102 | kunmap(page); |
101 | unlock_page(page); | 103 | unlock_page(page); |
102 | return 0; | 104 | return 0; |
103 | 105 | ||
104 | out: | 106 | out: |
105 | unlock_kernel(); | 107 | up_read(&iinfo->i_data_sem); |
106 | SetPageError(page); | 108 | SetPageError(page); |
107 | kunmap(page); | 109 | kunmap(page); |
108 | unlock_page(page); | 110 | unlock_page(page); |
diff --git a/fs/udf/udf_i.h b/fs/udf/udf_i.h index e58d1de41073..d1bd31ea724e 100644 --- a/fs/udf/udf_i.h +++ b/fs/udf/udf_i.h | |||
@@ -1,6 +1,18 @@ | |||
1 | #ifndef _UDF_I_H | 1 | #ifndef _UDF_I_H |
2 | #define _UDF_I_H | 2 | #define _UDF_I_H |
3 | 3 | ||
4 | /* | ||
5 | * The i_data_sem and i_mutex serve for protection of allocation information | ||
6 | * of a regular files and symlinks. This includes all extents belonging to | ||
7 | * the file/symlink, a fact whether data are in-inode or in external data | ||
8 | * blocks, preallocation, goal block information... When extents are read, | ||
9 | * i_mutex or i_data_sem must be held (for reading is enough in case of | ||
10 | * i_data_sem). When extents are changed, i_data_sem must be held for writing | ||
11 | * and also i_mutex must be held. | ||
12 | * | ||
13 | * For directories i_mutex is used for all the necessary protection. | ||
14 | */ | ||
15 | |||
4 | struct udf_inode_info { | 16 | struct udf_inode_info { |
5 | struct timespec i_crtime; | 17 | struct timespec i_crtime; |
6 | /* Physical address of inode */ | 18 | /* Physical address of inode */ |
@@ -21,6 +33,7 @@ struct udf_inode_info { | |||
21 | struct long_ad *i_lad; | 33 | struct long_ad *i_lad; |
22 | __u8 *i_data; | 34 | __u8 *i_data; |
23 | } i_ext; | 35 | } i_ext; |
36 | struct rw_semaphore i_data_sem; | ||
24 | struct inode vfs_inode; | 37 | struct inode vfs_inode; |
25 | }; | 38 | }; |
26 | 39 | ||