]> git.karo-electronics.de Git - linux-beck.git/commitdiff
staging: lustre: obdclass: race lustre_profile_list
authorHiroya Nozaki <nozaki.hiroya@jp.fujitsu.com>
Thu, 27 Oct 2016 22:11:55 +0000 (18:11 -0400)
committerGreg Kroah-Hartman <gregkh@linuxfoundation.org>
Sun, 30 Oct 2016 15:00:12 +0000 (11:00 -0400)
Running multiple mounts at the same time results in
lustre_profile_list corruption when adding a new profile.

This patch adds a new spin_lock to protect the list and
avoid the bug

Signed-off-by: Hiroya Nozaki <nozaki.hiroya@jp.fujitsu.com>
Intel-bug-id: https://jira.hpdd.intel.com/browse/LU-6600
Reviewed-on: http://review.whamcloud.com/14896
Reviewed-by: Andreas Dilger <andreas.dilger@intel.com>
Reviewed-by: Jian Yu <jian.yu@intel.com>
Reviewed-by: Oleg Drokin <oleg.drokin@intel.com>
Signed-off-by: James Simmons <jsimmons@infradead.org>
Signed-off-by: Greg Kroah-Hartman <gregkh@linuxfoundation.org>
drivers/staging/lustre/lustre/include/obd_class.h
drivers/staging/lustre/lustre/llite/llite_lib.c
drivers/staging/lustre/lustre/obdclass/obd_config.c

index aba96c33c95e498a4b4f1a339b06eced9772010b..70b355e3b7ede768eef7d5e287329d0e82f00529 100644 (file)
@@ -176,10 +176,13 @@ struct lustre_profile {
        char        *lp_profile;
        char        *lp_dt;
        char        *lp_md;
+       int                     lp_refs;
+       bool                    lp_list_deleted;
 };
 
 struct lustre_profile *class_get_profile(const char *prof);
 void class_del_profile(const char *prof);
+void class_put_profile(struct lustre_profile *lprof);
 void class_del_profiles(void);
 
 #if LUSTRE_TRACKS_LOCK_EXP_REFS
index b896ac1ba0f0c366d966a7db5c3bd19ee1ecffed..308da0660285768ba503fe57a89db88838bac3d1 100644 (file)
@@ -929,6 +929,8 @@ int ll_fill_super(struct super_block *sb, struct vfsmount *mnt)
 out_free:
        kfree(md);
        kfree(dt);
+       if (lprof)
+               class_put_profile(lprof);
        if (err)
                ll_put_super(sb);
        else if (sbi->ll_flags & LL_SBI_VERBOSE)
index bbed1b72d52e022f22ace6ce27f3712ad378cb72..017bdac55d111058c5af3f07a289e0402db515d1 100644 (file)
@@ -585,16 +585,21 @@ static int class_del_conn(struct obd_device *obd, struct lustre_cfg *lcfg)
 }
 
 static LIST_HEAD(lustre_profile_list);
+static DEFINE_SPINLOCK(lustre_profile_list_lock);
 
 struct lustre_profile *class_get_profile(const char *prof)
 {
        struct lustre_profile *lprof;
 
+       spin_lock(&lustre_profile_list_lock);
        list_for_each_entry(lprof, &lustre_profile_list, lp_list) {
                if (!strcmp(lprof->lp_profile, prof)) {
+                       lprof->lp_refs++;
+                       spin_unlock(&lustre_profile_list_lock);
                        return lprof;
                }
        }
+       spin_unlock(&lustre_profile_list_lock);
        return NULL;
 }
 EXPORT_SYMBOL(class_get_profile);
@@ -639,7 +644,11 @@ static int class_add_profile(int proflen, char *prof, int osclen, char *osc,
                }
        }
 
+       spin_lock(&lustre_profile_list_lock);
+       lprof->lp_refs = 1;
+       lprof->lp_list_deleted = false;
        list_add(&lprof->lp_list, &lustre_profile_list);
+       spin_unlock(&lustre_profile_list_lock);
        return err;
 
 free_lp_dt:
@@ -659,27 +668,59 @@ void class_del_profile(const char *prof)
 
        lprof = class_get_profile(prof);
        if (lprof) {
+               spin_lock(&lustre_profile_list_lock);
+               /* because get profile increments the ref counter */
+               lprof->lp_refs--;
                list_del(&lprof->lp_list);
-               kfree(lprof->lp_profile);
-               kfree(lprof->lp_dt);
-               kfree(lprof->lp_md);
-               kfree(lprof);
+               lprof->lp_list_deleted = true;
+               spin_unlock(&lustre_profile_list_lock);
+
+               class_put_profile(lprof);
        }
 }
 EXPORT_SYMBOL(class_del_profile);
 
+void class_put_profile(struct lustre_profile *lprof)
+{
+       spin_lock(&lustre_profile_list_lock);
+       if (--lprof->lp_refs > 0) {
+               LASSERT(lprof->lp_refs > 0);
+               spin_unlock(&lustre_profile_list_lock);
+               return;
+       }
+       spin_unlock(&lustre_profile_list_lock);
+
+       /* confirm not a negative number */
+       LASSERT(!lprof->lp_refs);
+
+       /*
+        * At least one class_del_profile/profiles must be called
+        * on the target profile or lustre_profile_list will corrupt
+        */
+       LASSERT(lprof->lp_list_deleted);
+       kfree(lprof->lp_profile);
+       kfree(lprof->lp_dt);
+       kfree(lprof->lp_md);
+       kfree(lprof);
+}
+EXPORT_SYMBOL(class_put_profile);
+
 /* COMPAT_146 */
 void class_del_profiles(void)
 {
        struct lustre_profile *lprof, *n;
 
+       spin_lock(&lustre_profile_list_lock);
        list_for_each_entry_safe(lprof, n, &lustre_profile_list, lp_list) {
                list_del(&lprof->lp_list);
-               kfree(lprof->lp_profile);
-               kfree(lprof->lp_dt);
-               kfree(lprof->lp_md);
-               kfree(lprof);
+               lprof->lp_list_deleted = true;
+               spin_unlock(&lustre_profile_list_lock);
+
+               class_put_profile(lprof);
+
+               spin_lock(&lustre_profile_list_lock);
        }
+       spin_unlock(&lustre_profile_list_lock);
 }
 EXPORT_SYMBOL(class_del_profiles);