* [PATCH] ecryptfs lower file handling code issues
@ 2007-02-07 16:50 Dmitriy Monakhov
2007-02-12 18:24 ` Dmitriy Monakhov
2007-02-21 20:13 ` [PATCH] eCryptfs: resolve lower page unlocking problem Michael Halcrow
0 siblings, 2 replies; 3+ messages in thread
From: Dmitriy Monakhov @ 2007-02-07 16:50 UTC (permalink / raw)
To: Linux Kernel; +Cc: ecryptfs-devel
[-- Attachment #1: Type: text/plain, Size: 293 bytes --]
eCryptfs lower file handling code has several issues:
- Retval from prepare_write()/commit_writ() was't checked to equality
to AOP_TRUNCATED_PAGE.
- In some places page was't unmapped and unlocked after error.
Signed-off-by: Dmitriy Monakhov <dmonakhov@openvz.org>
--------------
[-- Attachment #2: diff-ms-fs-ecryptfs-fix --]
[-- Type: text/plain, Size: 4253 bytes --]
diff --git a/fs/ecryptfs/mmap.c b/fs/ecryptfs/mmap.c
index 06843d2..27ac9ef 100644
--- a/fs/ecryptfs/mmap.c
+++ b/fs/ecryptfs/mmap.c
@@ -391,12 +391,14 @@ out:
return rc;
}
-static void ecryptfs_unmap_and_release_lower_page(struct page *lower_page)
+static void ecryptfs_unmap_and_release_lower_page(struct page *lower_page,
+ int page_locked)
{
kunmap(lower_page);
ecryptfs_printk(KERN_DEBUG, "Unlocking lower page with index = "
"[0x%.16x]\n", lower_page->index);
- unlock_page(lower_page);
+ if (page_locked)
+ unlock_page(lower_page);
page_cache_release(lower_page);
}
@@ -417,6 +419,7 @@ ecryptfs_write_inode_size_to_header(struct file *lower_file,
char *header_virt;
const struct address_space_operations *lower_a_ops;
u64 file_size;
+ int pg_locked = 1;
rc = ecryptfs_grab_and_map_lower_page(&header_page, &header_virt,
lower_inode, 0);
@@ -427,6 +430,12 @@ ecryptfs_write_inode_size_to_header(struct file *lower_file,
}
lower_a_ops = lower_inode->i_mapping->a_ops;
rc = lower_a_ops->prepare_write(lower_file, header_page, 0, 8);
+ if (rc) {
+ if (rc == AOP_TRUNCATED_PAGE)
+ pg_locked = 0;
+ ecryptfs_unmap_and_release_lower_page(header_page, pg_locked);
+ goto out;
+ }
file_size = (u64)i_size_read(inode);
ecryptfs_printk(KERN_DEBUG, "Writing size: [0x%.16x]\n", file_size);
file_size = cpu_to_be64(file_size);
@@ -435,7 +444,9 @@ ecryptfs_write_inode_size_to_header(struct file *lower_file,
if (rc < 0)
ecryptfs_printk(KERN_ERR, "Error commiting header page "
"write\n");
- ecryptfs_unmap_and_release_lower_page(header_page);
+ if (rc == AOP_TRUNCATED_PAGE)
+ pg_locked = 0;
+ ecryptfs_unmap_and_release_lower_page(header_page, pg_locked);
lower_inode->i_mtime = lower_inode->i_ctime = CURRENT_TIME;
mark_inode_dirty_sync(inode);
out:
@@ -468,7 +479,10 @@ int ecryptfs_get_lower_page(struct page **lower_page, struct inode *lower_inode,
}
out:
if (rc && (*lower_page)) {
- ecryptfs_unmap_and_release_lower_page(*lower_page);
+ int pg_locked = 1;
+ if (rc == AOP_TRUNCATED_PAGE)
+ pg_locked = 0;
+ ecryptfs_unmap_and_release_lower_page(*lower_page, pg_locked);
(*lower_page) = NULL;
}
return rc;
@@ -484,16 +498,19 @@ ecryptfs_commit_lower_page(struct page *lower_page, struct inode *lower_inode,
struct file *lower_file, int byte_offset,
int region_size)
{
+ int pg_locked = 1;
int rc = 0;
rc = lower_inode->i_mapping->a_ops->commit_write(
lower_file, lower_page, byte_offset, region_size);
+ if (rc == AOP_TRUNCATED_PAGE)
+ pg_locked = 0;
if (rc < 0) {
ecryptfs_printk(KERN_ERR,
"Error committing write; rc = [%d]\n", rc);
} else
rc = 0;
- ecryptfs_unmap_and_release_lower_page(lower_page);
+ ecryptfs_unmap_and_release_lower_page(lower_page, pg_locked);
return rc;
}
@@ -541,6 +558,7 @@ process_new_file(struct ecryptfs_crypt_stat *crypt_stat,
int current_header_page = 0;
int header_pages;
int more_header_data_to_be_written = 1;
+ int pg_locked = 1;
lower_inode = ecryptfs_inode_to_lower(inode);
lower_file = ecryptfs_file_to_lower(file);
@@ -563,6 +581,10 @@ process_new_file(struct ecryptfs_crypt_stat *crypt_stat,
rc = lower_a_ops->prepare_write(lower_file, header_page, 0,
PAGE_CACHE_SIZE);
if (rc) {
+ if (rc == AOP_TRUNCATED_PAGE)
+ pg_locked = 0;
+ ecryptfs_unmap_and_release_lower_page(header_page,
+ pg_locked);
ecryptfs_printk(KERN_ERR, "Error preparing to write "
"header page out; rc = [%d]\n", rc);
goto out;
@@ -579,7 +601,7 @@ process_new_file(struct ecryptfs_crypt_stat *crypt_stat,
rc = -EIO;
memset(header_virt, 0, PAGE_CACHE_SIZE);
ecryptfs_unmap_and_release_lower_page(
- header_page);
+ header_page, pg_locked);
goto out;
}
if (current_header_page == 0)
@@ -588,7 +610,9 @@ process_new_file(struct ecryptfs_crypt_stat *crypt_stat,
}
rc = lower_a_ops->commit_write(lower_file, header_page, 0,
PAGE_CACHE_SIZE);
- ecryptfs_unmap_and_release_lower_page(header_page);
+ if (rc == AOP_TRUNCATED_PAGE)
+ pg_locked = 0;
+ ecryptfs_unmap_and_release_lower_page(header_page, pg_locked);
if (rc < 0) {
ecryptfs_printk(KERN_ERR,
"Error commiting header page write; "
^ permalink raw reply related [flat|nested] 3+ messages in thread
* Re: [PATCH] ecryptfs lower file handling code issues
2007-02-07 16:50 [PATCH] ecryptfs lower file handling code issues Dmitriy Monakhov
@ 2007-02-12 18:24 ` Dmitriy Monakhov
2007-02-21 20:13 ` [PATCH] eCryptfs: resolve lower page unlocking problem Michael Halcrow
1 sibling, 0 replies; 3+ messages in thread
From: Dmitriy Monakhov @ 2007-02-12 18:24 UTC (permalink / raw)
To: Dmitriy Monakhov; +Cc: Linux Kernel, ecryptfs-devel
Dmitriy Monakhov <dmonakhov@openvz.org> writes:
> eCryptfs lower file handling code has several issues:
> - Retval from prepare_write()/commit_writ() was't checked to equality
> to AOP_TRUNCATED_PAGE.
> - In some places page was't unmapped and unlocked after error.
it is easy to retproduce:
##Prepare FS
dd if=/dev/zero of=FS.img bs=1M count=64
mkfs.ext3 -F FS.img
mkdir crypt_root
mkdir crypt_private
mount FS.img crypt_private/ -oloop
mount -t ecryptfs crypt_private/ crypt_root/ -ocipher=aes
## exhaust all available space, and provoke ENOSPC condition.
for ((i=0;i<100;i++));do dd if=/dev/zero of=crypt_root/file$i bs=1M count=1;done
###### after this we got folowing errors on console:
#process_new_file: Error preparing to write header page out; rc = [-28]
#ecryptfs_commit_write: Error processing new file; rc = [-28]
#write_zeros: Error attempting to write zero's to remainder of page at index [0x0000000000000000]
#ecryptfs_fill_zeros: write_zeros(file=[f561bde0], index=[0x0000000000000000], old_end_pos_in_page=[d], (PAGE_CACHE_SIZE - new_end_pos_in_page=[-1])=[d]) returned [0]
#grow_file: Error attempting to fill zeros in file; rc = [-28]
# After prepare_write() failed in process_new_file() page was't unlocked,
# so leter umount will stuck forever in D state.
umount crypt_root/
umount crypt_private/ ## stuck forever here.
>
> Signed-off-by: Dmitriy Monakhov <dmonakhov@openvz.org>
> --------------
> diff --git a/fs/ecryptfs/mmap.c b/fs/ecryptfs/mmap.c
> index 06843d2..27ac9ef 100644
> --- a/fs/ecryptfs/mmap.c
> +++ b/fs/ecryptfs/mmap.c
> @@ -391,12 +391,14 @@ out:
> return rc;
> }
>
> -static void ecryptfs_unmap_and_release_lower_page(struct page *lower_page)
> +static void ecryptfs_unmap_and_release_lower_page(struct page *lower_page,
> + int page_locked)
> {
> kunmap(lower_page);
> ecryptfs_printk(KERN_DEBUG, "Unlocking lower page with index = "
> "[0x%.16x]\n", lower_page->index);
> - unlock_page(lower_page);
> + if (page_locked)
> + unlock_page(lower_page);
> page_cache_release(lower_page);
> }
>
> @@ -417,6 +419,7 @@ ecryptfs_write_inode_size_to_header(struct file *lower_file,
> char *header_virt;
> const struct address_space_operations *lower_a_ops;
> u64 file_size;
> + int pg_locked = 1;
>
> rc = ecryptfs_grab_and_map_lower_page(&header_page, &header_virt,
> lower_inode, 0);
> @@ -427,6 +430,12 @@ ecryptfs_write_inode_size_to_header(struct file *lower_file,
> }
> lower_a_ops = lower_inode->i_mapping->a_ops;
> rc = lower_a_ops->prepare_write(lower_file, header_page, 0, 8);
> + if (rc) {
> + if (rc == AOP_TRUNCATED_PAGE)
> + pg_locked = 0;
> + ecryptfs_unmap_and_release_lower_page(header_page, pg_locked);
> + goto out;
> + }
> file_size = (u64)i_size_read(inode);
> ecryptfs_printk(KERN_DEBUG, "Writing size: [0x%.16x]\n", file_size);
> file_size = cpu_to_be64(file_size);
> @@ -435,7 +444,9 @@ ecryptfs_write_inode_size_to_header(struct file *lower_file,
> if (rc < 0)
> ecryptfs_printk(KERN_ERR, "Error commiting header page "
> "write\n");
> - ecryptfs_unmap_and_release_lower_page(header_page);
> + if (rc == AOP_TRUNCATED_PAGE)
> + pg_locked = 0;
> + ecryptfs_unmap_and_release_lower_page(header_page, pg_locked);
> lower_inode->i_mtime = lower_inode->i_ctime = CURRENT_TIME;
> mark_inode_dirty_sync(inode);
> out:
> @@ -468,7 +479,10 @@ int ecryptfs_get_lower_page(struct page **lower_page, struct inode *lower_inode,
> }
> out:
> if (rc && (*lower_page)) {
> - ecryptfs_unmap_and_release_lower_page(*lower_page);
> + int pg_locked = 1;
> + if (rc == AOP_TRUNCATED_PAGE)
> + pg_locked = 0;
> + ecryptfs_unmap_and_release_lower_page(*lower_page, pg_locked);
> (*lower_page) = NULL;
> }
> return rc;
> @@ -484,16 +498,19 @@ ecryptfs_commit_lower_page(struct page *lower_page, struct inode *lower_inode,
> struct file *lower_file, int byte_offset,
> int region_size)
> {
> + int pg_locked = 1;
> int rc = 0;
>
> rc = lower_inode->i_mapping->a_ops->commit_write(
> lower_file, lower_page, byte_offset, region_size);
> + if (rc == AOP_TRUNCATED_PAGE)
> + pg_locked = 0;
> if (rc < 0) {
> ecryptfs_printk(KERN_ERR,
> "Error committing write; rc = [%d]\n", rc);
> } else
> rc = 0;
> - ecryptfs_unmap_and_release_lower_page(lower_page);
> + ecryptfs_unmap_and_release_lower_page(lower_page, pg_locked);
> return rc;
> }
>
> @@ -541,6 +558,7 @@ process_new_file(struct ecryptfs_crypt_stat *crypt_stat,
> int current_header_page = 0;
> int header_pages;
> int more_header_data_to_be_written = 1;
> + int pg_locked = 1;
>
> lower_inode = ecryptfs_inode_to_lower(inode);
> lower_file = ecryptfs_file_to_lower(file);
> @@ -563,6 +581,10 @@ process_new_file(struct ecryptfs_crypt_stat *crypt_stat,
> rc = lower_a_ops->prepare_write(lower_file, header_page, 0,
> PAGE_CACHE_SIZE);
> if (rc) {
> + if (rc == AOP_TRUNCATED_PAGE)
> + pg_locked = 0;
> + ecryptfs_unmap_and_release_lower_page(header_page,
> + pg_locked);
> ecryptfs_printk(KERN_ERR, "Error preparing to write "
> "header page out; rc = [%d]\n", rc);
> goto out;
> @@ -579,7 +601,7 @@ process_new_file(struct ecryptfs_crypt_stat *crypt_stat,
> rc = -EIO;
> memset(header_virt, 0, PAGE_CACHE_SIZE);
> ecryptfs_unmap_and_release_lower_page(
> - header_page);
> + header_page, pg_locked);
> goto out;
> }
> if (current_header_page == 0)
> @@ -588,7 +610,9 @@ process_new_file(struct ecryptfs_crypt_stat *crypt_stat,
> }
> rc = lower_a_ops->commit_write(lower_file, header_page, 0,
> PAGE_CACHE_SIZE);
> - ecryptfs_unmap_and_release_lower_page(header_page);
> + if (rc == AOP_TRUNCATED_PAGE)
> + pg_locked = 0;
> + ecryptfs_unmap_and_release_lower_page(header_page, pg_locked);
> if (rc < 0) {
> ecryptfs_printk(KERN_ERR,
> "Error commiting header page write; "
^ permalink raw reply [flat|nested] 3+ messages in thread
* [PATCH] eCryptfs: resolve lower page unlocking problem
2007-02-07 16:50 [PATCH] ecryptfs lower file handling code issues Dmitriy Monakhov
2007-02-12 18:24 ` Dmitriy Monakhov
@ 2007-02-21 20:13 ` Michael Halcrow
1 sibling, 0 replies; 3+ messages in thread
From: Michael Halcrow @ 2007-02-21 20:13 UTC (permalink / raw)
To: akpm; +Cc: Linux Kernel, Dmitriy Monakhov
On Wed, Feb 07, 2007 at 07:50:44PM +0300, Dmitriy Monakhov wrote:
> eCryptfs lower file handling code has several issues:
> - Retval from prepare_write()/commit_writ() was't checked to equality
> to AOP_TRUNCATED_PAGE.
> - In some places page was't unmapped and unlocked after error.
I reworked Dmitriy's patch to apply cleanly against the more recent
version in the -mm tree.
---
eCryptfs lower file handling code has several issues:
- Retval from prepare_write()/commit_write() wasn't checked to equality
to AOP_TRUNCATED_PAGE.
- In some places page wasn't unmapped and unlocked after error.
Signed-off-by: Michael Halcrow <mhalcrow@us.ibm.com>
---
fs/ecryptfs/mmap.c | 28 +++++++++++++++++++++++-----
1 files changed, 23 insertions(+), 5 deletions(-)
diff --git a/fs/ecryptfs/mmap.c b/fs/ecryptfs/mmap.c
index 92a4147..09160ad 100644
--- a/fs/ecryptfs/mmap.c
+++ b/fs/ecryptfs/mmap.c
@@ -422,9 +422,11 @@ out:
return rc;
}
-static void ecryptfs_release_lower_page(struct page *lower_page)
+static
+void ecryptfs_release_lower_page(struct page *lower_page, int page_locked)
{
- unlock_page(lower_page);
+ if (page_locked)
+ unlock_page(lower_page);
page_cache_release(lower_page);
}
@@ -454,6 +456,13 @@ static int ecryptfs_write_inode_size_to_header(struct file *lower_file,
}
lower_a_ops = lower_inode->i_mapping->a_ops;
rc = lower_a_ops->prepare_write(lower_file, header_page, 0, 8);
+ if (rc) {
+ if (rc == AOP_TRUNCATED_PAGE)
+ ecryptfs_release_lower_page(header_page, 0);
+ else
+ ecryptfs_release_lower_page(header_page, 1);
+ goto out;
+ }
file_size = (u64)i_size_read(inode);
ecryptfs_printk(KERN_DEBUG, "Writing size: [0x%.16x]\n", file_size);
file_size = cpu_to_be64(file_size);
@@ -465,7 +474,10 @@ static int ecryptfs_write_inode_size_to_header(struct file *lower_file,
if (rc < 0)
ecryptfs_printk(KERN_ERR, "Error commiting header page "
"write\n");
- ecryptfs_release_lower_page(header_page);
+ if (rc == AOP_TRUNCATED_PAGE)
+ ecryptfs_release_lower_page(header_page, 0);
+ else
+ ecryptfs_release_lower_page(header_page, 1);
lower_inode->i_mtime = lower_inode->i_ctime = CURRENT_TIME;
mark_inode_dirty_sync(inode);
out:
@@ -572,7 +584,10 @@ int ecryptfs_get_lower_page(struct page **lower_page, struct inode *lower_inode,
}
out:
if (rc && (*lower_page)) {
- ecryptfs_release_lower_page(*lower_page);
+ if (rc == AOP_TRUNCATED_PAGE)
+ ecryptfs_release_lower_page(*lower_page, 0);
+ else
+ ecryptfs_release_lower_page(*lower_page, 1);
(*lower_page) = NULL;
}
return rc;
@@ -588,16 +603,19 @@ ecryptfs_commit_lower_page(struct page *lower_page, struct inode *lower_inode,
struct file *lower_file, int byte_offset,
int region_size)
{
+ int page_locked = 1;
int rc = 0;
rc = lower_inode->i_mapping->a_ops->commit_write(
lower_file, lower_page, byte_offset, region_size);
+ if (rc == AOP_TRUNCATED_PAGE)
+ page_locked = 0;
if (rc < 0) {
ecryptfs_printk(KERN_ERR,
"Error committing write; rc = [%d]\n", rc);
} else
rc = 0;
- ecryptfs_release_lower_page(lower_page);
+ ecryptfs_release_lower_page(lower_page, page_locked);
return rc;
}
--
1.4.4.4
^ permalink raw reply related [flat|nested] 3+ messages in thread
end of thread, other threads:[~2007-02-21 20:13 UTC | newest]
Thread overview: 3+ messages (download: mbox.gz follow: Atom feed
-- links below jump to the message on this page --
2007-02-07 16:50 [PATCH] ecryptfs lower file handling code issues Dmitriy Monakhov
2007-02-12 18:24 ` Dmitriy Monakhov
2007-02-21 20:13 ` [PATCH] eCryptfs: resolve lower page unlocking problem Michael Halcrow
This is an external index of several public inboxes,
see mirroring instructions on how to clone and mirror
all data and code used by this external index.