aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorTyler Hicks <tyhicks@linux.vnet.ibm.com>2011-04-14 16:35:11 -0400
committerTyler Hicks <tyhicks@linux.vnet.ibm.com>2011-04-25 19:32:37 -0400
commit332ab16f830f59e7621ae8eb2c353dc135a316f6 (patch)
treec5b249f34dcacf2aa5ee24de8d332d8171398203
parentdd55c89852481a0708c3fd4b48f3081f4280d9d3 (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.h5
-rw-r--r--fs/ecryptfs/file.c22
-rw-r--r--fs/ecryptfs/inode.c30
-rw-r--r--fs/ecryptfs/kthread.c6
-rw-r--r--fs/ecryptfs/main.c72
-rw-r--r--fs/ecryptfs/super.c16
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 {
295struct ecryptfs_inode_info { 295struct 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);
760int ecryptfs_init_persistent_file(struct dentry *ecryptfs_dentry); 762int ecryptfs_get_lower_file(struct dentry *ecryptfs_dentry);
763void ecryptfs_put_lower_file(struct inode *inode);
761int 764int
762ecryptfs_write_tag_70_packet(char *dest, size_t *remaining_bytes, 765ecryptfs_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;
248out_put:
249 ecryptfs_put_lower_file(inode);
248out_free: 250out_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
255static int ecryptfs_flush(struct file *file, fl_owner_t td) 257static 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
266static int ecryptfs_release(struct inode *inode, struct file *file) 263static 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 }
184out: 183out:
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);
324out: 324out:
325 if (put_lower)
326 ecryptfs_put_lower_file(ecryptfs_dentry->d_inode);
325 return rc;