diff options
-rw-r--r-- | fs/ext4/dir.c | 48 | ||||
-rw-r--r-- | fs/ext4/ext4.h | 21 | ||||
-rw-r--r-- | fs/ext4/hash.c | 34 | ||||
-rw-r--r-- | fs/ext4/ialloc.c | 2 | ||||
-rw-r--r-- | fs/ext4/inline.c | 2 | ||||
-rw-r--r-- | fs/ext4/inode.c | 4 | ||||
-rw-r--r-- | fs/ext4/ioctl.c | 18 | ||||
-rw-r--r-- | fs/ext4/namei.c | 107 | ||||
-rw-r--r-- | fs/ext4/super.c | 6 | ||||
-rw-r--r-- | include/linux/fs.h | 2 |
10 files changed, 223 insertions, 21 deletions
diff --git a/fs/ext4/dir.c b/fs/ext4/dir.c index 0ccd51f72048..884a6e776809 100644 --- a/fs/ext4/dir.c +++ b/fs/ext4/dir.c | |||
@@ -26,6 +26,7 @@ | |||
26 | #include <linux/buffer_head.h> | 26 | #include <linux/buffer_head.h> |
27 | #include <linux/slab.h> | 27 | #include <linux/slab.h> |
28 | #include <linux/iversion.h> | 28 | #include <linux/iversion.h> |
29 | #include <linux/unicode.h> | ||
29 | #include "ext4.h" | 30 | #include "ext4.h" |
30 | #include "xattr.h" | 31 | #include "xattr.h" |
31 | 32 | ||
@@ -660,3 +661,50 @@ const struct file_operations ext4_dir_operations = { | |||
660 | .open = ext4_dir_open, | 661 | .open = ext4_dir_open, |
661 | .release = ext4_release_dir, | 662 | .release = ext4_release_dir, |
662 | }; | 663 | }; |
664 | |||
665 | #ifdef CONFIG_UNICODE | ||
666 | static int ext4_d_compare(const struct dentry *dentry, unsigned int len, | ||
667 | const char *str, const struct qstr *name) | ||
668 | { | ||
669 | struct qstr qstr = {.name = str, .len = len }; | ||
670 | |||
671 | if (!IS_CASEFOLDED(dentry->d_parent->d_inode)) { | ||
672 | if (len != name->len) | ||
673 | return -1; | ||
674 | return !memcmp(str, name, len); | ||
675 | } | ||
676 | |||
677 | return ext4_ci_compare(dentry->d_parent->d_inode, name, &qstr); | ||
678 | } | ||
679 | |||
680 | static int ext4_d_hash(const struct dentry *dentry, struct qstr *str) | ||
681 | { | ||
682 | const struct ext4_sb_info *sbi = EXT4_SB(dentry->d_sb); | ||
683 | const struct unicode_map *um = sbi->s_encoding; | ||
684 | unsigned char *norm; | ||
685 | int len, ret = 0; | ||
686 | |||
687 | if (!IS_CASEFOLDED(dentry->d_inode)) | ||
688 | return 0; | ||
689 | |||
690 | norm = kmalloc(PATH_MAX, GFP_ATOMIC); | ||
691 | if (!norm) | ||
692 | return -ENOMEM; | ||
693 | |||
694 | len = utf8_casefold(um, str, norm, PATH_MAX); | ||
695 | if (len < 0) { | ||
696 | if (ext4_has_strict_mode(sbi)) | ||
697 | ret = -EINVAL; | ||
698 | goto out; | ||
699 | } | ||
700 | str->hash = full_name_hash(dentry, norm, len); | ||
701 | out: | ||
702 | kfree(norm); | ||
703 | return ret; | ||
704 | } | ||
705 | |||
706 | const struct dentry_operations ext4_dentry_ops = { | ||
707 | .d_hash = ext4_d_hash, | ||
708 | .d_compare = ext4_d_compare, | ||
709 | }; | ||
710 | #endif | ||
diff --git a/fs/ext4/ext4.h b/fs/ext4/ext4.h index c1504c471fef..c18ab748d20d 100644 --- a/fs/ext4/ext4.h +++ b/fs/ext4/ext4.h | |||
@@ -399,10 +399,11 @@ struct flex_groups { | |||
399 | #define EXT4_EOFBLOCKS_FL 0x00400000 /* Blocks allocated beyond EOF */ | 399 | #define EXT4_EOFBLOCKS_FL 0x00400000 /* Blocks allocated beyond EOF */ |
400 | #define EXT4_INLINE_DATA_FL 0x10000000 /* Inode has inline data. */ | 400 | #define EXT4_INLINE_DATA_FL 0x10000000 /* Inode has inline data. */ |
401 | #define EXT4_PROJINHERIT_FL 0x20000000 /* Create with parents projid */ | 401 | #define EXT4_PROJINHERIT_FL 0x20000000 /* Create with parents projid */ |
402 | #define EXT4_CASEFOLD_FL 0x40000000 /* Casefolded file */ | ||
402 | #define EXT4_RESERVED_FL 0x80000000 /* reserved for ext4 lib */ | 403 | #define EXT4_RESERVED_FL 0x80000000 /* reserved for ext4 lib */ |
403 | 404 | ||
404 | #define EXT4_FL_USER_VISIBLE 0x304BDFFF /* User visible flags */ | 405 | #define EXT4_FL_USER_VISIBLE 0x704BDFFF /* User visible flags */ |
405 | #define EXT4_FL_USER_MODIFIABLE 0x204BC0FF /* User modifiable flags */ | 406 | #define EXT4_FL_USER_MODIFIABLE 0x604BC0FF /* User modifiable flags */ |
406 | 407 | ||
407 | /* Flags we can manipulate with through EXT4_IOC_FSSETXATTR */ | 408 | /* Flags we can manipulate with through EXT4_IOC_FSSETXATTR */ |
408 | #define EXT4_FL_XFLAG_VISIBLE (EXT4_SYNC_FL | \ | 409 | #define EXT4_FL_XFLAG_VISIBLE (EXT4_SYNC_FL | \ |
@@ -417,10 +418,10 @@ struct flex_groups { | |||
417 | EXT4_SYNC_FL | EXT4_NODUMP_FL | EXT4_NOATIME_FL |\ | 418 | EXT4_SYNC_FL | EXT4_NODUMP_FL | EXT4_NOATIME_FL |\ |
418 | EXT4_NOCOMPR_FL | EXT4_JOURNAL_DATA_FL |\ | 419 | EXT4_NOCOMPR_FL | EXT4_JOURNAL_DATA_FL |\ |
419 | EXT4_NOTAIL_FL | EXT4_DIRSYNC_FL |\ | 420 | EXT4_NOTAIL_FL | EXT4_DIRSYNC_FL |\ |
420 | EXT4_PROJINHERIT_FL) | 421 | EXT4_PROJINHERIT_FL | EXT4_CASEFOLD_FL) |
421 | 422 | ||
422 | /* Flags that are appropriate for regular files (all but dir-specific ones). */ | 423 | /* Flags that are appropriate for regular files (all but dir-specific ones). */ |
423 | #define EXT4_REG_FLMASK (~(EXT4_DIRSYNC_FL | EXT4_TOPDIR_FL)) | 424 | #define EXT4_REG_FLMASK (~(EXT4_DIRSYNC_FL | EXT4_TOPDIR_FL | EXT4_CASEFOLD_FL)) |
424 | 425 | ||
425 | /* Flags that are appropriate for non-directories/regular files. */ | 426 | /* Flags that are appropriate for non-directories/regular files. */ |
426 | #define EXT4_OTHER_FLMASK (EXT4_NODUMP_FL | EXT4_NOATIME_FL) | 427 | #define EXT4_OTHER_FLMASK (EXT4_NODUMP_FL | EXT4_NOATIME_FL) |
@@ -2393,8 +2394,8 @@ extern int ext4_check_all_de(struct inode *dir, struct buffer_head *bh, | |||
2393 | extern int ext4_sync_file(struct file *, loff_t, loff_t, int); | 2394 | extern int ext4_sync_file(struct file *, loff_t, loff_t, int); |
2394 | 2395 | ||
2395 | /* hash.c */ | 2396 | /* hash.c */ |
2396 | extern int ext4fs_dirhash(const char *name, int len, struct | 2397 | extern int ext4fs_dirhash(const struct inode *dir, const char *name, int len, |
2397 | dx_hash_info *hinfo); | 2398 | struct dx_hash_info *hinfo); |
2398 | 2399 | ||
2399 | /* ialloc.c */ | 2400 | /* ialloc.c */ |
2400 | extern struct inode *__ext4_new_inode(handle_t *, struct inode *, umode_t, | 2401 | extern struct inode *__ext4_new_inode(handle_t *, struct inode *, umode_t, |
@@ -2990,6 +2991,10 @@ static inline void ext4_unlock_group(struct super_block *sb, | |||
2990 | /* dir.c */ | 2991 | /* dir.c */ |
2991 | extern const struct file_operations ext4_dir_operations; | 2992 | extern const struct file_operations ext4_dir_operations; |
2992 | 2993 | ||
2994 | #ifdef CONFIG_UNICODE | ||
2995 | extern const struct dentry_operations ext4_dentry_ops; | ||
2996 | #endif | ||
2997 | |||
2993 | /* file.c */ | 2998 | /* file.c */ |
2994 | extern const struct inode_operations ext4_file_inode_operations; | 2999 | extern const struct inode_operations ext4_file_inode_operations; |
2995 | extern const struct file_operations ext4_file_operations; | 3000 | extern const struct file_operations ext4_file_operations; |
@@ -3082,6 +3087,10 @@ extern void initialize_dirent_tail(struct ext4_dir_entry_tail *t, | |||
3082 | extern int ext4_handle_dirty_dirent_node(handle_t *handle, | 3087 | extern int ext4_handle_dirty_dirent_node(handle_t *handle, |
3083 | struct inode *inode, | 3088 | struct inode *inode, |
3084 | struct buffer_head *bh); | 3089 | struct buffer_head *bh); |
3090 | extern int ext4_ci_compare(const struct inode *parent, | ||
3091 | const struct qstr *name, | ||
3092 | const struct qstr *entry); | ||
3093 | |||
3085 | #define S_SHIFT 12 | 3094 | #define S_SHIFT 12 |
3086 | static const unsigned char ext4_type_by_mode[(S_IFMT >> S_SHIFT) + 1] = { | 3095 | static const unsigned char ext4_type_by_mode[(S_IFMT >> S_SHIFT) + 1] = { |
3087 | [S_IFREG >> S_SHIFT] = EXT4_FT_REG_FILE, | 3096 | [S_IFREG >> S_SHIFT] = EXT4_FT_REG_FILE, |
diff --git a/fs/ext4/hash.c b/fs/ext4/hash.c index 46b24da33a28..d358bfcb6b3f 100644 --- a/fs/ext4/hash.c +++ b/fs/ext4/hash.c | |||
@@ -6,6 +6,7 @@ | |||
6 | */ | 6 | */ |
7 | 7 | ||
8 | #include <linux/fs.h> | 8 | #include <linux/fs.h> |
9 | #include <linux/unicode.h> | ||
9 | #include <linux/compiler.h> | 10 | #include <linux/compiler.h> |
10 | #include <linux/bitops.h> | 11 | #include <linux/bitops.h> |
11 | #include "ext4.h" | 12 | #include "ext4.h" |
@@ -196,7 +197,8 @@ static void str2hashbuf_unsigned(const char *msg, int len, __u32 *buf, int num) | |||
196 | * represented, and whether or not the returned hash is 32 bits or 64 | 197 | * represented, and whether or not the returned hash is 32 bits or 64 |
197 | * bits. 32 bit hashes will return 0 for the minor hash. | 198 | * bits. 32 bit hashes will return 0 for the minor hash. |
198 | */ | 199 | */ |
199 | int ext4fs_dirhash(const char *name, int len, struct dx_hash_info *hinfo) | 200 | static int __ext4fs_dirhash(const char *name, int len, |
201 | struct dx_hash_info *hinfo) | ||
200 | { | 202 | { |
201 | __u32 hash; | 203 | __u32 hash; |
202 | __u32 minor_hash = 0; | 204 | __u32 minor_hash = 0; |
@@ -268,3 +270,33 @@ int ext4fs_dirhash(const char *name, int len, struct dx_hash_info *hinfo) | |||
268 | hinfo->minor_hash = minor_hash; | 270 | hinfo->minor_hash = minor_hash; |
269 | return 0; | 271 | return 0; |
270 | } | 272 | } |
273 | |||
274 | int ext4fs_dirhash(const struct inode *dir, const char *name, int len, | ||
275 | struct dx_hash_info *hinfo) | ||
276 | { | ||
277 | #ifdef CONFIG_UNICODE | ||
278 | const struct unicode_map *um = EXT4_SB(dir->i_sb)->s_encoding; | ||
279 | int r, dlen; | ||
280 | unsigned char *buff; | ||
281 | struct qstr qstr = {.name = name, .len = len }; | ||
282 | |||
283 | if (len && IS_CASEFOLDED(dir)) { | ||
284 | buff = kzalloc(sizeof(char) * PATH_MAX, GFP_KERNEL); | ||
285 | if (!buff) | ||
286 | return -ENOMEM; | ||
287 | |||
288 | dlen = utf8_casefold(um, &qstr, buff, PATH_MAX); | ||
289 | if (dlen < 0) { | ||
290 | kfree(buff); | ||
291 | goto opaque_seq; | ||
292 | } | ||
293 | |||
294 | r = __ext4fs_dirhash(buff, dlen, hinfo); | ||
295 | |||
296 | kfree(buff); | ||
297 | return r; | ||
298 | } | ||
299 | opaque_seq: | ||
300 | #endif | ||
301 | return __ext4fs_dirhash(name, len, hinfo); | ||
302 | } | ||
diff --git a/fs/ext4/ialloc.c b/fs/ext4/ialloc.c index f3e17a8c84b4..764ff4c56233 100644 --- a/fs/ext4/ialloc.c +++ b/fs/ext4/ialloc.c | |||
@@ -455,7 +455,7 @@ static int find_group_orlov(struct super_block *sb, struct inode *parent, | |||
455 | if (qstr) { | 455 | if (qstr) { |
456 | hinfo.hash_version = DX_HASH_HALF_MD4; | 456 | hinfo.hash_version = DX_HASH_HALF_MD4; |
457 | hinfo.seed = sbi->s_hash_seed; | 457 | hinfo.seed = sbi->s_hash_seed; |
458 | ext4fs_dirhash(qstr->name, qstr->len, &hinfo); | 458 | ext4fs_dirhash(parent, qstr->name, qstr->len, &hinfo); |
459 | grp = hinfo.hash; | 459 | grp = hinfo.hash; |
460 | } else | 460 | } else |
461 | grp = prandom_u32(); | 461 | grp = prandom_u32(); |
diff --git a/fs/ext4/inline.c b/fs/ext4/inline.c index 56f6e1782d5f..f73bc3925282 100644 --- a/fs/ext4/inline.c +++ b/fs/ext4/inline.c | |||
@@ -1407,7 +1407,7 @@ int htree_inlinedir_to_tree(struct file *dir_file, | |||
1407 | } | 1407 | } |
1408 | } | 1408 | } |
1409 | 1409 | ||
1410 | ext4fs_dirhash(de->name, de->name_len, hinfo); | 1410 | ext4fs_dirhash(dir, de->name, de->name_len, hinfo); |
1411 | if ((hinfo->hash < start_hash) || | 1411 | if ((hinfo->hash < start_hash) || |
1412 | ((hinfo->hash == start_hash) && | 1412 | ((hinfo->hash == start_hash) && |
1413 | (hinfo->minor_hash < start_minor_hash))) | 1413 | (hinfo->minor_hash < start_minor_hash))) |
diff --git a/fs/ext4/inode.c b/fs/ext4/inode.c index 609c8366d029..82298c63ea6d 100644 --- a/fs/ext4/inode.c +++ b/fs/ext4/inode.c | |||
@@ -4742,9 +4742,11 @@ void ext4_set_inode_flags(struct inode *inode) | |||
4742 | new_fl |= S_DAX; | 4742 | new_fl |= S_DAX; |
4743 | if (flags & EXT4_ENCRYPT_FL) | 4743 | if (flags & EXT4_ENCRYPT_FL) |
4744 | new_fl |= S_ENCRYPTED; | 4744 | new_fl |= S_ENCRYPTED; |
4745 | if (flags & EXT4_CASEFOLD_FL) | ||
4746 | new_fl |= S_CASEFOLD; | ||
4745 | inode_set_flags(inode, new_fl, | 4747 | inode_set_flags(inode, new_fl, |
4746 | S_SYNC|S_APPEND|S_IMMUTABLE|S_NOATIME|S_DIRSYNC|S_DAX| | 4748 | S_SYNC|S_APPEND|S_IMMUTABLE|S_NOATIME|S_DIRSYNC|S_DAX| |
4747 | S_ENCRYPTED); | 4749 | S_ENCRYPTED|S_CASEFOLD); |
4748 | } | 4750 | } |
4749 | 4751 | ||
4750 | static blkcnt_t ext4_inode_blocks(struct ext4_inode *raw_inode, | 4752 | static blkcnt_t ext4_inode_blocks(struct ext4_inode *raw_inode, |
diff --git a/fs/ext4/ioctl.c b/fs/ext4/ioctl.c index 20faa6a69238..7e85ecf0b849 100644 --- a/fs/ext4/ioctl.c +++ b/fs/ext4/ioctl.c | |||
@@ -278,6 +278,7 @@ static int ext4_ioctl_setflags(struct inode *inode, | |||
278 | struct ext4_iloc iloc; | 278 | struct ext4_iloc iloc; |
279 | unsigned int oldflags, mask, i; | 279 | unsigned int oldflags, mask, i; |
280 | unsigned int jflag; | 280 | unsigned int jflag; |
281 | struct super_block *sb = inode->i_sb; | ||
281 | 282 | ||
282 | /* Is it quota file? Do not allow user to mess with it */ | 283 | /* Is it quota file? Do not allow user to mess with it */ |
283 | if (ext4_is_quota_file(inode)) | 284 | if (ext4_is_quota_file(inode)) |
@@ -322,6 +323,23 @@ static int ext4_ioctl_setflags(struct inode *inode, | |||
322 | goto flags_out; | 323 | goto flags_out; |
323 | } | 324 | } |
324 | 325 | ||
326 | if ((flags ^ oldflags) & EXT4_CASEFOLD_FL) { | ||
327 | if (!ext4_has_feature_casefold(sb)) { | ||
328 | err = -EOPNOTSUPP; | ||
329 | goto flags_out; | ||
330 | } | ||
331 | |||
332 | if (!S_ISDIR(inode->i_mode)) { | ||
333 | err = -ENOTDIR; | ||
334 | goto flags_out; | ||
335 | } | ||
336 | |||
337 | if (!ext4_empty_dir(inode)) { | ||
338 | err = -ENOTEMPTY; | ||
339 | goto flags_out; | ||
340 | } | ||
341 | } | ||
342 | |||
325 | handle = ext4_journal_start(inode, EXT4_HT_INODE, 1); | 343 | handle = ext4_journal_start(inode, EXT4_HT_INODE, 1); |
326 | if (IS_ERR(handle)) { | 344 | if (IS_ERR(handle)) { |
327 | err = PTR_ERR(handle); | 345 | err = PTR_ERR(handle); |
diff --git a/fs/ext4/namei.c b/fs/ext4/namei.c index 980166a8122a..e917830eae84 100644 --- a/fs/ext4/namei.c +++ b/fs/ext4/namei.c | |||
@@ -35,6 +35,7 @@ | |||
35 | #include <linux/buffer_head.h> | 35 | #include <linux/buffer_head.h> |
36 | #include <linux/bio.h> | 36 | #include <linux/bio.h> |
37 | #include <linux/iversion.h> | 37 | #include <linux/iversion.h> |
38 | #include <linux/unicode.h> | ||
38 | #include "ext4.h" | 39 | #include "ext4.h" |
39 | #include "ext4_jbd2.h" | 40 | #include "ext4_jbd2.h" |
40 | 41 | ||
@@ -629,7 +630,7 @@ static struct stats dx_show_leaf(struct inode *dir, | |||
629 | } | 630 | } |
630 | if (!fscrypt_has_encryption_key(dir)) { | 631 | if (!fscrypt_has_encryption_key(dir)) { |
631 | /* Directory is not encrypted */ | 632 | /* Directory is not encrypted */ |
632 | ext4fs_dirhash(de->name, | 633 | ext4fs_dirhash(dir, de->name, |
633 | de->name_len, &h); | 634 | de->name_len, &h); |
634 | printk("%*.s:(U)%x.%u ", len, | 635 | printk("%*.s:(U)%x.%u ", len, |
635 | name, h.hash, | 636 | name, h.hash, |
@@ -662,8 +663,8 @@ static struct stats dx_show_leaf(struct inode *dir, | |||
662 | name = fname_crypto_str.name; | 663 | name = fname_crypto_str.name; |
663 | len = fname_crypto_str.len; | 664 | len = fname_crypto_str.len; |
664 | } | 665 | } |
665 | ext4fs_dirhash(de->name, de->name_len, | 666 | ext4fs_dirhash(dir, de->name, |
666 | &h); | 667 | de->name_len, &h); |
667 | printk("%*.s:(E)%x.%u ", len, name, | 668 | printk("%*.s:(E)%x.%u ", len, name, |
668 | h.hash, (unsigned) ((char *) de | 669 | h.hash, (unsigned) ((char *) de |
669 | - base)); | 670 | - base)); |
@@ -673,7 +674,7 @@ static struct stats dx_show_leaf(struct inode *dir, | |||
673 | #else | 674 | #else |
674 | int len = de->name_len; | 675 | int len = de->name_len; |
675 | char *name = de->name; | 676 | char *name = de->name; |
676 | ext4fs_dirhash(de->name, de->name_len, &h); | 677 | ext4fs_dirhash(dir, de->name, de->name_len, &h); |
677 | printk("%*.s:%x.%u ", len, name, h.hash, | 678 | printk("%*.s:%x.%u ", len, name, h.hash, |
678 | (unsigned) ((char *) de - base)); | 679 | (unsigned) ((char *) de - base)); |
679 | #endif | 680 | #endif |
@@ -762,7 +763,7 @@ dx_probe(struct ext4_filename *fname, struct inode *dir, | |||
762 | hinfo->hash_version += EXT4_SB(dir->i_sb)->s_hash_unsigned; | 763 | hinfo->hash_version += EXT4_SB(dir->i_sb)->s_hash_unsigned; |
763 | hinfo->seed = EXT4_SB(dir->i_sb)->s_hash_seed; | 764 | hinfo->seed = EXT4_SB(dir->i_sb)->s_hash_seed; |
764 | if (fname && fname_name(fname)) | 765 | if (fname && fname_name(fname)) |
765 | ext4fs_dirhash(fname_name(fname), fname_len(fname), hinfo); | 766 | ext4fs_dirhash(dir, fname_name(fname), fname_len(fname), hinfo); |
766 | hash = hinfo->hash; | 767 | hash = hinfo->hash; |
767 | 768 | ||
768 | if (root->info.unused_flags & 1) { | 769 | if (root->info.unused_flags & 1) { |
@@ -1008,7 +1009,7 @@ static int htree_dirblock_to_tree(struct file *dir_file, | |||
1008 | /* silently ignore the rest of the block */ | 1009 | /* silently ignore the rest of the block */ |
1009 | break; | 1010 | break; |
1010 | } | 1011 | } |
1011 | ext4fs_dirhash(de->name, de->name_len, hinfo); | 1012 | ext4fs_dirhash(dir, de->name, de->name_len, hinfo); |
1012 | if ((hinfo->hash < start_hash) || | 1013 | if ((hinfo->hash < start_hash) || |
1013 | ((hinfo->hash == start_hash) && | 1014 | ((hinfo->hash == start_hash) && |
1014 | (hinfo->minor_hash < start_minor_hash))) | 1015 | (hinfo->minor_hash < start_minor_hash))) |
@@ -1197,7 +1198,7 @@ static int dx_make_map(struct inode *dir, struct ext4_dir_entry_2 *de, | |||
1197 | 1198 | ||
1198 | while ((char *) de < base + blocksize) { | 1199 | while ((char *) de < base + blocksize) { |
1199 | if (de->name_len && de->inode) { | 1200 | if (de->name_len && de->inode) { |
1200 | ext4fs_dirhash(de->name, de->name_len, &h); | 1201 | ext4fs_dirhash(dir, de->name, de->name_len, &h); |
1201 | map_tail--; | 1202 | map_tail--; |
1202 | map_tail->hash = h.hash; | 1203 | map_tail->hash = h.hash; |
1203 | map_tail->offs = ((char *) de - base)>>2; | 1204 | map_tail->offs = ((char *) de - base)>>2; |
@@ -1252,15 +1253,52 @@ static void dx_insert_block(struct dx_frame *frame, u32 hash, ext4_lblk_t block) | |||
1252 | dx_set_count(entries, count + 1); | 1253 | dx_set_count(entries, count + 1); |
1253 | } | 1254 | } |
1254 | 1255 | ||
1256 | #ifdef CONFIG_UNICODE | ||
1257 | /* | ||
1258 | * Test whether a case-insensitive directory entry matches the filename | ||
1259 | * being searched for. | ||
1260 | * | ||
1261 | * Returns: 0 if the directory entry matches, more than 0 if it | ||
1262 | * doesn't match or less than zero on error. | ||
1263 | */ | ||
1264 | int ext4_ci_compare(const struct inode *parent, const struct qstr *name, | ||
1265 | const struct qstr *entry) | ||
1266 | { | ||
1267 | const struct ext4_sb_info *sbi = EXT4_SB(parent->i_sb); | ||
1268 | const struct unicode_map *um = sbi->s_encoding; | ||
1269 | int ret; | ||
1270 | |||
1271 | ret = utf8_strncasecmp(um, name, entry); | ||
1272 | if (ret < 0) { | ||
1273 | /* Handle invalid character sequence as either an error | ||
1274 | * or as an opaque byte sequence. | ||
1275 | */ | ||
1276 | if (ext4_has_strict_mode(sbi)) | ||
1277 | return -EINVAL; | ||
1278 | |||
1279 | if (name->len != entry->len) | ||
1280 | return 1; | ||
1281 | |||
1282 | return !!memcmp(name->name, entry->name, name->len); | ||
1283 | } | ||
1284 | |||
1285 | return ret; | ||
1286 | } | ||
1287 | #endif | ||
1288 | |||
1255 | /* | 1289 | /* |
1256 | * Test whether a directory entry matches the filename being searched for. | 1290 | * Test whether a directory entry matches the filename being searched for. |
1257 | * | 1291 | * |
1258 | * Return: %true if the directory entry matches, otherwise %false. | 1292 | * Return: %true if the directory entry matches, otherwise %false. |
1259 | */ | 1293 | */ |
1260 | static inline bool ext4_match(const struct ext4_filename *fname, | 1294 | static inline bool ext4_match(const struct inode *parent, |
1295 | const struct ext4_filename *fname, | ||
1261 | const struct ext4_dir_entry_2 *de) | 1296 | const struct ext4_dir_entry_2 *de) |
1262 | { | 1297 | { |
1263 | struct fscrypt_name f; | 1298 | struct fscrypt_name f; |
1299 | #ifdef CONFIG_UNICODE | ||
1300 | const struct qstr entry = {.name = de->name, .len = de->name_len}; | ||
1301 | #endif | ||
1264 | 1302 | ||
1265 | if (!de->inode) | 1303 | if (!de->inode) |
1266 | return false; | 1304 | return false; |
@@ -1270,6 +1308,12 @@ static inline bool ext4_match(const struct ext4_filename *fname, | |||
1270 | #ifdef CONFIG_FS_ENCRYPTION | 1308 | #ifdef CONFIG_FS_ENCRYPTION |
1271 | f.crypto_buf = fname->crypto_buf; | 1309 | f.crypto_buf = fname->crypto_buf; |
1272 | #endif | 1310 | #endif |
1311 | |||
1312 | #ifdef CONFIG_UNICODE | ||
1313 | if (EXT4_SB(parent->i_sb)->s_encoding && IS_CASEFOLDED(parent)) | ||
1314 | return (ext4_ci_compare(parent, fname->usr_fname, &entry) == 0); | ||
1315 | #endif | ||
1316 | |||
1273 | return fscrypt_match_name(&f, de->name, de->name_len); | 1317 | return fscrypt_match_name(&f, de->name, de->name_len); |
1274 | } | 1318 | } |
1275 | 1319 | ||
@@ -1290,7 +1334,7 @@ int ext4_search_dir(struct buffer_head *bh, char *search_buf, int buf_size, | |||
1290 | /* this code is executed quadratically often */ | 1334 | /* this code is executed quadratically often */ |
1291 | /* do minimal checking `by hand' */ | 1335 | /* do minimal checking `by hand' */ |
1292 | if ((char *) de + de->name_len <= dlimit && | 1336 | if ((char *) de + de->name_len <= dlimit && |
1293 | ext4_match(fname, de)) { | 1337 | ext4_match(dir, fname, de)) { |
1294 | /* found a match - just to be sure, do | 1338 | /* found a match - just to be sure, do |
1295 | * a full check */ | 1339 | * a full check */ |
1296 | if (ext4_check_dir_entry(dir, NULL, de, bh, bh->b_data, | 1340 | if (ext4_check_dir_entry(dir, NULL, de, bh, bh->b_data, |
@@ -1588,6 +1632,17 @@ static struct dentry *ext4_lookup(struct inode *dir, struct dentry *dentry, unsi | |||
1588 | return ERR_PTR(-EPERM); | 1632 | return ERR_PTR(-EPERM); |
1589 | } | 1633 | } |
1590 | } | 1634 | } |
1635 | |||
1636 | #ifdef CONFIG_UNICODE | ||
1637 | if (!inode && IS_CASEFOLDED(dir)) { | ||
1638 | /* Eventually we want to call d_add_ci(dentry, NULL) | ||
1639 | * for negative dentries in the encoding case as | ||
1640 | * well. For now, prevent the negative dentry | ||
1641 | * from being cached. | ||
1642 | */ | ||
1643 | return NULL; | ||
1644 | } | ||
1645 | #endif | ||
1591 | return d_splice_alias(inode, dentry); | 1646 | return d_splice_alias(inode, dentry); |
1592 | } | 1647 | } |
1593 | 1648 | ||
@@ -1798,7 +1853,7 @@ int ext4_find_dest_de(struct inode *dir, struct inode *inode, | |||
1798 | if (ext4_check_dir_entry(dir, NULL, de, bh, | 1853 | if (ext4_check_dir_entry(dir, NULL, de, bh, |
1799 | buf, buf_size, offset)) | 1854 | buf, buf_size, offset)) |
1800 | return -EFSCORRUPTED; | 1855 | return -EFSCORRUPTED; |
1801 | if (ext4_match(fname, de)) | 1856 | if (ext4_match(dir, fname, de)) |
1802 | return -EEXIST; | 1857 | return -EEXIST; |
1803 | nlen = EXT4_DIR_REC_LEN(de->name_len); | 1858 | nlen = EXT4_DIR_REC_LEN(de->name_len); |
1804 | rlen = ext4_rec_len_from_disk(de->rec_len, buf_size); | 1859 | rlen = ext4_rec_len_from_disk(de->rec_len, buf_size); |
@@ -1983,7 +2038,7 @@ static int make_indexed_dir(handle_t *handle, struct ext4_filename *fname, | |||
1983 | if (fname->hinfo.hash_version <= DX_HASH_TEA) | 2038 | if (fname->hinfo.hash_version <= DX_HASH_TEA) |
1984 | fname->hinfo.hash_version += EXT4_SB(dir->i_sb)->s_hash_unsigned; | 2039 | fname->hinfo.hash_version += EXT4_SB(dir->i_sb)->s_hash_unsigned; |
1985 | fname->hinfo.seed = EXT4_SB(dir->i_sb)->s_hash_seed; | 2040 | fname->hinfo.seed = EXT4_SB(dir->i_sb)->s_hash_seed; |
1986 | ext4fs_dirhash(fname_name(fname), fname_len(fname), &fname->hinfo); | 2041 | ext4fs_dirhash(dir, fname_name(fname), fname_len(fname), &fname->hinfo); |
1987 | 2042 | ||
1988 | memset(frames, 0, sizeof(frames)); | 2043 | memset(frames, 0, sizeof(frames)); |
1989 | frame = frames; | 2044 | frame = frames; |
@@ -2036,6 +2091,7 @@ static int ext4_add_entry(handle_t *handle, struct dentry *dentry, | |||
2036 | struct ext4_dir_entry_2 *de; | 2091 | struct ext4_dir_entry_2 *de; |
2037 | struct ext4_dir_entry_tail *t; | 2092 | struct ext4_dir_entry_tail *t; |
2038 | struct super_block *sb; | 2093 | struct super_block *sb; |
2094 | struct ext4_sb_info *sbi; | ||
2039 | struct ext4_filename fname; | 2095 | struct ext4_filename fname; |
2040 | int retval; | 2096 | int retval; |
2041 | int dx_fallback=0; | 2097 | int dx_fallback=0; |
@@ -2047,10 +2103,17 @@ static int ext4_add_entry(handle_t *handle, struct dentry *dentry, | |||
2047 | csum_size = sizeof(struct ext4_dir_entry_tail); | 2103 | csum_size = sizeof(struct ext4_dir_entry_tail); |
2048 | 2104 | ||
2049 | sb = dir->i_sb; | 2105 | sb = dir->i_sb; |
2106 | sbi = EXT4_SB(sb); | ||
2050 | blocksize = sb->s_blocksize; | 2107 | blocksize = sb->s_blocksize; |
2051 | if (!dentry->d_name.len) | 2108 | if (!dentry->d_name.len) |
2052 | return -EINVAL; | 2109 | return -EINVAL; |
2053 | 2110 | ||
2111 | #ifdef CONFIG_UNICODE | ||
2112 | if (ext4_has_strict_mode(sbi) && IS_CASEFOLDED(dir) && | ||
2113 | utf8_validate(sbi->s_encoding, &dentry->d_name)) | ||
2114 | return -EINVAL; | ||
2115 | #endif | ||
2116 | |||
2054 | retval = ext4_fname_setup_filename(dir, &dentry->d_name, 0, &fname); | 2117 | retval = ext4_fname_setup_filename(dir, &dentry->d_name, 0, &fname); |
2055 | if (retval) | 2118 | if (retval) |
2056 | return retval; | 2119 | return retval; |
@@ -2975,6 +3038,17 @@ static int ext4_rmdir(struct inode *dir, struct dentry *dentry) | |||
2975 | ext4_update_dx_flag(dir); | 3038 | ext4_update_dx_flag(dir); |
2976 | ext4_mark_inode_dirty(handle, dir); | 3039 | ext4_mark_inode_dirty(handle, dir); |
2977 | 3040 | ||
3041 | #ifdef CONFIG_UNICODE | ||
3042 | /* VFS negative dentries are incompatible with Encoding and | ||
3043 | * Case-insensitiveness. Eventually we'll want avoid | ||
3044 | * invalidating the dentries here, alongside with returning the | ||
3045 | * negative dentries at ext4_lookup(), when it is better | ||
3046 | * supported by the VFS for the CI case. | ||
3047 | */ | ||
3048 | if (IS_CASEFOLDED(dir)) | ||
3049 | d_invalidate(dentry); | ||
3050 | #endif | ||
3051 | |||
2978 | end_rmdir: | 3052 | end_rmdir: |
2979 | brelse(bh); | 3053 | brelse(bh); |
2980 | if (handle) | 3054 | if (handle) |
@@ -3044,6 +3118,17 @@ static int ext4_unlink(struct inode *dir, struct dentry *dentry) | |||
3044 | inode->i_ctime = current_time(inode); | 3118 | inode->i_ctime = current_time(inode); |
3045 | ext4_mark_inode_dirty(handle, inode); | 3119 | ext4_mark_inode_dirty(handle, inode); |
3046 | 3120 | ||
3121 | #ifdef CONFIG_UNICODE | ||
3122 | /* VFS negative dentries are incompatible with Encoding and | ||
3123 | * Case-insensitiveness. Eventually we'll want avoid | ||
3124 | * invalidating the dentries here, alongside with returning the | ||
3125 | * negative dentries at ext4_lookup(), when it is better | ||
3126 | * supported by the VFS for the CI case. | ||
3127 | */ | ||
3128 | if (IS_CASEFOLDED(dir)) | ||
3129 | d_invalidate(dentry); | ||
3130 | #endif | ||
3131 | |||
3047 | end_unlink: | 3132 | end_unlink: |
3048 | brelse(bh); | 3133 | brelse(bh); |
3049 | if (handle) | 3134 | if (handle) |
diff --git a/fs/ext4/super.c b/fs/ext4/super.c index c1b02c3a5a68..aeb6d22ea0ad 100644 --- a/fs/ext4/super.c +++ b/fs/ext4/super.c | |||
@@ -4484,6 +4484,12 @@ no_journal: | |||
4484 | iput(root); | 4484 | iput(root); |
4485 | goto failed_mount4; | 4485 | goto failed_mount4; |
4486 | } | 4486 | } |
4487 | |||
4488 | #ifdef CONFIG_UNICODE | ||
4489 | if (sbi->s_encoding) | ||
4490 | sb->s_d_op = &ext4_dentry_ops; | ||
4491 | #endif | ||
4492 | |||
4487 | sb->s_root = d_make_root(root); | 4493 | sb->s_root = d_make_root(root); |
4488 | if (!sb->s_root) { | 4494 | if (!sb->s_root) { |
4489 | ext4_msg(sb, KERN_ERR, "get root dentry failed"); | 4495 | ext4_msg(sb, KERN_ERR, "get root dentry failed"); |
diff --git a/include/linux/fs.h b/include/linux/fs.h index 8b42df09b04c..6261090e605b 100644 --- a/include/linux/fs.h +++ b/include/linux/fs.h | |||
@@ -1953,6 +1953,7 @@ struct super_operations { | |||
1953 | #define S_DAX 0 /* Make all the DAX code disappear */ | 1953 | #define S_DAX 0 /* Make all the DAX code disappear */ |
1954 | #endif | 1954 | #endif |
1955 | #define S_ENCRYPTED 16384 /* Encrypted file (using fs/crypto/) */ | 1955 | #define S_ENCRYPTED 16384 /* Encrypted file (using fs/crypto/) */ |
1956 | #define S_CASEFOLD 32768 /* Casefolded file */ | ||
1956 | 1957 | ||
1957 | /* | 1958 | /* |
1958 | * Note that nosuid etc flags are inode-specific: setting some file-system | 1959 | * Note that nosuid etc flags are inode-specific: setting some file-system |
@@ -1993,6 +1994,7 @@ static inline bool sb_rdonly(const struct super_block *sb) { return sb->s_flags | |||
1993 | #define IS_NOSEC(inode) ((inode)->i_flags & S_NOSEC) | 1994 | #define IS_NOSEC(inode) ((inode)->i_flags & S_NOSEC) |
1994 | #define IS_DAX(inode) ((inode)->i_flags & S_DAX) | 1995 | #define IS_DAX(inode) ((inode)->i_flags & S_DAX) |
1995 | #define IS_ENCRYPTED(inode) ((inode)->i_flags & S_ENCRYPTED) | 1996 | #define IS_ENCRYPTED(inode) ((inode)->i_flags & S_ENCRYPTED) |
1997 | #define IS_CASEFOLDED(inode) ((inode)->i_flags & S_CASEFOLD) | ||
1996 | 1998 | ||
1997 | #define IS_WHITEOUT(inode) (S_ISCHR(inode->i_mode) && \ | 1999 | #define IS_WHITEOUT(inode) (S_ISCHR(inode->i_mode) && \ |
1998 | (inode)->i_rdev == WHITEOUT_DEV) | 2000 | (inode)->i_rdev == WHITEOUT_DEV) |