diff options
Diffstat (limited to 'fs/reiserfs/xattr_acl.c')
-rw-r--r-- | fs/reiserfs/xattr_acl.c | 257 |
1 files changed, 142 insertions, 115 deletions
diff --git a/fs/reiserfs/xattr_acl.c b/fs/reiserfs/xattr_acl.c index b7e4fa4539de..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); |
@@ -172,6 +188,29 @@ static void *posix_acl_to_disk(const struct posix_acl *acl, size_t * size) | |||
172 | return ERR_PTR(-EINVAL); | 188 | return ERR_PTR(-EINVAL); |
173 | } | 189 | } |
174 | 190 | ||
191 | static inline void iset_acl(struct inode *inode, struct posix_acl **i_acl, | ||
192 | struct posix_acl *acl) | ||
193 | { | ||
194 | spin_lock(&inode->i_lock); | ||
195 | if (*i_acl != ERR_PTR(-ENODATA)) | ||
196 | posix_acl_release(*i_acl); | ||
197 | *i_acl = posix_acl_dup(acl); | ||
198 | spin_unlock(&inode->i_lock); | ||
199 | } | ||
200 | |||
201 | static inline struct posix_acl *iget_acl(struct inode *inode, | ||
202 | struct posix_acl **i_acl) | ||
203 | { | ||
204 | struct posix_acl *acl = ERR_PTR(-ENODATA); | ||
205 | |||
206 | spin_lock(&inode->i_lock); | ||
207 | if (*i_acl != ERR_PTR(-ENODATA)) | ||
208 | acl = posix_acl_dup(*i_acl); | ||
209 | spin_unlock(&inode->i_lock); | ||
210 | |||
211 | return acl; | ||
212 | } | ||
213 | |||
175 | /* | 214 | /* |
176 | * Inode operation get_posix_acl(). | 215 | * Inode operation get_posix_acl(). |
177 | * | 216 | * |
@@ -199,11 +238,11 @@ struct posix_acl *reiserfs_get_acl(struct inode *inode, int type) | |||
199 | return ERR_PTR(-EINVAL); | 238 | return ERR_PTR(-EINVAL); |
200 | } | 239 | } |
201 | 240 | ||
202 | if (IS_ERR(*p_acl)) { | 241 | acl = iget_acl(inode, p_acl); |
203 | if (PTR_ERR(*p_acl) == -ENODATA) | 242 | if (acl && !IS_ERR(acl)) |
204 | return NULL; | 243 | return acl; |
205 | } else if (*p_acl != NULL) | 244 | else if (PTR_ERR(acl) == -ENODATA) |
206 | return posix_acl_dup(*p_acl); | 245 | return NULL; |
207 | 246 | ||
208 | size = reiserfs_xattr_get(inode, name, NULL, 0); | 247 | size = reiserfs_xattr_get(inode, name, NULL, 0); |
209 | if (size < 0) { | 248 | if (size < 0) { |
@@ -229,7 +268,7 @@ struct posix_acl *reiserfs_get_acl(struct inode *inode, int type) | |||
229 | } else { | 268 | } else { |
230 | acl = posix_acl_from_disk(value, retval); | 269 | acl = posix_acl_from_disk(value, retval); |
231 | if (!IS_ERR(acl)) | 270 | if (!IS_ERR(acl)) |
232 | *p_acl = posix_acl_dup(acl); | 271 | iset_acl(inode, p_acl, acl); |
233 | } | 272 | } |
234 | 273 | ||
235 | kfree(value); | 274 | kfree(value); |
@@ -243,12 +282,13 @@ struct posix_acl *reiserfs_get_acl(struct inode *inode, int type) | |||
243 | * BKL held [before 2.5.x] | 282 | * BKL held [before 2.5.x] |
244 | */ | 283 | */ |
245 | static int | 284 | static int |
246 | 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) | ||
247 | { | 287 | { |
248 | char *name; | 288 | char *name; |
249 | void *value = NULL; | 289 | void *value = NULL; |
250 | struct posix_acl **p_acl; | 290 | struct posix_acl **p_acl; |
251 | size_t size; | 291 | size_t size = 0; |
252 | int error; | 292 | int error; |
253 | struct reiserfs_inode_info *reiserfs_i = REISERFS_I(inode); | 293 | struct reiserfs_inode_info *reiserfs_i = REISERFS_I(inode); |
254 | 294 | ||
@@ -285,31 +325,28 @@ reiserfs_set_acl(struct inode *inode, int type, struct posix_acl *acl) | |||
285 | value = posix_acl_to_disk(acl, &size); | 325 | value = posix_acl_to_disk(acl, &size); |
286 | if (IS_ERR(value)) | 326 | if (IS_ERR(value)) |
287 | return (int)PTR_ERR(value); | 327 | return (int)PTR_ERR(value); |
288 | error = reiserfs_xattr_set(inode, name, value, size, 0); | 328 | } |
289 | } else { | 329 | |
290 | error = reiserfs_xattr_del(inode, name); | 330 | error = reiserfs_xattr_set_handle(th, inode, name, value, size, 0); |
291 | if (error == -ENODATA) { | 331 | |
292 | /* This may seem odd here, but it means that the ACL was set | 332 | /* |
293 | * with a value representable with mode bits. If there was | 333 | * Ensure that the inode gets dirtied if we're only using |
294 | * an ACL before, reiserfs_xattr_del already dirtied the inode. | 334 | * the mode bits and an old ACL didn't exist. We don't need |
295 | */ | 335 | * to check if the inode is hashed here since we won't get |
336 | * called by reiserfs_inherit_default_acl(). | ||
337 | */ | ||
338 | if (error == -ENODATA) { | ||
339 | error = 0; | ||
340 | if (type == ACL_TYPE_ACCESS) { | ||
341 | inode->i_ctime = CURRENT_TIME_SEC; | ||
296 | mark_inode_dirty(inode); | 342 | mark_inode_dirty(inode); |
297 | error = 0; | ||
298 | } | 343 | } |
299 | } | 344 | } |
300 | 345 | ||
301 | kfree(value); | 346 | kfree(value); |
302 | 347 | ||
303 | if (!error) { | 348 | if (!error) |
304 | /* Release the old one */ | 349 | iset_acl(inode, p_acl, acl); |
305 | if (!IS_ERR(*p_acl) && *p_acl) | ||
306 | posix_acl_release(*p_acl); | ||
307 | |||
308 | if (acl == NULL) | ||
309 | *p_acl = ERR_PTR(-ENODATA); | ||
310 | else | ||
311 | *p_acl = posix_acl_dup(acl); | ||
312 | } | ||
313 | 350 | ||
314 | return error; | 351 | return error; |
315 | } | 352 | } |
@@ -317,7 +354,8 @@ reiserfs_set_acl(struct inode *inode, int type, struct posix_acl *acl) | |||
317 | /* dir->i_mutex: locked, | 354 | /* dir->i_mutex: locked, |
318 | * inode is new and not released into the wild yet */ | 355 | * inode is new and not released into the wild yet */ |
319 | int | 356 | int |
320 | 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, | ||
321 | struct inode *inode) | 359 | struct inode *inode) |
322 | { | 360 | { |
323 | struct posix_acl *acl; | 361 | struct posix_acl *acl; |
@@ -335,8 +373,8 @@ reiserfs_inherit_default_acl(struct inode *dir, struct dentry *dentry, | |||
335 | /* Don't apply ACLs to objects in the .reiserfs_priv tree.. This | 373 | /* Don't apply ACLs to objects in the .reiserfs_priv tree.. This |
336 | * would be useless since permissions are ignored, and a pain because | 374 | * would be useless since permissions are ignored, and a pain because |
337 | * it introduces locking cycles */ | 375 | * it introduces locking cycles */ |
338 | if (is_reiserfs_priv_object(dir)) { | 376 | if (IS_PRIVATE(dir)) { |
339 | reiserfs_mark_inode_private(inode); | 377 | inode->i_flags |= S_PRIVATE; |
340 | goto apply_umask; | 378 | goto apply_umask; |
341 | } | 379 | } |
342 | 380 | ||
@@ -354,7 +392,8 @@ reiserfs_inherit_default_acl(struct inode *dir, struct dentry *dentry, | |||
354 | 392 | ||
355 | /* 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 */ |
356 | if (S_ISDIR(inode->i_mode)) { | 394 | if (S_ISDIR(inode->i_mode)) { |
357 | err = reiserfs_set_acl(inode, ACL_TYPE_DEFAULT, acl); | 395 | err = reiserfs_set_acl(th, inode, ACL_TYPE_DEFAULT, |
396 | acl); | ||
358 | if (err) | 397 | if (err) |
359 | goto cleanup; | 398 | goto cleanup; |
360 | } | 399 | } |
@@ -375,9 +414,9 @@ reiserfs_inherit_default_acl(struct inode *dir, struct dentry *dentry, | |||
375 | 414 | ||
376 | /* If we need an ACL.. */ | 415 | /* If we need an ACL.. */ |
377 | if (need_acl > 0) { | 416 | if (need_acl > 0) { |
378 | err = | 417 | err = reiserfs_set_acl(th, inode, |
379 | reiserfs_set_acl(inode, ACL_TYPE_ACCESS, | 418 | ACL_TYPE_ACCESS, |
380 | acl_copy); | 419 | acl_copy); |
381 | if (err) | 420 | if (err) |
382 | goto cleanup_copy; | 421 | goto cleanup_copy; |
383 | } | 422 | } |
@@ -395,25 +434,45 @@ reiserfs_inherit_default_acl(struct inode *dir, struct dentry *dentry, | |||
395 | return err; | 434 | return err; |
396 | } | 435 | } |
397 | 436 | ||
398 | /* 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. |
399 | * 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 |
400 | * 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 | */ | ||
401 | int reiserfs_cache_default_acl(struct inode *inode) | 448 | int reiserfs_cache_default_acl(struct inode *inode) |
402 | { | 449 | { |
403 | int ret = 0; | 450 | struct posix_acl *acl; |
404 | if (reiserfs_posixacl(inode->i_sb) && !is_reiserfs_priv_object(inode)) { | 451 | int nblocks = 0; |
405 | struct posix_acl *acl; | 452 | |
406 | reiserfs_read_lock_xattr_i(inode); | 453 | if (IS_PRIVATE(inode)) |
407 | reiserfs_read_lock_xattrs(inode->i_sb); | 454 | return 0; |
408 | acl = reiserfs_get_acl(inode, ACL_TYPE_DEFAULT); | 455 | |
409 | reiserfs_read_unlock_xattrs(inode->i_sb); | 456 | acl = reiserfs_get_acl(inode, ACL_TYPE_DEFAULT); |
410 | reiserfs_read_unlock_xattr_i(inode); | 457 | |
411 | ret = (acl && !IS_ERR(acl)); | 458 | if (acl && !IS_ERR(acl)) { |
412 | if (ret) | 459 | int size = reiserfs_acl_size(acl->a_count); |
413 | posix_acl_release(acl); | 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); | ||
414 | } | 473 | } |
415 | 474 | ||
416 | return ret; | 475 | return nblocks; |
417 | } | 476 | } |
418 | 477 | ||
419 | int reiserfs_acl_chmod(struct inode *inode) | 478 | int reiserfs_acl_chmod(struct inode *inode) |
@@ -429,9 +488,7 @@ int reiserfs_acl_chmod(struct inode *inode) | |||
429 | return 0; | 488 | return 0; |
430 | } | 489 | } |
431 | 490 | ||
432 | reiserfs_read_lock_xattrs(inode->i_sb); | ||
433 | acl = reiserfs_get_acl(inode, ACL_TYPE_ACCESS); | 491 | acl = reiserfs_get_acl(inode, ACL_TYPE_ACCESS); |
434 | reiserfs_read_unlock_xattrs(inode->i_sb); | ||
435 | if (!acl) | 492 | if (!acl) |
436 | return 0; | 493 | return 0; |
437 | if (IS_ERR(acl)) | 494 | if (IS_ERR(acl)) |
@@ -442,18 +499,20 @@ int reiserfs_acl_chmod(struct inode *inode) | |||
442 | return -ENOMEM; | 499 | return -ENOMEM; |
443 | error = posix_acl_chmod_masq(clone, inode->i_mode); | 500 | error = posix_acl_chmod_masq(clone, inode->i_mode); |
444 | if (!error) { | 501 | if (!error) { |
445 | int lock = !has_xattr_dir(inode); | 502 | struct reiserfs_transaction_handle th; |
446 | reiserfs_write_lock_xattr_i(inode); | 503 | size_t size = reiserfs_xattr_nblocks(inode, |
447 | if (lock) | 504 | reiserfs_acl_size(clone->a_count)); |
448 | reiserfs_write_lock_xattrs(inode->i_sb); | 505 | reiserfs_write_lock(inode->i_sb); |
449 | else | 506 | error = journal_begin(&th, inode->i_sb, size * 2); |
450 | reiserfs_read_lock_xattrs(inode->i_sb); | 507 | if (!error) { |
451 | error = reiserfs_set_acl(inode, ACL_TYPE_ACCESS, clone); | 508 | int error2; |
452 | if (lock) | 509 | error = reiserfs_set_acl(&th, inode, ACL_TYPE_ACCESS, |
453 | reiserfs_write_unlock_xattrs(inode->i_sb); | 510 | clone); |
454 | else | 511 | error2 = journal_end(&th, inode->i_sb, size * 2); |
455 | reiserfs_read_unlock_xattrs(inode->i_sb); | 512 | if (error2) |
456 | reiserfs_write_unlock_xattr_i(inode); | 513 | error = error2; |
514 | } | ||
515 | reiserfs_write_unlock(inode->i_sb); | ||
457 | } | 516 | } |
458 | posix_acl_release(clone); | 517 | posix_acl_release(clone); |
459 | return error; | 518 | return error; |
@@ -477,38 +536,22 @@ posix_acl_access_set(struct inode *inode, const char *name, | |||
477 | return xattr_set_acl(inode, ACL_TYPE_ACCESS, value, size); | 536 | return xattr_set_acl(inode, ACL_TYPE_ACCESS, value, size); |
478 | } | 537 | } |
479 | 538 | ||
480 | static int posix_acl_access_del(struct inode *inode, const char *name) | 539 | static size_t posix_acl_access_list(struct inode *inode, char *list, |
540 | size_t list_size, const char *name, | ||
541 | size_t name_len) | ||
481 | { | 542 | { |
482 | struct reiserfs_inode_info *reiserfs_i = REISERFS_I(inode); | 543 | const size_t size = sizeof(POSIX_ACL_XATTR_ACCESS); |
483 | struct posix_acl **acl = &reiserfs_i->i_acl_access; | ||
484 | if (strlen(name) != sizeof(POSIX_ACL_XATTR_ACCESS) - 1) | ||
485 | return -EINVAL; | ||
486 | if (!IS_ERR(*acl) && *acl) { | ||
487 | posix_acl_release(*acl); | ||
488 | *acl = ERR_PTR(-ENODATA); | ||
489 | } | ||
490 | |||
491 | return 0; | ||
492 | } | ||
493 | |||
494 | static int | ||
495 | posix_acl_access_list(struct inode *inode, const char *name, int namelen, | ||
496 | char *out) | ||
497 | { | ||
498 | int len = namelen; | ||
499 | if (!reiserfs_posixacl(inode->i_sb)) | 544 | if (!reiserfs_posixacl(inode->i_sb)) |
500 | return 0; | 545 | return 0; |
501 | if (out) | 546 | if (list && size <= list_size) |
502 | memcpy(out, name, len); | 547 | memcpy(list, POSIX_ACL_XATTR_ACCESS, size); |
503 | 548 | return size; | |
504 | return len; | ||
505 | } | 549 | } |
506 | 550 | ||
507 | struct reiserfs_xattr_handler posix_acl_access_handler = { | 551 | struct xattr_handler reiserfs_posix_acl_access_handler = { |
508 | .prefix = POSIX_ACL_XATTR_ACCESS, | 552 | .prefix = POSIX_ACL_XATTR_ACCESS, |
509 | .get = posix_acl_access_get, | 553 | .get = posix_acl_access_get, |
510 | .set = posix_acl_access_set, | 554 | .set = posix_acl_access_set, |
511 | .del = posix_acl_access_del, | ||
512 | .list = posix_acl_access_list, | 555 | .list = posix_acl_access_list, |
513 | }; | 556 | }; |
514 | 557 | ||
@@ -530,37 +573,21 @@ posix_acl_default_set(struct inode *inode, const char *name, | |||
530 | return xattr_set_acl(inode, ACL_TYPE_DEFAULT, value, size); | 573 | return xattr_set_acl(inode, ACL_TYPE_DEFAULT, value, size); |
531 | } | 574 | } |
532 | 575 | ||
533 | static int posix_acl_default_del(struct inode *inode, const char *name) | 576 | static size_t posix_acl_default_list(struct inode *inode, char *list, |
577 | size_t list_size, const char *name, | ||
578 | size_t name_len) | ||
534 | { | 579 | { |
535 | struct reiserfs_inode_info *reiserfs_i = REISERFS_I(inode); | 580 | const size_t size = sizeof(POSIX_ACL_XATTR_DEFAULT); |
536 | struct posix_acl **acl = &reiserfs_i->i_acl_default; | ||
537 | if (strlen(name) != sizeof(POSIX_ACL_XATTR_DEFAULT) - 1) | ||
538 | return -EINVAL; | ||
539 | if (!IS_ERR(*acl) && *acl) { | ||
540 | posix_acl_release(*acl); | ||
541 | *acl = ERR_PTR(-ENODATA); | ||
542 | } | ||
543 | |||
544 | return 0; | ||
545 | } | ||
546 | |||
547 | static int | ||
548 | posix_acl_default_list(struct inode *inode, const char *name, int namelen, | ||
549 | char *out) | ||
550 | { | ||
551 | int len = namelen; | ||
552 | if (!reiserfs_posixacl(inode->i_sb)) | 581 | if (!reiserfs_posixacl(inode->i_sb)) |
553 | return 0; | 582 | return 0; |
554 | if (out) | 583 | if (list && size <= list_size) |
555 | memcpy(out, name, len); | 584 | memcpy(list, POSIX_ACL_XATTR_DEFAULT, size); |
556 | 585 | return size; | |
557 | return len; | ||
558 | } | 586 | } |
559 | 587 | ||
560 | struct reiserfs_xattr_handler posix_acl_default_handler = { | 588 | struct xattr_handler reiserfs_posix_acl_default_handler = { |
561 | .prefix = POSIX_ACL_XATTR_DEFAULT, | 589 | .prefix = POSIX_ACL_XATTR_DEFAULT, |
562 | .get = posix_acl_default_get, | 590 | .get = posix_acl_default_get, |
563 | .set = posix_acl_default_set, | 591 | .set = posix_acl_default_set, |
564 | .del = posix_acl_default_del, | ||
565 | .list = posix_acl_default_list, | 592 | .list = posix_acl_default_list, |
566 | }; | 593 | }; |