diff options
author | Michal Nazarewicz <m.nazarewicz@samsung.com> | 2010-05-12 06:51:13 -0400 |
---|---|---|
committer | Greg Kroah-Hartman <gregkh@suse.de> | 2010-05-20 16:21:45 -0400 |
commit | b9e000884e50bf6b25a92a3f3580e1d14fe01591 (patch) | |
tree | 05188e049219fed1cacc50f09e1d62a296d95bbe /drivers/usb/gadget | |
parent | f537da685c35a81a75f6067751bddb902c8adb68 (diff) |
USB: gadget: f_mass_storage: fix in error recovery
In to places in fsg_common_init() an unconditional call to kfree()
on common was performed in error recovery which is not a valid
behaviour since fsg_common structure is not always allocated by
fsg_common_init().
To fix, the calls has been replaced with a goto to a proper error
recovery which does the correct thing.
Also, refactored fsg_common_release() function.
Signed-off-by: Michal Nazarewicz <mina86@mina86.com>
Reviewed-by: Viral Mehta <viral.mehta@lntinfotech.com>
Signed-off-by: Greg Kroah-Hartman <gregkh@suse.de>
Diffstat (limited to 'drivers/usb/gadget')
-rw-r--r-- | drivers/usb/gadget/f_mass_storage.c | 51 |
1 files changed, 25 insertions, 26 deletions
diff --git a/drivers/usb/gadget/f_mass_storage.c b/drivers/usb/gadget/f_mass_storage.c index 6cfd2f428d38..7d05a0be5c60 100644 --- a/drivers/usb/gadget/f_mass_storage.c +++ b/drivers/usb/gadget/f_mass_storage.c | |||
@@ -2742,10 +2742,8 @@ static struct fsg_common *fsg_common_init(struct fsg_common *common, | |||
2742 | /* Maybe allocate device-global string IDs, and patch descriptors */ | 2742 | /* Maybe allocate device-global string IDs, and patch descriptors */ |
2743 | if (fsg_strings[FSG_STRING_INTERFACE].id == 0) { | 2743 | if (fsg_strings[FSG_STRING_INTERFACE].id == 0) { |
2744 | rc = usb_string_id(cdev); | 2744 | rc = usb_string_id(cdev); |
2745 | if (rc < 0) { | 2745 | if (unlikely(rc < 0)) |
2746 | kfree(common); | 2746 | goto error_release; |
2747 | return ERR_PTR(rc); | ||
2748 | } | ||
2749 | fsg_strings[FSG_STRING_INTERFACE].id = rc; | 2747 | fsg_strings[FSG_STRING_INTERFACE].id = rc; |
2750 | fsg_intf_desc.iInterface = rc; | 2748 | fsg_intf_desc.iInterface = rc; |
2751 | } | 2749 | } |
@@ -2753,9 +2751,9 @@ static struct fsg_common *fsg_common_init(struct fsg_common *common, | |||
2753 | /* Create the LUNs, open their backing files, and register the | 2751 | /* Create the LUNs, open their backing files, and register the |
2754 | * LUN devices in sysfs. */ | 2752 | * LUN devices in sysfs. */ |
2755 | curlun = kzalloc(nluns * sizeof *curlun, GFP_KERNEL); | 2753 | curlun = kzalloc(nluns * sizeof *curlun, GFP_KERNEL); |
2756 | if (!curlun) { | 2754 | if (unlikely(!curlun)) { |
2757 | kfree(common); | 2755 | rc = -ENOMEM; |
2758 | return ERR_PTR(-ENOMEM); | 2756 | goto error_release; |
2759 | } | 2757 | } |
2760 | common->luns = curlun; | 2758 | common->luns = curlun; |
2761 | 2759 | ||
@@ -2914,11 +2912,7 @@ error_release: | |||
2914 | 2912 | ||
2915 | static void fsg_common_release(struct kref *ref) | 2913 | static void fsg_common_release(struct kref *ref) |
2916 | { | 2914 | { |
2917 | struct fsg_common *common = | 2915 | struct fsg_common *common = container_of(ref, struct fsg_common, ref); |
2918 | container_of(ref, struct fsg_common, ref); | ||
2919 | unsigned i = common->nluns; | ||
2920 | struct fsg_lun *lun = common->luns; | ||
2921 | struct fsg_buffhd *bh; | ||
2922 | 2916 | ||
2923 | /* If the thread isn't already dead, tell it to exit now */ | 2917 | /* If the thread isn't already dead, tell it to exit now */ |
2924 | if (common->state != FSG_STATE_TERMINATED) { | 2918 | if (common->state != FSG_STATE_TERMINATED) { |
@@ -2929,23 +2923,28 @@ static void fsg_common_release(struct kref *ref) | |||
2929 | complete(&common->thread_notifier); | 2923 | complete(&common->thread_notifier); |
2930 | } | 2924 | } |
2931 | 2925 | ||
2932 | /* Beware tempting for -> do-while optimization: when in error | 2926 | if (likely(common->luns)) { |
2933 | * recovery nluns may be zero. */ | 2927 | struct fsg_lun *lun = common->luns; |
2928 | unsigned i = common->nluns; | ||
2934 | 2929 | ||
2935 | for (; i; --i, ++lun) { | 2930 | /* In error recovery common->nluns may be zero. */ |
2936 | device_remove_file(&lun->dev, &dev_attr_ro); | 2931 | for (; i; --i, ++lun) { |
2937 | device_remove_file(&lun->dev, &dev_attr_file); | 2932 | device_remove_file(&lun->dev, &dev_attr_ro); |
2938 | fsg_lun_close(lun); | 2933 | device_remove_file(&lun->dev, &dev_attr_file); |
2939 | device_unregister(&lun->dev); | 2934 | fsg_lun_close(lun); |
2940 | } | 2935 | device_unregister(&lun->dev); |
2936 | } | ||
2941 | 2937 | ||
2942 | kfree(common->luns); | 2938 | kfree(common->luns); |
2939 | } | ||
2943 | 2940 | ||
2944 | i = FSG_NUM_BUFFERS; | 2941 | { |
2945 | bh = common->buffhds; | 2942 | struct fsg_buffhd *bh = common->buffhds; |
2946 | do { | 2943 | unsigned i = FSG_NUM_BUFFERS; |
2947 | kfree(bh->buf); | 2944 | do { |
2948 | } while (++bh, --i); | 2945 | kfree(bh->buf); |
2946 | } while (++bh, --i); | ||
2947 | } | ||
2949 | 2948 | ||
2950 | if (common->free_storage_on_release) | 2949 | if (common->free_storage_on_release) |
2951 | kfree(common); | 2950 | kfree(common); |