diff options
| author | Tyler Hicks <tyhicks@linux.vnet.ibm.com> | 2011-04-14 16:35:11 -0400 |
|---|---|---|
| committer | Tyler Hicks <tyhicks@linux.vnet.ibm.com> | 2011-04-25 19:32:37 -0400 |
| commit | 332ab16f830f59e7621ae8eb2c353dc135a316f6 (patch) | |
| tree | c5b249f34dcacf2aa5ee24de8d332d8171398203 | |
| parent | dd55c89852481a0708c3fd4b48f3081f4280d9d3 (diff) | |
eCryptfs: Add reference counting to lower files
For any given lower inode, eCryptfs keeps only one lower file open and
multiplexes all eCryptfs file operations through that lower file. The
lower file was considered "persistent" and stayed open from the first
lookup through the lifetime of the inode.
This patch keeps the notion of a single, per-inode lower file, but adds
reference counting around the lower file so that it is closed when not
currently in use. If the reference count is at 0 when an operation (such
as open, create, etc.) needs to use the lower file, a new lower file is
opened. Since the file is no longer persistent, all references to the
term persistent file are changed to lower file.
Locking is added around the sections of code that opens the lower file
and assign the pointer in the inode info, as well as the code the fputs
the lower file when all eCryptfs users are done with it.
This patch is needed to fix issues, when mounted on top of the NFSv3
client, where the lower file is left silly renamed until the eCryptfs
inode is destroyed.
Signed-off-by: Tyler Hicks <tyhicks@linux.vnet.ibm.com>
| -rw-r--r-- | fs/ecryptfs/ecryptfs_kernel.h | 5 | ||||
| -rw-r--r-- | fs/ecryptfs/file.c | 22 | ||||
| -rw-r--r-- | fs/ecryptfs/inode.c | 30 | ||||
| -rw-r--r-- | fs/ecryptfs/kthread.c | 6 | ||||
| -rw-r--r-- | fs/ecryptfs/main.c | 72 | ||||
| -rw-r--r-- | fs/ecryptfs/super.c | 16 |
6 files changed, 92 insertions, 59 deletions
diff --git a/fs/ecryptfs/ecryptfs_kernel.h b/fs/ecryptfs/ecryptfs_kernel.h index bd3cafd0949d..380bee1094c3 100644 --- a/fs/ecryptfs/ecryptfs_kernel.h +++ b/fs/ecryptfs/ecryptfs_kernel.h | |||
| @@ -295,6 +295,8 @@ struct ecryptfs_crypt_stat { | |||
| 295 | struct ecryptfs_inode_info { | 295 | struct ecryptfs_inode_info { |
| 296 | struct inode vfs_inode; | 296 | struct inode vfs_inode; |
| 297 | struct inode *wii_inode; | 297 | struct inode *wii_inode; |
| 298 | struct mutex lower_file_mutex; | ||
| 299 | atomic_t lower_file_count; | ||
| 298 | struct file *lower_file; | 300 | struct file *lower_file; |
| 299 | struct ecryptfs_crypt_stat crypt_stat; | 301 | struct ecryptfs_crypt_stat crypt_stat; |
| 300 | }; | 302 | }; |
| @@ -757,7 +759,8 @@ int ecryptfs_privileged_open(struct file **lower_file, | |||
| 757 | struct dentry *lower_dentry, | 759 | struct dentry *lower_dentry, |
| 758 | struct vfsmount *lower_mnt, | 760 | struct vfsmount *lower_mnt, |
| 759 | const struct cred *cred); | 761 | const struct cred *cred); |
| 760 | int ecryptfs_init_persistent_file(struct dentry *ecryptfs_dentry); | 762 | int ecryptfs_get_lower_file(struct dentry *ecryptfs_dentry); |
| 763 | void ecryptfs_put_lower_file(struct inode *inode); | ||
| 761 | int | 764 | int |
| 762 | ecryptfs_write_tag_70_packet(char *dest, size_t *remaining_bytes, | 765 | ecryptfs_write_tag_70_packet(char *dest, size_t *remaining_bytes, |
| 763 | size_t *packet_size, | 766 | size_t *packet_size, |
diff --git a/fs/ecryptfs/file.c b/fs/ecryptfs/file.c index cedc913d11ba..146c4edff70c 100644 --- a/fs/ecryptfs/file.c +++ b/fs/ecryptfs/file.c | |||
| @@ -191,10 +191,10 @@ static int ecryptfs_open(struct inode *inode, struct file *file) | |||
| 191 | | ECRYPTFS_ENCRYPTED); | 191 | | ECRYPTFS_ENCRYPTED); |
| 192 | } | 192 | } |
| 193 | mutex_unlock(&crypt_stat->cs_mutex); | 193 | mutex_unlock(&crypt_stat->cs_mutex); |
| 194 | rc = ecryptfs_init_persistent_file(ecryptfs_dentry); | 194 | rc = ecryptfs_get_lower_file(ecryptfs_dentry); |
| 195 | if (rc) { | 195 | if (rc) { |
| 196 | printk(KERN_ERR "%s: Error attempting to initialize " | 196 | printk(KERN_ERR "%s: Error attempting to initialize " |
| 197 | "the persistent file for the dentry with name " | 197 | "the lower file for the dentry with name " |
| 198 | "[%s]; rc = [%d]\n", __func__, | 198 | "[%s]; rc = [%d]\n", __func__, |
| 199 | ecryptfs_dentry->d_name.name, rc); | 199 | ecryptfs_dentry->d_name.name, rc); |
| 200 | goto out_free; | 200 | goto out_free; |
| @@ -202,9 +202,9 @@ static int ecryptfs_open(struct inode *inode, struct file *file) | |||
| 202 | if ((ecryptfs_inode_to_private(inode)->lower_file->f_flags & O_ACCMODE) | 202 | if ((ecryptfs_inode_to_private(inode)->lower_file->f_flags & O_ACCMODE) |
| 203 | == O_RDONLY && (file->f_flags & O_ACCMODE) != O_RDONLY) { | 203 | == O_RDONLY && (file->f_flags & O_ACCMODE) != O_RDONLY) { |
| 204 | rc = -EPERM; | 204 | rc = -EPERM; |
| 205 | printk(KERN_WARNING "%s: Lower persistent file is RO; eCryptfs " | 205 | printk(KERN_WARNING "%s: Lower file is RO; eCryptfs " |
| 206 | "file must hence be opened RO\n", __func__); | 206 | "file must hence be opened RO\n", __func__); |
| 207 | goto out_free; | 207 | goto out_put; |
| 208 | } | 208 | } |
| 209 | ecryptfs_set_file_lower( | 209 | ecryptfs_set_file_lower( |
| 210 | file, ecryptfs_inode_to_private(inode)->lower_file); | 210 | file, ecryptfs_inode_to_private(inode)->lower_file); |
| @@ -232,7 +232,7 @@ static int ecryptfs_open(struct inode *inode, struct file *file) | |||
| 232 | "Plaintext passthrough mode is not " | 232 | "Plaintext passthrough mode is not " |
| 233 | "enabled; returning -EIO\n"); | 233 | "enabled; returning -EIO\n"); |
| 234 | mutex_unlock(&crypt_stat->cs_mutex); | 234 | mutex_unlock(&crypt_stat->cs_mutex); |
| 235 | goto out_free; | 235 | goto out_put; |
| 236 | } | 236 | } |
| 237 | rc = 0; | 237 | rc = 0; |
| 238 | crypt_stat->flags &= ~(ECRYPTFS_ENCRYPTED); | 238 | crypt_stat->flags &= ~(ECRYPTFS_ENCRYPTED); |
| @@ -245,6 +245,8 @@ static int ecryptfs_open(struct inode *inode, struct file *file) | |||
| 245 | "[0x%.16lx] size: [0x%.16llx]\n", inode, inode->i_ino, | 245 | "[0x%.16lx] size: [0x%.16llx]\n", inode, inode->i_ino, |
| 246 | (unsigned long long)i_size_read(inode)); | 246 | (unsigned long long)i_size_read(inode)); |
| 247 | goto out; | 247 | goto out; |
| 248 | out_put: | ||
| 249 | ecryptfs_put_lower_file(inode); | ||
| 248 | out_free: | 250 | out_free: |
| 249 | kmem_cache_free(ecryptfs_file_info_cache, | 251 | kmem_cache_free(ecryptfs_file_info_cache, |
| 250 | ecryptfs_file_to_private(file)); | 252 | ecryptfs_file_to_private(file)); |
| @@ -254,17 +256,13 @@ out: | |||
| 254 | 256 | ||
| 255 | static int ecryptfs_flush(struct file *file, fl_owner_t td) | 257 | static int ecryptfs_flush(struct file *file, fl_owner_t td) |
| 256 | { | 258 | { |
| 257 | int rc = 0; | 259 | return file->f_mode & FMODE_WRITE |
| 258 | struct file *lower_file = NULL; | 260 | ? filemap_write_and_wait(file->f_mapping) : 0; |
| 259 | |||
| 260 | lower_file = ecryptfs_file_to_lower(file); | ||
| 261 | if (lower_file->f_op && lower_file->f_op->flush) | ||
| 262 | rc = lower_file->f_op->flush(lower_file, td); | ||
| 263 | return rc; | ||
| 264 | } | 261 | } |
| 265 | 262 | ||
| 266 | static int ecryptfs_release(struct inode *inode, struct file *file) | 263 | static int ecryptfs_release(struct inode *inode, struct file *file) |
| 267 | { | 264 | { |
| 265 | ecryptfs_put_lower_file(inode); | ||
| 268 | kmem_cache_free(ecryptfs_file_info_cache, | 266 | kmem_cache_free(ecryptfs_file_info_cache, |
| 269 | ecryptfs_file_to_private(file)); | 267 | ecryptfs_file_to_private(file)); |
| 270 | return 0; | 268 | return 0; |
diff --git a/fs/ecryptfs/inode.c b/fs/ecryptfs/inode.c index 72d357649599..f6b388638c3d 100644 --- a/fs/ecryptfs/inode.c +++ b/fs/ecryptfs/inode.c | |||
| @@ -168,19 +168,18 @@ static int ecryptfs_initialize_file(struct dentry *ecryptfs_dentry) | |||
| 168 | "context; rc = [%d]\n", rc); | 168 | "context; rc = [%d]\n", rc); |
| 169 | goto out; | 169 | goto out; |
| 170 | } | 170 | } |
| 171 | rc = ecryptfs_init_persistent_file(ecryptfs_dentry); | 171 | rc = ecryptfs_get_lower_file(ecryptfs_dentry); |
| 172 | if (rc) { | 172 | if (rc) { |
| 173 | printk(KERN_ERR "%s: Error attempting to initialize " | 173 | printk(KERN_ERR "%s: Error attempting to initialize " |
| 174 | "the persistent file for the dentry with name " | 174 | "the lower file for the dentry with name " |
| 175 | "[%s]; rc = [%d]\n", __func__, | 175 | "[%s]; rc = [%d]\n", __func__, |
| 176 | ecryptfs_dentry->d_name.name, rc); | 176 | ecryptfs_dentry->d_name.name, rc); |
| 177 | goto out; | 177 | goto out; |
| 178 | } | 178 | } |
| 179 | rc = ecryptfs_write_metadata(ecryptfs_dentry); | 179 | rc = ecryptfs_write_metadata(ecryptfs_dentry); |
| 180 | if (rc) { | 180 | if (rc) |
| 181 | printk(KERN_ERR "Error writing headers; rc = [%d]\n", rc); | 181 | printk(KERN_ERR "Error writing headers; rc = [%d]\n", rc); |
| 182 | goto out; | 182 | ecryptfs_put_lower_file(ecryptfs_dentry->d_inode); |
| 183 | } | ||
| 184 | out: | 183 | out: |
| 185 | return rc; | 184 | return rc; |
| 186 | } | 185 | } |
| @@ -230,7 +229,7 @@ int ecryptfs_lookup_and_interpose_lower(struct dentry *ecryptfs_dentry, | |||
| 230 | struct ecryptfs_crypt_stat *crypt_stat; | 229 | struct ecryptfs_crypt_stat *crypt_stat; |
| 231 | char *page_virt = NULL; | 230 | char *page_virt = NULL; |
| 232 | u64 file_size; | 231 | u64 file_size; |
| 233 | int rc = 0; | 232 | int put_lower = 0, rc = 0; |
| 234 | 233 | ||
| 235 | lower_dir_dentry = lower_dentry->d_parent; | 234 | lower_dir_dentry = lower_dentry->d_parent; |
| 236 | lower_mnt = mntget(ecryptfs_dentry_to_lower_mnt( | 235 | lower_mnt = mntget(ecryptfs_dentry_to_lower_mnt( |
| @@ -277,14 +276,15 @@ int ecryptfs_lookup_and_interpose_lower(struct dentry *ecryptfs_dentry, | |||
| 277 | rc = -ENOMEM; | 276 | rc = -ENOMEM; |
| 278 | goto out; | 277 | goto out; |
| 279 | } | 278 | } |
| 280 | rc = ecryptfs_init_persistent_file(ecryptfs_dentry); | 279 | rc = ecryptfs_get_lower_file(ecryptfs_dentry); |
| 281 | if (rc) { | 280 | if (rc) { |
| 282 | printk(KERN_ERR "%s: Error attempting to initialize " | 281 | printk(KERN_ERR "%s: Error attempting to initialize " |
| 283 | "the persistent file for the dentry with name " | 282 | "the lower file for the dentry with name " |
| 284 | "[%s]; rc = [%d]\n", __func__, | 283 | "[%s]; rc = [%d]\n", __func__, |
| 285 | ecryptfs_dentry->d_name.name, rc); | 284 | ecryptfs_dentry->d_name.name, rc); |
| 286 | goto out_free_kmem; | 285 | goto out_free_kmem; |
| 287 | } | 286 | } |
| 287 | put_lower = 1; | ||
| 288 | crypt_stat = &ecryptfs_inode_to_private( | 288 | crypt_stat = &ecryptfs_inode_to_private( |
| 289 | ecryptfs_dentry->d_inode)->crypt_stat; | 289 | ecryptfs_dentry->d_inode)->crypt_stat; |
| 290 | /* TODO: lock for crypt_stat comparison */ | 290 | /* TODO: lock for crypt_stat comparison */ |
| @@ -322,6 +322,8 @@ out_put: | |||
| 322 | mntput(lower_mnt); | 322 | mntput(lower_mnt); |
| 323 | d_drop(ecryptfs_dentry); | 323 | d_drop(ecryptfs_dentry); |
| 324 | out: | 324 | out: |
| 325 | if (put_lower) | ||
| 326 | ecryptfs_put_lower_file(ecryptfs_dentry->d_inode); | ||
| 325 | return rc; | ||
