diff options
author | Christoph Hellwig <hch@tuxera.com> | 2010-09-30 23:45:08 -0400 |
---|---|---|
committer | Christoph Hellwig <hch@lst.de> | 2010-09-30 23:45:08 -0400 |
commit | 7ac9fb9c2a50963b699b3548e6f00698c1554dc6 (patch) | |
tree | 3660bfb2985c65838b5969694e54043ae6639b3a /fs/hfsplus/dir.c | |
parent | 58a818f532e83f337689358c102ba2048d1b37f5 (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/dir.c')
-rw-r--r-- | fs/hfsplus/dir.c | 54 |
1 files changed, 35 insertions, 19 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 | 290 | out: | |
290 | return 0; | 291 | mutex_unlock(&sbi->vh_mutex); |
292 | return res; | ||
291 | } | 293 | } |
292 | 294 | ||
293 | static int hfsplus_unlink(struct inode *dir, struct dentry *dentry) | 295 | static 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 | 345 | out: | |
346 | mutex_unlock(&sbi->vh_mutex); | ||
343 | return res; | 347 | return res; |
344 | } | 348 | } |
345 | 349 | ||
346 | static int hfsplus_rmdir(struct inode *dir, struct dentry *dentry) | 350 | static 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; | 367 | out: |
368 | mutex_unlock(&sbi->vh_mutex); | ||
369 | return res; | ||
362 | } | 370 | } |
363 | 371 | ||
364 | static int hfsplus_symlink(struct inode *dir, struct dentry *dentry, | 372 | static 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 | ||
386 | out_err: | 396 | out_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); |
400 | out: | ||
401 | mutex_unlock(&sbi->vh_mutex); | ||
390 | return res; | 402 | return res; |
391 | } | 403 | } |
392 | 404 | ||
393 | static int hfsplus_mknod(struct inode *dir, struct dentry *dentry, | 405 | static 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; | 430 | out: |
431 | mutex_unlock(&sbi->vh_mutex); | ||
432 | return res; | ||
417 | } | 433 | } |
418 | 434 | ||
419 | static int hfsplus_create(struct inode *dir, struct dentry *dentry, int mode, | 435 | static int hfsplus_create(struct inode *dir, struct dentry *dentry, int mode, |