2007-09-17 21:49:45

by Michael Halcrow

[permalink] [raw]
Subject: [PATCH 0/11] eCryptfs: Introduce persistent lower files for each eCryptfs inode

Currently, eCryptfs directly accesses the lower inode address space,
doing things like grab_cache_page() on lower_inode->i_mapping. It
really should not do that. The main point of this patch set is to make
all I/O with the lower files go through vfs_read() and vfs_write()
instead.

In order to accomplish this, eCryptfs needs a way to call vfs_read()
and vfs_write() on the lower file when ecryptfs_aops->readpage() and
ecryptfs_aops->writepage() are called. I propose keeping a persistent
lower file around for each eCryptfs inode. This is the only lower file
that eCryptfs will open for any given eCryptfs inode; multiple
eCryptfs files may map to this one persistent lower file. When the
eCrypfs inode is destroyed, this persistent lower file is closed.

Consolidating all reads and writes to the lower file to a single
execution path simplifies the code. This should also make it easier to
port eCryptfs to use the asynchronous crypto API functions. Note that
this patch set also removes all direct calls to lower prepare_write()
and commite_write(), fixing an oops when mounted on NFS.

Mike


2007-09-17 21:50:15

by Michael Halcrow

[permalink] [raw]
Subject: [PATCH 1/11] eCryptfs: Remove header_extent_size

There is no point to keeping a separate header_extent_size and an
extent_size. The total size of the header can always be represented as
some multiple of the regular data extent size.

Signed-off-by: Michael Halcrow <[email protected]>
---
fs/ecryptfs/crypto.c | 40 ++++++++++++++++++++--------------------
fs/ecryptfs/ecryptfs_kernel.h | 39 +++++++++++++++++++++++++++------------
fs/ecryptfs/inode.c | 7 ++++---
fs/ecryptfs/mmap.c | 2 +-
4 files changed, 52 insertions(+), 36 deletions(-)

diff --git a/fs/ecryptfs/crypto.c b/fs/ecryptfs/crypto.c
index 8e9b36d..3dbb21a 100644
--- a/fs/ecryptfs/crypto.c
+++ b/fs/ecryptfs/crypto.c
@@ -366,8 +366,8 @@ ecryptfs_extent_to_lwr_pg_idx_and_offset(unsigned long *lower_page_idx,
int extents_per_page;

bytes_occupied_by_headers_at_front =
- ( crypt_stat->header_extent_size
- * crypt_stat->num_header_extents_at_front );
+ (crypt_stat->extent_size
+ * crypt_stat->num_header_extents_at_front);
extents_occupied_by_headers_at_front =
( bytes_occupied_by_headers_at_front
/ crypt_stat->extent_size );
@@ -376,8 +376,8 @@ ecryptfs_extent_to_lwr_pg_idx_and_offset(unsigned long *lower_page_idx,
(*lower_page_idx) = lower_extent_num / extents_per_page;
extent_offset = lower_extent_num % extents_per_page;
(*byte_offset) = extent_offset * crypt_stat->extent_size;
- ecryptfs_printk(KERN_DEBUG, " * crypt_stat->header_extent_size = "
- "[%d]\n", crypt_stat->header_extent_size);
+ ecryptfs_printk(KERN_DEBUG, " * crypt_stat->extent_size = "
+ "[%d]\n", crypt_stat->extent_size);
ecryptfs_printk(KERN_DEBUG, " * crypt_stat->"
"num_header_extents_at_front = [%d]\n",
crypt_stat->num_header_extents_at_front);
@@ -899,15 +899,17 @@ void ecryptfs_set_default_sizes(struct ecryptfs_crypt_stat *crypt_stat)
crypt_stat->extent_size = ECRYPTFS_DEFAULT_EXTENT_SIZE;
set_extent_mask_and_shift(crypt_stat);
crypt_stat->iv_bytes = ECRYPTFS_DEFAULT_IV_BYTES;
- if (PAGE_CACHE_SIZE <= ECRYPTFS_MINIMUM_HEADER_EXTENT_SIZE) {
- crypt_stat->header_extent_size =
- ECRYPTFS_MINIMUM_HEADER_EXTENT_SIZE;
- } else
- crypt_stat->header_extent_size = PAGE_CACHE_SIZE;
if (crypt_stat->flags & ECRYPTFS_METADATA_IN_XATTR)
crypt_stat->num_header_extents_at_front = 0;
- else
- crypt_stat->num_header_extents_at_front = 1;
+ else {
+ if (PAGE_CACHE_SIZE <= ECRYPTFS_MINIMUM_HEADER_EXTENT_SIZE)
+ crypt_stat->num_header_extents_at_front =
+ (ECRYPTFS_MINIMUM_HEADER_EXTENT_SIZE
+ / crypt_stat->extent_size);
+ else
+ crypt_stat->num_header_extents_at_front =
+ (PAGE_CACHE_SIZE / crypt_stat->extent_size);
+ }
}

/**
@@ -1319,7 +1321,7 @@ ecryptfs_write_header_metadata(char *virt,
u32 header_extent_size;
u16 num_header_extents_at_front;

- header_extent_size = (u32)crypt_stat->header_extent_size;
+ header_extent_size = (u32)crypt_stat->extent_size;
num_header_extents_at_front =
(u16)crypt_stat->num_header_extents_at_front;
header_extent_size = cpu_to_be32(header_extent_size);
@@ -1415,7 +1417,7 @@ ecryptfs_write_metadata_to_contents(struct ecryptfs_crypt_stat *crypt_stat,
set_fs(oldfs);
goto out;
}
- header_pages = ((crypt_stat->header_extent_size
+ header_pages = ((crypt_stat->extent_size
* crypt_stat->num_header_extents_at_front)
/ PAGE_CACHE_SIZE);
memset(page_virt, 0, PAGE_CACHE_SIZE);
@@ -1532,17 +1534,16 @@ static int parse_header_metadata(struct ecryptfs_crypt_stat *crypt_stat,
virt += 4;
memcpy(&num_header_extents_at_front, virt, 2);
num_header_extents_at_front = be16_to_cpu(num_header_extents_at_front);
- crypt_stat->header_extent_size = (int)header_extent_size;
crypt_stat->num_header_extents_at_front =
(int)num_header_extents_at_front;
- (*bytes_read) = 6;
+ (*bytes_read) = (sizeof(u32) + sizeof(u16));
if ((validate_header_size == ECRYPTFS_VALIDATE_HEADER_SIZE)
- && ((crypt_stat->header_extent_size
+ && ((crypt_stat->extent_size
* crypt_stat->num_header_extents_at_front)
< ECRYPTFS_MINIMUM_HEADER_EXTENT_SIZE)) {
rc = -EINVAL;
- ecryptfs_printk(KERN_WARNING, "Invalid header extent size: "
- "[%d]\n", crypt_stat->header_extent_size);
+ printk(KERN_WARNING "Invalid number of header extents: [%d]\n",
+ crypt_stat->num_header_extents_at_front);
}
return rc;
}
@@ -1557,8 +1558,7 @@ static int parse_header_metadata(struct ecryptfs_crypt_stat *crypt_stat,
*/
static void set_default_header_data(struct ecryptfs_crypt_stat *crypt_stat)
{
- crypt_stat->header_extent_size = 4096;
- crypt_stat->num_header_extents_at_front = 1;
+ crypt_stat->num_header_extents_at_front = 2;
}

/**
diff --git a/fs/ecryptfs/ecryptfs_kernel.h b/fs/ecryptfs/ecryptfs_kernel.h
index 78761e4..a618ab7 100644
--- a/fs/ecryptfs/ecryptfs_kernel.h
+++ b/fs/ecryptfs/ecryptfs_kernel.h
@@ -38,7 +38,7 @@
/* Version verification for shared data structures w/ userspace */
#define ECRYPTFS_VERSION_MAJOR 0x00
#define ECRYPTFS_VERSION_MINOR 0x04
-#define ECRYPTFS_SUPPORTED_FILE_VERSION 0x02
+#define ECRYPTFS_SUPPORTED_FILE_VERSION 0x03
/* These flags indicate which features are supported by the kernel
* module; userspace tools such as the mount helper read
* ECRYPTFS_VERSIONING_MASK from a sysfs handle in order to determine
@@ -67,8 +67,7 @@
#define ECRYPTFS_MAX_KEY_BYTES 64
#define ECRYPTFS_MAX_ENCRYPTED_KEY_BYTES 512
#define ECRYPTFS_DEFAULT_IV_BYTES 16
-#define ECRYPTFS_FILE_VERSION 0x02
-#define ECRYPTFS_DEFAULT_HEADER_EXTENT_SIZE 8192
+#define ECRYPTFS_FILE_VERSION 0x03
#define ECRYPTFS_DEFAULT_EXTENT_SIZE 4096
#define ECRYPTFS_MINIMUM_HEADER_EXTENT_SIZE 8192
#define ECRYPTFS_DEFAULT_MSG_CTX_ELEMS 32
@@ -201,7 +200,7 @@ ecryptfs_get_key_payload_data(struct key *key)
#define ECRYPTFS_SALT_BYTES 2
#define MAGIC_ECRYPTFS_MARKER 0x3c81b7f5
#define MAGIC_ECRYPTFS_MARKER_SIZE_BYTES 8 /* 4*2 */
-#define ECRYPTFS_FILE_SIZE_BYTES 8
+#define ECRYPTFS_FILE_SIZE_BYTES (sizeof(u64))
#define ECRYPTFS_DEFAULT_CIPHER "aes"
#define ECRYPTFS_DEFAULT_KEY_BYTES 16
#define ECRYPTFS_DEFAULT_HASH "md5"
@@ -238,7 +237,6 @@ struct ecryptfs_crypt_stat {
u32 flags;
unsigned int file_version;
size_t iv_bytes;
- size_t header_extent_size;
size_t num_header_extents_at_front;
size_t extent_size; /* Data extent size; default is 4096 */
size_t key_size;
@@ -273,6 +271,17 @@ struct ecryptfs_dentry_info {
};

/**
+ * ecryptfs_global_auth_tok - A key used to encrypt all new files under the mountpoint
+ * @flags: Status flags
+ * @mount_crypt_stat_list: These auth_toks hang off the mount-wide
+ * cryptographic context. Every time a new
+ * inode comes into existence, eCryptfs copies
+ * the auth_toks on that list to the set of
+ * auth_toks on the inode's crypt_stat
+ * @global_auth_tok_key: The key from the user's keyring for the sig
+ * @global_auth_tok: The key contents
+ * @sig: The key identifier
+ *
* ecryptfs_global_auth_tok structs refer to authentication token keys
* in the user keyring that apply to newly created files. A list of
* these objects hangs off of the mount_crypt_stat struct for any
@@ -283,15 +292,21 @@ struct ecryptfs_dentry_info {
struct ecryptfs_global_auth_tok {
#define ECRYPTFS_AUTH_TOK_INVALID 0x00000001
u32 flags;
- struct list_head mount_crypt_stat_list; /* Default auth_tok list for
- * the mount_crypt_stat */
- struct key *global_auth_tok_key; /* The key from the user's keyring for
- * the sig */
- struct ecryptfs_auth_tok *global_auth_tok; /* The key contents */
- unsigned char sig[ECRYPTFS_SIG_SIZE_HEX + 1]; /* The key identifier */
+ struct list_head mount_crypt_stat_list;
+ struct key *global_auth_tok_key;
+ struct ecryptfs_auth_tok *global_auth_tok;
+ unsigned char sig[ECRYPTFS_SIG_SIZE_HEX + 1];
};

/**
+ * ecryptfs_key_tfm - Persistent key tfm
+ * @key_tfm: crypto API handle to the key
+ * @key_size: Key size in bytes
+ * @key_tfm_mutex: Mutex to ensure only one operation in eCryptfs is
+ * using the persistent TFM at any point in time
+ * @key_tfm_list: Handle to hang this off the module-wide TFM list
+ * @cipher_name: String name for the cipher for this TFM
+ *
* Typically, eCryptfs will use the same ciphers repeatedly throughout
* the course of its operations. In order to avoid unnecessarily
* destroying and initializing the same cipher repeatedly, eCryptfs
@@ -301,7 +316,7 @@ struct ecryptfs_key_tfm {
struct crypto_blkcipher *key_tfm;
size_t key_size;
struct mutex key_tfm_mutex;
- struct list_head key_tfm_list; /* The module's tfm list */
+ struct list_head key_tfm_list;
unsigned char cipher_name[ECRYPTFS_MAX_CIPHER_NAME_SIZE + 1];
};

diff --git a/fs/ecryptfs/inode.c b/fs/ecryptfs/inode.c
index 131954b..abac91c 100644
--- a/fs/ecryptfs/inode.c
+++ b/fs/ecryptfs/inode.c
@@ -392,7 +392,8 @@ static struct dentry *ecryptfs_lookup(struct inode *dir, struct dentry *dentry,
dentry->d_sb)->mount_crypt_stat;
if (mount_crypt_stat->flags & ECRYPTFS_ENCRYPTED_VIEW_ENABLED) {
if (crypt_stat->flags & ECRYPTFS_METADATA_IN_XATTR)
- file_size = (crypt_stat->header_extent_size
+ file_size = ((crypt_stat->extent_size
+ * crypt_stat->num_header_extents_at_front)
+ i_size_read(lower_dentry->d_inode));
else
file_size = i_size_read(lower_dentry->d_inode);
@@ -722,8 +723,8 @@ upper_size_to_lower_size(struct ecryptfs_crypt_stat *crypt_stat,
{
loff_t lower_size;

- lower_size = ( crypt_stat->header_extent_size
- * crypt_stat->num_header_extents_at_front );
+ lower_size = (crypt_stat->extent_size
+ * crypt_stat->num_header_extents_at_front);
if (upper_size != 0) {
loff_t num_extents;

diff --git a/fs/ecryptfs/mmap.c b/fs/ecryptfs/mmap.c
index aaea55a..89dbbbb 100644
--- a/fs/ecryptfs/mmap.c
+++ b/fs/ecryptfs/mmap.c
@@ -301,7 +301,7 @@ static int ecryptfs_readpage(struct file *file, struct page *page)
} else if (crypt_stat->flags & ECRYPTFS_VIEW_AS_ENCRYPTED) {
if (crypt_stat->flags & ECRYPTFS_METADATA_IN_XATTR) {
int num_pages_in_header_region =
- (crypt_stat->header_extent_size
+ (crypt_stat->extent_size
/ PAGE_CACHE_SIZE);

if (page->index < num_pages_in_header_region) {
--
1.5.1.6

2007-09-17 21:50:49

by Michael Halcrow

[permalink] [raw]
Subject: [PATCH 2/11] eCryptfs: Remove assignments in if-statements

Remove assignments in if-statements.

Signed-off-by: Michael Halcrow <[email protected]>
---
fs/ecryptfs/crypto.c | 17 ++++++++------
fs/ecryptfs/file.c | 8 ++++--
fs/ecryptfs/inode.c | 35 ++++++++++++++++++------------
fs/ecryptfs/keystore.c | 55 +++++++++++++++++++++++++---------------------
fs/ecryptfs/main.c | 28 ++++++++++++++---------
fs/ecryptfs/messaging.c | 5 ++-
fs/ecryptfs/mmap.c | 5 ++-
7 files changed, 89 insertions(+), 64 deletions(-)

diff --git a/fs/ecryptfs/crypto.c b/fs/ecryptfs/crypto.c
index 3dbb21a..5d8a553 100644
--- a/fs/ecryptfs/crypto.c
+++ b/fs/ecryptfs/crypto.c
@@ -1277,8 +1277,8 @@ static int ecryptfs_read_header_region(char *data, struct dentry *dentry,
mm_segment_t oldfs;
int rc;

- if ((rc = ecryptfs_open_lower_file(&lower_file, dentry, mnt,
- O_RDONLY))) {
+ rc = ecryptfs_open_lower_file(&lower_file, dentry, mnt, O_RDONLY);
+ if (rc) {
printk(KERN_ERR
"Error opening lower_file to read header region\n");
goto out;
@@ -1289,7 +1289,8 @@ static int ecryptfs_read_header_region(char *data, struct dentry *dentry,
rc = lower_file->f_op->read(lower_file, (char __user *)data,
ECRYPTFS_DEFAULT_EXTENT_SIZE, &lower_file->f_pos);
set_fs(oldfs);
- if ((rc = ecryptfs_close_lower_file(lower_file))) {
+ rc = ecryptfs_close_lower_file(lower_file);
+ if (rc) {
printk(KERN_ERR "Error closing lower_file\n");
goto out;
}
@@ -1951,9 +1952,10 @@ ecryptfs_add_new_key_tfm(struct ecryptfs_key_tfm **key_tfm, char *cipher_name,
strncpy(tmp_tfm->cipher_name, cipher_name,
ECRYPTFS_MAX_CIPHER_NAME_SIZE);
tmp_tfm->key_size = key_size;
- if ((rc = ecryptfs_process_key_cipher(&tmp_tfm->key_tfm,
- tmp_tfm->cipher_name,
- &tmp_tfm->key_size))) {
+ rc = ecryptfs_process_key_cipher(&tmp_tfm->key_tfm,
+ tmp_tfm->cipher_name,
+ &tmp_tfm->key_size);
+ if (rc) {
printk(KERN_ERR "Error attempting to initialize key TFM "
"cipher with name = [%s]; rc = [%d]\n",
tmp_tfm->cipher_name, rc);
@@ -1988,7 +1990,8 @@ int ecryptfs_get_tfm_and_mutex_for_cipher_name(struct crypto_blkcipher **tfm,
}
}
mutex_unlock(&key_tfm_list_mutex);
- if ((rc = ecryptfs_add_new_key_tfm(&key_tfm, cipher_name, 0))) {
+ rc = ecryptfs_add_new_key_tfm(&key_tfm, cipher_name, 0);
+ if (rc) {
printk(KERN_ERR "Error adding new key_tfm to list; rc = [%d]\n",
rc);
goto out;
diff --git a/fs/ecryptfs/file.c b/fs/ecryptfs/file.c
index 12ba7e3..59c846d 100644
--- a/fs/ecryptfs/file.c
+++ b/fs/ecryptfs/file.c
@@ -230,8 +230,9 @@ static int ecryptfs_open(struct inode *inode, struct file *file)
lower_flags &= ~O_APPEND;
lower_mnt = ecryptfs_dentry_to_lower_mnt(ecryptfs_dentry);
/* Corresponding fput() in ecryptfs_release() */
- if ((rc = ecryptfs_open_lower_file(&lower_file, lower_dentry, lower_mnt,
- lower_flags))) {
+ rc = ecryptfs_open_lower_file(&lower_file, lower_dentry, lower_mnt,
+ lower_flags);
+ if (rc) {
ecryptfs_printk(KERN_ERR, "Error opening lower file\n");
goto out_puts;
}
@@ -300,7 +301,8 @@ static int ecryptfs_release(struct inode *inode, struct file *file)
struct inode *lower_inode = ecryptfs_inode_to_lower(inode);
int rc;

- if ((rc = ecryptfs_close_lower_file(lower_file))) {
+ rc = ecryptfs_close_lower_file(lower_file);
+ if (rc) {
printk(KERN_ERR "Error closing lower_file\n");
goto out;
}
diff --git a/fs/ecryptfs/inode.c b/fs/ecryptfs/inode.c
index abac91c..d70f599 100644
--- a/fs/ecryptfs/inode.c
+++ b/fs/ecryptfs/inode.c
@@ -202,8 +202,9 @@ static int ecryptfs_initialize_file(struct dentry *ecryptfs_dentry)
lower_flags = ((O_CREAT | O_TRUNC) & O_ACCMODE) | O_RDWR;
lower_mnt = ecryptfs_dentry_to_lower_mnt(ecryptfs_dentry);
/* Corresponding fput() at end of this function */
- if ((rc = ecryptfs_open_lower_file(&lower_file, lower_dentry, lower_mnt,
- lower_flags))) {
+ rc = ecryptfs_open_lower_file(&lower_file, lower_dentry, lower_mnt,
+ lower_flags);
+ if (rc) {
ecryptfs_printk(KERN_ERR,
"Error opening dentry; rc = [%i]\n", rc);
goto out;
@@ -229,7 +230,8 @@ static int ecryptfs_initialize_file(struct dentry *ecryptfs_dentry)
}
rc = grow_file(ecryptfs_dentry, lower_file, inode, lower_inode);
out_fput:
- if ((rc = ecryptfs_close_lower_file(lower_file)))
+ rc = ecryptfs_close_lower_file(lower_file);
+ if (rc)
printk(KERN_ERR "Error closing lower_file\n");
out:
return rc;
@@ -779,8 +781,9 @@ int ecryptfs_truncate(struct dentry *dentry, loff_t new_length)
lower_dentry = ecryptfs_dentry_to_lower(dentry);
/* This dget & mntget is released through fput at out_fput: */
lower_mnt = ecryptfs_dentry_to_lower_mnt(dentry);
- if ((rc = ecryptfs_open_lower_file(&lower_file, lower_dentry, lower_mnt,
- O_RDWR))) {
+ rc = ecryptfs_open_lower_file(&lower_file, lower_dentry, lower_mnt,
+ O_RDWR);
+ if (rc) {
ecryptfs_printk(KERN_ERR,
"Error opening dentry; rc = [%i]\n", rc);
goto out_free;
@@ -813,11 +816,12 @@ int ecryptfs_truncate(struct dentry *dentry, loff_t new_length)
end_pos_in_page = ((new_length - 1) & ~PAGE_CACHE_MASK);
}
if (end_pos_in_page != (PAGE_CACHE_SIZE - 1)) {
- if ((rc = ecryptfs_write_zeros(&fake_ecryptfs_file,
- index,
- (end_pos_in_page + 1),
- ((PAGE_CACHE_SIZE - 1)
- - end_pos_in_page)))) {
+ rc = ecryptfs_write_zeros(&fake_ecryptfs_file,
+ index,
+ (end_pos_in_page + 1),
+ ((PAGE_CACHE_SIZE - 1)
+ - end_pos_in_page));
+ if (rc) {
printk(KERN_ERR "Error attempting to zero out "
"the remainder of the end page on "
"reducing truncate; rc = [%d]\n", rc);
@@ -849,7 +853,8 @@ int ecryptfs_truncate(struct dentry *dentry, loff_t new_length)
= CURRENT_TIME;
mark_inode_dirty_sync(inode);
out_fput:
- if ((rc = ecryptfs_close_lower_file(lower_file)))
+ rc = ecryptfs_close_lower_file(lower_file);
+ if (rc)
printk(KERN_ERR "Error closing lower_file\n");
out_free:
if (ecryptfs_file_to_private(&fake_ecryptfs_file))
@@ -917,8 +922,9 @@ static int ecryptfs_setattr(struct dentry *dentry, struct iattr *ia)

lower_mnt = ecryptfs_dentry_to_lower_mnt(dentry);
lower_flags = O_RDONLY;
- if ((rc = ecryptfs_open_lower_file(&lower_file, lower_dentry,
- lower_mnt, lower_flags))) {
+ rc = ecryptfs_open_lower_file(&lower_file, lower_dentry,
+ lower_mnt, lower_flags);
+ if (rc) {
printk(KERN_ERR
"Error opening lower file; rc = [%d]\n", rc);
mutex_unlock(&crypt_stat->cs_mutex);
@@ -926,7 +932,8 @@ static int ecryptfs_setattr(struct dentry *dentry, struct iattr *ia)
}
mount_crypt_stat = &ecryptfs_superblock_to_private(
dentry->d_sb)->mount_crypt_stat;
- if ((rc = ecryptfs_read_metadata(dentry, lower_file))) {
+ rc = ecryptfs_read_metadata(dentry, lower_file);
+ if (rc) {
if (!(mount_crypt_stat->flags
& ECRYPTFS_PLAINTEXT_PASSTHROUGH_ENABLED)) {
rc = -EIO;
diff --git a/fs/ecryptfs/keystore.c b/fs/ecryptfs/keystore.c
index 09e2340..89d9710 100644
--- a/fs/ecryptfs/keystore.c
+++ b/fs/ecryptfs/keystore.c
@@ -436,7 +436,8 @@ decrypt_pki_encrypted_session_key(struct ecryptfs_auth_tok *auth_tok,
size_t netlink_message_length;
int rc;

- if ((rc = ecryptfs_get_auth_tok_sig(&auth_tok_sig, auth_tok))) {
+ rc = ecryptfs_get_auth_tok_sig(&auth_tok_sig, auth_tok);
+ if (rc) {
printk(KERN_ERR "Unrecognized auth tok type: [%d]\n",
auth_tok->token_type);
goto out;
@@ -569,8 +570,9 @@ parse_tag_1_packet(struct ecryptfs_crypt_stat *crypt_stat,
goto out;
}
(*new_auth_tok) = &auth_tok_list_item->auth_tok;
- if ((rc = parse_packet_length(&data[(*packet_size)], &body_size,
- &length_size))) {
+ rc = parse_packet_length(&data[(*packet_size)], &body_size,
+ &length_size);
+ if (rc) {
printk(KERN_WARNING "Error parsing packet length; "
"rc = [%d]\n", rc);
goto out_free;
@@ -702,8 +704,9 @@ parse_tag_3_packet(struct ecryptfs_crypt_stat *crypt_stat,
goto out;
}
(*new_auth_tok) = &auth_tok_list_item->auth_tok;
- if ((rc = parse_packet_length(&data[(*packet_size)], &body_size,
- &length_size))) {
+ rc = parse_packet_length(&data[(*packet_size)], &body_size,
+ &length_size);
+ if (rc) {
printk(KERN_WARNING "Error parsing packet length; rc = [%d]\n",
rc);
goto out_free;
@@ -849,8 +852,9 @@ parse_tag_11_packet(unsigned char *data, unsigned char *contents,
rc = -EINVAL;
goto out;
}
- if ((rc = parse_packet_length(&data[(*packet_size)], &body_size,
- &length_size))) {
+ rc = parse_packet_length(&data[(*packet_size)], &body_size,
+ &length_size);
+ if (rc) {
printk(KERN_WARNING "Invalid tag 11 packet format\n");
goto out;
}
@@ -1052,9 +1056,10 @@ decrypt_passphrase_encrypted_session_key(struct ecryptfs_auth_tok *auth_tok,
crypt_stat->cipher, rc);
goto out;
}
- if ((rc = virt_to_scatterlist(auth_tok->session_key.encrypted_key,
- auth_tok->session_key.encrypted_key_size,
- &src_sg, 1)) != 1) {
+ rc = virt_to_scatterlist(auth_tok->session_key.encrypted_key,
+ auth_tok->session_key.encrypted_key_size,
+ &src_sg, 1);
+ if (rc != 1) {
printk(KERN_ERR "Internal error whilst attempting to convert "
"auth_tok->session_key.encrypted_key to scatterlist; "
"expected rc = 1; got rc = [%d]. "
@@ -1064,9 +1069,10 @@ decrypt_passphrase_encrypted_session_key(struct ecryptfs_auth_tok *auth_tok,
}
auth_tok->session_key.decrypted_key_size =
auth_tok->session_key.encrypted_key_size;
- if ((rc = virt_to_scatterlist(auth_tok->session_key.decrypted_key,
- auth_tok->session_key.decrypted_key_size,
- &dst_sg, 1)) != 1) {
+ rc = virt_to_scatterlist(auth_tok->session_key.decrypted_key,
+ auth_tok->session_key.decrypted_key_size,
+ &dst_sg, 1);
+ if (rc != 1) {
printk(KERN_ERR "Internal error whilst attempting to convert "
"auth_tok->session_key.decrypted_key to scatterlist; "
"expected rc = 1; got rc = [%d]\n", rc);
@@ -1236,18 +1242,17 @@ find_next_matching_auth_tok:
"Considering cadidate auth tok:\n");
ecryptfs_dump_auth_tok(candidate_auth_tok);
}
- if ((rc = ecryptfs_get_auth_tok_sig(&candidate_auth_tok_sig,
- candidate_auth_tok))) {
+ rc = ecryptfs_get_auth_tok_sig(&candidate_auth_tok_sig,
+ candidate_auth_tok);
+ if (rc) {
printk(KERN_ERR
"Unrecognized candidate auth tok type: [%d]\n",
candidate_auth_tok->token_type);
rc = -EINVAL;
goto out_wipe_list;
}
- if ((rc = ecryptfs_find_auth_tok_for_sig(
- &matching_auth_tok, crypt_stat,
- candidate_auth_tok_sig)))
- rc = 0;
+ ecryptfs_find_auth_tok_for_sig(&matching_auth_tok, crypt_stat,
+ candidate_auth_tok_sig);
if (matching_auth_tok) {
found_auth_tok = 1;
goto found_matching_auth_tok;
@@ -1605,9 +1610,9 @@ write_tag_3_packet(char *dest, size_t *remaining_bytes,
ecryptfs_printk(KERN_DEBUG, "Session key encryption key:\n");
ecryptfs_dump_hex(session_key_encryption_key, 16);
}
- if ((rc = virt_to_scatterlist(crypt_stat->key,
- key_rec->enc_key_size, &src_sg, 1))
- != 1) {
+ rc = virt_to_scatterlist(crypt_stat->key, key_rec->enc_key_size,
+ &src_sg, 1);
+ if (rc != 1) {
ecryptfs_printk(KERN_ERR, "Error generating scatterlist "
"for crypt_stat session key; expected rc = 1; "
"got rc = [%d]. key_rec->enc_key_size = [%d]\n",
@@ -1615,9 +1620,9 @@ write_tag_3_packet(char *dest, size_t *remaining_bytes,
rc = -ENOMEM;
goto out;
}
- if ((rc = virt_to_scatterlist(key_rec->enc_key,
- key_rec->enc_key_size, &dst_sg, 1))
- != 1) {
+ rc = virt_to_scatterlist(key_rec->enc_key, key_rec->enc_key_size,
+ &dst_sg, 1);
+ if (rc != 1) {
ecryptfs_printk(KERN_ERR, "Error generating scatterlist "
"for crypt_stat encrypted session key; "
"expected rc = 1; got rc = [%d]. "
diff --git a/fs/ecryptfs/main.c b/fs/ecryptfs/main.c
index 6e71cde..967bad0 100644
--- a/fs/ecryptfs/main.c
+++ b/fs/ecryptfs/main.c
@@ -187,10 +187,11 @@ static int ecryptfs_init_global_auth_toks(
list_for_each_entry(global_auth_tok,
&mount_crypt_stat->global_auth_tok_list,
mount_crypt_stat_list) {
- if ((rc = ecryptfs_keyring_auth_tok_for_sig(
- &global_auth_tok->global_auth_tok_key,
- &global_auth_tok->global_auth_tok,
- global_auth_tok->sig))) {
+ rc = ecryptfs_keyring_auth_tok_for_sig(
+ &global_auth_tok->global_auth_tok_key,
+ &global_auth_tok->global_auth_tok,
+ global_auth_tok->sig);
+ if (rc) {
printk(KERN_ERR "Could not find valid key in user "
"session keyring for sig specified in mount "
"option: [%s]\n", global_auth_tok->sig);
@@ -354,9 +355,10 @@ static int ecryptfs_parse_options(struct super_block *sb, char *options)
if (!cipher_key_bytes_set) {
mount_crypt_stat->global_default_cipher_key_size = 0;
}
- if ((rc = ecryptfs_add_new_key_tfm(
- NULL, mount_crypt_stat->global_default_cipher_name,
- mount_crypt_stat->global_default_cipher_key_size))) {
+ rc = ecryptfs_add_new_key_tfm(
+ NULL, mount_crypt_stat->global_default_cipher_name,
+ mount_crypt_stat->global_default_cipher_key_size);
+ if (rc) {
printk(KERN_ERR "Error attempting to initialize cipher with "
"name = [%s] and key size = [%td]; rc = [%d]\n",
mount_crypt_stat->global_default_cipher_name,
@@ -364,7 +366,8 @@ static int ecryptfs_parse_options(struct super_block *sb, char *options)
rc = -EINVAL;
goto out;
}
- if ((rc = ecryptfs_init_global_auth_toks(mount_crypt_stat))) {
+ rc = ecryptfs_init_global_auth_toks(mount_crypt_stat);
+ if (rc) {
printk(KERN_WARNING "One or more global auth toks could not "
"properly register; rc = [%d]\n", rc);
}
@@ -457,7 +460,8 @@ static int ecryptfs_read_super(struct super_block *sb, const char *dev_name)
sb->s_maxbytes = lower_root->d_sb->s_maxbytes;
ecryptfs_set_dentry_lower(sb->s_root, lower_root);
ecryptfs_set_dentry_lower_mnt(sb->s_root, lower_mnt);
- if ((rc = ecryptfs_interpose(lower_root, sb->s_root, sb, 0)))
+ rc = ecryptfs_interpose(lower_root, sb->s_root, sb, 0);
+ if (rc)
goto out_free;
rc = 0;
goto out;
@@ -764,7 +768,8 @@ static int do_sysfs_registration(void)
{
int rc;

- if ((rc = subsystem_register(&ecryptfs_subsys))) {
+ rc = subsystem_register(&ecryptfs_subsys);
+ if (rc) {
printk(KERN_ERR
"Unable to register ecryptfs sysfs subsystem\n");
goto out;
@@ -795,7 +800,8 @@ static void do_sysfs_unregistration(void)
{
int rc;

- if ((rc = ecryptfs_destroy_crypto())) {
+ rc = ecryptfs_destroy_crypto();
+ if (rc) {
printk(KERN_ERR "Failure whilst attempting to destroy crypto; "
"rc = [%d]\n", rc);
}
diff --git a/fs/ecryptfs/messaging.c b/fs/ecryptfs/messaging.c
index a9d87c4..a96d341 100644
--- a/fs/ecryptfs/messaging.c
+++ b/fs/ecryptfs/messaging.c
@@ -419,8 +419,9 @@ int ecryptfs_init_messaging(unsigned int transport)
}
mutex_init(&ecryptfs_daemon_id_hash_mux);
mutex_lock(&ecryptfs_daemon_id_hash_mux);
- ecryptfs_hash_buckets = 0;
- while (ecryptfs_number_of_users >> ++ecryptfs_hash_buckets);
+ ecryptfs_hash_buckets = 1;
+ while (ecryptfs_number_of_users >> ecryptfs_hash_buckets)
+ ecryptfs_hash_buckets++;
ecryptfs_daemon_id_hash = kmalloc(sizeof(struct hlist_head)
* ecryptfs_hash_buckets, GFP_KERNEL);
if (!ecryptfs_daemon_id_hash) {
diff --git a/fs/ecryptfs/mmap.c b/fs/ecryptfs/mmap.c
index 89dbbbb..307f7ee 100644
--- a/fs/ecryptfs/mmap.c
+++ b/fs/ecryptfs/mmap.c
@@ -762,8 +762,9 @@ ecryptfs_write_zeros(struct file *file, pgoff_t index, int start, int num_zeros)
rc = PTR_ERR(tmp_page);
goto out;
}
- if ((rc = ecryptfs_prepare_write_no_truncate(file, tmp_page, start,
- (start + num_zeros)))) {
+ rc = ecryptfs_prepare_write_no_truncate(file, tmp_page, start,
+ (start + num_zeros));
+ if (rc) {
ecryptfs_printk(KERN_ERR, "Error preparing to write zero's "
"to page at index [0x%.16x]\n",
index);
--
1.5.1.6

2007-09-17 21:51:31

by Michael Halcrow

[permalink] [raw]
Subject: [PATCH 3/11] eCryptfs: read_write.c routines

Add a set of functions through which all I/O to lower files is
consolidated. This patch adds a new inode_info reference to a
persistent lower file for each eCryptfs inode; another patch later in
this series will set that up. This persistent lower file is what the
read_write.c functions use to call vfs_read() and vfs_write() on the
lower filesystem, so even when reads and writes come in through
aops->readpage and aops->writepage, we can satisfy them without
resorting to direct access to the lower inode's address space.
Several function declarations are going to be changing with this
patchset. For now, in order to keep from breaking the build, I am
putting dummy parameters in for those functions.

Signed-off-by: Michael Halcrow <[email protected]>
---
fs/ecryptfs/Makefile | 2 +-
fs/ecryptfs/ecryptfs_kernel.h | 18 ++
fs/ecryptfs/mmap.c | 2 +-
fs/ecryptfs/read_write.c | 359 +++++++++++++++++++++++++++++++++++++++++
4 files changed, 379 insertions(+), 2 deletions(-)
create mode 100644 fs/ecryptfs/read_write.c

diff --git a/fs/ecryptfs/Makefile b/fs/ecryptfs/Makefile
index 1f11072..7688570 100644
--- a/fs/ecryptfs/Makefile
+++ b/fs/ecryptfs/Makefile
@@ -4,4 +4,4 @@

obj-$(CONFIG_ECRYPT_FS) += ecryptfs.o

-ecryptfs-objs := dentry.o file.o inode.o main.o super.o mmap.o crypto.o keystore.o messaging.o netlink.o debug.o
+ecryptfs-objs := dentry.o file.o inode.o main.o super.o mmap.o read_write.o crypto.o keystore.o messaging.o netlink.o debug.o
diff --git a/fs/ecryptfs/ecryptfs_kernel.h b/fs/ecryptfs/ecryptfs_kernel.h
index a618ab7..e6a68a8 100644
--- a/fs/ecryptfs/ecryptfs_kernel.h
+++ b/fs/ecryptfs/ecryptfs_kernel.h
@@ -260,6 +260,8 @@ struct ecryptfs_crypt_stat {
struct ecryptfs_inode_info {
struct inode vfs_inode;
struct inode *wii_inode;
+ struct file *lower_file;
+ struct mutex lower_file_mutex;
struct ecryptfs_crypt_stat crypt_stat;
};

@@ -653,5 +655,21 @@ int ecryptfs_keyring_auth_tok_for_sig(struct key **auth_tok_key,
char *sig);
int ecryptfs_write_zeros(struct file *file, pgoff_t index, int start,
int num_zeros);
+int ecryptfs_write_lower(struct inode *ecryptfs_inode, char *data,
+ loff_t offset, size_t size);
+int ecryptfs_write_lower_page_segment(struct inode *ecryptfs_inode,
+ struct page *page_for_lower,
+ size_t offset_in_page, size_t size);
+int ecryptfs_write(struct file *ecryptfs_file, char *data, loff_t offset,
+ size_t size);
+int ecryptfs_read_lower(char *data, loff_t offset, size_t size,
+ struct inode *ecryptfs_inode);
+int ecryptfs_read_lower_page_segment(struct page *page_for_ecryptfs,
+ pgoff_t page_index,
+ size_t offset_in_page, size_t size,
+ struct inode *ecryptfs_inode);
+int ecryptfs_read(char *data, loff_t offset, size_t size,
+ struct file *ecryptfs_file);
+struct page *ecryptfs_get1page(struct file *file, loff_t index);

#endif /* #ifndef ECRYPTFS_KERNEL_H */
diff --git a/fs/ecryptfs/mmap.c b/fs/ecryptfs/mmap.c
index 307f7ee..0c53320 100644
--- a/fs/ecryptfs/mmap.c
+++ b/fs/ecryptfs/mmap.c
@@ -44,7 +44,7 @@ struct kmem_cache *ecryptfs_lower_page_cache;
* Returns unlocked and up-to-date page (if ok), with increased
* refcnt.
*/
-static struct page *ecryptfs_get1page(struct file *file, int index)
+struct page *ecryptfs_get1page(struct file *file, loff_t index)
{
struct dentry *dentry;
struct inode *inode;
diff --git a/fs/ecryptfs/read_write.c b/fs/ecryptfs/read_write.c
new file mode 100644
index 0000000..e59c94a
--- /dev/null
+++ b/fs/ecryptfs/read_write.c
@@ -0,0 +1,359 @@
+/**
+ * eCryptfs: Linux filesystem encryption layer
+ *
+ * Copyright (C) 2007 International Business Machines Corp.
+ * Author(s): Michael A. Halcrow <[email protected]>
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License as
+ * published by the Free Software Foundation; either version 2 of the
+ * License, or (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful, but
+ * WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA
+ * 02111-1307, USA.
+ */
+
+#include <linux/fs.h>
+#include <linux/pagemap.h>
+#include "ecryptfs_kernel.h"
+
+/**
+ * ecryptfs_write_lower
+ * @ecryptfs_inode: The eCryptfs inode
+ * @data: Data to write
+ * @offset: Byte offset in the lower file to which to write the data
+ * @size: Number of bytes from @data to write at @offset in the lower
+ * file
+ *
+ * Write data to the lower file.
+ *
+ * Returns zero on success; non-zero on error
+ */
+int ecryptfs_write_lower(struct inode *ecryptfs_inode, char *data,
+ loff_t offset, size_t size)
+{
+ struct ecryptfs_inode_info *inode_info;
+ ssize_t octets_written;
+ mm_segment_t fs_save;
+ int rc = 0;
+
+ inode_info = ecryptfs_inode_to_private(ecryptfs_inode);
+ mutex_lock(&inode_info->lower_file_mutex);
+ BUG_ON(!inode_info->lower_file);
+ inode_info->lower_file->f_pos = offset;
+ fs_save = get_fs();
+ set_fs(get_ds());
+ octets_written = vfs_write(inode_info->lower_file, data, size,
+ &inode_info->lower_file->f_pos);
+ set_fs(fs_save);
+ if (octets_written < 0) {
+ printk(KERN_ERR "%s: octets_written = [%td]; "
+ "expected [%td]\n", __FUNCTION__, octets_written, size);
+ rc = -EINVAL;
+ }
+ mutex_unlock(&inode_info->lower_file_mutex);
+ mark_inode_dirty_sync(ecryptfs_inode);
+ return rc;
+}
+
+/**
+ * ecryptfs_write_lower_page_segment
+ * @ecryptfs_inode: The eCryptfs inode
+ * @page_for_lower: The page containing the data to be written to the
+ * lower file
+ * @offset_in_page: The offset in the @page_for_lower from which to
+ * start writing the data
+ * @size: The amount of data from @page_for_lower to write to the
+ * lower file
+ *
+ * Determines the byte offset in the file for the given page and
+ * offset within the page, maps the page, and makes the call to write
+ * the contents of @page_for_lower to the lower inode.
+ *
+ * Returns zero on success; non-zero otherwise
+ */
+int ecryptfs_write_lower_page_segment(struct inode *ecryptfs_inode,
+ struct page *page_for_lower,
+ size_t offset_in_page, size_t size)
+{
+ char *virt;
+ loff_t offset;
+ int rc;
+
+ offset = (page_for_lower->index << PAGE_CACHE_SHIFT) + offset_in_page;
+ virt = kmap(page_for_lower);
+ rc = ecryptfs_write_lower(ecryptfs_inode, virt, offset, size);
+ kunmap(page_for_lower);
+ return rc;
+}
+
+/**
+ * ecryptfs_write
+ * @ecryptfs_file: The eCryptfs file into which to write
+ * @data: Virtual address where data to write is located
+ * @offset: Offset in the eCryptfs file at which to begin writing the
+ * data from @data
+ * @size: The number of bytes to write from @data
+ *
+ * Write an arbitrary amount of data to an arbitrary location in the
+ * eCryptfs inode page cache. This is done on a page-by-page, and then
+ * by an extent-by-extent, basis; individual extents are encrypted and
+ * written to the lower page cache (via VFS writes). This function
+ * takes care of all the address translation to locations in the lower
+ * filesystem; it also handles truncate events, writing out zeros
+ * where necessary.
+ *
+ * Returns zero on success; non-zero otherwise
+ */
+int ecryptfs_write(struct file *ecryptfs_file, char *data, loff_t offset,
+ size_t size)
+{
+ struct page *ecryptfs_page;
+ char *ecryptfs_page_virt;
+ u64 ecryptfs_file_size = i_size_read(ecryptfs_file->f_dentry->d_inode);
+ loff_t data_offset = 0;
+ loff_t pos;
+ int rc = 0;
+
+ if (offset > ecryptfs_file_size)
+ pos = ecryptfs_file_size;
+ else
+ pos = offset;
+ while (pos < (offset + size)) {
+ pgoff_t ecryptfs_page_idx = (pos >> PAGE_CACHE_SHIFT);
+ size_t start_offset_in_page = (pos & ~PAGE_CACHE_MASK);
+ size_t num_bytes = (PAGE_CACHE_SIZE - start_offset_in_page);
+ size_t total_remaining_bytes = ((offset + size) - pos);
+
+ if (num_bytes > total_remaining_bytes)
+ num_bytes = total_remaining_bytes;
+ if (pos < offset) {
+ size_t total_remaining_zeros = (offset - pos);
+
+ if (num_bytes > total_remaining_zeros)
+ num_bytes = total_remaining_zeros;
+ }
+ ecryptfs_page = ecryptfs_get1page(ecryptfs_file,
+ ecryptfs_page_idx);
+ if (IS_ERR(ecryptfs_page)) {
+ rc = PTR_ERR(ecryptfs_page);
+ printk(KERN_ERR "%s: Error getting page at "
+ "index [%ld] from eCryptfs inode "
+ "mapping; rc = [%d]\n", __FUNCTION__,
+ ecryptfs_page_idx, rc);
+ goto out;
+ }
+ if (start_offset_in_page) {
+ /* Read in the page from the lower
+ * into the eCryptfs inode page cache,
+ * decrypting */
+ if ((rc = ecryptfs_decrypt_page(NULL, /* placeholder for git-bisect */
+ ecryptfs_page))) {
+ printk(KERN_ERR "%s: Error decrypting "
+ "page; rc = [%d]\n",
+ __FUNCTION__, rc);
+ page_cache_release(ecryptfs_page);
+ goto out;
+ }
+ }
+ ecryptfs_page_virt = kmap_atomic(ecryptfs_page, KM_USER0);
+ if (pos >= offset) {
+ memcpy(((char *)ecryptfs_page_virt
+ + start_offset_in_page),
+ (data + data_offset), num_bytes);
+ data_offset += num_bytes;
+ } else {
+ /* We are extending past the previous end of the file.
+ * Fill in zero values up to the start of where we
+ * will be writing data. */
+ memset(((char *)ecryptfs_page_virt
+ + start_offset_in_page), 0, num_bytes);
+ }
+ kunmap_atomic(ecryptfs_page_virt, KM_USER0);
+ flush_dcache_page(ecryptfs_page);
+ rc = ecryptfs_encrypt_page(NULL /* placeholder for git-bisect */);
+ if (rc) {
+ printk(KERN_ERR "%s: Error encrypting "
+ "page; rc = [%d]\n", __FUNCTION__, rc);
+ page_cache_release(ecryptfs_page);
+ goto out;
+ }
+ page_cache_release(ecryptfs_page);
+ pos += num_bytes;
+ }
+ if ((offset + size) > ecryptfs_file_size) {
+ i_size_write(ecryptfs_file->f_dentry->d_inode, (offset + size));
+ rc = ecryptfs_write_inode_size_to_metadata(NULL, NULL, NULL,
+ NULL, 0); /* placeholders for git-bisect */
+ if (rc) {
+ printk(KERN_ERR "Problem with "
+ "ecryptfs_write_inode_size_to_metadata; "
+ "rc = [%d]\n", rc);
+ goto out;
+ }
+ }
+out:
+ return rc;
+}
+
+/**
+ * ecryptfs_read_lower
+ * @data: The read data is stored here by this function
+ * @offset: Byte offset in the lower file from which to read the data
+ * @size: Number of bytes to read from @offset of the lower file and
+ * store into @data
+ * @ecryptfs_inode: The eCryptfs inode
+ *
+ * Read @size bytes of data at byte offset @offset from the lower
+ * inode into memory location @data.
+ *
+ * Returns zero on success; non-zero on error
+ */
+int ecryptfs_read_lower(char *data, loff_t offset, size_t size,
+ struct inode *ecryptfs_inode)
+{
+ struct ecryptfs_inode_info *inode_info =
+ ecryptfs_inode_to_private(ecryptfs_inode);
+ ssize_t octets_read;
+ mm_segment_t fs_save;
+ size_t i;
+ int rc = 0;
+
+ mutex_lock(&inode_info->lower_file_mutex);
+ BUG_ON(!inode_info->lower_file);
+ inode_info->lower_file->f_pos = offset;
+ fs_save = get_fs();
+ set_fs(get_ds());
+ octets_read = vfs_read(inode_info->lower_file, data, size,
+ &inode_info->lower_file->f_pos);
+ set_fs(fs_save);
+ if (octets_read < 0) {
+ printk(KERN_ERR "%s: octets_read = [%td]; "
+ "expected [%td]\n", __FUNCTION__, octets_read, size);
+ rc = -EINVAL;
+ }
+ mutex_unlock(&inode_info->lower_file_mutex);
+ for (i = 0; i < size; i += PAGE_CACHE_SIZE) {
+ struct page *data_page;
+
+ data_page = virt_to_page(data + i);
+ flush_dcache_page(data_page);
+ if (rc)
+ ClearPageUptodate(data_page);
+ else
+ SetPageUptodate(data_page);
+ }
+ return rc;
+}
+
+/**
+ * ecryptfs_read_lower_page_segment
+ * @page_for_ecryptfs: The page into which data for eCryptfs will be
+ * written
+ * @offset_in_page: Offset in @page_for_ecryptfs from which to start
+ * writing
+ * @size: The number of bytes to write into @page_for_ecryptfs
+ * @ecryptfs_inode: The eCryptfs inode
+ *
+ * Determines the byte offset in the file for the given page and
+ * offset within the page, maps the page, and makes the call to read
+ * the contents of @page_for_ecryptfs from the lower inode.
+ *
+ * Returns zero on success; non-zero otherwise
+ */
+int ecryptfs_read_lower_page_segment(struct page *page_for_ecryptfs,
+ pgoff_t page_index,
+ size_t offset_in_page, size_t size,
+ struct inode *ecryptfs_inode)
+{
+ char *virt;
+ loff_t offset;
+ int rc;
+
+ offset = ((page_index << PAGE_CACHE_SHIFT) + offset_in_page);
+ virt = kmap(page_for_ecryptfs);
+ rc = ecryptfs_read_lower(virt, offset, size, ecryptfs_inode);
+ kunmap(page_for_ecryptfs);
+ return rc;
+}
+
+/**
+ * ecryptfs_read
+ * @data: The virtual address into which to write the data read (and
+ * possibly decrypted) from the lower file
+ * @offset: The offset in the decrypted view of the file from which to
+ * read into @data
+ * @size: The number of bytes to read into @data
+ * @ecryptfs_file: The eCryptfs file from which to read
+ *
+ * Read an arbitrary amount of data from an arbitrary location in the
+ * eCryptfs page cache. This is done on an extent-by-extent basis;
+ * individual extents are decrypted and read from the lower page
+ * cache (via VFS reads). This function takes care of all the
+ * address translation to locations in the lower filesystem.
+ *
+ * Returns zero on success; non-zero otherwise
+ */
+int ecryptfs_read(char *data, loff_t offset, size_t size,
+ struct file *ecryptfs_file)
+{
+ struct page *ecryptfs_page;
+ char *ecryptfs_page_virt;
+ u64 ecryptfs_file_size = i_size_read(ecryptfs_file->f_dentry->d_inode);
+ loff_t data_offset = 0;
+ loff_t pos;
+ int rc = 0;
+
+ if ((offset + size) > ecryptfs_file_size) {
+ rc = -EINVAL;
+ printk(KERN_ERR "%s: Attempt to read data past the end of the "
+ "file; offset = [%lld]; size = [%td]; "
+ "ecryptfs_file_size = [%lld]\n",
+ __FUNCTION__, offset, size, ecryptfs_file_size);
+ goto out;
+ }
+ pos = offset;
+ while (pos < (offset + size)) {
+ pgoff_t ecryptfs_page_idx = (pos >> PAGE_CACHE_SHIFT);
+ size_t start_offset_in_page = (pos & ~PAGE_CACHE_MASK);
+ size_t num_bytes = (PAGE_CACHE_SIZE - start_offset_in_page);
+ size_t total_remaining_bytes = ((offset + size) - pos);
+
+ if (num_bytes > total_remaining_bytes)
+ num_bytes = total_remaining_bytes;
+ ecryptfs_page = ecryptfs_get1page(ecryptfs_file,
+ ecryptfs_page_idx);
+ if (IS_ERR(ecryptfs_page)) {
+ rc = PTR_ERR(ecryptfs_page);
+ printk(KERN_ERR "%s: Error getting page at "
+ "index [%ld] from eCryptfs inode "
+ "mapping; rc = [%d]\n", __FUNCTION__,
+ ecryptfs_page_idx, rc);
+ goto out;
+ }
+ rc = ecryptfs_decrypt_page(NULL /* placeholder for git-bisect */, ecryptfs_page);
+ if (rc) {
+ printk(KERN_ERR "%s: Error decrypting "
+ "page; rc = [%d]\n", __FUNCTION__, rc);
+ page_cache_release(ecryptfs_page);
+ goto out;
+ }
+ ecryptfs_page_virt = kmap_atomic(ecryptfs_page, KM_USER0);
+ memcpy((data + data_offset),
+ ((char *)ecryptfs_page_virt + start_offset_in_page),
+ num_bytes);
+ kunmap_atomic(ecryptfs_page_virt, KM_USER0);
+ page_cache_release(ecryptfs_page);
+ pos += num_bytes;
+ data_offset += num_bytes;
+ }
+out:
+ return rc;
+}
--
1.5.1.6

2007-09-17 21:52:09

by Michael Halcrow

[permalink] [raw]
Subject: [PATCH 4/11] eCryptfs: Replace encrypt, decrypt, and inode size write

Replace page encryption and decryption routines and inode size write
routine with versions that utilize the read_write.c functions.

Signed-off-by: Michael Halcrow <[email protected]>
---
fs/ecryptfs/crypto.c | 427 ++++++++++++++++++++++------------------
fs/ecryptfs/ecryptfs_kernel.h | 14 +-
fs/ecryptfs/inode.c | 12 +-
fs/ecryptfs/mmap.c | 131 ++++---------
fs/ecryptfs/read_write.c | 12 +-
5 files changed, 290 insertions(+), 306 deletions(-)

diff --git a/fs/ecryptfs/crypto.c b/fs/ecryptfs/crypto.c
index 5d8a553..b829d3c 100644
--- a/fs/ecryptfs/crypto.c
+++ b/fs/ecryptfs/crypto.c
@@ -467,8 +467,91 @@ out:
}

/**
+ * ecryptfs_lower_offset_for_extent
+ *
+ * Convert an eCryptfs page index into a lower byte offset
+ */
+void ecryptfs_lower_offset_for_extent(loff_t *offset, loff_t extent_num,
+ struct ecryptfs_crypt_stat *crypt_stat)
+{
+ (*offset) = ((crypt_stat->extent_size
+ * crypt_stat->num_header_extents_at_front)
+ + (crypt_stat->extent_size * extent_num));
+}
+
+/**
+ * ecryptfs_encrypt_extent
+ * @enc_extent_page: Allocated page into which to encrypt the data in
+ * @page
+ * @crypt_stat: crypt_stat containing cryptographic context for the
+ * encryption operation
+ * @page: Page containing plaintext data extent to encrypt
+ * @extent_offset: Page extent offset for use in generating IV
+ *
+ * Encrypts one extent of data.
+ *
+ * Return zero on success; non-zero otherwise
+ */
+static int ecryptfs_encrypt_extent(struct page *enc_extent_page,
+ struct ecryptfs_crypt_stat *crypt_stat,
+ struct page *page,
+ unsigned long extent_offset)
+{
+ unsigned long extent_base;
+ char extent_iv[ECRYPTFS_MAX_IV_BYTES];
+ int rc;
+
+ extent_base = (page->index
+ * (PAGE_CACHE_SIZE / crypt_stat->extent_size));
+ rc = ecryptfs_derive_iv(extent_iv, crypt_stat,
+ (extent_base + extent_offset));
+ if (rc) {
+ ecryptfs_printk(KERN_ERR, "Error attempting to "
+ "derive IV for extent [0x%.16x]; "
+ "rc = [%d]\n", (extent_base + extent_offset),
+ rc);
+ goto out;
+ }
+ if (unlikely(ecryptfs_verbosity > 0)) {
+ ecryptfs_printk(KERN_DEBUG, "Encrypting extent "
+ "with iv:\n");
+ ecryptfs_dump_hex(extent_iv, crypt_stat->iv_bytes);
+ ecryptfs_printk(KERN_DEBUG, "First 8 bytes before "
+ "encryption:\n");
+ ecryptfs_dump_hex((char *)
+ (page_address(page)
+ + (extent_offset * crypt_stat->extent_size)),
+ 8);
+ }
+ rc = ecryptfs_encrypt_page_offset(crypt_stat, enc_extent_page, 0,
+ page, (extent_offset
+ * crypt_stat->extent_size),
+ crypt_stat->extent_size, extent_iv);
+ if (rc < 0) {
+ printk(KERN_ERR "%s: Error attempting to encrypt page with "
+ "page->index = [%ld], extent_offset = [%ld]; "
+ "rc = [%d]\n", __FUNCTION__, page->index, extent_offset,
+ rc);
+ goto out;
+ }
+ rc = 0;
+ if (unlikely(ecryptfs_verbosity > 0)) {
+ ecryptfs_printk(KERN_DEBUG, "Encrypt extent [0x%.16x]; "
+ "rc = [%d]\n", (extent_base + extent_offset),
+ rc);
+ ecryptfs_printk(KERN_DEBUG, "First 8 bytes after "
+ "encryption:\n");
+ ecryptfs_dump_hex((char *)(page_address(enc_extent_page)), 8);
+ }
+out:
+ return rc;
+}
+
+/**
* ecryptfs_encrypt_page
- * @ctx: The context of the page
+ * @page: Page mapped from the eCryptfs inode for the file; contains
+ * decrypted content that needs to be encrypted (to a temporary
+ * page; not in place) and written out to the lower file
*
* Encrypt an eCryptfs page. This is done on a per-extent basis. Note
* that eCryptfs pages may straddle the lower pages -- for instance,
@@ -478,128 +561,121 @@ out:
* file, 24K of page 0 of the lower file will be read and decrypted,
* and then 8K of page 1 of the lower file will be read and decrypted.
*
- * The actual operations performed on each page depends on the
- * contents of the ecryptfs_page_crypt_context struct.
- *
* Returns zero on success; negative on error
*/
-int ecryptfs_encrypt_page(struct ecryptfs_page_crypt_context *ctx)
+int ecryptfs_encrypt_page(struct page *page)
{
- char extent_iv[ECRYPTFS_MAX_IV_BYTES];
- unsigned long base_extent;
- unsigned long extent_offset = 0;
- unsigned long lower_page_idx = 0;
- unsigned long prior_lower_page_idx = 0;
- struct page *lower_page;
- struct inode *lower_inode;
- struct ecryptfs_inode_info *inode_info;
+ struct inode *ecryptfs_inode;
struct ecryptfs_crypt_stat *crypt_stat;
+ char *enc_extent_virt = NULL;
+ struct page *enc_extent_page;
+ loff_t extent_offset;
int rc = 0;
- int lower_byte_offset = 0;
- int orig_byte_offset = 0;
- int num_extents_per_page;
-#define ECRYPTFS_PAGE_STATE_UNREAD 0
-#define ECRYPTFS_PAGE_STATE_READ 1
-#define ECRYPTFS_PAGE_STATE_MODIFIED 2
-#define ECRYPTFS_PAGE_STATE_WRITTEN 3
- int page_state;
-
- lower_inode = ecryptfs_inode_to_lower(ctx->page->mapping->host);
- inode_info = ecryptfs_inode_to_private(ctx->page->mapping->host);
- crypt_stat = &inode_info->crypt_stat;
+
+ ecryptfs_inode = page->mapping->host;
+ crypt_stat =
+ &(ecryptfs_inode_to_private(ecryptfs_inode)->crypt_stat);
if (!(crypt_stat->flags & ECRYPTFS_ENCRYPTED)) {
- rc = ecryptfs_copy_page_to_lower(ctx->page, lower_inode,
- ctx->param.lower_file);
+ rc = ecryptfs_write_lower_page_segment(ecryptfs_inode, page,
+ 0, PAGE_CACHE_SIZE);
if (rc)
- ecryptfs_printk(KERN_ERR, "Error attempting to copy "
- "page at index [0x%.16x]\n",
- ctx->page->index);
+ printk(KERN_ERR "%s: Error attempting to copy "
+ "page at index [%ld]\n", __FUNCTION__,
+ page->index);
goto out;
}
- num_extents_per_page = PAGE_CACHE_SIZE / crypt_stat->extent_size;
- base_extent = (ctx->page->index * num_extents_per_page);
- page_state = ECRYPTFS_PAGE_STATE_UNREAD;
- while (extent_offset < num_extents_per_page) {
- ecryptfs_extent_to_lwr_pg_idx_and_offset(
- &lower_page_idx, &lower_byte_offset, crypt_stat,
- (base_extent + extent_offset));
- if (prior_lower_page_idx != lower_page_idx
- && page_state == ECRYPTFS_PAGE_STATE_MODIFIED) {
- rc = ecryptfs_write_out_page(ctx, lower_page,
- lower_inode,
- orig_byte_offset,
- (PAGE_CACHE_SIZE
- - orig_byte_offset));
- if (rc) {
- ecryptfs_printk(KERN_ERR, "Error attempting "
- "to write out page; rc = [%d]"
- "\n", rc);
- goto out;
- }
- page_state = ECRYPTFS_PAGE_STATE_WRITTEN;
- }
- if (page_state == ECRYPTFS_PAGE_STATE_UNREAD
- || page_state == ECRYPTFS_PAGE_STATE_WRITTEN) {
- rc = ecryptfs_read_in_page(ctx, &lower_page,
- lower_inode, lower_page_idx,
- lower_byte_offset);
- if (rc) {
- ecryptfs_printk(KERN_ERR, "Error attempting "
- "to read in lower page with "
- "index [0x%.16x]; rc = [%d]\n",
- lower_page_idx, rc);
- goto out;
- }
- orig_byte_offset = lower_byte_offset;
- prior_lower_page_idx = lower_page_idx;
- page_state = ECRYPTFS_PAGE_STATE_READ;
- }
- BUG_ON(!(page_state == ECRYPTFS_PAGE_STATE_MODIFIED
- || page_state == ECRYPTFS_PAGE_STATE_READ));
- rc = ecryptfs_derive_iv(extent_iv, crypt_stat,
- (base_extent + extent_offset));
+ enc_extent_virt = kmalloc(PAGE_CACHE_SIZE, GFP_USER);
+ if (!enc_extent_virt) {
+ rc = -ENOMEM;
+ ecryptfs_printk(KERN_ERR, "Error allocating memory for "
+ "encrypted extent\n");
+ goto out;
+ }
+ enc_extent_page = virt_to_page(enc_extent_virt);
+ for (extent_offset = 0;
+ extent_offset < (PAGE_CACHE_SIZE / crypt_stat->extent_size);
+ extent_offset++) {
+ loff_t offset;
+
+ rc = ecryptfs_encrypt_extent(enc_extent_page, crypt_stat, page,
+ extent_offset);
if (rc) {
- ecryptfs_printk(KERN_ERR, "Error attempting to "
- "derive IV for extent [0x%.16x]; "
- "rc = [%d]\n",
- (base_extent + extent_offset), rc);
+ printk(KERN_ERR "%s: Error encrypting extent; "
+ "rc = [%d]\n", __FUNCTION__, rc);
goto out;
}
- if (unlikely(ecryptfs_verbosity > 0)) {
- ecryptfs_printk(KERN_DEBUG, "Encrypting extent "
- "with iv:\n");
- ecryptfs_dump_hex(extent_iv, crypt_stat->iv_bytes);
- ecryptfs_printk(KERN_DEBUG, "First 8 bytes before "
- "encryption:\n");
- ecryptfs_dump_hex((char *)
- (page_address(ctx->page)
- + (extent_offset
- * crypt_stat->extent_size)), 8);
- }
- rc = ecryptfs_encrypt_page_offset(
- crypt_stat, lower_page, lower_byte_offset, ctx->page,
- (extent_offset * crypt_stat->extent_size),
- crypt_stat->extent_size, extent_iv);
- ecryptfs_printk(KERN_DEBUG, "Encrypt extent [0x%.16x]; "
- "rc = [%d]\n",
- (base_extent + extent_offset), rc);
- if (unlikely(ecryptfs_verbosity > 0)) {
- ecryptfs_printk(KERN_DEBUG, "First 8 bytes after "
- "encryption:\n");
- ecryptfs_dump_hex((char *)(page_address(lower_page)
- + lower_byte_offset), 8);
+ ecryptfs_lower_offset_for_extent(
+ &offset, ((page->index * (PAGE_CACHE_SIZE
+ / crypt_stat->extent_size))
+ + extent_offset), crypt_stat);
+ rc = ecryptfs_write_lower(ecryptfs_inode, enc_extent_virt,
+ offset, crypt_stat->extent_size);
+ if (rc) {
+ ecryptfs_printk(KERN_ERR, "Error attempting "
+ "to write lower page; rc = [%d]"
+ "\n", rc);
+ goto out;
}
- page_state = ECRYPTFS_PAGE_STATE_MODIFIED;
extent_offset++;
}
- BUG_ON(orig_byte_offset != 0);
- rc = ecryptfs_write_out_page(ctx, lower_page, lower_inode, 0,
- (lower_byte_offset
- + crypt_stat->extent_size));
+out:
+ kfree(enc_extent_virt);
+ return rc;
+}
+
+static int ecryptfs_decrypt_extent(struct page *page,
+ struct ecryptfs_crypt_stat *crypt_stat,
+ struct page *enc_extent_page,
+ unsigned long extent_offset)
+{
+ unsigned long extent_base;
+ char extent_iv[ECRYPTFS_MAX_IV_BYTES];
+ int rc;
+
+ extent_base = (page->index
+ * (PAGE_CACHE_SIZE / crypt_stat->extent_size));
+ rc = ecryptfs_derive_iv(extent_iv, crypt_stat,
+ (extent_base + extent_offset));
if (rc) {
- ecryptfs_printk(KERN_ERR, "Error attempting to write out "
- "page; rc = [%d]\n", rc);
- goto out;
+ ecryptfs_printk(KERN_ERR, "Error attempting to "
+ "derive IV for extent [0x%.16x]; "
+ "rc = [%d]\n", (extent_base + extent_offset),
+ rc);
+ goto out;
+ }
+ if (unlikely(ecryptfs_verbosity > 0)) {
+ ecryptfs_printk(KERN_DEBUG, "Decrypting extent "
+ "with iv:\n");
+ ecryptfs_dump_hex(extent_iv, crypt_stat->iv_bytes);
+ ecryptfs_printk(KERN_DEBUG, "First 8 bytes before "
+ "decryption:\n");
+ ecryptfs_dump_hex((char *)
+ (page_address(enc_extent_page)
+ + (extent_offset * crypt_stat->extent_size)),
+ 8);
+ }
+ rc = ecryptfs_decrypt_page_offset(crypt_stat, page,
+ (extent_offset
+ * crypt_stat->extent_size),
+ enc_extent_page, 0,
+ crypt_stat->extent_size, extent_iv);
+ if (rc < 0) {
+ printk(KERN_ERR "%s: Error attempting to decrypt to page with "
+ "page->index = [%ld], extent_offset = [%ld]; "
+ "rc = [%d]\n", __FUNCTION__, page->index, extent_offset,
+ rc);
+ goto out;
+ }
+ rc = 0;
+ if (unlikely(ecryptfs_verbosity > 0)) {
+ ecryptfs_printk(KERN_DEBUG, "Decrypt extent [0x%.16x]; "
+ "rc = [%d]\n", (extent_base + extent_offset),
+ rc);
+ ecryptfs_printk(KERN_DEBUG, "First 8 bytes after "
+ "decryption:\n");
+ ecryptfs_dump_hex((char *)(page_address(page)
+ + (extent_offset
+ * crypt_stat->extent_size)), 8);
}
out:
return rc;
@@ -607,8 +683,9 @@ out:

/**
* ecryptfs_decrypt_page
- * @file: The ecryptfs file
- * @page: The page in ecryptfs to decrypt
+ * @page: Page mapped from the eCryptfs inode for the file; data read
+ * and decrypted from the lower file will be written into this
+ * page
*
* Decrypt an eCryptfs page. This is done on a per-extent basis. Note
* that eCryptfs pages may straddle the lower pages -- for instance,
@@ -620,103 +697,69 @@ out:
*
* Returns zero on success; negative on error
*/
-int ecryptfs_decrypt_page(struct file *file, struct page *page)
+int ecryptfs_decrypt_page(struct page *page)
{
- char extent_iv[ECRYPTFS_MAX_IV_BYTES];
- unsigned long base_extent;
- unsigned long extent_offset = 0;
- unsigned long lower_page_idx = 0;
- unsigned long prior_lower_page_idx = 0;
- struct page *lower_page;
- char *lower_page_virt = NULL;
- struct inode *lower_inode;
+ struct inode *ecryptfs_inode;
struct ecryptfs_crypt_stat *crypt_stat;
+ char *enc_extent_virt = NULL;
+ struct page *enc_extent_page;
+ unsigned long extent_offset;
int rc = 0;
- int byte_offset;
- int num_extents_per_page;
- int page_state;

- crypt_stat = &(ecryptfs_inode_to_private(
- page->mapping->host)->crypt_stat);
- lower_inode = ecryptfs_inode_to_lower(page->mapping->host);
+ ecryptfs_inode = page->mapping->host;
+ crypt_stat =
+ &(ecryptfs_inode_to_private(ecryptfs_inode)->crypt_stat);
if (!(crypt_stat->flags & ECRYPTFS_ENCRYPTED)) {
- rc = ecryptfs_do_readpage(file, page, page->index);
+ rc = ecryptfs_read_lower_page_segment(page, page->index, 0,
+ PAGE_CACHE_SIZE,
+ ecryptfs_inode);
if (rc)
- ecryptfs_printk(KERN_ERR, "Error attempting to copy "
- "page at index [0x%.16x]\n",
- page->index);
- goto out;
+ printk(KERN_ERR "%s: Error attempting to copy "
+ "page at index [%ld]\n", __FUNCTION__,
+ page->index);
+ goto out_clear_uptodate;
}
- num_extents_per_page = PAGE_CACHE_SIZE / crypt_stat->extent_size;
- base_extent = (page->index * num_extents_per_page);
- lower_page_virt = kmem_cache_alloc(ecryptfs_lower_page_cache,
- GFP_KERNEL);
- if (!lower_page_virt) {
+ enc_extent_virt = kmalloc(PAGE_CACHE_SIZE, GFP_USER);
+ if (!enc_extent_virt) {
rc = -ENOMEM;
- ecryptfs_printk(KERN_ERR, "Error getting page for encrypted "
- "lower page(s)\n");
- goto out;
- }
- lower_page = virt_to_page(lower_page_virt);
- page_state = ECRYPTFS_PAGE_STATE_UNREAD;
- while (extent_offset < num_extents_per_page) {
- ecryptfs_extent_to_lwr_pg_idx_and_offset(
- &lower_page_idx, &byte_offset, crypt_stat,
- (base_extent + extent_offset));
- if (prior_lower_page_idx != lower_page_idx
- || page_state == ECRYPTFS_PAGE_STATE_UNREAD) {
- rc = ecryptfs_do_readpage(file, lower_page,
- lower_page_idx);
- if (rc) {
- ecryptfs_printk(KERN_ERR, "Error reading "
- "lower encrypted page; rc = "
- "[%d]\n", rc);
- goto out;
- }
- prior_lower_page_idx = lower_page_idx;
- page_state = ECRYPTFS_PAGE_STATE_READ;
- }
- rc = ecryptfs_derive_iv(extent_iv, crypt_stat,
- (base_extent + extent_offset));
+ ecryptfs_printk(KERN_ERR, "Error allocating memory for "
+ "encrypted extent\n");
+ goto out_clear_uptodate;
+ }
+ enc_extent_page = virt_to_page(enc_extent_virt);
+ for (extent_offset = 0;
+ extent_offset < (PAGE_CACHE_SIZE / crypt_stat->extent_size);
+ extent_offset++) {
+ loff_t offset;
+
+ ecryptfs_lower_offset_for_extent(
+ &offset, ((page->index * (PAGE_CACHE_SIZE
+ / crypt_stat->extent_size))
+ + extent_offset), crypt_stat);
+ rc = ecryptfs_read_lower(enc_extent_virt, offset,
+ crypt_stat->extent_size,
+ ecryptfs_inode);
if (rc) {
- ecryptfs_printk(KERN_ERR, "Error attempting to "
- "derive IV for extent [0x%.16x]; rc = "
- "[%d]\n",
- (base_extent + extent_offset), rc);
- goto out;
- }
- if (unlikely(ecryptfs_verbosity > 0)) {
- ecryptfs_printk(KERN_DEBUG, "Decrypting extent "
- "with iv:\n");
- ecryptfs_dump_hex(extent_iv, crypt_stat->iv_bytes);
- ecryptfs_printk(KERN_DEBUG, "First 8 bytes before "
- "decryption:\n");
- ecryptfs_dump_hex((lower_page_virt + byte_offset), 8);
+ ecryptfs_printk(KERN_ERR, "Error attempting "
+ "to read lower page; rc = [%d]"
+ "\n", rc);
+ goto out_clear_uptodate;
}
- rc = ecryptfs_decrypt_page_offset(crypt_stat, page,
- (extent_offset
- * crypt_stat->extent_size),
- lower_page, byte_offset,
- crypt_stat->extent_size,
- extent_iv);
- if (rc != crypt_stat->extent_size) {
- ecryptfs_printk(KERN_ERR, "Error attempting to "
- "decrypt extent [0x%.16x]\n",
- (base_extent + extent_offset));
- goto out;
- }
- rc = 0;
- if (unlikely(ecryptfs_verbosity > 0)) {
- ecryptfs_printk(KERN_DEBUG, "First 8 bytes after "
- "decryption:\n");
- ecryptfs_dump_hex((char *)(page_address(page)
- + byte_offset), 8);
+ rc = ecryptfs_decrypt_extent(page, crypt_stat, enc_extent_page,
+ extent_offset);
+ if (rc) {
+ printk(KERN_ERR "%s: Error encrypting extent; "
+ "rc = [%d]\n", __FUNCTION__, rc);
+ goto out_clear_uptodate;
}
extent_offset++;
}
+ SetPageUptodate(page);
+ goto out;
+out_clear_uptodate:
+ ClearPageUptodate(page);
out:
- if (lower_page_virt)
- kmem_cache_free(ecryptfs_lower_page_cache, lower_page_virt);
+ kfree(enc_extent_virt);
return rc;
}

diff --git a/fs/ecryptfs/ecryptfs_kernel.h b/fs/ecryptfs/ecryptfs_kernel.h
index e6a68a8..65f7ddf 100644
--- a/fs/ecryptfs/ecryptfs_kernel.h
+++ b/fs/ecryptfs/ecryptfs_kernel.h
@@ -552,13 +552,7 @@ void ecryptfs_destroy_crypt_stat(struct ecryptfs_crypt_stat *crypt_stat);
void ecryptfs_destroy_mount_crypt_stat(
struct ecryptfs_mount_crypt_stat *mount_crypt_stat);
int ecryptfs_init_crypt_ctx(struct ecryptfs_crypt_stat *crypt_stat);
-#define ECRYPTFS_LOWER_I_MUTEX_NOT_HELD 0
-#define ECRYPTFS_LOWER_I_MUTEX_HELD 1
-int ecryptfs_write_inode_size_to_metadata(struct file *lower_file,
- struct inode *lower_inode,
- struct inode *inode,
- struct dentry *ecryptfs_dentry,
- int lower_i_mutex_held);
+int ecryptfs_write_inode_size_to_metadata(struct inode *ecryptefs_inode);
int ecryptfs_get_lower_page(struct page **lower_page, struct inode *lower_inode,
struct file *lower_file,
unsigned long lower_page_index, int byte_offset,
@@ -574,8 +568,8 @@ int ecryptfs_do_readpage(struct file *file, struct page *page,
int ecryptfs_writepage_and_release_lower_page(struct page *lower_page,
struct inode *lower_inode,
struct writeback_control *wbc);
-int ecryptfs_encrypt_page(struct ecryptfs_page_crypt_context *ctx);
-int ecryptfs_decrypt_page(struct file *file, struct page *page);
+int ecryptfs_encrypt_page(struct page *page);
+int ecryptfs_decrypt_page(struct page *page);
int ecryptfs_write_metadata(struct dentry *ecryptfs_dentry,
struct file *lower_file);
int ecryptfs_read_metadata(struct dentry *ecryptfs_dentry,
@@ -655,6 +649,8 @@ int ecryptfs_keyring_auth_tok_for_sig(struct key **auth_tok_key,
char *sig);
int ecryptfs_write_zeros(struct file *file, pgoff_t index, int start,
int num_zeros);
+void ecryptfs_lower_offset_for_extent(loff_t *offset, loff_t extent_num,
+ struct ecryptfs_crypt_stat *crypt_stat);
int ecryptfs_write_lower(struct inode *ecryptfs_inode, char *data,
loff_t offset, size_t size);
int ecryptfs_write_lower_page_segment(struct inode *ecryptfs_inode,
diff --git a/fs/ecryptfs/inode.c b/fs/ecryptfs/inode.c
index d70f599..7192a81 100644
--- a/fs/ecryptfs/inode.c
+++ b/fs/ecryptfs/inode.c
@@ -168,9 +168,7 @@ static int grow_file(struct dentry *ecryptfs_dentry, struct file *lower_file,
goto out;
}
i_size_write(inode, 0);
- rc = ecryptfs_write_inode_size_to_metadata(lower_file, lower_inode,
- inode, ecryptfs_dentry,
- ECRYPTFS_LOWER_I_MUTEX_NOT_HELD);
+ rc = ecryptfs_write_inode_size_to_metadata(inode);
ecryptfs_inode_to_private(inode)->crypt_stat.flags |= ECRYPTFS_NEW_FILE;
out:
return rc;
@@ -798,9 +796,7 @@ int ecryptfs_truncate(struct dentry *dentry, loff_t new_length)
goto out_fput;
}
i_size_write(inode, new_length);
- rc = ecryptfs_write_inode_size_to_metadata(
- lower_file, lower_dentry->d_inode, inode, dentry,
- ECRYPTFS_LOWER_I_MUTEX_NOT_HELD);
+ rc = ecryptfs_write_inode_size_to_metadata(inode);
if (rc) {
printk(KERN_ERR "Problem with "
"ecryptfs_write_inode_size_to_metadata; "
@@ -829,9 +825,7 @@ int ecryptfs_truncate(struct dentry *dentry, loff_t new_length)
}
}
vmtruncate(inode, new_length);
- rc = ecryptfs_write_inode_size_to_metadata(
- lower_file, lower_dentry->d_inode, inode, dentry,
- ECRYPTFS_LOWER_I_MUTEX_NOT_HELD);
+ rc = ecryptfs_write_inode_size_to_metadata(inode);
if (rc) {
printk(KERN_ERR "Problem with "
"ecryptfs_write_inode_size_to_metadata; "
diff --git a/fs/ecryptfs/mmap.c b/fs/ecryptfs/mmap.c
index 0c53320..9b62110 100644
--- a/fs/ecryptfs/mmap.c
+++ b/fs/ecryptfs/mmap.c
@@ -171,13 +171,9 @@ out:
*/
static int ecryptfs_writepage(struct page *page, struct writeback_control *wbc)
{
- struct ecryptfs_page_crypt_context ctx;
int rc;

- ctx.page = page;
- ctx.mode = ECRYPTFS_WRITEPAGE_MODE;
- ctx.param.wbc = wbc;
- rc = ecryptfs_encrypt_page(&ctx);
+ rc = ecryptfs_encrypt_page(page);
if (rc) {
ecryptfs_printk(KERN_WARNING, "Error encrypting "
"page (upper index [0x%.16x])\n", page->index);
@@ -341,7 +337,7 @@ static int ecryptfs_readpage(struct file *file, struct page *page)
}
}
} else {
- rc = ecryptfs_decrypt_page(file, page);
+ rc = ecryptfs_decrypt_page(page);
if (rc) {
ecryptfs_printk(KERN_ERR, "Error decrypting page; "
"rc = [%d]\n", rc);
@@ -459,58 +455,48 @@ static void ecryptfs_release_lower_page(struct page *lower_page)
*
* Returns zero on success; non-zero on error.
*/
-static int ecryptfs_write_inode_size_to_header(struct file *lower_file,
- struct inode *lower_inode,
- struct inode *inode)
+static int ecryptfs_write_inode_size_to_header(struct inode *ecryptfs_inode)
{
- int rc = 0;
- struct page *header_page;
- char *header_virt;
- const struct address_space_operations *lower_a_ops;
u64 file_size;
+ char *file_size_virt;
+ int rc;

- header_page = grab_cache_page(lower_inode->i_mapping, 0);
- if (!header_page) {
- ecryptfs_printk(KERN_ERR, "grab_cache_page for "
- "lower_page_index 0 failed\n");
- rc = -EINVAL;
- goto out;
- }
- lower_a_ops = lower_inode->i_mapping->a_ops;
- rc = lower_a_ops->prepare_write(lower_file, header_page, 0, 8);
- if (rc) {
- ecryptfs_release_lower_page(header_page);
+ file_size_virt = kmalloc(sizeof(u64), GFP_KERNEL);
+ if (!file_size_virt) {
+ rc = -ENOMEM;
goto out;
}
- file_size = (u64)i_size_read(inode);
- ecryptfs_printk(KERN_DEBUG, "Writing size: [0x%.16x]\n", file_size);
+ file_size = (u64)i_size_read(ecryptfs_inode);
file_size = cpu_to_be64(file_size);
- header_virt = kmap_atomic(header_page, KM_USER0);
- memcpy(header_virt, &file_size, sizeof(u64));
- kunmap_atomic(header_virt, KM_USER0);
- flush_dcache_page(header_page);
- rc = lower_a_ops->commit_write(lower_file, header_page, 0, 8);
- if (rc < 0)
- ecryptfs_printk(KERN_ERR, "Error commiting header page "
- "write\n");
- ecryptfs_release_lower_page(header_page);
- lower_inode->i_mtime = lower_inode->i_ctime = CURRENT_TIME;
- mark_inode_dirty_sync(inode);
+ memcpy(file_size_virt, &file_size, sizeof(u64));
+ rc = ecryptfs_write_lower(ecryptfs_inode, file_size_virt, 0,
+ sizeof(u64));
+ kfree(file_size_virt);
+ if (rc)
+ printk(KERN_ERR "%s: Error writing file size to header; "
+ "rc = [%d]\n", __FUNCTION__, rc);
out:
return rc;
}

-static int ecryptfs_write_inode_size_to_xattr(struct inode *lower_inode,
- struct inode *inode,
- struct dentry *ecryptfs_dentry,
- int lower_i_mutex_held)
+struct kmem_cache *ecryptfs_xattr_cache;
+
+static int ecryptfs_write_inode_size_to_xattr(struct inode *ecryptfs_inode)
{
ssize_t size;
void *xattr_virt;
- struct dentry *lower_dentry;
+ struct dentry *lower_dentry =
+ ecryptfs_inode_to_private(ecryptfs_inode)->lower_file->f_dentry;
+ struct inode *lower_inode = lower_dentry->d_inode;
u64 file_size;
int rc;

+ if (!lower_inode->i_op->getxattr || !lower_inode->i_op->setxattr) {
+ printk(KERN_WARNING
+ "No support for setting xattr in lower filesystem\n");
+ rc = -ENOSYS;
+ goto out;
+ }
xattr_virt = kmem_cache_alloc(ecryptfs_xattr_cache, GFP_KERNEL);
if (!xattr_virt) {
printk(KERN_ERR "Out of memory whilst attempting to write "
@@ -518,35 +504,17 @@ static int ecryptfs_write_inode_size_to_xattr(struct inode *lower_inode,
rc = -ENOMEM;
goto out;
}
- lower_dentry = ecryptfs_dentry_to_lower(ecryptfs_dentry);
- if (!lower_dentry->d_inode->i_op->getxattr ||
- !lower_dentry->d_inode->i_op->setxattr) {
- printk(KERN_WARNING
- "No support for setting xattr in lower filesystem\n");
- rc = -ENOSYS;
- kmem_cache_free(ecryptfs_xattr_cache, xattr_virt);
- goto out;
- }
- if (!lower_i_mutex_held)
- mutex_lock(&lower_dentry->d_inode->i_mutex);
- size = lower_dentry->d_inode->i_op->getxattr(lower_dentry,
- ECRYPTFS_XATTR_NAME,
- xattr_virt,
- PAGE_CACHE_SIZE);
- if (!lower_i_mutex_held)
- mutex_unlock(&lower_dentry->d_inode->i_mutex);
+ mutex_lock(&lower_inode->i_mutex);
+ size = lower_inode->i_op->getxattr(lower_dentry, ECRYPTFS_XATTR_NAME,
+ xattr_virt, PAGE_CACHE_SIZE);
if (size < 0)
size = 8;
- file_size = (u64)i_size_read(inode);
+ file_size = (u64)i_size_read(ecryptfs_inode);
file_size = cpu_to_be64(file_size);
memcpy(xattr_virt, &file_size, sizeof(u64));
- if (!lower_i_mutex_held)
- mutex_lock(&lower_dentry->d_inode->i_mutex);
- rc = lower_dentry->d_inode->i_op->setxattr(lower_dentry,
- ECRYPTFS_XATTR_NAME,
- xattr_virt, size, 0);
- if (!lower_i_mutex_held)
- mutex_unlock(&lower_dentry->d_inode->i_mutex);
+ rc = lower_inode->i_op->setxattr(lower_dentry, ECRYPTFS_XATTR_NAME,
+ xattr_virt, size, 0);
+ mutex_unlock(&lower_inode->i_mutex);
if (rc)
printk(KERN_ERR "Error whilst attempting to write inode size "
"to lower file xattr; rc = [%d]\n", rc);
@@ -555,24 +523,15 @@ out:
return rc;
}

-int
-ecryptfs_write_inode_size_to_metadata(struct file *lower_file,
- struct inode *lower_inode,
- struct inode *inode,
- struct dentry *ecryptfs_dentry,
- int lower_i_mutex_held)
+int ecryptfs_write_inode_size_to_metadata(struct inode *ecryptfs_inode)
{
struct ecryptfs_crypt_stat *crypt_stat;

- crypt_stat = &ecryptfs_inode_to_private(inode)->crypt_stat;
+ crypt_stat = &ecryptfs_inode_to_private(ecryptfs_inode)->crypt_stat;
if (crypt_stat->flags & ECRYPTFS_METADATA_IN_XATTR)
- return ecryptfs_write_inode_size_to_xattr(lower_inode, inode,
- ecryptfs_dentry,
- lower_i_mutex_held);
+ return ecryptfs_write_inode_size_to_xattr(ecryptfs_inode);
else
- return ecryptfs_write_inode_size_to_header(lower_file,
- lower_inode,
- inode);
+ return ecryptfs_write_inode_size_to_header(ecryptfs_inode);
}

int ecryptfs_get_lower_page(struct page **lower_page, struct inode *lower_inode,
@@ -659,8 +618,6 @@ out:
return rc;
}

-struct kmem_cache *ecryptfs_xattr_cache;
-
/**
* ecryptfs_commit_write
* @file: The eCryptfs file object
@@ -675,7 +632,6 @@ struct kmem_cache *ecryptfs_xattr_cache;
static int ecryptfs_commit_write(struct file *file, struct page *page,
unsigned from, unsigned to)
{
- struct ecryptfs_page_crypt_context ctx;
loff_t pos;
struct inode *inode;
struct inode *lower_inode;
@@ -705,10 +661,7 @@ static int ecryptfs_commit_write(struct file *file, struct page *page,
page->index);
goto out;
}
- ctx.page = page;
- ctx.mode = ECRYPTFS_PREPARE_COMMIT_MODE;
- ctx.param.lower_file = lower_file;
- rc = ecryptfs_encrypt_page(&ctx);
+ rc = ecryptfs_encrypt_page(page);
if (rc) {
ecryptfs_printk(KERN_WARNING, "Error encrypting page (upper "
"index [0x%.16x])\n", page->index);
@@ -721,9 +674,7 @@ static int ecryptfs_commit_write(struct file *file, struct page *page,
ecryptfs_printk(KERN_DEBUG, "Expanded file size to "
"[0x%.16x]\n", i_size_read(inode));
}
- rc = ecryptfs_write_inode_size_to_metadata(lower_file, lower_inode,
- inode, file->f_dentry,
- ECRYPTFS_LOWER_I_MUTEX_HELD);
+ rc = ecryptfs_write_inode_size_to_metadata(inode);
if (rc)
printk(KERN_ERR "Error writing inode size to metadata; "
"rc = [%d]\n", rc);
diff --git a/fs/ecryptfs/read_write.c b/fs/ecryptfs/read_write.c
index e59c94a..ccd2599 100644
--- a/fs/ecryptfs/read_write.c
+++ b/fs/ecryptfs/read_write.c
@@ -154,8 +154,8 @@ int ecryptfs_write(struct file *ecryptfs_file, char *data, loff_t offset,
/* Read in the page from the lower
* into the eCryptfs inode page cache,
* decrypting */
- if ((rc = ecryptfs_decrypt_page(NULL, /* placeholder for git-bisect */
- ecryptfs_page))) {
+ rc = ecryptfs_decrypt_page(ecryptfs_page);
+ if (rc) {
printk(KERN_ERR "%s: Error decrypting "
"page; rc = [%d]\n",
__FUNCTION__, rc);
@@ -178,7 +178,7 @@ int ecryptfs_write(struct file *ecryptfs_file, char *data, loff_t offset,
}
kunmap_atomic(ecryptfs_page_virt, KM_USER0);
flush_dcache_page(ecryptfs_page);
- rc = ecryptfs_encrypt_page(NULL /* placeholder for git-bisect */);
+ rc = ecryptfs_encrypt_page(ecryptfs_page);
if (rc) {
printk(KERN_ERR "%s: Error encrypting "
"page; rc = [%d]\n", __FUNCTION__, rc);
@@ -190,8 +190,8 @@ int ecryptfs_write(struct file *ecryptfs_file, char *data, loff_t offset,
}
if ((offset + size) > ecryptfs_file_size) {
i_size_write(ecryptfs_file->f_dentry->d_inode, (offset + size));
- rc = ecryptfs_write_inode_size_to_metadata(NULL, NULL, NULL,
- NULL, 0); /* placeholders for git-bisect */
+ rc = ecryptfs_write_inode_size_to_metadata(
+ ecryptfs_file->f_dentry->d_inode);
if (rc) {
printk(KERN_ERR "Problem with "
"ecryptfs_write_inode_size_to_metadata; "
@@ -338,7 +338,7 @@ int ecryptfs_read(char *data, loff_t offset, size_t size,
ecryptfs_page_idx, rc);
goto out;
}
- rc = ecryptfs_decrypt_page(NULL /* placeholder for git-bisect */, ecryptfs_page);
+ rc = ecryptfs_decrypt_page(ecryptfs_page);
if (rc) {
printk(KERN_ERR "%s: Error decrypting "
"page; rc = [%d]\n", __FUNCTION__, rc);
--
1.5.1.6

2007-09-17 21:52:44

by Michael Halcrow

[permalink] [raw]
Subject: [PATCH 5/11] eCryptfs: Set up and destroy persistent lower file

This patch sets up and destroys the persistent lower file for each
eCryptfs inode.

Signed-off-by: Michael Halcrow <[email protected]>
---
fs/ecryptfs/inode.c | 23 +++++++++++++++---
fs/ecryptfs/main.c | 65 +++++++++++++++++++++++++++++++++++++++++++++++++++
fs/ecryptfs/super.c | 22 +++++++++++++++--
3 files changed, 103 insertions(+), 7 deletions(-)

diff --git a/fs/ecryptfs/inode.c b/fs/ecryptfs/inode.c
index 7192a81..c746b5d 100644
--- a/fs/ecryptfs/inode.c
+++ b/fs/ecryptfs/inode.c
@@ -119,10 +119,23 @@ ecryptfs_do_create(struct inode *directory_inode,
}
rc = ecryptfs_create_underlying_file(lower_dir_dentry->d_inode,
ecryptfs_dentry, mode, nd);
- if (unlikely(rc)) {
- ecryptfs_printk(KERN_ERR,
- "Failure to create underlying file\n");
- goto out_lock;
+ if (rc) {
+ struct inode *ecryptfs_inode = ecryptfs_dentry->d_inode;
+ struct ecryptfs_inode_info *inode_info =
+ ecryptfs_inode_to_private(ecryptfs_inode);
+
+ printk(KERN_WARNING "%s: Error creating underlying file; "
+ "rc = [%d]; checking for existing\n", __FUNCTION__, rc);
+ if (inode_info) {
+ mutex_lock(&inode_info->lower_file_mutex);
+ if (!inode_info->lower_file) {
+ mutex_unlock(&inode_info->lower_file_mutex);
+ printk(KERN_ERR "%s: Failure to set underlying "
+ "file; rc = [%d]\n", __FUNCTION__, rc);
+ goto out_lock;
+ }
+ mutex_unlock(&inode_info->lower_file_mutex);
+ }
}
rc = ecryptfs_interpose(lower_dentry, ecryptfs_dentry,
directory_inode->i_sb, 0);
@@ -252,6 +265,8 @@ ecryptfs_create(struct inode *directory_inode, struct dentry *ecryptfs_dentry,
{
int rc;

+ /* ecryptfs_do_create() calls ecryptfs_interpose(), which opens
+ * the crypt_stat->lower_file (persistent file) */
rc = ecryptfs_do_create(directory_inode, ecryptfs_dentry, mode, nd);
if (unlikely(rc)) {
ecryptfs_printk(KERN_WARNING, "Failed to create file in"
diff --git a/fs/ecryptfs/main.c b/fs/ecryptfs/main.c
index 967bad0..3e324f8 100644
--- a/fs/ecryptfs/main.c
+++ b/fs/ecryptfs/main.c
@@ -98,6 +98,64 @@ void __ecryptfs_printk(const char *fmt, ...)
}

/**
+ * ecryptfs_init_persistent_file
+ * @ecryptfs_dentry: Fully initialized eCryptfs dentry object, with
+ * the lower dentry and the lower mount set
+ *
+ * eCryptfs only ever keeps a single open file for every lower
+ * inode. All I/O operations to the lower inode occur through that
+ * file. When the first eCryptfs dentry that interposes with the first
+ * lower dentry for that inode is created, this function creates the
+ * persistent file struct and associates it with the eCryptfs
+ * inode. When the eCryptfs inode is destroyed, the file is closed.
+ *
+ * The persistent file will be opened with read/write permissions, if
+ * possible. Otherwise, it is opened read-only.
+ *
+ * This function does nothing if a lower persistent file is already
+ * associated with the eCryptfs inode.
+ *
+ * Returns zero on success; non-zero otherwise
+ */
+int ecryptfs_init_persistent_file(struct dentry *ecryptfs_dentry)
+{
+ struct ecryptfs_inode_info *inode_info =
+ ecryptfs_inode_to_private(ecryptfs_dentry->d_inode);
+ int rc = 0;
+
+ mutex_lock(&inode_info->lower_file_mutex);
+ if (!inode_info->lower_file) {
+ struct dentry *lower_dentry;
+ struct vfsmount *lower_mnt =
+ ecryptfs_dentry_to_lower_mnt(ecryptfs_dentry);
+
+ lower_dentry = ecryptfs_dentry_to_lower(ecryptfs_dentry);
+ /* Corresponding dput() and mntput() are done when the
+ * persistent file is fput() when the eCryptfs inode
+ * is destroyed. */
+ dget(lower_dentry);
+ mntget(lower_mnt);
+ inode_info->lower_file = dentry_open(lower_dentry,
+ lower_mnt,
+ (O_RDWR | O_LARGEFILE));
+ if (IS_ERR(inode_info->lower_file))
+ inode_info->lower_file = dentry_open(lower_dentry,
+ lower_mnt,
+ (O_RDONLY
+ | O_LARGEFILE));
+ if (IS_ERR(inode_info->lower_file)) {
+ printk(KERN_ERR "Error opening lower persistent file "
+ "for lower_dentry [0x%p] and lower_mnt [0x%p]\n",
+ lower_dentry, lower_mnt);
+ rc = PTR_ERR(inode_info->lower_file);
+ inode_info->lower_file = NULL;
+ }
+ }
+ mutex_unlock(&inode_info->lower_file_mutex);
+ return rc;
+}
+
+/**
* ecryptfs_interpose
* @lower_dentry: Existing dentry in the lower filesystem
* @dentry: ecryptfs' dentry
@@ -154,6 +212,13 @@ int ecryptfs_interpose(struct dentry *lower_dentry, struct dentry *dentry,
/* This size will be overwritten for real files w/ headers and
* other metadata */
fsstack_copy_inode_size(inode, lower_inode);
+ rc = ecryptfs_init_persistent_file(dentry);
+ if (rc) {
+ printk(KERN_ERR "%s: Error attempting to initialize the "
+ "persistent file for the dentry with name [%s]; "
+ "rc = [%d]\n", __FUNCTION__, dentry->d_name.name, rc);
+ goto out;
+ }
out:
return rc;
}
diff --git a/fs/ecryptfs/super.c b/fs/ecryptfs/super.c
index 18d77f8..b97e210 100644
--- a/fs/ecryptfs/super.c
+++ b/fs/ecryptfs/super.c
@@ -27,6 +27,7 @@
#include <linux/mount.h>
#include <linux/key.h>
#include <linux/seq_file.h>
+#include <linux/file.h>
#include <linux/crypto.h>
#include "ecryptfs_kernel.h"

@@ -63,9 +64,10 @@ out:
* ecryptfs_destroy_inode
* @inode: The ecryptfs inode
*
- * This is used during the final destruction of the inode.
- * All allocation of memory related to the inode, including allocated
- * memory in the crypt_stat struct, will be released here.
+ * This is used during the final destruction of the inode. All
+ * allocation of memory related to the inode, including allocated
+ * memory in the crypt_stat struct, will be released here. This
+ * function also fput()'s the persistent file for the lower inode.
* There should be no chance that this deallocation will be missed.
*/
static void ecryptfs_destroy_inode(struct inode *inode)
@@ -73,6 +75,20 @@ static void ecryptfs_destroy_inode(struct inode *inode)
struct ecryptfs_inode_info *inode_info;

inode_info = ecryptfs_inode_to_private(inode);
+ mutex_lock(&inode_info->lower_file_mutex);
+ if (inode_info->lower_file) {
+ struct dentry *lower_dentry =
+ inode_info->lower_file->f_dentry;
+
+ BUG_ON(!lower_dentry);
+ if (lower_dentry->d_inode) {
+ fput(inode_info->lower_file);
+ inode_info->lower_file = NULL;
+ d_drop(lower_dentry);
+ d_delete(lower_dentry);
+ }
+ }
+ mutex_unlock(&inode_info->lower_file_mutex);
ecryptfs_destroy_crypt_stat(&inode_info->crypt_stat);
kmem_cache_free(ecryptfs_inode_info_cache, inode_info);
}
--
1.5.1.6

2007-09-17 21:53:38

by Michael Halcrow

[permalink] [raw]
Subject: [PATCH 6/11] eCryptfs: Update metadata read/write functions

Update the metadata read/write functions and grow_file() to use the
read_write.c routines. Do not open another lower file; use the
persistent lower file instead. Provide a separate function for
crypto.c::ecryptfs_read_xattr_region() to get to the lower xattr
without having to go through the eCryptfs getxattr.

Signed-off-by: Michael Halcrow <[email protected]>
---
fs/ecryptfs/crypto.c | 126 +++++++++++++++++++----------------------
fs/ecryptfs/ecryptfs_kernel.h | 15 +++--
fs/ecryptfs/file.c | 2 +-
fs/ecryptfs/inode.c | 101 +++++++++++++++------------------
fs/ecryptfs/mmap.c | 2 +-
5 files changed, 113 insertions(+), 133 deletions(-)

diff --git a/fs/ecryptfs/crypto.c b/fs/ecryptfs/crypto.c
index d6a0680..6b4d310 100644
--- a/fs/ecryptfs/crypto.c
+++ b/fs/ecryptfs/crypto.c
@@ -1344,21 +1344,28 @@ out:
return rc;
}

-int ecryptfs_read_and_validate_header_region(char *data, struct dentry *dentry,
- struct vfsmount *mnt)
+int ecryptfs_read_and_validate_header_region(char *data,
+ struct inode *ecryptfs_inode)
{
+ struct ecryptfs_crypt_stat *crypt_stat =
+ &(ecryptfs_inode_to_private(ecryptfs_inode)->crypt_stat);
int rc;

- rc = ecryptfs_read_header_region(data, dentry, mnt);
- if (rc)
+ rc = ecryptfs_read_lower(data, 0, crypt_stat->extent_size,
+ ecryptfs_inode);
+ if (rc) {
+ printk(KERN_ERR "%s: Error reading header region; rc = [%d]\n",
+ __FUNCTION__, rc);
goto out;
- if (!contains_ecryptfs_marker(data + ECRYPTFS_FILE_SIZE_BYTES))
+ }
+ if (!contains_ecryptfs_marker(data + ECRYPTFS_FILE_SIZE_BYTES)) {
rc = -EINVAL;
+ ecryptfs_printk(KERN_DEBUG, "Valid marker not found\n");
+ }
out:
return rc;
}

-
void
ecryptfs_write_header_metadata(char *virt,
struct ecryptfs_crypt_stat *crypt_stat,
@@ -1443,24 +1450,18 @@ static int ecryptfs_write_headers_virt(char *page_virt, size_t *size,

static int
ecryptfs_write_metadata_to_contents(struct ecryptfs_crypt_stat *crypt_stat,
- struct file *lower_file, char *page_virt)
+ struct dentry *ecryptfs_dentry,
+ char *page_virt)
{
- mm_segment_t oldfs;
int current_header_page;
int header_pages;
- ssize_t size;
- int rc = 0;
+ int rc;

- lower_file->f_pos = 0;
- oldfs = get_fs();
- set_fs(get_ds());
- size = vfs_write(lower_file, (char __user *)page_virt, PAGE_CACHE_SIZE,
- &lower_file->f_pos);
- if (size < 0) {
- rc = (int)size;
- printk(KERN_ERR "Error attempting to write lower page; "
- "rc = [%d]\n", rc);
- set_fs(oldfs);
+ if ((rc = ecryptfs_write_lower(ecryptfs_dentry->d_inode, page_virt,
+ 0, PAGE_CACHE_SIZE))) {
+ printk(KERN_ERR "%s: Error attempting to write header "
+ "information to lower file; rc = [%d]\n", __FUNCTION__,
+ rc);
goto out;
}
header_pages = ((crypt_stat->extent_size
@@ -1469,18 +1470,19 @@ ecryptfs_write_metadata_to_contents(struct ecryptfs_crypt_stat *crypt_stat,
memset(page_virt, 0, PAGE_CACHE_SIZE);
current_header_page = 1;
while (current_header_page < header_pages) {
- size = vfs_write(lower_file, (char __user *)page_virt,
- PAGE_CACHE_SIZE, &lower_file->f_pos);
- if (size < 0) {
- rc = (int)size;
- printk(KERN_ERR "Error attempting to write lower page; "
- "rc = [%d]\n", rc);
- set_fs(oldfs);
+ loff_t offset;
+
+ offset = (current_header_page << PAGE_CACHE_SHIFT);
+ if ((rc = ecryptfs_write_lower(ecryptfs_dentry->d_inode,
+ page_virt, offset,
+ PAGE_CACHE_SIZE))) {
+ printk(KERN_ERR "%s: Error attempting to write header "
+ "information to lower file; rc = [%d]\n",
+ __FUNCTION__, rc);
goto out;
}
current_header_page++;
}
- set_fs(oldfs);
out:
return rc;
}
@@ -1500,7 +1502,6 @@ ecryptfs_write_metadata_to_xattr(struct dentry *ecryptfs_dentry,
/**
* ecryptfs_write_metadata
* @ecryptfs_dentry: The eCryptfs dentry
- * @lower_file: The lower file struct, which was returned from dentry_open
*
* Write the file headers out. This will likely involve a userspace
* callout, in which the session key is encrypted with one or more
@@ -1508,22 +1509,21 @@ ecryptfs_write_metadata_to_xattr(struct dentry *ecryptfs_dentry,
* retrieved via a prompt. Exactly what happens at this point should
* be policy-dependent.
*
+ * TODO: Support header information spanning multiple pages
+ *
* Returns zero on success; non-zero on error
*/
-int ecryptfs_write_metadata(struct dentry *ecryptfs_dentry,
- struct file *lower_file)
+int ecryptfs_write_metadata(struct dentry *ecryptfs_dentry)
{
- struct ecryptfs_crypt_stat *crypt_stat;
+ struct ecryptfs_crypt_stat *crypt_stat =
+ &ecryptfs_inode_to_private(ecryptfs_dentry->d_inode)->crypt_stat;
char *page_virt;
- size_t size;
+ size_t size = 0;
int rc = 0;

- crypt_stat = &ecryptfs_inode_to_private(
- ecryptfs_dentry->d_inode)->crypt_stat;
if (likely(crypt_stat->flags & ECRYPTFS_ENCRYPTED)) {
if (!(crypt_stat->flags & ECRYPTFS_KEY_VALID)) {
- ecryptfs_printk(KERN_DEBUG, "Key is "
- "invalid; bailing out\n");
+ printk(KERN_ERR "Key is invalid; bailing out\n");
rc = -EINVAL;
goto out;
}
@@ -1552,7 +1552,8 @@ int ecryptfs_write_metadata(struct dentry *ecryptfs_dentry,
crypt_stat, page_virt,
size);
else
- rc = ecryptfs_write_metadata_to_contents(crypt_stat, lower_file,
+ rc = ecryptfs_write_metadata_to_contents(crypt_stat,
+ ecryptfs_dentry,
page_virt);
if (rc) {
printk(KERN_ERR "Error writing metadata out to lower file; "
@@ -1680,15 +1681,17 @@ out:
*
* Returns zero on success; non-zero on error
*/
-int ecryptfs_read_xattr_region(char *page_virt, struct dentry *ecryptfs_dentry)
+int ecryptfs_read_xattr_region(char *page_virt, struct inode *ecryptfs_inode)
{
+ struct dentry *lower_dentry =
+ ecryptfs_inode_to_private(ecryptfs_inode)->lower_file->f_dentry;
ssize_t size;
int rc = 0;

- size = ecryptfs_getxattr(ecryptfs_dentry, ECRYPTFS_XATTR_NAME,
- page_virt, ECRYPTFS_DEFAULT_EXTENT_SIZE);
+ size = ecryptfs_getxattr_lower(lower_dentry, ECRYPTFS_XATTR_NAME,
+ page_virt, ECRYPTFS_DEFAULT_EXTENT_SIZE);
if (size < 0) {
- printk(KERN_DEBUG "Error attempting to read the [%s] "
+ printk(KERN_ERR "Error attempting to read the [%s] "
"xattr from the lower file; return value = [%zd]\n",
ECRYPTFS_XATTR_NAME, size);
rc = -EINVAL;
@@ -1703,7 +1706,7 @@ int ecryptfs_read_and_validate_xattr_region(char *page_virt,
{
int rc;

- rc = ecryptfs_read_xattr_region(page_virt, ecryptfs_dentry);
+ rc = ecryptfs_read_xattr_region(page_virt, ecryptfs_dentry->d_inode);
if (rc)
goto out;
if (!contains_ecryptfs_marker(page_virt + ECRYPTFS_FILE_SIZE_BYTES)) {
@@ -1717,8 +1720,6 @@ out:

/**
* ecryptfs_read_metadata
- * @ecryptfs_dentry: The eCryptfs dentry
- * @lower_file: The lower file from which to read the metadata
*
* Common entry point for reading file metadata. From here, we could
* retrieve the header information from the header region of the file,
@@ -1729,15 +1730,13 @@ out:
*
* Returns zero if valid headers found and parsed; non-zero otherwise
*/
-int ecryptfs_read_metadata(struct dentry *ecryptfs_dentry,
- struct file *lower_file)
+int ecryptfs_read_metadata(struct dentry *ecryptfs_dentry)
{
int rc = 0;
char *page_virt = NULL;
- mm_segment_t oldfs;
- ssize_t bytes_read;
+ struct inode *ecryptfs_inode = ecryptfs_dentry->d_inode;
struct ecryptfs_crypt_stat *crypt_stat =
- &ecryptfs_inode_to_private(ecryptfs_dentry->d_inode)->crypt_stat;
+ &ecryptfs_inode_to_private(ecryptfs_inode)->crypt_stat;
struct ecryptfs_mount_crypt_stat *mount_crypt_stat =
&ecryptfs_superblock_to_private(
ecryptfs_dentry->d_sb)->mount_crypt_stat;
@@ -1748,27 +1747,18 @@ int ecryptfs_read_metadata(struct dentry *ecryptfs_dentry,
page_virt = kmem_cache_alloc(ecryptfs_header_cache_1, GFP_USER);
if (!page_virt) {
rc = -ENOMEM;
- ecryptfs_printk(KERN_ERR, "Unable to allocate page_virt\n");
+ printk(KERN_ERR "%s: Unable to allocate page_virt\n",
+ __FUNCTION__);
goto out;
}
- lower_file->f_pos = 0;
- oldfs = get_fs();
- set_fs(get_ds());
- bytes_read = lower_file->f_op->read(lower_file,
- (char __user *)page_virt,
- ECRYPTFS_DEFAULT_EXTENT_SIZE,
- &lower_file->f_pos);
- set_fs(oldfs);
- if (bytes_read != ECRYPTFS_DEFAULT_EXTENT_SIZE) {
- rc = -EINVAL;
- goto out;
- }
- rc = ecryptfs_read_headers_virt(page_virt, crypt_stat,
- ecryptfs_dentry,
- ECRYPTFS_VALIDATE_HEADER_SIZE);
+ rc = ecryptfs_read_lower(page_virt, 0, crypt_stat->extent_size,
+ ecryptfs_inode);
+ if (!rc)
+ rc = ecryptfs_read_headers_virt(page_virt, crypt_stat,
+ ecryptfs_dentry,
+ ECRYPTFS_VALIDATE_HEADER_SIZE);
if (rc) {
- rc = ecryptfs_read_xattr_region(page_virt,
- ecryptfs_dentry);
+ rc = ecryptfs_read_xattr_region(page_virt, ecryptfs_inode);
if (rc) {
printk(KERN_DEBUG "Valid eCryptfs headers not found in "
"file header region or xattr region\n");
diff --git a/fs/ecryptfs/ecryptfs_kernel.h b/fs/ecryptfs/ecryptfs_kernel.h
index 65f7ddf..3e52b42 100644
--- a/fs/ecryptfs/ecryptfs_kernel.h
+++ b/fs/ecryptfs/ecryptfs_kernel.h
@@ -570,13 +570,11 @@ int ecryptfs_writepage_and_release_lower_page(struct page *lower_page,
struct writeback_control *wbc);
int ecryptfs_encrypt_page(struct page *page);
int ecryptfs_decrypt_page(struct page *page);
-int ecryptfs_write_metadata(struct dentry *ecryptfs_dentry,
- struct file *lower_file);
-int ecryptfs_read_metadata(struct dentry *ecryptfs_dentry,
- struct file *lower_file);
+int ecryptfs_write_metadata(struct dentry *ecryptfs_dentry);
+int ecryptfs_read_metadata(struct dentry *ecryptfs_dentry);
int ecryptfs_new_file_context(struct dentry *ecryptfs_dentry);
-int ecryptfs_read_and_validate_header_region(char *data, struct dentry *dentry,
- struct vfsmount *mnt);
+int ecryptfs_read_and_validate_header_region(char *data,
+ struct inode *ecryptfs_inode);
int ecryptfs_read_and_validate_xattr_region(char *page_virt,
struct dentry *ecryptfs_dentry);
u16 ecryptfs_code_for_cipher_string(struct ecryptfs_crypt_stat *crypt_stat);
@@ -599,10 +597,13 @@ int ecryptfs_open_lower_file(struct file **lower_file,
int ecryptfs_close_lower_file(struct file *lower_file);
ssize_t ecryptfs_getxattr(struct dentry *dentry, const char *name, void *value,
size_t size);
+ssize_t
+ecryptfs_getxattr_lower(struct dentry *lower_dentry, const char *name,
+ void *value, size_t size);
int
ecryptfs_setxattr(struct dentry *dentry, const char *name, const void *value,
size_t size, int flags);
-int ecryptfs_read_xattr_region(char *page_virt, struct dentry *ecryptfs_dentry);
+int ecryptfs_read_xattr_region(char *page_virt, struct inode *ecryptfs_inode);
int ecryptfs_process_helo(unsigned int transport, uid_t uid, pid_t pid);
int ecryptfs_process_quit(uid_t uid, pid_t pid);
int ecryptfs_process_response(struct ecryptfs_message *msg, uid_t uid,
diff --git a/fs/ecryptfs/file.c b/fs/ecryptfs/file.c
index 59c846d..df70bfa 100644
--- a/fs/ecryptfs/file.c
+++ b/fs/ecryptfs/file.c
@@ -248,7 +248,7 @@ static int ecryptfs_open(struct inode *inode, struct file *file)
mutex_lock(&crypt_stat->cs_mutex);
if (!(crypt_stat->flags & ECRYPTFS_POLICY_APPLIED)
|| !(crypt_stat->flags & ECRYPTFS_KEY_VALID)) {
- rc = ecryptfs_read_metadata(ecryptfs_dentry, lower_file);
+ rc = ecryptfs_read_metadata(ecryptfs_dentry);
if (rc) {
ecryptfs_printk(KERN_DEBUG,
"Valid headers not found\n");
diff --git a/fs/ecryptfs/inode.c b/fs/ecryptfs/inode.c
index c746b5d..a29dc31 100644
--- a/fs/ecryptfs/inode.c
+++ b/fs/ecryptfs/inode.c
@@ -153,37 +153,30 @@ out:

/**
* grow_file
- * @ecryptfs_dentry: the ecryptfs dentry
- * @lower_file: The lower file
- * @inode: The ecryptfs inode
- * @lower_inode: The lower inode
+ * @ecryptfs_dentry: the eCryptfs dentry
*
* This is the code which will grow the file to its correct size.
*/
-static int grow_file(struct dentry *ecryptfs_dentry, struct file *lower_file,
- struct inode *inode, struct inode *lower_inode)
+static int grow_file(struct dentry *ecryptfs_dentry)
{
- int rc = 0;
+ struct inode *ecryptfs_inode = ecryptfs_dentry->d_inode;
struct file fake_file;
struct ecryptfs_file_info tmp_file_info;
+ char zero_virt[] = { 0x00 };
+ int rc = 0;

memset(&fake_file, 0, sizeof(fake_file));
fake_file.f_path.dentry = ecryptfs_dentry;
memset(&tmp_file_info, 0, sizeof(tmp_file_info));
ecryptfs_set_file_private(&fake_file, &tmp_file_info);
- ecryptfs_set_file_lower(&fake_file, lower_file);
- rc = ecryptfs_fill_zeros(&fake_file, 1);
- if (rc) {
- ecryptfs_inode_to_private(inode)->crypt_stat.flags |=
- ECRYPTFS_SECURITY_WARNING;
- ecryptfs_printk(KERN_WARNING, "Error attempting to fill zeros "
- "in file; rc = [%d]\n", rc);
- goto out;
- }
- i_size_write(inode, 0);
- rc = ecryptfs_write_inode_size_to_metadata(inode);
- ecryptfs_inode_to_private(inode)->crypt_stat.flags |= ECRYPTFS_NEW_FILE;
-out:
+ ecryptfs_set_file_lower(
+ &fake_file,
+ ecryptfs_inode_to_private(ecryptfs_inode)->lower_file);
+ rc = ecryptfs_write(&fake_file, zero_virt, 0, 1);
+ i_size_write(ecryptfs_inode, 0);
+ rc = ecryptfs_write_inode_size_to_metadata(ecryptfs_inode);
+ ecryptfs_inode_to_private(ecryptfs_inode)->crypt_stat.flags |=
+ ECRYPTFS_NEW_FILE;
return rc;
}

@@ -197,53 +190,31 @@ out:
*/
static int ecryptfs_initialize_file(struct dentry *ecryptfs_dentry)
{
+ struct ecryptfs_crypt_stat *crypt_stat =
+ &ecryptfs_inode_to_private(ecryptfs_dentry->d_inode)->crypt_stat;
int rc = 0;
- int lower_flags;
- struct ecryptfs_crypt_stat *crypt_stat;
- struct dentry *lower_dentry;
- struct file *lower_file;
- struct inode *inode, *lower_inode;
- struct vfsmount *lower_mnt;

- lower_dentry = ecryptfs_dentry_to_lower(ecryptfs_dentry);
- ecryptfs_printk(KERN_DEBUG, "lower_dentry->d_name.name = [%s]\n",
- lower_dentry->d_name.name);
- inode = ecryptfs_dentry->d_inode;
- crypt_stat = &ecryptfs_inode_to_private(inode)->crypt_stat;
- lower_flags = ((O_CREAT | O_TRUNC) & O_ACCMODE) | O_RDWR;
- lower_mnt = ecryptfs_dentry_to_lower_mnt(ecryptfs_dentry);
- /* Corresponding fput() at end of this function */
- rc = ecryptfs_open_lower_file(&lower_file, lower_dentry, lower_mnt,
- lower_flags);
- if (rc) {
- ecryptfs_printk(KERN_ERR,
- "Error opening dentry; rc = [%i]\n", rc);
- goto out;
- }
- lower_inode = lower_dentry->d_inode;
if (S_ISDIR(ecryptfs_dentry->d_inode->i_mode)) {
ecryptfs_printk(KERN_DEBUG, "This is a directory\n");
crypt_stat->flags &= ~(ECRYPTFS_ENCRYPTED);
- goto out_fput;
+ goto out;
}
crypt_stat->flags |= ECRYPTFS_NEW_FILE;
ecryptfs_printk(KERN_DEBUG, "Initializing crypto context\n");
rc = ecryptfs_new_file_context(ecryptfs_dentry);
if (rc) {
- ecryptfs_printk(KERN_DEBUG, "Error creating new file "
- "context\n");
- goto out_fput;
+ ecryptfs_printk(KERN_ERR, "Error creating new file "
+ "context; rc = [%d]\n", rc);
+ goto out;
}
- rc = ecryptfs_write_metadata(ecryptfs_dentry, lower_file);
+ rc = ecryptfs_write_metadata(ecryptfs_dentry);
if (rc) {
- ecryptfs_printk(KERN_DEBUG, "Error writing headers\n");
- goto out_fput;
+ printk(KERN_ERR "Error writing headers; rc = [%d]\n", rc);
+ goto out;
}
- rc = grow_file(ecryptfs_dentry, lower_file, inode, lower_inode);
-out_fput:
- rc = ecryptfs_close_lower_file(lower_file);
+ rc = grow_file(ecryptfs_dentry);
if (rc)
- printk(KERN_ERR "Error closing lower_file\n");
+ printk(KERN_ERR "Error growing file; rc = [%d]\n", rc);
out:
return rc;
}
@@ -389,8 +360,8 @@ static struct dentry *ecryptfs_lookup(struct inode *dir, struct dentry *dentry,
crypt_stat = &ecryptfs_inode_to_private(dentry->d_inode)->crypt_stat;
if (!(crypt_stat->flags & ECRYPTFS_POLICY_APPLIED))
ecryptfs_set_default_sizes(crypt_stat);
- rc = ecryptfs_read_and_validate_header_region(page_virt, lower_dentry,
- nd->mnt);
+ rc = ecryptfs_read_and_validate_header_region(page_virt,
+ dentry->d_inode);
if (rc) {
rc = ecryptfs_read_and_validate_xattr_region(page_virt, dentry);
if (rc) {
@@ -941,7 +912,7 @@ static int ecryptfs_setattr(struct dentry *dentry, struct iattr *ia)
}
mount_crypt_stat = &ecryptfs_superblock_to_private(
dentry->d_sb)->mount_crypt_stat;
- rc = ecryptfs_read_metadata(dentry, lower_file);
+ rc = ecryptfs_read_metadata(dentry);
if (rc) {
if (!(mount_crypt_stat->flags
& ECRYPTFS_PLAINTEXT_PASSTHROUGH_ENABLED)) {
@@ -1003,6 +974,24 @@ out:
}

ssize_t
+ecryptfs_getxattr_lower(struct dentry *lower_dentry, const char *name,
+ void *value, size_t size)
+{
+ int rc = 0;
+
+ if (!lower_dentry->d_inode->i_op->getxattr) {
+ rc = -ENOSYS;
+ goto out;
+ }
+ mutex_lock(&lower_dentry->d_inode->i_mutex);
+ rc = lower_dentry->d_inode->i_op->getxattr(lower_dentry, name, value,
+ size);
+ mutex_unlock(&lower_dentry->d_inode->i_mutex);
+out:
+ return rc;
+}
+
+ssize_t
ecryptfs_getxattr(struct dentry *dentry, const char *name, void *value,
size_t size)
{
diff --git a/fs/ecryptfs/mmap.c b/fs/ecryptfs/mmap.c
index 9b62110..60e635e 100644
--- a/fs/ecryptfs/mmap.c
+++ b/fs/ecryptfs/mmap.c
@@ -307,7 +307,7 @@ static int ecryptfs_readpage(struct file *file, struct page *page)
memset(page_virt, 0, PAGE_CACHE_SIZE);
if (page->index == 0) {
rc = ecryptfs_read_xattr_region(
- page_virt, file->f_path.dentry);
+ page_virt, page->mapping->host);
set_header_info(page_virt, crypt_stat);
}
kunmap_atomic(page_virt, KM_USER0);
--
1.5.1.6

2007-09-17 21:54:32

by Michael Halcrow

[permalink] [raw]
Subject: [PATCH 7/11] eCryptfs: Make open, truncate, and setattr use persistent file

Rather than open a new lower file for every eCryptfs file that is
opened, truncated, or setattr'd, instead use the existing lower
persistent file for the eCryptfs inode. Change truncate to use
read_write.c functions. Change ecryptfs_getxattr() to use the common
ecryptfs_getxattr_lower() function.

Signed-off-by: Michael Halcrow <[email protected]>
---
fs/ecryptfs/crypto.c | 2 +-
fs/ecryptfs/file.c | 50 ++++------------------
fs/ecryptfs/inode.c | 113 +++++++++++++++-----------------------------------
3 files changed, 44 insertions(+), 121 deletions(-)

diff --git a/fs/ecryptfs/crypto.c b/fs/ecryptfs/crypto.c
index 6b4d310..b3014d7 100644
--- a/fs/ecryptfs/crypto.c
+++ b/fs/ecryptfs/crypto.c
@@ -1674,7 +1674,7 @@ out:
/**
* ecryptfs_read_xattr_region
* @page_virt: The vitual address into which to read the xattr data
- * @ecryptfs_dentry: The eCryptfs dentry
+ * @ecryptfs_inode: The eCryptfs inode
*
* Attempts to read the crypto metadata from the extended attribute
* region of the lower file.
diff --git a/fs/ecryptfs/file.c b/fs/ecryptfs/file.c
index df70bfa..95be9a9 100644
--- a/fs/ecryptfs/file.c
+++ b/fs/ecryptfs/file.c
@@ -187,11 +187,7 @@ static int ecryptfs_open(struct inode *inode, struct file *file)
/* Private value of ecryptfs_dentry allocated in
* ecryptfs_lookup() */
struct dentry *lower_dentry = ecryptfs_dentry_to_lower(ecryptfs_dentry);
- struct inode *lower_inode = NULL;
- struct file *lower_file = NULL;
- struct vfsmount *lower_mnt;
struct ecryptfs_file_info *file_info;
- int lower_flags;

mount_crypt_stat = &ecryptfs_superblock_to_private(
ecryptfs_dentry->d_sb)->mount_crypt_stat;
@@ -219,26 +215,12 @@ static int ecryptfs_open(struct inode *inode, struct file *file)
if (!(crypt_stat->flags & ECRYPTFS_POLICY_APPLIED)) {
ecryptfs_printk(KERN_DEBUG, "Setting flags for stat...\n");
/* Policy code enabled in future release */
- crypt_stat->flags |= ECRYPTFS_POLICY_APPLIED;
- crypt_stat->flags |= ECRYPTFS_ENCRYPTED;
+ crypt_stat->flags |= (ECRYPTFS_POLICY_APPLIED
+ | ECRYPTFS_ENCRYPTED);
}
mutex_unlock(&crypt_stat->cs_mutex);
- lower_flags = file->f_flags;
- if ((lower_flags & O_ACCMODE) == O_WRONLY)
- lower_flags = (lower_flags & O_ACCMODE) | O_RDWR;
- if (file->f_flags & O_APPEND)
- lower_flags &= ~O_APPEND;
- lower_mnt = ecryptfs_dentry_to_lower_mnt(ecryptfs_dentry);
- /* Corresponding fput() in ecryptfs_release() */
- rc = ecryptfs_open_lower_file(&lower_file, lower_dentry, lower_mnt,
- lower_flags);
- if (rc) {
- ecryptfs_printk(KERN_ERR, "Error opening lower file\n");
- goto out_puts;
- }
- ecryptfs_set_file_lower(file, lower_file);
- /* Isn't this check the same as the one in lookup? */
- lower_inode = lower_dentry->d_inode;
+ ecryptfs_set_file_lower(
+ file, ecryptfs_inode_to_private(inode)->lower_file);
if (S_ISDIR(ecryptfs_dentry->d_inode->i_mode)) {
ecryptfs_printk(KERN_DEBUG, "This is a directory\n");
crypt_stat->flags &= ~(ECRYPTFS_ENCRYPTED);
@@ -260,7 +242,7 @@ static int ecryptfs_open(struct inode *inode, struct file *file)
"and plaintext passthrough mode is not "
"enabled; returning -EIO\n");
mutex_unlock(&crypt_stat->cs_mutex);
- goto out_puts;
+ goto out_free;
}
rc = 0;
crypt_stat->flags &= ~(ECRYPTFS_ENCRYPTED);
@@ -272,11 +254,8 @@ static int ecryptfs_open(struct inode *inode, struct file *file)
ecryptfs_printk(KERN_DEBUG, "inode w/ addr = [0x%p], i_ino = [0x%.16x] "
"size: [0x%.16x]\n", inode, inode->i_ino,
i_size_read(inode));
- ecryptfs_set_file_lower(file, lower_file);
goto out;
-out_puts:
- mntput(lower_mnt);
- dput(lower_dentry);
+out_free:
kmem_cache_free(ecryptfs_file_info_cache,
ecryptfs_file_to_private(file));
out:
@@ -296,20 +275,9 @@ static int ecryptfs_flush(struct file *file, fl_owner_t td)

static int ecryptfs_release(struct inode *inode, struct file *file)
{
- struct file *lower_file = ecryptfs_file_to_lower(file);
- struct ecryptfs_file_info *file_info = ecryptfs_file_to_private(file);
- struct inode *lower_inode = ecryptfs_inode_to_lower(inode);
- int rc;
-
- rc = ecryptfs_close_lower_file(lower_file);
- if (rc) {
- printk(KERN_ERR "Error closing lower_file\n");
- goto out;
- }
- inode->i_blocks = lower_inode->i_blocks;
- kmem_cache_free(ecryptfs_file_info_cache, file_info);
-out:
- return rc;
+ kmem_cache_free(ecryptfs_file_info_cache,
+ ecryptfs_file_to_private(file));
+ return 0;
}

static int
diff --git a/fs/ecryptfs/inode.c b/fs/ecryptfs/inode.c
index a29dc31..5701f81 100644
--- a/fs/ecryptfs/inode.c
+++ b/fs/ecryptfs/inode.c
@@ -739,8 +739,7 @@ int ecryptfs_truncate(struct dentry *dentry, loff_t new_length)
int rc = 0;
struct inode *inode = dentry->d_inode;
struct dentry *lower_dentry;
- struct vfsmount *lower_mnt;
- struct file fake_ecryptfs_file, *lower_file = NULL;
+ struct file fake_ecryptfs_file;
struct ecryptfs_crypt_stat *crypt_stat;
loff_t i_size = i_size_read(inode);
loff_t lower_size_before_truncate;
@@ -763,51 +762,43 @@ int ecryptfs_truncate(struct dentry *dentry, loff_t new_length)
goto out;
}
lower_dentry = ecryptfs_dentry_to_lower(dentry);
- /* This dget & mntget is released through fput at out_fput: */
- lower_mnt = ecryptfs_dentry_to_lower_mnt(dentry);
- rc = ecryptfs_open_lower_file(&lower_file, lower_dentry, lower_mnt,
- O_RDWR);
- if (rc) {
- ecryptfs_printk(KERN_ERR,
- "Error opening dentry; rc = [%i]\n", rc);
- goto out_free;
- }
- ecryptfs_set_file_lower(&fake_ecryptfs_file, lower_file);
+ ecryptfs_set_file_lower(
+ &fake_ecryptfs_file,
+ ecryptfs_inode_to_private(dentry->d_inode)->lower_file);
/* Switch on growing or shrinking file */
if (new_length > i_size) {
- rc = ecryptfs_fill_zeros(&fake_ecryptfs_file, new_length);
- if (rc) {
- ecryptfs_printk(KERN_ERR,
- "Problem with fill_zeros\n");
- goto out_fput;
- }
- i_size_write(inode, new_length);
- rc = ecryptfs_write_inode_size_to_metadata(inode);
- if (rc) {
- printk(KERN_ERR "Problem with "
- "ecryptfs_write_inode_size_to_metadata; "
- "rc = [%d]\n", rc);
- goto out_fput;
- }
+ char zero[] = { 0x00 };
+
+ /* Write a single 0 at the last position of the file;
+ * this triggers code that will fill in 0's throughout
+ * the intermediate portion of the previous end of the
+ * file and the new and of the file */
+ rc = ecryptfs_write(&fake_ecryptfs_file, zero,
+ (new_length - 1), 1);
} else { /* new_length < i_size_read(inode) */
- pgoff_t index = 0;
- int end_pos_in_page = -1;
-
- if (new_length != 0) {
- index = ((new_length - 1) >> PAGE_CACHE_SHIFT);
- end_pos_in_page = ((new_length - 1) & ~PAGE_CACHE_MASK);
- }
- if (end_pos_in_page != (PAGE_CACHE_SIZE - 1)) {
- rc = ecryptfs_write_zeros(&fake_ecryptfs_file,
- index,
- (end_pos_in_page + 1),
- ((PAGE_CACHE_SIZE - 1)
- - end_pos_in_page));
+ /* We're chopping off all the pages down do the page
+ * in which new_length is located. Fill in the end of
+ * that page from (new_length & ~PAGE_CACHE_MASK) to
+ * PAGE_CACHE_SIZE with zeros. */
+ size_t num_zeros = (PAGE_CACHE_SIZE
+ - (new_length & ~PAGE_CACHE_MASK));
+
+ if (num_zeros) {
+ char *zeros_virt;
+
+ zeros_virt = kzalloc(num_zeros, GFP_KERNEL);
+ if (!zeros_virt) {
+ rc = -ENOMEM;
+ goto out_free;
+ }
+ rc = ecryptfs_write(&fake_ecryptfs_file, zeros_virt,
+ new_length, num_zeros);
+ kfree(zeros_virt);
if (rc) {
printk(KERN_ERR "Error attempting to zero out "
"the remainder of the end page on "
"reducing truncate; rc = [%d]\n", rc);
- goto out_fput;
+ goto out_free;
}
}
vmtruncate(inode, new_length);
@@ -816,7 +807,7 @@ int ecryptfs_truncate(struct dentry *dentry, loff_t new_length)
printk(KERN_ERR "Problem with "
"ecryptfs_write_inode_size_to_metadata; "
"rc = [%d]\n", rc);
- goto out_fput;
+ goto out_free;
}
/* We are reducing the size of the ecryptfs file, and need to
* know if we need to reduce the size of the lower file. */
@@ -828,14 +819,6 @@ int ecryptfs_truncate(struct dentry *dentry, loff_t new_length)
vmtruncate(lower_dentry->d_inode,
lower_size_after_truncate);
}
- /* Update the access times */
- lower_dentry->d_inode->i_mtime = lower_dentry->d_inode->i_ctime
- = CURRENT_TIME;
- mark_inode_dirty_sync(inode);
-out_fput:
- rc = ecryptfs_close_lower_file(lower_file);
- if (rc)
- printk(KERN_ERR "Error closing lower_file\n");
out_free:
if (ecryptfs_file_to_private(&fake_ecryptfs_file))
kmem_cache_free(ecryptfs_file_info_cache,
@@ -895,21 +878,8 @@ static int ecryptfs_setattr(struct dentry *dentry, struct iattr *ia)
else if (S_ISREG(dentry->d_inode->i_mode)
&& (!(crypt_stat->flags & ECRYPTFS_POLICY_APPLIED)
|| !(crypt_stat->flags & ECRYPTFS_KEY_VALID))) {
- struct vfsmount *lower_mnt;
- struct file *lower_file = NULL;
struct ecryptfs_mount_crypt_stat *mount_crypt_stat;
- int lower_flags;

- lower_mnt = ecryptfs_dentry_to_lower_mnt(dentry);
- lower_flags = O_RDONLY;
- rc = ecryptfs_open_lower_file(&lower_file, lower_dentry,
- lower_mnt, lower_flags);
- if (rc) {
- printk(KERN_ERR
- "Error opening lower file; rc = [%d]\n", rc);
- mutex_unlock(&crypt_stat->cs_mutex);
- goto out;
- }
mount_crypt_stat = &ecryptfs_superblock_to_private(
dentry->d_sb)->mount_crypt_stat;
rc = ecryptfs_read_metadata(dentry);
@@ -923,16 +893,13 @@ static int ecryptfs_setattr(struct dentry *dentry, struct iattr *ia)
"enabled; returning -EIO\n");

mutex_unlock(&crypt_stat->cs_mutex);
- fput(lower_file);
goto out;
}
rc = 0;
crypt_stat->flags &= ~(ECRYPTFS_ENCRYPTED);
mutex_unlock(&crypt_stat->cs_mutex);
- fput(lower_file);
goto out;
}
- fput(lower_file);
}
mutex_unlock(&crypt_stat->cs_mutex);
if (ia->ia_valid & ATTR_SIZE) {
@@ -995,20 +962,8 @@ ssize_t
ecryptfs_getxattr(struct dentry *dentry, const char *name, void *value,
size_t size)
{
- int rc = 0;
- struct dentry *lower_dentry;
-
- lower_dentry = ecryptfs_dentry_to_lower(dentry);
- if (!lower_dentry->d_inode->i_op->getxattr) {
- rc = -ENOSYS;
- goto out;
- }
- mutex_lock(&lower_dentry->d_inode->i_mutex);
- rc = lower_dentry->d_inode->i_op->getxattr(lower_dentry, name, value,
- size);
- mutex_unlock(&lower_dentry->d_inode->i_mutex);
-out:
- return rc;
+ return ecryptfs_getxattr_lower(ecryptfs_dentry_to_lower(dentry), name,
+ value, size);
}

static ssize_t
--
1.5.1.6

2007-09-17 21:55:19

by Michael Halcrow

[permalink] [raw]
Subject: [PATCH 8/11] eCryptfs: Convert mmap functions to use persistent file

Convert readpage, prepare_write, and commit_write to use read_write.c
routines. Remove sync_page; I cannot think of a good reason for
implementing that in eCryptfs.

Signed-off-by: Michael Halcrow <[email protected]>
---
fs/ecryptfs/mmap.c | 199 +++++++++++++++++++++++++++-------------------------
1 files changed, 103 insertions(+), 96 deletions(-)

diff --git a/fs/ecryptfs/mmap.c b/fs/ecryptfs/mmap.c
index 60e635e..dd68dd3 100644
--- a/fs/ecryptfs/mmap.c
+++ b/fs/ecryptfs/mmap.c
@@ -267,9 +267,78 @@ static void set_header_info(char *page_virt,
}

/**
+ * ecryptfs_copy_up_encrypted_with_header
+ * @page: Sort of a ``virtual'' representation of the encrypted lower
+ * file. The actual lower file does not have the metadata in
+ * the header.
+ * @crypt_stat: The eCryptfs inode's cryptographic context
+ *
+ * The ``view'' is the version of the file that userspace winds up
+ * seeing, with the header information inserted.
+ */
+static int
+ecryptfs_copy_up_encrypted_with_header(struct page *page,
+ struct ecryptfs_crypt_stat *crypt_stat)
+{
+ loff_t extent_num_in_page = 0;
+ loff_t num_extents_per_page = (PAGE_CACHE_SIZE
+ / crypt_stat->extent_size);
+ int rc = 0;
+
+ while (extent_num_in_page < num_extents_per_page) {
+ loff_t view_extent_num = ((page->index * num_extents_per_page)
+ + extent_num_in_page);
+
+ if (view_extent_num < crypt_stat->num_header_extents_at_front) {
+ /* This is a header extent */
+ char *page_virt;
+
+ page_virt = kmap_atomic(page, KM_USER0);
+ memset(page_virt, 0, PAGE_CACHE_SIZE);
+ /* TODO: Support more than one header extent */
+ if (view_extent_num == 0) {
+ rc = ecryptfs_read_xattr_region(
+ page_virt, page->mapping->host);
+ set_header_info(page_virt, crypt_stat);
+ }
+ kunmap_atomic(page_virt, KM_USER0);
+ flush_dcache_page(page);
+ if (rc) {
+ ClearPageUptodate(page);
+ printk(KERN_ERR "%s: Error reading xattr "
+ "region; rc = [%d]\n", __FUNCTION__, rc);
+ goto out;
+ }
+ SetPageUptodate(page);
+ } else {
+ /* This is an encrypted data extent */
+ loff_t lower_offset =
+ ((view_extent_num -
+ crypt_stat->num_header_extents_at_front)
+ * crypt_stat->extent_size);
+
+ rc = ecryptfs_read_lower_page_segment(
+ page, (lower_offset >> PAGE_CACHE_SHIFT),
+ (lower_offset & ~PAGE_CACHE_MASK),
+ crypt_stat->extent_size, page->mapping->host);
+ if (rc) {
+ printk(KERN_ERR "%s: Error attempting to read "
+ "extent at offset [%lld] in the lower "
+ "file; rc = [%d]\n", __FUNCTION__,
+ lower_offset, rc);
+ goto out;
+ }
+ }
+ extent_num_in_page++;
+ }
+out:
+ return rc;
+}
+
+/**
* ecryptfs_readpage
- * @file: This is an ecryptfs file
- * @page: ecryptfs associated page to stick the read data into
+ * @file: An eCryptfs file
+ * @page: Page from eCryptfs inode mapping into which to stick the read data
*
* Read in a page, decrypting if necessary.
*
@@ -277,59 +346,35 @@ static void set_header_info(char *page_virt,
*/
static int ecryptfs_readpage(struct file *file, struct page *page)
{
+ struct ecryptfs_crypt_stat *crypt_stat =
+ &ecryptfs_inode_to_private(file->f_path.dentry->d_inode)->crypt_stat;
int rc = 0;
- struct ecryptfs_crypt_stat *crypt_stat;

- BUG_ON(!(file && file->f_path.dentry && file->f_path.dentry->d_inode));
- crypt_stat = &ecryptfs_inode_to_private(file->f_path.dentry->d_inode)
- ->crypt_stat;
if (!crypt_stat
|| !(crypt_stat->flags & ECRYPTFS_ENCRYPTED)
|| (crypt_stat->flags & ECRYPTFS_NEW_FILE)) {
ecryptfs_printk(KERN_DEBUG,
"Passing through unencrypted page\n");
- rc = ecryptfs_do_readpage(file, page, page->index);
- if (rc) {
- ecryptfs_printk(KERN_ERR, "Error reading page; rc = "
- "[%d]\n", rc);
- goto out;
- }
+ rc = ecryptfs_read_lower_page_segment(page, page->index, 0,
+ PAGE_CACHE_SIZE,
+ page->mapping->host);
} else if (crypt_stat->flags & ECRYPTFS_VIEW_AS_ENCRYPTED) {
if (crypt_stat->flags & ECRYPTFS_METADATA_IN_XATTR) {
- int num_pages_in_header_region =
- (crypt_stat->extent_size
- / PAGE_CACHE_SIZE);
-
- if (page->index < num_pages_in_header_region) {
- char *page_virt;
-
- page_virt = kmap_atomic(page, KM_USER0);
- memset(page_virt, 0, PAGE_CACHE_SIZE);
- if (page->index == 0) {
- rc = ecryptfs_read_xattr_region(
- page_virt, page->mapping->host);
- set_header_info(page_virt, crypt_stat);
- }
- kunmap_atomic(page_virt, KM_USER0);
- flush_dcache_page(page);
- if (rc) {
- printk(KERN_ERR "Error reading xattr "
- "region\n");
- goto out;
- }
- } else {
- rc = ecryptfs_do_readpage(
- file, page,
- (page->index
- - num_pages_in_header_region));
- if (rc) {
- printk(KERN_ERR "Error reading page; "
- "rc = [%d]\n", rc);
- goto out;
- }
+ rc = ecryptfs_copy_up_encrypted_with_header(page,
+ crypt_stat);
+ if (rc) {
+ printk(KERN_ERR "%s: Error attempting to copy "
+ "the encrypted content from the lower "
+ "file whilst inserting the metadata "
+ "from the xattr into the header; rc = "
+ "[%d]\n", __FUNCTION__, rc);
+ goto out;
}
+
} else {
- rc = ecryptfs_do_readpage(file, page, page->index);
+ rc = ecryptfs_read_lower_page_segment(
+ page, page->index, 0, PAGE_CACHE_SIZE,
+ page->mapping->host);
if (rc) {
printk(KERN_ERR "Error reading page; rc = "
"[%d]\n", rc);
@@ -344,10 +389,7 @@ static int ecryptfs_readpage(struct file *file, struct page *page)
goto out;
}
}
- SetPageUptodate(page);
out:
- if (rc)
- ClearPageUptodate(page);
ecryptfs_printk(KERN_DEBUG, "Unlocking page with index = [0x%.16x]\n",
page->index);
unlock_page(page);
@@ -403,9 +445,12 @@ static int ecryptfs_prepare_write(struct file *file, struct page *page,
goto out; /* If we are writing a full page, it will be
up to date. */
if (!PageUptodate(page))
- rc = ecryptfs_do_readpage(file, page, page->index);
+ rc = ecryptfs_read_lower_page_segment(page, page->index, 0,
+ PAGE_CACHE_SIZE,
+ page->mapping->host);
if (page->index != 0) {
- loff_t end_of_prev_pg_pos = page_offset(page) - 1;
+ loff_t end_of_prev_pg_pos =
+ (((loff_t)page->index << PAGE_CACHE_SHIFT) - 1);

if (end_of_prev_pg_pos > i_size_read(page->mapping->host)) {
rc = ecryptfs_truncate(file->f_path.dentry,
@@ -633,18 +678,11 @@ static int ecryptfs_commit_write(struct file *file, struct page *page,
unsigned from, unsigned to)
{
loff_t pos;
- struct inode *inode;
- struct inode *lower_inode;
- struct file *lower_file;
- struct ecryptfs_crypt_stat *crypt_stat;
+ struct inode *ecryptfs_inode = page->mapping->host;
+ struct ecryptfs_crypt_stat *crypt_stat =
+ &ecryptfs_inode_to_private(file->f_path.dentry->d_inode)->crypt_stat;
int rc;

- inode = page->mapping->host;
- lower_inode = ecryptfs_inode_to_lower(inode);
- lower_file = ecryptfs_file_to_lower(file);
- mutex_lock(&lower_inode->i_mutex);
- crypt_stat = &ecryptfs_inode_to_private(file->f_path.dentry->d_inode)
- ->crypt_stat;
if (crypt_stat->flags & ECRYPTFS_NEW_FILE) {
ecryptfs_printk(KERN_DEBUG, "ECRYPTFS_NEW_FILE flag set in "
"crypt_stat at memory location [%p]\n", crypt_stat);
@@ -654,6 +692,7 @@ static int ecryptfs_commit_write(struct file *file, struct page *page,
ecryptfs_printk(KERN_DEBUG, "Calling fill_zeros_to_end_of_page"
"(page w/ index = [0x%.16x], to = [%d])\n", page->index,
to);
+ /* Fills in zeros if 'to' goes beyond inode size */
rc = fill_zeros_to_end_of_page(page, to);
if (rc) {
ecryptfs_printk(KERN_WARNING, "Error attempting to fill "
@@ -667,25 +706,17 @@ static int ecryptfs_commit_write(struct file *file, struct page *page,
"index [0x%.16x])\n", page->index);
goto out;
}
- inode->i_blocks = lower_inode->i_blocks;
- pos = page_offset(page) + to;
- if (pos > i_size_read(inode)) {
- i_size_write(inode, pos);
+ pos = (page->index << PAGE_CACHE_SHIFT) + to;
+ if (pos > i_size_read(ecryptfs_inode)) {
+ i_size_write(ecryptfs_inode, pos);
ecryptfs_printk(KERN_DEBUG, "Expanded file size to "
- "[0x%.16x]\n", i_size_read(inode));
+ "[0x%.16x]\n", i_size_read(ecryptfs_inode));
}
- rc = ecryptfs_write_inode_size_to_metadata(inode);
+ rc = ecryptfs_write_inode_size_to_metadata(ecryptfs_inode);
if (rc)
printk(KERN_ERR "Error writing inode size to metadata; "
"rc = [%d]\n", rc);
- lower_inode->i_mtime = lower_inode->i_ctime = CURRENT_TIME;
- mark_inode_dirty_sync(inode);
out:
- if (rc < 0)
- ClearPageUptodate(page);
- else
- SetPageUptodate(page);
- mutex_unlock(&lower_inode->i_mutex);
return rc;
}

@@ -751,34 +782,10 @@ static sector_t ecryptfs_bmap(struct address_space *mapping, sector_t block)
return rc;
}

-static void ecryptfs_sync_page(struct page *page)
-{
- struct inode *inode;
- struct inode *lower_inode;
- struct page *lower_page;
-
- inode = page->mapping->host;
- lower_inode = ecryptfs_inode_to_lower(inode);
- /* NOTE: Recently swapped with grab_cache_page(), since
- * sync_page() just makes sure that pending I/O gets done. */
- lower_page = find_lock_page(lower_inode->i_mapping, page->index);
- if (!lower_page) {
- ecryptfs_printk(KERN_DEBUG, "find_lock_page failed\n");
- return;
- }
- if (lower_page->mapping->a_ops->sync_page)
- lower_page->mapping->a_ops->sync_page(lower_page);
- ecryptfs_printk(KERN_DEBUG, "Unlocking page with index = [0x%.16x]\n",
- lower_page->index);
- unlock_page(lower_page);
- page_cache_release(lower_page);
-}
-
struct address_space_operations ecryptfs_aops = {
.writepage = ecryptfs_writepage,
.readpage = ecryptfs_readpage,
.prepare_write = ecryptfs_prepare_write,
.commit_write = ecryptfs_commit_write,
.bmap = ecryptfs_bmap,
- .sync_page = ecryptfs_sync_page,
};
--
1.5.1.6

2007-09-17 21:55:46

by Michael Halcrow

[permalink] [raw]
Subject: [PATCH 9/11] eCryptfs: Initialize persistent lower file on inode create

Initialize persistent lower file on inode create.

Signed-off-by: Michael Halcrow <[email protected]>
---
fs/ecryptfs/super.c | 13 +++++++------
1 files changed, 7 insertions(+), 6 deletions(-)

diff --git a/fs/ecryptfs/super.c b/fs/ecryptfs/super.c
index b97e210..f8cdab2 100644
--- a/fs/ecryptfs/super.c
+++ b/fs/ecryptfs/super.c
@@ -47,15 +47,16 @@ struct kmem_cache *ecryptfs_inode_info_cache;
*/
static struct inode *ecryptfs_alloc_inode(struct super_block *sb)
{
- struct ecryptfs_inode_info *ecryptfs_inode;
+ struct ecryptfs_inode_info *inode_info;
struct inode *inode = NULL;

- ecryptfs_inode = kmem_cache_alloc(ecryptfs_inode_info_cache,
- GFP_KERNEL);
- if (unlikely(!ecryptfs_inode))
+ inode_info = kmem_cache_alloc(ecryptfs_inode_info_cache, GFP_KERNEL);
+ if (unlikely(!inode_info))
goto out;
- ecryptfs_init_crypt_stat(&ecryptfs_inode->crypt_stat);
- inode = &ecryptfs_inode->vfs_inode;
+ ecryptfs_init_crypt_stat(&inode_info->crypt_stat);
+ mutex_init(&inode_info->lower_file_mutex);
+ inode_info->lower_file = NULL;
+ inode = &inode_info->vfs_inode;
out:
return inode;
}
--
1.5.1.6

2007-09-17 21:56:41

by Michael Halcrow

[permalink] [raw]
Subject: [PATCH 10/11] eCryptfs: Remove unused functions and kmem_cache

The switch to read_write.c routines and the persistent file make a
number of functions unnecessary. This patch removes them.

Signed-off-by: Michael Halcrow <[email protected]>
---
fs/ecryptfs/crypto.c | 150 ------------------
fs/ecryptfs/ecryptfs_kernel.h | 21 +---
fs/ecryptfs/file.c | 28 ----
fs/ecryptfs/main.c | 5 -
fs/ecryptfs/mmap.c | 336 -----------------------------------------
5 files changed, 1 insertions(+), 539 deletions(-)

diff --git a/fs/ecryptfs/crypto.c b/fs/ecryptfs/crypto.c
index b3014d7..3b3cf27 100644
--- a/fs/ecryptfs/crypto.c
+++ b/fs/ecryptfs/crypto.c
@@ -353,119 +353,6 @@ out:
return rc;
}

-static void
-ecryptfs_extent_to_lwr_pg_idx_and_offset(unsigned long *lower_page_idx,
- int *byte_offset,
- struct ecryptfs_crypt_stat *crypt_stat,
- unsigned long extent_num)
-{
- unsigned long lower_extent_num;
- int extents_occupied_by_headers_at_front;
- int bytes_occupied_by_headers_at_front;
- int extent_offset;
- int extents_per_page;
-
- bytes_occupied_by_headers_at_front =
- (crypt_stat->extent_size
- * crypt_stat->num_header_extents_at_front);
- extents_occupied_by_headers_at_front =
- ( bytes_occupied_by_headers_at_front
- / crypt_stat->extent_size );
- lower_extent_num = extents_occupied_by_headers_at_front + extent_num;
- extents_per_page = PAGE_CACHE_SIZE / crypt_stat->extent_size;
- (*lower_page_idx) = lower_extent_num / extents_per_page;
- extent_offset = lower_extent_num % extents_per_page;
- (*byte_offset) = extent_offset * crypt_stat->extent_size;
- ecryptfs_printk(KERN_DEBUG, " * crypt_stat->extent_size = "
- "[%d]\n", crypt_stat->extent_size);
- ecryptfs_printk(KERN_DEBUG, " * crypt_stat->"
- "num_header_extents_at_front = [%d]\n",
- crypt_stat->num_header_extents_at_front);
- ecryptfs_printk(KERN_DEBUG, " * extents_occupied_by_headers_at_"
- "front = [%d]\n", extents_occupied_by_headers_at_front);
- ecryptfs_printk(KERN_DEBUG, " * lower_extent_num = [0x%.16x]\n",
- lower_extent_num);
- ecryptfs_printk(KERN_DEBUG, " * extents_per_page = [%d]\n",
- extents_per_page);
- ecryptfs_printk(KERN_DEBUG, " * (*lower_page_idx) = [0x%.16x]\n",
- (*lower_page_idx));
- ecryptfs_printk(KERN_DEBUG, " * extent_offset = [%d]\n",
- extent_offset);
- ecryptfs_printk(KERN_DEBUG, " * (*byte_offset) = [%d]\n",
- (*byte_offset));
-}
-
-static int ecryptfs_write_out_page(struct ecryptfs_page_crypt_context *ctx,
- struct page *lower_page,
- struct inode *lower_inode,
- int byte_offset_in_page, int bytes_to_write)
-{
- int rc = 0;
-
- if (ctx->mode == ECRYPTFS_PREPARE_COMMIT_MODE) {
- rc = ecryptfs_commit_lower_page(lower_page, lower_inode,
- ctx->param.lower_file,
- byte_offset_in_page,
- bytes_to_write);
- if (rc) {
- ecryptfs_printk(KERN_ERR, "Error calling lower "
- "commit; rc = [%d]\n", rc);
- goto out;
- }
- } else {
- rc = ecryptfs_writepage_and_release_lower_page(lower_page,
- lower_inode,
- ctx->param.wbc);
- if (rc) {
- ecryptfs_printk(KERN_ERR, "Error calling lower "
- "writepage(); rc = [%d]\n", rc);
- goto out;
- }
- }
-out:
- return rc;
-}
-
-static int ecryptfs_read_in_page(struct ecryptfs_page_crypt_context *ctx,
- struct page **lower_page,
- struct inode *lower_inode,
- unsigned long lower_page_idx,
- int byte_offset_in_page)
-{
- int rc = 0;
-
- if (ctx->mode == ECRYPTFS_PREPARE_COMMIT_MODE) {
- /* TODO: Limit this to only the data extents that are
- * needed */
- rc = ecryptfs_get_lower_page(lower_page, lower_inode,
- ctx->param.lower_file,
- lower_page_idx,
- byte_offset_in_page,
- (PAGE_CACHE_SIZE
- - byte_offset_in_page));
- if (rc) {
- ecryptfs_printk(
- KERN_ERR, "Error attempting to grab, map, "
- "and prepare_write lower page with index "
- "[0x%.16x]; rc = [%d]\n", lower_page_idx, rc);
- goto out;
- }
- } else {
- *lower_page = grab_cache_page(lower_inode->i_mapping,
- lower_page_idx);
- if (!(*lower_page)) {
- rc = -EINVAL;
- ecryptfs_printk(
- KERN_ERR, "Error attempting to grab and map "
- "lower page with index [0x%.16x]; rc = [%d]\n",
- lower_page_idx, rc);
- goto out;
- }
- }
-out:
- return rc;
-}
-
/**
* ecryptfs_lower_offset_for_extent
*
@@ -1307,43 +1194,6 @@ int ecryptfs_cipher_code_to_string(char *str, u16 cipher_code)
return rc;
}

-/**
- * ecryptfs_read_header_region
- * @data: The virtual address to write header region data into
- * @dentry: The lower dentry
- * @mnt: The lower VFS mount
- *
- * Returns zero on success; non-zero otherwise
- */
-static int ecryptfs_read_header_region(char *data, struct dentry *dentry,
- struct vfsmount *mnt)
-{
- struct file *lower_file;
- mm_segment_t oldfs;
- int rc;
-
- rc = ecryptfs_open_lower_file(&lower_file, dentry, mnt, O_RDONLY);
- if (rc) {
- printk(KERN_ERR
- "Error opening lower_file to read header region\n");
- goto out;
- }
- lower_file->f_pos = 0;
- oldfs = get_fs();
- set_fs(get_ds());
- rc = lower_file->f_op->read(lower_file, (char __user *)data,
- ECRYPTFS_DEFAULT_EXTENT_SIZE, &lower_file->f_pos);
- set_fs(oldfs);
- rc = ecryptfs_close_lower_file(lower_file);
- if (rc) {
- printk(KERN_ERR "Error closing lower_file\n");
- goto out;
- }
- rc = 0;
-out:
- return rc;
-}
-
int ecryptfs_read_and_validate_header_region(char *data,
struct inode *ecryptfs_inode)
{
diff --git a/fs/ecryptfs/ecryptfs_kernel.h b/fs/ecryptfs/ecryptfs_kernel.h
index 3e52b42..bb92b74 100644
--- a/fs/ecryptfs/ecryptfs_kernel.h
+++ b/fs/ecryptfs/ecryptfs_kernel.h
@@ -552,22 +552,7 @@ void ecryptfs_destroy_crypt_stat(struct ecryptfs_crypt_stat *crypt_stat);
void ecryptfs_destroy_mount_crypt_stat(
struct ecryptfs_mount_crypt_stat *mount_crypt_stat);
int ecryptfs_init_crypt_ctx(struct ecryptfs_crypt_stat *crypt_stat);
-int ecryptfs_write_inode_size_to_metadata(struct inode *ecryptefs_inode);
-int ecryptfs_get_lower_page(struct page **lower_page, struct inode *lower_inode,
- struct file *lower_file,
- unsigned long lower_page_index, int byte_offset,
- int region_bytes);
-int
-ecryptfs_commit_lower_page(struct page *lower_page, struct inode *lower_inode,
- struct file *lower_file, int byte_offset,
- int region_size);
-int ecryptfs_copy_page_to_lower(struct page *page, struct inode *lower_inode,
- struct file *lower_file);
-int ecryptfs_do_readpage(struct file *file, struct page *page,
- pgoff_t lower_page_index);
-int ecryptfs_writepage_and_release_lower_page(struct page *lower_page,
- struct inode *lower_inode,
- struct writeback_control *wbc);
+int ecryptfs_write_inode_size_to_metadata(struct inode *ecryptfs_inode);
int ecryptfs_encrypt_page(struct page *page);
int ecryptfs_decrypt_page(struct page *page);
int ecryptfs_write_metadata(struct dentry *ecryptfs_dentry);
@@ -591,10 +576,6 @@ int ecryptfs_truncate(struct dentry *dentry, loff_t new_length);
int ecryptfs_inode_test(struct inode *inode, void *candidate_lower_inode);
int ecryptfs_inode_set(struct inode *inode, void *lower_inode);
void ecryptfs_init_inode(struct inode *inode, struct inode *lower_inode);
-int ecryptfs_open_lower_file(struct file **lower_file,
- struct dentry *lower_dentry,
- struct vfsmount *lower_mnt, int flags);
-int ecryptfs_close_lower_file(struct file *lower_file);
ssize_t ecryptfs_getxattr(struct dentry *dentry, const char *name, void *value,
size_t size);
ssize_t
diff --git a/fs/ecryptfs/file.c b/fs/ecryptfs/file.c
index 95be9a9..c98c469 100644
--- a/fs/ecryptfs/file.c
+++ b/fs/ecryptfs/file.c
@@ -141,34 +141,6 @@ retry:

struct kmem_cache *ecryptfs_file_info_cache;

-int ecryptfs_open_lower_file(struct file **lower_file,
- struct dentry *lower_dentry,
- struct vfsmount *lower_mnt, int flags)
-{
- int rc = 0;
-
- flags |= O_LARGEFILE;
- dget(lower_dentry);
- mntget(lower_mnt);
- *lower_file = dentry_open(lower_dentry, lower_mnt, flags);
- if (IS_ERR(*lower_file)) {
- printk(KERN_ERR "Error opening lower file for lower_dentry "
- "[0x%p], lower_mnt [0x%p], and flags [0x%x]\n",
- lower_dentry, lower_mnt, flags);
- rc = PTR_ERR(*lower_file);
- *lower_file = NULL;
- goto out;
- }
-out:
- return rc;
-}
-
-int ecryptfs_close_lower_file(struct file *lower_file)
-{
- fput(lower_file);
- return 0;
-}
-
/**
* ecryptfs_open
* @inode: inode speciying file to open
diff --git a/fs/ecryptfs/main.c b/fs/ecryptfs/main.c
index 3e324f8..92b1e6c 100644
--- a/fs/ecryptfs/main.c
+++ b/fs/ecryptfs/main.c
@@ -670,11 +670,6 @@ static struct ecryptfs_cache_info {
.size = PAGE_CACHE_SIZE,
},
{
- .cache = &ecryptfs_lower_page_cache,
- .name = "ecryptfs_lower_page_cache",
- .size = PAGE_CACHE_SIZE,
- },
- {
.cache = &ecryptfs_key_record_cache,
.name = "ecryptfs_key_record_cache",
.size = sizeof(struct ecryptfs_key_record),
diff --git a/fs/ecryptfs/mmap.c b/fs/ecryptfs/mmap.c
index ecd43da..c90d5a8 100644
--- a/fs/ecryptfs/mmap.c
+++ b/fs/ecryptfs/mmap.c
@@ -57,113 +57,6 @@ struct page *ecryptfs_get1page(struct file *file, loff_t index)
}

/**
- * ecryptfs_fill_zeros
- * @file: The ecryptfs file
- * @new_length: The new length of the data in the underlying file;
- * everything between the prior end of the file and the
- * new end of the file will be filled with zero's.
- * new_length must be greater than current length
- *
- * Function for handling lseek-ing past the end of the file.
- *
- * This function does not support shrinking, only growing a file.
- *
- * Returns zero on success; non-zero otherwise.
- */
-int ecryptfs_fill_zeros(struct file *file, loff_t new_length)
-{
- int rc = 0;
- struct dentry *dentry = file->f_path.dentry;
- struct inode *inode = dentry->d_inode;
- pgoff_t old_end_page_index = 0;
- pgoff_t index = old_end_page_index;
- int old_end_pos_in_page = -1;
- pgoff_t new_end_page_index;
- int new_end_pos_in_page;
- loff_t cur_length = i_size_read(inode);
-
- if (cur_length != 0) {
- index = old_end_page_index =
- ((cur_length - 1) >> PAGE_CACHE_SHIFT);
- old_end_pos_in_page = ((cur_length - 1) & ~PAGE_CACHE_MASK);
- }
- new_end_page_index = ((new_length - 1) >> PAGE_CACHE_SHIFT);
- new_end_pos_in_page = ((new_length - 1) & ~PAGE_CACHE_MASK);
- ecryptfs_printk(KERN_DEBUG, "old_end_page_index = [0x%.16x]; "
- "old_end_pos_in_page = [%d]; "
- "new_end_page_index = [0x%.16x]; "
- "new_end_pos_in_page = [%d]\n",
- old_end_page_index, old_end_pos_in_page,
- new_end_page_index, new_end_pos_in_page);
- if (old_end_page_index == new_end_page_index) {
- /* Start and end are in the same page; we just need to
- * set a portion of the existing page to zero's */
- rc = ecryptfs_write_zeros(file, index,
- (old_end_pos_in_page + 1),
- (new_end_pos_in_page
- - old_end_pos_in_page));
- if (rc)
- ecryptfs_printk(KERN_ERR, "ecryptfs_write_zeros("
- "file=[%p], "
- "index=[0x%.16x], "
- "old_end_pos_in_page=[d], "
- "(PAGE_CACHE_SIZE - new_end_pos_in_page"
- "=[%d]"
- ")=[d]) returned [%d]\n", file, index,
- old_end_pos_in_page,
- new_end_pos_in_page,
- (PAGE_CACHE_SIZE - new_end_pos_in_page),
- rc);
- goto out;
- }
- /* Fill the remainder of the previous last page with zeros */
- rc = ecryptfs_write_zeros(file, index, (old_end_pos_in_page + 1),
- ((PAGE_CACHE_SIZE - 1) - old_end_pos_in_page));
- if (rc) {
- ecryptfs_printk(KERN_ERR, "ecryptfs_write_zeros(file=[%p], "
- "index=[0x%.16x], old_end_pos_in_page=[d], "
- "(PAGE_CACHE_SIZE - old_end_pos_in_page)=[d]) "
- "returned [%d]\n", file, index,
- old_end_pos_in_page,
- (PAGE_CACHE_SIZE - old_end_pos_in_page), rc);
- goto out;
- }
- index++;
- while (index < new_end_page_index) {
- /* Fill all intermediate pages with zeros */
- rc = ecryptfs_write_zeros(file, index, 0, PAGE_CACHE_SIZE);
- if (rc) {
- ecryptfs_printk(KERN_ERR, "ecryptfs_write_zeros("
- "file=[%p], "
- "index=[0x%.16x], "
- "old_end_pos_in_page=[d], "
- "(PAGE_CACHE_SIZE - new_end_pos_in_page"
- "=[%d]"
- ")=[d]) returned [%d]\n", file, index,
- old_end_pos_in_page,
- new_end_pos_in_page,
- (PAGE_CACHE_SIZE - new_end_pos_in_page),
- rc);
- goto out;
- }
- index++;
- }
- /* Fill the portion at the beginning of the last new page with
- * zero's */
- rc = ecryptfs_write_zeros(file, index, 0, (new_end_pos_in_page + 1));
- if (rc) {
- ecryptfs_printk(KERN_ERR, "ecryptfs_write_zeros(file="
- "[%p], index=[0x%.16x], 0, "
- "new_end_pos_in_page=[%d]"
- "returned [%d]\n", file, index,
- new_end_pos_in_page, rc);
- goto out;
- }
-out:
- return rc;
-}
-
-/**
* ecryptfs_writepage
* @page: Page that is locked before this call is made
*
@@ -187,58 +80,6 @@ out:
}

/**
- * Reads the data from the lower file file at index lower_page_index
- * and copies that data into page.
- *
- * @param page Page to fill
- * @param lower_page_index Index of the page in the lower file to get
- */
-int ecryptfs_do_readpage(struct file *file, struct page *page,
- pgoff_t lower_page_index)
-{
- int rc;
- struct dentry *dentry;
- struct file *lower_file;
- struct dentry *lower_dentry;
- struct inode *inode;
- struct inode *lower_inode;
- char *page_data;
- struct page *lower_page = NULL;
- char *lower_page_data;
- const struct address_space_operations *lower_a_ops;
-
- dentry = file->f_path.dentry;
- lower_file = ecryptfs_file_to_lower(file);
- lower_dentry = ecryptfs_dentry_to_lower(dentry);
- inode = dentry->d_inode;
- lower_inode = ecryptfs_inode_to_lower(inode);
- lower_a_ops = lower_inode->i_mapping->a_ops;
- lower_page = read_cache_page(lower_inode->i_mapping, lower_page_index,
- (filler_t *)lower_a_ops->readpage,
- (void *)lower_file);
- if (IS_ERR(lower_page)) {
- rc = PTR_ERR(lower_page);
- lower_page = NULL;
- ecryptfs_printk(KERN_ERR, "Error reading from page cache\n");
- goto out;
- }
- page_data = kmap_atomic(page, KM_USER0);
- lower_page_data = kmap_atomic(lower_page, KM_USER1);
- memcpy(page_data, lower_page_data, PAGE_CACHE_SIZE);
- kunmap_atomic(lower_page_data, KM_USER1);
- kunmap_atomic(page_data, KM_USER0);
- flush_dcache_page(page);
- rc = 0;
-out:
- if (likely(lower_page))
- page_cache_release(lower_page);
- if (rc == 0)
- SetPageUptodate(page);
- else
- ClearPageUptodate(page);
- return rc;
-}
-/**
* Header Extent:
* Octets 0-7: Unencrypted file size (big-endian)
* Octets 8-15: eCryptfs special marker
@@ -416,27 +257,6 @@ out:
return 0;
}

-/**
- * eCryptfs does not currently support holes. When writing after a
- * seek past the end of the file, eCryptfs fills in 0's through to the
- * current location. The code to fill in the 0's to all the
- * intermediate pages calls ecryptfs_prepare_write_no_truncate().
- */
-static int
-ecryptfs_prepare_write_no_truncate(struct file *file, struct page *page,
- unsigned from, unsigned to)
-{
- int rc = 0;
-
- if (from == 0 && to == PAGE_CACHE_SIZE)
- goto out; /* If we are writing a full page, it will be
- up to date. */
- if (!PageUptodate(page))
- rc = ecryptfs_do_readpage(file, page, page->index);
-out:
- return rc;
-}
-
static int ecryptfs_prepare_write(struct file *file, struct page *page,
unsigned from, unsigned to)
{
@@ -470,30 +290,6 @@ out:
return rc;
}

-int ecryptfs_writepage_and_release_lower_page(struct page *lower_page,
- struct inode *lower_inode,
- struct writeback_control *wbc)
-{
- int rc = 0;
-
- rc = lower_inode->i_mapping->a_ops->writepage(lower_page, wbc);
- if (rc) {
- ecryptfs_printk(KERN_ERR, "Error calling lower writepage(); "
- "rc = [%d]\n", rc);
- goto out;
- }
- lower_inode->i_mtime = lower_inode->i_ctime = CURRENT_TIME;
- page_cache_release(lower_page);
-out:
- return rc;
-}
-
-static void ecryptfs_release_lower_page(struct page *lower_page)
-{
- unlock_page(lower_page);
- page_cache_release(lower_page);
-}
-
/**
* ecryptfs_write_inode_size_to_header
*
@@ -580,90 +376,6 @@ int ecryptfs_write_inode_size_to_metadata(struct inode *ecryptfs_inode)
return ecryptfs_write_inode_size_to_header(ecryptfs_inode);
}

-int ecryptfs_get_lower_page(struct page **lower_page, struct inode *lower_inode,
- struct file *lower_file,
- unsigned long lower_page_index, int byte_offset,
- int region_bytes)
-{
- int rc = 0;
-
- *lower_page = grab_cache_page(lower_inode->i_mapping, lower_page_index);
- if (!(*lower_page)) {
- rc = -EINVAL;
- ecryptfs_printk(KERN_ERR, "Error attempting to grab "
- "lower page with index [0x%.16x]\n",
- lower_page_index);
- goto out;
- }
- rc = lower_inode->i_mapping->a_ops->prepare_write(lower_file,
- (*lower_page),
- byte_offset,
- region_bytes);
- if (rc) {
- ecryptfs_printk(KERN_ERR, "prepare_write for "
- "lower_page_index = [0x%.16x] failed; rc = "
- "[%d]\n", lower_page_index, rc);
- ecryptfs_release_lower_page(*lower_page);
- (*lower_page) = NULL;
- }
-out:
- return rc;
-}
-
-/**
- * ecryptfs_commit_lower_page
- *
- * Returns zero on success; non-zero on error
- */
-int
-ecryptfs_commit_lower_page(struct page *lower_page, struct inode *lower_inode,
- struct file *lower_file, int byte_offset,
- int region_size)
-{
- int rc = 0;
-
- rc = lower_inode->i_mapping->a_ops->commit_write(
- lower_file, lower_page, byte_offset, region_size);
- if (rc < 0) {
- ecryptfs_printk(KERN_ERR,
- "Error committing write; rc = [%d]\n", rc);
- } else
- rc = 0;
- ecryptfs_release_lower_page(lower_page);
- return rc;
-}
-
-/**
- * ecryptfs_copy_page_to_lower
- *
- * Used for plaintext pass-through; no page index interpolation
- * required.
- */
-int ecryptfs_copy_page_to_lower(struct page *page, struct inode *lower_inode,
- struct file *lower_file)
-{
- int rc = 0;
- struct page *lower_page;
-
- rc = ecryptfs_get_lower_page(&lower_page, lower_inode, lower_file,
- page->index, 0, PAGE_CACHE_SIZE);
- if (rc) {
- ecryptfs_printk(KERN_ERR, "Error attempting to get page "
- "at index [0x%.16x]\n", page->index);
- goto out;
- }
- /* TODO: aops */
- memcpy((char *)page_address(lower_page), page_address(page),
- PAGE_CACHE_SIZE);
- rc = ecryptfs_commit_lower_page(lower_page, lower_inode, lower_file,
- 0, PAGE_CACHE_SIZE);
- if (rc)
- ecryptfs_printk(KERN_ERR, "Error attempting to commit page "
- "at index [0x%.16x]\n", page->index);
-out:
- return rc;
-}
-
/**
* ecryptfs_commit_write
* @file: The eCryptfs file object
@@ -721,54 +433,6 @@ out:
return rc;
}

-/**
- * ecryptfs_write_zeros
- * @file: The ecryptfs file
- * @index: The index in which we are writing
- * @start: The position after the last block of data
- * @num_zeros: The number of zeros to write
- *
- * Write a specified number of zero's to a page.
- *
- * (start + num_zeros) must be less than or equal to PAGE_CACHE_SIZE
- */
-int
-ecryptfs_write_zeros(struct file *file, pgoff_t index, int start, int num_zeros)
-{
- int rc = 0;
- struct page *tmp_page;
-
- tmp_page = ecryptfs_get1page(file, index);
- if (IS_ERR(tmp_page)) {
- ecryptfs_printk(KERN_ERR, "Error getting page at index "
- "[0x%.16x]\n", index);
- rc = PTR_ERR(tmp_page);
- goto out;
- }
- rc = ecryptfs_prepare_write_no_truncate(file, tmp_page, start,
- (start + num_zeros));
- if (rc) {
- ecryptfs_printk(KERN_ERR, "Error preparing to write zero's "
- "to page at index [0x%.16x]\n",
- index);
- page_cache_release(tmp_page);
- goto out;
- }
- zero_user_page(tmp_page, start, num_zeros, KM_USER0);
- rc = ecryptfs_commit_write(file, tmp_page, start, start + num_zeros);
- if (rc < 0) {
- ecryptfs_printk(KERN_ERR, "Error attempting to write zero's "
- "to remainder of page at index [0x%.16x]\n",
- index);
- page_cache_release(tmp_page);
- goto out;
- }
- rc = 0;
- page_cache_release(tmp_page);
-out:
- return rc;
-}
-
static sector_t ecryptfs_bmap(struct address_space *mapping, sector_t block)
{
int rc = 0;
--
1.5.1.6

2007-09-17 21:56:58

by Michael Halcrow

[permalink] [raw]
Subject: [PATCH 11/11] eCryptfs: Replace magic numbers

Replace some magic numbers with sizeof() equivalents.

Signed-off-by: Michael Halcrow <[email protected]>
---
fs/ecryptfs/crypto.c | 6 +++---
1 files changed, 3 insertions(+), 3 deletions(-)

diff --git a/fs/ecryptfs/crypto.c b/fs/ecryptfs/crypto.c
index 3b3cf27..425a144 100644
--- a/fs/ecryptfs/crypto.c
+++ b/fs/ecryptfs/crypto.c
@@ -1426,10 +1426,10 @@ static int parse_header_metadata(struct ecryptfs_crypt_stat *crypt_stat,
u32 header_extent_size;
u16 num_header_extents_at_front;

- memcpy(&header_extent_size, virt, 4);
+ memcpy(&header_extent_size, virt, sizeof(u32));
header_extent_size = be32_to_cpu(header_extent_size);
- virt += 4;
- memcpy(&num_header_extents_at_front, virt, 2);
+ virt += sizeof(u32);
+ memcpy(&num_header_extents_at_front, virt, sizeof(u16));
num_header_extents_at_front = be16_to_cpu(num_header_extents_at_front);
crypt_stat->num_header_extents_at_front =
(int)num_header_extents_at_front;
--
1.5.1.6

2007-09-20 05:25:32

by Andrew Morton

[permalink] [raw]
Subject: Re: [PATCH 3/11] eCryptfs: read_write.c routines

On Mon, 17 Sep 2007 16:46:32 -0500 Michael Halcrow <[email protected]> wrote:

> +/**
> + * ecryptfs_write_lower
> + * @ecryptfs_inode: The eCryptfs inode
> + * @data: Data to write
> + * @offset: Byte offset in the lower file to which to write the data
> + * @size: Number of bytes from @data to write at @offset in the lower
> + * file
> + *
> + * Write data to the lower file.
> + *
> + * Returns zero on success; non-zero on error
> + */

That might come out looking odd in the kernel doc? Normally the documentation
would start out with

+/**
+ * ecryptfs_write_lower - write data to the lower file

2007-09-20 05:39:31

by Andrew Morton

[permalink] [raw]
Subject: Re: [PATCH 3/11] eCryptfs: read_write.c routines

On Mon, 17 Sep 2007 16:46:32 -0500 Michael Halcrow <[email protected]> wrote:

> Add a set of functions through which all I/O to lower files is
> consolidated. This patch adds a new inode_info reference to a
> persistent lower file for each eCryptfs inode; another patch later in
> this series will set that up. This persistent lower file is what the
> read_write.c functions use to call vfs_read() and vfs_write() on the
> lower filesystem, so even when reads and writes come in through
> aops->readpage and aops->writepage, we can satisfy them without
> resorting to direct access to the lower inode's address space.
> Several function declarations are going to be changing with this
> patchset. For now, in order to keep from breaking the build, I am
> putting dummy parameters in for those functions.
>
> ..
>
> +/**
> + * ecryptfs_write_lower_page_segment
> + * @ecryptfs_inode: The eCryptfs inode
> + * @page_for_lower: The page containing the data to be written to the
> + * lower file
> + * @offset_in_page: The offset in the @page_for_lower from which to
> + * start writing the data
> + * @size: The amount of data from @page_for_lower to write to the
> + * lower file
> + *
> + * Determines the byte offset in the file for the given page and
> + * offset within the page, maps the page, and makes the call to write
> + * the contents of @page_for_lower to the lower inode.
> + *
> + * Returns zero on success; non-zero otherwise
> + */
> +int ecryptfs_write_lower_page_segment(struct inode *ecryptfs_inode,
> + struct page *page_for_lower,
> + size_t offset_in_page, size_t size)
> +{
> + char *virt;
> + loff_t offset;
> + int rc;
> +
> + offset = (page_for_lower->index << PAGE_CACHE_SHIFT) + offset_in_page;

bug. You need to cast page.index to loff_t before shifting.

I'd fix it on the spot, but this would be a good time to review the whole
patchset and perhaps the whole fs for this easy-to-do, hard-to-find bug.

> + virt = kmap(page_for_lower);
> + rc = ecryptfs_write_lower(ecryptfs_inode, virt, offset, size);
> + kunmap(page_for_lower);
> + return rc;
> +}

argh, kmap. http://lkml.org/lkml/2007/9/15/55

> +/**
> + * ecryptfs_write
> + * @ecryptfs_file: The eCryptfs file into which to write
> + * @data: Virtual address where data to write is located
> + * @offset: Offset in the eCryptfs file at which to begin writing the
> + * data from @data
> + * @size: The number of bytes to write from @data
> + *
> + * Write an arbitrary amount of data to an arbitrary location in the
> + * eCryptfs inode page cache. This is done on a page-by-page, and then
> + * by an extent-by-extent, basis; individual extents are encrypted and
> + * written to the lower page cache (via VFS writes). This function
> + * takes care of all the address translation to locations in the lower
> + * filesystem; it also handles truncate events, writing out zeros
> + * where necessary.
> + *
> + * Returns zero on success; non-zero otherwise
> + */
> +int ecryptfs_write(struct file *ecryptfs_file, char *data, loff_t offset,
> + size_t size)
> +{
> + struct page *ecryptfs_page;
> + char *ecryptfs_page_virt;
> + u64 ecryptfs_file_size = i_size_read(ecryptfs_file->f_dentry->d_inode);

Not loff_t?

> + loff_t data_offset = 0;
> + loff_t pos;
> + int rc = 0;
> +
> + if (offset > ecryptfs_file_size)
> + pos = ecryptfs_file_size;

loff_t = u64. The typing seems a bit confused?

> + else
> + pos = offset;
> + while (pos < (offset + size)) {
> + pgoff_t ecryptfs_page_idx = (pos >> PAGE_CACHE_SHIFT);
> + size_t start_offset_in_page = (pos & ~PAGE_CACHE_MASK);
> + size_t num_bytes = (PAGE_CACHE_SIZE - start_offset_in_page);
> + size_t total_remaining_bytes = ((offset + size) - pos);
> +
> + if (num_bytes > total_remaining_bytes)
> + num_bytes = total_remaining_bytes;
> + if (pos < offset) {
> + size_t total_remaining_zeros = (offset - pos);
> +
> + if (num_bytes > total_remaining_zeros)
> + num_bytes = total_remaining_zeros;
> + }
> + ecryptfs_page = ecryptfs_get1page(ecryptfs_file,
> + ecryptfs_page_idx);
> + if (IS_ERR(ecryptfs_page)) {
> + rc = PTR_ERR(ecryptfs_page);
> + printk(KERN_ERR "%s: Error getting page at "
> + "index [%ld] from eCryptfs inode "
> + "mapping; rc = [%d]\n", __FUNCTION__,
> + ecryptfs_page_idx, rc);
> + goto out;
> + }
> + if (start_offset_in_page) {
> + /* Read in the page from the lower
> + * into the eCryptfs inode page cache,
> + * decrypting */
> + if ((rc = ecryptfs_decrypt_page(NULL, /* placeholder for git-bisect */
> + ecryptfs_page))) {

hm, checkpatch doesn't warn about the combined assignment-and-test because
it already warned about the over-80-cols line.


> + printk(KERN_ERR "%s: Error decrypting "
> + "page; rc = [%d]\n",
> + __FUNCTION__, rc);
> + page_cache_release(ecryptfs_page);
> + goto out;
> + }
> + }
> + ecryptfs_page_virt = kmap_atomic(ecryptfs_page, KM_USER0);
> + if (pos >= offset) {
> + memcpy(((char *)ecryptfs_page_virt
> + + start_offset_in_page),
> + (data + data_offset), num_bytes);
> + data_offset += num_bytes;
> + } else {
> + /* We are extending past the previous end of the file.
> + * Fill in zero values up to the start of where we
> + * will be writing data. */
> + memset(((char *)ecryptfs_page_virt
> + + start_offset_in_page), 0, num_bytes);
> + }
> + kunmap_atomic(ecryptfs_page_virt, KM_USER0);
> + flush_dcache_page(ecryptfs_page);
> + rc = ecryptfs_encrypt_page(NULL /* placeholder for git-bisect */);
> + if (rc) {
> + printk(KERN_ERR "%s: Error encrypting "
> + "page; rc = [%d]\n", __FUNCTION__, rc);
> + page_cache_release(ecryptfs_page);
> + goto out;
> + }
> + page_cache_release(ecryptfs_page);
> + pos += num_bytes;
> + }
> + if ((offset + size) > ecryptfs_file_size) {
> + i_size_write(ecryptfs_file->f_dentry->d_inode, (offset + size));
> + rc = ecryptfs_write_inode_size_to_metadata(NULL, NULL, NULL,
> + NULL, 0); /* placeholders for git-bisect */
> + if (rc) {
> + printk(KERN_ERR "Problem with "
> + "ecryptfs_write_inode_size_to_metadata; "
> + "rc = [%d]\n", rc);
> + goto out;
> + }
> + }
> +out:
> + return rc;
> +}
> +
> +/**
> + * ecryptfs_read_lower
> + * @data: The read data is stored here by this function
> + * @offset: Byte offset in the lower file from which to read the data
> + * @size: Number of bytes to read from @offset of the lower file and
> + * store into @data
> + * @ecryptfs_inode: The eCryptfs inode
> + *
> + * Read @size bytes of data at byte offset @offset from the lower
> + * inode into memory location @data.
> + *
> + * Returns zero on success; non-zero on error
> + */
> +int ecryptfs_read_lower(char *data, loff_t offset, size_t size,
> + struct inode *ecryptfs_inode)
> +{
> + struct ecryptfs_inode_info *inode_info =
> + ecryptfs_inode_to_private(ecryptfs_inode);
> + ssize_t octets_read;
> + mm_segment_t fs_save;
> + size_t i;
> + int rc = 0;
> +
> + mutex_lock(&inode_info->lower_file_mutex);
> + BUG_ON(!inode_info->lower_file);
> + inode_info->lower_file->f_pos = offset;
> + fs_save = get_fs();
> + set_fs(get_ds());
> + octets_read = vfs_read(inode_info->lower_file, data, size,
> + &inode_info->lower_file->f_pos);
> + set_fs(fs_save);
> + if (octets_read < 0) {
> + printk(KERN_ERR "%s: octets_read = [%td]; "
> + "expected [%td]\n", __FUNCTION__, octets_read, size);
> + rc = -EINVAL;
> + }
> + mutex_unlock(&inode_info->lower_file_mutex);
> + for (i = 0; i < size; i += PAGE_CACHE_SIZE) {
> + struct page *data_page;
> +
> + data_page = virt_to_page(data + i);
> + flush_dcache_page(data_page);
> + if (rc)
> + ClearPageUptodate(data_page);
> + else
> + SetPageUptodate(data_page);
> + }
> + return rc;
> +}

It's ... strange to do virt_to_page() to get at a pageframe (ie: it is
kernel memory) and to then run xxPageUptodate() against it (ie: it is a
pagecache page).

What's actually happening here?

Has it been tested on i386 highmem?

sparse might get upset about the mixture of kernel pointers and __user
pointers in this new code.

> +/**
> + * ecryptfs_read_lower_page_segment
> + * @page_for_ecryptfs: The page into which data for eCryptfs will be
> + * written
> + * @offset_in_page: Offset in @page_for_ecryptfs from which to start
> + * writing
> + * @size: The number of bytes to write into @page_for_ecryptfs
> + * @ecryptfs_inode: The eCryptfs inode
> + *
> + * Determines the byte offset in the file for the given page and
> + * offset within the page, maps the page, and makes the call to read
> + * the contents of @page_for_ecryptfs from the lower inode.
> + *
> + * Returns zero on success; non-zero otherwise
> + */
> +int ecryptfs_read_lower_page_segment(struct page *page_for_ecryptfs,
> + pgoff_t page_index,
> + size_t offset_in_page, size_t size,
> + struct inode *ecryptfs_inode)
> +{
> + char *virt;
> + loff_t offset;
> + int rc;
> +
> + offset = ((page_index << PAGE_CACHE_SHIFT) + offset_in_page);

Another overflow bug.

> + virt = kmap(page_for_ecryptfs);
> + rc = ecryptfs_read_lower(virt, offset, size, ecryptfs_inode);
> + kunmap(page_for_ecryptfs);
> + return rc;
> +}
> +
> +/**
> + * ecryptfs_read
> + * @data: The virtual address into which to write the data read (and
> + * possibly decrypted) from the lower file
> + * @offset: The offset in the decrypted view of the file from which to
> + * read into @data
> + * @size: The number of bytes to read into @data
> + * @ecryptfs_file: The eCryptfs file from which to read
> + *
> + * Read an arbitrary amount of data from an arbitrary location in the
> + * eCryptfs page cache. This is done on an extent-by-extent basis;
> + * individual extents are decrypted and read from the lower page
> + * cache (via VFS reads). This function takes care of all the
> + * address translation to locations in the lower filesystem.
> + *
> + * Returns zero on success; non-zero otherwise
> + */
> +int ecryptfs_read(char *data, loff_t offset, size_t size,
> + struct file *ecryptfs_file)
> +{
> + struct page *ecryptfs_page;
> + char *ecryptfs_page_virt;
> + u64 ecryptfs_file_size = i_size_read(ecryptfs_file->f_dentry->d_inode);

loff_t

> + loff_t data_offset = 0;
> + loff_t pos;
> + int rc = 0;
> +
> + if ((offset + size) > ecryptfs_file_size) {
> + rc = -EINVAL;
> + printk(KERN_ERR "%s: Attempt to read data past the end of the "
> + "file; offset = [%lld]; size = [%td]; "
> + "ecryptfs_file_size = [%lld]\n",
> + __FUNCTION__, offset, size, ecryptfs_file_size);
> + goto out;
> + }
> + pos = offset;
> + while (pos < (offset + size)) {
> + pgoff_t ecryptfs_page_idx = (pos >> PAGE_CACHE_SHIFT);
> + size_t start_offset_in_page = (pos & ~PAGE_CACHE_MASK);
> + size_t num_bytes = (PAGE_CACHE_SIZE - start_offset_in_page);
> + size_t total_remaining_bytes = ((offset + size) - pos);
> +
> + if (num_bytes > total_remaining_bytes)
> + num_bytes = total_remaining_bytes;
> + ecryptfs_page = ecryptfs_get1page(ecryptfs_file,
> + ecryptfs_page_idx);
> + if (IS_ERR(ecryptfs_page)) {
> + rc = PTR_ERR(ecryptfs_page);
> + printk(KERN_ERR "%s: Error getting page at "
> + "index [%ld] from eCryptfs inode "
> + "mapping; rc = [%d]\n", __FUNCTION__,
> + ecryptfs_page_idx, rc);
> + goto out;
> + }
> + rc = ecryptfs_decrypt_page(NULL /* placeholder for git-bisect */, ecryptfs_page);
> + if (rc) {
> + printk(KERN_ERR "%s: Error decrypting "
> + "page; rc = [%d]\n", __FUNCTION__, rc);
> + page_cache_release(ecryptfs_page);
> + goto out;
> + }
> + ecryptfs_page_virt = kmap_atomic(ecryptfs_page, KM_USER0);
> + memcpy((data + data_offset),
> + ((char *)ecryptfs_page_virt + start_offset_in_page),
> + num_bytes);
> + kunmap_atomic(ecryptfs_page_virt, KM_USER0);
> + page_cache_release(ecryptfs_page);
> + pos += num_bytes;
> + data_offset += num_bytes;
> + }
> +out:
> + return rc;
> +}

2007-09-20 05:46:52

by Andrew Morton

[permalink] [raw]
Subject: Re: [PATCH 4/11] eCryptfs: Replace encrypt, decrypt, and inode size write

On Mon, 17 Sep 2007 16:47:10 -0500 Michael Halcrow <[email protected]> wrote:

> Replace page encryption and decryption routines and inode size write
> routine with versions that utilize the read_write.c functions.
>
> Signed-off-by: Michael Halcrow <[email protected]>
> ---
> fs/ecryptfs/crypto.c | 427 ++++++++++++++++++++++------------------
> fs/ecryptfs/ecryptfs_kernel.h | 14 +-
> fs/ecryptfs/inode.c | 12 +-
> fs/ecryptfs/mmap.c | 131 ++++---------
> fs/ecryptfs/read_write.c | 12 +-
> 5 files changed, 290 insertions(+), 306 deletions(-)
>
> diff --git a/fs/ecryptfs/crypto.c b/fs/ecryptfs/crypto.c
> index 5d8a553..b829d3c 100644
> --- a/fs/ecryptfs/crypto.c
> +++ b/fs/ecryptfs/crypto.c
> @@ -467,8 +467,91 @@ out:
> }
>
> /**
> + * ecryptfs_lower_offset_for_extent
> + *
> + * Convert an eCryptfs page index into a lower byte offset
> + */
> +void ecryptfs_lower_offset_for_extent(loff_t *offset, loff_t extent_num,
> + struct ecryptfs_crypt_stat *crypt_stat)
> +{
> + (*offset) = ((crypt_stat->extent_size
> + * crypt_stat->num_header_extents_at_front)
> + + (crypt_stat->extent_size * extent_num));
> +}
> +
> +/**
> + * ecryptfs_encrypt_extent
> + * @enc_extent_page: Allocated page into which to encrypt the data in
> + * @page
> + * @crypt_stat: crypt_stat containing cryptographic context for the
> + * encryption operation
> + * @page: Page containing plaintext data extent to encrypt
> + * @extent_offset: Page extent offset for use in generating IV
> + *
> + * Encrypts one extent of data.
> + *
> + * Return zero on success; non-zero otherwise
> + */
> +static int ecryptfs_encrypt_extent(struct page *enc_extent_page,
> + struct ecryptfs_crypt_stat *crypt_stat,
> + struct page *page,
> + unsigned long extent_offset)
> +{
> + unsigned long extent_base;
> + char extent_iv[ECRYPTFS_MAX_IV_BYTES];
> + int rc;
> +
> + extent_base = (page->index
> + * (PAGE_CACHE_SIZE / crypt_stat->extent_size));

I think this is vulnerable to overflow on 32-bit machines?

> + rc = ecryptfs_derive_iv(extent_iv, crypt_stat,
> + (extent_base + extent_offset));
> + if (rc) {
> + ecryptfs_printk(KERN_ERR, "Error attempting to "
> + "derive IV for extent [0x%.16x]; "
> + "rc = [%d]\n", (extent_base + extent_offset),
> + rc);
> + goto out;
> + }
> + if (unlikely(ecryptfs_verbosity > 0)) {
> + ecryptfs_printk(KERN_DEBUG, "Encrypting extent "
> + "with iv:\n");
> + ecryptfs_dump_hex(extent_iv, crypt_stat->iv_bytes);
> + ecryptfs_printk(KERN_DEBUG, "First 8 bytes before "
> + "encryption:\n");
> + ecryptfs_dump_hex((char *)
> + (page_address(page)
> + + (extent_offset * crypt_stat->extent_size)),
> + 8);
> + }
> + rc = ecryptfs_encrypt_page_offset(crypt_stat, enc_extent_page, 0,
> + page, (extent_offset
> + * crypt_stat->extent_size),

maybe that is too, dunno.

> + crypt_stat->extent_size, extent_iv);
> + if (rc < 0) {
> + printk(KERN_ERR "%s: Error attempting to encrypt page with "
> + "page->index = [%ld], extent_offset = [%ld]; "
> + "rc = [%d]\n", __FUNCTION__, page->index, extent_offset,
> + rc);
> + goto out;
> + }
> + rc = 0;
> + if (unlikely(ecryptfs_verbosity > 0)) {
> + ecryptfs_printk(KERN_DEBUG, "Encrypt extent [0x%.16x]; "
> + "rc = [%d]\n", (extent_base + extent_offset),
> + rc);
> + ecryptfs_printk(KERN_DEBUG, "First 8 bytes after "
> + "encryption:\n");
> + ecryptfs_dump_hex((char *)(page_address(enc_extent_page)), 8);
> + }
> +out:
> + return rc;
> +}
> +
> +/**
> * ecryptfs_encrypt_page
> - * @ctx: The context of the page
> + * @page: Page mapped from the eCryptfs inode for the file; contains
> + * decrypted content that needs to be encrypted (to a temporary
> + * page; not in place) and written out to the lower file
> *
> * Encrypt an eCryptfs page. This is done on a per-extent basis. Note
> * that eCryptfs pages may straddle the lower pages -- for instance,
> @@ -478,128 +561,121 @@ out:
> * file, 24K of page 0 of the lower file will be read and decrypted,
> * and then 8K of page 1 of the lower file will be read and decrypted.
> *
> - * The actual operations performed on each page depends on the
> - * contents of the ecryptfs_page_crypt_context struct.
> - *
> * Returns zero on success; negative on error
> */
> -int ecryptfs_encrypt_page(struct ecryptfs_page_crypt_context *ctx)
> +int ecryptfs_encrypt_page(struct page *page)
> {
> - char extent_iv[ECRYPTFS_MAX_IV_BYTES];
> - unsigned long base_extent;
> - unsigned long extent_offset = 0;
> - unsigned long lower_page_idx = 0;
> - unsigned long prior_lower_page_idx = 0;
> - struct page *lower_page;
> - struct inode *lower_inode;
> - struct ecryptfs_inode_info *inode_info;
> + struct inode *ecryptfs_inode;
> struct ecryptfs_crypt_stat *crypt_stat;
> + char *enc_extent_virt = NULL;
> + struct page *enc_extent_page;
> + loff_t extent_offset;
> int rc = 0;
> - int lower_byte_offset = 0;
> - int orig_byte_offset = 0;
> - int num_extents_per_page;
> -#define ECRYPTFS_PAGE_STATE_UNREAD 0
> -#define ECRYPTFS_PAGE_STATE_READ 1
> -#define ECRYPTFS_PAGE_STATE_MODIFIED 2
> -#define ECRYPTFS_PAGE_STATE_WRITTEN 3
> - int page_state;
> -
> - lower_inode = ecryptfs_inode_to_lower(ctx->page->mapping->host);
> - inode_info = ecryptfs_inode_to_private(ctx->page->mapping->host);
> - crypt_stat = &inode_info->crypt_stat;
> +
> + ecryptfs_inode = page->mapping->host;
> + crypt_stat =
> + &(ecryptfs_inode_to_private(ecryptfs_inode)->crypt_stat);
> if (!(crypt_stat->flags & ECRYPTFS_ENCRYPTED)) {
> - rc = ecryptfs_copy_page_to_lower(ctx->page, lower_inode,
> - ctx->param.lower_file);
> + rc = ecryptfs_write_lower_page_segment(ecryptfs_inode, page,
> + 0, PAGE_CACHE_SIZE);
> if (rc)
> - ecryptfs_printk(KERN_ERR, "Error attempting to copy "
> - "page at index [0x%.16x]\n",
> - ctx->page->index);
> + printk(KERN_ERR "%s: Error attempting to copy "
> + "page at index [%ld]\n", __FUNCTION__,
> + page->index);
> goto out;
> }
> - num_extents_per_page = PAGE_CACHE_SIZE / crypt_stat->extent_size;
> - base_extent = (ctx->page->index * num_extents_per_page);
> - page_state = ECRYPTFS_PAGE_STATE_UNREAD;
> - while (extent_offset < num_extents_per_page) {
> - ecryptfs_extent_to_lwr_pg_idx_and_offset(
> - &lower_page_idx, &lower_byte_offset, crypt_stat,
> - (base_extent + extent_offset));
> - if (prior_lower_page_idx != lower_page_idx
> - && page_state == ECRYPTFS_PAGE_STATE_MODIFIED) {
> - rc = ecryptfs_write_out_page(ctx, lower_page,
> - lower_inode,
> - orig_byte_offset,
> - (PAGE_CACHE_SIZE
> - - orig_byte_offset));
> - if (rc) {
> - ecryptfs_printk(KERN_ERR, "Error attempting "
> - "to write out page; rc = [%d]"
> - "\n", rc);
> - goto out;
> - }
> - page_state = ECRYPTFS_PAGE_STATE_WRITTEN;
> - }
> - if (page_state == ECRYPTFS_PAGE_STATE_UNREAD
> - || page_state == ECRYPTFS_PAGE_STATE_WRITTEN) {
> - rc = ecryptfs_read_in_page(ctx, &lower_page,
> - lower_inode, lower_page_idx,
> - lower_byte_offset);
> - if (rc) {
> - ecryptfs_printk(KERN_ERR, "Error attempting "
> - "to read in lower page with "
> - "index [0x%.16x]; rc = [%d]\n",
> - lower_page_idx, rc);
> - goto out;
> - }
> - orig_byte_offset = lower_byte_offset;
> - prior_lower_page_idx = lower_page_idx;
> - page_state = ECRYPTFS_PAGE_STATE_READ;
> - }
> - BUG_ON(!(page_state == ECRYPTFS_PAGE_STATE_MODIFIED
> - || page_state == ECRYPTFS_PAGE_STATE_READ));
> - rc = ecryptfs_derive_iv(extent_iv, crypt_stat,
> - (base_extent + extent_offset));
> + enc_extent_virt = kmalloc(PAGE_CACHE_SIZE, GFP_USER);

I'd have thought that alloc_page() would be nicer. After all, we _are_
treating it as a page, and not as a random piece of memry.

> + if (!enc_extent_virt) {
> + rc = -ENOMEM;
> + ecryptfs_printk(KERN_ERR, "Error allocating memory for "
> + "encrypted extent\n");
> + goto out;
> + }
> + enc_extent_page = virt_to_page(enc_extent_virt);

And then we don't need this.

> + for (extent_offset = 0;
> + extent_offset < (PAGE_CACHE_SIZE / crypt_stat->extent_size);
> + extent_offset++) {
> + loff_t offset;
> +
> + rc = ecryptfs_encrypt_extent(enc_extent_page, crypt_stat, page,
> + extent_offset);
> if (rc) {
> - ecryptfs_printk(KERN_ERR, "Error attempting to "
> - "derive IV for extent [0x%.16x]; "
> - "rc = [%d]\n",
> - (base_extent + extent_offset), rc);
> + printk(KERN_ERR "%s: Error encrypting extent; "
> + "rc = [%d]\n", __FUNCTION__, rc);
> goto out;
> }
> - if (unlikely(ecryptfs_verbosity > 0)) {
> - ecryptfs_printk(KERN_DEBUG, "Encrypting extent "
> - "with iv:\n");
> - ecryptfs_dump_hex(extent_iv, crypt_stat->iv_bytes);
> - ecryptfs_printk(KERN_DEBUG, "First 8 bytes before "
> - "encryption:\n");
> - ecryptfs_dump_hex((char *)
> - (page_address(ctx->page)
> - + (extent_offset
> - * crypt_stat->extent_size)), 8);
> - }
> - rc = ecryptfs_encrypt_page_offset(
> - crypt_stat, lower_page, lower_byte_offset, ctx->page,
> - (extent_offset * crypt_stat->extent_size),
> - crypt_stat->extent_size, extent_iv);
> - ecryptfs_printk(KERN_DEBUG, "Encrypt extent [0x%.16x]; "
> - "rc = [%d]\n",
> - (base_extent + extent_offset), rc);
> - if (unlikely(ecryptfs_verbosity > 0)) {
> - ecryptfs_printk(KERN_DEBUG, "First 8 bytes after "
> - "encryption:\n");
> - ecryptfs_dump_hex((char *)(page_address(lower_page)
> - + lower_byte_offset), 8);
> + ecryptfs_lower_offset_for_extent(
> + &offset, ((page->index * (PAGE_CACHE_SIZE
> + / crypt_stat->extent_size))

overflow?

> + + extent_offset), crypt_stat);
> + rc = ecryptfs_write_lower(ecryptfs_inode, enc_extent_virt,
> + offset, crypt_stat->extent_size);
> + if (rc) {
> + ecryptfs_printk(KERN_ERR, "Error attempting "
> + "to write lower page; rc = [%d]"
> + "\n", rc);
> + goto out;
> }
> - page_state = ECRYPTFS_PAGE_STATE_MODIFIED;
> extent_offset++;
> }
> - BUG_ON(orig_byte_offset != 0);
> - rc = ecryptfs_write_out_page(ctx, lower_page, lower_inode, 0,
> - (lower_byte_offset
> - + crypt_stat->extent_size));
> +out:
> + kfree(enc_extent_virt);
> + return rc;
> +}
> +
> +static int ecryptfs_decrypt_extent(struct page *page,
> + struct ecryptfs_crypt_stat *crypt_stat,
> + struct page *enc_extent_page,
> + unsigned long extent_offset)
> +{
> + unsigned long extent_base;
> + char extent_iv[ECRYPTFS_MAX_IV_BYTES];
> + int rc;
> +
> + extent_base = (page->index
> + * (PAGE_CACHE_SIZE / crypt_stat->extent_size));

overflow?

> + rc = ecryptfs_derive_iv(extent_iv, crypt_stat,
> + (extent_base + extent_offset));
> if (rc) {
> - ecryptfs_printk(KERN_ERR, "Error attempting to write out "
> - "page; rc = [%d]\n", rc);
> - goto out;
> + ecryptfs_printk(KERN_ERR, "Error attempting to "
> + "derive IV for extent [0x%.16x]; "
> + "rc = [%d]\n", (extent_base + extent_offset),
> + rc);
> + goto out;
> + }
> + if (unlikely(ecryptfs_verbosity > 0)) {
> + ecryptfs_printk(KERN_DEBUG, "Decrypting extent "
> + "with iv:\n");
> + ecryptfs_dump_hex(extent_iv, crypt_stat->iv_bytes);
> + ecryptfs_printk(KERN_DEBUG, "First 8 bytes before "
> + "decryption:\n");
> + ecryptfs_dump_hex((char *)
> + (page_address(enc_extent_page)
> + + (extent_offset * crypt_stat->extent_size)),
> + 8);
> + }
> + rc = ecryptfs_decrypt_page_offset(crypt_stat, page,
> + (extent_offset
> + * crypt_stat->extent_size),
> + enc_extent_page, 0,
> + crypt_stat->extent_size, extent_iv);
> + if (rc < 0) {
> + printk(KERN_ERR "%s: Error attempting to decrypt to page with "
> + "page->index = [%ld], extent_offset = [%ld]; "
> + "rc = [%d]\n", __FUNCTION__, page->index, extent_offset,
> + rc);
> + goto out;
> + }
> + rc = 0;
> + if (unlikely(ecryptfs_verbosity > 0)) {
> + ecryptfs_printk(KERN_DEBUG, "Decrypt extent [0x%.16x]; "
> + "rc = [%d]\n", (extent_base + extent_offset),
> + rc);
> + ecryptfs_printk(KERN_DEBUG, "First 8 bytes after "
> + "decryption:\n");
> + ecryptfs_dump_hex((char *)(page_address(page)
> + + (extent_offset
> + * crypt_stat->extent_size)), 8);
> }
> out:
> return rc;
> @@ -607,8 +683,9 @@ out:
>
> /**
> * ecryptfs_decrypt_page
> - * @file: The ecryptfs file
> - * @page: The page in ecryptfs to decrypt
> + * @page: Page mapped from the eCryptfs inode for the file; data read
> + * and decrypted from the lower file will be written into this
> + * page
> *
> * Decrypt an eCryptfs page. This is done on a per-extent basis. Note
> * that eCryptfs pages may straddle the lower pages -- for instance,
> @@ -620,103 +697,69 @@ out:
> *
> * Returns zero on success; negative on error
> */
> -int ecryptfs_decrypt_page(struct file *file, struct page *page)
> +int ecryptfs_decrypt_page(struct page *page)
> {
> - char extent_iv[ECRYPTFS_MAX_IV_BYTES];
> - unsigned long base_extent;
> - unsigned long extent_offset = 0;
> - unsigned long lower_page_idx = 0;
> - unsigned long prior_lower_page_idx = 0;
> - struct page *lower_page;
> - char *lower_page_virt = NULL;
> - struct inode *lower_inode;
> + struct inode *ecryptfs_inode;
> struct ecryptfs_crypt_stat *crypt_stat;
> + char *enc_extent_virt = NULL;
> + struct page *enc_extent_page;
> + unsigned long extent_offset;
> int rc = 0;
> - int byte_offset;
> - int num_extents_per_page;
> - int page_state;
>
> - crypt_stat = &(ecryptfs_inode_to_private(
> - page->mapping->host)->crypt_stat);
> - lower_inode = ecryptfs_inode_to_lower(page->mapping->host);
> + ecryptfs_inode = page->mapping->host;
> + crypt_stat =
> + &(ecryptfs_inode_to_private(ecryptfs_inode)->crypt_stat);
> if (!(crypt_stat->flags & ECRYPTFS_ENCRYPTED)) {
> - rc = ecryptfs_do_readpage(file, page, page->index);
> + rc = ecryptfs_read_lower_page_segment(page, page->index, 0,
> + PAGE_CACHE_SIZE,
> + ecryptfs_inode);
> if (rc)
> - ecryptfs_printk(KERN_ERR, "Error attempting to copy "
> - "page at index [0x%.16x]\n",
> - page->index);
> - goto out;
> + printk(KERN_ERR "%s: Error attempting to copy "
> + "page at index [%ld]\n", __FUNCTION__,
> + page->index);
> + goto out_clear_uptodate;
> }
> - num_extents_per_page = PAGE_CACHE_SIZE / crypt_stat->extent_size;
> - base_extent = (page->index * num_extents_per_page);
> - lower_page_virt = kmem_cache_alloc(ecryptfs_lower_page_cache,
> - GFP_KERNEL);
> - if (!lower_page_virt) {
> + enc_extent_virt = kmalloc(PAGE_CACHE_SIZE, GFP_USER);
> + if (!enc_extent_virt) {
> rc = -ENOMEM;
> - ecryptfs_printk(KERN_ERR, "Error getting page for encrypted "
> - "lower page(s)\n");
> - goto out;
> - }
> - lower_page = virt_to_page(lower_page_virt);
> - page_state = ECRYPTFS_PAGE_STATE_UNREAD;
> - while (extent_offset < num_extents_per_page) {
> - ecryptfs_extent_to_lwr_pg_idx_and_offset(
> - &lower_page_idx, &byte_offset, crypt_stat,
> - (base_extent + extent_offset));
> - if (prior_lower_page_idx != lower_page_idx
> - || page_state == ECRYPTFS_PAGE_STATE_UNREAD) {
> - rc = ecryptfs_do_readpage(file, lower_page,
> - lower_page_idx);
> - if (rc) {
> - ecryptfs_printk(KERN_ERR, "Error reading "
> - "lower encrypted page; rc = "
> - "[%d]\n", rc);
> - goto out;
> - }
> - prior_lower_page_idx = lower_page_idx;
> - page_state = ECRYPTFS_PAGE_STATE_READ;
> - }
> - rc = ecryptfs_derive_iv(extent_iv, crypt_stat,
> - (base_extent + extent_offset));
> + ecryptfs_printk(KERN_ERR, "Error allocating memory for "
> + "encrypted extent\n");
> + goto out_clear_uptodate;
> + }
> + enc_extent_page = virt_to_page(enc_extent_virt);

> +static int ecryptfs_write_inode_size_to_xattr(struct inode *ecryptfs_inode)
> {
> ssize_t size;
> void *xattr_virt;
> - struct dentry *lower_dentry;
> + struct dentry *lower_dentry =
> + ecryptfs_inode_to_private(ecryptfs_inode)->lower_file->f_dentry;
> + struct inode *lower_inode = lower_dentry->d_inode;
> u64 file_size;
> int rc;
>
> + if (!lower_inode->i_op->getxattr || !lower_inode->i_op->setxattr) {
> + printk(KERN_WARNING
> + "No support for setting xattr in lower filesystem\n");
> + rc = -ENOSYS;
> + goto out;
> + }
> xattr_virt = kmem_cache_alloc(ecryptfs_xattr_cache, GFP_KERNEL);
> if (!xattr_virt) {
> printk(KERN_ERR "Out of memory whilst attempting to write "
> @@ -518,35 +504,17 @@ static int ecryptfs_write_inode_size_to_xattr(struct inode *lower_inode,
> rc = -ENOMEM;
> goto out;
> }
> - lower_dentry = ecryptfs_dentry_to_lower(ecryptfs_dentry);
> - if (!lower_dentry->d_inode->i_op->getxattr ||
> - !lower_dentry->d_inode->i_op->setxattr) {
> - printk(KERN_WARNING
> - "No support for setting xattr in lower filesystem\n");
> - rc = -ENOSYS;
> - kmem_cache_free(ecryptfs_xattr_cache, xattr_virt);
> - goto out;
> - }
> - if (!lower_i_mutex_held)
> - mutex_lock(&lower_dentry->d_inode->i_mutex);
> - size = lower_dentry->d_inode->i_op->getxattr(lower_dentry,
> - ECRYPTFS_XATTR_NAME,
> - xattr_virt,
> - PAGE_CACHE_SIZE);
> - if (!lower_i_mutex_held)
> - mutex_unlock(&lower_dentry->d_inode->i_mutex);
> + mutex_lock(&lower_inode->i_mutex);
> + size = lower_inode->i_op->getxattr(lower_dentry, ECRYPTFS_XATTR_NAME,
> + xattr_virt, PAGE_CACHE_SIZE);
> if (size < 0)
> size = 8;
> - file_size = (u64)i_size_read(inode);
> + file_size = (u64)i_size_read(ecryptfs_inode);
> file_size = cpu_to_be64(file_size);
> memcpy(xattr_virt, &file_size, sizeof(u64));
> - if (!lower_i_mutex_held)
> - mutex_lock(&lower_dentry->d_inode->i_mutex);
> - rc = lower_dentry->d_inode->i_op->setxattr(lower_dentry,
> - ECRYPTFS_XATTR_NAME,
> - xattr_virt, size, 0);
> - if (!lower_i_mutex_held)
> - mutex_unlock(&lower_dentry->d_inode->i_mutex);
> + rc = lower_inode->i_op->setxattr(lower_dentry, ECRYPTFS_XATTR_NAME,
> + xattr_virt, size, 0);
> + mutex_unlock(&lower_inode->i_mutex);
> if (rc)
> printk(KERN_ERR "Error whilst attempting to write inode size "
> "to lower file xattr; rc = [%d]\n", rc);
> @@ -555,24 +523,15 @@ out:
> return rc;
> }
>
> -int
> -ecryptfs_write_inode_size_to_metadata(struct file *lower_file,
> - struct inode *lower_inode,
> - struct inode *inode,
> - struct dentry *ecryptfs_dentry,
> - int lower_i_mutex_held)
> +int ecryptfs_write_inode_size_to_metadata(struct inode *ecryptfs_inode)
> {
> struct ecryptfs_crypt_stat *crypt_stat;
>
> - crypt_stat = &ecryptfs_inode_to_private(inode)->crypt_stat;
> + crypt_stat = &ecryptfs_inode_to_private(ecryptfs_inode)->crypt_stat;
> if (crypt_stat->flags & ECRYPTFS_METADATA_IN_XATTR)
> - return ecryptfs_write_inode_size_to_xattr(lower_inode, inode,
> - ecryptfs_dentry,
> - lower_i_mutex_held);
> + return ecryptfs_write_inode_size_to_xattr(ecryptfs_inode);
> else
> - return ecryptfs_write_inode_size_to_header(lower_file,
> - lower_inode,
> - inode);
> + return ecryptfs_write_inode_size_to_header(ecryptfs_inode);
> }
>
> int ecryptfs_get_lower_page(struct page **lower_page, struct inode *lower_inode,
> @@ -659,8 +618,6 @@ out:
> return rc;
> }
>
> -struct kmem_cache *ecryptfs_xattr_cache;
> -
> /**
> * ecryptfs_commit_write
> * @file: The eCryptfs file object
> @@ -675,7 +632,6 @@ struct kmem_cache *ecryptfs_xattr_cache;
> static int ecryptfs_commit_write(struct file *file, struct page *page,
> unsigned from, unsigned to)
> {
> - struct ecryptfs_page_crypt_context ctx;
> loff_t pos;
> struct inode *inode;
> struct inode *lower_inode;
> @@ -705,10 +661,7 @@ static int ecryptfs_commit_write(struct file *file, struct page *page,
> page->index);
> goto out;
> }
> - ctx.page = page;
> - ctx.mode = ECRYPTFS_PREPARE_COMMIT_MODE;
> - ctx.param.lower_file = lower_file;
> - rc = ecryptfs_encrypt_page(&ctx);
> + rc = ecryptfs_encrypt_page(page);
> if (rc) {
> ecryptfs_printk(KERN_WARNING, "Error encrypting page (upper "
> "index [0x%.16x])\n", page->index);
> @@ -721,9 +674,7 @@ static int ecryptfs_commit_write(struct file *file, struct page *page,
> ecryptfs_printk(KERN_DEBUG, "Expanded file size to "
> "[0x%.16x]\n", i_size_read(inode));
> }
> - rc = ecryptfs_write_inode_size_to_metadata(lower_file, lower_inode,
> - inode, file->f_dentry,
> - ECRYPTFS_LOWER_I_MUTEX_HELD);
> + rc = ecryptfs_write_inode_size_to_metadata(inode);
> if (rc)
> printk(KERN_ERR "Error writing inode size to metadata; "
> "rc = [%d]\n", rc);
> diff --git a/fs/ecryptfs/read_write.c b/fs/ecryptfs/read_write.c
> index e59c94a..ccd2599 100644
> --- a/fs/ecryptfs/read_write.c
> +++ b/fs/ecryptfs/read_write.c
> @@ -154,8 +154,8 @@ int ecryptfs_write(struct file *ecryptfs_file, char *data, loff_t offset,
> /* Read in the page from the lower
> * into the eCryptfs inode page cache,
> * decrypting */
> - if ((rc = ecryptfs_decrypt_page(NULL, /* placeholder for git-bisect */
> - ecryptfs_page))) {
> + rc = ecryptfs_decrypt_page(ecryptfs_page);
> + if (rc) {
> printk(KERN_ERR "%s: Error decrypting "
> "page; rc = [%d]\n",
> __FUNCTION__, rc);
> @@ -178,7 +178,7 @@ int ecryptfs_write(struct file *ecryptfs_file, char *data, loff_t offset,
> }
> kunmap_atomic(ecryptfs_page_virt, KM_USER0);
> flush_dcache_page(ecryptfs_page);
> - rc = ecryptfs_encrypt_page(NULL /* placeholder for git-bisect */);
> + rc = ecryptfs_encrypt_page(ecryptfs_page);
> if (rc) {
> printk(KERN_ERR "%s: Error encrypting "
> "page; rc = [%d]\n", __FUNCTION__, rc);
> @@ -190,8 +190,8 @@ int ecryptfs_write(struct file *ecryptfs_file, char *data, loff_t offset,
> }
> if ((offset + size) > ecryptfs_file_size) {
> i_size_write(ecryptfs_file->f_dentry->d_inode, (offset + size));
> - rc = ecryptfs_write_inode_size_to_metadata(NULL, NULL, NULL,
> - NULL, 0); /* placeholders for git-bisect */
> + rc = ecryptfs_write_inode_size_to_metadata(
> + ecryptfs_file->f_dentry->d_inode);
> if (rc) {
> printk(KERN_ERR "Problem with "
> "ecryptfs_write_inode_size_to_metadata; "
> @@ -338,7 +338,7 @@ int ecryptfs_read(char *data, loff_t offset, size_t size,
> ecryptfs_page_idx, rc);
> goto out;
> }
> - rc = ecryptfs_decrypt_page(NULL /* placeholder for git-bisect */, ecryptfs_page);
> + rc = ecryptfs_decrypt_page(ecryptfs_page);
> if (rc) {
> printk(KERN_ERR "%s: Error decrypting "
> "page; rc = [%d]\n", __FUNCTION__, rc);
> --
> 1.5.1.6

2007-09-20 05:49:23

by Andrew Morton

[permalink] [raw]
Subject: Re: [PATCH 6/11] eCryptfs: Update metadata read/write functions

On Mon, 17 Sep 2007 16:48:44 -0500 Michael Halcrow <[email protected]> wrote:

> + if ((rc = ecryptfs_write_lower(ecryptfs_dentry->d_inode,

checkpatch missed the assignment-in-an-if here.

2007-09-20 05:52:11

by Andrew Morton

[permalink] [raw]
Subject: Re: [PATCH 8/11] eCryptfs: Convert mmap functions to use persistent file

On Mon, 17 Sep 2007 16:50:16 -0500 Michael Halcrow <[email protected]> wrote:

> Convert readpage, prepare_write, and commit_write to use read_write.c
> routines. Remove sync_page; I cannot think of a good reason for
> implementing that in eCryptfs.
>
> Signed-off-by: Michael Halcrow <[email protected]>
> ---
> fs/ecryptfs/mmap.c | 199 +++++++++++++++++++++++++++-------------------------
> 1 files changed, 103 insertions(+), 96 deletions(-)
>
> diff --git a/fs/ecryptfs/mmap.c b/fs/ecryptfs/mmap.c
> index 60e635e..dd68dd3 100644
> --- a/fs/ecryptfs/mmap.c
> +++ b/fs/ecryptfs/mmap.c
> @@ -267,9 +267,78 @@ static void set_header_info(char *page_virt,
> }
>
> /**
> + * ecryptfs_copy_up_encrypted_with_header
> + * @page: Sort of a ``virtual'' representation of the encrypted lower
> + * file. The actual lower file does not have the metadata in
> + * the header.
> + * @crypt_stat: The eCryptfs inode's cryptographic context
> + *
> + * The ``view'' is the version of the file that userspace winds up
> + * seeing, with the header information inserted.
> + */
> +static int
> +ecryptfs_copy_up_encrypted_with_header(struct page *page,
> + struct ecryptfs_crypt_stat *crypt_stat)
> +{
> + loff_t extent_num_in_page = 0;
> + loff_t num_extents_per_page = (PAGE_CACHE_SIZE
> + / crypt_stat->extent_size);
> + int rc = 0;
> +
> + while (extent_num_in_page < num_extents_per_page) {
> + loff_t view_extent_num = ((page->index * num_extents_per_page)

overflow?

> + + extent_num_in_page);
> +
> + if (view_extent_num < crypt_stat->num_header_extents_at_front) {
> + /* This is a header extent */
> + char *page_virt;
> +
> + page_virt = kmap_atomic(page, KM_USER0);
> + memset(page_virt, 0, PAGE_CACHE_SIZE);
> + /* TODO: Support more than one header extent */
> + if (view_extent_num == 0) {
> + rc = ecryptfs_read_xattr_region(
> + page_virt, page->mapping->host);
> + set_header_info(page_virt, crypt_stat);
> + }
> + kunmap_atomic(page_virt, KM_USER0);
> + flush_dcache_page(page);
> + if (rc) {
> + ClearPageUptodate(page);
> + printk(KERN_ERR "%s: Error reading xattr "
> + "region; rc = [%d]\n", __FUNCTION__, rc);
> + goto out;
> + }
> + SetPageUptodate(page);

I don't know what sort of page `page' refers to here, but normally we only
manipulate the page uptodate status under lock_page().


> + } else {
> + /* This is an encrypted data extent */
> + loff_t lower_offset =
> + ((view_extent_num -
> + crypt_stat->num_header_extents_at_front)
> + * crypt_stat->extent_size);

overflow?

> + rc = ecryptfs_read_lower_page_segment(
> + page, (lower_offset >> PAGE_CACHE_SHIFT),
> + (lower_offset & ~PAGE_CACHE_MASK),
> + crypt_stat->extent_size, page->mapping->host);
> + if (rc) {
> + printk(KERN_ERR "%s: Error attempting to read "
> + "extent at offset [%lld] in the lower "
> + "file; rc = [%d]\n", __FUNCTION__,
> + lower_offset, rc);
> + goto out;
> + }
> + }
> + extent_num_in_page++;
> + }
> +out:
> + return rc;
> +}
> +
> +/**
> * ecryptfs_readpage
> - * @file: This is an ecryptfs file
> - * @page: ecryptfs associated page to stick the read data into
> + * @file: An eCryptfs file
> + * @page: Page from eCryptfs inode mapping into which to stick the read data
> *
> * Read in a page, decrypting if necessary.
> *
> @@ -277,59 +346,35 @@ static void set_header_info(char *page_virt,
> */
> static int ecryptfs_readpage(struct file *file, struct page *page)
> {
> + struct ecryptfs_crypt_stat *crypt_stat =
> + &ecryptfs_inode_to_private(file->f_path.dentry->d_inode)->crypt_stat;
> int rc = 0;
> - struct ecryptfs_crypt_stat *crypt_stat;
>
> - BUG_ON(!(file && file->f_path.dentry && file->f_path.dentry->d_inode));
> - crypt_stat = &ecryptfs_inode_to_private(file->f_path.dentry->d_inode)
> - ->crypt_stat;
> if (!crypt_stat
> || !(crypt_stat->flags & ECRYPTFS_ENCRYPTED)
> || (crypt_stat->flags & ECRYPTFS_NEW_FILE)) {
> ecryptfs_printk(KERN_DEBUG,
> "Passing through unencrypted page\n");
> - rc = ecryptfs_do_readpage(file, page, page->index);
> - if (rc) {
> - ecryptfs_printk(KERN_ERR, "Error reading page; rc = "
> - "[%d]\n", rc);
> - goto out;
> - }
> + rc = ecryptfs_read_lower_page_segment(page, page->index, 0,
> + PAGE_CACHE_SIZE,
> + page->mapping->host);
> } else if (crypt_stat->flags & ECRYPTFS_VIEW_AS_ENCRYPTED) {
> if (crypt_stat->flags & ECRYPTFS_METADATA_IN_XATTR) {
> - int num_pages_in_header_region =
> - (crypt_stat->extent_size
> - / PAGE_CACHE_SIZE);
> -
> - if (page->index < num_pages_in_header_region) {
> - char *page_virt;
> -
> - page_virt = kmap_atomic(page, KM_USER0);
> - memset(page_virt, 0, PAGE_CACHE_SIZE);
> - if (page->index == 0) {
> - rc = ecryptfs_read_xattr_region(
> - page_virt, page->mapping->host);
> - set_header_info(page_virt, crypt_stat);
> - }
> - kunmap_atomic(page_virt, KM_USER0);
> - flush_dcache_page(page);
> - if (rc) {
> - printk(KERN_ERR "Error reading xattr "
> - "region\n");
> - goto out;
> - }
> - } else {
> - rc = ecryptfs_do_readpage(
> - file, page,
> - (page->index
> - - num_pages_in_header_region));
> - if (rc) {
> - printk(KERN_ERR "Error reading page; "
> - "rc = [%d]\n", rc);
> - goto out;
> - }
> + rc = ecryptfs_copy_up_encrypted_with_header(page,
> + crypt_stat);
> + if (rc) {
> + printk(KERN_ERR "%s: Error attempting to copy "
> + "the encrypted content from the lower "
> + "file whilst inserting the metadata "
> + "from the xattr into the header; rc = "
> + "[%d]\n", __FUNCTION__, rc);
> + goto out;
> }
> +
> } else {
> - rc = ecryptfs_do_readpage(file, page, page->index);
> + rc = ecryptfs_read_lower_page_segment(
> + page, page->index, 0, PAGE_CACHE_SIZE,
> + page->mapping->host);
> if (rc) {
> printk(KERN_ERR "Error reading page; rc = "
> "[%d]\n", rc);
> @@ -344,10 +389,7 @@ static int ecryptfs_readpage(struct file *file, struct page *page)
> goto out;
> }
> }
> - SetPageUptodate(page);
> out:
> - if (rc)
> - ClearPageUptodate(page);
> ecryptfs_printk(KERN_DEBUG, "Unlocking page with index = [0x%.16x]\n",
> page->index);
> unlock_page(page);
> @@ -403,9 +445,12 @@ static int ecryptfs_prepare_write(struct file *file, struct page *page,
> goto out; /* If we are writing a full page, it will be
> up to date. */
> if (!PageUptodate(page))
> - rc = ecryptfs_do_readpage(file, page, page->index);
> + rc = ecryptfs_read_lower_page_segment(page, page->index, 0,
> + PAGE_CACHE_SIZE,
> + page->mapping->host);
> if (page->index != 0) {
> - loff_t end_of_prev_pg_pos = page_offset(page) - 1;
> + loff_t end_of_prev_pg_pos =
> + (((loff_t)page->index << PAGE_CACHE_SHIFT) - 1);
>
> if (end_of_prev_pg_pos > i_size_read(page->mapping->host)) {
> rc = ecryptfs_truncate(file->f_path.dentry,
> @@ -633,18 +678,11 @@ static int ecryptfs_commit_write(struct file *file, struct page *page,
> unsigned from, unsigned to)
> {
> loff_t pos;
> - struct inode *inode;
> - struct inode *lower_inode;
> - struct file *lower_file;
> - struct ecryptfs_crypt_stat *crypt_stat;
> + struct inode *ecryptfs_inode = page->mapping->host;
> + struct ecryptfs_crypt_stat *crypt_stat =
> + &ecryptfs_inode_to_private(file->f_path.dentry->d_inode)->crypt_stat;
> int rc;
>
> - inode = page->mapping->host;
> - lower_inode = ecryptfs_inode_to_lower(inode);
> - lower_file = ecryptfs_file_to_lower(file);
> - mutex_lock(&lower_inode->i_mutex);
> - crypt_stat = &ecryptfs_inode_to_private(file->f_path.dentry->d_inode)
> - ->crypt_stat;
> if (crypt_stat->flags & ECRYPTFS_NEW_FILE) {
> ecryptfs_printk(KERN_DEBUG, "ECRYPTFS_NEW_FILE flag set in "
> "crypt_stat at memory location [%p]\n", crypt_stat);
> @@ -654,6 +692,7 @@ static int ecryptfs_commit_write(struct file *file, struct page *page,
> ecryptfs_printk(KERN_DEBUG, "Calling fill_zeros_to_end_of_page"
> "(page w/ index = [0x%.16x], to = [%d])\n", page->index,
> to);
> + /* Fills in zeros if 'to' goes beyond inode size */
> rc = fill_zeros_to_end_of_page(page, to);
> if (rc) {
> ecryptfs_printk(KERN_WARNING, "Error attempting to fill "
> @@ -667,25 +706,17 @@ static int ecryptfs_commit_write(struct file *file, struct page *page,
> "index [0x%.16x])\n", page->index);
> goto out;
> }
> - inode->i_blocks = lower_inode->i_blocks;
> - pos = page_offset(page) + to;
> - if (pos > i_size_read(inode)) {
> - i_size_write(inode, pos);
> + pos = (page->index << PAGE_CACHE_SHIFT) + to;

overflow

> + if (pos > i_size_read(ecryptfs_inode)) {
> + i_size_write(ecryptfs_inode, pos);
> ecryptfs_printk(KERN_DEBUG, "Expanded file size to "
> - "[0x%.16x]\n", i_size_read(inode));
> + "[0x%.16x]\n", i_size_read(ecryptfs_inode));
> }
> - rc = ecryptfs_write_inode_size_to_metadata(inode);
> + rc = ecryptfs_write_inode_size_to_metadata(ecryptfs_inode);
> if (rc)
> printk(KERN_ERR "Error writing inode size to metadata; "
> "rc = [%d]\n", rc);
> - lower_inode->i_mtime = lower_inode->i_ctime = CURRENT_TIME;
> - mark_inode_dirty_sync(inode);
> out:
> - if (rc < 0)
> - ClearPageUptodate(page);
> - else
> - SetPageUptodate(page);
> - mutex_unlock(&lower_inode->i_mutex);
> return rc;
> }
>
> @@ -751,34 +782,10 @@ static sector_t ecryptfs_bmap(struct address_space *mapping, sector_t block)
> return rc;
> }
>
> -static void ecryptfs_sync_page(struct page *page)
> -{
> - struct inode *inode;
> - struct inode *lower_inode;
> - struct page *lower_page;
> -
> - inode = page->mapping->host;
> - lower_inode = ecryptfs_inode_to_lower(inode);
> - /* NOTE: Recently swapped with grab_cache_page(), since
> - * sync_page() just makes sure that pending I/O gets done. */
> - lower_page = find_lock_page(lower_inode->i_mapping, page->index);
> - if (!lower_page) {
> - ecryptfs_printk(KERN_DEBUG, "find_lock_page failed\n");
> - return;
> - }
> - if (lower_page->mapping->a_ops->sync_page)
> - lower_page->mapping->a_ops->sync_page(lower_page);
> - ecryptfs_printk(KERN_DEBUG, "Unlocking page with index = [0x%.16x]\n",
> - lower_page->index);
> - unlock_page(lower_page);
> - page_cache_release(lower_page);
> -}
> -
> struct address_space_operations ecryptfs_aops = {
> .writepage = ecryptfs_writepage,
> .readpage = ecryptfs_readpage,
> .prepare_write = ecryptfs_prepare_write,
> .commit_write = ecryptfs_commit_write,
> .bmap = ecryptfs_bmap,
> - .sync_page = ecryptfs_sync_page,
> };
> --
> 1.5.1.6

2007-09-20 21:45:04

by Michael Halcrow

[permalink] [raw]
Subject: Re: [PATCH 4/11] eCryptfs: Replace encrypt, decrypt, and inode size write

On Wed, Sep 19, 2007 at 10:46:26PM -0700, Andrew Morton wrote:
(from ecryptfs_encrypt_page()):
> > + enc_extent_virt = kmalloc(PAGE_CACHE_SIZE, GFP_USER);
>
> I'd have thought that alloc_page() would be nicer. After all, we _are_
> treating it as a page, and not as a random piece of memry.
>
> > + if (!enc_extent_virt) {
> > + rc = -ENOMEM;
> > + ecryptfs_printk(KERN_ERR, "Error allocating memory for "
> > + "encrypted extent\n");
> > + goto out;
> > + }
> > + enc_extent_page = virt_to_page(enc_extent_virt);
>
> And then we don't need this.

If neither kmap() nor kmap_atomic() can be safely used to get a
virtual address to pass to vfs_write(), then I do not know what my
other options are here.

2007-09-20 22:04:14

by Michael Halcrow

[permalink] [raw]
Subject: Re: [PATCH 8/11] eCryptfs: Convert mmap functions to use persistent file

On Wed, Sep 19, 2007 at 10:50:57PM -0700, Andrew Morton wrote:
> On Mon, 17 Sep 2007 16:50:16 -0500 Michael Halcrow <[email protected]> wrote:
> > +ecryptfs_copy_up_encrypted_with_header(struct page *page,
> > + struct ecryptfs_crypt_stat *crypt_stat)
> > +{
...
> > + flush_dcache_page(page);
> > + if (rc) {
> > + ClearPageUptodate(page);
> > + printk(KERN_ERR "%s: Error reading xattr "
> > + "region; rc = [%d]\n", __FUNCTION__, rc);
> > + goto out;
> > + }
> > + SetPageUptodate(page);
>
> I don't know what sort of page `page' refers to here, but normally we only
> manipulate the page uptodate status under lock_page().

This is the page that eCryptfs gets via
ecryptfs_aops->ecryptfs_readpage(), so this should be okay. The
comment should make the fact that the page is locked explicit.

Signed-off-by: Michael Halcrow <[email protected]>

---
diff --git a/fs/ecryptfs/mmap.c b/fs/ecryptfs/mmap.c
index 04103ff..c6a8a33 100644
--- a/fs/ecryptfs/mmap.c
+++ b/fs/ecryptfs/mmap.c
@@ -111,7 +111,7 @@ static void set_header_info(char *page_virt,
* ecryptfs_copy_up_encrypted_with_header
* @page: Sort of a ``virtual'' representation of the encrypted lower
* file. The actual lower file does not have the metadata in
- * the header.
+ * the header. This is locked.
* @crypt_stat: The eCryptfs inode's cryptographic context
*
* The ``view'' is the version of the file that userspace winds up

2007-09-20 23:36:29

by Erez Zadok

[permalink] [raw]
Subject: Re: [PATCH 4/11] eCryptfs: Replace encrypt, decrypt, and inode size write

In message <[email protected]>, Michael Halcrow writes:
> On Wed, Sep 19, 2007 at 10:46:26PM -0700, Andrew Morton wrote:
> (from ecryptfs_encrypt_page()):
> > > + enc_extent_virt = kmalloc(PAGE_CACHE_SIZE, GFP_USER);
> >
> > I'd have thought that alloc_page() would be nicer. After all, we _are_
> > treating it as a page, and not as a random piece of memry.
> >
> > > + if (!enc_extent_virt) {
> > > + rc = -ENOMEM;
> > > + ecryptfs_printk(KERN_ERR, "Error allocating memory for "
> > > + "encrypted extent\n");
> > > + goto out;
> > > + }
> > > + enc_extent_page = virt_to_page(enc_extent_virt);
> >
> > And then we don't need this.
>
> If neither kmap() nor kmap_atomic() can be safely used to get a
> virtual address to pass to vfs_write(), then I do not know what my
> other options are here.

kmap_atomic is intended for short-lived code sections, where you may not
sleep, so you can't do a vfs_read/write in b/t kmap/kunmap_atomic.

Erez.

2007-09-21 21:51:49

by Michael Halcrow

[permalink] [raw]
Subject: Re: [Ecryptfs-devel] [PATCH 3/11] eCryptfs: read_write.c routines

On Wed, Sep 19, 2007 at 10:38:50PM -0700, Andrew Morton wrote:
> > + virt = kmap(page_for_lower);
> > + rc = ecryptfs_write_lower(ecryptfs_inode, virt, offset, size);
> > + kunmap(page_for_lower);
> > + return rc;
> > +}
>
> argh, kmap. http://lkml.org/lkml/2007/9/15/55

Here is a patch that moves to kmap_atomic(), adding an intermediate
copy. Although I would really like to find a way to avoid having to do
this extra copy.

---

Replace kmap() with kmap_atomic() for read_write.c routines

kmap() can lead to deadlock when multiple tasks attempt to take more
than one simultaneously:

http://lkml.org/lkml/2007/9/15/55

In order to avoid this possibility, eCryptfs must allocate an
intermediate block of memory to use with vfs_read() and vfs_write(),
copying the data through this memory region, since kmap_atomic()
cannot be held during calls which may block.

Signed-off-by: Michael Halcrow <[email protected]>
---
diff --git a/fs/ecryptfs/ecryptfs_kernel.h b/fs/ecryptfs/ecryptfs_kernel.h
index bb92b74..ce7a5d4 100644
--- a/fs/ecryptfs/ecryptfs_kernel.h
+++ b/fs/ecryptfs/ecryptfs_kernel.h
@@ -648,6 +648,6 @@ int ecryptfs_read_lower_page_segment(struct page *page_for_ecryptfs,
struct inode *ecryptfs_inode);
int ecryptfs_read(char *data, loff_t offset, size_t size,
struct file *ecryptfs_file);
-struct page *ecryptfs_get1page(struct file *file, loff_t index);
+struct page *ecryptfs_get_locked_page(struct file *file, loff_t index);

#endif /* #ifndef ECRYPTFS_KERNEL_H */
diff --git a/fs/ecryptfs/mmap.c b/fs/ecryptfs/mmap.c
index c6a8a33..6abf805 100644
--- a/fs/ecryptfs/mmap.c
+++ b/fs/ecryptfs/mmap.c
@@ -37,23 +37,30 @@
struct kmem_cache *ecryptfs_lower_page_cache;

/**
- * ecryptfs_get1page
+ * ecryptfs_get_locked_page
*
* Get one page from cache or lower f/s, return error otherwise.
*
- * Returns unlocked and up-to-date page (if ok), with increased
+ * Returns a locked and up-to-date page (if ok), with increased
* refcnt.
*/
-struct page *ecryptfs_get1page(struct file *file, loff_t index)
+struct page *ecryptfs_get_locked_page(struct file *file, loff_t index)
{
struct dentry *dentry;
struct inode *inode;
struct address_space *mapping;
+ struct page *page;

dentry = file->f_path.dentry;
inode = dentry->d_inode;
mapping = inode->i_mapping;
- return read_mapping_page(mapping, index, (void *)file);
+ page = read_mapping_page(mapping, index, (void *)file);
+ if (!IS_ERR(page))
+ lock_page(page);
+ else
+ printk(KERN_ERR "%s: Error from read_mapping_page()\n",
+ __FUNCTION__);
+ return page;
}

/**
diff --git a/fs/ecryptfs/read_write.c b/fs/ecryptfs/read_write.c
index ccd2599..6732a4c 100644
--- a/fs/ecryptfs/read_write.c
+++ b/fs/ecryptfs/read_write.c
@@ -83,14 +83,24 @@ int ecryptfs_write_lower_page_segment(struct inode *ecryptfs_inode,
struct page *page_for_lower,
size_t offset_in_page, size_t size)
{
- char *virt;
+ char *page_for_lower_virt;
+ char *tmp_virt;
loff_t offset;
int rc;

- offset = (page_for_lower->index << PAGE_CACHE_SHIFT) + offset_in_page;
- virt = kmap(page_for_lower);
- rc = ecryptfs_write_lower(ecryptfs_inode, virt, offset, size);
- kunmap(page_for_lower);
+ tmp_virt = kmalloc(PAGE_CACHE_SIZE, GFP_KERNEL);
+ if (!tmp_virt) {
+ rc = -ENOMEM;
+ goto out;
+ }
+ offset = ((((loff_t)page_for_lower->index) << PAGE_CACHE_SHIFT)
+ + offset_in_page);
+ page_for_lower_virt = kmap_atomic(page_for_lower, KM_USER0);
+ memcpy(tmp_virt, page_for_lower_virt, PAGE_CACHE_SIZE);
+ kunmap_atomic(page_for_lower_virt, KM_USER0);
+ rc = ecryptfs_write_lower(ecryptfs_inode, tmp_virt, offset, size);
+ kfree(tmp_virt);
+out:
return rc;
}

@@ -140,8 +150,8 @@ int ecryptfs_write(struct file *ecryptfs_file, char *data, loff_t offset,
if (num_bytes > total_remaining_zeros)
num_bytes = total_remaining_zeros;
}
- ecryptfs_page = ecryptfs_get1page(ecryptfs_file,
- ecryptfs_page_idx);
+ ecryptfs_page = ecryptfs_get_locked_page(ecryptfs_file,
+ ecryptfs_page_idx);
if (IS_ERR(ecryptfs_page)) {
rc = PTR_ERR(ecryptfs_page);
printk(KERN_ERR "%s: Error getting page at "
@@ -159,6 +169,7 @@ int ecryptfs_write(struct file *ecryptfs_file, char *data, loff_t offset,
printk(KERN_ERR "%s: Error decrypting "
"page; rc = [%d]\n",
__FUNCTION__, rc);
+ unlock_page(ecryptfs_page);
page_cache_release(ecryptfs_page);
goto out;
}
@@ -182,9 +193,11 @@ int ecryptfs_write(struct file *ecryptfs_file, char *data, loff_t offset,
if (rc) {
printk(KERN_ERR "%s: Error encrypting "
"page; rc = [%d]\n", __FUNCTION__, rc);
+ unlock_page(ecryptfs_page);
page_cache_release(ecryptfs_page);
goto out;
}
+ unlock_page(ecryptfs_page);
page_cache_release(ecryptfs_page);
pos += num_bytes;
}
@@ -245,10 +258,6 @@ int ecryptfs_read_lower(char *data, loff_t offset, size_t size,

data_page = virt_to_page(data + i);
flush_dcache_page(data_page);
- if (rc)
- ClearPageUptodate(data_page);
- else
- SetPageUptodate(data_page);
}
return rc;
}
@@ -273,14 +282,34 @@ int ecryptfs_read_lower_page_segment(struct page *page_for_ecryptfs,
size_t offset_in_page, size_t size,
struct inode *ecryptfs_inode)
{
- char *virt;
+ char *page_for_ecryptfs_virt;
+ char *tmp_virt;
loff_t offset;
int rc;

- offset = ((page_index << PAGE_CACHE_SHIFT) + offset_in_page);
- virt = kmap(page_for_ecryptfs);
- rc = ecryptfs_read_lower(virt, offset, size, ecryptfs_inode);
- kunmap(page_for_ecryptfs);
+ tmp_virt = kmalloc(PAGE_CACHE_SIZE, GFP_KERNEL);
+ if (!tmp_virt) {
+ rc = -ENOMEM;
+ goto out;
+ }
+ offset = ((((loff_t)page_index) << PAGE_CACHE_SHIFT) + offset_in_page);
+ rc = ecryptfs_read_lower(tmp_virt, offset, size, ecryptfs_inode);
+ if (rc) {
+ printk(KERN_ERR "%s: Error reading lower; rc = [%d]\n",
+ __FUNCTION__, rc);
+ goto out_free;
+ }
+ page_for_ecryptfs_virt = kmap_atomic(page_for_ecryptfs, KM_USER0);
+ memcpy(page_for_ecryptfs_virt, tmp_virt, PAGE_CACHE_SIZE);
+ kunmap_atomic(page_for_ecryptfs_virt, KM_USER0);
+ flush_dcache_page(page_for_ecryptfs);
+out_free:
+ kfree(tmp_virt);
+out:
+ if (rc)
+ ClearPageUptodate(page_for_ecryptfs);
+ else
+ SetPageUptodate(page_for_ecryptfs);
return rc;
}

@@ -328,8 +357,8 @@ int ecryptfs_read(char *data, loff_t offset, size_t size,

if (num_bytes > total_remaining_bytes)
num_bytes = total_remaining_bytes;
- ecryptfs_page = ecryptfs_get1page(ecryptfs_file,
- ecryptfs_page_idx);
+ ecryptfs_page = ecryptfs_get_locked_page(ecryptfs_file,
+ ecryptfs_page_idx);
if (IS_ERR(ecryptfs_page)) {
rc = PTR_ERR(ecryptfs_page);
printk(KERN_ERR "%s: Error getting page at "
@@ -342,6 +371,7 @@ int ecryptfs_read(char *data, loff_t offset, size_t size,
if (rc) {
printk(KERN_ERR "%s: Error decrypting "
"page; rc = [%d]\n", __FUNCTION__, rc);
+ unlock_page(ecryptfs_page);
page_cache_release(ecryptfs_page);
goto out;
}
@@ -350,6 +380,7 @@ int ecryptfs_read(char *data, loff_t offset, size_t size,
((char *)ecryptfs_page_virt + start_offset_in_page),
num_bytes);
kunmap_atomic(ecryptfs_page_virt, KM_USER0);
+ unlock_page(ecryptfs_page);
page_cache_release(ecryptfs_page);
pos += num_bytes;
data_offset += num_bytes;

2007-09-21 22:06:06

by Andrew Morton

[permalink] [raw]
Subject: Re: [Ecryptfs-devel] [PATCH 3/11] eCryptfs: read_write.c routines

On Fri, 21 Sep 2007 16:51:25 -0500
Michael Halcrow <[email protected]> wrote:

> On Wed, Sep 19, 2007 at 10:38:50PM -0700, Andrew Morton wrote:
> > > + virt = kmap(page_for_lower);
> > > + rc = ecryptfs_write_lower(ecryptfs_inode, virt, offset, size);
> > > + kunmap(page_for_lower);
> > > + return rc;
> > > +}
> >
> > argh, kmap. http://lkml.org/lkml/2007/9/15/55
>
> Here is a patch that moves to kmap_atomic(), adding an intermediate
> copy. Although I would really like to find a way to avoid having to do
> this extra copy.

We might as well stick with kmap. I was just having a whine - I don't know
what to do about this really, apart from perhaps giving in to reality and
making kmap work better.


btw, I'm not really a great admirer of the whole patchset: it does some
pretty nasty-looking things: allocating dynamic memory, grabbing the
underlying pageframes with virt_to_page(), passing them back into kernel
APIs which are supposed to be called from userspace, etc. It's all rather
ugly and abusive-looking.

But given that you're trying to do things which the kernel just isn't set
up to do, it isn't immediately obvious what can be done to fix it.

Perhaps there are problems whcih I didn't have time to spot, and perhaps
there are things which could be done to improve it. But I don't have time
to sit down and absorb it all to a sufficient level of detail to be able to
suggest anything, and nobody else seems to be interested in reading the
patches so whoop, in it all goes.

2007-09-24 22:13:34

by Michael Halcrow

[permalink] [raw]
Subject: Re: [PATCH 3/11] eCryptfs: read_write.c routines

On Wed, Sep 19, 2007 at 10:38:50PM -0700, Andrew Morton wrote:
> > + offset = (page_for_lower->index << PAGE_CACHE_SHIFT) + offset_in_page;
>
> bug. You need to cast page.index to loff_t before shifting.
>
> I'd fix it on the spot, but this would be a good time to review the
> whole patchset and perhaps the whole fs for this easy-to-do,
> hard-to-find bug.

Update data types and add casts in order to avoid potential overflow
issues.

Signed-off-by: Michael Halcrow <[email protected]>
---
diff --git a/fs/ecryptfs/crypto.c b/fs/ecryptfs/crypto.c
index 5d27cf9..4bf1a95 100644
--- a/fs/ecryptfs/crypto.c
+++ b/fs/ecryptfs/crypto.c
@@ -149,7 +149,7 @@ out:
* ecryptfs_derive_iv
* @iv: destination for the derived iv vale
* @crypt_stat: Pointer to crypt_stat struct for the current inode
- * @offset: Offset of the page whose's iv we are to derive
+ * @offset: Offset of the extent whose IV we are to derive
*
* Generate the initialization vector from the given root IV and page
* offset.
@@ -157,7 +157,7 @@ out:
* Returns zero on success; non-zero on error.
*/
static int ecryptfs_derive_iv(char *iv, struct ecryptfs_crypt_stat *crypt_stat,
- pgoff_t offset)
+ loff_t offset)
{
int rc = 0;
char dst[MD5_DIGEST_SIZE];
@@ -173,7 +173,7 @@ static int ecryptfs_derive_iv(char *iv, struct ecryptfs_crypt_stat *crypt_stat,
* hashing business. -Halcrow */
memcpy(src, crypt_stat->root_iv, crypt_stat->iv_bytes);
memset((src + crypt_stat->iv_bytes), 0, 16);
- snprintf((src + crypt_stat->iv_bytes), 16, "%ld", offset);
+ snprintf((src + crypt_stat->iv_bytes), 16, "%lld", offset);
if (unlikely(ecryptfs_verbosity > 0)) {
ecryptfs_printk(KERN_DEBUG, "source:\n");
ecryptfs_dump_hex(src, (crypt_stat->iv_bytes + 16));
@@ -384,11 +384,11 @@ static int ecryptfs_encrypt_extent(struct page *enc_extent_page,
struct page *page,
unsigned long extent_offset)
{
- unsigned long extent_base;
+ loff_t extent_base;
char extent_iv[ECRYPTFS_MAX_IV_BYTES];
int rc;

- extent_base = (page->index
+ extent_base = (((loff_t)page->index)
* (PAGE_CACHE_SIZE / crypt_stat->extent_size));
rc = ecryptfs_derive_iv(extent_iv, crypt_stat,
(extent_base + extent_offset));
@@ -492,8 +492,9 @@ int ecryptfs_encrypt_page(struct page *page)
goto out;
}
ecryptfs_lower_offset_for_extent(
- &offset, ((page->index * (PAGE_CACHE_SIZE
- / crypt_stat->extent_size))
+ &offset, ((((loff_t)page->index)
+ * (PAGE_CACHE_SIZE
+ / crypt_stat->extent_size))
+ extent_offset), crypt_stat);
rc = ecryptfs_write_lower(ecryptfs_inode, enc_extent_virt,
offset, crypt_stat->extent_size);
@@ -515,11 +516,11 @@ static int ecryptfs_decrypt_extent(struct page *page,
struct page *enc_extent_page,
unsigned long extent_offset)
{
- unsigned long extent_base;
+ loff_t extent_base;
char extent_iv[ECRYPTFS_MAX_IV_BYTES];
int rc;

- extent_base = (page->index
+ extent_base = (((loff_t)page->index)
* (PAGE_CACHE_SIZE / crypt_stat->extent_size));
rc = ecryptfs_derive_iv(extent_iv, crypt_stat,
(extent_base + extent_offset));
@@ -1320,7 +1321,7 @@ ecryptfs_write_metadata_to_contents(struct ecryptfs_crypt_stat *crypt_stat,
while (current_header_page < header_pages) {
loff_t offset;

- offset = (current_header_page << PAGE_CACHE_SHIFT);
+ offset = (((loff_t)current_header_page) << PAGE_CACHE_SHIFT);
if ((rc = ecryptfs_write_lower(ecryptfs_dentry->d_inode,
page_virt, offset,
PAGE_CACHE_SIZE))) {
diff --git a/fs/ecryptfs/mmap.c b/fs/ecryptfs/mmap.c
index c6a8a33..4eb09c1 100644
--- a/fs/ecryptfs/mmap.c
+++ b/fs/ecryptfs/mmap.c
@@ -127,7 +127,8 @@ ecryptfs_copy_up_encrypted_with_header(struct page *page,
int rc = 0;

while (extent_num_in_page < num_extents_per_page) {
- loff_t view_extent_num = ((page->index * num_extents_per_page)
+ loff_t view_extent_num = ((((loff_t)page->index)
+ * num_extents_per_page)
+ extent_num_in_page);

if (view_extent_num < crypt_stat->num_header_extents_at_front) {
@@ -418,7 +419,7 @@ static int ecryptfs_commit_write(struct file *file, struct page *page,
"index [0x%.16x])\n", page->index);
goto out;
}
- pos = (page->index << PAGE_CACHE_SHIFT) + to;
+ pos = (((loff_t)page->index) << PAGE_CACHE_SHIFT) + to;
if (pos > i_size_read(ecryptfs_inode)) {
i_size_write(ecryptfs_inode, pos);
ecryptfs_printk(KERN_DEBUG, "Expanded file size to "
diff --git a/fs/ecryptfs/read_write.c b/fs/ecryptfs/read_write.c
index ccd2599..272eaeb 100644
--- a/fs/ecryptfs/read_write.c
+++ b/fs/ecryptfs/read_write.c
@@ -87,7 +87,8 @@ int ecryptfs_write_lower_page_segment(struct inode *ecryptfs_inode,
loff_t offset;
int rc;

- offset = (page_for_lower->index << PAGE_CACHE_SHIFT) + offset_in_page;
+ offset = ((((off_t)page_for_lower->index) << PAGE_CACHE_SHIFT)
+ + offset_in_page);
virt = kmap(page_for_lower);
rc = ecryptfs_write_lower(ecryptfs_inode, virt, offset, size);
kunmap(page_for_lower);
@@ -117,7 +118,8 @@ int ecryptfs_write(struct file *ecryptfs_file, char *data, loff_t offset,
{
struct page *ecryptfs_page;
char *ecryptfs_page_virt;
- u64 ecryptfs_file_size = i_size_read(ecryptfs_file->f_dentry->d_inode);
+ loff_t ecryptfs_file_size =
+ i_size_read(ecryptfs_file->f_dentry->d_inode);
loff_t data_offset = 0;
loff_t pos;
int rc = 0;
@@ -277,7 +279,7 @@ int ecryptfs_read_lower_page_segment(struct page *page_for_ecryptfs,
loff_t offset;
int rc;

- offset = ((page_index << PAGE_CACHE_SHIFT) + offset_in_page);
+ offset = ((((loff_t)page_index) << PAGE_CACHE_SHIFT) + offset_in_page);
virt = kmap(page_for_ecryptfs);
rc = ecryptfs_read_lower(virt, offset, size, ecryptfs_inode);
kunmap(page_for_ecryptfs);
@@ -306,7 +308,8 @@ int ecryptfs_read(char *data, loff_t offset, size_t size,
{
struct page *ecryptfs_page;
char *ecryptfs_page_virt;
- u64 ecryptfs_file_size = i_size_read(ecryptfs_file->f_dentry->d_inode);
+ loff_t ecryptfs_file_size =
+ i_size_read(ecryptfs_file->f_dentry->d_inode);
loff_t data_offset = 0;
loff_t pos;
int rc = 0;

2007-09-24 22:41:22

by Michael Halcrow

[permalink] [raw]
Subject: Re: [PATCH 6/11] eCryptfs: Update metadata read/write functions

On Wed, Sep 19, 2007 at 10:48:17PM -0700, Andrew Morton wrote:
> On Mon, 17 Sep 2007 16:48:44 -0500 Michael Halcrow <[email protected]> wrote:
> > + if ((rc = ecryptfs_write_lower(ecryptfs_dentry->d_inode,
>
> checkpatch missed the assignment-in-an-if here.

Fix an assignment-in-an-if.

Signed-off-by: Michael Halcrow <[email protected]>
---
diff --git a/fs/ecryptfs/crypto.c b/fs/ecryptfs/crypto.c
index 4bf1a95..b3795f6 100644
--- a/fs/ecryptfs/crypto.c
+++ b/fs/ecryptfs/crypto.c
@@ -1306,8 +1306,9 @@ ecryptfs_write_metadata_to_contents(struct ecryptfs_crypt_stat *crypt_stat,
int header_pages;
int rc;

- if ((rc = ecryptfs_write_lower(ecryptfs_dentry->d_inode, page_virt,
- 0, PAGE_CACHE_SIZE))) {
+ rc = ecryptfs_write_lower(ecryptfs_dentry->d_inode, page_virt,
+ 0, PAGE_CACHE_SIZE);
+ if (rc) {
printk(KERN_ERR "%s: Error attempting to write header "
"information to lower file; rc = [%d]\n", __FUNCTION__,
rc);

2007-09-25 15:57:52

by Michael Halcrow

[permalink] [raw]
Subject: Re: [Ecryptfs-devel] [PATCH 3/11] eCryptfs: read_write.c routines

On Fri, Sep 21, 2007 at 03:05:40PM -0700, Andrew Morton wrote:
> btw, I'm not really a great admirer of the whole patchset: it does
> some pretty nasty-looking things: allocating dynamic memory,
> grabbing the underlying pageframes with virt_to_page(), passing them
> back into kernel APIs which are supposed to be called from
> userspace, etc. It's all rather ugly and abusive-looking.

Functions higher up the execution stack should be the ones mucking
with the Uptodate flag. The patch below addresses some of these
issues. I also whipped up a post-patch partial call graph to help
illustrate what is going on with the page mapping and Uptodate status
in the various eCryptfs read/write paths:

http://ecryptfs.sourceforge.net/ecryptfs-pageuptodate-call-graph.png

---

The functions that eventually call down to ecryptfs_read_lower(),
ecryptfs_decrypt_page(), and ecryptfs_copy_up_encrypted_with_header()
should have the responsibility of managing the page Uptodate
status. This patch gets rid of some of the ugliness that resulted from
trying to push some of the page flag setting too far down the stack.

Signed-off-by: Michael Halcrow <[email protected]>
---
diff --git a/fs/ecryptfs/crypto.c b/fs/ecryptfs/crypto.c
index b3795f6..bbec711 100644
--- a/fs/ecryptfs/crypto.c
+++ b/fs/ecryptfs/crypto.c
@@ -605,14 +605,14 @@ int ecryptfs_decrypt_page(struct page *page)
printk(KERN_ERR "%s: Error attempting to copy "
"page at index [%ld]\n", __FUNCTION__,
page->index);
- goto out_clear_uptodate;
+ goto out;
}
enc_extent_virt = kmalloc(PAGE_CACHE_SIZE, GFP_USER);
if (!enc_extent_virt) {
rc = -ENOMEM;
ecryptfs_printk(KERN_ERR, "Error allocating memory for "
"encrypted extent\n");
- goto out_clear_uptodate;
+ goto out;
}
enc_extent_page = virt_to_page(enc_extent_virt);
for (extent_offset = 0;
@@ -631,21 +631,17 @@ int ecryptfs_decrypt_page(struct page *page)
ecryptfs_printk(KERN_ERR, "Error attempting "
"to read lower page; rc = [%d]"
"\n", rc);
- goto out_clear_uptodate;
+ goto out;
}
rc = ecryptfs_decrypt_extent(page, crypt_stat, enc_extent_page,
extent_offset);
if (rc) {
printk(KERN_ERR "%s: Error encrypting extent; "
"rc = [%d]\n", __FUNCTION__, rc);
- goto out_clear_uptodate;
+ goto out;
}
extent_offset++;
}
- SetPageUptodate(page);
- goto out;
-out_clear_uptodate:
- ClearPageUptodate(page);
out:
kfree(enc_extent_virt);
return rc;
diff --git a/fs/ecryptfs/ecryptfs_kernel.h b/fs/ecryptfs/ecryptfs_kernel.h
index bb92b74..ce7a5d4 100644
--- a/fs/ecryptfs/ecryptfs_kernel.h
+++ b/fs/ecryptfs/ecryptfs_kernel.h
@@ -648,6 +648,6 @@ int ecryptfs_read_lower_page_segment(struct page *page_for_ecryptfs,
struct inode *ecryptfs_inode);
int ecryptfs_read(char *data, loff_t offset, size_t size,
struct file *ecryptfs_file);
-struct page *ecryptfs_get1page(struct file *file, loff_t index);
+struct page *ecryptfs_get_locked_page(struct file *file, loff_t index);

#endif /* #ifndef ECRYPTFS_KERNEL_H */
diff --git a/fs/ecryptfs/mmap.c b/fs/ecryptfs/mmap.c
index 4eb09c1..16a7a55 100644
--- a/fs/ecryptfs/mmap.c
+++ b/fs/ecryptfs/mmap.c
@@ -37,23 +37,27 @@
struct kmem_cache *ecryptfs_lower_page_cache;

/**
- * ecryptfs_get1page
+ * ecryptfs_get_locked_page
*
* Get one page from cache or lower f/s, return error otherwise.
*
- * Returns unlocked and up-to-date page (if ok), with increased
+ * Returns locked and up-to-date page (if ok), with increased
* refcnt.
*/
-struct page *ecryptfs_get1page(struct file *file, loff_t index)
+struct page *ecryptfs_get_locked_page(struct file *file, loff_t index)
{
struct dentry *dentry;
struct inode *inode;
struct address_space *mapping;
+ struct page *page;

dentry = file->f_path.dentry;
inode = dentry->d_inode;
mapping = inode->i_mapping;
- return read_mapping_page(mapping, index, (void *)file);
+ page = read_mapping_page(mapping, index, (void *)file);
+ if (!IS_ERR(page))
+ lock_page(page);
+ return page;
}

/**
@@ -146,12 +150,10 @@ ecryptfs_copy_up_encrypted_with_header(struct page *page,
kunmap_atomic(page_virt, KM_USER0);
flush_dcache_page(page);
if (rc) {
- ClearPageUptodate(page);
printk(KERN_ERR "%s: Error reading xattr "
"region; rc = [%d]\n", __FUNCTION__, rc);
goto out;
}
- SetPageUptodate(page);
} else {
/* This is an encrypted data extent */
loff_t lower_offset =
@@ -232,6 +234,10 @@ static int ecryptfs_readpage(struct file *file, struct page *page)
}
}
out:
+ if (rc)
+ ClearPageUptodate(page);
+ else
+ SetPageUptodate(page);
ecryptfs_printk(KERN_DEBUG, "Unlocking page with index = [0x%.16x]\n",
page->index);
unlock_page(page);
@@ -265,10 +271,18 @@ static int ecryptfs_prepare_write(struct file *file, struct page *page,
if (from == 0 && to == PAGE_CACHE_SIZE)
goto out; /* If we are writing a full page, it will be
up to date. */
- if (!PageUptodate(page))
+ if (!PageUptodate(page)) {
rc = ecryptfs_read_lower_page_segment(page, page->index, 0,
PAGE_CACHE_SIZE,
page->mapping->host);
+ if (rc) {
+ printk(KERN_ERR "%s: Error attemping to read lower "
+ "page segment; rc = [%d]\n", __FUNCTION__, rc);
+ ClearPageUptodate(page);
+ goto out;
+ } else
+ SetPageUptodate(page);
+ }
if (page->index != 0) {
loff_t end_of_prev_pg_pos =
(((loff_t)page->index << PAGE_CACHE_SHIFT) - 1);
diff --git a/fs/ecryptfs/read_write.c b/fs/ecryptfs/read_write.c
index 272eaeb..2150edf 100644
--- a/fs/ecryptfs/read_write.c
+++ b/fs/ecryptfs/read_write.c
@@ -142,8 +142,8 @@ int ecryptfs_write(struct file *ecryptfs_file, char *data, loff_t offset,
if (num_bytes > total_remaining_zeros)
num_bytes = total_remaining_zeros;
}
- ecryptfs_page = ecryptfs_get1page(ecryptfs_file,
- ecryptfs_page_idx);
+ ecryptfs_page = ecryptfs_get_locked_page(ecryptfs_file,
+ ecryptfs_page_idx);
if (IS_ERR(ecryptfs_page)) {
rc = PTR_ERR(ecryptfs_page);
printk(KERN_ERR "%s: Error getting page at "
@@ -161,6 +161,7 @@ int ecryptfs_write(struct file *ecryptfs_file, char *data, loff_t offset,
printk(KERN_ERR "%s: Error decrypting "
"page; rc = [%d]\n",
__FUNCTION__, rc);
+ ClearPageUptodate(ecryptfs_page);
page_cache_release(ecryptfs_page);
goto out;
}
@@ -180,14 +181,15 @@ int ecryptfs_write(struct file *ecryptfs_file, char *data, loff_t offset,
}
kunmap_atomic(ecryptfs_page_virt, KM_USER0);
flush_dcache_page(ecryptfs_page);
+ SetPageUptodate(ecryptfs_page);
+ unlock_page(ecryptfs_page);
rc = ecryptfs_encrypt_page(ecryptfs_page);
+ page_cache_release(ecryptfs_page);
if (rc) {
printk(KERN_ERR "%s: Error encrypting "
"page; rc = [%d]\n", __FUNCTION__, rc);
- page_cache_release(ecryptfs_page);
goto out;
}
- page_cache_release(ecryptfs_page);
pos += num_bytes;
}
if ((offset + size) > ecryptfs_file_size) {
@@ -225,7 +227,6 @@ int ecryptfs_read_lower(char *data, loff_t offset, size_t size,
ecryptfs_inode_to_private(ecryptfs_inode);
ssize_t octets_read;
mm_segment_t fs_save;
- size_t i;
int rc = 0;

mutex_lock(&inode_info->lower_file_mutex);
@@ -242,16 +243,6 @@ int ecryptfs_read_lower(char *data, loff_t offset, size_t size,
rc = -EINVAL;
}
mutex_unlock(&inode_info->lower_file_mutex);
- for (i = 0; i < size; i += PAGE_CACHE_SIZE) {
- struct page *data_page;
-
- data_page = virt_to_page(data + i);
- flush_dcache_page(data_page);
- if (rc)
- ClearPageUptodate(data_page);
- else
- SetPageUptodate(data_page);
- }
return rc;
}

@@ -283,6 +274,7 @@ int ecryptfs_read_lower_page_segment(struct page *page_for_ecryptfs,
virt = kmap(page_for_ecryptfs);
rc = ecryptfs_read_lower(virt, offset, size, ecryptfs_inode);
kunmap(page_for_ecryptfs);
+ flush_dcache_page(page_for_ecryptfs);
return rc;
}

@@ -331,8 +323,8 @@ int ecryptfs_read(char *data, loff_t offset, size_t size,

if (num_bytes > total_remaining_bytes)
num_bytes = total_remaining_bytes;
- ecryptfs_page = ecryptfs_get1page(ecryptfs_file,
- ecryptfs_page_idx);
+ ecryptfs_page = ecryptfs_get_locked_page(ecryptfs_file,
+ ecryptfs_page_idx);
if (IS_ERR(ecryptfs_page)) {
rc = PTR_ERR(ecryptfs_page);
printk(KERN_ERR "%s: Error getting page at "
@@ -345,6 +337,7 @@ int ecryptfs_read(char *data, loff_t offset, size_t size,
if (rc) {
printk(KERN_ERR "%s: Error decrypting "
"page; rc = [%d]\n", __FUNCTION__, rc);
+ ClearPageUptodate(ecryptfs_page);
page_cache_release(ecryptfs_page);
goto out;
}
@@ -353,6 +346,9 @@ int ecryptfs_read(char *data, loff_t offset, size_t size,
((char *)ecryptfs_page_virt + start_offset_in_page),
num_bytes);
kunmap_atomic(ecryptfs_page_virt, KM_USER0);
+ flush_dcache_page(ecryptfs_page);
+ SetPageUptodate(ecryptfs_page);
+ unlock_page(ecryptfs_page);
page_cache_release(ecryptfs_page);
pos += num_bytes;
data_offset += num_bytes;