diff options
Diffstat (limited to 'fs/fat/inode.c')
-rw-r--r-- | fs/fat/inode.c | 210 |
1 files changed, 72 insertions, 138 deletions
diff --git a/fs/fat/inode.c b/fs/fat/inode.c index 05e897fe9866..76f60c642c06 100644 --- a/fs/fat/inode.c +++ b/fs/fat/inode.c | |||
@@ -281,15 +281,42 @@ static inline unsigned long fat_hash(loff_t i_pos) | |||
281 | return hash_32(i_pos, FAT_HASH_BITS); | 281 | return hash_32(i_pos, FAT_HASH_BITS); |
282 | } | 282 | } |
283 | 283 | ||
284 | static void dir_hash_init(struct super_block *sb) | ||
285 | { | ||
286 | struct msdos_sb_info *sbi = MSDOS_SB(sb); | ||
287 | int i; | ||
288 | |||
289 | spin_lock_init(&sbi->dir_hash_lock); | ||
290 | for (i = 0; i < FAT_HASH_SIZE; i++) | ||
291 | INIT_HLIST_HEAD(&sbi->dir_hashtable[i]); | ||
292 | } | ||
293 | |||
284 | void fat_attach(struct inode *inode, loff_t i_pos) | 294 | void fat_attach(struct inode *inode, loff_t i_pos) |
285 | { | 295 | { |
286 | struct msdos_sb_info *sbi = MSDOS_SB(inode->i_sb); | 296 | struct msdos_sb_info *sbi = MSDOS_SB(inode->i_sb); |
287 | struct hlist_head *head = sbi->inode_hashtable + fat_hash(i_pos); | ||
288 | 297 | ||
289 | spin_lock(&sbi->inode_hash_lock); | 298 | if (inode->i_ino != MSDOS_ROOT_INO) { |
290 | MSDOS_I(inode)->i_pos = i_pos; | 299 | struct hlist_head *head = sbi->inode_hashtable |
291 | hlist_add_head(&MSDOS_I(inode)->i_fat_hash, head); | 300 | + fat_hash(i_pos); |
292 | spin_unlock(&sbi->inode_hash_lock); | 301 | |
302 | spin_lock(&sbi->inode_hash_lock); | ||
303 | MSDOS_I(inode)->i_pos = i_pos; | ||
304 | hlist_add_head(&MSDOS_I(inode)->i_fat_hash, head); | ||
305 | spin_unlock(&sbi->inode_hash_lock); | ||
306 | } | ||
307 | |||
308 | /* If NFS support is enabled, cache the mapping of start cluster | ||
309 | * to directory inode. This is used during reconnection of | ||
310 | * dentries to the filesystem root. | ||
311 | */ | ||
312 | if (S_ISDIR(inode->i_mode) && sbi->options.nfs) { | ||
313 | struct hlist_head *d_head = sbi->dir_hashtable; | ||
314 | d_head += fat_dir_hash(MSDOS_I(inode)->i_logstart); | ||
315 | |||
316 | spin_lock(&sbi->dir_hash_lock); | ||
317 | hlist_add_head(&MSDOS_I(inode)->i_dir_hash, d_head); | ||
318 | spin_unlock(&sbi->dir_hash_lock); | ||
319 | } | ||
293 | } | 320 | } |
294 | EXPORT_SYMBOL_GPL(fat_attach); | 321 | EXPORT_SYMBOL_GPL(fat_attach); |
295 | 322 | ||
@@ -300,6 +327,12 @@ void fat_detach(struct inode *inode) | |||
300 | MSDOS_I(inode)->i_pos = 0; | 327 | MSDOS_I(inode)->i_pos = 0; |
301 | hlist_del_init(&MSDOS_I(inode)->i_fat_hash); | 328 | hlist_del_init(&MSDOS_I(inode)->i_fat_hash); |
302 | spin_unlock(&sbi->inode_hash_lock); | 329 | spin_unlock(&sbi->inode_hash_lock); |
330 | |||
331 | if (S_ISDIR(inode->i_mode) && sbi->options.nfs) { | ||
332 | spin_lock(&sbi->dir_hash_lock); | ||
333 | hlist_del_init(&MSDOS_I(inode)->i_dir_hash); | ||
334 | spin_unlock(&sbi->dir_hash_lock); | ||
335 | } | ||
303 | } | 336 | } |
304 | EXPORT_SYMBOL_GPL(fat_detach); | 337 | EXPORT_SYMBOL_GPL(fat_detach); |
305 | 338 | ||
@@ -504,6 +537,7 @@ static void init_once(void *foo) | |||
504 | ei->cache_valid_id = FAT_CACHE_VALID + 1; | 537 | ei->cache_valid_id = FAT_CACHE_VALID + 1; |
505 | INIT_LIST_HEAD(&ei->cache_lru); | 538 | INIT_LIST_HEAD(&ei->cache_lru); |
506 | INIT_HLIST_NODE(&ei->i_fat_hash); | 539 | INIT_HLIST_NODE(&ei->i_fat_hash); |
540 | INIT_HLIST_NODE(&ei->i_dir_hash); | ||
507 | inode_init_once(&ei->vfs_inode); | 541 | inode_init_once(&ei->vfs_inode); |
508 | } | 542 | } |
509 | 543 | ||
@@ -521,6 +555,11 @@ static int __init fat_init_inodecache(void) | |||
521 | 555 | ||
522 | static void __exit fat_destroy_inodecache(void) | 556 | static void __exit fat_destroy_inodecache(void) |
523 | { | 557 | { |
558 | /* | ||
559 | * Make sure all delayed rcu free inodes are flushed before we | ||
560 | * destroy cache. | ||
561 | */ | ||
562 | rcu_barrier(); | ||
524 | kmem_cache_destroy(fat_inode_cachep); | 563 | kmem_cache_destroy(fat_inode_cachep); |
525 | } | 564 | } |
526 | 565 | ||
@@ -663,125 +702,9 @@ static const struct super_operations fat_sops = { | |||
663 | .show_options = fat_show_options, | 702 | .show_options = fat_show_options, |
664 | }; | 703 | }; |
665 | 704 | ||
666 | /* | ||
667 | * a FAT file handle with fhtype 3 is | ||
668 | * 0/ i_ino - for fast, reliable lookup if still in the cache | ||
669 | * 1/ i_generation - to see if i_ino is still valid | ||
670 | * bit 0 == 0 iff directory | ||
671 | * 2/ i_pos(8-39) - if ino has changed, but still in cache | ||
672 | * 3/ i_pos(4-7)|i_logstart - to semi-verify inode found at i_pos | ||
673 | * 4/ i_pos(0-3)|parent->i_logstart - maybe used to hunt for the file on disc | ||
674 | * | ||
675 | * Hack for NFSv2: Maximum FAT entry number is 28bits and maximum | ||
676 | * i_pos is 40bits (blocknr(32) + dir offset(8)), so two 4bits | ||
677 | * of i_logstart is used to store the directory entry offset. | ||
678 | */ | ||
679 | |||
680 | static struct dentry *fat_fh_to_dentry(struct super_block *sb, | ||
681 | struct fid *fid, int fh_len, int fh_type) | ||
682 | { | ||
683 | struct inode *inode = NULL; | ||
684 | u32 *fh = fid->raw; | ||
685 | |||
686 | if (fh_len < 5 || fh_type != 3) | ||
687 | return NULL; | ||
688 | |||
689 | inode = ilookup(sb, fh[0]); | ||
690 | if (!inode || inode->i_generation != fh[1]) { | ||
691 | if (inode) | ||
692 | iput(inode); | ||
693 | inode = NULL; | ||
694 | } | ||
695 | if (!inode) { | ||
696 | loff_t i_pos; | ||
697 | int i_logstart = fh[3] & 0x0fffffff; | ||
698 | |||
699 | i_pos = (loff_t)fh[2] << 8; | ||
700 | i_pos |= ((fh[3] >> 24) & 0xf0) | (fh[4] >> 28); | ||
701 | |||
702 | /* try 2 - see if i_pos is in F-d-c | ||
703 | * require i_logstart to be the same | ||
704 | * Will fail if you truncate and then re-write | ||
705 | */ | ||
706 | |||
707 | inode = fat_iget(sb, i_pos); | ||
708 | if (inode && MSDOS_I(inode)->i_logstart != i_logstart) { | ||
709 | iput(inode); | ||
710 | inode = NULL; | ||
711 | } | ||
712 | } | ||
713 | |||
714 | /* | ||
715 | * For now, do nothing if the inode is not found. | ||
716 | * | ||
717 | * What we could do is: | ||
718 | * | ||
719 | * - follow the file starting at fh[4], and record the ".." entry, | ||
720 | * and the name of the fh[2] entry. | ||
721 | * - then follow the ".." file finding the next step up. | ||
722 | * | ||
723 | * This way we build a path to the root of the tree. If this works, we | ||
724 | * lookup the path and so get this inode into the cache. Finally try | ||
725 | * the fat_iget lookup again. If that fails, then we are totally out | ||
726 | * of luck. But all that is for another day | ||
727 | */ | ||
728 | return d_obtain_alias(inode); | ||
729 | } | ||
730 | |||
731 | static int | ||
732 | fat_encode_fh(struct inode *inode, __u32 *fh, int *lenp, struct inode *parent) | ||
733 | { | ||
734 | int len = *lenp; | ||
735 | struct msdos_sb_info *sbi = MSDOS_SB(inode->i_sb); | ||
736 | loff_t i_pos; | ||
737 | |||
738 | if (len < 5) { | ||
739 | *lenp = 5; | ||
740 | return 255; /* no room */ | ||
741 | } | ||
742 | |||
743 | i_pos = fat_i_pos_read(sbi, inode); | ||
744 | *lenp = 5; | ||
745 | fh[0] = inode->i_ino; | ||
746 | fh[1] = inode->i_generation; | ||
747 | fh[2] = i_pos >> 8; | ||
748 | fh[3] = ((i_pos & 0xf0) << 24) | MSDOS_I(inode)->i_logstart; | ||
749 | fh[4] = (i_pos & 0x0f) << 28; | ||
750 | if (parent) | ||
751 | fh[4] |= MSDOS_I(parent)->i_logstart; | ||
752 | return 3; | ||
753 | } | ||
754 | |||
755 | static struct dentry *fat_get_parent(struct dentry *child) | ||
756 | { | ||
757 | struct super_block *sb = child->d_sb; | ||
758 | struct buffer_head *bh; | ||
759 | struct msdos_dir_entry *de; | ||
760 | loff_t i_pos; | ||
761 | struct dentry *parent; | ||
762 | struct inode *inode; | ||
763 | int err; | ||
764 | |||
765 | lock_super(sb); | ||
766 | |||
767 | err = fat_get_dotdot_entry(child->d_inode, &bh, &de, &i_pos); | ||
768 | if (err) { | ||
769 | parent = ERR_PTR(err); | ||
770 | goto out; | ||
771 | } | ||
772 | inode = fat_build_inode(sb, de, i_pos); | ||
773 | brelse(bh); | ||
774 | |||
775 | parent = d_obtain_alias(inode); | ||
776 | out: | ||
777 | unlock_super(sb); | ||
778 | |||
779 | return parent; | ||
780 | } | ||
781 | |||
782 | static const struct export_operations fat_export_ops = { | 705 | static const struct export_operations fat_export_ops = { |
783 | .encode_fh = fat_encode_fh, | ||
784 | .fh_to_dentry = fat_fh_to_dentry, | 706 | .fh_to_dentry = fat_fh_to_dentry, |
707 | .fh_to_parent = fat_fh_to_parent, | ||
785 | .get_parent = fat_get_parent, | 708 | .get_parent = fat_get_parent, |
786 | }; | 709 | }; |
787 | 710 | ||
@@ -791,10 +714,12 @@ static int fat_show_options(struct seq_file *m, struct dentry *root) | |||
791 | struct fat_mount_options *opts = &sbi->options; | 714 | struct fat_mount_options *opts = &sbi->options; |
792 | int isvfat = opts->isvfat; | 715 | int isvfat = opts->isvfat; |
793 | 716 | ||
794 | if (opts->fs_uid != 0) | 717 | if (!uid_eq(opts->fs_uid, GLOBAL_ROOT_UID)) |
795 | seq_printf(m, ",uid=%u", opts->fs_uid); | 718 | seq_printf(m, ",uid=%u", |
796 | if (opts->fs_gid != 0) | 719 | from_kuid_munged(&init_user_ns, opts->fs_uid)); |
797 | seq_printf(m, ",gid=%u", opts->fs_gid); | 720 | if (!gid_eq(opts->fs_gid, GLOBAL_ROOT_GID)) |
721 | seq_printf(m, ",gid=%u", | ||
722 | from_kgid_munged(&init_user_ns, opts->fs_gid)); | ||
798 | seq_printf(m, ",fmask=%04o", opts->fs_fmask); | 723 | seq_printf(m, ",fmask=%04o", opts->fs_fmask); |
799 | seq_printf(m, ",dmask=%04o", opts->fs_dmask); | 724 | seq_printf(m, ",dmask=%04o", opts->fs_dmask); |
800 | if (opts->allow_utime) | 725 | if (opts->allow_utime) |
@@ -829,6 +754,8 @@ static int fat_show_options(struct seq_file *m, struct dentry *root) | |||
829 | seq_puts(m, ",usefree"); | 754 | seq_puts(m, ",usefree"); |
830 | if (opts->quiet) | 755 | if (opts->quiet) |
831 | seq_puts(m, ",quiet"); | 756 | seq_puts(m, ",quiet"); |
757 | if (opts->nfs) | ||
758 | seq_puts(m, ",nfs"); | ||
832 | if (opts->showexec) | 759 | if (opts->showexec) |
833 | seq_puts(m, ",showexec"); | 760 | seq_puts(m, ",showexec"); |
834 | if (opts->sys_immutable) | 761 | if (opts->sys_immutable) |
@@ -873,7 +800,7 @@ enum { | |||
873 | Opt_shortname_winnt, Opt_shortname_mixed, Opt_utf8_no, Opt_utf8_yes, | 800 | Opt_shortname_winnt, Opt_shortname_mixed, Opt_utf8_no, Opt_utf8_yes, |
874 | Opt_uni_xl_no, Opt_uni_xl_yes, Opt_nonumtail_no, Opt_nonumtail_yes, | 801 | Opt_uni_xl_no, Opt_uni_xl_yes, Opt_nonumtail_no, Opt_nonumtail_yes, |
875 | Opt_obsolete, Opt_flush, Opt_tz_utc, Opt_rodir, Opt_err_cont, | 802 | Opt_obsolete, Opt_flush, Opt_tz_utc, Opt_rodir, Opt_err_cont, |
876 | Opt_err_panic, Opt_err_ro, Opt_discard, Opt_err, | 803 | Opt_err_panic, Opt_err_ro, Opt_discard, Opt_nfs, Opt_err, |
877 | }; | 804 | }; |
878 | 805 | ||
879 | static const match_table_t fat_tokens = { | 806 | static const match_table_t fat_tokens = { |
@@ -902,6 +829,7 @@ static const match_table_t fat_tokens = { | |||
902 | {Opt_err_panic, "errors=panic"}, | 829 | {Opt_err_panic, "errors=panic"}, |
903 | {Opt_err_ro, "errors=remount-ro"}, | 830 | {Opt_err_ro, "errors=remount-ro"}, |
904 | {Opt_discard, "discard"}, | 831 | {Opt_discard, "discard"}, |
832 | {Opt_nfs, "nfs"}, | ||
905 | {Opt_obsolete, "conv=binary"}, | 833 | {Opt_obsolete, "conv=binary"}, |
906 | {Opt_obsolete, "conv=text"}, | 834 | {Opt_obsolete, "conv=text"}, |
907 | {Opt_obsolete, "conv=auto"}, | 835 | {Opt_obsolete, "conv=auto"}, |
@@ -982,6 +910,7 @@ static int parse_options(struct super_block *sb, char *options, int is_vfat, | |||
982 | opts->numtail = 1; | 910 | opts->numtail = 1; |
983 | opts->usefree = opts->nocase = 0; | 911 | opts->usefree = opts->nocase = 0; |
984 | opts->tz_utc = 0; | 912 | opts->tz_utc = 0; |
913 | opts->nfs = 0; | ||
985 | opts->errors = FAT_ERRORS_RO; | 914 | opts->errors = FAT_ERRORS_RO; |
986 | *debug = 0; | 915 | *debug = 0; |
987 | 916 | ||
@@ -1037,12 +966,16 @@ static int parse_options(struct super_block *sb, char *options, int is_vfat, | |||
1037 | case Opt_uid: | 966 | case Opt_uid: |
1038 | if (match_int(&args[0], &option)) | 967 | if (match_int(&args[0], &option)) |
1039 | return 0; | 968 | return 0; |
1040 | opts->fs_uid = option; | 969 | opts->fs_uid = make_kuid(current_user_ns(), option); |
970 | if (!uid_valid(opts->fs_uid)) | ||
971 | return 0; | ||
1041 | break; | 972 | break; |
1042 | case Opt_gid: | 973 | case Opt_gid: |
1043 | if (match_int(&args[0], &option)) | 974 | if (match_int(&args[0], &option)) |
1044 | return 0; | 975 | return 0; |
1045 | opts->fs_gid = option; | 976 | opts->fs_gid = make_kgid(current_user_ns(), option); |
977 | if (!gid_valid(opts->fs_gid)) | ||
978 | return 0; | ||
1046 | break; | 979 | break; |
1047 | case Opt_umask: | 980 | case Opt_umask: |
1048 | if (match_octal(&args[0], &option)) | 981 | if (match_octal(&args[0], &option)) |
@@ -1142,6 +1075,9 @@ static int parse_options(struct super_block *sb, char *options, int is_vfat, | |||
1142 | case Opt_discard: | 1075 | case Opt_discard: |
1143 | opts->discard = 1; | 1076 | opts->discard = 1; |
1144 | break; | 1077 | break; |
1078 | case Opt_nfs: | ||
1079 | opts->nfs = 1; | ||
1080 | break; | ||
1145 | 1081 | ||
1146 | /* obsolete mount options */ | 1082 | /* obsolete mount options */ |
1147 | case Opt_obsolete: | 1083 | case Opt_obsolete: |
@@ -1432,6 +1368,7 @@ int fat_fill_super(struct super_block *sb, void *data, int silent, int isvfat, | |||
1432 | 1368 | ||
1433 | /* set up enough so that it can read an inode */ | 1369 | /* set up enough so that it can read an inode */ |
1434 | fat_hash_init(sb); | 1370 | fat_hash_init(sb); |
1371 | dir_hash_init(sb); | ||
1435 | fat_ent_access_init(sb); | 1372 | fat_ent_access_init(sb); |
1436 | 1373 | ||
1437 | /* | 1374 | /* |
@@ -1486,6 +1423,7 @@ int fat_fill_super(struct super_block *sb, void *data, int silent, int isvfat, | |||
1486 | } | 1423 | } |
1487 | error = -ENOMEM; | 1424 | error = -ENOMEM; |
1488 | insert_inode_hash(root_inode); | 1425 | insert_inode_hash(root_inode); |
1426 | fat_attach(root_inode, 0); | ||
1489 | sb->s_root = d_make_root(root_inode); | 1427 | sb->s_root = d_make_root(root_inode); |
1490 | if (!sb->s_root) { | 1428 | if (!sb->s_root) { |
1491 | fat_msg(sb, KERN_ERR, "get root inode failed"); | 1429 | fat_msg(sb, KERN_ERR, "get root inode failed"); |
@@ -1525,18 +1463,14 @@ static int writeback_inode(struct inode *inode) | |||
1525 | { | 1463 | { |
1526 | 1464 | ||
1527 | int ret; | 1465 | int ret; |
1528 | struct address_space *mapping = inode->i_mapping; | 1466 | |
1529 | struct writeback_control wbc = { | 1467 | /* if we used wait=1, sync_inode_metadata waits for the io for the |
1530 | .sync_mode = WB_SYNC_NONE, | 1468 | * inode to finish. So wait=0 is sent down to sync_inode_metadata |
1531 | .nr_to_write = 0, | ||
1532 | }; | ||
1533 | /* if we used WB_SYNC_ALL, sync_inode waits for the io for the | ||
1534 | * inode to finish. So WB_SYNC_NONE is sent down to sync_inode | ||
1535 | * and filemap_fdatawrite is used for the data blocks | 1469 | * and filemap_fdatawrite is used for the data blocks |
1536 | */ | 1470 | */ |
1537 | ret = sync_inode(inode, &wbc); | 1471 | ret = sync_inode_metadata(inode, 0); |
1538 | if (!ret) | 1472 | if (!ret) |
1539 | ret = filemap_fdatawrite(mapping); | 1473 | ret = filemap_fdatawrite(inode->i_mapping); |
1540 | return ret; | 1474 | return ret; |
1541 | } | 1475 | } |
1542 | 1476 | ||