aboutsummaryrefslogtreecommitdiffstats
path: root/fs/hfsplus
diff options
context:
space:
mode:
authorChristoph Hellwig <hch@tuxera.com>2010-09-30 23:45:08 -0400
committerChristoph Hellwig <hch@lst.de>2010-09-30 23:45:08 -0400
commit7ac9fb9c2a50963b699b3548e6f00698c1554dc6 (patch)
tree3660bfb2985c65838b5969694e54043ae6639b3a /fs/hfsplus
parent58a818f532e83f337689358c102ba2048d1b37f5 (diff)
hfsplus: add per-superblock lock for volume header updates
Lock updates to the mutal fields in the volume header, and document the locing in the hfsplus_sb_info structure. Signed-off-by: Christoph Hellwig <hch@tuxera.com>
Diffstat (limited to 'fs/hfsplus')
-rw-r--r--fs/hfsplus/dir.c54
-rw-r--r--fs/hfsplus/hfsplus_fs.h13
-rw-r--r--fs/hfsplus/super.c7
3 files changed, 50 insertions, 24 deletions
diff --git a/fs/hfsplus/dir.c b/fs/hfsplus/dir.c
index f8ae468f4ab6..1c81eedcab01 100644
--- a/fs/hfsplus/dir.c
+++ b/fs/hfsplus/dir.c
@@ -251,6 +251,7 @@ static int hfsplus_link(struct dentry *src_dentry, struct inode *dst_dir,
251 if (HFSPLUS_IS_RSRC(inode)) 251 if (HFSPLUS_IS_RSRC(inode))
252 return -EPERM; 252 return -EPERM;
253 253
254 mutex_lock(&sbi->vh_mutex);
254 if (inode->i_ino == (u32)(unsigned long)src_dentry->d_fsdata) { 255 if (inode->i_ino == (u32)(unsigned long)src_dentry->d_fsdata) {
255 for (;;) { 256 for (;;) {
256 get_random_bytes(&id, sizeof(cnid)); 257 get_random_bytes(&id, sizeof(cnid));
@@ -263,7 +264,7 @@ static int hfsplus_link(struct dentry *src_dentry, struct inode *dst_dir,
263 if (!res) 264 if (!res)
264 break; 265 break;
265 if (res != -EEXIST) 266 if (res != -EEXIST)
266 return res; 267 goto out;
267 } 268 }
268 HFSPLUS_I(inode)->dev = id; 269 HFSPLUS_I(inode)->dev = id;
269 cnid = sbi->next_cnid++; 270 cnid = sbi->next_cnid++;
@@ -271,13 +272,13 @@ static int hfsplus_link(struct dentry *src_dentry, struct inode *dst_dir,
271 res = hfsplus_create_cat(cnid, src_dir, &src_dentry->d_name, inode); 272 res = hfsplus_create_cat(cnid, src_dir, &src_dentry->d_name, inode);
272 if (res) 273 if (res)
273 /* panic? */ 274 /* panic? */
274 return res; 275 goto out;
275 sbi->file_count++; 276 sbi->file_count++;
276 } 277 }
277 cnid = sbi->next_cnid++; 278 cnid = sbi->next_cnid++;
278 res = hfsplus_create_cat(cnid, dst_dir, &dst_dentry->d_name, inode); 279 res = hfsplus_create_cat(cnid, dst_dir, &dst_dentry->d_name, inode);
279 if (res) 280 if (res)
280 return res; 281 goto out;
281 282
282 inc_nlink(inode); 283 inc_nlink(inode);
283 hfsplus_instantiate(dst_dentry, inode, cnid); 284 hfsplus_instantiate(dst_dentry, inode, cnid);
@@ -286,8 +287,9 @@ static int hfsplus_link(struct dentry *src_dentry, struct inode *dst_dir,
286 mark_inode_dirty(inode); 287 mark_inode_dirty(inode);
287 sbi->file_count++; 288 sbi->file_count++;
288 dst_dir->i_sb->s_dirt = 1; 289 dst_dir->i_sb->s_dirt = 1;
289 290out:
290 return 0; 291 mutex_unlock(&sbi->vh_mutex);
292 return res;
291} 293}
292 294
293static int hfsplus_unlink(struct inode *dir, struct dentry *dentry) 295static int hfsplus_unlink(struct inode *dir, struct dentry *dentry)
@@ -302,6 +304,7 @@ static int hfsplus_unlink(struct inode *dir, struct dentry *dentry)
302 if (HFSPLUS_IS_RSRC(inode)) 304 if (HFSPLUS_IS_RSRC(inode))
303 return -EPERM; 305 return -EPERM;
304 306
307 mutex_lock(&sbi->vh_mutex);
305 cnid = (u32)(unsigned long)dentry->d_fsdata; 308 cnid = (u32)(unsigned long)dentry->d_fsdata;
306 if (inode->i_ino == cnid && 309 if (inode->i_ino == cnid &&
307 atomic_read(&HFSPLUS_I(inode)->opencnt)) { 310 atomic_read(&HFSPLUS_I(inode)->opencnt)) {
@@ -312,11 +315,11 @@ static int hfsplus_unlink(struct inode *dir, struct dentry *dentry)
312 sbi->hidden_dir, &str); 315 sbi->hidden_dir, &str);
313 if (!res) 316 if (!res)
314 inode->i_flags |= S_DEAD; 317 inode->i_flags |= S_DEAD;
315 return res; 318 goto out;
316 } 319 }
317 res = hfsplus_delete_cat(cnid, dir, &dentry->d_name); 320 res = hfsplus_delete_cat(cnid, dir, &dentry->d_name);
318 if (res) 321 if (res)
319 return res; 322 goto out;
320 323
321 if (inode->i_nlink > 0) 324 if (inode->i_nlink > 0)
322 drop_nlink(inode); 325 drop_nlink(inode);
@@ -339,37 +342,44 @@ static int hfsplus_unlink(struct inode *dir, struct dentry *dentry)
339 sbi->file_count--; 342 sbi->file_count--;
340 inode->i_ctime = CURRENT_TIME_SEC; 343 inode->i_ctime = CURRENT_TIME_SEC;
341 mark_inode_dirty(inode); 344 mark_inode_dirty(inode);
342 345out:
346 mutex_unlock(&sbi->vh_mutex);
343 return res; 347 return res;
344} 348}
345 349
346static int hfsplus_rmdir(struct inode *dir, struct dentry *dentry) 350static int hfsplus_rmdir(struct inode *dir, struct dentry *dentry)
347{ 351{
348 struct inode *inode; 352 struct hfsplus_sb_info *sbi = HFSPLUS_SB(dir->i_sb);
353 struct inode *inode = dentry->d_inode;
349 int res; 354 int res;
350 355
351 inode = dentry->d_inode;
352 if (inode->i_size != 2) 356 if (inode->i_size != 2)
353 return -ENOTEMPTY; 357 return -ENOTEMPTY;
358
359 mutex_lock(&sbi->vh_mutex);
354 res = hfsplus_delete_cat(inode->i_ino, dir, &dentry->d_name); 360 res = hfsplus_delete_cat(inode->i_ino, dir, &dentry->d_name);
355 if (res) 361 if (res)
356 return res; 362 goto out;
357 clear_nlink(inode); 363 clear_nlink(inode);
358 inode->i_ctime = CURRENT_TIME_SEC; 364 inode->i_ctime = CURRENT_TIME_SEC;
359 hfsplus_delete_inode(inode); 365 hfsplus_delete_inode(inode);
360 mark_inode_dirty(inode); 366 mark_inode_dirty(inode);
361 return 0; 367out:
368 mutex_unlock(&sbi->vh_mutex);
369 return res;
362} 370}
363 371
364static int hfsplus_symlink(struct inode *dir, struct dentry *dentry, 372static int hfsplus_symlink(struct inode *dir, struct dentry *dentry,
365 const char *symname) 373 const char *symname)
366{ 374{
375 struct hfsplus_sb_info *sbi = HFSPLUS_SB(dir->i_sb);
367 struct inode *inode; 376 struct inode *inode;
368 int res; 377 int res = -ENOSPC;
369 378
379 mutex_lock(&sbi->vh_mutex);
370 inode = hfsplus_new_inode(dir->i_sb, S_IFLNK | S_IRWXUGO); 380 inode = hfsplus_new_inode(dir->i_sb, S_IFLNK | S_IRWXUGO);
371 if (!inode) 381 if (!inode)
372 return -ENOSPC; 382 goto out;
373 383
374 res = page_symlink(inode, symname, strlen(symname) + 1); 384 res = page_symlink(inode, symname, strlen(symname) + 1);
375 if (res) 385 if (res)
@@ -381,31 +391,35 @@ static int hfsplus_symlink(struct inode *dir, struct dentry *dentry,
381 391
382 hfsplus_instantiate(dentry, inode, inode->i_ino); 392 hfsplus_instantiate(dentry, inode, inode->i_ino);
383 mark_inode_dirty(inode); 393 mark_inode_dirty(inode);
384 return 0; 394 goto out;
385 395
386out_err: 396out_err:
387 inode->i_nlink = 0; 397 inode->i_nlink = 0;
388 hfsplus_delete_inode(inode); 398 hfsplus_delete_inode(inode);
389 iput(inode); 399 iput(inode);
400out:
401 mutex_unlock(&sbi->vh_mutex);
390 return res; 402 return res;
391} 403}
392 404
393static int hfsplus_mknod(struct inode *dir, struct dentry *dentry, 405static int hfsplus_mknod(struct inode *dir, struct dentry *dentry,
394 int mode, dev_t rdev) 406 int mode, dev_t rdev)
395{ 407{
408 struct hfsplus_sb_info *sbi = HFSPLUS_SB(dir->i_sb);
396 struct inode *inode; 409 struct inode *inode;
397 int res; 410 int res = -ENOSPC;
398 411
412 mutex_lock(&sbi->vh_mutex);
399 inode = hfsplus_new_inode(dir->i_sb, mode); 413 inode = hfsplus_new_inode(dir->i_sb, mode);
400 if (!inode) 414 if (!inode)
401 return -ENOSPC; 415 goto out;
402 416
403 res = hfsplus_create_cat(inode->i_ino, dir, &dentry->d_name, inode); 417 res = hfsplus_create_cat(inode->i_ino, dir, &dentry->d_name, inode);
404 if (res) { 418 if (res) {
405 inode->i_nlink = 0; 419 inode->i_nlink = 0;
406 hfsplus_delete_inode(inode); 420 hfsplus_delete_inode(inode);
407 iput(inode); 421 iput(inode);
408 return res; 422 goto out;
409 } 423 }
410 424
411 if (S_ISBLK(mode) || S_ISCHR(mode) || S_ISFIFO(mode) || S_ISSOCK(mode)) 425 if (S_ISBLK(mode) || S_ISCHR(mode) || S_ISFIFO(mode) || S_ISSOCK(mode))
@@ -413,7 +427,9 @@ static int hfsplus_mknod(struct inode *dir, struct dentry *dentry,
413 427
414 hfsplus_instantiate(dentry, inode, inode->i_ino); 428 hfsplus_instantiate(dentry, inode, inode->i_ino);
415 mark_inode_dirty(inode); 429 mark_inode_dirty(inode);
416 return 0; 430out:
431 mutex_unlock(&sbi->vh_mutex);
432 return res;
417} 433}
418 434
419static int hfsplus_create(struct inode *dir, struct dentry *dentry, int mode, 435static int hfsplus_create(struct inode *dir, struct dentry *dentry, int mode,
diff --git a/fs/hfsplus/hfsplus_fs.h b/fs/hfsplus/hfsplus_fs.h
index 0cd9ba00f968..08865ed70f00 100644
--- a/fs/hfsplus/hfsplus_fs.h
+++ b/fs/hfsplus/hfsplus_fs.h
@@ -116,23 +116,26 @@ struct hfsplus_sb_info {
116 struct inode *hidden_dir; 116 struct inode *hidden_dir;
117 struct nls_table *nls; 117 struct nls_table *nls;
118 118
119 /* synchronize block allocations */
120 struct mutex alloc_mutex;
121
122 /* Runtime variables */ 119 /* Runtime variables */
123 u32 blockoffset; 120 u32 blockoffset;
124 u32 sect_count; 121 u32 sect_count;
125 int fs_shift; 122 int fs_shift;
126 123
127 /* Stuff in host order from Vol Header */ 124 /* immutable data from the volume header */
128 u32 alloc_blksz; 125 u32 alloc_blksz;
129 int alloc_blksz_shift; 126 int alloc_blksz_shift;
130 u32 total_blocks; 127 u32 total_blocks;
128 u32 data_clump_blocks, rsrc_clump_blocks;
129
130 /* mutable data from the volume header, protected by alloc_mutex */
131 u32 free_blocks; 131 u32 free_blocks;
132 struct mutex alloc_mutex;
133
134 /* mutable data from the volume header, protected by vh_mutex */
132 u32 next_cnid; 135 u32 next_cnid;
133 u32 file_count; 136 u32 file_count;
134 u32 folder_count; 137 u32 folder_count;
135 u32 data_clump_blocks, rsrc_clump_blocks; 138 struct mutex vh_mutex;
136 139
137 /* Config options */ 140 /* Config options */
138 u32 creator; 141 u32 creator;
diff --git a/fs/hfsplus/super.c b/fs/hfsplus/super.c
index 923f385b32ca..b766c170e4d8 100644
--- a/fs/hfsplus/super.c
+++ b/fs/hfsplus/super.c
@@ -160,6 +160,7 @@ int hfsplus_sync_fs(struct super_block *sb, int wait)
160 160
161 dprint(DBG_SUPER, "hfsplus_write_super\n"); 161 dprint(DBG_SUPER, "hfsplus_write_super\n");
162 162
163 mutex_lock(&sbi->vh_mutex);
163 mutex_lock(&sbi->alloc_mutex); 164 mutex_lock(&sbi->alloc_mutex);
164 sb->s_dirt = 0; 165 sb->s_dirt = 0;
165 166
@@ -194,6 +195,7 @@ int hfsplus_sync_fs(struct super_block *sb, int wait)
194 sbi->flags &= ~HFSPLUS_SB_WRITEBACKUP; 195 sbi->flags &= ~HFSPLUS_SB_WRITEBACKUP;
195 } 196 }
196 mutex_unlock(&sbi->alloc_mutex); 197 mutex_unlock(&sbi->alloc_mutex);
198 mutex_unlock(&sbi->vh_mutex);
197 return 0; 199 return 0;
198} 200}
199 201
@@ -319,6 +321,7 @@ static int hfsplus_fill_super(struct super_block *sb, void *data, int silent)
319 321
320 sb->s_fs_info = sbi; 322 sb->s_fs_info = sbi;
321 mutex_init(&sbi->alloc_mutex); 323 mutex_init(&sbi->alloc_mutex);
324 mutex_init(&sbi->vh_mutex);
322 hfsplus_fill_defaults(sbi); 325 hfsplus_fill_defaults(sbi);
323 if (!hfsplus_parse_options(data, sbi)) { 326 if (!hfsplus_parse_options(data, sbi)) {
324 printk(KERN_ERR "hfs: unable to parse mount options\n"); 327 printk(KERN_ERR "hfs: unable to parse mount options\n");
@@ -453,9 +456,13 @@ static int hfsplus_fill_super(struct super_block *sb, void *data, int silent)
453 456
454 if (!sbi->hidden_dir) { 457 if (!sbi->hidden_dir) {
455 printk(KERN_DEBUG "hfs: create hidden dir...\n"); 458 printk(KERN_DEBUG "hfs: create hidden dir...\n");
459
460 mutex_lock(&sbi->vh_mutex);
456 sbi->hidden_dir = hfsplus_new_inode(sb, S_IFDIR); 461 sbi->hidden_dir = hfsplus_new_inode(sb, S_IFDIR);
457 hfsplus_create_cat(sbi->hidden_dir->i_ino, sb->s_root->d_inode, 462 hfsplus_create_cat(sbi->hidden_dir->i_ino, sb->s_root->d_inode,
458 &str, sbi->hidden_dir); 463 &str, sbi->hidden_dir);
464 mutex_unlock(&sbi->vh_mutex);
465
459 mark_inode_dirty(sbi->hidden_dir); 466 mark_inode_dirty(sbi->hidden_dir);
460 } 467 }
461out: 468out: