diff options
Diffstat (limited to 'fs/ecryptfs/mmap.c')
-rw-r--r-- | fs/ecryptfs/mmap.c | 96 |
1 files changed, 89 insertions, 7 deletions
diff --git a/fs/ecryptfs/mmap.c b/fs/ecryptfs/mmap.c index 0af3aa3b4b3e..ba3650d03c48 100644 --- a/fs/ecryptfs/mmap.c +++ b/fs/ecryptfs/mmap.c | |||
@@ -6,7 +6,7 @@ | |||
6 | * | 6 | * |
7 | * Copyright (C) 1997-2003 Erez Zadok | 7 | * Copyright (C) 1997-2003 Erez Zadok |
8 | * Copyright (C) 2001-2003 Stony Brook University | 8 | * Copyright (C) 2001-2003 Stony Brook University |
9 | * Copyright (C) 2004-2006 International Business Machines Corp. | 9 | * Copyright (C) 2004-2007 International Business Machines Corp. |
10 | * Author(s): Michael A. Halcrow <mahalcro@us.ibm.com> | 10 | * Author(s): Michael A. Halcrow <mahalcro@us.ibm.com> |
11 | * | 11 | * |
12 | * This program is free software; you can redistribute it and/or | 12 | * This program is free software; you can redistribute it and/or |
@@ -308,6 +308,9 @@ out: | |||
308 | return rc; | 308 | return rc; |
309 | } | 309 | } |
310 | 310 | ||
311 | /** | ||
312 | * Called with lower inode mutex held. | ||
313 | */ | ||
311 | static int fill_zeros_to_end_of_page(struct page *page, unsigned int to) | 314 | static int fill_zeros_to_end_of_page(struct page *page, unsigned int to) |
312 | { | 315 | { |
313 | struct inode *inode = page->mapping->host; | 316 | struct inode *inode = page->mapping->host; |
@@ -407,10 +410,9 @@ static void ecryptfs_unmap_and_release_lower_page(struct page *lower_page) | |||
407 | * | 410 | * |
408 | * Returns zero on success; non-zero on error. | 411 | * Returns zero on success; non-zero on error. |
409 | */ | 412 | */ |
410 | int | 413 | static int ecryptfs_write_inode_size_to_header(struct file *lower_file, |
411 | ecryptfs_write_inode_size_to_header(struct file *lower_file, | 414 | struct inode *lower_inode, |
412 | struct inode *lower_inode, | 415 | struct inode *inode) |
413 | struct inode *inode) | ||
414 | { | 416 | { |
415 | int rc = 0; | 417 | int rc = 0; |
416 | struct page *header_page; | 418 | struct page *header_page; |
@@ -442,6 +444,80 @@ out: | |||
442 | return rc; | 444 | return rc; |
443 | } | 445 | } |
444 | 446 | ||
447 | static int ecryptfs_write_inode_size_to_xattr(struct inode *lower_inode, | ||
448 | struct inode *inode, | ||
449 | struct dentry *ecryptfs_dentry, | ||
450 | int lower_i_mutex_held) | ||
451 | { | ||
452 | ssize_t size; | ||
453 | void *xattr_virt; | ||
454 | struct dentry *lower_dentry; | ||
455 | u64 file_size; | ||
456 | int rc; | ||
457 | |||
458 | xattr_virt = kmem_cache_alloc(ecryptfs_xattr_cache, GFP_KERNEL); | ||
459 | if (!xattr_virt) { | ||
460 | printk(KERN_ERR "Out of memory whilst attempting to write " | ||
461 | "inode size to xattr\n"); | ||
462 | rc = -ENOMEM; | ||
463 | goto out; | ||
464 | } | ||
465 | lower_dentry = ecryptfs_dentry_to_lower(ecryptfs_dentry); | ||
466 | if (!lower_dentry->d_inode->i_op->getxattr) { | ||
467 | printk(KERN_WARNING | ||
468 | "No support for setting xattr in lower filesystem\n"); | ||
469 | rc = -ENOSYS; | ||
470 | kmem_cache_free(ecryptfs_xattr_cache, xattr_virt); | ||
471 | goto out; | ||
472 | } | ||
473 | if (!lower_i_mutex_held) | ||
474 | mutex_lock(&lower_dentry->d_inode->i_mutex); | ||
475 | size = lower_dentry->d_inode->i_op->getxattr(lower_dentry, | ||
476 | ECRYPTFS_XATTR_NAME, | ||
477 | xattr_virt, | ||
478 | PAGE_CACHE_SIZE); | ||
479 | if (!lower_i_mutex_held) | ||
480 | mutex_unlock(&lower_dentry->d_inode->i_mutex); | ||
481 | if (size < 0) | ||
482 | size = 8; | ||
483 | file_size = (u64)i_size_read(inode); | ||
484 | file_size = cpu_to_be64(file_size); | ||
485 | memcpy(xattr_virt, &file_size, sizeof(u64)); | ||
486 | if (!lower_i_mutex_held) | ||
487 | mutex_lock(&lower_dentry->d_inode->i_mutex); | ||
488 | rc = lower_dentry->d_inode->i_op->setxattr(lower_dentry, | ||
489 | ECRYPTFS_XATTR_NAME, | ||
490 | xattr_virt, size, 0); | ||
491 | if (!lower_i_mutex_held) | ||
492 | mutex_unlock(&lower_dentry->d_inode->i_mutex); | ||
493 | if (rc) | ||
494 | printk(KERN_ERR "Error whilst attempting to write inode size " | ||
495 | "to lower file xattr; rc = [%d]\n", rc); | ||
496 | kmem_cache_free(ecryptfs_xattr_cache, xattr_virt); | ||
497 | out: | ||
498 | return rc; | ||
499 | } | ||
500 | |||
501 | int | ||
502 | ecryptfs_write_inode_size_to_metadata(struct file *lower_file, | ||
503 | struct inode *lower_inode, | ||
504 | struct inode *inode, | ||
505 | struct dentry *ecryptfs_dentry, | ||
506 | int lower_i_mutex_held) | ||
507 | { | ||
508 | struct ecryptfs_crypt_stat *crypt_stat; | ||
509 | |||
510 | crypt_stat = &ecryptfs_inode_to_private(inode)->crypt_stat; | ||
511 | if (crypt_stat->flags & ECRYPTFS_METADATA_IN_XATTR) | ||
512 | return ecryptfs_write_inode_size_to_xattr(lower_inode, inode, | ||
513 | ecryptfs_dentry, | ||
514 | lower_i_mutex_held); | ||
515 | else | ||
516 | return ecryptfs_write_inode_size_to_header(lower_file, | ||
517 | lower_inode, | ||
518 | inode); | ||
519 | } | ||
520 | |||
445 | int ecryptfs_get_lower_page(struct page **lower_page, struct inode *lower_inode, | 521 | int ecryptfs_get_lower_page(struct page **lower_page, struct inode *lower_inode, |
446 | struct file *lower_file, | 522 | struct file *lower_file, |
447 | unsigned long lower_page_index, int byte_offset, | 523 | unsigned long lower_page_index, int byte_offset, |
@@ -528,6 +604,8 @@ out: | |||
528 | return rc; | 604 | return rc; |
529 | } | 605 | } |
530 | 606 | ||
607 | struct kmem_cache *ecryptfs_xattr_cache; | ||
608 | |||
531 | /** | 609 | /** |
532 | * ecryptfs_commit_write | 610 | * ecryptfs_commit_write |
533 | * @file: The eCryptfs file object | 611 | * @file: The eCryptfs file object |
@@ -581,7 +659,6 @@ static int ecryptfs_commit_write(struct file *file, struct page *page, | |||
581 | "index [0x%.16x])\n", page->index); | 659 | "index [0x%.16x])\n", page->index); |
582 | goto out; | 660 | goto out; |
583 | } | 661 | } |
584 | rc = 0; | ||
585 | inode->i_blocks = lower_inode->i_blocks; | 662 | inode->i_blocks = lower_inode->i_blocks; |
586 | pos = (page->index << PAGE_CACHE_SHIFT) + to; | 663 | pos = (page->index << PAGE_CACHE_SHIFT) + to; |
587 | if (pos > i_size_read(inode)) { | 664 | if (pos > i_size_read(inode)) { |
@@ -589,7 +666,12 @@ static int ecryptfs_commit_write(struct file *file, struct page *page, | |||
589 | ecryptfs_printk(KERN_DEBUG, "Expanded file size to " | 666 | ecryptfs_printk(KERN_DEBUG, "Expanded file size to " |
590 | "[0x%.16x]\n", i_size_read(inode)); | 667 | "[0x%.16x]\n", i_size_read(inode)); |
591 | } | 668 | } |
592 | ecryptfs_write_inode_size_to_header(lower_file, lower_inode, inode); | 669 | rc = ecryptfs_write_inode_size_to_metadata(lower_file, lower_inode, |
670 | inode, file->f_dentry, | ||
671 | ECRYPTFS_LOWER_I_MUTEX_HELD); | ||
672 | if (rc) | ||
673 | printk(KERN_ERR "Error writing inode size to metadata; " | ||
674 | "rc = [%d]\n", rc); | ||
593 | lower_inode->i_mtime = lower_inode->i_ctime = CURRENT_TIME; | 675 | lower_inode->i_mtime = lower_inode->i_ctime = CURRENT_TIME; |
594 | mark_inode_dirty_sync(inode); | 676 | mark_inode_dirty_sync(inode); |
595 | out: | 677 | out: |