aboutsummaryrefslogtreecommitdiffstats
path: root/fs/reiserfs/xattr_acl.c
diff options
context:
space:
mode:
authorJeff Mahoney <jeffm@suse.com>2009-03-30 14:02:39 -0400
committerLinus Torvalds <torvalds@linux-foundation.org>2009-03-30 15:16:38 -0400
commit0ab2621ebd9a28bf7a524ecd50d492a10579dfcc (patch)
tree62dda6de2fed116aff363190f95a58d56c690e3e /fs/reiserfs/xattr_acl.c
parent48b32a3553a54740d236b79a90f20147a25875e3 (diff)
reiserfs: journaled xattrs
Deadlocks are possible in the xattr code between the journal lock and the xattr sems. This patch implements journalling for xattr operations. The benefit is twofold: * It gets rid of the deadlock possibility by always ensuring that xattr write operations are initiated inside a transaction. * It corrects the problem where xattr backing files aren't considered any differently than normal files, despite the fact they are metadata. I discussed the added journal load with Chris Mason, and we decided that since xattrs (versus other journal activity) is fairly rare, the introduction of larger transactions to support journaled xattrs wouldn't be too big a deal. Signed-off-by: Jeff Mahoney <jeffm@suse.com> Signed-off-by: Linus Torvalds <torvalds@linux-foundation.org>
Diffstat (limited to 'fs/reiserfs/xattr_acl.c')
-rw-r--r--fs/reiserfs/xattr_acl.c105
1 files changed, 81 insertions, 24 deletions
diff --git a/fs/reiserfs/xattr_acl.c b/fs/reiserfs/xattr_acl.c
index bfecf7553002..d423416d93d1 100644
--- a/fs/reiserfs/xattr_acl.c
+++ b/fs/reiserfs/xattr_acl.c
@@ -10,15 +10,17 @@
10#include <linux/reiserfs_acl.h> 10#include <linux/reiserfs_acl.h>
11#include <asm/uaccess.h> 11#include <asm/uaccess.h>
12 12
13static int reiserfs_set_acl(struct inode *inode, int type, 13static int reiserfs_set_acl(struct reiserfs_transaction_handle *th,
14 struct inode *inode, int type,
14 struct posix_acl *acl); 15 struct posix_acl *acl);
15 16
16static int 17static int
17xattr_set_acl(struct inode *inode, int type, const void *value, size_t size) 18xattr_set_acl(struct inode *inode, int type, const void *value, size_t size)
18{ 19{
19 struct posix_acl *acl; 20 struct posix_acl *acl;
20 int error; 21 int error, error2;
21 22 struct reiserfs_transaction_handle th;
23 size_t jcreate_blocks;
22 if (!reiserfs_posixacl(inode->i_sb)) 24 if (!reiserfs_posixacl(inode->i_sb))
23 return -EOPNOTSUPP; 25 return -EOPNOTSUPP;
24 if (!is_owner_or_cap(inode)) 26 if (!is_owner_or_cap(inode))
@@ -36,7 +38,21 @@ xattr_set_acl(struct inode *inode, int type, const void *value, size_t size)
36 } else 38 } else
37 acl = NULL; 39 acl = NULL;
38 40
39 error = reiserfs_set_acl(inode, type, acl); 41 /* Pessimism: We can't assume that anything from the xattr root up
42 * has been created. */
43
44 jcreate_blocks = reiserfs_xattr_jcreate_nblocks(inode) +
45 reiserfs_xattr_nblocks(inode, size) * 2;
46
47 reiserfs_write_lock(inode->i_sb);
48 error = journal_begin(&th, inode->i_sb, jcreate_blocks);
49 if (error == 0) {
50 error = reiserfs_set_acl(&th, inode, type, acl);
51 error2 = journal_end(&th, inode->i_sb, jcreate_blocks);
52 if (error2)
53 error = error2;
54 }
55 reiserfs_write_unlock(inode->i_sb);
40 56
41 release_and_out: 57 release_and_out:
42 posix_acl_release(acl); 58 posix_acl_release(acl);
@@ -266,7 +282,8 @@ struct posix_acl *reiserfs_get_acl(struct inode *inode, int type)
266 * BKL held [before 2.5.x] 282 * BKL held [before 2.5.x]
267 */ 283 */
268static int 284static int
269reiserfs_set_acl(struct inode *inode, int type, struct posix_acl *acl) 285reiserfs_set_acl(struct reiserfs_transaction_handle *th, struct inode *inode,
286 int type, struct posix_acl *acl)
270{ 287{
271 char *name; 288 char *name;
272 void *value = NULL; 289 void *value = NULL;
@@ -310,7 +327,7 @@ reiserfs_set_acl(struct inode *inode, int type, struct posix_acl *acl)
310 return (int)PTR_ERR(value); 327 return (int)PTR_ERR(value);
311 } 328 }
312 329
313 error = __reiserfs_xattr_set(inode, name, value, size, 0); 330 error = reiserfs_xattr_set_handle(th, inode, name, value, size, 0);
314 331
315 /* 332 /*
316 * Ensure that the inode gets dirtied if we're only using 333 * Ensure that the inode gets dirtied if we're only using
@@ -337,7 +354,8 @@ reiserfs_set_acl(struct inode *inode, int type, struct posix_acl *acl)
337/* dir->i_mutex: locked, 354/* dir->i_mutex: locked,
338 * inode is new and not released into the wild yet */ 355 * inode is new and not released into the wild yet */
339int 356int
340reiserfs_inherit_default_acl(struct inode *dir, struct dentry *dentry, 357reiserfs_inherit_default_acl(struct reiserfs_transaction_handle *th,
358 struct inode *dir, struct dentry *dentry,
341 struct inode *inode) 359 struct inode *inode)
342{ 360{
343 struct posix_acl *acl; 361 struct posix_acl *acl;
@@ -374,7 +392,8 @@ reiserfs_inherit_default_acl(struct inode *dir, struct dentry *dentry,
374 392
375 /* Copy the default ACL to the default ACL of a new directory */ 393 /* Copy the default ACL to the default ACL of a new directory */
376 if (S_ISDIR(inode->i_mode)) { 394 if (S_ISDIR(inode->i_mode)) {
377 err = reiserfs_set_acl(inode, ACL_TYPE_DEFAULT, acl); 395 err = reiserfs_set_acl(th, inode, ACL_TYPE_DEFAULT,
396 acl);
378 if (err) 397 if (err)
379 goto cleanup; 398 goto cleanup;
380 } 399 }
@@ -395,9 +414,9 @@ reiserfs_inherit_default_acl(struct inode *dir, struct dentry *dentry,
395 414
396 /* If we need an ACL.. */ 415 /* If we need an ACL.. */
397 if (need_acl > 0) { 416 if (need_acl > 0) {
398 err = 417 err = reiserfs_set_acl(th, inode,
399 reiserfs_set_acl(inode, ACL_TYPE_ACCESS, 418 ACL_TYPE_ACCESS,
400 acl_copy); 419 acl_copy);
401 if (err) 420 if (err)
402 goto cleanup_copy; 421 goto cleanup_copy;
403 } 422 }
@@ -415,21 +434,45 @@ reiserfs_inherit_default_acl(struct inode *dir, struct dentry *dentry,
415 return err; 434 return err;
416} 435}
417 436
418/* Looks up and caches the result of the default ACL. 437/* This is used to cache the default acl before a new object is created.
419 * We do this so that we don't need to carry the xattr_sem into 438 * The biggest reason for this is to get an idea of how many blocks will
420 * reiserfs_new_inode if we don't need to */ 439 * actually be required for the create operation if we must inherit an ACL.
440 * An ACL write can add up to 3 object creations and an additional file write
441 * so we'd prefer not to reserve that many blocks in the journal if we can.
442 * It also has the advantage of not loading the ACL with a transaction open,
443 * this may seem silly, but if the owner of the directory is doing the
444 * creation, the ACL may not be loaded since the permissions wouldn't require
445 * it.
446 * We return the number of blocks required for the transaction.
447 */
421int reiserfs_cache_default_acl(struct inode *inode) 448int reiserfs_cache_default_acl(struct inode *inode)
422{ 449{
423 int ret = 0; 450 struct posix_acl *acl;
424 if (reiserfs_posixacl(inode->i_sb) && !IS_PRIVATE(inode)) { 451 int nblocks = 0;
425 struct posix_acl *acl; 452
426 acl = reiserfs_get_acl(inode, ACL_TYPE_DEFAULT); 453 if (IS_PRIVATE(inode))
427 ret = (acl && !IS_ERR(acl)); 454 return 0;
428 if (ret) 455
429 posix_acl_release(acl); 456 acl = reiserfs_get_acl(inode, ACL_TYPE_DEFAULT);
457
458 if (acl && !IS_ERR(acl)) {
459 int size = reiserfs_acl_size(acl->a_count);
460
461 /* Other xattrs can be created during inode creation. We don't
462 * want to claim too many blocks, so we check to see if we
463 * we need to create the tree to the xattrs, and then we
464 * just want two files. */
465 nblocks = reiserfs_xattr_jcreate_nblocks(inode);
466 nblocks += JOURNAL_BLOCKS_PER_OBJECT(inode->i_sb);
467
468 REISERFS_I(inode)->i_flags |= i_has_xattr_dir;
469
470 /* We need to account for writes + bitmaps for two files */
471 nblocks += reiserfs_xattr_nblocks(inode, size) * 4;
472 posix_acl_release(acl);
430 } 473 }
431 474
432 return ret; 475 return nblocks;
433} 476}
434 477
435int reiserfs_acl_chmod(struct inode *inode) 478int reiserfs_acl_chmod(struct inode *inode)
@@ -455,8 +498,22 @@ int reiserfs_acl_chmod(struct inode *inode)
455 if (!clone) 498 if (!clone)
456 return -ENOMEM; 499 return -ENOMEM;
457 error = posix_acl_chmod_masq(clone, inode->i_mode); 500 error = posix_acl_chmod_masq(clone, inode->i_mode);
458 if (!error) 501 if (!error) {
459 error = reiserfs_set_acl(inode, ACL_TYPE_ACCESS, clone); 502 struct reiserfs_transaction_handle th;
503 size_t size = reiserfs_xattr_nblocks(inode,
504 reiserfs_acl_size(clone->a_count));
505 reiserfs_write_lock(inode->i_sb);
506 error = journal_begin(&th, inode->i_sb, size * 2);
507 if (!error) {
508 int error2;
509 error = reiserfs_set_acl(&th, inode, ACL_TYPE_ACCESS,
510 clone);
511 error2 = journal_end(&th, inode->i_sb, size * 2);
512 if (error2)
513 error = error2;
514 }
515 reiserfs_write_unlock(inode->i_sb);
516 }
460 posix_acl_release(clone); 517 posix_acl_release(clone);
461 return error; 518 return error;
462} 519}