diff options
author | Jonathan Herman <hermanjl@cs.unc.edu> | 2013-01-17 16:15:55 -0500 |
---|---|---|
committer | Jonathan Herman <hermanjl@cs.unc.edu> | 2013-01-17 16:15:55 -0500 |
commit | 8dea78da5cee153b8af9c07a2745f6c55057fe12 (patch) | |
tree | a8f4d49d63b1ecc92f2fddceba0655b2472c5bd9 /fs/fat/inode.c | |
parent | 406089d01562f1e2bf9f089fd7637009ebaad589 (diff) |
Patched in Tegra support.
Diffstat (limited to 'fs/fat/inode.c')
-rw-r--r-- | fs/fat/inode.c | 386 |
1 files changed, 225 insertions, 161 deletions
diff --git a/fs/fat/inode.c b/fs/fat/inode.c index f8f491677a4..b2eae577b91 100644 --- a/fs/fat/inode.c +++ b/fs/fat/inode.c | |||
@@ -26,7 +26,6 @@ | |||
26 | #include <linux/writeback.h> | 26 | #include <linux/writeback.h> |
27 | #include <linux/log2.h> | 27 | #include <linux/log2.h> |
28 | #include <linux/hash.h> | 28 | #include <linux/hash.h> |
29 | #include <linux/blkdev.h> | ||
30 | #include <asm/unaligned.h> | 29 | #include <asm/unaligned.h> |
31 | #include "fat.h" | 30 | #include "fat.h" |
32 | 31 | ||
@@ -282,42 +281,15 @@ static inline unsigned long fat_hash(loff_t i_pos) | |||
282 | return hash_32(i_pos, FAT_HASH_BITS); | 281 | return hash_32(i_pos, FAT_HASH_BITS); |
283 | } | 282 | } |
284 | 283 | ||
285 | static void dir_hash_init(struct super_block *sb) | ||
286 | { | ||
287 | struct msdos_sb_info *sbi = MSDOS_SB(sb); | ||
288 | int i; | ||
289 | |||
290 | spin_lock_init(&sbi->dir_hash_lock); | ||
291 | for (i = 0; i < FAT_HASH_SIZE; i++) | ||
292 | INIT_HLIST_HEAD(&sbi->dir_hashtable[i]); | ||
293 | } | ||
294 | |||
295 | void fat_attach(struct inode *inode, loff_t i_pos) | 284 | void fat_attach(struct inode *inode, loff_t i_pos) |
296 | { | 285 | { |
297 | struct msdos_sb_info *sbi = MSDOS_SB(inode->i_sb); | 286 | struct msdos_sb_info *sbi = MSDOS_SB(inode->i_sb); |
287 | struct hlist_head *head = sbi->inode_hashtable + fat_hash(i_pos); | ||
298 | 288 | ||
299 | if (inode->i_ino != MSDOS_ROOT_INO) { | 289 | spin_lock(&sbi->inode_hash_lock); |
300 | struct hlist_head *head = sbi->inode_hashtable | 290 | MSDOS_I(inode)->i_pos = i_pos; |
301 | + fat_hash(i_pos); | 291 | hlist_add_head(&MSDOS_I(inode)->i_fat_hash, head); |
302 | 292 | spin_unlock(&sbi->inode_hash_lock); | |
303 | spin_lock(&sbi->inode_hash_lock); | ||
304 | MSDOS_I(inode)->i_pos = i_pos; | ||
305 | hlist_add_head(&MSDOS_I(inode)->i_fat_hash, head); | ||
306 | spin_unlock(&sbi->inode_hash_lock); | ||
307 | } | ||
308 | |||
309 | /* If NFS support is enabled, cache the mapping of start cluster | ||
310 | * to directory inode. This is used during reconnection of | ||
311 | * dentries to the filesystem root. | ||
312 | */ | ||
313 | if (S_ISDIR(inode->i_mode) && sbi->options.nfs) { | ||
314 | struct hlist_head *d_head = sbi->dir_hashtable; | ||
315 | d_head += fat_dir_hash(MSDOS_I(inode)->i_logstart); | ||
316 | |||
317 | spin_lock(&sbi->dir_hash_lock); | ||
318 | hlist_add_head(&MSDOS_I(inode)->i_dir_hash, d_head); | ||
319 | spin_unlock(&sbi->dir_hash_lock); | ||
320 | } | ||
321 | } | 293 | } |
322 | EXPORT_SYMBOL_GPL(fat_attach); | 294 | EXPORT_SYMBOL_GPL(fat_attach); |
323 | 295 | ||
@@ -328,12 +300,6 @@ void fat_detach(struct inode *inode) | |||
328 | MSDOS_I(inode)->i_pos = 0; | 300 | MSDOS_I(inode)->i_pos = 0; |
329 | hlist_del_init(&MSDOS_I(inode)->i_fat_hash); | 301 | hlist_del_init(&MSDOS_I(inode)->i_fat_hash); |
330 | spin_unlock(&sbi->inode_hash_lock); | 302 | spin_unlock(&sbi->inode_hash_lock); |
331 | |||
332 | if (S_ISDIR(inode->i_mode) && sbi->options.nfs) { | ||
333 | spin_lock(&sbi->dir_hash_lock); | ||
334 | hlist_del_init(&MSDOS_I(inode)->i_dir_hash); | ||
335 | spin_unlock(&sbi->dir_hash_lock); | ||
336 | } | ||
337 | } | 303 | } |
338 | EXPORT_SYMBOL_GPL(fat_detach); | 304 | EXPORT_SYMBOL_GPL(fat_detach); |
339 | 305 | ||
@@ -403,20 +369,25 @@ static int fat_fill_inode(struct inode *inode, struct msdos_dir_entry *de) | |||
403 | inode->i_op = sbi->dir_ops; | 369 | inode->i_op = sbi->dir_ops; |
404 | inode->i_fop = &fat_dir_operations; | 370 | inode->i_fop = &fat_dir_operations; |
405 | 371 | ||
406 | MSDOS_I(inode)->i_start = fat_get_start(sbi, de); | 372 | MSDOS_I(inode)->i_start = le16_to_cpu(de->start); |
373 | if (sbi->fat_bits == 32) | ||
374 | MSDOS_I(inode)->i_start |= (le16_to_cpu(de->starthi) << 16); | ||
375 | |||
407 | MSDOS_I(inode)->i_logstart = MSDOS_I(inode)->i_start; | 376 | MSDOS_I(inode)->i_logstart = MSDOS_I(inode)->i_start; |
408 | error = fat_calc_dir_size(inode); | 377 | error = fat_calc_dir_size(inode); |
409 | if (error < 0) | 378 | if (error < 0) |
410 | return error; | 379 | return error; |
411 | MSDOS_I(inode)->mmu_private = inode->i_size; | 380 | MSDOS_I(inode)->mmu_private = inode->i_size; |
412 | 381 | ||
413 | set_nlink(inode, fat_subdirs(inode)); | 382 | inode->i_nlink = fat_subdirs(inode); |
414 | } else { /* not a directory */ | 383 | } else { /* not a directory */ |
415 | inode->i_generation |= 1; | 384 | inode->i_generation |= 1; |
416 | inode->i_mode = fat_make_mode(sbi, de->attr, | 385 | inode->i_mode = fat_make_mode(sbi, de->attr, |
417 | ((sbi->options.showexec && !is_exec(de->name + 8)) | 386 | ((sbi->options.showexec && !is_exec(de->name + 8)) |
418 | ? S_IRUGO|S_IWUGO : S_IRWXUGO)); | 387 | ? S_IRUGO|S_IWUGO : S_IRWXUGO)); |
419 | MSDOS_I(inode)->i_start = fat_get_start(sbi, de); | 388 | MSDOS_I(inode)->i_start = le16_to_cpu(de->start); |
389 | if (sbi->fat_bits == 32) | ||
390 | MSDOS_I(inode)->i_start |= (le16_to_cpu(de->starthi) << 16); | ||
420 | 391 | ||
421 | MSDOS_I(inode)->i_logstart = MSDOS_I(inode)->i_start; | 392 | MSDOS_I(inode)->i_logstart = MSDOS_I(inode)->i_start; |
422 | inode->i_size = le32_to_cpu(de->size); | 393 | inode->i_size = le32_to_cpu(de->size); |
@@ -483,16 +454,42 @@ static void fat_evict_inode(struct inode *inode) | |||
483 | fat_truncate_blocks(inode, 0); | 454 | fat_truncate_blocks(inode, 0); |
484 | } | 455 | } |
485 | invalidate_inode_buffers(inode); | 456 | invalidate_inode_buffers(inode); |
486 | clear_inode(inode); | 457 | end_writeback(inode); |
487 | fat_cache_inval_inode(inode); | 458 | fat_cache_inval_inode(inode); |
488 | fat_detach(inode); | 459 | fat_detach(inode); |
489 | } | 460 | } |
490 | 461 | ||
462 | static void fat_write_super(struct super_block *sb) | ||
463 | { | ||
464 | lock_super(sb); | ||
465 | sb->s_dirt = 0; | ||
466 | |||
467 | if (!(sb->s_flags & MS_RDONLY)) | ||
468 | fat_clusters_flush(sb); | ||
469 | unlock_super(sb); | ||
470 | } | ||
471 | |||
472 | static int fat_sync_fs(struct super_block *sb, int wait) | ||
473 | { | ||
474 | int err = 0; | ||
475 | |||
476 | if (sb->s_dirt) { | ||
477 | lock_super(sb); | ||
478 | sb->s_dirt = 0; | ||
479 | err = fat_clusters_flush(sb); | ||
480 | unlock_super(sb); | ||
481 | } | ||
482 | |||
483 | return err; | ||
484 | } | ||
485 | |||
491 | static void fat_put_super(struct super_block *sb) | 486 | static void fat_put_super(struct super_block *sb) |
492 | { | 487 | { |
493 | struct msdos_sb_info *sbi = MSDOS_SB(sb); | 488 | struct msdos_sb_info *sbi = MSDOS_SB(sb); |
494 | 489 | ||
495 | iput(sbi->fsinfo_inode); | 490 | if (sb->s_dirt) |
491 | fat_write_super(sb); | ||
492 | |||
496 | iput(sbi->fat_inode); | 493 | iput(sbi->fat_inode); |
497 | 494 | ||
498 | unload_nls(sbi->nls_disk); | 495 | unload_nls(sbi->nls_disk); |
@@ -521,6 +518,7 @@ static struct inode *fat_alloc_inode(struct super_block *sb) | |||
521 | static void fat_i_callback(struct rcu_head *head) | 518 | static void fat_i_callback(struct rcu_head *head) |
522 | { | 519 | { |
523 | struct inode *inode = container_of(head, struct inode, i_rcu); | 520 | struct inode *inode = container_of(head, struct inode, i_rcu); |
521 | INIT_LIST_HEAD(&inode->i_dentry); | ||
524 | kmem_cache_free(fat_inode_cachep, MSDOS_I(inode)); | 522 | kmem_cache_free(fat_inode_cachep, MSDOS_I(inode)); |
525 | } | 523 | } |
526 | 524 | ||
@@ -538,7 +536,6 @@ static void init_once(void *foo) | |||
538 | ei->cache_valid_id = FAT_CACHE_VALID + 1; | 536 | ei->cache_valid_id = FAT_CACHE_VALID + 1; |
539 | INIT_LIST_HEAD(&ei->cache_lru); | 537 | INIT_LIST_HEAD(&ei->cache_lru); |
540 | INIT_HLIST_NODE(&ei->i_fat_hash); | 538 | INIT_HLIST_NODE(&ei->i_fat_hash); |
541 | INIT_HLIST_NODE(&ei->i_dir_hash); | ||
542 | inode_init_once(&ei->vfs_inode); | 539 | inode_init_once(&ei->vfs_inode); |
543 | } | 540 | } |
544 | 541 | ||
@@ -556,11 +553,6 @@ static int __init fat_init_inodecache(void) | |||
556 | 553 | ||
557 | static void __exit fat_destroy_inodecache(void) | 554 | static void __exit fat_destroy_inodecache(void) |
558 | { | 555 | { |
559 | /* | ||
560 | * Make sure all delayed rcu free inodes are flushed before we | ||
561 | * destroy cache. | ||
562 | */ | ||
563 | rcu_barrier(); | ||
564 | kmem_cache_destroy(fat_inode_cachep); | 556 | kmem_cache_destroy(fat_inode_cachep); |
565 | } | 557 | } |
566 | 558 | ||
@@ -648,7 +640,8 @@ retry: | |||
648 | else | 640 | else |
649 | raw_entry->size = cpu_to_le32(inode->i_size); | 641 | raw_entry->size = cpu_to_le32(inode->i_size); |
650 | raw_entry->attr = fat_make_attrs(inode); | 642 | raw_entry->attr = fat_make_attrs(inode); |
651 | fat_set_start(raw_entry, MSDOS_I(inode)->i_logstart); | 643 | raw_entry->start = cpu_to_le16(MSDOS_I(inode)->i_logstart); |
644 | raw_entry->starthi = cpu_to_le16(MSDOS_I(inode)->i_logstart >> 16); | ||
652 | fat_time_unix2fat(sbi, &inode->i_mtime, &raw_entry->time, | 645 | fat_time_unix2fat(sbi, &inode->i_mtime, &raw_entry->time, |
653 | &raw_entry->date, NULL); | 646 | &raw_entry->date, NULL); |
654 | if (sbi->options.isvfat) { | 647 | if (sbi->options.isvfat) { |
@@ -669,18 +662,7 @@ retry: | |||
669 | 662 | ||
670 | static int fat_write_inode(struct inode *inode, struct writeback_control *wbc) | 663 | static int fat_write_inode(struct inode *inode, struct writeback_control *wbc) |
671 | { | 664 | { |
672 | int err; | 665 | return __fat_write_inode(inode, wbc->sync_mode == WB_SYNC_ALL); |
673 | |||
674 | if (inode->i_ino == MSDOS_FSINFO_INO) { | ||
675 | struct super_block *sb = inode->i_sb; | ||
676 | |||
677 | mutex_lock(&MSDOS_SB(sb)->s_lock); | ||
678 | err = fat_clusters_flush(sb); | ||
679 | mutex_unlock(&MSDOS_SB(sb)->s_lock); | ||
680 | } else | ||
681 | err = __fat_write_inode(inode, wbc->sync_mode == WB_SYNC_ALL); | ||
682 | |||
683 | return err; | ||
684 | } | 666 | } |
685 | 667 | ||
686 | int fat_sync_inode(struct inode *inode) | 668 | int fat_sync_inode(struct inode *inode) |
@@ -690,44 +672,161 @@ int fat_sync_inode(struct inode *inode) | |||
690 | 672 | ||
691 | EXPORT_SYMBOL_GPL(fat_sync_inode); | 673 | EXPORT_SYMBOL_GPL(fat_sync_inode); |
692 | 674 | ||
693 | static int fat_show_options(struct seq_file *m, struct dentry *root); | 675 | static int fat_show_options(struct seq_file *m, struct vfsmount *mnt); |
694 | static const struct super_operations fat_sops = { | 676 | static const struct super_operations fat_sops = { |
695 | .alloc_inode = fat_alloc_inode, | 677 | .alloc_inode = fat_alloc_inode, |
696 | .destroy_inode = fat_destroy_inode, | 678 | .destroy_inode = fat_destroy_inode, |
697 | .write_inode = fat_write_inode, | 679 | .write_inode = fat_write_inode, |
698 | .evict_inode = fat_evict_inode, | 680 | .evict_inode = fat_evict_inode, |
699 | .put_super = fat_put_super, | 681 | .put_super = fat_put_super, |
682 | .write_super = fat_write_super, | ||
683 | .sync_fs = fat_sync_fs, | ||
700 | .statfs = fat_statfs, | 684 | .statfs = fat_statfs, |
701 | .remount_fs = fat_remount, | 685 | .remount_fs = fat_remount, |
702 | 686 | ||
703 | .show_options = fat_show_options, | 687 | .show_options = fat_show_options, |
704 | }; | 688 | }; |
705 | 689 | ||
690 | /* | ||
691 | * a FAT file handle with fhtype 3 is | ||
692 | * 0/ i_ino - for fast, reliable lookup if still in the cache | ||
693 | * 1/ i_generation - to see if i_ino is still valid | ||
694 | * bit 0 == 0 iff directory | ||
695 | * 2/ i_pos(8-39) - if ino has changed, but still in cache | ||
696 | * 3/ i_pos(4-7)|i_logstart - to semi-verify inode found at i_pos | ||
697 | * 4/ i_pos(0-3)|parent->i_logstart - maybe used to hunt for the file on disc | ||
698 | * | ||
699 | * Hack for NFSv2: Maximum FAT entry number is 28bits and maximum | ||
700 | * i_pos is 40bits (blocknr(32) + dir offset(8)), so two 4bits | ||
701 | * of i_logstart is used to store the directory entry offset. | ||
702 | */ | ||
703 | |||
704 | static struct dentry *fat_fh_to_dentry(struct super_block *sb, | ||
705 | struct fid *fid, int fh_len, int fh_type) | ||
706 | { | ||
707 | struct inode *inode = NULL; | ||
708 | u32 *fh = fid->raw; | ||
709 | |||
710 | if (fh_len < 5 || fh_type != 3) | ||
711 | return NULL; | ||
712 | |||
713 | inode = ilookup(sb, fh[0]); | ||
714 | if (!inode || inode->i_generation != fh[1]) { | ||
715 | if (inode) | ||
716 | iput(inode); | ||
717 | inode = NULL; | ||
718 | } | ||
719 | if (!inode) { | ||
720 | loff_t i_pos; | ||
721 | int i_logstart = fh[3] & 0x0fffffff; | ||
722 | |||
723 | i_pos = (loff_t)fh[2] << 8; | ||
724 | i_pos |= ((fh[3] >> 24) & 0xf0) | (fh[4] >> 28); | ||
725 | |||
726 | /* try 2 - see if i_pos is in F-d-c | ||
727 | * require i_logstart to be the same | ||
728 | * Will fail if you truncate and then re-write | ||
729 | */ | ||
730 | |||
731 | inode = fat_iget(sb, i_pos); | ||
732 | if (inode && MSDOS_I(inode)->i_logstart != i_logstart) { | ||
733 | iput(inode); | ||
734 | inode = NULL; | ||
735 | } | ||
736 | } | ||
737 | |||
738 | /* | ||
739 | * For now, do nothing if the inode is not found. | ||
740 | * | ||
741 | * What we could do is: | ||
742 | * | ||
743 | * - follow the file starting at fh[4], and record the ".." entry, | ||
744 | * and the name of the fh[2] entry. | ||
745 | * - then follow the ".." file finding the next step up. | ||
746 | * | ||
747 | * This way we build a path to the root of the tree. If this works, we | ||
748 | * lookup the path and so get this inode into the cache. Finally try | ||
749 | * the fat_iget lookup again. If that fails, then we are totally out | ||
750 | * of luck. But all that is for another day | ||
751 | */ | ||
752 | return d_obtain_alias(inode); | ||
753 | } | ||
754 | |||
755 | static int | ||
756 | fat_encode_fh(struct dentry *de, __u32 *fh, int *lenp, int connectable) | ||
757 | { | ||
758 | int len = *lenp; | ||
759 | struct inode *inode = de->d_inode; | ||
760 | u32 ipos_h, ipos_m, ipos_l; | ||
761 | |||
762 | if (len < 5) { | ||
763 | *lenp = 5; | ||
764 | return 255; /* no room */ | ||
765 | } | ||
766 | |||
767 | ipos_h = MSDOS_I(inode)->i_pos >> 8; | ||
768 | ipos_m = (MSDOS_I(inode)->i_pos & 0xf0) << 24; | ||
769 | ipos_l = (MSDOS_I(inode)->i_pos & 0x0f) << 28; | ||
770 | *lenp = 5; | ||
771 | fh[0] = inode->i_ino; | ||
772 | fh[1] = inode->i_generation; | ||
773 | fh[2] = ipos_h; | ||
774 | fh[3] = ipos_m | MSDOS_I(inode)->i_logstart; | ||
775 | spin_lock(&de->d_lock); | ||
776 | fh[4] = ipos_l | MSDOS_I(de->d_parent->d_inode)->i_logstart; | ||
777 | spin_unlock(&de->d_lock); | ||
778 | return 3; | ||
779 | } | ||
780 | |||
781 | static struct dentry *fat_get_parent(struct dentry *child) | ||
782 | { | ||
783 | struct super_block *sb = child->d_sb; | ||
784 | struct buffer_head *bh; | ||
785 | struct msdos_dir_entry *de; | ||
786 | loff_t i_pos; | ||
787 | struct dentry *parent; | ||
788 | struct inode *inode; | ||
789 | int err; | ||
790 | |||
791 | lock_super(sb); | ||
792 | |||
793 | err = fat_get_dotdot_entry(child->d_inode, &bh, &de, &i_pos); | ||
794 | if (err) { | ||
795 | parent = ERR_PTR(err); | ||
796 | goto out; | ||
797 | } | ||
798 | inode = fat_build_inode(sb, de, i_pos); | ||
799 | brelse(bh); | ||
800 | |||
801 | parent = d_obtain_alias(inode); | ||
802 | out: | ||
803 | unlock_super(sb); | ||
804 | |||
805 | return parent; | ||
806 | } | ||
807 | |||
706 | static const struct export_operations fat_export_ops = { | 808 | static const struct export_operations fat_export_ops = { |
809 | .encode_fh = fat_encode_fh, | ||
707 | .fh_to_dentry = fat_fh_to_dentry, | 810 | .fh_to_dentry = fat_fh_to_dentry, |
708 | .fh_to_parent = fat_fh_to_parent, | ||
709 | .get_parent = fat_get_parent, | 811 | .get_parent = fat_get_parent, |
710 | }; | 812 | }; |
711 | 813 | ||
712 | static int fat_show_options(struct seq_file *m, struct dentry *root) | 814 | static int fat_show_options(struct seq_file *m, struct vfsmount *mnt) |
713 | { | 815 | { |
714 | struct msdos_sb_info *sbi = MSDOS_SB(root->d_sb); | 816 | struct msdos_sb_info *sbi = MSDOS_SB(mnt->mnt_sb); |
715 | struct fat_mount_options *opts = &sbi->options; | 817 | struct fat_mount_options *opts = &sbi->options; |
716 | int isvfat = opts->isvfat; | 818 | int isvfat = opts->isvfat; |
717 | 819 | ||
718 | if (!uid_eq(opts->fs_uid, GLOBAL_ROOT_UID)) | 820 | if (opts->fs_uid != 0) |
719 | seq_printf(m, ",uid=%u", | 821 | seq_printf(m, ",uid=%u", opts->fs_uid); |
720 | from_kuid_munged(&init_user_ns, opts->fs_uid)); | 822 | if (opts->fs_gid != 0) |
721 | if (!gid_eq(opts->fs_gid, GLOBAL_ROOT_GID)) | 823 | seq_printf(m, ",gid=%u", opts->fs_gid); |
722 | seq_printf(m, ",gid=%u", | ||
723 | from_kgid_munged(&init_user_ns, opts->fs_gid)); | ||
724 | seq_printf(m, ",fmask=%04o", opts->fs_fmask); | 824 | seq_printf(m, ",fmask=%04o", opts->fs_fmask); |
725 | seq_printf(m, ",dmask=%04o", opts->fs_dmask); | 825 | seq_printf(m, ",dmask=%04o", opts->fs_dmask); |
726 | if (opts->allow_utime) | 826 | if (opts->allow_utime) |
727 | seq_printf(m, ",allow_utime=%04o", opts->allow_utime); | 827 | seq_printf(m, ",allow_utime=%04o", opts->allow_utime); |
728 | if (sbi->nls_disk) | 828 | if (sbi->nls_disk) |
729 | /* strip "cp" prefix from displayed option */ | 829 | seq_printf(m, ",codepage=%s", sbi->nls_disk->charset); |
730 | seq_printf(m, ",codepage=%s", &sbi->nls_disk->charset[2]); | ||
731 | if (isvfat) { | 830 | if (isvfat) { |
732 | if (sbi->nls_io) | 831 | if (sbi->nls_io) |
733 | seq_printf(m, ",iocharset=%s", sbi->nls_io->charset); | 832 | seq_printf(m, ",iocharset=%s", sbi->nls_io->charset); |
@@ -756,8 +855,6 @@ static int fat_show_options(struct seq_file *m, struct dentry *root) | |||
756 | seq_puts(m, ",usefree"); | 855 | seq_puts(m, ",usefree"); |
757 | if (opts->quiet) | 856 | if (opts->quiet) |
758 | seq_puts(m, ",quiet"); | 857 | seq_puts(m, ",quiet"); |
759 | if (opts->nfs) | ||
760 | seq_puts(m, ",nfs"); | ||
761 | if (opts->showexec) | 858 | if (opts->showexec) |
762 | seq_puts(m, ",showexec"); | 859 | seq_puts(m, ",showexec"); |
763 | if (opts->sys_immutable) | 860 | if (opts->sys_immutable) |
@@ -779,12 +876,8 @@ static int fat_show_options(struct seq_file *m, struct dentry *root) | |||
779 | } | 876 | } |
780 | if (opts->flush) | 877 | if (opts->flush) |
781 | seq_puts(m, ",flush"); | 878 | seq_puts(m, ",flush"); |
782 | if (opts->tz_set) { | 879 | if (opts->tz_utc) |
783 | if (opts->time_offset) | 880 | seq_puts(m, ",tz=UTC"); |
784 | seq_printf(m, ",time_offset=%d", opts->time_offset); | ||
785 | else | ||
786 | seq_puts(m, ",tz=UTC"); | ||
787 | } | ||
788 | if (opts->errors == FAT_ERRORS_CONT) | 881 | if (opts->errors == FAT_ERRORS_CONT) |
789 | seq_puts(m, ",errors=continue"); | 882 | seq_puts(m, ",errors=continue"); |
790 | else if (opts->errors == FAT_ERRORS_PANIC) | 883 | else if (opts->errors == FAT_ERRORS_PANIC) |
@@ -805,9 +898,8 @@ enum { | |||
805 | Opt_charset, Opt_shortname_lower, Opt_shortname_win95, | 898 | Opt_charset, Opt_shortname_lower, Opt_shortname_win95, |
806 | Opt_shortname_winnt, Opt_shortname_mixed, Opt_utf8_no, Opt_utf8_yes, | 899 | Opt_shortname_winnt, Opt_shortname_mixed, Opt_utf8_no, Opt_utf8_yes, |
807 | Opt_uni_xl_no, Opt_uni_xl_yes, Opt_nonumtail_no, Opt_nonumtail_yes, | 900 | Opt_uni_xl_no, Opt_uni_xl_yes, Opt_nonumtail_no, Opt_nonumtail_yes, |
808 | Opt_obsolete, Opt_flush, Opt_tz_utc, Opt_rodir, Opt_err_cont, | 901 | Opt_obsolate, Opt_flush, Opt_tz_utc, Opt_rodir, Opt_err_cont, |
809 | Opt_err_panic, Opt_err_ro, Opt_discard, Opt_nfs, Opt_time_offset, | 902 | Opt_err_panic, Opt_err_ro, Opt_discard, Opt_err, |
810 | Opt_err, | ||
811 | }; | 903 | }; |
812 | 904 | ||
813 | static const match_table_t fat_tokens = { | 905 | static const match_table_t fat_tokens = { |
@@ -832,23 +924,21 @@ static const match_table_t fat_tokens = { | |||
832 | {Opt_immutable, "sys_immutable"}, | 924 | {Opt_immutable, "sys_immutable"}, |
833 | {Opt_flush, "flush"}, | 925 | {Opt_flush, "flush"}, |
834 | {Opt_tz_utc, "tz=UTC"}, | 926 | {Opt_tz_utc, "tz=UTC"}, |
835 | {Opt_time_offset, "time_offset=%d"}, | ||
836 | {Opt_err_cont, "errors=continue"}, | 927 | {Opt_err_cont, "errors=continue"}, |
837 | {Opt_err_panic, "errors=panic"}, | 928 | {Opt_err_panic, "errors=panic"}, |
838 | {Opt_err_ro, "errors=remount-ro"}, | 929 | {Opt_err_ro, "errors=remount-ro"}, |
839 | {Opt_discard, "discard"}, | 930 | {Opt_discard, "discard"}, |
840 | {Opt_nfs, "nfs"}, | 931 | {Opt_obsolate, "conv=binary"}, |
841 | {Opt_obsolete, "conv=binary"}, | 932 | {Opt_obsolate, "conv=text"}, |
842 | {Opt_obsolete, "conv=text"}, | 933 | {Opt_obsolate, "conv=auto"}, |
843 | {Opt_obsolete, "conv=auto"}, | 934 | {Opt_obsolate, "conv=b"}, |
844 | {Opt_obsolete, "conv=b"}, | 935 | {Opt_obsolate, "conv=t"}, |
845 | {Opt_obsolete, "conv=t"}, | 936 | {Opt_obsolate, "conv=a"}, |
846 | {Opt_obsolete, "conv=a"}, | 937 | {Opt_obsolate, "fat=%u"}, |
847 | {Opt_obsolete, "fat=%u"}, | 938 | {Opt_obsolate, "blocksize=%u"}, |
848 | {Opt_obsolete, "blocksize=%u"}, | 939 | {Opt_obsolate, "cvf_format=%20s"}, |
849 | {Opt_obsolete, "cvf_format=%20s"}, | 940 | {Opt_obsolate, "cvf_options=%100s"}, |
850 | {Opt_obsolete, "cvf_options=%100s"}, | 941 | {Opt_obsolate, "posix"}, |
851 | {Opt_obsolete, "posix"}, | ||
852 | {Opt_err, NULL}, | 942 | {Opt_err, NULL}, |
853 | }; | 943 | }; |
854 | static const match_table_t msdos_tokens = { | 944 | static const match_table_t msdos_tokens = { |
@@ -917,8 +1007,7 @@ static int parse_options(struct super_block *sb, char *options, int is_vfat, | |||
917 | opts->utf8 = opts->unicode_xlate = 0; | 1007 | opts->utf8 = opts->unicode_xlate = 0; |
918 | opts->numtail = 1; | 1008 | opts->numtail = 1; |
919 | opts->usefree = opts->nocase = 0; | 1009 | opts->usefree = opts->nocase = 0; |
920 | opts->tz_set = 0; | 1010 | opts->tz_utc = 0; |
921 | opts->nfs = 0; | ||
922 | opts->errors = FAT_ERRORS_RO; | 1011 | opts->errors = FAT_ERRORS_RO; |
923 | *debug = 0; | 1012 | *debug = 0; |
924 | 1013 | ||
@@ -973,57 +1062,44 @@ static int parse_options(struct super_block *sb, char *options, int is_vfat, | |||
973 | break; | 1062 | break; |
974 | case Opt_uid: | 1063 | case Opt_uid: |
975 | if (match_int(&args[0], &option)) | 1064 | if (match_int(&args[0], &option)) |
976 | return -EINVAL; | 1065 | return 0; |
977 | opts->fs_uid = make_kuid(current_user_ns(), option); | 1066 | opts->fs_uid = option; |
978 | if (!uid_valid(opts->fs_uid)) | ||
979 | return -EINVAL; | ||
980 | break; | 1067 | break; |
981 | case Opt_gid: | 1068 | case Opt_gid: |
982 | if (match_int(&args[0], &option)) | 1069 | if (match_int(&args[0], &option)) |
983 | return -EINVAL; | 1070 | return 0; |
984 | opts->fs_gid = make_kgid(current_user_ns(), option); | 1071 | opts->fs_gid = option; |
985 | if (!gid_valid(opts->fs_gid)) | ||
986 | return -EINVAL; | ||
987 | break; | 1072 | break; |
988 | case Opt_umask: | 1073 | case Opt_umask: |
989 | if (match_octal(&args[0], &option)) | 1074 | if (match_octal(&args[0], &option)) |
990 | return -EINVAL; | 1075 | return 0; |
991 | opts->fs_fmask = opts->fs_dmask = option; | 1076 | opts->fs_fmask = opts->fs_dmask = option; |
992 | break; | 1077 | break; |
993 | case Opt_dmask: | 1078 | case Opt_dmask: |
994 | if (match_octal(&args[0], &option)) | 1079 | if (match_octal(&args[0], &option)) |
995 | return -EINVAL; | 1080 | return 0; |
996 | opts->fs_dmask = option; | 1081 | opts->fs_dmask = option; |
997 | break; | 1082 | break; |
998 | case Opt_fmask: | 1083 | case Opt_fmask: |
999 | if (match_octal(&args[0], &option)) | 1084 | if (match_octal(&args[0], &option)) |
1000 | return -EINVAL; | 1085 | return 0; |
1001 | opts->fs_fmask = option; | 1086 | opts->fs_fmask = option; |
1002 | break; | 1087 | break; |
1003 | case Opt_allow_utime: | 1088 | case Opt_allow_utime: |
1004 | if (match_octal(&args[0], &option)) | 1089 | if (match_octal(&args[0], &option)) |
1005 | return -EINVAL; | 1090 | return 0; |
1006 | opts->allow_utime = option & (S_IWGRP | S_IWOTH); | 1091 | opts->allow_utime = option & (S_IWGRP | S_IWOTH); |
1007 | break; | 1092 | break; |
1008 | case Opt_codepage: | 1093 | case Opt_codepage: |
1009 | if (match_int(&args[0], &option)) | 1094 | if (match_int(&args[0], &option)) |
1010 | return -EINVAL; | 1095 | return 0; |
1011 | opts->codepage = option; | 1096 | opts->codepage = option; |
1012 | break; | 1097 | break; |
1013 | case Opt_flush: | 1098 | case Opt_flush: |
1014 | opts->flush = 1; | 1099 | opts->flush = 1; |
1015 | break; | 1100 | break; |
1016 | case Opt_time_offset: | ||
1017 | if (match_int(&args[0], &option)) | ||
1018 | return -EINVAL; | ||
1019 | if (option < -12 * 60 || option > 12 * 60) | ||
1020 | return -EINVAL; | ||
1021 | opts->tz_set = 1; | ||
1022 | opts->time_offset = option; | ||
1023 | break; | ||
1024 | case Opt_tz_utc: | 1101 | case Opt_tz_utc: |
1025 | opts->tz_set = 1; | 1102 | opts->tz_utc = 1; |
1026 | opts->time_offset = 0; | ||
1027 | break; | 1103 | break; |
1028 | case Opt_err_cont: | 1104 | case Opt_err_cont: |
1029 | opts->errors = FAT_ERRORS_CONT; | 1105 | opts->errors = FAT_ERRORS_CONT; |
@@ -1092,12 +1168,9 @@ static int parse_options(struct super_block *sb, char *options, int is_vfat, | |||
1092 | case Opt_discard: | 1168 | case Opt_discard: |
1093 | opts->discard = 1; | 1169 | opts->discard = 1; |
1094 | break; | 1170 | break; |
1095 | case Opt_nfs: | ||
1096 | opts->nfs = 1; | ||
1097 | break; | ||
1098 | 1171 | ||
1099 | /* obsolete mount options */ | 1172 | /* obsolete mount options */ |
1100 | case Opt_obsolete: | 1173 | case Opt_obsolate: |
1101 | fat_msg(sb, KERN_INFO, "\"%s\" option is obsolete, " | 1174 | fat_msg(sb, KERN_INFO, "\"%s\" option is obsolete, " |
1102 | "not supported now", p); | 1175 | "not supported now", p); |
1103 | break; | 1176 | break; |
@@ -1160,7 +1233,7 @@ static int fat_read_root(struct inode *inode) | |||
1160 | fat_save_attrs(inode, ATTR_DIR); | 1233 | fat_save_attrs(inode, ATTR_DIR); |
1161 | inode->i_mtime.tv_sec = inode->i_atime.tv_sec = inode->i_ctime.tv_sec = 0; | 1234 | inode->i_mtime.tv_sec = inode->i_atime.tv_sec = inode->i_ctime.tv_sec = 0; |
1162 | inode->i_mtime.tv_nsec = inode->i_atime.tv_nsec = inode->i_ctime.tv_nsec = 0; | 1235 | inode->i_mtime.tv_nsec = inode->i_atime.tv_nsec = inode->i_ctime.tv_nsec = 0; |
1163 | set_nlink(inode, fat_subdirs(inode)+2); | 1236 | inode->i_nlink = fat_subdirs(inode)+2; |
1164 | 1237 | ||
1165 | return 0; | 1238 | return 0; |
1166 | } | 1239 | } |
@@ -1172,9 +1245,9 @@ int fat_fill_super(struct super_block *sb, void *data, int silent, int isvfat, | |||
1172 | void (*setup)(struct super_block *)) | 1245 | void (*setup)(struct super_block *)) |
1173 | { | 1246 | { |
1174 | struct inode *root_inode = NULL, *fat_inode = NULL; | 1247 | struct inode *root_inode = NULL, *fat_inode = NULL; |
1175 | struct inode *fsinfo_inode = NULL; | ||
1176 | struct buffer_head *bh; | 1248 | struct buffer_head *bh; |
1177 | struct fat_boot_sector *b; | 1249 | struct fat_boot_sector *b; |
1250 | struct fat_boot_bsx *bsx; | ||
1178 | struct msdos_sb_info *sbi; | 1251 | struct msdos_sb_info *sbi; |
1179 | u16 logical_sector_size; | 1252 | u16 logical_sector_size; |
1180 | u32 total_sectors, total_clusters, fat_clusters, rootdir_sectors; | 1253 | u32 total_sectors, total_clusters, fat_clusters, rootdir_sectors; |
@@ -1285,7 +1358,6 @@ int fat_fill_super(struct super_block *sb, void *data, int silent, int isvfat, | |||
1285 | b = (struct fat_boot_sector *) bh->b_data; | 1358 | b = (struct fat_boot_sector *) bh->b_data; |
1286 | } | 1359 | } |
1287 | 1360 | ||
1288 | mutex_init(&sbi->s_lock); | ||
1289 | sbi->cluster_size = sb->s_blocksize * sbi->sec_per_clus; | 1361 | sbi->cluster_size = sb->s_blocksize * sbi->sec_per_clus; |
1290 | sbi->cluster_bits = ffs(sbi->cluster_size) - 1; | 1362 | sbi->cluster_bits = ffs(sbi->cluster_size) - 1; |
1291 | sbi->fats = b->fats; | 1363 | sbi->fats = b->fats; |
@@ -1320,6 +1392,8 @@ int fat_fill_super(struct super_block *sb, void *data, int silent, int isvfat, | |||
1320 | goto out_fail; | 1392 | goto out_fail; |
1321 | } | 1393 | } |
1322 | 1394 | ||
1395 | bsx = (struct fat_boot_bsx *)(bh->b_data + FAT32_BSX_OFFSET); | ||
1396 | |||
1323 | fsinfo = (struct fat_boot_fsinfo *)fsinfo_bh->b_data; | 1397 | fsinfo = (struct fat_boot_fsinfo *)fsinfo_bh->b_data; |
1324 | if (!IS_FSINFO(fsinfo)) { | 1398 | if (!IS_FSINFO(fsinfo)) { |
1325 | fat_msg(sb, KERN_WARNING, "Invalid FSINFO signature: " | 1399 | fat_msg(sb, KERN_WARNING, "Invalid FSINFO signature: " |
@@ -1335,8 +1409,14 @@ int fat_fill_super(struct super_block *sb, void *data, int silent, int isvfat, | |||
1335 | } | 1409 | } |
1336 | 1410 | ||
1337 | brelse(fsinfo_bh); | 1411 | brelse(fsinfo_bh); |
1412 | } else { | ||
1413 | bsx = (struct fat_boot_bsx *)(bh->b_data + FAT16_BSX_OFFSET); | ||
1338 | } | 1414 | } |
1339 | 1415 | ||
1416 | /* interpret volume ID as a little endian 32 bit integer */ | ||
1417 | sbi->vol_id = (((u32)bsx->vol_id[0]) | ((u32)bsx->vol_id[1] << 8) | | ||
1418 | ((u32)bsx->vol_id[2] << 16) | ((u32)bsx->vol_id[3] << 24)); | ||
1419 | |||
1340 | sbi->dir_per_block = sb->s_blocksize / sizeof(struct msdos_dir_entry); | 1420 | sbi->dir_per_block = sb->s_blocksize / sizeof(struct msdos_dir_entry); |
1341 | sbi->dir_per_block_bits = ffs(sbi->dir_per_block) - 1; | 1421 | sbi->dir_per_block_bits = ffs(sbi->dir_per_block) - 1; |
1342 | 1422 | ||
@@ -1344,7 +1424,7 @@ int fat_fill_super(struct super_block *sb, void *data, int silent, int isvfat, | |||
1344 | sbi->dir_entries = get_unaligned_le16(&b->dir_entries); | 1424 | sbi->dir_entries = get_unaligned_le16(&b->dir_entries); |
1345 | if (sbi->dir_entries & (sbi->dir_per_block - 1)) { | 1425 | if (sbi->dir_entries & (sbi->dir_per_block - 1)) { |
1346 | if (!silent) | 1426 | if (!silent) |
1347 | fat_msg(sb, KERN_ERR, "bogus directory-entries per block" | 1427 | fat_msg(sb, KERN_ERR, "bogus directroy-entries per block" |
1348 | " (%u)", sbi->dir_entries); | 1428 | " (%u)", sbi->dir_entries); |
1349 | brelse(bh); | 1429 | brelse(bh); |
1350 | goto out_invalid; | 1430 | goto out_invalid; |
@@ -1386,7 +1466,6 @@ int fat_fill_super(struct super_block *sb, void *data, int silent, int isvfat, | |||
1386 | 1466 | ||
1387 | /* set up enough so that it can read an inode */ | 1467 | /* set up enough so that it can read an inode */ |
1388 | fat_hash_init(sb); | 1468 | fat_hash_init(sb); |
1389 | dir_hash_init(sb); | ||
1390 | fat_ent_access_init(sb); | 1469 | fat_ent_access_init(sb); |
1391 | 1470 | ||
1392 | /* | 1471 | /* |
@@ -1421,41 +1500,22 @@ int fat_fill_super(struct super_block *sb, void *data, int silent, int isvfat, | |||
1421 | goto out_fail; | 1500 | goto out_fail; |
1422 | MSDOS_I(fat_inode)->i_pos = 0; | 1501 | MSDOS_I(fat_inode)->i_pos = 0; |
1423 | sbi->fat_inode = fat_inode; | 1502 | sbi->fat_inode = fat_inode; |
1424 | |||
1425 | fsinfo_inode = new_inode(sb); | ||
1426 | if (!fsinfo_inode) | ||
1427 | goto out_fail; | ||
1428 | fsinfo_inode->i_ino = MSDOS_FSINFO_INO; | ||
1429 | sbi->fsinfo_inode = fsinfo_inode; | ||
1430 | insert_inode_hash(fsinfo_inode); | ||
1431 | |||
1432 | root_inode = new_inode(sb); | 1503 | root_inode = new_inode(sb); |
1433 | if (!root_inode) | 1504 | if (!root_inode) |
1434 | goto out_fail; | 1505 | goto out_fail; |
1435 | root_inode->i_ino = MSDOS_ROOT_INO; | 1506 | root_inode->i_ino = MSDOS_ROOT_INO; |
1436 | root_inode->i_version = 1; | 1507 | root_inode->i_version = 1; |
1437 | error = fat_read_root(root_inode); | 1508 | error = fat_read_root(root_inode); |
1438 | if (error < 0) { | 1509 | if (error < 0) |
1439 | iput(root_inode); | ||
1440 | goto out_fail; | 1510 | goto out_fail; |
1441 | } | ||
1442 | error = -ENOMEM; | 1511 | error = -ENOMEM; |
1443 | insert_inode_hash(root_inode); | 1512 | insert_inode_hash(root_inode); |
1444 | fat_attach(root_inode, 0); | 1513 | sb->s_root = d_alloc_root(root_inode); |
1445 | sb->s_root = d_make_root(root_inode); | ||
1446 | if (!sb->s_root) { | 1514 | if (!sb->s_root) { |
1447 | fat_msg(sb, KERN_ERR, "get root inode failed"); | 1515 | fat_msg(sb, KERN_ERR, "get root inode failed"); |
1448 | goto out_fail; | 1516 | goto out_fail; |
1449 | } | 1517 | } |
1450 | 1518 | ||
1451 | if (sbi->options.discard) { | ||
1452 | struct request_queue *q = bdev_get_queue(sb->s_bdev); | ||
1453 | if (!blk_queue_discard(q)) | ||
1454 | fat_msg(sb, KERN_WARNING, | ||
1455 | "mounting with \"discard\" option, but " | ||
1456 | "the device does not support discard"); | ||
1457 | } | ||
1458 | |||
1459 | return 0; | 1519 | return 0; |
1460 | 1520 | ||
1461 | out_invalid: | 1521 | out_invalid: |
@@ -1464,10 +1524,10 @@ out_invalid: | |||
1464 | fat_msg(sb, KERN_INFO, "Can't find a valid FAT filesystem"); | 1524 | fat_msg(sb, KERN_INFO, "Can't find a valid FAT filesystem"); |
1465 | 1525 | ||
1466 | out_fail: | 1526 | out_fail: |
1467 | if (fsinfo_inode) | ||
1468 | iput(fsinfo_inode); | ||
1469 | if (fat_inode) | 1527 | if (fat_inode) |
1470 | iput(fat_inode); | 1528 | iput(fat_inode); |
1529 | if (root_inode) | ||
1530 | iput(root_inode); | ||
1471 | unload_nls(sbi->nls_io); | 1531 | unload_nls(sbi->nls_io); |
1472 | unload_nls(sbi->nls_disk); | 1532 | unload_nls(sbi->nls_disk); |
1473 | if (sbi->options.iocharset != fat_default_iocharset) | 1533 | if (sbi->options.iocharset != fat_default_iocharset) |
@@ -1489,14 +1549,18 @@ static int writeback_inode(struct inode *inode) | |||
1489 | { | 1549 | { |
1490 | 1550 | ||
1491 | int ret; | 1551 | int ret; |
1492 | 1552 | struct address_space *mapping = inode->i_mapping; | |
1493 | /* if we used wait=1, sync_inode_metadata waits for the io for the | 1553 | struct writeback_control wbc = { |
1494 | * inode to finish. So wait=0 is sent down to sync_inode_metadata | 1554 | .sync_mode = WB_SYNC_NONE, |
1555 | .nr_to_write = 0, | ||
1556 | }; | ||
1557 | /* if we used WB_SYNC_ALL, sync_inode waits for the io for the | ||
1558 | * inode to finish. So WB_SYNC_NONE is sent down to sync_inode | ||
1495 | * and filemap_fdatawrite is used for the data blocks | 1559 | * and filemap_fdatawrite is used for the data blocks |
1496 | */ | 1560 | */ |
1497 | ret = sync_inode_metadata(inode, 0); | 1561 | ret = sync_inode(inode, &wbc); |
1498 | if (!ret) | 1562 | if (!ret) |
1499 | ret = filemap_fdatawrite(inode->i_mapping); | 1563 | ret = filemap_fdatawrite(mapping); |
1500 | return ret; | 1564 | return ret; |
1501 | } | 1565 | } |
1502 | 1566 | ||