diff options
Diffstat (limited to 'fs/reiserfs/xattr_acl.c')
-rw-r--r-- | fs/reiserfs/xattr_acl.c | 105 |
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 | ||
13 | static int reiserfs_set_acl(struct inode *inode, int type, | 13 | static 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 | ||
16 | static int | 17 | static int |
17 | xattr_set_acl(struct inode *inode, int type, const void *value, size_t size) | 18 | xattr_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 | */ |
268 | static int | 284 | static int |
269 | reiserfs_set_acl(struct inode *inode, int type, struct posix_acl *acl) | 285 | reiserfs_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 */ |
339 | int | 356 | int |
340 | reiserfs_inherit_default_acl(struct inode *dir, struct dentry *dentry, | 357 | reiserfs_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 | */ | ||
421 | int reiserfs_cache_default_acl(struct inode *inode) | 448 | int 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 | ||
435 | int reiserfs_acl_chmod(struct inode *inode) | 478 | int 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 | } |