Blame view

fs/fat/inode.c 51 KB
09c434b8a   Thomas Gleixner   treewide: Add SPD...
1
  // SPDX-License-Identifier: GPL-2.0-only
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
2
3
4
5
6
7
8
9
10
11
12
13
14
  /*
   *  linux/fs/fat/inode.c
   *
   *  Written 1992,1993 by Werner Almesberger
   *  VFAT extensions by Gordon Chaffee, merged with msdos fs by Henrik Storner
   *  Rewritten for the constant inumbers support by Al Viro
   *
   *  Fixes:
   *
   *	Max Cohan: Fixed invalid FSINFO offset when info_sector is 0
   */
  
  #include <linux/module.h>
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
15
  #include <linux/pagemap.h>
a5425d292   OGAWA Hirofumi   [PATCH] fat: add ...
16
  #include <linux/mpage.h>
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
17
  #include <linux/vfs.h>
58932ef7f   Alexander Kuleshov   fs/fat: remove un...
18
  #include <linux/seq_file.h>
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
19
  #include <linux/parser.h>
e5174baae   OGAWA Hirofumi   [PATCH] fat: supp...
20
  #include <linux/uio.h>
f562146a3   Namjae Jeon   fat: notify when ...
21
  #include <linux/blkdev.h>
66114cad6   Tejun Heo   writeback: separa...
22
  #include <linux/backing-dev.h>
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
23
  #include <asm/unaligned.h>
74b5cab6c   Arnd Bergmann   fat: use prandom_...
24
  #include <linux/random.h>
2489dbabe   Jeff Layton   fat: convert to n...
25
  #include <linux/iversion.h>
9e975dae2   OGAWA Hirofumi   fat: split includ...
26
  #include "fat.h"
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
27
28
29
30
31
  
  #ifndef CONFIG_FAT_DEFAULT_IOCHARSET
  /* if user don't select VFAT, this is undefined. */
  #define CONFIG_FAT_DEFAULT_IOCHARSET	""
  #endif
190a8843d   Conrad Meyer   fs/fat/: add supp...
32
  #define KB_IN_SECTORS 2
c0da64f6b   Deepa Dinamani   fs: fat: Initiali...
33
34
35
36
  /* DOS dates from 1980/1/1 through 2107/12/31 */
  #define FAT_DATE_MIN (0<<9 | 1<<5 | 1)
  #define FAT_DATE_MAX (127<<9 | 12<<5 | 31)
  #define FAT_TIME_MAX (23<<11 | 59<<5 | 29)
190a8843d   Conrad Meyer   fs/fat/: add supp...
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
  /*
   * A deserialized copy of the on-disk structure laid out in struct
   * fat_boot_sector.
   */
  struct fat_bios_param_block {
  	u16	fat_sector_size;
  	u8	fat_sec_per_clus;
  	u16	fat_reserved;
  	u8	fat_fats;
  	u16	fat_dir_entries;
  	u16	fat_sectors;
  	u16	fat_fat_length;
  	u32	fat_total_sect;
  
  	u8	fat16_state;
  	u32	fat16_vol_id;
  
  	u32	fat32_length;
  	u32	fat32_root_cluster;
  	u16	fat32_info_sector;
  	u8	fat32_state;
  	u32	fat32_vol_id;
  };
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
60
61
  static int fat_default_codepage = CONFIG_FAT_DEFAULT_CODEPAGE;
  static char fat_default_iocharset[] = CONFIG_FAT_DEFAULT_IOCHARSET;
190a8843d   Conrad Meyer   fs/fat/: add supp...
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
  static struct fat_floppy_defaults {
  	unsigned nr_sectors;
  	unsigned sec_per_clus;
  	unsigned dir_entries;
  	unsigned media;
  	unsigned fat_length;
  } floppy_defaults[] = {
  {
  	.nr_sectors = 160 * KB_IN_SECTORS,
  	.sec_per_clus = 1,
  	.dir_entries = 64,
  	.media = 0xFE,
  	.fat_length = 1,
  },
  {
  	.nr_sectors = 180 * KB_IN_SECTORS,
  	.sec_per_clus = 1,
  	.dir_entries = 64,
  	.media = 0xFC,
  	.fat_length = 2,
  },
  {
  	.nr_sectors = 320 * KB_IN_SECTORS,
  	.sec_per_clus = 2,
  	.dir_entries = 112,
  	.media = 0xFF,
  	.fat_length = 1,
  },
  {
  	.nr_sectors = 360 * KB_IN_SECTORS,
  	.sec_per_clus = 2,
  	.dir_entries = 112,
  	.media = 0xFD,
  	.fat_length = 2,
  },
  };
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
98

b13bb33ea   Namjae Jeon   fat: add fat_fall...
99
  int fat_add_cluster(struct inode *inode)
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
100
101
102
103
104
105
106
107
108
109
110
111
112
  {
  	int err, cluster;
  
  	err = fat_alloc_clusters(inode, &cluster, 1);
  	if (err)
  		return err;
  	/* FIXME: this cluster should be added after data of this
  	 * cluster is writed */
  	err = fat_chain_add(inode, cluster, 1);
  	if (err)
  		fat_free_clusters(inode, cluster);
  	return err;
  }
6a1d9805e   OGAWA Hirofumi   [PATCH] fat: clea...
113
114
115
  static inline int __fat_get_block(struct inode *inode, sector_t iblock,
  				  unsigned long *max_blocks,
  				  struct buffer_head *bh_result, int create)
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
116
117
  {
  	struct super_block *sb = inode->i_sb;
e5174baae   OGAWA Hirofumi   [PATCH] fat: supp...
118
  	struct msdos_sb_info *sbi = MSDOS_SB(sb);
e5174baae   OGAWA Hirofumi   [PATCH] fat: supp...
119
  	unsigned long mapped_blocks;
7e0f236b5   Namjae Jeon   fat: skip cluster...
120
  	sector_t phys, last_block;
e5174baae   OGAWA Hirofumi   [PATCH] fat: supp...
121
  	int err, offset;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
122

16fab2015   Namjae Jeon   fat: permit to re...
123
  	err = fat_bmap(inode, iblock, &phys, &mapped_blocks, create, false);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
124
125
126
127
  	if (err)
  		return err;
  	if (phys) {
  		map_bh(bh_result, sb, phys);
e5174baae   OGAWA Hirofumi   [PATCH] fat: supp...
128
  		*max_blocks = min(mapped_blocks, *max_blocks);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
129
130
131
132
  		return 0;
  	}
  	if (!create)
  		return 0;
e5174baae   OGAWA Hirofumi   [PATCH] fat: supp...
133

1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
134
  	if (iblock != MSDOS_I(inode)->mmu_private >> sb->s_blocksize_bits) {
85c785919   Denis Karpov   FAT: add 'errors'...
135
  		fat_fs_error(sb, "corrupted file size (i_pos %lld, %lld)",
6a1d9805e   OGAWA Hirofumi   [PATCH] fat: clea...
136
  			MSDOS_I(inode)->i_pos, MSDOS_I(inode)->mmu_private);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
137
138
  		return -EIO;
  	}
e5174baae   OGAWA Hirofumi   [PATCH] fat: supp...
139

7e0f236b5   Namjae Jeon   fat: skip cluster...
140
  	last_block = inode->i_blocks >> (sb->s_blocksize_bits - 9);
e5174baae   OGAWA Hirofumi   [PATCH] fat: supp...
141
  	offset = (unsigned long)iblock & (sbi->sec_per_clus - 1);
7e0f236b5   Namjae Jeon   fat: skip cluster...
142
143
144
145
146
147
  	/*
  	 * allocate a cluster according to the following.
  	 * 1) no more available blocks
  	 * 2) not part of fallocate region
  	 */
  	if (!offset && !(iblock < last_block)) {
e5174baae   OGAWA Hirofumi   [PATCH] fat: supp...
148
  		/* TODO: multiple cluster allocation would be desirable. */
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
149
150
151
152
  		err = fat_add_cluster(inode);
  		if (err)
  			return err;
  	}
e5174baae   OGAWA Hirofumi   [PATCH] fat: supp...
153
154
155
156
157
  	/* available blocks on this cluster */
  	mapped_blocks = sbi->sec_per_clus - offset;
  
  	*max_blocks = min(mapped_blocks, *max_blocks);
  	MSDOS_I(inode)->mmu_private += *max_blocks << sb->s_blocksize_bits;
16fab2015   Namjae Jeon   fat: permit to re...
158
  	err = fat_bmap(inode, iblock, &phys, &mapped_blocks, create, false);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
159
160
  	if (err)
  		return err;
c2574aaa5   OGAWA Hirofumi   fat: use fat_fs_e...
161
162
163
164
165
166
167
  	if (!phys) {
  		fat_fs_error(sb,
  			     "invalid FAT chain (i_pos %lld, last_block %llu)",
  			     MSDOS_I(inode)->i_pos,
  			     (unsigned long long)last_block);
  		return -EIO;
  	}
6a1d9805e   OGAWA Hirofumi   [PATCH] fat: clea...
168

e5174baae   OGAWA Hirofumi   [PATCH] fat: supp...
169
  	BUG_ON(*max_blocks != mapped_blocks);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
170
171
  	set_buffer_new(bh_result);
  	map_bh(bh_result, sb, phys);
6a1d9805e   OGAWA Hirofumi   [PATCH] fat: clea...
172

1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
173
174
  	return 0;
  }
6a1d9805e   OGAWA Hirofumi   [PATCH] fat: clea...
175
176
  static int fat_get_block(struct inode *inode, sector_t iblock,
  			 struct buffer_head *bh_result, int create)
e5174baae   OGAWA Hirofumi   [PATCH] fat: supp...
177
178
  {
  	struct super_block *sb = inode->i_sb;
1d8fa7a2b   Badari Pulavarty   [PATCH] remove ->...
179
  	unsigned long max_blocks = bh_result->b_size >> inode->i_blkbits;
6a1d9805e   OGAWA Hirofumi   [PATCH] fat: clea...
180
  	int err;
e5174baae   OGAWA Hirofumi   [PATCH] fat: supp...
181

6a1d9805e   OGAWA Hirofumi   [PATCH] fat: clea...
182
  	err = __fat_get_block(inode, iblock, &max_blocks, bh_result, create);
e5174baae   OGAWA Hirofumi   [PATCH] fat: supp...
183
184
185
186
187
  	if (err)
  		return err;
  	bh_result->b_size = max_blocks << sb->s_blocksize_bits;
  	return 0;
  }
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
188
189
190
191
  static int fat_writepage(struct page *page, struct writeback_control *wbc)
  {
  	return block_write_full_page(page, fat_get_block, wbc);
  }
a5425d292   OGAWA Hirofumi   [PATCH] fat: add ...
192
193
194
195
196
  static int fat_writepages(struct address_space *mapping,
  			  struct writeback_control *wbc)
  {
  	return mpage_writepages(mapping, wbc, fat_get_block);
  }
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
197
198
  static int fat_readpage(struct file *file, struct page *page)
  {
a5425d292   OGAWA Hirofumi   [PATCH] fat: add ...
199
200
  	return mpage_readpage(page, fat_get_block);
  }
d4388340a   Matthew Wilcox (Oracle)   fs: convert mpage...
201
  static void fat_readahead(struct readahead_control *rac)
a5425d292   OGAWA Hirofumi   [PATCH] fat: add ...
202
  {
d4388340a   Matthew Wilcox (Oracle)   fs: convert mpage...
203
  	mpage_readahead(rac, fat_get_block);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
204
  }
459f6ed3b   npiggin@suse.de   fat: convert to u...
205
206
207
208
209
  static void fat_write_failed(struct address_space *mapping, loff_t to)
  {
  	struct inode *inode = mapping->host;
  
  	if (to > inode->i_size) {
7caef2676   Kirill A. Shutemov   truncate: drop 'o...
210
  		truncate_pagecache(inode, inode->i_size);
459f6ed3b   npiggin@suse.de   fat: convert to u...
211
212
213
  		fat_truncate_blocks(inode, inode->i_size);
  	}
  }
d7777a25a   Nick Piggin   fat: convert to n...
214
215
216
  static int fat_write_begin(struct file *file, struct address_space *mapping,
  			loff_t pos, unsigned len, unsigned flags,
  			struct page **pagep, void **fsdata)
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
217
  {
459f6ed3b   npiggin@suse.de   fat: convert to u...
218
  	int err;
d7777a25a   Nick Piggin   fat: convert to n...
219
  	*pagep = NULL;
282dc1788   Christoph Hellwig   get rid of cont_w...
220
  	err = cont_write_begin(file, mapping, pos, len, flags,
459f6ed3b   npiggin@suse.de   fat: convert to u...
221
  				pagep, fsdata, fat_get_block,
d7777a25a   Nick Piggin   fat: convert to n...
222
  				&MSDOS_I(mapping->host)->mmu_private);
459f6ed3b   npiggin@suse.de   fat: convert to u...
223
224
225
  	if (err < 0)
  		fat_write_failed(mapping, pos + len);
  	return err;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
226
  }
d7777a25a   Nick Piggin   fat: convert to n...
227
228
229
  static int fat_write_end(struct file *file, struct address_space *mapping,
  			loff_t pos, unsigned len, unsigned copied,
  			struct page *pagep, void *fsdata)
ef402268f   OGAWA Hirofumi   [PATCH] FAT: miss...
230
  {
d7777a25a   Nick Piggin   fat: convert to n...
231
232
233
  	struct inode *inode = mapping->host;
  	int err;
  	err = generic_write_end(file, mapping, pos, len, copied, pagep, fsdata);
459f6ed3b   npiggin@suse.de   fat: convert to u...
234
235
  	if (err < len)
  		fat_write_failed(mapping, pos + len);
d7777a25a   Nick Piggin   fat: convert to n...
236
  	if (!(err < 0) && !(MSDOS_I(inode)->i_attrs & ATTR_ARCH)) {
cd83f6b19   Frank Sorenson   fat: change times...
237
  		fat_truncate_time(inode, NULL, S_CTIME|S_MTIME);
ef402268f   OGAWA Hirofumi   [PATCH] FAT: miss...
238
239
240
241
242
  		MSDOS_I(inode)->i_attrs |= ATTR_ARCH;
  		mark_inode_dirty(inode);
  	}
  	return err;
  }
c8b8e32d7   Christoph Hellwig   direct-io: elimin...
243
  static ssize_t fat_direct_IO(struct kiocb *iocb, struct iov_iter *iter)
e5174baae   OGAWA Hirofumi   [PATCH] fat: supp...
244
245
  {
  	struct file *file = iocb->ki_filp;
459f6ed3b   npiggin@suse.de   fat: convert to u...
246
247
  	struct address_space *mapping = file->f_mapping;
  	struct inode *inode = mapping->host;
a6cbcd4a4   Al Viro   get rid of pointl...
248
  	size_t count = iov_iter_count(iter);
c8b8e32d7   Christoph Hellwig   direct-io: elimin...
249
  	loff_t offset = iocb->ki_pos;
459f6ed3b   npiggin@suse.de   fat: convert to u...
250
  	ssize_t ret;
e5174baae   OGAWA Hirofumi   [PATCH] fat: supp...
251

6f6737631   Omar Sandoval   direct_IO: use io...
252
  	if (iov_iter_rw(iter) == WRITE) {
e5174baae   OGAWA Hirofumi   [PATCH] fat: supp...
253
  		/*
4e02ed4b4   Nick Piggin   fs: remove prepar...
254
  		 * FIXME: blockdev_direct_IO() doesn't use ->write_begin(),
e5174baae   OGAWA Hirofumi   [PATCH] fat: supp...
255
256
257
258
  		 * so we need to update the ->mmu_private to block boundary.
  		 *
  		 * But we must fill the remaining area or hole by nul for
  		 * updating ->mmu_private.
94412a96c   OGAWA Hirofumi   [PATCH] FAT: DIO-...
259
260
  		 *
  		 * Return 0, and fallback to normal buffered write.
e5174baae   OGAWA Hirofumi   [PATCH] fat: supp...
261
  		 */
a6cbcd4a4   Al Viro   get rid of pointl...
262
  		loff_t size = offset + count;
e5174baae   OGAWA Hirofumi   [PATCH] fat: supp...
263
  		if (MSDOS_I(inode)->mmu_private < size)
94412a96c   OGAWA Hirofumi   [PATCH] FAT: DIO-...
264
  			return 0;
e5174baae   OGAWA Hirofumi   [PATCH] fat: supp...
265
266
267
268
269
270
  	}
  
  	/*
  	 * FAT need to use the DIO_LOCKING for avoiding the race
  	 * condition of fat_get_block() and ->truncate().
  	 */
c8b8e32d7   Christoph Hellwig   direct-io: elimin...
271
  	ret = blockdev_direct_IO(iocb, inode, iter, fat_get_block);
6f6737631   Omar Sandoval   direct_IO: use io...
272
  	if (ret < 0 && iov_iter_rw(iter) == WRITE)
a6cbcd4a4   Al Viro   get rid of pointl...
273
  		fat_write_failed(mapping, offset + count);
459f6ed3b   npiggin@suse.de   fat: convert to u...
274
275
  
  	return ret;
e5174baae   OGAWA Hirofumi   [PATCH] fat: supp...
276
  }
16fab2015   Namjae Jeon   fat: permit to re...
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
  static int fat_get_block_bmap(struct inode *inode, sector_t iblock,
  		struct buffer_head *bh_result, int create)
  {
  	struct super_block *sb = inode->i_sb;
  	unsigned long max_blocks = bh_result->b_size >> inode->i_blkbits;
  	int err;
  	sector_t bmap;
  	unsigned long mapped_blocks;
  
  	BUG_ON(create != 0);
  
  	err = fat_bmap(inode, iblock, &bmap, &mapped_blocks, create, true);
  	if (err)
  		return err;
  
  	if (bmap) {
  		map_bh(bh_result, sb, bmap);
  		max_blocks = min(mapped_blocks, max_blocks);
  	}
  
  	bh_result->b_size = max_blocks << sb->s_blocksize_bits;
  
  	return 0;
  }
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
301
302
  static sector_t _fat_bmap(struct address_space *mapping, sector_t block)
  {
fa93ca18a   OGAWA Hirofumi   fat: Fix _fat_bma...
303
304
305
  	sector_t blocknr;
  
  	/* fat_get_cluster() assumes the requested blocknr isn't truncated. */
582686915   Christoph Hellwig   fat: remove i_all...
306
  	down_read(&MSDOS_I(mapping->host)->truncate_lock);
16fab2015   Namjae Jeon   fat: permit to re...
307
  	blocknr = generic_block_bmap(mapping, block, fat_get_block_bmap);
582686915   Christoph Hellwig   fat: remove i_all...
308
  	up_read(&MSDOS_I(mapping->host)->truncate_lock);
fa93ca18a   OGAWA Hirofumi   fat: Fix _fat_bma...
309
310
  
  	return blocknr;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
311
  }
c0ef0cc9d   Namjae Jeon   fat: fix data pas...
312
313
314
315
316
317
318
319
320
321
322
  /*
   * fat_block_truncate_page() zeroes out a mapping from file offset `from'
   * up to the end of the block which corresponds to `from'.
   * This is required during truncate to physically zeroout the tail end
   * of that block so it doesn't yield old data if the file is later grown.
   * Also, avoid causing failure from fsx for cases of "data past EOF"
   */
  int fat_block_truncate_page(struct inode *inode, loff_t from)
  {
  	return block_truncate_page(inode->i_mapping, from, fat_get_block);
  }
f5e54d6e5   Christoph Hellwig   [PATCH] mark addr...
323
  static const struct address_space_operations fat_aops = {
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
324
  	.readpage	= fat_readpage,
d4388340a   Matthew Wilcox (Oracle)   fs: convert mpage...
325
  	.readahead	= fat_readahead,
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
326
  	.writepage	= fat_writepage,
a5425d292   OGAWA Hirofumi   [PATCH] fat: add ...
327
  	.writepages	= fat_writepages,
d7777a25a   Nick Piggin   fat: convert to n...
328
329
  	.write_begin	= fat_write_begin,
  	.write_end	= fat_write_end,
e5174baae   OGAWA Hirofumi   [PATCH] fat: supp...
330
  	.direct_IO	= fat_direct_IO,
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
331
332
333
334
335
336
337
338
339
340
341
342
343
344
345
346
347
348
349
350
351
352
  	.bmap		= _fat_bmap
  };
  
  /*
   * New FAT inode stuff. We do the following:
   *	a) i_ino is constant and has nothing with on-disk location.
   *	b) FAT manages its own cache of directory entries.
   *	c) *This* cache is indexed by on-disk location.
   *	d) inode has an associated directory entry, all right, but
   *		it may be unhashed.
   *	e) currently entries are stored within struct inode. That should
   *		change.
   *	f) we deal with races in the following way:
   *		1. readdir() and lookup() do FAT-dir-cache lookup.
   *		2. rename() unhashes the F-d-c entry and rehashes it in
   *			a new place.
   *		3. unlink() and rmdir() unhash F-d-c entry.
   *		4. fat_write_inode() checks whether the thing is unhashed.
   *			If it is we silently return. If it isn't we do bread(),
   *			check if the location is still valid and retry if it
   *			isn't. Otherwise we do changes.
   *		5. Spinlock is used to protect hash/unhash/location check/lookup
deee3ce46   Al Viro   covert fatfs to -...
353
   *		6. fat_evict_inode() unhashes the F-d-c entry.
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
354
355
356
357
358
359
360
361
362
363
364
365
366
   *		7. lookup() and readdir() do igrab() if they find a F-d-c entry
   *			and consider negative result as cache miss.
   */
  
  static void fat_hash_init(struct super_block *sb)
  {
  	struct msdos_sb_info *sbi = MSDOS_SB(sb);
  	int i;
  
  	spin_lock_init(&sbi->inode_hash_lock);
  	for (i = 0; i < FAT_HASH_SIZE; i++)
  		INIT_HLIST_HEAD(&sbi->inode_hashtable[i]);
  }
d3dfa8228   OGAWA Hirofumi   fat: improve fat_...
367
  static inline unsigned long fat_hash(loff_t i_pos)
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
368
  {
d3dfa8228   OGAWA Hirofumi   fat: improve fat_...
369
  	return hash_32(i_pos, FAT_HASH_BITS);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
370
  }
7669e8fb0   Steven J. Magnani   fat (exportfs): f...
371
372
373
374
375
376
377
378
379
  static void dir_hash_init(struct super_block *sb)
  {
  	struct msdos_sb_info *sbi = MSDOS_SB(sb);
  	int i;
  
  	spin_lock_init(&sbi->dir_hash_lock);
  	for (i = 0; i < FAT_HASH_SIZE; i++)
  		INIT_HLIST_HEAD(&sbi->dir_hashtable[i]);
  }
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
380
381
  void fat_attach(struct inode *inode, loff_t i_pos)
  {
d3dfa8228   OGAWA Hirofumi   fat: improve fat_...
382
  	struct msdos_sb_info *sbi = MSDOS_SB(inode->i_sb);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
383

7669e8fb0   Steven J. Magnani   fat (exportfs): f...
384
385
386
387
388
389
390
391
392
393
394
395
396
397
398
399
400
401
402
403
404
405
  	if (inode->i_ino != MSDOS_ROOT_INO) {
  		struct hlist_head *head =   sbi->inode_hashtable
  					  + fat_hash(i_pos);
  
  		spin_lock(&sbi->inode_hash_lock);
  		MSDOS_I(inode)->i_pos = i_pos;
  		hlist_add_head(&MSDOS_I(inode)->i_fat_hash, head);
  		spin_unlock(&sbi->inode_hash_lock);
  	}
  
  	/* If NFS support is enabled, cache the mapping of start cluster
  	 * to directory inode. This is used during reconnection of
  	 * dentries to the filesystem root.
  	 */
  	if (S_ISDIR(inode->i_mode) && sbi->options.nfs) {
  		struct hlist_head *d_head = sbi->dir_hashtable;
  		d_head += fat_dir_hash(MSDOS_I(inode)->i_logstart);
  
  		spin_lock(&sbi->dir_hash_lock);
  		hlist_add_head(&MSDOS_I(inode)->i_dir_hash, d_head);
  		spin_unlock(&sbi->dir_hash_lock);
  	}
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
406
  }
7c709d00d   OGAWA Hirofumi   [PATCH] fat: s/EX...
407
  EXPORT_SYMBOL_GPL(fat_attach);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
408
409
410
411
412
413
414
415
  
  void fat_detach(struct inode *inode)
  {
  	struct msdos_sb_info *sbi = MSDOS_SB(inode->i_sb);
  	spin_lock(&sbi->inode_hash_lock);
  	MSDOS_I(inode)->i_pos = 0;
  	hlist_del_init(&MSDOS_I(inode)->i_fat_hash);
  	spin_unlock(&sbi->inode_hash_lock);
7669e8fb0   Steven J. Magnani   fat (exportfs): f...
416
417
418
419
420
421
  
  	if (S_ISDIR(inode->i_mode) && sbi->options.nfs) {
  		spin_lock(&sbi->dir_hash_lock);
  		hlist_del_init(&MSDOS_I(inode)->i_dir_hash);
  		spin_unlock(&sbi->dir_hash_lock);
  	}
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
422
  }
7c709d00d   OGAWA Hirofumi   [PATCH] fat: s/EX...
423
  EXPORT_SYMBOL_GPL(fat_detach);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
424
425
426
427
  
  struct inode *fat_iget(struct super_block *sb, loff_t i_pos)
  {
  	struct msdos_sb_info *sbi = MSDOS_SB(sb);
d3dfa8228   OGAWA Hirofumi   fat: improve fat_...
428
  	struct hlist_head *head = sbi->inode_hashtable + fat_hash(i_pos);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
429
430
431
432
  	struct msdos_inode_info *i;
  	struct inode *inode = NULL;
  
  	spin_lock(&sbi->inode_hash_lock);
b67bfe0d4   Sasha Levin   hlist: drop the n...
433
  	hlist_for_each_entry(i, head, i_fat_hash) {
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
434
435
436
437
438
439
440
441
442
443
444
445
446
  		BUG_ON(i->vfs_inode.i_sb != sb);
  		if (i->i_pos != i_pos)
  			continue;
  		inode = igrab(&i->vfs_inode);
  		if (inode)
  			break;
  	}
  	spin_unlock(&sbi->inode_hash_lock);
  	return inode;
  }
  
  static int is_exec(unsigned char *extension)
  {
ef19470ef   Manuel Schölling   fs/fat/inode.c: c...
447
  	unsigned char exe_extensions[] = "EXECOMBAT", *walk;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
448
449
450
451
452
453
454
455
456
457
458
459
460
461
462
463
464
465
466
467
468
469
470
  
  	for (walk = exe_extensions; *walk; walk += 3)
  		if (!strncmp(extension, walk, 3))
  			return 1;
  	return 0;
  }
  
  static int fat_calc_dir_size(struct inode *inode)
  {
  	struct msdos_sb_info *sbi = MSDOS_SB(inode->i_sb);
  	int ret, fclus, dclus;
  
  	inode->i_size = 0;
  	if (MSDOS_I(inode)->i_start == 0)
  		return 0;
  
  	ret = fat_get_cluster(inode, FAT_ENT_EOF, &fclus, &dclus);
  	if (ret < 0)
  		return ret;
  	inode->i_size = (fclus + 1) << sbi->cluster_bits;
  
  	return 0;
  }
a3082d526   OGAWA Hirofumi   fat: add simple v...
471
472
473
474
475
476
477
478
479
480
481
482
483
484
485
486
487
  static int fat_validate_dir(struct inode *dir)
  {
  	struct super_block *sb = dir->i_sb;
  
  	if (dir->i_nlink < 2) {
  		/* Directory should have "."/".." entries at least. */
  		fat_fs_error(sb, "corrupted directory (invalid entries)");
  		return -EIO;
  	}
  	if (MSDOS_I(dir)->i_start == 0 ||
  	    MSDOS_I(dir)->i_start == MSDOS_SB(sb)->root_cluster) {
  		/* Directory should point valid cluster. */
  		fat_fs_error(sb, "corrupted directory (invalid i_start)");
  		return -EIO;
  	}
  	return 0;
  }
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
488
  /* doesn't deal with root inode */
f1e6fb0ab   Namjae Jeon   fat (exportfs): r...
489
  int fat_fill_inode(struct inode *inode, struct msdos_dir_entry *de)
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
490
491
492
493
494
495
496
  {
  	struct msdos_sb_info *sbi = MSDOS_SB(inode->i_sb);
  	int error;
  
  	MSDOS_I(inode)->i_pos = 0;
  	inode->i_uid = sbi->options.fs_uid;
  	inode->i_gid = sbi->options.fs_gid;
2489dbabe   Jeff Layton   fat: convert to n...
497
  	inode_inc_iversion(inode);
74b5cab6c   Arnd Bergmann   fat: use prandom_...
498
  	inode->i_generation = prandom_u32();
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
499
500
501
  
  	if ((de->attr & ATTR_DIR) && !IS_FREE(de->name)) {
  		inode->i_generation &= ~1;
9c0aa1b87   OGAWA Hirofumi   fat: Cleanup FAT ...
502
  		inode->i_mode = fat_make_mode(sbi, de->attr, S_IRWXUGO);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
503
504
  		inode->i_op = sbi->dir_ops;
  		inode->i_fop = &fat_dir_operations;
a943ed71c   Steven J. Magnani   fat: accessors fo...
505
  		MSDOS_I(inode)->i_start = fat_get_start(sbi, de);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
506
507
508
509
510
  		MSDOS_I(inode)->i_logstart = MSDOS_I(inode)->i_start;
  		error = fat_calc_dir_size(inode);
  		if (error < 0)
  			return error;
  		MSDOS_I(inode)->mmu_private = inode->i_size;
bfe868486   Miklos Szeredi   filesystems: add ...
511
  		set_nlink(inode, fat_subdirs(inode));
a3082d526   OGAWA Hirofumi   fat: add simple v...
512
513
514
515
  
  		error = fat_validate_dir(inode);
  		if (error < 0)
  			return error;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
516
517
  	} else { /* not a directory */
  		inode->i_generation |= 1;
9c0aa1b87   OGAWA Hirofumi   fat: Cleanup FAT ...
518
519
520
  		inode->i_mode = fat_make_mode(sbi, de->attr,
  			((sbi->options.showexec && !is_exec(de->name + 8))
  			 ? S_IRUGO|S_IWUGO : S_IRWXUGO));
a943ed71c   Steven J. Magnani   fat: accessors fo...
521
  		MSDOS_I(inode)->i_start = fat_get_start(sbi, de);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
522
523
524
525
526
527
528
529
530
531
532
533
  
  		MSDOS_I(inode)->i_logstart = MSDOS_I(inode)->i_start;
  		inode->i_size = le32_to_cpu(de->size);
  		inode->i_op = &fat_file_inode_operations;
  		inode->i_fop = &fat_file_operations;
  		inode->i_mapping->a_ops = &fat_aops;
  		MSDOS_I(inode)->mmu_private = inode->i_size;
  	}
  	if (de->attr & ATTR_SYS) {
  		if (sbi->options.sys_immutable)
  			inode->i_flags |= S_IMMUTABLE;
  	}
9c0aa1b87   OGAWA Hirofumi   fat: Cleanup FAT ...
534
  	fat_save_attrs(inode, de->attr);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
535
536
  	inode->i_blocks = ((inode->i_size + (sbi->cluster_size - 1))
  			   & ~((loff_t)sbi->cluster_size - 1)) >> 9;
7decd1cb0   OGAWA Hirofumi   fat: Fix and clea...
537

f423420c2   Arnd Bergmann   fat: propagate 64...
538
  	fat_time_fat2unix(sbi, &inode->i_mtime, de->time, de->date, 0);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
539
  	if (sbi->options.isvfat) {
f423420c2   Arnd Bergmann   fat: propagate 64...
540
  		fat_time_fat2unix(sbi, &inode->i_ctime, de->ctime,
7decd1cb0   OGAWA Hirofumi   fat: Fix and clea...
541
  				  de->cdate, de->ctime_cs);
f423420c2   Arnd Bergmann   fat: propagate 64...
542
  		fat_time_fat2unix(sbi, &inode->i_atime, 0, de->adate, 0);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
543
  	} else
cd83f6b19   Frank Sorenson   fat: change times...
544
  		fat_truncate_time(inode, &inode->i_mtime, S_ATIME|S_CTIME);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
545
546
547
  
  	return 0;
  }
8fceb4e01   Namjae Jeon   fat (exportfs): r...
548
549
550
551
552
553
554
555
556
557
558
  static inline void fat_lock_build_inode(struct msdos_sb_info *sbi)
  {
  	if (sbi->options.nfs == FAT_NFS_NOSTALE_RO)
  		mutex_lock(&sbi->nfs_build_inode_lock);
  }
  
  static inline void fat_unlock_build_inode(struct msdos_sb_info *sbi)
  {
  	if (sbi->options.nfs == FAT_NFS_NOSTALE_RO)
  		mutex_unlock(&sbi->nfs_build_inode_lock);
  }
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
559
560
561
562
563
  struct inode *fat_build_inode(struct super_block *sb,
  			struct msdos_dir_entry *de, loff_t i_pos)
  {
  	struct inode *inode;
  	int err;
8fceb4e01   Namjae Jeon   fat (exportfs): r...
564
  	fat_lock_build_inode(MSDOS_SB(sb));
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
565
566
567
568
569
570
571
572
573
  	inode = fat_iget(sb, i_pos);
  	if (inode)
  		goto out;
  	inode = new_inode(sb);
  	if (!inode) {
  		inode = ERR_PTR(-ENOMEM);
  		goto out;
  	}
  	inode->i_ino = iunique(sb, MSDOS_ROOT_INO);
2489dbabe   Jeff Layton   fat: convert to n...
574
  	inode_set_iversion(inode, 1);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
575
576
577
578
579
580
581
582
583
  	err = fat_fill_inode(inode, de);
  	if (err) {
  		iput(inode);
  		inode = ERR_PTR(err);
  		goto out;
  	}
  	fat_attach(inode, i_pos);
  	insert_inode_hash(inode);
  out:
8fceb4e01   Namjae Jeon   fat (exportfs): r...
584
  	fat_unlock_build_inode(MSDOS_SB(sb));
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
585
586
  	return inode;
  }
7c709d00d   OGAWA Hirofumi   [PATCH] fat: s/EX...
587
  EXPORT_SYMBOL_GPL(fat_build_inode);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
588

b13bb33ea   Namjae Jeon   fat: add fat_fall...
589
590
591
592
593
594
595
596
597
598
599
600
601
602
603
604
605
606
607
608
609
610
611
612
613
614
615
  static int __fat_write_inode(struct inode *inode, int wait);
  
  static void fat_free_eofblocks(struct inode *inode)
  {
  	/* Release unwritten fallocated blocks on inode eviction. */
  	if ((inode->i_blocks << 9) >
  			round_up(MSDOS_I(inode)->mmu_private,
  				MSDOS_SB(inode->i_sb)->cluster_size)) {
  		int err;
  
  		fat_truncate_blocks(inode, MSDOS_I(inode)->mmu_private);
  		/* Fallocate results in updating the i_start/iogstart
  		 * for the zero byte file. So, make it return to
  		 * original state during evict and commit it to avoid
  		 * any corruption on the next access to the cluster
  		 * chain for the file.
  		 */
  		err = __fat_write_inode(inode, inode_needs_sync(inode));
  		if (err) {
  			fat_msg(inode->i_sb, KERN_WARNING, "Failed to "
  					"update on disk inode for unused "
  					"fallocated blocks, inode could be "
  					"corrupted. Please run fsck");
  		}
  
  	}
  }
deee3ce46   Al Viro   covert fatfs to -...
616
  static void fat_evict_inode(struct inode *inode)
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
617
  {
91b0abe36   Johannes Weiner   mm + fs: store sh...
618
  	truncate_inode_pages_final(&inode->i_data);
deee3ce46   Al Viro   covert fatfs to -...
619
620
621
  	if (!inode->i_nlink) {
  		inode->i_size = 0;
  		fat_truncate_blocks(inode, 0);
b13bb33ea   Namjae Jeon   fat: add fat_fall...
622
623
  	} else
  		fat_free_eofblocks(inode);
deee3ce46   Al Viro   covert fatfs to -...
624
  	invalidate_inode_buffers(inode);
dbd5768f8   Jan Kara   vfs: Rename end_w...
625
  	clear_inode(inode);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
626
  	fat_cache_inval_inode(inode);
a993b542b   OGAWA Hirofumi   fat: use fat_deta...
627
  	fat_detach(inode);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
628
  }
b88a10580   Oleksij Rempel   fat: mark fs as d...
629
630
631
632
633
  static void fat_set_state(struct super_block *sb,
  			unsigned int set, unsigned int force)
  {
  	struct buffer_head *bh;
  	struct fat_boot_sector *b;
d6bd42827   Fred Chou   fs: fat: use MSDO...
634
  	struct msdos_sb_info *sbi = MSDOS_SB(sb);
b88a10580   Oleksij Rempel   fat: mark fs as d...
635
636
  
  	/* do not change any thing if mounted read only */
bc98a42c1   David Howells   VFS: Convert sb->...
637
  	if (sb_rdonly(sb) && !force)
b88a10580   Oleksij Rempel   fat: mark fs as d...
638
639
640
641
642
643
644
645
646
647
648
649
650
651
652
653
654
655
656
657
  		return;
  
  	/* do not change state if fs was dirty */
  	if (sbi->dirty) {
  		/* warn only on set (mount). */
  		if (set)
  			fat_msg(sb, KERN_WARNING, "Volume was not properly "
  				"unmounted. Some data may be corrupt. "
  				"Please run fsck.");
  		return;
  	}
  
  	bh = sb_bread(sb, 0);
  	if (bh == NULL) {
  		fat_msg(sb, KERN_ERR, "unable to read boot sector "
  			"to mark fs as dirty");
  		return;
  	}
  
  	b = (struct fat_boot_sector *) bh->b_data;
306790f75   Carmeli Tamir   fat: new inline f...
658
  	if (is_fat32(sbi)) {
b88a10580   Oleksij Rempel   fat: mark fs as d...
659
660
661
662
663
664
665
666
667
668
669
670
671
672
673
  		if (set)
  			b->fat32.state |= FAT_STATE_DIRTY;
  		else
  			b->fat32.state &= ~FAT_STATE_DIRTY;
  	} else /* fat 16 and 12 */ {
  		if (set)
  			b->fat16.state |= FAT_STATE_DIRTY;
  		else
  			b->fat16.state &= ~FAT_STATE_DIRTY;
  	}
  
  	mark_buffer_dirty(bh);
  	sync_dirty_buffer(bh);
  	brelse(bh);
  }
35033ab98   OGAWA Hirofumi   fat: fix memory a...
674
675
676
677
678
679
680
681
  static void fat_reset_iocharset(struct fat_mount_options *opts)
  {
  	if (opts->iocharset != fat_default_iocharset) {
  		/* Note: opts->iocharset can be NULL here */
  		kfree(opts->iocharset);
  		opts->iocharset = fat_default_iocharset;
  	}
  }
cac45b062   Al Viro   fat: rcu-delay un...
682
683
684
685
686
  static void delayed_free(struct rcu_head *p)
  {
  	struct msdos_sb_info *sbi = container_of(p, struct msdos_sb_info, rcu);
  	unload_nls(sbi->nls_disk);
  	unload_nls(sbi->nls_io);
35033ab98   OGAWA Hirofumi   fat: fix memory a...
687
  	fat_reset_iocharset(&sbi->options);
cac45b062   Al Viro   fat: rcu-delay un...
688
689
  	kfree(sbi);
  }
a6bf6b211   OGAWA Hirofumi   [PATCH] fat: move...
690
691
692
  static void fat_put_super(struct super_block *sb)
  {
  	struct msdos_sb_info *sbi = MSDOS_SB(sb);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
693

b88a10580   Oleksij Rempel   fat: mark fs as d...
694
  	fat_set_state(sb, 0, 0);
020ac5b6b   Artem Bityutskiy   fat: introduce sp...
695
  	iput(sbi->fsinfo_inode);
b522412ae   Al Viro   Sanitize ->fsync(...
696
  	iput(sbi->fat_inode);
cac45b062   Al Viro   fat: rcu-delay un...
697
  	call_rcu(&sbi->rcu, delayed_free);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
698
  }
e18b890bb   Christoph Lameter   [PATCH] slab: rem...
699
  static struct kmem_cache *fat_inode_cachep;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
700
701
702
703
  
  static struct inode *fat_alloc_inode(struct super_block *sb)
  {
  	struct msdos_inode_info *ei;
8f5934278   Linus Torvalds   Replace BKL with ...
704
  	ei = kmem_cache_alloc(fat_inode_cachep, GFP_NOFS);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
705
706
  	if (!ei)
  		return NULL;
582686915   Christoph Hellwig   fat: remove i_all...
707
708
  
  	init_rwsem(&ei->truncate_lock);
bc87302a0   OGAWA Hirofumi   fat: fix uninit-m...
709
710
711
712
713
714
  	/* Zeroing to allow iput() even if partial initialized inode. */
  	ei->mmu_private = 0;
  	ei->i_start = 0;
  	ei->i_logstart = 0;
  	ei->i_attrs = 0;
  	ei->i_pos = 0;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
715
716
  	return &ei->vfs_inode;
  }
f9ec991d4   Al Viro   fat: switch to ->...
717
  static void fat_free_inode(struct inode *inode)
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
718
719
720
  {
  	kmem_cache_free(fat_inode_cachep, MSDOS_I(inode));
  }
51cc50685   Alexey Dobriyan   SL*B: drop kmem c...
721
  static void init_once(void *foo)
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
722
723
  {
  	struct msdos_inode_info *ei = (struct msdos_inode_info *)foo;
a35afb830   Christoph Lameter   Remove SLAB_CTOR_...
724
725
726
727
728
  	spin_lock_init(&ei->cache_lru_lock);
  	ei->nr_caches = 0;
  	ei->cache_valid_id = FAT_CACHE_VALID + 1;
  	INIT_LIST_HEAD(&ei->cache_lru);
  	INIT_HLIST_NODE(&ei->i_fat_hash);
7669e8fb0   Steven J. Magnani   fat (exportfs): f...
729
  	INIT_HLIST_NODE(&ei->i_dir_hash);
a35afb830   Christoph Lameter   Remove SLAB_CTOR_...
730
  	inode_init_once(&ei->vfs_inode);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
731
732
733
734
735
736
  }
  
  static int __init fat_init_inodecache(void)
  {
  	fat_inode_cachep = kmem_cache_create("fat_inode_cache",
  					     sizeof(struct msdos_inode_info),
fffb60f93   Paul Jackson   [PATCH] cpuset me...
737
  					     0, (SLAB_RECLAIM_ACCOUNT|
5d097056c   Vladimir Davydov   kmemcg: account c...
738
  						SLAB_MEM_SPREAD|SLAB_ACCOUNT),
20c2df83d   Paul Mundt   mm: Remove slab d...
739
  					     init_once);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
740
741
742
743
744
745
746
  	if (fat_inode_cachep == NULL)
  		return -ENOMEM;
  	return 0;
  }
  
  static void __exit fat_destroy_inodecache(void)
  {
8c0a85377   Kirill A. Shutemov   fs: push rcu_barr...
747
748
749
750
751
  	/*
  	 * Make sure all delayed rcu free inodes are flushed before we
  	 * destroy cache.
  	 */
  	rcu_barrier();
1a1d92c10   Alexey Dobriyan   [PATCH] Really ig...
752
  	kmem_cache_destroy(fat_inode_cachep);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
753
754
755
756
  }
  
  static int fat_remount(struct super_block *sb, int *flags, char *data)
  {
b6e8e12c0   OGAWA Hirofumi   fs/fat/inode.c: f...
757
  	bool new_rdonly;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
758
  	struct msdos_sb_info *sbi = MSDOS_SB(sb);
1751e8a6c   Linus Torvalds   Rename superblock...
759
  	*flags |= SB_NODIRATIME | (sbi->options.isvfat ? 0 : SB_NOATIME);
b88a10580   Oleksij Rempel   fat: mark fs as d...
760

02b9984d6   Theodore Ts'o   fs: push sync_fil...
761
  	sync_filesystem(sb);
b88a10580   Oleksij Rempel   fat: mark fs as d...
762
  	/* make sure we update state on remount. */
1751e8a6c   Linus Torvalds   Rename superblock...
763
  	new_rdonly = *flags & SB_RDONLY;
bc98a42c1   David Howells   VFS: Convert sb->...
764
  	if (new_rdonly != sb_rdonly(sb)) {
b88a10580   Oleksij Rempel   fat: mark fs as d...
765
766
767
768
769
  		if (new_rdonly)
  			fat_set_state(sb, 0, 0);
  		else
  			fat_set_state(sb, 1, 1);
  	}
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
770
771
  	return 0;
  }
726c33422   David Howells   [PATCH] VFS: Perm...
772
  static int fat_statfs(struct dentry *dentry, struct kstatfs *buf)
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
773
  {
aac49b754   Coly Li   fs/fat: return f_...
774
775
776
  	struct super_block *sb = dentry->d_sb;
  	struct msdos_sb_info *sbi = MSDOS_SB(sb);
  	u64 id = huge_encode_dev(sb->s_bdev->bd_dev);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
777
778
  
  	/* If the count of free cluster is still unknown, counts it here. */
606e423e4   OGAWA Hirofumi   fat: Update free_...
779
  	if (sbi->free_clusters == -1 || !sbi->free_clus_valid) {
726c33422   David Howells   [PATCH] VFS: Perm...
780
  		int err = fat_count_free_clusters(dentry->d_sb);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
781
782
783
  		if (err)
  			return err;
  	}
726c33422   David Howells   [PATCH] VFS: Perm...
784
  	buf->f_type = dentry->d_sb->s_magic;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
785
786
787
788
  	buf->f_bsize = sbi->cluster_size;
  	buf->f_blocks = sbi->max_cluster - FAT_START_ENT;
  	buf->f_bfree = sbi->free_clusters;
  	buf->f_bavail = sbi->free_clusters;
6d1349c76   Al Viro   [PATCH] reduce bo...
789
  	buf->f_fsid = u64_to_fsid(id);
f68e542f3   OGAWA Hirofumi   fat: Fix statfs->...
790
791
  	buf->f_namelen =
  		(sbi->options.isvfat ? FAT_LFN_LEN : 12) * NLS_MAX_CHARSET_SIZE;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
792
793
794
  
  	return 0;
  }
a9185b41a   Christoph Hellwig   pass writeback_co...
795
  static int __fat_write_inode(struct inode *inode, int wait)
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
796
797
798
799
800
801
  {
  	struct super_block *sb = inode->i_sb;
  	struct msdos_sb_info *sbi = MSDOS_SB(sb);
  	struct buffer_head *bh;
  	struct msdos_dir_entry *raw_entry;
  	loff_t i_pos;
e22a44427   Namjae Jeon   fat: introduce a ...
802
803
  	sector_t blocknr;
  	int err, offset;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
804

9ca59f4c3   OGAWA Hirofumi   fat: ->i_pos race...
805
806
  	if (inode->i_ino == MSDOS_ROOT_INO)
  		return 0;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
807
  retry:
9ca59f4c3   OGAWA Hirofumi   fat: ->i_pos race...
808
809
  	i_pos = fat_i_pos_read(sbi, inode);
  	if (!i_pos)
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
810
  		return 0;
e22a44427   Namjae Jeon   fat: introduce a ...
811
812
  	fat_get_blknr_offset(sbi, i_pos, &blocknr, &offset);
  	bh = sb_bread(sb, blocknr);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
813
  	if (!bh) {
869f58c0c   Alexey Fisher   fat: Replace all ...
814
815
  		fat_msg(sb, KERN_ERR, "unable to read inode block "
  		       "for updating (i_pos %lld)", i_pos);
5f22ca9b1   Linus Torvalds   vfat: fix 'sync' ...
816
  		return -EIO;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
817
818
819
820
821
  	}
  	spin_lock(&sbi->inode_hash_lock);
  	if (i_pos != MSDOS_I(inode)->i_pos) {
  		spin_unlock(&sbi->inode_hash_lock);
  		brelse(bh);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
822
823
  		goto retry;
  	}
e22a44427   Namjae Jeon   fat: introduce a ...
824
  	raw_entry = &((struct msdos_dir_entry *) (bh->b_data))[offset];
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
825
826
827
828
  	if (S_ISDIR(inode->i_mode))
  		raw_entry->size = 0;
  	else
  		raw_entry->size = cpu_to_le32(inode->i_size);
9c0aa1b87   OGAWA Hirofumi   fat: Cleanup FAT ...
829
  	raw_entry->attr = fat_make_attrs(inode);
a943ed71c   Steven J. Magnani   fat: accessors fo...
830
  	fat_set_start(raw_entry, MSDOS_I(inode)->i_logstart);
f423420c2   Arnd Bergmann   fat: propagate 64...
831
  	fat_time_unix2fat(sbi, &inode->i_mtime, &raw_entry->time,
7decd1cb0   OGAWA Hirofumi   fat: Fix and clea...
832
  			  &raw_entry->date, NULL);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
833
  	if (sbi->options.isvfat) {
62a36c43c   Stephane Kardas   [PATCH] fat: fix ...
834
  		__le16 atime;
f423420c2   Arnd Bergmann   fat: propagate 64...
835
  		fat_time_unix2fat(sbi, &inode->i_ctime, &raw_entry->ctime,
7decd1cb0   OGAWA Hirofumi   fat: Fix and clea...
836
  				  &raw_entry->cdate, &raw_entry->ctime_cs);
f423420c2   Arnd Bergmann   fat: propagate 64...
837
  		fat_time_unix2fat(sbi, &inode->i_atime, &atime,
7decd1cb0   OGAWA Hirofumi   fat: Fix and clea...
838
  				  &raw_entry->adate, NULL);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
839
840
841
  	}
  	spin_unlock(&sbi->inode_hash_lock);
  	mark_buffer_dirty(bh);
5f22ca9b1   Linus Torvalds   vfat: fix 'sync' ...
842
  	err = 0;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
843
844
845
  	if (wait)
  		err = sync_dirty_buffer(bh);
  	brelse(bh);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
846
847
  	return err;
  }
a9185b41a   Christoph Hellwig   pass writeback_co...
848
849
  static int fat_write_inode(struct inode *inode, struct writeback_control *wbc)
  {
78491189d   Artem Bityutskiy   fat: switch to fs...
850
851
852
853
  	int err;
  
  	if (inode->i_ino == MSDOS_FSINFO_INO) {
  		struct super_block *sb = inode->i_sb;
e40b34c79   Marco Stornelli   fat: drop lock/un...
854
  		mutex_lock(&MSDOS_SB(sb)->s_lock);
78491189d   Artem Bityutskiy   fat: switch to fs...
855
  		err = fat_clusters_flush(sb);
e40b34c79   Marco Stornelli   fat: drop lock/un...
856
  		mutex_unlock(&MSDOS_SB(sb)->s_lock);
78491189d   Artem Bityutskiy   fat: switch to fs...
857
858
859
860
  	} else
  		err = __fat_write_inode(inode, wbc->sync_mode == WB_SYNC_ALL);
  
  	return err;
a9185b41a   Christoph Hellwig   pass writeback_co...
861
  }
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
862
863
  int fat_sync_inode(struct inode *inode)
  {
a9185b41a   Christoph Hellwig   pass writeback_co...
864
  	return __fat_write_inode(inode, 1);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
865
  }
7c709d00d   OGAWA Hirofumi   [PATCH] fat: s/EX...
866
  EXPORT_SYMBOL_GPL(fat_sync_inode);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
867

34c80b1d9   Al Viro   vfs: switch ->sho...
868
  static int fat_show_options(struct seq_file *m, struct dentry *root);
ee9b6d61a   Josef 'Jeff' Sipek   [PATCH] Mark stru...
869
  static const struct super_operations fat_sops = {
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
870
  	.alloc_inode	= fat_alloc_inode,
f9ec991d4   Al Viro   fat: switch to ->...
871
  	.free_inode	= fat_free_inode,
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
872
  	.write_inode	= fat_write_inode,
deee3ce46   Al Viro   covert fatfs to -...
873
  	.evict_inode	= fat_evict_inode,
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
874
875
  	.put_super	= fat_put_super,
  	.statfs		= fat_statfs,
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
876
  	.remount_fs	= fat_remount,
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
877
878
  	.show_options	= fat_show_options,
  };
34c80b1d9   Al Viro   vfs: switch ->sho...
879
  static int fat_show_options(struct seq_file *m, struct dentry *root)
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
880
  {
34c80b1d9   Al Viro   vfs: switch ->sho...
881
  	struct msdos_sb_info *sbi = MSDOS_SB(root->d_sb);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
882
883
  	struct fat_mount_options *opts = &sbi->options;
  	int isvfat = opts->isvfat;
170782eb8   Eric W. Biederman   userns: Convert f...
884
885
886
887
888
889
  	if (!uid_eq(opts->fs_uid, GLOBAL_ROOT_UID))
  		seq_printf(m, ",uid=%u",
  				from_kuid_munged(&init_user_ns, opts->fs_uid));
  	if (!gid_eq(opts->fs_gid, GLOBAL_ROOT_GID))
  		seq_printf(m, ",gid=%u",
  				from_kgid_munged(&init_user_ns, opts->fs_gid));
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
890
891
  	seq_printf(m, ",fmask=%04o", opts->fs_fmask);
  	seq_printf(m, ",dmask=%04o", opts->fs_dmask);
1ae43f826   OGAWA Hirofumi   fat: Add allow_ut...
892
893
  	if (opts->allow_utime)
  		seq_printf(m, ",allow_utime=%04o", opts->allow_utime);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
894
  	if (sbi->nls_disk)
c6c20372b   Dave Reisner   fs/fat: strip "cp...
895
896
  		/* strip "cp" prefix from displayed option */
  		seq_printf(m, ",codepage=%s", &sbi->nls_disk->charset[2]);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
897
898
899
900
901
902
903
904
905
906
907
908
909
910
911
  	if (isvfat) {
  		if (sbi->nls_io)
  			seq_printf(m, ",iocharset=%s", sbi->nls_io->charset);
  
  		switch (opts->shortname) {
  		case VFAT_SFN_DISPLAY_WIN95 | VFAT_SFN_CREATE_WIN95:
  			seq_puts(m, ",shortname=win95");
  			break;
  		case VFAT_SFN_DISPLAY_WINNT | VFAT_SFN_CREATE_WINNT:
  			seq_puts(m, ",shortname=winnt");
  			break;
  		case VFAT_SFN_DISPLAY_WINNT | VFAT_SFN_CREATE_WIN95:
  			seq_puts(m, ",shortname=mixed");
  			break;
  		case VFAT_SFN_DISPLAY_LOWER | VFAT_SFN_CREATE_WIN95:
955234755   Paul Wise   vfat: change the ...
912
  			seq_puts(m, ",shortname=lower");
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
913
914
915
916
917
918
919
920
  			break;
  		default:
  			seq_puts(m, ",shortname=unknown");
  			break;
  		}
  	}
  	if (opts->name_check != 'n')
  		seq_printf(m, ",check=%c", opts->name_check);
28ec039c2   OGAWA Hirofumi   fat: don't use fr...
921
922
  	if (opts->usefree)
  		seq_puts(m, ",usefree");
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
923
924
925
926
927
928
929
930
931
932
933
934
935
936
937
938
939
940
  	if (opts->quiet)
  		seq_puts(m, ",quiet");
  	if (opts->showexec)
  		seq_puts(m, ",showexec");
  	if (opts->sys_immutable)
  		seq_puts(m, ",sys_immutable");
  	if (!isvfat) {
  		if (opts->dotsOK)
  			seq_puts(m, ",dotsOK=yes");
  		if (opts->nocase)
  			seq_puts(m, ",nocase");
  	} else {
  		if (opts->utf8)
  			seq_puts(m, ",utf8");
  		if (opts->unicode_xlate)
  			seq_puts(m, ",uni_xlate");
  		if (!opts->numtail)
  			seq_puts(m, ",nonumtail");
dfc209c00   OGAWA Hirofumi   fat: Fix ATTR_RO ...
941
942
  		if (opts->rodir)
  			seq_puts(m, ",rodir");
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
943
  	}
dfc209c00   OGAWA Hirofumi   fat: Fix ATTR_RO ...
944
  	if (opts->flush)
c1fca3b60   Miklos Szeredi   mount options: fi...
945
  		seq_puts(m, ",flush");
58156c8fb   Jan Kara   fat: provide opti...
946
947
948
949
950
951
  	if (opts->tz_set) {
  		if (opts->time_offset)
  			seq_printf(m, ",time_offset=%d", opts->time_offset);
  		else
  			seq_puts(m, ",tz=UTC");
  	}
85c785919   Denis Karpov   FAT: add 'errors'...
952
953
954
955
956
957
  	if (opts->errors == FAT_ERRORS_CONT)
  		seq_puts(m, ",errors=continue");
  	else if (opts->errors == FAT_ERRORS_PANIC)
  		seq_puts(m, ",errors=panic");
  	else
  		seq_puts(m, ",errors=remount-ro");
2628b7a6a   Namjae Jeon   fat: introduce 2 ...
958
959
960
961
  	if (opts->nfs == FAT_NFS_NOSTALE_RO)
  		seq_puts(m, ",nfs=nostale_ro");
  	else if (opts->nfs)
  		seq_puts(m, ",nfs=stale_rw");
681142f92   Christoph Hellwig   fat: make discard...
962
963
  	if (opts->discard)
  		seq_puts(m, ",discard");
190a8843d   Conrad Meyer   fs/fat/: add supp...
964
965
  	if (opts->dos1xfloppy)
  		seq_puts(m, ",dos1xfloppy");
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
966
967
968
969
970
971
  
  	return 0;
  }
  
  enum {
  	Opt_check_n, Opt_check_r, Opt_check_s, Opt_uid, Opt_gid,
1ae43f826   OGAWA Hirofumi   fat: Add allow_ut...
972
973
974
  	Opt_umask, Opt_dmask, Opt_fmask, Opt_allow_utime, Opt_codepage,
  	Opt_usefree, Opt_nocase, Opt_quiet, Opt_showexec, Opt_debug,
  	Opt_immutable, Opt_dots, Opt_nodots,
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
975
976
977
  	Opt_charset, Opt_shortname_lower, Opt_shortname_win95,
  	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,
d7a83c0f7   Geert Uytterhoeven   fat: Spelling s/o...
978
  	Opt_obsolete, Opt_flush, Opt_tz_utc, Opt_rodir, Opt_err_cont,
58156c8fb   Jan Kara   fat: provide opti...
979
  	Opt_err_panic, Opt_err_ro, Opt_discard, Opt_nfs, Opt_time_offset,
190a8843d   Conrad Meyer   fs/fat/: add supp...
980
  	Opt_nfs_stale_rw, Opt_nfs_nostale_ro, Opt_err, Opt_dos1xfloppy,
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
981
  };
a447c0932   Steven Whitehouse   vfs: Use const fo...
982
  static const match_table_t fat_tokens = {
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
983
984
985
986
987
988
989
990
991
992
993
  	{Opt_check_r, "check=relaxed"},
  	{Opt_check_s, "check=strict"},
  	{Opt_check_n, "check=normal"},
  	{Opt_check_r, "check=r"},
  	{Opt_check_s, "check=s"},
  	{Opt_check_n, "check=n"},
  	{Opt_uid, "uid=%u"},
  	{Opt_gid, "gid=%u"},
  	{Opt_umask, "umask=%o"},
  	{Opt_dmask, "dmask=%o"},
  	{Opt_fmask, "fmask=%o"},
1ae43f826   OGAWA Hirofumi   fat: Add allow_ut...
994
  	{Opt_allow_utime, "allow_utime=%o"},
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
995
  	{Opt_codepage, "codepage=%u"},
28ec039c2   OGAWA Hirofumi   fat: don't use fr...
996
  	{Opt_usefree, "usefree"},
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
997
998
999
1000
1001
  	{Opt_nocase, "nocase"},
  	{Opt_quiet, "quiet"},
  	{Opt_showexec, "showexec"},
  	{Opt_debug, "debug"},
  	{Opt_immutable, "sys_immutable"},
85c785919   Denis Karpov   FAT: add 'errors'...
1002
1003
  	{Opt_flush, "flush"},
  	{Opt_tz_utc, "tz=UTC"},
58156c8fb   Jan Kara   fat: provide opti...
1004
  	{Opt_time_offset, "time_offset=%d"},
85c785919   Denis Karpov   FAT: add 'errors'...
1005
1006
1007
  	{Opt_err_cont, "errors=continue"},
  	{Opt_err_panic, "errors=panic"},
  	{Opt_err_ro, "errors=remount-ro"},
681142f92   Christoph Hellwig   fat: make discard...
1008
  	{Opt_discard, "discard"},
2628b7a6a   Namjae Jeon   fat: introduce 2 ...
1009
1010
1011
  	{Opt_nfs_stale_rw, "nfs"},
  	{Opt_nfs_stale_rw, "nfs=stale_rw"},
  	{Opt_nfs_nostale_ro, "nfs=nostale_ro"},
190a8843d   Conrad Meyer   fs/fat/: add supp...
1012
  	{Opt_dos1xfloppy, "dos1xfloppy"},
d7a83c0f7   Geert Uytterhoeven   fat: Spelling s/o...
1013
1014
1015
1016
1017
1018
1019
1020
1021
1022
1023
  	{Opt_obsolete, "conv=binary"},
  	{Opt_obsolete, "conv=text"},
  	{Opt_obsolete, "conv=auto"},
  	{Opt_obsolete, "conv=b"},
  	{Opt_obsolete, "conv=t"},
  	{Opt_obsolete, "conv=a"},
  	{Opt_obsolete, "fat=%u"},
  	{Opt_obsolete, "blocksize=%u"},
  	{Opt_obsolete, "cvf_format=%20s"},
  	{Opt_obsolete, "cvf_options=%100s"},
  	{Opt_obsolete, "posix"},
ae78bf9c4   Chris Mason   [PATCH] add -o fl...
1024
  	{Opt_err, NULL},
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
1025
  };
a447c0932   Steven Whitehouse   vfs: Use const fo...
1026
  static const match_table_t msdos_tokens = {
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
1027
1028
1029
1030
1031
1032
  	{Opt_nodots, "nodots"},
  	{Opt_nodots, "dotsOK=no"},
  	{Opt_dots, "dots"},
  	{Opt_dots, "dotsOK=yes"},
  	{Opt_err, NULL}
  };
a447c0932   Steven Whitehouse   vfs: Use const fo...
1033
  static const match_table_t vfat_tokens = {
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
1034
1035
1036
1037
1038
1039
1040
1041
1042
1043
1044
1045
1046
1047
1048
1049
1050
1051
1052
1053
1054
1055
1056
1057
1058
1059
  	{Opt_charset, "iocharset=%s"},
  	{Opt_shortname_lower, "shortname=lower"},
  	{Opt_shortname_win95, "shortname=win95"},
  	{Opt_shortname_winnt, "shortname=winnt"},
  	{Opt_shortname_mixed, "shortname=mixed"},
  	{Opt_utf8_no, "utf8=0"},		/* 0 or no or false */
  	{Opt_utf8_no, "utf8=no"},
  	{Opt_utf8_no, "utf8=false"},
  	{Opt_utf8_yes, "utf8=1"},		/* empty or 1 or yes or true */
  	{Opt_utf8_yes, "utf8=yes"},
  	{Opt_utf8_yes, "utf8=true"},
  	{Opt_utf8_yes, "utf8"},
  	{Opt_uni_xl_no, "uni_xlate=0"},		/* 0 or no or false */
  	{Opt_uni_xl_no, "uni_xlate=no"},
  	{Opt_uni_xl_no, "uni_xlate=false"},
  	{Opt_uni_xl_yes, "uni_xlate=1"},	/* empty or 1 or yes or true */
  	{Opt_uni_xl_yes, "uni_xlate=yes"},
  	{Opt_uni_xl_yes, "uni_xlate=true"},
  	{Opt_uni_xl_yes, "uni_xlate"},
  	{Opt_nonumtail_no, "nonumtail=0"},	/* 0 or no or false */
  	{Opt_nonumtail_no, "nonumtail=no"},
  	{Opt_nonumtail_no, "nonumtail=false"},
  	{Opt_nonumtail_yes, "nonumtail=1"},	/* empty or 1 or yes or true */
  	{Opt_nonumtail_yes, "nonumtail=yes"},
  	{Opt_nonumtail_yes, "nonumtail=true"},
  	{Opt_nonumtail_yes, "nonumtail"},
dfc209c00   OGAWA Hirofumi   fat: Fix ATTR_RO ...
1060
  	{Opt_rodir, "rodir"},
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
1061
1062
  	{Opt_err, NULL}
  };
869f58c0c   Alexey Fisher   fat: Replace all ...
1063
1064
  static int parse_options(struct super_block *sb, char *options, int is_vfat,
  			 int silent, int *debug, struct fat_mount_options *opts)
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
1065
1066
1067
1068
1069
1070
1071
  {
  	char *p;
  	substring_t args[MAX_OPT_ARGS];
  	int option;
  	char *iocharset;
  
  	opts->isvfat = is_vfat;
f0ce7ee3a   David Howells   CRED: Wrap task c...
1072
1073
  	opts->fs_uid = current_uid();
  	opts->fs_gid = current_gid();
3e107603a   OGAWA Hirofumi   fat: Fix the remo...
1074
  	opts->fs_fmask = opts->fs_dmask = current_umask();
1ae43f826   OGAWA Hirofumi   fat: Add allow_ut...
1075
  	opts->allow_utime = -1;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
1076
  	opts->codepage = fat_default_codepage;
35033ab98   OGAWA Hirofumi   fat: fix memory a...
1077
  	fat_reset_iocharset(opts);
dfc209c00   OGAWA Hirofumi   fat: Fix ATTR_RO ...
1078
  	if (is_vfat) {
955234755   Paul Wise   vfat: change the ...
1079
  		opts->shortname = VFAT_SFN_DISPLAY_WINNT|VFAT_SFN_CREATE_WIN95;
dfc209c00   OGAWA Hirofumi   fat: Fix ATTR_RO ...
1080
1081
  		opts->rodir = 0;
  	} else {
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
1082
  		opts->shortname = 0;
dfc209c00   OGAWA Hirofumi   fat: Fix ATTR_RO ...
1083
1084
  		opts->rodir = 1;
  	}
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
1085
1086
  	opts->name_check = 'n';
  	opts->quiet = opts->showexec = opts->sys_immutable = opts->dotsOK =  0;
387393806   Maciej S. Szmigiero   fat: add config o...
1087
  	opts->unicode_xlate = 0;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
1088
  	opts->numtail = 1;
28ec039c2   OGAWA Hirofumi   fat: don't use fr...
1089
  	opts->usefree = opts->nocase = 0;
58156c8fb   Jan Kara   fat: provide opti...
1090
  	opts->tz_set = 0;
7669e8fb0   Steven J. Magnani   fat (exportfs): f...
1091
  	opts->nfs = 0;
85c785919   Denis Karpov   FAT: add 'errors'...
1092
  	opts->errors = FAT_ERRORS_RO;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
1093
  	*debug = 0;
387393806   Maciej S. Szmigiero   fat: add config o...
1094
  	opts->utf8 = IS_ENABLED(CONFIG_FAT_DEFAULT_UTF8) && is_vfat;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
1095
  	if (!options)
8d44d9741   OGAWA Hirofumi   fat: fix parse_op...
1096
  		goto out;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
1097
1098
1099
1100
1101
1102
1103
1104
1105
1106
1107
1108
1109
1110
1111
1112
1113
1114
1115
1116
1117
1118
1119
  
  	while ((p = strsep(&options, ",")) != NULL) {
  		int token;
  		if (!*p)
  			continue;
  
  		token = match_token(p, fat_tokens, args);
  		if (token == Opt_err) {
  			if (is_vfat)
  				token = match_token(p, vfat_tokens, args);
  			else
  				token = match_token(p, msdos_tokens, args);
  		}
  		switch (token) {
  		case Opt_check_s:
  			opts->name_check = 's';
  			break;
  		case Opt_check_r:
  			opts->name_check = 'r';
  			break;
  		case Opt_check_n:
  			opts->name_check = 'n';
  			break;
28ec039c2   OGAWA Hirofumi   fat: don't use fr...
1120
1121
1122
  		case Opt_usefree:
  			opts->usefree = 1;
  			break;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
1123
1124
1125
1126
1127
1128
1129
1130
1131
1132
1133
1134
1135
1136
1137
1138
1139
1140
1141
1142
1143
1144
1145
  		case Opt_nocase:
  			if (!is_vfat)
  				opts->nocase = 1;
  			else {
  				/* for backward compatibility */
  				opts->shortname = VFAT_SFN_DISPLAY_WIN95
  					| VFAT_SFN_CREATE_WIN95;
  			}
  			break;
  		case Opt_quiet:
  			opts->quiet = 1;
  			break;
  		case Opt_showexec:
  			opts->showexec = 1;
  			break;
  		case Opt_debug:
  			*debug = 1;
  			break;
  		case Opt_immutable:
  			opts->sys_immutable = 1;
  			break;
  		case Opt_uid:
  			if (match_int(&args[0], &option))
5b3d5aeaa   Jan Kara   fat: ix mount opt...
1146
  				return -EINVAL;
170782eb8   Eric W. Biederman   userns: Convert f...
1147
1148
  			opts->fs_uid = make_kuid(current_user_ns(), option);
  			if (!uid_valid(opts->fs_uid))
5b3d5aeaa   Jan Kara   fat: ix mount opt...
1149
  				return -EINVAL;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
1150
1151
1152
  			break;
  		case Opt_gid:
  			if (match_int(&args[0], &option))
5b3d5aeaa   Jan Kara   fat: ix mount opt...
1153
  				return -EINVAL;
170782eb8   Eric W. Biederman   userns: Convert f...
1154
1155
  			opts->fs_gid = make_kgid(current_user_ns(), option);
  			if (!gid_valid(opts->fs_gid))
5b3d5aeaa   Jan Kara   fat: ix mount opt...
1156
  				return -EINVAL;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
1157
1158
1159
  			break;
  		case Opt_umask:
  			if (match_octal(&args[0], &option))
5b3d5aeaa   Jan Kara   fat: ix mount opt...
1160
  				return -EINVAL;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
1161
1162
1163
1164
  			opts->fs_fmask = opts->fs_dmask = option;
  			break;
  		case Opt_dmask:
  			if (match_octal(&args[0], &option))
5b3d5aeaa   Jan Kara   fat: ix mount opt...
1165
  				return -EINVAL;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
1166
1167
1168
1169
  			opts->fs_dmask = option;
  			break;
  		case Opt_fmask:
  			if (match_octal(&args[0], &option))
5b3d5aeaa   Jan Kara   fat: ix mount opt...
1170
  				return -EINVAL;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
1171
1172
  			opts->fs_fmask = option;
  			break;
1ae43f826   OGAWA Hirofumi   fat: Add allow_ut...
1173
1174
  		case Opt_allow_utime:
  			if (match_octal(&args[0], &option))
5b3d5aeaa   Jan Kara   fat: ix mount opt...
1175
  				return -EINVAL;
1ae43f826   OGAWA Hirofumi   fat: Add allow_ut...
1176
1177
  			opts->allow_utime = option & (S_IWGRP | S_IWOTH);
  			break;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
1178
1179
  		case Opt_codepage:
  			if (match_int(&args[0], &option))
5b3d5aeaa   Jan Kara   fat: ix mount opt...
1180
  				return -EINVAL;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
1181
1182
  			opts->codepage = option;
  			break;
ae78bf9c4   Chris Mason   [PATCH] add -o fl...
1183
1184
1185
  		case Opt_flush:
  			opts->flush = 1;
  			break;
58156c8fb   Jan Kara   fat: provide opti...
1186
1187
  		case Opt_time_offset:
  			if (match_int(&args[0], &option))
5b3d5aeaa   Jan Kara   fat: ix mount opt...
1188
  				return -EINVAL;
a513d8698   Jan Kara   fat: allow time_o...
1189
1190
1191
1192
1193
1194
  			/*
  			 * GMT+-12 zones may have DST corrections so at least
  			 * 13 hours difference is needed. Make the limit 24
  			 * just in case someone invents something unusual.
  			 */
  			if (option < -24 * 60 || option > 24 * 60)
5b3d5aeaa   Jan Kara   fat: ix mount opt...
1195
  				return -EINVAL;
58156c8fb   Jan Kara   fat: provide opti...
1196
1197
1198
  			opts->tz_set = 1;
  			opts->time_offset = option;
  			break;
b271e067c   Joe Peterson   fatfs: add UTC ti...
1199
  		case Opt_tz_utc:
58156c8fb   Jan Kara   fat: provide opti...
1200
1201
  			opts->tz_set = 1;
  			opts->time_offset = 0;
b271e067c   Joe Peterson   fatfs: add UTC ti...
1202
  			break;
85c785919   Denis Karpov   FAT: add 'errors'...
1203
1204
1205
1206
1207
1208
1209
1210
1211
  		case Opt_err_cont:
  			opts->errors = FAT_ERRORS_CONT;
  			break;
  		case Opt_err_panic:
  			opts->errors = FAT_ERRORS_PANIC;
  			break;
  		case Opt_err_ro:
  			opts->errors = FAT_ERRORS_RO;
  			break;
2628b7a6a   Namjae Jeon   fat: introduce 2 ...
1212
1213
1214
1215
1216
1217
  		case Opt_nfs_stale_rw:
  			opts->nfs = FAT_NFS_STALE_RW;
  			break;
  		case Opt_nfs_nostale_ro:
  			opts->nfs = FAT_NFS_NOSTALE_RO;
  			break;
190a8843d   Conrad Meyer   fs/fat/: add supp...
1218
1219
1220
  		case Opt_dos1xfloppy:
  			opts->dos1xfloppy = 1;
  			break;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
1221
1222
1223
1224
1225
1226
1227
1228
1229
1230
1231
  
  		/* msdos specific */
  		case Opt_dots:
  			opts->dotsOK = 1;
  			break;
  		case Opt_nodots:
  			opts->dotsOK = 0;
  			break;
  
  		/* vfat specific */
  		case Opt_charset:
35033ab98   OGAWA Hirofumi   fat: fix memory a...
1232
  			fat_reset_iocharset(opts);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
1233
1234
1235
1236
1237
1238
1239
1240
1241
1242
1243
1244
1245
1246
1247
1248
1249
1250
1251
1252
1253
1254
1255
1256
1257
1258
1259
1260
1261
1262
1263
1264
1265
1266
1267
1268
1269
1270
1271
  			iocharset = match_strdup(&args[0]);
  			if (!iocharset)
  				return -ENOMEM;
  			opts->iocharset = iocharset;
  			break;
  		case Opt_shortname_lower:
  			opts->shortname = VFAT_SFN_DISPLAY_LOWER
  					| VFAT_SFN_CREATE_WIN95;
  			break;
  		case Opt_shortname_win95:
  			opts->shortname = VFAT_SFN_DISPLAY_WIN95
  					| VFAT_SFN_CREATE_WIN95;
  			break;
  		case Opt_shortname_winnt:
  			opts->shortname = VFAT_SFN_DISPLAY_WINNT
  					| VFAT_SFN_CREATE_WINNT;
  			break;
  		case Opt_shortname_mixed:
  			opts->shortname = VFAT_SFN_DISPLAY_WINNT
  					| VFAT_SFN_CREATE_WIN95;
  			break;
  		case Opt_utf8_no:		/* 0 or no or false */
  			opts->utf8 = 0;
  			break;
  		case Opt_utf8_yes:		/* empty or 1 or yes or true */
  			opts->utf8 = 1;
  			break;
  		case Opt_uni_xl_no:		/* 0 or no or false */
  			opts->unicode_xlate = 0;
  			break;
  		case Opt_uni_xl_yes:		/* empty or 1 or yes or true */
  			opts->unicode_xlate = 1;
  			break;
  		case Opt_nonumtail_no:		/* 0 or no or false */
  			opts->numtail = 1;	/* negated option */
  			break;
  		case Opt_nonumtail_yes:		/* empty or 1 or yes or true */
  			opts->numtail = 0;	/* negated option */
  			break;
dfc209c00   OGAWA Hirofumi   fat: Fix ATTR_RO ...
1272
1273
1274
  		case Opt_rodir:
  			opts->rodir = 1;
  			break;
681142f92   Christoph Hellwig   fat: make discard...
1275
1276
1277
  		case Opt_discard:
  			opts->discard = 1;
  			break;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
1278
1279
  
  		/* obsolete mount options */
d7a83c0f7   Geert Uytterhoeven   fat: Spelling s/o...
1280
  		case Opt_obsolete:
869f58c0c   Alexey Fisher   fat: Replace all ...
1281
1282
  			fat_msg(sb, KERN_INFO, "\"%s\" option is obsolete, "
  			       "not supported now", p);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
1283
1284
1285
  			break;
  		/* unknown option */
  		default:
41a34a4fe   Christoph Hellwig   [PATCH] fat: resp...
1286
  			if (!silent) {
869f58c0c   Alexey Fisher   fat: Replace all ...
1287
1288
1289
  				fat_msg(sb, KERN_ERR,
  				       "Unrecognized mount option \"%s\" "
  				       "or missing value", p);
41a34a4fe   Christoph Hellwig   [PATCH] fat: resp...
1290
  			}
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
1291
1292
1293
  			return -EINVAL;
  		}
  	}
8d44d9741   OGAWA Hirofumi   fat: fix parse_op...
1294
1295
  
  out:
4de151d8c   Alexey Dobriyan   It's UTF-8
1296
  	/* UTF-8 doesn't provide FAT semantics */
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
1297
  	if (!strcmp(opts->iocharset, "utf8")) {
186b53701   Mihai Moldovan   fat: fix utf8 ioc...
1298
  		fat_msg(sb, KERN_WARNING, "utf8 is not a recommended IO charset"
8d44d9741   OGAWA Hirofumi   fat: fix parse_op...
1299
  		       " for FAT filesystems, filesystem will be "
186b53701   Mihai Moldovan   fat: fix utf8 ioc...
1300
  		       "case sensitive!");
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
1301
  	}
1ae43f826   OGAWA Hirofumi   fat: Add allow_ut...
1302
1303
1304
  	/* If user doesn't specify allow_utime, it's initialized from dmask. */
  	if (opts->allow_utime == (unsigned short)-1)
  		opts->allow_utime = ~opts->fs_dmask & (S_IWGRP | S_IWOTH);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
1305
1306
  	if (opts->unicode_xlate)
  		opts->utf8 = 0;
ea3983ace   Namjae Jeon   fat: restructure ...
1307
  	if (opts->nfs == FAT_NFS_NOSTALE_RO) {
1751e8a6c   Linus Torvalds   Rename superblock...
1308
  		sb->s_flags |= SB_RDONLY;
ea3983ace   Namjae Jeon   fat: restructure ...
1309
1310
  		sb->s_export_op = &fat_export_ops_nostale;
  	}
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
1311
1312
1313
1314
1315
1316
  
  	return 0;
  }
  
  static int fat_read_root(struct inode *inode)
  {
a40a7d9d0   Alexander Kuleshov   fs/fat: remove un...
1317
  	struct msdos_sb_info *sbi = MSDOS_SB(inode->i_sb);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
1318
  	int error;
ea3983ace   Namjae Jeon   fat: restructure ...
1319
  	MSDOS_I(inode)->i_pos = MSDOS_ROOT_INO;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
1320
1321
  	inode->i_uid = sbi->options.fs_uid;
  	inode->i_gid = sbi->options.fs_gid;
2489dbabe   Jeff Layton   fat: convert to n...
1322
  	inode_inc_iversion(inode);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
1323
  	inode->i_generation = 0;
9c0aa1b87   OGAWA Hirofumi   fat: Cleanup FAT ...
1324
  	inode->i_mode = fat_make_mode(sbi, ATTR_DIR, S_IRWXUGO);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
1325
1326
  	inode->i_op = sbi->dir_ops;
  	inode->i_fop = &fat_dir_operations;
306790f75   Carmeli Tamir   fat: new inline f...
1327
  	if (is_fat32(sbi)) {
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
1328
1329
1330
1331
1332
1333
1334
1335
  		MSDOS_I(inode)->i_start = sbi->root_cluster;
  		error = fat_calc_dir_size(inode);
  		if (error < 0)
  			return error;
  	} else {
  		MSDOS_I(inode)->i_start = 0;
  		inode->i_size = sbi->dir_entries * sizeof(struct msdos_dir_entry);
  	}
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
1336
1337
1338
1339
  	inode->i_blocks = ((inode->i_size + (sbi->cluster_size - 1))
  			   & ~((loff_t)sbi->cluster_size - 1)) >> 9;
  	MSDOS_I(inode)->i_logstart = 0;
  	MSDOS_I(inode)->mmu_private = inode->i_size;
9c0aa1b87   OGAWA Hirofumi   fat: Cleanup FAT ...
1340
  	fat_save_attrs(inode, ATTR_DIR);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
1341
1342
  	inode->i_mtime.tv_sec = inode->i_atime.tv_sec = inode->i_ctime.tv_sec = 0;
  	inode->i_mtime.tv_nsec = inode->i_atime.tv_nsec = inode->i_ctime.tv_nsec = 0;
bfe868486   Miklos Szeredi   filesystems: add ...
1343
  	set_nlink(inode, fat_subdirs(inode)+2);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
1344
1345
1346
  
  	return 0;
  }
7b92d03c3   OGAWA Hirofumi   fat: fix possible...
1347
1348
1349
1350
1351
  static unsigned long calc_fat_clusters(struct super_block *sb)
  {
  	struct msdos_sb_info *sbi = MSDOS_SB(sb);
  
  	/* Divide first to avoid overflow */
306790f75   Carmeli Tamir   fat: new inline f...
1352
  	if (!is_fat12(sbi)) {
7b92d03c3   OGAWA Hirofumi   fat: fix possible...
1353
1354
1355
1356
1357
1358
  		unsigned long ent_per_sec = sb->s_blocksize * 8 / sbi->fat_bits;
  		return ent_per_sec * sbi->fat_length;
  	}
  
  	return sbi->fat_length * sb->s_blocksize * 8 / sbi->fat_bits;
  }
190a8843d   Conrad Meyer   fs/fat/: add supp...
1359
1360
1361
1362
1363
1364
1365
1366
1367
1368
1369
1370
1371
1372
1373
1374
1375
1376
1377
1378
1379
1380
1381
1382
1383
1384
1385
1386
1387
1388
1389
1390
1391
1392
1393
1394
1395
1396
1397
1398
1399
1400
1401
1402
1403
1404
1405
1406
1407
1408
1409
1410
1411
1412
1413
1414
1415
1416
1417
1418
1419
1420
1421
1422
1423
1424
1425
1426
1427
1428
1429
1430
1431
1432
1433
1434
1435
1436
1437
1438
1439
1440
1441
1442
1443
1444
1445
1446
1447
1448
  static bool fat_bpb_is_zero(struct fat_boot_sector *b)
  {
  	if (get_unaligned_le16(&b->sector_size))
  		return false;
  	if (b->sec_per_clus)
  		return false;
  	if (b->reserved)
  		return false;
  	if (b->fats)
  		return false;
  	if (get_unaligned_le16(&b->dir_entries))
  		return false;
  	if (get_unaligned_le16(&b->sectors))
  		return false;
  	if (b->media)
  		return false;
  	if (b->fat_length)
  		return false;
  	if (b->secs_track)
  		return false;
  	if (b->heads)
  		return false;
  	return true;
  }
  
  static int fat_read_bpb(struct super_block *sb, struct fat_boot_sector *b,
  	int silent, struct fat_bios_param_block *bpb)
  {
  	int error = -EINVAL;
  
  	/* Read in BPB ... */
  	memset(bpb, 0, sizeof(*bpb));
  	bpb->fat_sector_size = get_unaligned_le16(&b->sector_size);
  	bpb->fat_sec_per_clus = b->sec_per_clus;
  	bpb->fat_reserved = le16_to_cpu(b->reserved);
  	bpb->fat_fats = b->fats;
  	bpb->fat_dir_entries = get_unaligned_le16(&b->dir_entries);
  	bpb->fat_sectors = get_unaligned_le16(&b->sectors);
  	bpb->fat_fat_length = le16_to_cpu(b->fat_length);
  	bpb->fat_total_sect = le32_to_cpu(b->total_sect);
  
  	bpb->fat16_state = b->fat16.state;
  	bpb->fat16_vol_id = get_unaligned_le32(b->fat16.vol_id);
  
  	bpb->fat32_length = le32_to_cpu(b->fat32.length);
  	bpb->fat32_root_cluster = le32_to_cpu(b->fat32.root_cluster);
  	bpb->fat32_info_sector = le16_to_cpu(b->fat32.info_sector);
  	bpb->fat32_state = b->fat32.state;
  	bpb->fat32_vol_id = get_unaligned_le32(b->fat32.vol_id);
  
  	/* Validate this looks like a FAT filesystem BPB */
  	if (!bpb->fat_reserved) {
  		if (!silent)
  			fat_msg(sb, KERN_ERR,
  				"bogus number of reserved sectors");
  		goto out;
  	}
  	if (!bpb->fat_fats) {
  		if (!silent)
  			fat_msg(sb, KERN_ERR, "bogus number of FAT structure");
  		goto out;
  	}
  
  	/*
  	 * Earlier we checked here that b->secs_track and b->head are nonzero,
  	 * but it turns out valid FAT filesystems can have zero there.
  	 */
  
  	if (!fat_valid_media(b->media)) {
  		if (!silent)
  			fat_msg(sb, KERN_ERR, "invalid media value (0x%02x)",
  				(unsigned)b->media);
  		goto out;
  	}
  
  	if (!is_power_of_2(bpb->fat_sector_size)
  	    || (bpb->fat_sector_size < 512)
  	    || (bpb->fat_sector_size > 4096)) {
  		if (!silent)
  			fat_msg(sb, KERN_ERR, "bogus logical sector size %u",
  			       (unsigned)bpb->fat_sector_size);
  		goto out;
  	}
  
  	if (!is_power_of_2(bpb->fat_sec_per_clus)) {
  		if (!silent)
  			fat_msg(sb, KERN_ERR, "bogus sectors per cluster %u",
  				(unsigned)bpb->fat_sec_per_clus);
  		goto out;
  	}
b1b65750b   OGAWA Hirofumi   fat: don't allow ...
1449
1450
1451
1452
1453
  	if (bpb->fat_fat_length == 0 && bpb->fat32_length == 0) {
  		if (!silent)
  			fat_msg(sb, KERN_ERR, "bogus number of FAT sectors");
  		goto out;
  	}
190a8843d   Conrad Meyer   fs/fat/: add supp...
1454
1455
1456
1457
1458
1459
1460
1461
1462
1463
1464
1465
1466
1467
1468
1469
1470
1471
1472
1473
1474
1475
1476
1477
1478
1479
1480
1481
1482
1483
1484
1485
1486
1487
1488
1489
1490
1491
1492
1493
1494
1495
1496
1497
1498
1499
1500
1501
1502
1503
1504
1505
1506
1507
1508
1509
1510
1511
1512
1513
1514
1515
1516
1517
1518
1519
1520
1521
1522
1523
1524
  	error = 0;
  
  out:
  	return error;
  }
  
  static int fat_read_static_bpb(struct super_block *sb,
  	struct fat_boot_sector *b, int silent,
  	struct fat_bios_param_block *bpb)
  {
  	static const char *notdos1x = "This doesn't look like a DOS 1.x volume";
  
  	struct fat_floppy_defaults *fdefaults = NULL;
  	int error = -EINVAL;
  	sector_t bd_sects;
  	unsigned i;
  
  	bd_sects = i_size_read(sb->s_bdev->bd_inode) / SECTOR_SIZE;
  
  	/* 16-bit DOS 1.x reliably wrote bootstrap short-jmp code */
  	if (b->ignored[0] != 0xeb || b->ignored[2] != 0x90) {
  		if (!silent)
  			fat_msg(sb, KERN_ERR,
  				"%s; no bootstrapping code", notdos1x);
  		goto out;
  	}
  
  	/*
  	 * If any value in this region is non-zero, it isn't archaic
  	 * DOS.
  	 */
  	if (!fat_bpb_is_zero(b)) {
  		if (!silent)
  			fat_msg(sb, KERN_ERR,
  				"%s; DOS 2.x BPB is non-zero", notdos1x);
  		goto out;
  	}
  
  	for (i = 0; i < ARRAY_SIZE(floppy_defaults); i++) {
  		if (floppy_defaults[i].nr_sectors == bd_sects) {
  			fdefaults = &floppy_defaults[i];
  			break;
  		}
  	}
  
  	if (fdefaults == NULL) {
  		if (!silent)
  			fat_msg(sb, KERN_WARNING,
  				"This looks like a DOS 1.x volume, but isn't a recognized floppy size (%llu sectors)",
  				(u64)bd_sects);
  		goto out;
  	}
  
  	if (!silent)
  		fat_msg(sb, KERN_INFO,
  			"This looks like a DOS 1.x volume; assuming default BPB values");
  
  	memset(bpb, 0, sizeof(*bpb));
  	bpb->fat_sector_size = SECTOR_SIZE;
  	bpb->fat_sec_per_clus = fdefaults->sec_per_clus;
  	bpb->fat_reserved = 1;
  	bpb->fat_fats = 2;
  	bpb->fat_dir_entries = fdefaults->dir_entries;
  	bpb->fat_sectors = fdefaults->nr_sectors;
  	bpb->fat_fat_length = fdefaults->fat_length;
  
  	error = 0;
  
  out:
  	return error;
  }
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
1525
1526
1527
  /*
   * Read the super block of an MS-DOS FS.
   */
384f5c96e   OGAWA Hirofumi   fat: use new setu...
1528
  int fat_fill_super(struct super_block *sb, void *data, int silent, int isvfat,
3d23985d6   Al Viro   switch fat to ->s...
1529
  		   void (*setup)(struct super_block *))
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
1530
  {
b522412ae   Al Viro   Sanitize ->fsync(...
1531
  	struct inode *root_inode = NULL, *fat_inode = NULL;
020ac5b6b   Artem Bityutskiy   fat: introduce sp...
1532
  	struct inode *fsinfo_inode = NULL;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
1533
  	struct buffer_head *bh;
190a8843d   Conrad Meyer   fs/fat/: add supp...
1534
  	struct fat_bios_param_block bpb;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
1535
1536
1537
1538
  	struct msdos_sb_info *sbi;
  	u16 logical_sector_size;
  	u32 total_sectors, total_clusters, fat_clusters, rootdir_sectors;
  	int debug;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
1539
1540
  	long error;
  	char buf[50];
c0da64f6b   Deepa Dinamani   fs: fat: Initiali...
1541
  	struct timespec64 ts;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
1542

8f5934278   Linus Torvalds   Replace BKL with ...
1543
1544
  	/*
  	 * GFP_KERNEL is ok here, because while we do hold the
dcc381e83   Zheng Lv   fat: fix typo s/s...
1545
  	 * superblock lock, memory pressure can't call back into
8f5934278   Linus Torvalds   Replace BKL with ...
1546
1547
1548
  	 * the filesystem, since we're only just about to mount
  	 * it and have no inodes etc active!
  	 */
f8314dc60   Panagiotis Issaris   [PATCH] fs: Conve...
1549
  	sbi = kzalloc(sizeof(struct msdos_sb_info), GFP_KERNEL);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
1550
1551
1552
  	if (!sbi)
  		return -ENOMEM;
  	sb->s_fs_info = sbi;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
1553

1751e8a6c   Linus Torvalds   Rename superblock...
1554
  	sb->s_flags |= SB_NODIRATIME;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
1555
1556
1557
  	sb->s_magic = MSDOS_SUPER_MAGIC;
  	sb->s_op = &fat_sops;
  	sb->s_export_op = &fat_export_ops;
6bb885ecd   Frank Sorenson   fat: add function...
1558
1559
1560
1561
1562
  	/*
  	 * fat timestamps are complex and truncated by fat itself, so
  	 * we set 1 here to be fast
  	 */
  	sb->s_time_gran = 1;
8fceb4e01   Namjae Jeon   fat (exportfs): r...
1563
  	mutex_init(&sbi->nfs_build_inode_lock);
aaa04b487   OGAWA Hirofumi   fatfs: ratelimit ...
1564
1565
  	ratelimit_state_init(&sbi->ratelimit, DEFAULT_RATELIMIT_INTERVAL,
  			     DEFAULT_RATELIMIT_BURST);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
1566

869f58c0c   Alexey Fisher   fat: Replace all ...
1567
  	error = parse_options(sb, data, isvfat, silent, &debug, &sbi->options);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
1568
1569
  	if (error)
  		goto out_fail;
3d23985d6   Al Viro   switch fat to ->s...
1570
  	setup(sb); /* flavour-specific stuff that needs options */
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
1571
1572
1573
1574
  	error = -EIO;
  	sb_min_blocksize(sb, 512);
  	bh = sb_bread(sb, 0);
  	if (bh == NULL) {
869f58c0c   Alexey Fisher   fat: Replace all ...
1575
  		fat_msg(sb, KERN_ERR, "unable to read boot sector");
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
1576
1577
  		goto out_fail;
  	}
190a8843d   Conrad Meyer   fs/fat/: add supp...
1578
1579
1580
1581
1582
1583
  	error = fat_read_bpb(sb, (struct fat_boot_sector *)bh->b_data, silent,
  		&bpb);
  	if (error == -EINVAL && sbi->options.dos1xfloppy)
  		error = fat_read_static_bpb(sb,
  			(struct fat_boot_sector *)bh->b_data, silent, &bpb);
  	brelse(bh);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
1584

190a8843d   Conrad Meyer   fs/fat/: add supp...
1585
  	if (error == -EINVAL)
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
1586
  		goto out_invalid;
190a8843d   Conrad Meyer   fs/fat/: add supp...
1587
1588
  	else if (error)
  		goto out_fail;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
1589

190a8843d   Conrad Meyer   fs/fat/: add supp...
1590
1591
1592
1593
  	logical_sector_size = bpb.fat_sector_size;
  	sbi->sec_per_clus = bpb.fat_sec_per_clus;
  
  	error = -EIO;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
1594
  	if (logical_sector_size < sb->s_blocksize) {
869f58c0c   Alexey Fisher   fat: Replace all ...
1595
1596
  		fat_msg(sb, KERN_ERR, "logical sector size too small for device"
  		       " (logical sector size = %u)", logical_sector_size);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
1597
1598
  		goto out_fail;
  	}
190a8843d   Conrad Meyer   fs/fat/: add supp...
1599

1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
1600
  	if (logical_sector_size > sb->s_blocksize) {
190a8843d   Conrad Meyer   fs/fat/: add supp...
1601
  		struct buffer_head *bh_resize;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
1602
1603
  
  		if (!sb_set_blocksize(sb, logical_sector_size)) {
869f58c0c   Alexey Fisher   fat: Replace all ...
1604
  			fat_msg(sb, KERN_ERR, "unable to set blocksize %u",
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
1605
1606
1607
  			       logical_sector_size);
  			goto out_fail;
  		}
190a8843d   Conrad Meyer   fs/fat/: add supp...
1608
1609
1610
1611
  
  		/* Verify that the larger boot sector is fully readable */
  		bh_resize = sb_bread(sb, 0);
  		if (bh_resize == NULL) {
869f58c0c   Alexey Fisher   fat: Replace all ...
1612
1613
  			fat_msg(sb, KERN_ERR, "unable to read boot sector"
  			       " (logical sector size = %lu)",
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
1614
1615
1616
  			       sb->s_blocksize);
  			goto out_fail;
  		}
190a8843d   Conrad Meyer   fs/fat/: add supp...
1617
  		brelse(bh_resize);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
1618
  	}
e40b34c79   Marco Stornelli   fat: drop lock/un...
1619
  	mutex_init(&sbi->s_lock);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
1620
1621
  	sbi->cluster_size = sb->s_blocksize * sbi->sec_per_clus;
  	sbi->cluster_bits = ffs(sbi->cluster_size) - 1;
190a8843d   Conrad Meyer   fs/fat/: add supp...
1622
  	sbi->fats = bpb.fat_fats;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
1623
  	sbi->fat_bits = 0;		/* Don't know yet */
190a8843d   Conrad Meyer   fs/fat/: add supp...
1624
1625
  	sbi->fat_start = bpb.fat_reserved;
  	sbi->fat_length = bpb.fat_fat_length;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
1626
1627
  	sbi->root_cluster = 0;
  	sbi->free_clusters = -1;	/* Don't know yet */
606e423e4   OGAWA Hirofumi   fat: Update free_...
1628
  	sbi->free_clus_valid = 0;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
1629
  	sbi->prev_free = FAT_START_ENT;
710d4403a   Namjae Jeon   fat: fat16 suppor...
1630
  	sb->s_maxbytes = 0xffffffff;
c0da64f6b   Deepa Dinamani   fs: fat: Initiali...
1631
1632
1633
1634
1635
1636
  	fat_time_fat2unix(sbi, &ts, 0, cpu_to_le16(FAT_DATE_MIN), 0);
  	sb->s_time_min = ts.tv_sec;
  
  	fat_time_fat2unix(sbi, &ts, cpu_to_le16(FAT_TIME_MAX),
  			  cpu_to_le16(FAT_DATE_MAX), 0);
  	sb->s_time_max = ts.tv_sec;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
1637

190a8843d   Conrad Meyer   fs/fat/: add supp...
1638
  	if (!sbi->fat_length && bpb.fat32_length) {
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
1639
1640
1641
1642
1643
  		struct fat_boot_fsinfo *fsinfo;
  		struct buffer_head *fsinfo_bh;
  
  		/* Must be FAT32 */
  		sbi->fat_bits = 32;
190a8843d   Conrad Meyer   fs/fat/: add supp...
1644
1645
  		sbi->fat_length = bpb.fat32_length;
  		sbi->root_cluster = bpb.fat32_root_cluster;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
1646

1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
1647
  		/* MC - if info_sector is 0, don't multiply by 0 */
190a8843d   Conrad Meyer   fs/fat/: add supp...
1648
  		sbi->fsinfo_sector = bpb.fat32_info_sector;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
1649
1650
1651
1652
1653
  		if (sbi->fsinfo_sector == 0)
  			sbi->fsinfo_sector = 1;
  
  		fsinfo_bh = sb_bread(sb, sbi->fsinfo_sector);
  		if (fsinfo_bh == NULL) {
869f58c0c   Alexey Fisher   fat: Replace all ...
1654
1655
  			fat_msg(sb, KERN_ERR, "bread failed, FSINFO block"
  			       " (sector = %lu)", sbi->fsinfo_sector);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
1656
1657
1658
1659
1660
  			goto out_fail;
  		}
  
  		fsinfo = (struct fat_boot_fsinfo *)fsinfo_bh->b_data;
  		if (!IS_FSINFO(fsinfo)) {
869f58c0c   Alexey Fisher   fat: Replace all ...
1661
1662
  			fat_msg(sb, KERN_WARNING, "Invalid FSINFO signature: "
  			       "0x%08x, 0x%08x (sector = %lu)",
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
1663
1664
1665
1666
  			       le32_to_cpu(fsinfo->signature1),
  			       le32_to_cpu(fsinfo->signature2),
  			       sbi->fsinfo_sector);
  		} else {
28ec039c2   OGAWA Hirofumi   fat: don't use fr...
1667
  			if (sbi->options.usefree)
606e423e4   OGAWA Hirofumi   fat: Update free_...
1668
1669
  				sbi->free_clus_valid = 1;
  			sbi->free_clusters = le32_to_cpu(fsinfo->free_clusters);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
1670
1671
1672
1673
1674
  			sbi->prev_free = le32_to_cpu(fsinfo->next_cluster);
  		}
  
  		brelse(fsinfo_bh);
  	}
6e5b93ee5   Mike Lockwood   fatfs: add FAT_IO...
1675
  	/* interpret volume ID as a little endian 32 bit integer */
306790f75   Carmeli Tamir   fat: new inline f...
1676
  	if (is_fat32(sbi))
190a8843d   Conrad Meyer   fs/fat/: add supp...
1677
  		sbi->vol_id = bpb.fat32_vol_id;
6e5b93ee5   Mike Lockwood   fatfs: add FAT_IO...
1678
  	else /* fat 16 or 12 */
190a8843d   Conrad Meyer   fs/fat/: add supp...
1679
  		sbi->vol_id = bpb.fat16_vol_id;
6e5b93ee5   Mike Lockwood   fatfs: add FAT_IO...
1680

1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
1681
1682
1683
1684
  	sbi->dir_per_block = sb->s_blocksize / sizeof(struct msdos_dir_entry);
  	sbi->dir_per_block_bits = ffs(sbi->dir_per_block) - 1;
  
  	sbi->dir_start = sbi->fat_start + sbi->fats * sbi->fat_length;
190a8843d   Conrad Meyer   fs/fat/: add supp...
1685
  	sbi->dir_entries = bpb.fat_dir_entries;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
1686
1687
  	if (sbi->dir_entries & (sbi->dir_per_block - 1)) {
  		if (!silent)
34df11741   Zheng Lv   fat: fix error me...
1688
  			fat_msg(sb, KERN_ERR, "bogus number of directory entries"
869f58c0c   Alexey Fisher   fat: Replace all ...
1689
  			       " (%u)", sbi->dir_entries);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
1690
1691
1692
1693
1694
1695
  		goto out_invalid;
  	}
  
  	rootdir_sectors = sbi->dir_entries
  		* sizeof(struct msdos_dir_entry) / sb->s_blocksize;
  	sbi->data_start = sbi->dir_start + rootdir_sectors;
190a8843d   Conrad Meyer   fs/fat/: add supp...
1696
  	total_sectors = bpb.fat_sectors;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
1697
  	if (total_sectors == 0)
190a8843d   Conrad Meyer   fs/fat/: add supp...
1698
  		total_sectors = bpb.fat_total_sect;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
1699
1700
  
  	total_clusters = (total_sectors - sbi->data_start) / sbi->sec_per_clus;
306790f75   Carmeli Tamir   fat: new inline f...
1701
  	if (!is_fat32(sbi))
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
1702
  		sbi->fat_bits = (total_clusters > MAX_FAT12) ? 16 : 12;
b88a10580   Oleksij Rempel   fat: mark fs as d...
1703
  	/* some OSes set FAT_STATE_DIRTY and clean it on unmount. */
306790f75   Carmeli Tamir   fat: new inline f...
1704
  	if (is_fat32(sbi))
190a8843d   Conrad Meyer   fs/fat/: add supp...
1705
  		sbi->dirty = bpb.fat32_state & FAT_STATE_DIRTY;
b88a10580   Oleksij Rempel   fat: mark fs as d...
1706
  	else /* fat 16 or 12 */
190a8843d   Conrad Meyer   fs/fat/: add supp...
1707
  		sbi->dirty = bpb.fat16_state & FAT_STATE_DIRTY;
b88a10580   Oleksij Rempel   fat: mark fs as d...
1708

1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
1709
  	/* check that FAT table does not overflow */
7b92d03c3   OGAWA Hirofumi   fat: fix possible...
1710
  	fat_clusters = calc_fat_clusters(sb);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
1711
  	total_clusters = min(total_clusters, fat_clusters - FAT_START_ENT);
d19dc0161   Carmeli Tamir   fat: move MAX_FAT...
1712
  	if (total_clusters > max_fat(sb)) {
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
1713
  		if (!silent)
869f58c0c   Alexey Fisher   fat: Replace all ...
1714
  			fat_msg(sb, KERN_ERR, "count of clusters too big (%u)",
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
1715
  			       total_clusters);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
1716
1717
1718
1719
1720
1721
1722
1723
1724
1725
1726
  		goto out_invalid;
  	}
  
  	sbi->max_cluster = total_clusters + FAT_START_ENT;
  	/* check the free_clusters, it's not necessarily correct */
  	if (sbi->free_clusters != -1 && sbi->free_clusters > total_clusters)
  		sbi->free_clusters = -1;
  	/* check the prev_free, it's not necessarily correct */
  	sbi->prev_free %= sbi->max_cluster;
  	if (sbi->prev_free < FAT_START_ENT)
  		sbi->prev_free = FAT_START_ENT;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
1727
1728
  	/* set up enough so that it can read an inode */
  	fat_hash_init(sb);
7669e8fb0   Steven J. Magnani   fat (exportfs): f...
1729
  	dir_hash_init(sb);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
1730
1731
1732
  	fat_ent_access_init(sb);
  
  	/*
b553337a5   Carmeli Tamir   fat: remove FAT_F...
1733
1734
1735
  	 * The low byte of the first FAT entry must have the same value as
  	 * the media field of the boot sector. But in real world, too many
  	 * devices are writing wrong values. So, removed that validity check.
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
1736
  	 *
b553337a5   Carmeli Tamir   fat: remove FAT_F...
1737
1738
1739
1740
1741
  	 * The removed check compared the first FAT entry to a value dependent
  	 * on the media field like this:
  	 * == (0x0F00 | media), for FAT12
  	 * == (0XFF00 | media), for FAT16
  	 * == (0x0FFFFF | media), for FAT32
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
1742
1743
1744
1745
1746
1747
  	 */
  
  	error = -EINVAL;
  	sprintf(buf, "cp%d", sbi->options.codepage);
  	sbi->nls_disk = load_nls(buf);
  	if (!sbi->nls_disk) {
869f58c0c   Alexey Fisher   fat: Replace all ...
1748
  		fat_msg(sb, KERN_ERR, "codepage %s not found", buf);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
1749
1750
1751
1752
1753
1754
1755
  		goto out_fail;
  	}
  
  	/* FIXME: utf8 is using iocharset for upper/lower conversion */
  	if (sbi->options.isvfat) {
  		sbi->nls_io = load_nls(sbi->options.iocharset);
  		if (!sbi->nls_io) {
869f58c0c   Alexey Fisher   fat: Replace all ...
1756
  			fat_msg(sb, KERN_ERR, "IO charset %s not found",
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
1757
1758
1759
1760
1761
1762
  			       sbi->options.iocharset);
  			goto out_fail;
  		}
  	}
  
  	error = -ENOMEM;
b522412ae   Al Viro   Sanitize ->fsync(...
1763
1764
1765
  	fat_inode = new_inode(sb);
  	if (!fat_inode)
  		goto out_fail;
b522412ae   Al Viro   Sanitize ->fsync(...
1766
  	sbi->fat_inode = fat_inode;
020ac5b6b   Artem Bityutskiy   fat: introduce sp...
1767
1768
1769
1770
1771
1772
1773
  
  	fsinfo_inode = new_inode(sb);
  	if (!fsinfo_inode)
  		goto out_fail;
  	fsinfo_inode->i_ino = MSDOS_FSINFO_INO;
  	sbi->fsinfo_inode = fsinfo_inode;
  	insert_inode_hash(fsinfo_inode);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
1774
1775
1776
1777
  	root_inode = new_inode(sb);
  	if (!root_inode)
  		goto out_fail;
  	root_inode->i_ino = MSDOS_ROOT_INO;
2489dbabe   Jeff Layton   fat: convert to n...
1778
  	inode_set_iversion(root_inode, 1);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
1779
  	error = fat_read_root(root_inode);
1688f8604   Al Viro   fat: switch to d_...
1780
1781
  	if (error < 0) {
  		iput(root_inode);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
1782
  		goto out_fail;
1688f8604   Al Viro   fat: switch to d_...
1783
  	}
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
1784
1785
  	error = -ENOMEM;
  	insert_inode_hash(root_inode);
7669e8fb0   Steven J. Magnani   fat (exportfs): f...
1786
  	fat_attach(root_inode, 0);
1688f8604   Al Viro   fat: switch to d_...
1787
  	sb->s_root = d_make_root(root_inode);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
1788
  	if (!sb->s_root) {
869f58c0c   Alexey Fisher   fat: Replace all ...
1789
  		fat_msg(sb, KERN_ERR, "get root inode failed");
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
1790
1791
  		goto out_fail;
  	}
f562146a3   Namjae Jeon   fat: notify when ...
1792
1793
1794
1795
1796
1797
1798
  	if (sbi->options.discard) {
  		struct request_queue *q = bdev_get_queue(sb->s_bdev);
  		if (!blk_queue_discard(q))
  			fat_msg(sb, KERN_WARNING,
  					"mounting with \"discard\" option, but "
  					"the device does not support discard");
  	}
b88a10580   Oleksij Rempel   fat: mark fs as d...
1799
  	fat_set_state(sb, 1, 0);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
1800
1801
1802
1803
1804
  	return 0;
  
  out_invalid:
  	error = -EINVAL;
  	if (!silent)
869f58c0c   Alexey Fisher   fat: Replace all ...
1805
  		fat_msg(sb, KERN_INFO, "Can't find a valid FAT filesystem");
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
1806
1807
  
  out_fail:
020ac5b6b   Artem Bityutskiy   fat: introduce sp...
1808
1809
  	if (fsinfo_inode)
  		iput(fsinfo_inode);
b522412ae   Al Viro   Sanitize ->fsync(...
1810
1811
  	if (fat_inode)
  		iput(fat_inode);
1bdb6f919   OGAWA Hirofumi   fat: Cleanup nls_...
1812
1813
  	unload_nls(sbi->nls_io);
  	unload_nls(sbi->nls_disk);
35033ab98   OGAWA Hirofumi   fat: fix memory a...
1814
  	fat_reset_iocharset(&sbi->options);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
1815
1816
1817
1818
  	sb->s_fs_info = NULL;
  	kfree(sbi);
  	return error;
  }
7c709d00d   OGAWA Hirofumi   [PATCH] fat: s/EX...
1819
  EXPORT_SYMBOL_GPL(fat_fill_super);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
1820

ae78bf9c4   Chris Mason   [PATCH] add -o fl...
1821
1822
1823
1824
1825
1826
1827
1828
1829
1830
  /*
   * helper function for fat_flush_inodes.  This writes both the inode
   * and the file data blocks, waiting for in flight data blocks before
   * the start of the call.  It does not wait for any io started
   * during the call
   */
  static int writeback_inode(struct inode *inode)
  {
  
  	int ret;
14864655c   Namjae Jeon   fat: simplify wri...
1831
1832
1833
  
  	/* if we used wait=1, sync_inode_metadata waits for the io for the
  	* inode to finish.  So wait=0 is sent down to sync_inode_metadata
ae78bf9c4   Chris Mason   [PATCH] add -o fl...
1834
1835
  	* and filemap_fdatawrite is used for the data blocks
  	*/
14864655c   Namjae Jeon   fat: simplify wri...
1836
  	ret = sync_inode_metadata(inode, 0);
ae78bf9c4   Chris Mason   [PATCH] add -o fl...
1837
  	if (!ret)
14864655c   Namjae Jeon   fat: simplify wri...
1838
  		ret = filemap_fdatawrite(inode->i_mapping);
ae78bf9c4   Chris Mason   [PATCH] add -o fl...
1839
1840
1841
1842
1843
1844
1845
1846
1847
1848
1849
1850
1851
1852
1853
1854
1855
1856
1857
1858
  	return ret;
  }
  
  /*
   * write data and metadata corresponding to i1 and i2.  The io is
   * started but we do not wait for any of it to finish.
   *
   * filemap_flush is used for the block device, so if there is a dirty
   * page for a block already in flight, we will not wait and start the
   * io over again
   */
  int fat_flush_inodes(struct super_block *sb, struct inode *i1, struct inode *i2)
  {
  	int ret = 0;
  	if (!MSDOS_SB(sb)->options.flush)
  		return 0;
  	if (i1)
  		ret = writeback_inode(i1);
  	if (!ret && i2)
  		ret = writeback_inode(i2);
97e860d36   Eric Sesterhenn   [PATCH] Remove un...
1859
  	if (!ret) {
ae78bf9c4   Chris Mason   [PATCH] add -o fl...
1860
1861
1862
1863
1864
1865
  		struct address_space *mapping = sb->s_bdev->bd_inode->i_mapping;
  		ret = filemap_flush(mapping);
  	}
  	return ret;
  }
  EXPORT_SYMBOL_GPL(fat_flush_inodes);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
1866
1867
  static int __init init_fat_fs(void)
  {
532a39a37   Pekka J Enberg   [PATCH] fat: fix ...
1868
  	int err;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
1869

532a39a37   Pekka J Enberg   [PATCH] fat: fix ...
1870
1871
1872
1873
1874
1875
1876
1877
1878
1879
1880
1881
1882
  	err = fat_cache_init();
  	if (err)
  		return err;
  
  	err = fat_init_inodecache();
  	if (err)
  		goto failed;
  
  	return 0;
  
  failed:
  	fat_cache_destroy();
  	return err;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
1883
1884
1885
1886
1887
1888
1889
1890
1891
1892
1893
1894
  }
  
  static void __exit exit_fat_fs(void)
  {
  	fat_cache_destroy();
  	fat_destroy_inodecache();
  }
  
  module_init(init_fat_fs)
  module_exit(exit_fat_fs)
  
  MODULE_LICENSE("GPL");