Fix remount races with symlink handling in affs
[safe/jmp/linux-2.6] / fs / affs / super.c
index b2a5958..be6a6e8 100644 (file)
@@ -221,8 +221,6 @@ parse_options(char *options, uid_t *uid, gid_t *gid, int *mode, int *reserved, s
                        *mount_opts |= SF_MUFS;
                        break;
                case Opt_prefix:
-                       /* Free any previous prefix */
-                       kfree(*prefix);
                        *prefix = match_strdup(&args[0]);
                        if (!*prefix)
                                return 0;
@@ -311,6 +309,7 @@ static int affs_fill_super(struct super_block *sb, void *data, int silent)
                return -ENOMEM;
        sb->s_fs_info = sbi;
        mutex_init(&sbi->s_bmlock);
+       spin_lock_init(&sbi->symlink_lock);
 
        if (!parse_options(data,&uid,&gid,&i,&reserved,&root_block,
                                &blocksize,&sbi->s_prefix,
@@ -518,14 +517,18 @@ affs_remount(struct super_block *sb, int *flags, char *data)
        unsigned long            mount_flags;
        int                      res = 0;
        char                    *new_opts = kstrdup(data, GFP_KERNEL);
+       char                     volume[32];
+       char                    *prefix = NULL;
 
        pr_debug("AFFS: remount(flags=0x%x,opts=\"%s\")\n",*flags,data);
 
        *flags |= MS_NODIRATIME;
 
+       memcpy(volume, sbi->s_volume, 32);
        if (!parse_options(data, &uid, &gid, &mode, &reserved, &root_block,
-                          &blocksize, &sbi->s_prefix, sbi->s_volume,
+                          &blocksize, &prefix, volume,
                           &mount_flags)) {
+               kfree(prefix);
                kfree(new_opts);
                return -EINVAL;
        }
@@ -536,6 +539,14 @@ affs_remount(struct super_block *sb, int *flags, char *data)
        sbi->s_mode  = mode;
        sbi->s_uid   = uid;
        sbi->s_gid   = gid;
+       /* protect against readers */
+       spin_lock(&sbi->symlink_lock);
+       if (prefix) {
+               kfree(sbi->s_prefix);
+               sbi->s_prefix = prefix;
+       }
+       memcpy(sbi->s_volume, volume, 32);
+       spin_unlock(&sbi->symlink_lock);
 
        if ((*flags & MS_RDONLY) == (sb->s_flags & MS_RDONLY)) {
                unlock_kernel();