Blame view

fs/fat/misc.c 7.66 KB
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
1
2
3
4
5
6
7
8
9
10
  /*
   *  linux/fs/fat/misc.c
   *
   *  Written 1992,1993 by Werner Almesberger
   *  22/11/2000 - Fixed fat_date_unix2dos for dates earlier than 01/01/1980
   *		 and date_dos2unix for date==0 by Igor Zhbanov(bsg@uniyar.ac.ru)
   */
  
  #include <linux/module.h>
  #include <linux/fs.h>
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
11
  #include <linux/buffer_head.h>
1d81a181e   Zhaolei   fatfs: use common...
12
  #include <linux/time.h>
9e975dae2   OGAWA Hirofumi   fat: split includ...
13
  #include "fat.h"
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
14
15
  
  /*
85c785919   Denis Karpov   FAT: add 'errors'...
16
17
18
19
20
21
   * fat_fs_error reports a file system problem that might indicate fa data
   * corruption/inconsistency. Depending on 'errors' mount option the
   * panic() is called, or error message is printed FAT and nothing is done,
   * or filesystem is remounted read-only (default behavior).
   * In case the file system is remounted read-only, it can be made writable
   * again by remounting it.
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
22
   */
2c8a5ffb9   Alexey Fisher   fat: Convert fat_...
23
  void __fat_fs_error(struct super_block *sb, int report, const char *fmt, ...)
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
24
  {
2c8a5ffb9   Alexey Fisher   fat: Convert fat_...
25
  	struct fat_mount_options *opts = &MSDOS_SB(sb)->options;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
26
  	va_list args;
2c8a5ffb9   Alexey Fisher   fat: Convert fat_...
27
  	struct va_format vaf;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
28

aaa04b487   OGAWA Hirofumi   fatfs: ratelimit ...
29
  	if (report) {
aaa04b487   OGAWA Hirofumi   fatfs: ratelimit ...
30
  		va_start(args, fmt);
2c8a5ffb9   Alexey Fisher   fat: Convert fat_...
31
32
  		vaf.fmt = fmt;
  		vaf.va = &args;
e68e96d2a   Gu Zheng   fs/fat: use fat_m...
33
  		fat_msg(sb, KERN_ERR, "error, %pV", &vaf);
aaa04b487   OGAWA Hirofumi   fatfs: ratelimit ...
34
  		va_end(args);
aaa04b487   OGAWA Hirofumi   fatfs: ratelimit ...
35
  	}
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
36

85c785919   Denis Karpov   FAT: add 'errors'...
37
  	if (opts->errors == FAT_ERRORS_PANIC)
2c8a5ffb9   Alexey Fisher   fat: Convert fat_...
38
39
40
41
  		panic("FAT-fs (%s): fs panic from previous error
  ", sb->s_id);
  	else if (opts->errors == FAT_ERRORS_RO && !(sb->s_flags & MS_RDONLY)) {
  		sb->s_flags |= MS_RDONLY;
e68e96d2a   Gu Zheng   fs/fat: use fat_m...
42
  		fat_msg(sb, KERN_ERR, "Filesystem has been set read-only");
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
43
44
  	}
  }
aaa04b487   OGAWA Hirofumi   fatfs: ratelimit ...
45
  EXPORT_SYMBOL_GPL(__fat_fs_error);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
46

81ac21d34   Alexey Fisher   fat: Add fat_msg(...
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
  /**
   * fat_msg() - print preformated FAT specific messages. Every thing what is
   * not fat_fs_error() should be fat_msg().
   */
  void fat_msg(struct super_block *sb, const char *level, const char *fmt, ...)
  {
  	struct va_format vaf;
  	va_list args;
  
  	va_start(args, fmt);
  	vaf.fmt = fmt;
  	vaf.va = &args;
  	printk("%sFAT-fs (%s): %pV
  ", level, sb->s_id, &vaf);
  	va_end(args);
  }
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
63
64
  /* Flushes the number of free clusters on FAT32 */
  /* XXX: Need to write one per FSINFO block.  Currently only writes 1 */
ed248b290   OGAWA Hirofumi   fat: Check s_dirt...
65
  int fat_clusters_flush(struct super_block *sb)
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
66
67
68
69
70
71
  {
  	struct msdos_sb_info *sbi = MSDOS_SB(sb);
  	struct buffer_head *bh;
  	struct fat_boot_fsinfo *fsinfo;
  
  	if (sbi->fat_bits != 32)
ed248b290   OGAWA Hirofumi   fat: Check s_dirt...
72
  		return 0;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
73
74
75
  
  	bh = sb_bread(sb, sbi->fsinfo_sector);
  	if (bh == NULL) {
869f58c0c   Alexey Fisher   fat: Replace all ...
76
  		fat_msg(sb, KERN_ERR, "bread failed in fat_clusters_flush");
ed248b290   OGAWA Hirofumi   fat: Check s_dirt...
77
  		return -EIO;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
78
79
80
81
82
  	}
  
  	fsinfo = (struct fat_boot_fsinfo *)bh->b_data;
  	/* Sanity check */
  	if (!IS_FSINFO(fsinfo)) {
869f58c0c   Alexey Fisher   fat: Replace all ...
83
84
  		fat_msg(sb, KERN_ERR, "Invalid FSINFO signature: "
  		       "0x%08x, 0x%08x (sector = %lu)",
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
85
86
87
88
89
90
91
92
93
  		       le32_to_cpu(fsinfo->signature1),
  		       le32_to_cpu(fsinfo->signature2),
  		       sbi->fsinfo_sector);
  	} else {
  		if (sbi->free_clusters != -1)
  			fsinfo->free_clusters = cpu_to_le32(sbi->free_clusters);
  		if (sbi->prev_free != -1)
  			fsinfo->next_cluster = cpu_to_le32(sbi->prev_free);
  		mark_buffer_dirty(bh);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
94
95
  	}
  	brelse(bh);
ed248b290   OGAWA Hirofumi   fat: Check s_dirt...
96
97
  
  	return 0;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
  }
  
  /*
   * fat_chain_add() adds a new cluster to the chain of clusters represented
   * by inode.
   */
  int fat_chain_add(struct inode *inode, int new_dclus, int nr_cluster)
  {
  	struct super_block *sb = inode->i_sb;
  	struct msdos_sb_info *sbi = MSDOS_SB(sb);
  	int ret, new_fclus, last;
  
  	/*
  	 * We must locate the last cluster of the file to add this new
  	 * one (new_dclus) to the end of the link list (the FAT).
  	 */
  	last = new_fclus = 0;
  	if (MSDOS_I(inode)->i_start) {
  		int fclus, dclus;
  
  		ret = fat_get_cluster(inode, FAT_ENT_EOF, &fclus, &dclus);
  		if (ret < 0)
  			return ret;
  		new_fclus = fclus + 1;
  		last = dclus;
  	}
  
  	/* add new one to the last of the cluster chain */
  	if (last) {
  		struct fat_entry fatent;
  
  		fatent_init(&fatent);
  		ret = fat_ent_read(inode, &fatent, last);
  		if (ret >= 0) {
  			int wait = inode_needs_sync(inode);
  			ret = fat_ent_write(inode, &fatent, new_dclus, wait);
  			fatent_brelse(&fatent);
  		}
  		if (ret < 0)
  			return ret;
c39540c6d   Ravishankar N   fat: fix incorrec...
138
139
140
141
  		/*
  		 * FIXME:Although we can add this cache, fat_cache_add() is
  		 * assuming to be called after linear search with fat_cache_id.
  		 */
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
142
143
144
145
146
  //		fat_cache_add(inode, new_fclus, new_dclus);
  	} else {
  		MSDOS_I(inode)->i_start = new_dclus;
  		MSDOS_I(inode)->i_logstart = new_dclus;
  		/*
2f3d675bc   Jan Kara   fat: Opencode syn...
147
148
  		 * Since generic_write_sync() synchronizes regular files later,
  		 * we sync here only directories.
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
149
150
151
152
153
154
155
156
157
  		 */
  		if (S_ISDIR(inode->i_mode) && IS_DIRSYNC(inode)) {
  			ret = fat_sync_inode(inode);
  			if (ret)
  				return ret;
  		} else
  			mark_inode_dirty(inode);
  	}
  	if (new_fclus != (inode->i_blocks >> (sbi->cluster_bits - 9))) {
85c785919   Denis Karpov   FAT: add 'errors'...
158
  		fat_fs_error(sb, "clusters badly computed (%d != %llu)",
c3302931d   OGAWA Hirofumi   fat: i_blocks war...
159
160
  			     new_fclus,
  			     (llu)(inode->i_blocks >> (sbi->cluster_bits - 9)));
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
161
162
163
164
165
166
167
168
  		fat_cache_inval_inode(inode);
  	}
  	inode->i_blocks += nr_cluster << (sbi->cluster_bits - 9);
  
  	return 0;
  }
  
  extern struct timezone sys_tz;
7decd1cb0   OGAWA Hirofumi   fat: Fix and clea...
169
170
171
172
173
174
175
176
177
178
179
180
181
  /*
   * The epoch of FAT timestamp is 1980.
   *     :  bits :     value
   * date:  0 -  4: day	(1 -  31)
   * date:  5 -  8: month	(1 -  12)
   * date:  9 - 15: year	(0 - 127) from 1980
   * time:  0 -  4: sec	(0 -  29) 2sec counts
   * time:  5 - 10: min	(0 -  59)
   * time: 11 - 15: hour	(0 -  23)
   */
  #define SECS_PER_MIN	60
  #define SECS_PER_HOUR	(60 * 60)
  #define SECS_PER_DAY	(SECS_PER_HOUR * 24)
7decd1cb0   OGAWA Hirofumi   fat: Fix and clea...
182
183
184
185
186
  /* 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 */
  #define YEAR_2100	120
  #define IS_LEAP_YEAR(y)	(!((y) & 3) && (y) != YEAR_2100)
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
187
  /* Linear day numbers of the respective 1sts in non-leap years. */
7decd1cb0   OGAWA Hirofumi   fat: Fix and clea...
188
189
190
  static time_t days_in_year[] = {
  	/* Jan  Feb  Mar  Apr  May  Jun  Jul  Aug  Sep  Oct  Nov  Dec */
  	0,   0,  31,  59,  90, 120, 151, 181, 212, 243, 273, 304, 334, 0, 0, 0,
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
191
  };
7decd1cb0   OGAWA Hirofumi   fat: Fix and clea...
192
193
194
  /* Convert a FAT time/date pair to a UNIX date (seconds since 1 1 70). */
  void fat_time_fat2unix(struct msdos_sb_info *sbi, struct timespec *ts,
  		       __le16 __time, __le16 __date, u8 time_cs)
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
195
  {
7decd1cb0   OGAWA Hirofumi   fat: Fix and clea...
196
197
  	u16 time = le16_to_cpu(__time), date = le16_to_cpu(__date);
  	time_t second, day, leap_day, month, year;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
198

7decd1cb0   OGAWA Hirofumi   fat: Fix and clea...
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
  	year  = date >> 9;
  	month = max(1, (date >> 5) & 0xf);
  	day   = max(1, date & 0x1f) - 1;
  
  	leap_day = (year + 3) / 4;
  	if (year > YEAR_2100)		/* 2100 isn't leap year */
  		leap_day--;
  	if (IS_LEAP_YEAR(year) && month > 2)
  		leap_day++;
  
  	second =  (time & 0x1f) << 1;
  	second += ((time >> 5) & 0x3f) * SECS_PER_MIN;
  	second += (time >> 11) * SECS_PER_HOUR;
  	second += (year * 365 + leap_day
  		   + days_in_year[month] + day
  		   + DAYS_DELTA) * SECS_PER_DAY;
58156c8fb   Jan Kara   fat: provide opti...
215
  	if (!sbi->options.tz_set)
7decd1cb0   OGAWA Hirofumi   fat: Fix and clea...
216
  		second += sys_tz.tz_minuteswest * SECS_PER_MIN;
58156c8fb   Jan Kara   fat: provide opti...
217
218
  	else
  		second -= sbi->options.time_offset * SECS_PER_MIN;
7decd1cb0   OGAWA Hirofumi   fat: Fix and clea...
219
220
221
222
223
224
225
226
  
  	if (time_cs) {
  		ts->tv_sec = second + (time_cs / 100);
  		ts->tv_nsec = (time_cs % 100) * 10000000;
  	} else {
  		ts->tv_sec = second;
  		ts->tv_nsec = 0;
  	}
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
227
  }
7decd1cb0   OGAWA Hirofumi   fat: Fix and clea...
228
229
230
  /* Convert linear UNIX date to a FAT time/date pair. */
  void fat_time_unix2fat(struct msdos_sb_info *sbi, struct timespec *ts,
  		       __le16 *time, __le16 *date, u8 *time_cs)
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
231
  {
1d81a181e   Zhaolei   fatfs: use common...
232
  	struct tm tm;
58156c8fb   Jan Kara   fat: provide opti...
233
234
235
  	time_to_tm(ts->tv_sec,
  		   (sbi->options.tz_set ? sbi->options.time_offset :
  		   -sys_tz.tz_minuteswest) * SECS_PER_MIN, &tm);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
236

1d81a181e   Zhaolei   fatfs: use common...
237
238
  	/*  FAT can only support year between 1980 to 2107 */
  	if (tm.tm_year < 1980 - 1900) {
7decd1cb0   OGAWA Hirofumi   fat: Fix and clea...
239
240
241
242
243
244
  		*time = 0;
  		*date = cpu_to_le16((0 << 9) | (1 << 5) | 1);
  		if (time_cs)
  			*time_cs = 0;
  		return;
  	}
1d81a181e   Zhaolei   fatfs: use common...
245
  	if (tm.tm_year > 2107 - 1900) {
7decd1cb0   OGAWA Hirofumi   fat: Fix and clea...
246
247
248
249
250
251
  		*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;
  	}
7decd1cb0   OGAWA Hirofumi   fat: Fix and clea...
252

1d81a181e   Zhaolei   fatfs: use common...
253
254
255
256
257
258
  	/* 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;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
259

1d81a181e   Zhaolei   fatfs: use common...
260
261
  	*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);
7decd1cb0   OGAWA Hirofumi   fat: Fix and clea...
262
263
264
265
  	if (time_cs)
  		*time_cs = (ts->tv_sec & 1) * 100 + ts->tv_nsec / 10000000;
  }
  EXPORT_SYMBOL_GPL(fat_time_unix2fat);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
266
267
268
  
  int fat_sync_bhs(struct buffer_head **bhs, int nr_bhs)
  {
5b00226d4   OGAWA Hirofumi   [PATCH] fat: Repl...
269
  	int i, err = 0;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
270

9cb569d60   Christoph Hellwig   remove SWRITE* I/...
271
272
  	for (i = 0; i < nr_bhs; i++)
  		write_dirty_buffer(bhs[i], WRITE);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
273
274
  	for (i = 0; i < nr_bhs; i++) {
  		wait_on_buffer(bhs[i]);
0edd55fae   Christoph Hellwig   block: remove the...
275
  		if (!err && !buffer_uptodate(bhs[i]))
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
276
277
278
279
  			err = -EIO;
  	}
  	return err;
  }