return size;
 }
 
-/* Decomposes a single unicode character. */
-static inline u16 *decompose_unichar(wchar_t uc, int *size)
+/* Decomposes a non-Hangul unicode character. */
+static u16 *hfsplus_decompose_nonhangul(wchar_t uc, int *size)
 {
        int off;
 
        return hfsplus_decompose_table + (off / 4);
 }
 
+/*
+ * Try to decompose a unicode character as Hangul. Return 0 if @uc is not
+ * precomposed Hangul, otherwise return the length of the decomposition.
+ *
+ * This function was adapted from sample code from the Unicode Standard
+ * Annex #15: Unicode Normalization Forms, version 3.2.0.
+ *
+ * Copyright (C) 1991-2018 Unicode, Inc.  All rights reserved.  Distributed
+ * under the Terms of Use in http://www.unicode.org/copyright.html.
+ */
+static int hfsplus_try_decompose_hangul(wchar_t uc, u16 *result)
+{
+       int index;
+       int l, v, t;
+
+       index = uc - Hangul_SBase;
+       if (index < 0 || index >= Hangul_SCount)
+               return 0;
+
+       l = Hangul_LBase + index / Hangul_NCount;
+       v = Hangul_VBase + (index % Hangul_NCount) / Hangul_TCount;
+       t = Hangul_TBase + index % Hangul_TCount;
+
+       result[0] = l;
+       result[1] = v;
+       if (t != Hangul_TBase) {
+               result[2] = t;
+               return 3;
+       }
+       return 2;
+}
+
+/* Decomposes a single unicode character. */
+static u16 *decompose_unichar(wchar_t uc, int *size, u16 *hangul_buffer)
+{
+       u16 *result;
+
+       /* Hangul is handled separately */
+       result = hangul_buffer;
+       *size = hfsplus_try_decompose_hangul(uc, result);
+       if (*size == 0)
+               result = hfsplus_decompose_nonhangul(uc, size);
+       return result;
+}
+
 int hfsplus_asc2uni(struct super_block *sb,
                    struct hfsplus_unistr *ustr, int max_unistr_len,
                    const char *astr, int len)
        int size, dsize, decompose;
        u16 *dstr, outlen = 0;
        wchar_t c;
+       u16 dhangul[3];
 
        decompose = !test_bit(HFSPLUS_SB_NODECOMPOSE, &HFSPLUS_SB(sb)->flags);
        while (outlen < max_unistr_len && len > 0) {
                size = asc2unichar(sb, astr, len, &c);
 
                if (decompose)
-                       dstr = decompose_unichar(c, &dsize);
+                       dstr = decompose_unichar(c, &dsize, dhangul);
                else
                        dstr = NULL;
                if (dstr) {
        unsigned long hash;
        wchar_t c;
        u16 c2;
+       u16 dhangul[3];
 
        casefold = test_bit(HFSPLUS_SB_CASEFOLD, &HFSPLUS_SB(sb)->flags);
        decompose = !test_bit(HFSPLUS_SB_NODECOMPOSE, &HFSPLUS_SB(sb)->flags);
                len -= size;
 
                if (decompose)
-                       dstr = decompose_unichar(c, &dsize);
+                       dstr = decompose_unichar(c, &dsize, dhangul);
                else
                        dstr = NULL;
                if (dstr) {
        const char *astr1, *astr2;
        u16 c1, c2;
        wchar_t c;
+       u16 dhangul_1[3], dhangul_2[3];
 
        casefold = test_bit(HFSPLUS_SB_CASEFOLD, &HFSPLUS_SB(sb)->flags);
        decompose = !test_bit(HFSPLUS_SB_NODECOMPOSE, &HFSPLUS_SB(sb)->flags);
                        len1 -= size;
 
                        if (decompose)
-                               dstr1 = decompose_unichar(c, &dsize1);
+                               dstr1 = decompose_unichar(c, &dsize1,
+                                                         dhangul_1);
                        if (!decompose || !dstr1) {
                                c1 = c;
                                dstr1 = &c1;
                        len2 -= size;
 
                        if (decompose)
-                               dstr2 = decompose_unichar(c, &dsize2);
+                               dstr2 = decompose_unichar(c, &dsize2,
+                                                         dhangul_2);
                        if (!decompose || !dstr2) {
                                c2 = c;
                                dstr2 = &c2;