diff options
Diffstat (limited to 'fs/fat/inode.c')
-rw-r--r-- | fs/fat/inode.c | 187 |
1 files changed, 55 insertions, 132 deletions
diff --git a/fs/fat/inode.c b/fs/fat/inode.c index 4e5a6ac54ebd..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 | ||
@@ -668,125 +702,9 @@ static const struct super_operations fat_sops = { | |||
668 | .show_options = fat_show_options, | 702 | .show_options = fat_show_options, |
669 | }; | 703 | }; |
670 | 704 | ||
671 | /* | ||
672 | * a FAT file handle with fhtype 3 is | ||
673 | * 0/ i_ino - for fast, reliable lookup if still in the cache | ||
674 | * 1/ i_generation - to see if i_ino is still valid | ||
675 | * bit 0 == 0 iff directory | ||
676 | * 2/ i_pos(8-39) - if ino has changed, but still in cache | ||
677 | * 3/ i_pos(4-7)|i_logstart - to semi-verify inode found at i_pos | ||
678 | * 4/ i_pos(0-3)|parent->i_logstart - maybe used to hunt for the file on disc | ||
679 | * | ||
680 | * Hack for NFSv2: Maximum FAT entry number is 28bits and maximum | ||
681 | * i_pos is 40bits (blocknr(32) + dir offset(8)), so two 4bits | ||
682 | * of i_logstart is used to store the directory entry offset. | ||
683 | */ | ||
684 | |||
685 | static struct dentry *fat_fh_to_dentry(struct super_block *sb, | ||
686 | struct fid *fid, int fh_len, int fh_type) | ||
687 | { | ||
688 | struct inode *inode = NULL; | ||
689 | u32 *fh = fid->raw; | ||
690 | |||
691 | if (fh_len < 5 || fh_type != 3) | ||
692 | return NULL; | ||
693 | |||
694 | inode = ilookup(sb, fh[0]); | ||
695 | if (!inode || inode->i_generation != fh[1]) { | ||
696 | if (inode) | ||
697 | iput(inode); | ||
698 | inode = NULL; | ||
699 | } | ||
700 | if (!inode) { | ||
701 | loff_t i_pos; | ||
702 | int i_logstart = fh[3] & 0x0fffffff; | ||
703 | |||
704 | i_pos = (loff_t)fh[2] << 8; | ||
705 | i_pos |= ((fh[3] >> 24) & 0xf0) | (fh[4] >> 28); | ||
706 | |||
707 | /* try 2 - see if i_pos is in F-d-c | ||
708 | * require i_logstart to be the same | ||
709 | * Will fail if you truncate and then re-write | ||
710 | */ | ||
711 | |||
712 | inode = fat_iget(sb, i_pos); | ||
713 | if (inode && MSDOS_I(inode)->i_logstart != i_logstart) { | ||
714 | iput(inode); | ||
715 | inode = NULL; | ||
716 | } | ||
717 | } | ||
718 | |||
719 | /* | ||
720 | * For now, do nothing if the inode is not found. | ||
721 | * | ||
722 | * What we could do is: | ||
723 | * | ||
724 | * - follow the file starting at fh[4], and record the ".." entry, | ||
725 | * and the name of the fh[2] entry. | ||
726 | * - then follow the ".." file finding the next step up. | ||
727 | * | ||
728 | * This way we build a path to the root of the tree. If this works, we | ||
729 | * lookup the path and so get this inode into the cache. Finally try | ||
730 | * the fat_iget lookup again. If that fails, then we are totally out | ||
731 | * of luck. But all that is for another day | ||
732 | */ | ||
733 | return d_obtain_alias(inode); | ||
734 | } | ||
735 | |||
736 | static int | ||
737 | fat_encode_fh(struct inode *inode, __u32 *fh, int *lenp, struct inode *parent) | ||
738 | { | ||
739 | int len = *lenp; | ||
740 | struct msdos_sb_info *sbi = MSDOS_SB(inode->i_sb); | ||
741 | loff_t i_pos; | ||
742 | |||
743 | if (len < 5) { | ||
744 | *lenp = 5; | ||
745 | return 255; /* no room */ | ||
746 | } | ||
747 | |||
748 | i_pos = fat_i_pos_read(sbi, inode); | ||
749 | *lenp = 5; | ||
750 | fh[0] = inode->i_ino; | ||
751 | fh[1] = inode->i_generation; | ||
752 | fh[2] = i_pos >> 8; | ||
753 | fh[3] = ((i_pos & 0xf0) << 24) | MSDOS_I(inode)->i_logstart; | ||
754 | fh[4] = (i_pos & 0x0f) << 28; | ||
755 | if (parent) | ||
756 | fh[4] |= MSDOS_I(parent)->i_logstart; | ||
757 | return 3; | ||
758 | } | ||
759 | |||
760 | static struct dentry *fat_get_parent(struct dentry *child) | ||
761 | { | ||
762 | struct super_block *sb = child->d_sb; | ||
763 | struct buffer_head *bh; | ||
764 | struct msdos_dir_entry *de; | ||
765 | loff_t i_pos; | ||
766 | struct dentry *parent; | ||
767 | struct inode *inode; | ||
768 | int err; | ||
769 | |||
770 | lock_super(sb); | ||
771 | |||
772 | err = fat_get_dotdot_entry(child->d_inode, &bh, &de, &i_pos); | ||
773 | if (err) { | ||
774 | parent = ERR_PTR(err); | ||
775 | goto out; | ||
776 | } | ||
777 | inode = fat_build_inode(sb, de, i_pos); | ||
778 | brelse(bh); | ||
779 | |||
780 | parent = d_obtain_alias(inode); | ||
781 | out: | ||
782 | unlock_super(sb); | ||
783 | |||
784 | return parent; | ||
785 | } | ||
786 | |||
787 | static const struct export_operations fat_export_ops = { | 705 | static const struct export_operations fat_export_ops = { |
788 | .encode_fh = fat_encode_fh, | ||
789 | .fh_to_dentry = fat_fh_to_dentry, | 706 | .fh_to_dentry = fat_fh_to_dentry, |
707 | .fh_to_parent = fat_fh_to_parent, | ||
790 | .get_parent = fat_get_parent, | 708 | .get_parent = fat_get_parent, |
791 | }; | 709 | }; |
792 | 710 | ||
@@ -836,6 +754,8 @@ static int fat_show_options(struct seq_file *m, struct dentry *root) | |||
836 | seq_puts(m, ",usefree"); | 754 | seq_puts(m, ",usefree"); |
837 | if (opts->quiet) | 755 | if (opts->quiet) |
838 | seq_puts(m, ",quiet"); | 756 | seq_puts(m, ",quiet"); |
757 | if (opts->nfs) | ||
758 | seq_puts(m, ",nfs"); | ||
839 | if (opts->showexec) | 759 | if (opts->showexec) |
840 | seq_puts(m, ",showexec"); | 760 | seq_puts(m, ",showexec"); |
841 | if (opts->sys_immutable) | 761 | if (opts->sys_immutable) |
@@ -880,7 +800,7 @@ enum { | |||
880 | 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, |
881 | 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, |
882 | 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, |
883 | Opt_err_panic, Opt_err_ro, Opt_discard, Opt_err, | 803 | Opt_err_panic, Opt_err_ro, Opt_discard, Opt_nfs, Opt_err, |
884 | }; | 804 | }; |
885 | 805 | ||
886 | static const match_table_t fat_tokens = { | 806 | static const match_table_t fat_tokens = { |
@@ -909,6 +829,7 @@ static const match_table_t fat_tokens = { | |||
909 | {Opt_err_panic, "errors=panic"}, | 829 | {Opt_err_panic, "errors=panic"}, |
910 | {Opt_err_ro, "errors=remount-ro"}, | 830 | {Opt_err_ro, "errors=remount-ro"}, |
911 | {Opt_discard, "discard"}, | 831 | {Opt_discard, "discard"}, |
832 | {Opt_nfs, "nfs"}, | ||
912 | {Opt_obsolete, "conv=binary"}, | 833 | {Opt_obsolete, "conv=binary"}, |
913 | {Opt_obsolete, "conv=text"}, | 834 | {Opt_obsolete, "conv=text"}, |
914 | {Opt_obsolete, "conv=auto"}, | 835 | {Opt_obsolete, "conv=auto"}, |
@@ -989,6 +910,7 @@ static int parse_options(struct super_block *sb, char *options, int is_vfat, | |||
989 | opts->numtail = 1; | 910 | opts->numtail = 1; |
990 | opts->usefree = opts->nocase = 0; | 911 | opts->usefree = opts->nocase = 0; |
991 | opts->tz_utc = 0; | 912 | opts->tz_utc = 0; |
913 | opts->nfs = 0; | ||
992 | opts->errors = FAT_ERRORS_RO; | 914 | opts->errors = FAT_ERRORS_RO; |
993 | *debug = 0; | 915 | *debug = 0; |
994 | 916 | ||
@@ -1153,6 +1075,9 @@ static int parse_options(struct super_block *sb, char *options, int is_vfat, | |||
1153 | case Opt_discard: | 1075 | case Opt_discard: |
1154 | opts->discard = 1; | 1076 | opts->discard = 1; |
1155 | break; | 1077 | break; |
1078 | case Opt_nfs: | ||
1079 | opts->nfs = 1; | ||
1080 | break; | ||
1156 | 1081 | ||
1157 | /* obsolete mount options */ | 1082 | /* obsolete mount options */ |
1158 | case Opt_obsolete: | 1083 | case Opt_obsolete: |
@@ -1443,6 +1368,7 @@ int fat_fill_super(struct super_block *sb, void *data, int silent, int isvfat, | |||
1443 | 1368 | ||
1444 | /* set up enough so that it can read an inode */ | 1369 | /* set up enough so that it can read an inode */ |
1445 | fat_hash_init(sb); | 1370 | fat_hash_init(sb); |
1371 | dir_hash_init(sb); | ||
1446 | fat_ent_access_init(sb); | 1372 | fat_ent_access_init(sb); |
1447 | 1373 | ||
1448 | /* | 1374 | /* |
@@ -1497,6 +1423,7 @@ int fat_fill_super(struct super_block *sb, void *data, int silent, int isvfat, | |||
1497 | } | 1423 | } |
1498 | error = -ENOMEM; | 1424 | error = -ENOMEM; |
1499 | insert_inode_hash(root_inode); | 1425 | insert_inode_hash(root_inode); |
1426 | fat_attach(root_inode, 0); | ||
1500 | sb->s_root = d_make_root(root_inode); | 1427 | sb->s_root = d_make_root(root_inode); |
1501 | if (!sb->s_root) { | 1428 | if (!sb->s_root) { |
1502 | fat_msg(sb, KERN_ERR, "get root inode failed"); | 1429 | fat_msg(sb, KERN_ERR, "get root inode failed"); |
@@ -1536,18 +1463,14 @@ static int writeback_inode(struct inode *inode) | |||
1536 | { | 1463 | { |
1537 | 1464 | ||
1538 | int ret; | 1465 | int ret; |
1539 | struct address_space *mapping = inode->i_mapping; | 1466 | |
1540 | struct writeback_control wbc = { | 1467 | /* if we used wait=1, sync_inode_metadata waits for the io for the |
1541 | .sync_mode = WB_SYNC_NONE, | 1468 | * inode to finish. So wait=0 is sent down to sync_inode_metadata |
1542 | .nr_to_write = 0, | ||
1543 | }; | ||
1544 | /* if we used WB_SYNC_ALL, sync_inode waits for the io for the | ||
1545 | * inode to finish. So WB_SYNC_NONE is sent down to sync_inode | ||
1546 | * and filemap_fdatawrite is used for the data blocks | 1469 | * and filemap_fdatawrite is used for the data blocks |
1547 | */ | 1470 | */ |
1548 | ret = sync_inode(inode, &wbc); | 1471 | ret = sync_inode_metadata(inode, 0); |
1549 | if (!ret) | 1472 | if (!ret) |
1550 | ret = filemap_fdatawrite(mapping); | 1473 | ret = filemap_fdatawrite(inode->i_mapping); |
1551 | return ret; | 1474 | return ret; |
1552 | } | 1475 | } |
1553 | 1476 | ||