diff options
author | Christoph Hellwig <hch@tuxera.com> | 2010-09-30 23:46:31 -0400 |
---|---|---|
committer | Christoph Hellwig <hch@lst.de> | 2010-09-30 23:46:31 -0400 |
commit | 7fcc99f4f2ddb1c39abc05fbb9b32f05b03c7f8f (patch) | |
tree | b07045981f17d855f89f1ef59579e330d8ffce20 /fs/hfsplus | |
parent | 89755dcace09b44b3aa024bf302d9b19b4c24cad (diff) |
hfsplus: add missing extent locking in hfsplus_write_inode
Most of the extent handling code already does proper SMP locking, but
hfsplus_write_inode was calling into hfsplus_ext_write_extent without
taking the extents_lock. Fix this by splitting hfsplus_ext_write_extent
into an internal helper that expects the lock, and a public interface
that first acquires it.
Also add a few locking asserts and document the locking rules in
hfsplus_fs.h.
Signed-off-by: Christoph Hellwig <hch@tuxera.com>
Diffstat (limited to 'fs/hfsplus')
-rw-r--r-- | fs/hfsplus/extents.c | 15 | ||||
-rw-r--r-- | fs/hfsplus/hfsplus_fs.h | 34 |
2 files changed, 34 insertions, 15 deletions
diff --git a/fs/hfsplus/extents.c b/fs/hfsplus/extents.c index b1017eaa4fdc..0c9cb1820a52 100644 --- a/fs/hfsplus/extents.c +++ b/fs/hfsplus/extents.c | |||
@@ -88,6 +88,8 @@ static void __hfsplus_ext_write_extent(struct inode *inode, struct hfs_find_data | |||
88 | struct hfsplus_inode_info *hip = HFSPLUS_I(inode); | 88 | struct hfsplus_inode_info *hip = HFSPLUS_I(inode); |
89 | int res; | 89 | int res; |
90 | 90 | ||
91 | WARN_ON(!mutex_is_locked(&hip->extents_lock)); | ||
92 | |||
91 | hfsplus_ext_build_key(fd->search_key, inode->i_ino, hip->cached_start, | 93 | hfsplus_ext_build_key(fd->search_key, inode->i_ino, hip->cached_start, |
92 | HFSPLUS_IS_RSRC(inode) ? | 94 | HFSPLUS_IS_RSRC(inode) ? |
93 | HFSPLUS_TYPE_RSRC : HFSPLUS_TYPE_DATA); | 95 | HFSPLUS_TYPE_RSRC : HFSPLUS_TYPE_DATA); |
@@ -108,7 +110,7 @@ static void __hfsplus_ext_write_extent(struct inode *inode, struct hfs_find_data | |||
108 | } | 110 | } |
109 | } | 111 | } |
110 | 112 | ||
111 | void hfsplus_ext_write_extent(struct inode *inode) | 113 | static void hfsplus_ext_write_extent_locked(struct inode *inode) |
112 | { | 114 | { |
113 | if (HFSPLUS_I(inode)->flags & HFSPLUS_FLG_EXT_DIRTY) { | 115 | if (HFSPLUS_I(inode)->flags & HFSPLUS_FLG_EXT_DIRTY) { |
114 | struct hfs_find_data fd; | 116 | struct hfs_find_data fd; |
@@ -119,6 +121,13 @@ void hfsplus_ext_write_extent(struct inode *inode) | |||
119 | } | 121 | } |
120 | } | 122 | } |
121 | 123 | ||
124 | void hfsplus_ext_write_extent(struct inode *inode) | ||
125 | { | ||
126 | mutex_lock(&HFSPLUS_I(inode)->extents_lock); | ||
127 | hfsplus_ext_write_extent_locked(inode); | ||
128 | mutex_unlock(&HFSPLUS_I(inode)->extents_lock); | ||
129 | } | ||
130 | |||
122 | static inline int __hfsplus_ext_read_extent(struct hfs_find_data *fd, | 131 | static inline int __hfsplus_ext_read_extent(struct hfs_find_data *fd, |
123 | struct hfsplus_extent *extent, | 132 | struct hfsplus_extent *extent, |
124 | u32 cnid, u32 block, u8 type) | 133 | u32 cnid, u32 block, u8 type) |
@@ -144,6 +153,8 @@ static inline int __hfsplus_ext_cache_extent(struct hfs_find_data *fd, struct in | |||
144 | struct hfsplus_inode_info *hip = HFSPLUS_I(inode); | 153 | struct hfsplus_inode_info *hip = HFSPLUS_I(inode); |
145 | int res; | 154 | int res; |
146 | 155 | ||
156 | WARN_ON(!mutex_is_locked(&hip->extents_lock)); | ||
157 | |||
147 | if (hip->flags & HFSPLUS_FLG_EXT_DIRTY) | 158 | if (hip->flags & HFSPLUS_FLG_EXT_DIRTY) |
148 | __hfsplus_ext_write_extent(inode, fd); | 159 | __hfsplus_ext_write_extent(inode, fd); |
149 | 160 | ||
@@ -433,7 +444,7 @@ out: | |||
433 | 444 | ||
434 | insert_extent: | 445 | insert_extent: |
435 | dprint(DBG_EXTENT, "insert new extent\n"); | 446 | dprint(DBG_EXTENT, "insert new extent\n"); |
436 | hfsplus_ext_write_extent(inode); | 447 | hfsplus_ext_write_extent_locked(inode); |
437 | 448 | ||
438 | memset(hip->cached_extents, 0, sizeof(hfsplus_extent_rec)); | 449 | memset(hip->cached_extents, 0, sizeof(hfsplus_extent_rec)); |
439 | hip->cached_extents[0].start_block = cpu_to_be32(start); | 450 | hip->cached_extents[0].start_block = cpu_to_be32(start); |
diff --git a/fs/hfsplus/hfsplus_fs.h b/fs/hfsplus/hfsplus_fs.h index c521d44f0747..c007cc201279 100644 --- a/fs/hfsplus/hfsplus_fs.h +++ b/fs/hfsplus/hfsplus_fs.h | |||
@@ -158,28 +158,36 @@ struct hfsplus_sb_info { | |||
158 | 158 | ||
159 | 159 | ||
160 | struct hfsplus_inode_info { | 160 | struct hfsplus_inode_info { |
161 | struct mutex extents_lock; | ||
162 | u32 clump_blocks, alloc_blocks; | ||
163 | sector_t fs_blocks; | ||
164 | /* Allocation extents from catalog record or volume header */ | ||
165 | hfsplus_extent_rec first_extents; | ||
166 | u32 first_blocks; | ||
167 | hfsplus_extent_rec cached_extents; | ||
168 | u32 cached_start, cached_blocks; | ||
169 | atomic_t opencnt; | 161 | atomic_t opencnt; |
170 | 162 | ||
171 | struct inode *rsrc_inode; | 163 | /* |
164 | * Extent allocation information, protected by extents_lock. | ||
165 | */ | ||
166 | u32 first_blocks; | ||
167 | u32 clump_blocks; | ||
168 | u32 alloc_blocks; | ||
169 | u32 cached_start; | ||
170 | u32 cached_blocks; | ||
171 | hfsplus_extent_rec first_extents; | ||
172 | hfsplus_extent_rec cached_extents; | ||
172 | unsigned long flags; | 173 | unsigned long flags; |
174 | struct mutex extents_lock; | ||
173 | 175 | ||
176 | /* | ||
177 | * Immutable data. | ||
178 | */ | ||
179 | struct inode *rsrc_inode; | ||
174 | __be32 create_date; | 180 | __be32 create_date; |
175 | /* Device number in hfsplus_permissions in catalog */ | ||
176 | u32 dev; | 181 | u32 dev; |
177 | /* BSD system and user file flags */ | ||
178 | u8 rootflags; | ||
179 | u8 userflags; | ||
180 | 182 | ||
183 | /* | ||
184 | * Protected by i_mutex. | ||
185 | */ | ||
186 | sector_t fs_blocks; | ||
187 | u8 rootflags, userflags; /* BSD system and user file flags */ | ||
181 | struct list_head open_dir_list; | 188 | struct list_head open_dir_list; |
182 | loff_t phys_size; | 189 | loff_t phys_size; |
190 | |||
183 | struct inode vfs_inode; | 191 | struct inode vfs_inode; |
184 | }; | 192 | }; |
185 | 193 | ||