Skip to content

Commit b2648d5

Browse files
author
Al Viro
committed
ecryptfs: saner API for lock_parent()
Switch all users of lock_parent() to the approach used by ->unlink() and ->rmdir() - instead of playing with dget_parent() of underlying dentry of child, * start with ecryptfs dentry of child. * find underlying dentries for that dentry and its parent (which is stable, since the parent directory in upper layer is held at least shared). No need to pin them, they are already pinned by ecryptfs dentries. * lock the inode of undelying directory of parent * check if it's the parent of underlying dentry of child. ->d_parent of underlying dentry of child might be unstable. However, result of its comparison with underlying dentry of parent *is* stable now. Turn that into replacement of lock_parent(), convert the existing callers of lock_parent() to that, along with ecryptfs_unlink() and ecryptfs_rmdir(). Callers need only the underlying dentry of child and inode of underlying dentry of parent, so lock_parent() passes those to the caller now. Note that underlying directory is locked in any case, success or failure. That approach does not need a primitive for unlocking - we hadn't grabbed any dentry references, so all we need is to unlock the underlying directory inode. Signed-off-by: Al Viro <[email protected]>
1 parent 4313e35 commit b2648d5

File tree

1 file changed

+74
-83
lines changed

1 file changed

+74
-83
lines changed

fs/ecryptfs/inode.c

Lines changed: 74 additions & 83 deletions
Original file line numberDiff line numberDiff line change
@@ -21,19 +21,18 @@
2121
#include <asm/unaligned.h>
2222
#include "ecryptfs_kernel.h"
2323

24-
static struct dentry *lock_parent(struct dentry *dentry)
24+
static int lock_parent(struct dentry *dentry,
25+
struct dentry **lower_dentry,
26+
struct inode **lower_dir)
2527
{
26-
struct dentry *dir;
28+
struct dentry *lower_dir_dentry;
2729

28-
dir = dget_parent(dentry);
29-
inode_lock_nested(d_inode(dir), I_MUTEX_PARENT);
30-
return dir;
31-
}
30+
lower_dir_dentry = ecryptfs_dentry_to_lower(dentry->d_parent);
31+
*lower_dir = d_inode(lower_dir_dentry);
32+
*lower_dentry = ecryptfs_dentry_to_lower(dentry);
3233

33-
static void unlock_dir(struct dentry *dir)
34-
{
35-
inode_unlock(d_inode(dir));
36-
dput(dir);
34+
inode_lock_nested(*lower_dir, I_MUTEX_PARENT);
35+
return (*lower_dentry)->d_parent == lower_dir_dentry ? 0 : -EINVAL;
3736
}
3837

3938
static int ecryptfs_inode_test(struct inode *inode, void *lower_inode)
@@ -127,32 +126,29 @@ static int ecryptfs_interpose(struct dentry *lower_dentry,
127126
static int ecryptfs_do_unlink(struct inode *dir, struct dentry *dentry,
128127
struct inode *inode)
129128
{
130-
struct dentry *lower_dentry = ecryptfs_dentry_to_lower(dentry);
131-
struct dentry *lower_dir_dentry;
132-
struct inode *lower_dir_inode;
129+
struct dentry *lower_dentry;
130+
struct inode *lower_dir;
133131
int rc;
134132

135-
lower_dir_dentry = ecryptfs_dentry_to_lower(dentry->d_parent);
136-
lower_dir_inode = d_inode(lower_dir_dentry);
137-
inode_lock_nested(lower_dir_inode, I_MUTEX_PARENT);
133+
rc = lock_parent(dentry, &lower_dentry, &lower_dir);
138134
dget(lower_dentry); // don't even try to make the lower negative
139-
if (lower_dentry->d_parent != lower_dir_dentry)
140-
rc = -EINVAL;
141-
else if (d_unhashed(lower_dentry))
142-
rc = -EINVAL;
143-
else
144-
rc = vfs_unlink(&init_user_ns, lower_dir_inode, lower_dentry,
145-
NULL);
135+
if (!rc) {
136+
if (d_unhashed(lower_dentry))
137+
rc = -EINVAL;
138+
else
139+
rc = vfs_unlink(&init_user_ns, lower_dir, lower_dentry,
140+
NULL);
141+
}
146142
if (rc) {
147143
printk(KERN_ERR "Error in vfs_unlink; rc = [%d]\n", rc);
148144
goto out_unlock;
149145
}
150-
fsstack_copy_attr_times(dir, lower_dir_inode);
146+
fsstack_copy_attr_times(dir, lower_dir);
151147
set_nlink(inode, ecryptfs_inode_to_lower(inode)->i_nlink);
152148
inode->i_ctime = dir->i_ctime;
153149
out_unlock:
154150
dput(lower_dentry);
155-
inode_unlock(lower_dir_inode);
151+
inode_unlock(lower_dir);
156152
if (!rc)
157153
d_drop(dentry);
158154
return rc;
@@ -176,13 +172,13 @@ ecryptfs_do_create(struct inode *directory_inode,
176172
{
177173
int rc;
178174
struct dentry *lower_dentry;
179-
struct dentry *lower_dir_dentry;
175+
struct inode *lower_dir;
180176
struct inode *inode;
181177

182-
lower_dentry = ecryptfs_dentry_to_lower(ecryptfs_dentry);
183-
lower_dir_dentry = lock_parent(lower_dentry);
184-
rc = vfs_create(&init_user_ns, d_inode(lower_dir_dentry), lower_dentry,
185-
mode, true);
178+
rc = lock_parent(ecryptfs_dentry, &lower_dentry, &lower_dir);
179+
if (!rc)
180+
rc = vfs_create(&init_user_ns, lower_dir,
181+
lower_dentry, mode, true);
186182
if (rc) {
187183
printk(KERN_ERR "%s: Failure to create dentry in lower fs; "
188184
"rc = [%d]\n", __func__, rc);
@@ -192,14 +188,13 @@ ecryptfs_do_create(struct inode *directory_inode,
192188
inode = __ecryptfs_get_inode(d_inode(lower_dentry),
193189
directory_inode->i_sb);
194190
if (IS_ERR(inode)) {
195-
vfs_unlink(&init_user_ns, d_inode(lower_dir_dentry),
196-
lower_dentry, NULL);
191+
vfs_unlink(&init_user_ns, lower_dir, lower_dentry, NULL);
197192
goto out_lock;
198193
}
199-
fsstack_copy_attr_times(directory_inode, d_inode(lower_dir_dentry));
200-
fsstack_copy_inode_size(directory_inode, d_inode(lower_dir_dentry));
194+
fsstack_copy_attr_times(directory_inode, lower_dir);
195+
fsstack_copy_inode_size(directory_inode, lower_dir);
201196
out_lock:
202-
unlock_dir(lower_dir_dentry);
197+
inode_unlock(lower_dir);
203198
return inode;
204199
}
205200

@@ -430,28 +425,28 @@ static int ecryptfs_link(struct dentry *old_dentry, struct inode *dir,
430425
{
431426
struct dentry *lower_old_dentry;
432427
struct dentry *lower_new_dentry;
433-
struct dentry *lower_dir_dentry;
428+
struct inode *lower_dir;
434429
u64 file_size_save;
435430
int rc;
436431

437432
file_size_save = i_size_read(d_inode(old_dentry));
438433
lower_old_dentry = ecryptfs_dentry_to_lower(old_dentry);
439-
lower_new_dentry = ecryptfs_dentry_to_lower(new_dentry);
440-
lower_dir_dentry = lock_parent(lower_new_dentry);
441-
rc = vfs_link(lower_old_dentry, &init_user_ns,
442-
d_inode(lower_dir_dentry), lower_new_dentry, NULL);
434+
rc = lock_parent(new_dentry, &lower_new_dentry, &lower_dir);
435+
if (!rc)
436+
rc = vfs_link(lower_old_dentry, &init_user_ns, lower_dir,
437+
lower_new_dentry, NULL);
443438
if (rc || d_really_is_negative(lower_new_dentry))
444439
goto out_lock;
445440
rc = ecryptfs_interpose(lower_new_dentry, new_dentry, dir->i_sb);
446441
if (rc)
447442
goto out_lock;
448-
fsstack_copy_attr_times(dir, d_inode(lower_dir_dentry));
449-
fsstack_copy_inode_size(dir, d_inode(lower_dir_dentry));
443+
fsstack_copy_attr_times(dir, lower_dir);
444+
fsstack_copy_inode_size(dir, lower_dir);
450445
set_nlink(d_inode(old_dentry),
451446
ecryptfs_inode_to_lower(d_inode(old_dentry))->i_nlink);
452447
i_size_write(d_inode(new_dentry), file_size_save);
453448
out_lock:
454-
unlock_dir(lower_dir_dentry);
449+
inode_unlock(lower_dir);
455450
return rc;
456451
}
457452

@@ -466,13 +461,14 @@ static int ecryptfs_symlink(struct user_namespace *mnt_userns,
466461
{
467462
int rc;
468463
struct dentry *lower_dentry;
469-
struct dentry *lower_dir_dentry;
464+
struct inode *lower_dir;
470465
char *encoded_symname;
471466
size_t encoded_symlen;
472467
struct ecryptfs_mount_crypt_stat *mount_crypt_stat = NULL;
473468

474-
lower_dentry = ecryptfs_dentry_to_lower(dentry);
475-
lower_dir_dentry = lock_parent(lower_dentry);
469+
rc = lock_parent(dentry, &lower_dentry, &lower_dir);
470+
if (rc)
471+
goto out_lock;
476472
mount_crypt_stat = &ecryptfs_superblock_to_private(
477473
dir->i_sb)->mount_crypt_stat;
478474
rc = ecryptfs_encrypt_and_encode_filename(&encoded_symname,
@@ -481,18 +477,18 @@ static int ecryptfs_symlink(struct user_namespace *mnt_userns,
481477
strlen(symname));
482478
if (rc)
483479
goto out_lock;
484-
rc = vfs_symlink(&init_user_ns, d_inode(lower_dir_dentry), lower_dentry,
480+
rc = vfs_symlink(&init_user_ns, lower_dir, lower_dentry,
485481
encoded_symname);
486482
kfree(encoded_symname);
487483
if (rc || d_really_is_negative(lower_dentry))
488484
goto out_lock;
489485
rc = ecryptfs_interpose(lower_dentry, dentry, dir->i_sb);
490486
if (rc)
491487
goto out_lock;
492-
fsstack_copy_attr_times(dir, d_inode(lower_dir_dentry));
493-
fsstack_copy_inode_size(dir, d_inode(lower_dir_dentry));
488+
fsstack_copy_attr_times(dir, lower_dir);
489+
fsstack_copy_inode_size(dir, lower_dir);
494490
out_lock:
495-
unlock_dir(lower_dir_dentry);
491+
inode_unlock(lower_dir);
496492
if (d_really_is_negative(dentry))
497493
d_drop(dentry);
498494
return rc;
@@ -503,22 +499,22 @@ static int ecryptfs_mkdir(struct user_namespace *mnt_userns, struct inode *dir,
503499
{
504500
int rc;
505501
struct dentry *lower_dentry;
506-
struct dentry *lower_dir_dentry;
502+
struct inode *lower_dir;
507503

508-
lower_dentry = ecryptfs_dentry_to_lower(dentry);
509-
lower_dir_dentry = lock_parent(lower_dentry);
510-
rc = vfs_mkdir(&init_user_ns, d_inode(lower_dir_dentry), lower_dentry,
511-
mode);
504+
rc = lock_parent(dentry, &lower_dentry, &lower_dir);
505+
if (!rc)
506+
rc = vfs_mkdir(&init_user_ns, lower_dir,
507+
lower_dentry, mode);
512508
if (rc || d_really_is_negative(lower_dentry))
513509
goto out;
514510
rc = ecryptfs_interpose(lower_dentry, dentry, dir->i_sb);
515511
if (rc)
516512
goto out;
517-
fsstack_copy_attr_times(dir, d_inode(lower_dir_dentry));
518-
fsstack_copy_inode_size(dir, d_inode(lower_dir_dentry));
519-
set_nlink(dir, d_inode(lower_dir_dentry)->i_nlink);
513+
fsstack_copy_attr_times(dir, lower_dir);
514+
fsstack_copy_inode_size(dir, lower_dir);
515+
set_nlink(dir, lower_dir->i_nlink);
520516
out:
521-
unlock_dir(lower_dir_dentry);
517+
inode_unlock(lower_dir);
522518
if (d_really_is_negative(dentry))
523519
d_drop(dentry);
524520
return rc;
@@ -527,29 +523,24 @@ static int ecryptfs_mkdir(struct user_namespace *mnt_userns, struct inode *dir,
527523
static int ecryptfs_rmdir(struct inode *dir, struct dentry *dentry)
528524
{
529525
struct dentry *lower_dentry;
530-
struct dentry *lower_dir_dentry;
531-
struct inode *lower_dir_inode;
526+
struct inode *lower_dir;
532527
int rc;
533528

534-
lower_dentry = ecryptfs_dentry_to_lower(dentry);
535-
lower_dir_dentry = ecryptfs_dentry_to_lower(dentry->d_parent);
536-
lower_dir_inode = d_inode(lower_dir_dentry);
537-
538-
inode_lock_nested(lower_dir_inode, I_MUTEX_PARENT);
529+
rc = lock_parent(dentry, &lower_dentry, &lower_dir);
539530
dget(lower_dentry); // don't even try to make the lower negative
540-
if (lower_dentry->d_parent != lower_dir_dentry)
541-
rc = -EINVAL;
542-
else if (d_unhashed(lower_dentry))
543-
rc = -EINVAL;
544-
else
545-
rc = vfs_rmdir(&init_user_ns, lower_dir_inode, lower_dentry);
531+
if (!rc) {
532+
if (d_unhashed(lower_dentry))
533+
rc = -EINVAL;
534+
else
535+
rc = vfs_rmdir(&init_user_ns, lower_dir, lower_dentry);
536+
}
546537
if (!rc) {
547538
clear_nlink(d_inode(dentry));
548-
fsstack_copy_attr_times(dir, lower_dir_inode);
549-
set_nlink(dir, lower_dir_inode->i_nlink);
539+
fsstack_copy_attr_times(dir, lower_dir);
540+
set_nlink(dir, lower_dir->i_nlink);
550541
}
551542
dput(lower_dentry);
552-
inode_unlock(lower_dir_inode);
543+
inode_unlock(lower_dir);
553544
if (!rc)
554545
d_drop(dentry);
555546
return rc;
@@ -561,21 +552,21 @@ ecryptfs_mknod(struct user_namespace *mnt_userns, struct inode *dir,
561552
{
562553
int rc;
563554
struct dentry *lower_dentry;
564-
struct dentry *lower_dir_dentry;
555+
struct inode *lower_dir;
565556

566-
lower_dentry = ecryptfs_dentry_to_lower(dentry);
567-
lower_dir_dentry = lock_parent(lower_dentry);
568-
rc = vfs_mknod(&init_user_ns, d_inode(lower_dir_dentry), lower_dentry,
569-
mode, dev);
557+
rc = lock_parent(dentry, &lower_dentry, &lower_dir);
558+
if (!rc)
559+
rc = vfs_mknod(&init_user_ns, lower_dir,
560+
lower_dentry, mode, dev);
570561
if (rc || d_really_is_negative(lower_dentry))
571562
goto out;
572563
rc = ecryptfs_interpose(lower_dentry, dentry, dir->i_sb);
573564
if (rc)
574565
goto out;
575-
fsstack_copy_attr_times(dir, d_inode(lower_dir_dentry));
576-
fsstack_copy_inode_size(dir, d_inode(lower_dir_dentry));
566+
fsstack_copy_attr_times(dir, lower_dir);
567+
fsstack_copy_inode_size(dir, lower_dir);
577568
out:
578-
unlock_dir(lower_dir_dentry);
569+
inode_unlock(lower_dir);
579570
if (d_really_is_negative(dentry))
580571
d_drop(dentry);
581572
return rc;

0 commit comments

Comments
 (0)