aboutsummaryrefslogtreecommitdiffstats
path: root/fs
diff options
context:
space:
mode:
Diffstat (limited to 'fs')
-rw-r--r--fs/namei.c24
1 files changed, 16 insertions, 8 deletions
diff --git a/fs/namei.c b/fs/namei.c
index 6301963b161f..9e425e7e6c8f 100644
--- a/fs/namei.c
+++ b/fs/namei.c
@@ -812,6 +812,11 @@ static int follow_automount(struct path *path, unsigned flags,
812 if (!mnt) /* mount collision */ 812 if (!mnt) /* mount collision */
813 return 0; 813 return 0;
814 814
815 if (!*need_mntput) {
816 /* lock_mount() may release path->mnt on error */
817 mntget(path->mnt);
818 *need_mntput = true;
819 }
815 err = finish_automount(mnt, path); 820 err = finish_automount(mnt, path);
816 821
817 switch (err) { 822 switch (err) {
@@ -819,12 +824,9 @@ static int follow_automount(struct path *path, unsigned flags,
819 /* Someone else made a mount here whilst we were busy */ 824 /* Someone else made a mount here whilst we were busy */
820 return 0; 825 return 0;
821 case 0: 826 case 0:
822 dput(path->dentry); 827 path_put(path);
823 if (*need_mntput)
824 mntput(path->mnt);
825 path->mnt = mnt; 828 path->mnt = mnt;
826 path->dentry = dget(mnt->mnt_root); 829 path->dentry = dget(mnt->mnt_root);
827 *need_mntput = true;
828 return 0; 830 return 0;
829 default: 831 default:
830 return err; 832 return err;
@@ -844,9 +846,10 @@ static int follow_automount(struct path *path, unsigned flags,
844 */ 846 */
845static int follow_managed(struct path *path, unsigned flags) 847static int follow_managed(struct path *path, unsigned flags)
846{ 848{
849 struct vfsmount *mnt = path->mnt; /* held by caller, must be left alone */
847 unsigned managed; 850 unsigned managed;
848 bool need_mntput = false; 851 bool need_mntput = false;
849 int ret; 852 int ret = 0;
850 853
851 /* Given that we're not holding a lock here, we retain the value in a 854 /* Given that we're not holding a lock here, we retain the value in a
852 * local variable for each dentry as we look at it so that we don't see 855 * local variable for each dentry as we look at it so that we don't see
@@ -861,7 +864,7 @@ static int follow_managed(struct path *path, unsigned flags)
861 BUG_ON(!path->dentry->d_op->d_manage); 864 BUG_ON(!path->dentry->d_op->d_manage);
862 ret = path->dentry->d_op->d_manage(path->dentry, false); 865 ret = path->dentry->d_op->d_manage(path->dentry, false);
863 if (ret < 0) 866 if (ret < 0)
864 return ret == -EISDIR ? 0 : ret; 867 break;
865 } 868 }
866 869
867 /* Transit to a mounted filesystem. */ 870 /* Transit to a mounted filesystem. */
@@ -887,14 +890,19 @@ static int follow_managed(struct path *path, unsigned flags)
887 if (managed & DCACHE_NEED_AUTOMOUNT) { 890 if (managed & DCACHE_NEED_AUTOMOUNT) {
888 ret = follow_automount(path, flags, &need_mntput); 891 ret = follow_automount(path, flags, &need_mntput);
889 if (ret < 0) 892 if (ret < 0)
890 return ret == -EISDIR ? 0 : ret; 893 break;
891 continue; 894 continue;
892 } 895 }
893 896
894 /* We didn't change the current path point */ 897 /* We didn't change the current path point */
895 break; 898 break;
896 } 899 }
897 return 0; 900
901 if (need_mntput && path->mnt == mnt)
902 mntput(path->mnt);
903 if (ret == -EISDIR)
904 ret = 0;
905 return ret;
898} 906}
899 907
900int follow_down_one(struct path *path) 908int follow_down_one(struct path *path)