diff options
author | Thomas Gleixner <tglx@linutronix.de> | 2010-02-21 20:17:22 +0100 |
---|---|---|
committer | Thomas Gleixner <tglx@linutronix.de> | 2010-02-21 20:17:22 +0100 |
commit | 5f854cfc024622e4aae14d7cf422f6ff86278688 (patch) | |
tree | 426e77c6f6e4939c80440bf1fabcb020e3ee145b /fs/fat | |
parent | cc24da0742870f152ddf1002aa39dfcd83f7cf9c (diff) | |
parent | 4ec62b2b2e6bd7ddef7b6cea6e5db7b5578a6532 (diff) | |
download | lwn-5f854cfc024622e4aae14d7cf422f6ff86278688.tar.gz lwn-5f854cfc024622e4aae14d7cf422f6ff86278688.zip |
Forward to 2.6.33-rc8
Merge branch 'linus' into rt/head with a pile of conflicts.
Signed-off-by: Thomas Gleixner <tglx@linutronix.de>
Diffstat (limited to 'fs/fat')
-rw-r--r-- | fs/fat/fat.h | 5 | ||||
-rw-r--r-- | fs/fat/fatent.c | 25 | ||||
-rw-r--r-- | fs/fat/file.c | 22 | ||||
-rw-r--r-- | fs/fat/inode.c | 42 | ||||
-rw-r--r-- | fs/fat/misc.c | 69 | ||||
-rw-r--r-- | fs/fat/namei_vfat.c | 15 |
6 files changed, 86 insertions, 92 deletions
diff --git a/fs/fat/fat.h b/fs/fat/fat.h index adb0e72a176d..e6efdfa0f6db 100644 --- a/fs/fat/fat.h +++ b/fs/fat/fat.h @@ -44,7 +44,8 @@ struct fat_mount_options { nocase:1, /* Does this need case conversion? 0=need case conversion*/ usefree:1, /* Use free_clusters for FAT32 */ tz_utc:1, /* Filesystem timestamps are in UTC */ - rodir:1; /* allow ATTR_RO for directory */ + rodir:1, /* allow ATTR_RO for directory */ + discard:1; /* Issue discard requests on deletions */ }; #define FAT_HASH_BITS 8 @@ -323,7 +324,7 @@ extern int fat_flush_inodes(struct super_block *sb, struct inode *i1, /* fat/misc.c */ extern void fat_fs_error(struct super_block *s, const char *fmt, ...) __attribute__ ((format (printf, 2, 3))) __cold; -extern void fat_clusters_flush(struct super_block *sb); +extern int fat_clusters_flush(struct super_block *sb); extern int fat_chain_add(struct inode *inode, int new_dclus, int nr_cluster); extern void fat_time_fat2unix(struct msdos_sb_info *sbi, struct timespec *ts, __le16 __time, __le16 __date, u8 time_cs); diff --git a/fs/fat/fatent.c b/fs/fat/fatent.c index a81037721a6f..81184d3b75a3 100644 --- a/fs/fat/fatent.c +++ b/fs/fat/fatent.c @@ -566,16 +566,21 @@ int fat_free_clusters(struct inode *inode, int cluster) goto error; } - /* - * Issue discard for the sectors we no longer care about, - * batching contiguous clusters into one request - */ - if (cluster != fatent.entry + 1) { - int nr_clus = fatent.entry - first_cl + 1; - - sb_issue_discard(sb, fat_clus_to_blknr(sbi, first_cl), - nr_clus * sbi->sec_per_clus); - first_cl = cluster; + if (sbi->options.discard) { + /* + * Issue discard for the sectors we no longer + * care about, batching contiguous clusters + * into one request + */ + if (cluster != fatent.entry + 1) { + int nr_clus = fatent.entry - first_cl + 1; + + sb_issue_discard(sb, + fat_clus_to_blknr(sbi, first_cl), + nr_clus * sbi->sec_per_clus); + + first_cl = cluster; + } } ops->ent_put(&fatent, FAT_ENT_FREE); diff --git a/fs/fat/file.c b/fs/fat/file.c index f042b965c95c..e8c159de236b 100644 --- a/fs/fat/file.c +++ b/fs/fat/file.c @@ -176,8 +176,26 @@ static int fat_cont_expand(struct inode *inode, loff_t size) inode->i_ctime = inode->i_mtime = CURRENT_TIME_SEC; mark_inode_dirty(inode); - if (IS_SYNC(inode)) - err = sync_page_range_nolock(inode, mapping, start, count); + if (IS_SYNC(inode)) { + int err2; + + /* + * Opencode syncing since we don't have a file open to use + * standard fsync path. + */ + err = filemap_fdatawrite_range(mapping, start, + start + count - 1); + err2 = sync_mapping_buffers(mapping); + if (!err) + err = err2; + err2 = write_inode_now(inode, 1); + if (!err) + err = err2; + if (!err) { + err = filemap_fdatawait_range(mapping, start, + start + count - 1); + } + } out: return err; } diff --git a/fs/fat/inode.c b/fs/fat/inode.c index da8dbb1ac5f9..5c5e1cd62414 100644 --- a/fs/fat/inode.c +++ b/fs/fat/inode.c @@ -451,12 +451,16 @@ static void fat_write_super(struct super_block *sb) static int fat_sync_fs(struct super_block *sb, int wait) { - lock_super(sb); - fat_clusters_flush(sb); - sb->s_dirt = 0; - unlock_super(sb); + int err = 0; - return 0; + if (sb->s_dirt) { + lock_super(sb); + sb->s_dirt = 0; + err = fat_clusters_flush(sb); + unlock_super(sb); + } + + return err; } static void fat_put_super(struct super_block *sb) @@ -470,19 +474,11 @@ static void fat_put_super(struct super_block *sb) iput(sbi->fat_inode); - if (sbi->nls_disk) { - unload_nls(sbi->nls_disk); - sbi->nls_disk = NULL; - sbi->options.codepage = fat_default_codepage; - } - if (sbi->nls_io) { - unload_nls(sbi->nls_io); - sbi->nls_io = NULL; - } - if (sbi->options.iocharset != fat_default_iocharset) { + unload_nls(sbi->nls_disk); + unload_nls(sbi->nls_io); + + if (sbi->options.iocharset != fat_default_iocharset) kfree(sbi->options.iocharset); - sbi->options.iocharset = fat_default_iocharset; - } sb->s_fs_info = NULL; kfree(sbi); @@ -820,7 +816,7 @@ static int fat_show_options(struct seq_file *m, struct vfsmount *mnt) seq_puts(m, ",shortname=mixed"); break; case VFAT_SFN_DISPLAY_LOWER | VFAT_SFN_CREATE_WIN95: - /* seq_puts(m, ",shortname=lower"); */ + seq_puts(m, ",shortname=lower"); break; default: seq_puts(m, ",shortname=unknown"); @@ -862,6 +858,8 @@ static int fat_show_options(struct seq_file *m, struct vfsmount *mnt) seq_puts(m, ",errors=panic"); else seq_puts(m, ",errors=remount-ro"); + if (opts->discard) + seq_puts(m, ",discard"); return 0; } @@ -875,7 +873,7 @@ enum { Opt_shortname_winnt, Opt_shortname_mixed, Opt_utf8_no, Opt_utf8_yes, Opt_uni_xl_no, Opt_uni_xl_yes, Opt_nonumtail_no, Opt_nonumtail_yes, Opt_obsolate, Opt_flush, Opt_tz_utc, Opt_rodir, Opt_err_cont, - Opt_err_panic, Opt_err_ro, Opt_err, + Opt_err_panic, Opt_err_ro, Opt_discard, Opt_err, }; static const match_table_t fat_tokens = { @@ -903,6 +901,7 @@ static const match_table_t fat_tokens = { {Opt_err_cont, "errors=continue"}, {Opt_err_panic, "errors=panic"}, {Opt_err_ro, "errors=remount-ro"}, + {Opt_discard, "discard"}, {Opt_obsolate, "conv=binary"}, {Opt_obsolate, "conv=text"}, {Opt_obsolate, "conv=auto"}, @@ -971,7 +970,7 @@ static int parse_options(char *options, int is_vfat, int silent, int *debug, opts->codepage = fat_default_codepage; opts->iocharset = fat_default_iocharset; if (is_vfat) { - opts->shortname = VFAT_SFN_DISPLAY_LOWER|VFAT_SFN_CREATE_WIN95; + opts->shortname = VFAT_SFN_DISPLAY_WINNT|VFAT_SFN_CREATE_WIN95; opts->rodir = 0; } else { opts->shortname = 0; @@ -1140,6 +1139,9 @@ static int parse_options(char *options, int is_vfat, int silent, int *debug, case Opt_rodir: opts->rodir = 1; break; + case Opt_discard: + opts->discard = 1; + break; /* obsolete mount options */ case Opt_obsolate: diff --git a/fs/fat/misc.c b/fs/fat/misc.c index a6c20473dfd7..d3da05f26465 100644 --- a/fs/fat/misc.c +++ b/fs/fat/misc.c @@ -9,6 +9,7 @@ #include <linux/module.h> #include <linux/fs.h> #include <linux/buffer_head.h> +#include <linux/time.h> #include "fat.h" /* @@ -43,19 +44,19 @@ EXPORT_SYMBOL_GPL(fat_fs_error); /* Flushes the number of free clusters on FAT32 */ /* XXX: Need to write one per FSINFO block. Currently only writes 1 */ -void fat_clusters_flush(struct super_block *sb) +int fat_clusters_flush(struct super_block *sb) { struct msdos_sb_info *sbi = MSDOS_SB(sb); struct buffer_head *bh; struct fat_boot_fsinfo *fsinfo; if (sbi->fat_bits != 32) - return; + return 0; bh = sb_bread(sb, sbi->fsinfo_sector); if (bh == NULL) { printk(KERN_ERR "FAT: bread failed in fat_clusters_flush\n"); - return; + return -EIO; } fsinfo = (struct fat_boot_fsinfo *)bh->b_data; @@ -74,6 +75,8 @@ void fat_clusters_flush(struct super_block *sb) mark_buffer_dirty(bh); } brelse(bh); + + return 0; } /* @@ -119,8 +122,8 @@ int fat_chain_add(struct inode *inode, int new_dclus, int nr_cluster) MSDOS_I(inode)->i_start = new_dclus; MSDOS_I(inode)->i_logstart = new_dclus; /* - * Since generic_osync_inode() synchronize later if - * this is not directory, we don't here. + * Since generic_write_sync() synchronizes regular files later, + * we sync here only directories. */ if (S_ISDIR(inode->i_mode) && IS_DIRSYNC(inode)) { ret = fat_sync_inode(inode); @@ -155,10 +158,6 @@ extern struct timezone sys_tz; #define SECS_PER_MIN 60 #define SECS_PER_HOUR (60 * 60) #define SECS_PER_DAY (SECS_PER_HOUR * 24) -#define UNIX_SECS_1980 315532800L -#if BITS_PER_LONG == 64 -#define UNIX_SECS_2108 4354819200L -#endif /* days between 1.1.70 and 1.1.80 (2 leap days) */ #define DAYS_DELTA (365 * 10 + 2) /* 120 (2100 - 1980) isn't leap year */ @@ -211,58 +210,35 @@ void fat_time_fat2unix(struct msdos_sb_info *sbi, struct timespec *ts, void fat_time_unix2fat(struct msdos_sb_info *sbi, struct timespec *ts, __le16 *time, __le16 *date, u8 *time_cs) { - time_t second = ts->tv_sec; - time_t day, leap_day, month, year; + struct tm tm; + time_to_tm(ts->tv_sec, sbi->options.tz_utc ? 0 : + -sys_tz.tz_minuteswest * 60, &tm); - if (!sbi->options.tz_utc) - second -= sys_tz.tz_minuteswest * SECS_PER_MIN; - - /* Jan 1 GMT 00:00:00 1980. But what about another time zone? */ - if (second < UNIX_SECS_1980) { + /* FAT can only support year between 1980 to 2107 */ + if (tm.tm_year < 1980 - 1900) { *time = 0; *date = cpu_to_le16((0 << 9) | (1 << 5) | 1); if (time_cs) *time_cs = 0; return; } -#if BITS_PER_LONG == 64 - if (second >= UNIX_SECS_2108) { + if (tm.tm_year > 2107 - 1900) { *time = cpu_to_le16((23 << 11) | (59 << 5) | 29); *date = cpu_to_le16((127 << 9) | (12 << 5) | 31); if (time_cs) *time_cs = 199; return; } -#endif - day = second / SECS_PER_DAY - DAYS_DELTA; - year = day / 365; - leap_day = (year + 3) / 4; - if (year > YEAR_2100) /* 2100 isn't leap year */ - leap_day--; - if (year * 365 + leap_day > day) - year--; - leap_day = (year + 3) / 4; - if (year > YEAR_2100) /* 2100 isn't leap year */ - leap_day--; - day -= year * 365 + leap_day; - - if (IS_LEAP_YEAR(year) && day == days_in_year[3]) { - month = 2; - } else { - if (IS_LEAP_YEAR(year) && day > days_in_year[3]) - day--; - for (month = 1; month < 12; month++) { - if (days_in_year[month + 1] > day) - break; - } - } - day -= days_in_year[month]; + /* from 1900 -> from 1980 */ + tm.tm_year -= 80; + /* 0~11 -> 1~12 */ + tm.tm_mon++; + /* 0~59 -> 0~29(2sec counts) */ + tm.tm_sec >>= 1; - *time = cpu_to_le16(((second / SECS_PER_HOUR) % 24) << 11 - | ((second / SECS_PER_MIN) % 60) << 5 - | (second % SECS_PER_MIN) >> 1); - *date = cpu_to_le16((year << 9) | (month << 5) | (day + 1)); + *time = cpu_to_le16(tm.tm_hour << 11 | tm.tm_min << 5 | tm.tm_sec); + *date = cpu_to_le16(tm.tm_year << 9 | tm.tm_mon << 5 | tm.tm_mday); if (time_cs) *time_cs = (ts->tv_sec & 1) * 100 + ts->tv_nsec / 10000000; } @@ -283,4 +259,3 @@ int fat_sync_bhs(struct buffer_head **bhs, int nr_bhs) } return err; } - diff --git a/fs/fat/namei_vfat.c b/fs/fat/namei_vfat.c index cb6e83557112..f565f24019b5 100644 --- a/fs/fat/namei_vfat.c +++ b/fs/fat/namei_vfat.c @@ -499,17 +499,10 @@ xlate_to_uni(const unsigned char *name, int len, unsigned char *outname, int charlen; if (utf8) { - int name_len = strlen(name); - - *outlen = utf8s_to_utf16s(name, PATH_MAX, (wchar_t *) outname); - - /* - * We stripped '.'s before and set len appropriately, - * but utf8s_to_utf16s doesn't care about len - */ - *outlen -= (name_len - len); - - if (*outlen > 255) + *outlen = utf8s_to_utf16s(name, len, (wchar_t *)outname); + if (*outlen < 0) + return *outlen; + else if (*outlen > 255) return -ENAMETOOLONG; op = &outname[*outlen * sizeof(wchar_t)]; |