inode.c 50.5 KB
Newer Older
Linus Torvalds's avatar
Linus Torvalds committed
1
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>
#include <linux/pagemap.h>
15
#include <linux/mpage.h>
Linus Torvalds's avatar
Linus Torvalds committed
16
#include <linux/vfs.h>
17
#include <linux/seq_file.h>
Linus Torvalds's avatar
Linus Torvalds committed
18
#include <linux/parser.h>
19
#include <linux/uio.h>
20
#include <linux/blkdev.h>
21
#include <linux/backing-dev.h>
Linus Torvalds's avatar
Linus Torvalds committed
22
#include <asm/unaligned.h>
23
#include <linux/iversion.h>
OGAWA Hirofumi's avatar
OGAWA Hirofumi committed
24
#include "fat.h"
Linus Torvalds's avatar
Linus Torvalds committed
25
26
27
28
29
30

#ifndef CONFIG_FAT_DEFAULT_IOCHARSET
/* if user don't select VFAT, this is undefined. */
#define CONFIG_FAT_DEFAULT_IOCHARSET	""
#endif

31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
#define KB_IN_SECTORS 2

/*
 * 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;
};

Linus Torvalds's avatar
Linus Torvalds committed
57
58
59
static int fat_default_codepage = CONFIG_FAT_DEFAULT_CODEPAGE;
static char fat_default_iocharset[] = CONFIG_FAT_DEFAULT_IOCHARSET;

60
61
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
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,
},
};
Linus Torvalds's avatar
Linus Torvalds committed
96

Namjae Jeon's avatar
Namjae Jeon committed
97
int fat_add_cluster(struct inode *inode)
Linus Torvalds's avatar
Linus Torvalds committed
98
99
100
101
102
103
104
105
106
107
108
109
110
111
{
	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;
}

112
113
114
static inline int __fat_get_block(struct inode *inode, sector_t iblock,
				  unsigned long *max_blocks,
				  struct buffer_head *bh_result, int create)
Linus Torvalds's avatar
Linus Torvalds committed
115
116
{
	struct super_block *sb = inode->i_sb;
117
118
	struct msdos_sb_info *sbi = MSDOS_SB(sb);
	unsigned long mapped_blocks;
119
	sector_t phys, last_block;
120
	int err, offset;
Linus Torvalds's avatar
Linus Torvalds committed
121

122
	err = fat_bmap(inode, iblock, &phys, &mapped_blocks, create, false);
Linus Torvalds's avatar
Linus Torvalds committed
123
124
125
126
	if (err)
		return err;
	if (phys) {
		map_bh(bh_result, sb, phys);
127
		*max_blocks = min(mapped_blocks, *max_blocks);
Linus Torvalds's avatar
Linus Torvalds committed
128
129
130
131
		return 0;
	}
	if (!create)
		return 0;
132

Linus Torvalds's avatar
Linus Torvalds committed
133
	if (iblock != MSDOS_I(inode)->mmu_private >> sb->s_blocksize_bits) {
Denis Karpov's avatar
Denis Karpov committed
134
		fat_fs_error(sb, "corrupted file size (i_pos %lld, %lld)",
135
			MSDOS_I(inode)->i_pos, MSDOS_I(inode)->mmu_private);
Linus Torvalds's avatar
Linus Torvalds committed
136
137
		return -EIO;
	}
138

139
	last_block = inode->i_blocks >> (sb->s_blocksize_bits - 9);
140
	offset = (unsigned long)iblock & (sbi->sec_per_clus - 1);
141
142
143
144
145
146
	/*
	 * allocate a cluster according to the following.
	 * 1) no more available blocks
	 * 2) not part of fallocate region
	 */
	if (!offset && !(iblock < last_block)) {
147
		/* TODO: multiple cluster allocation would be desirable. */
Linus Torvalds's avatar
Linus Torvalds committed
148
149
150
151
		err = fat_add_cluster(inode);
		if (err)
			return err;
	}
152
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;

158
	err = fat_bmap(inode, iblock, &phys, &mapped_blocks, create, false);
Linus Torvalds's avatar
Linus Torvalds committed
159
160
	if (err)
		return err;
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;
	}
168

169
	BUG_ON(*max_blocks != mapped_blocks);
Linus Torvalds's avatar
Linus Torvalds committed
170
171
	set_buffer_new(bh_result);
	map_bh(bh_result, sb, phys);
172

Linus Torvalds's avatar
Linus Torvalds committed
173
174
175
	return 0;
}

176
177
static int fat_get_block(struct inode *inode, sector_t iblock,
			 struct buffer_head *bh_result, int create)
178
179
{
	struct super_block *sb = inode->i_sb;
180
	unsigned long max_blocks = bh_result->b_size >> inode->i_blkbits;
181
	int err;
182

183
	err = __fat_get_block(inode, iblock, &max_blocks, bh_result, create);
184
185
186
187
188
189
	if (err)
		return err;
	bh_result->b_size = max_blocks << sb->s_blocksize_bits;
	return 0;
}

Linus Torvalds's avatar
Linus Torvalds committed
190
191
192
193
194
static int fat_writepage(struct page *page, struct writeback_control *wbc)
{
	return block_write_full_page(page, fat_get_block, wbc);
}

195
196
197
198
199
200
static int fat_writepages(struct address_space *mapping,
			  struct writeback_control *wbc)
{
	return mpage_writepages(mapping, wbc, fat_get_block);
}

Linus Torvalds's avatar
Linus Torvalds committed
201
202
static int fat_readpage(struct file *file, struct page *page)
{
203
204
205
206
207
208
209
	return mpage_readpage(page, fat_get_block);
}

static int fat_readpages(struct file *file, struct address_space *mapping,
			 struct list_head *pages, unsigned nr_pages)
{
	return mpage_readpages(mapping, pages, nr_pages, fat_get_block);
Linus Torvalds's avatar
Linus Torvalds committed
210
211
}

212
213
214
215
216
static void fat_write_failed(struct address_space *mapping, loff_t to)
{
	struct inode *inode = mapping->host;

	if (to > inode->i_size) {
217
		truncate_pagecache(inode, inode->i_size);
218
219
220
221
		fat_truncate_blocks(inode, inode->i_size);
	}
}

Nick Piggin's avatar
Nick Piggin committed
222
223
224
static int fat_write_begin(struct file *file, struct address_space *mapping,
			loff_t pos, unsigned len, unsigned flags,
			struct page **pagep, void **fsdata)
Linus Torvalds's avatar
Linus Torvalds committed
225
{
226
227
	int err;

Nick Piggin's avatar
Nick Piggin committed
228
	*pagep = NULL;
229
	err = cont_write_begin(file, mapping, pos, len, flags,
230
				pagep, fsdata, fat_get_block,
Nick Piggin's avatar
Nick Piggin committed
231
				&MSDOS_I(mapping->host)->mmu_private);
232
233
234
	if (err < 0)
		fat_write_failed(mapping, pos + len);
	return err;
Linus Torvalds's avatar
Linus Torvalds committed
235
236
}

Nick Piggin's avatar
Nick Piggin committed
237
238
239
static int fat_write_end(struct file *file, struct address_space *mapping,
			loff_t pos, unsigned len, unsigned copied,
			struct page *pagep, void *fsdata)
240
{
Nick Piggin's avatar
Nick Piggin committed
241
242
243
	struct inode *inode = mapping->host;
	int err;
	err = generic_write_end(file, mapping, pos, len, copied, pagep, fsdata);
244
245
	if (err < len)
		fat_write_failed(mapping, pos + len);
Nick Piggin's avatar
Nick Piggin committed
246
	if (!(err < 0) && !(MSDOS_I(inode)->i_attrs & ATTR_ARCH)) {
247
		inode->i_mtime = inode->i_ctime = current_time(inode);
248
249
250
251
252
253
		MSDOS_I(inode)->i_attrs |= ATTR_ARCH;
		mark_inode_dirty(inode);
	}
	return err;
}

254
static ssize_t fat_direct_IO(struct kiocb *iocb, struct iov_iter *iter)
255
256
{
	struct file *file = iocb->ki_filp;
257
258
	struct address_space *mapping = file->f_mapping;
	struct inode *inode = mapping->host;
259
	size_t count = iov_iter_count(iter);
260
	loff_t offset = iocb->ki_pos;
261
	ssize_t ret;
262

263
	if (iov_iter_rw(iter) == WRITE) {
264
		/*
265
		 * FIXME: blockdev_direct_IO() doesn't use ->write_begin(),
266
267
268
269
		 * 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.
270
271
		 *
		 * Return 0, and fallback to normal buffered write.
272
		 */
273
		loff_t size = offset + count;
274
		if (MSDOS_I(inode)->mmu_private < size)
275
			return 0;
276
277
278
279
280
281
	}

	/*
	 * FAT need to use the DIO_LOCKING for avoiding the race
	 * condition of fat_get_block() and ->truncate().
	 */
282
	ret = blockdev_direct_IO(iocb, inode, iter, fat_get_block);
283
	if (ret < 0 && iov_iter_rw(iter) == WRITE)
284
		fat_write_failed(mapping, offset + count);
285
286

	return ret;
287
288
}

289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
307
308
309
310
311
312
313
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;
}

Linus Torvalds's avatar
Linus Torvalds committed
314
315
static sector_t _fat_bmap(struct address_space *mapping, sector_t block)
{
OGAWA Hirofumi's avatar
OGAWA Hirofumi committed
316
317
318
	sector_t blocknr;

	/* fat_get_cluster() assumes the requested blocknr isn't truncated. */
319
	down_read(&MSDOS_I(mapping->host)->truncate_lock);
320
	blocknr = generic_block_bmap(mapping, block, fat_get_block_bmap);
321
	up_read(&MSDOS_I(mapping->host)->truncate_lock);
OGAWA Hirofumi's avatar
OGAWA Hirofumi committed
322
323

	return blocknr;
Linus Torvalds's avatar
Linus Torvalds committed
324
325
}

326
327
328
329
330
331
332
333
334
335
336
337
/*
 * 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);
}

338
static const struct address_space_operations fat_aops = {
Linus Torvalds's avatar
Linus Torvalds committed
339
	.readpage	= fat_readpage,
340
	.readpages	= fat_readpages,
Linus Torvalds's avatar
Linus Torvalds committed
341
	.writepage	= fat_writepage,
342
	.writepages	= fat_writepages,
Nick Piggin's avatar
Nick Piggin committed
343
344
	.write_begin	= fat_write_begin,
	.write_end	= fat_write_end,
345
	.direct_IO	= fat_direct_IO,
Linus Torvalds's avatar
Linus Torvalds committed
346
347
348
349
350
351
352
353
354
355
356
357
358
359
360
361
362
363
364
365
366
367
	.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
Al Viro's avatar
Al Viro committed
368
 *		6. fat_evict_inode() unhashes the F-d-c entry.
Linus Torvalds's avatar
Linus Torvalds committed
369
370
371
372
373
374
375
376
377
378
379
380
381
382
 *		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]);
}

OGAWA Hirofumi's avatar
OGAWA Hirofumi committed
383
static inline unsigned long fat_hash(loff_t i_pos)
Linus Torvalds's avatar
Linus Torvalds committed
384
{
OGAWA Hirofumi's avatar
OGAWA Hirofumi committed
385
	return hash_32(i_pos, FAT_HASH_BITS);
Linus Torvalds's avatar
Linus Torvalds committed
386
387
}

388
389
390
391
392
393
394
395
396
397
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]);
}

Linus Torvalds's avatar
Linus Torvalds committed
398
399
void fat_attach(struct inode *inode, loff_t i_pos)
{
OGAWA Hirofumi's avatar
OGAWA Hirofumi committed
400
	struct msdos_sb_info *sbi = MSDOS_SB(inode->i_sb);
Linus Torvalds's avatar
Linus Torvalds committed
401

402
403
404
405
406
407
408
409
410
411
412
413
414
415
416
417
418
419
420
421
422
423
	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);
	}
Linus Torvalds's avatar
Linus Torvalds committed
424
}
425
EXPORT_SYMBOL_GPL(fat_attach);
Linus Torvalds's avatar
Linus Torvalds committed
426
427
428
429
430
431
432
433

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);
434
435
436
437
438
439

	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);
	}
Linus Torvalds's avatar
Linus Torvalds committed
440
}
441
EXPORT_SYMBOL_GPL(fat_detach);
Linus Torvalds's avatar
Linus Torvalds committed
442
443
444
445

struct inode *fat_iget(struct super_block *sb, loff_t i_pos)
{
	struct msdos_sb_info *sbi = MSDOS_SB(sb);
OGAWA Hirofumi's avatar
OGAWA Hirofumi committed
446
	struct hlist_head *head = sbi->inode_hashtable + fat_hash(i_pos);
Linus Torvalds's avatar
Linus Torvalds committed
447
448
449
450
	struct msdos_inode_info *i;
	struct inode *inode = NULL;

	spin_lock(&sbi->inode_hash_lock);
451
	hlist_for_each_entry(i, head, i_fat_hash) {
Linus Torvalds's avatar
Linus Torvalds committed
452
453
454
455
456
457
458
459
460
461
462
463
464
		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)
{
465
	unsigned char exe_extensions[] = "EXECOMBAT", *walk;
Linus Torvalds's avatar
Linus Torvalds committed
466
467
468
469
470
471
472
473
474
475
476
477
478
479
480
481
482
483
484
485
486
487
488
489

	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;
}

490
491
492
493
494
495
496
497
498
499
500
501
502
503
504
505
506
507
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;
}

Linus Torvalds's avatar
Linus Torvalds committed
508
/* doesn't deal with root inode */
509
int fat_fill_inode(struct inode *inode, struct msdos_dir_entry *de)
Linus Torvalds's avatar
Linus Torvalds committed
510
511
512
513
514
515
516
{
	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;
517
	inode_inc_iversion(inode);
Linus Torvalds's avatar
Linus Torvalds committed
518
519
520
521
	inode->i_generation = get_seconds();

	if ((de->attr & ATTR_DIR) && !IS_FREE(de->name)) {
		inode->i_generation &= ~1;
522
		inode->i_mode = fat_make_mode(sbi, de->attr, S_IRWXUGO);
Linus Torvalds's avatar
Linus Torvalds committed
523
524
525
		inode->i_op = sbi->dir_ops;
		inode->i_fop = &fat_dir_operations;

526
		MSDOS_I(inode)->i_start = fat_get_start(sbi, de);
Linus Torvalds's avatar
Linus Torvalds committed
527
528
529
530
531
532
		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;

Miklos Szeredi's avatar
Miklos Szeredi committed
533
		set_nlink(inode, fat_subdirs(inode));
534
535
536
537

		error = fat_validate_dir(inode);
		if (error < 0)
			return error;
Linus Torvalds's avatar
Linus Torvalds committed
538
539
	} else { /* not a directory */
		inode->i_generation |= 1;
540
541
542
		inode->i_mode = fat_make_mode(sbi, de->attr,
			((sbi->options.showexec && !is_exec(de->name + 8))
			 ? S_IRUGO|S_IWUGO : S_IRWXUGO));
543
		MSDOS_I(inode)->i_start = fat_get_start(sbi, de);
Linus Torvalds's avatar
Linus Torvalds committed
544
545
546
547
548
549
550
551
552
553
554
555

		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;
	}
556
557
	fat_save_attrs(inode, de->attr);

Linus Torvalds's avatar
Linus Torvalds committed
558
559
	inode->i_blocks = ((inode->i_size + (sbi->cluster_size - 1))
			   & ~((loff_t)sbi->cluster_size - 1)) >> 9;
560
561

	fat_time_fat2unix(sbi, &inode->i_mtime, de->time, de->date, 0);
Linus Torvalds's avatar
Linus Torvalds committed
562
	if (sbi->options.isvfat) {
563
564
565
		fat_time_fat2unix(sbi, &inode->i_ctime, de->ctime,
				  de->cdate, de->ctime_cs);
		fat_time_fat2unix(sbi, &inode->i_atime, 0, de->adate, 0);
Linus Torvalds's avatar
Linus Torvalds committed
566
	} else
Stephane Kardas's avatar
Stephane Kardas committed
567
		inode->i_ctime = inode->i_atime = inode->i_mtime;
Linus Torvalds's avatar
Linus Torvalds committed
568
569
570
571

	return 0;
}

572
573
574
575
576
577
578
579
580
581
582
583
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);
}

Linus Torvalds's avatar
Linus Torvalds committed
584
585
586
587
588
589
struct inode *fat_build_inode(struct super_block *sb,
			struct msdos_dir_entry *de, loff_t i_pos)
{
	struct inode *inode;
	int err;

590
	fat_lock_build_inode(MSDOS_SB(sb));
Linus Torvalds's avatar
Linus Torvalds committed
591
592
593
594
595
596
597
598
599
	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);
600
	inode_set_iversion(inode, 1);
Linus Torvalds's avatar
Linus Torvalds committed
601
602
603
604
605
606
607
608
609
	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:
610
	fat_unlock_build_inode(MSDOS_SB(sb));
Linus Torvalds's avatar
Linus Torvalds committed
611
612
613
	return inode;
}

614
EXPORT_SYMBOL_GPL(fat_build_inode);
Linus Torvalds's avatar
Linus Torvalds committed
615

Namjae Jeon's avatar
Namjae Jeon committed
616
617
618
619
620
621
622
623
624
625
626
627
628
629
630
631
632
633
634
635
636
637
638
639
640
641
642
643
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");
		}

	}
}

Al Viro's avatar
Al Viro committed
644
static void fat_evict_inode(struct inode *inode)
Linus Torvalds's avatar
Linus Torvalds committed
645
{
646
	truncate_inode_pages_final(&inode->i_data);
Al Viro's avatar
Al Viro committed
647
648
649
	if (!inode->i_nlink) {
		inode->i_size = 0;
		fat_truncate_blocks(inode, 0);
Namjae Jeon's avatar
Namjae Jeon committed
650
651
652
	} else
		fat_free_eofblocks(inode);

Al Viro's avatar
Al Viro committed
653
	invalidate_inode_buffers(inode);
654
	clear_inode(inode);
Linus Torvalds's avatar
Linus Torvalds committed
655
	fat_cache_inval_inode(inode);
656
	fat_detach(inode);
Linus Torvalds's avatar
Linus Torvalds committed
657
658
}

659
660
661
662
663
static void fat_set_state(struct super_block *sb,
			unsigned int set, unsigned int force)
{
	struct buffer_head *bh;
	struct fat_boot_sector *b;
664
	struct msdos_sb_info *sbi = MSDOS_SB(sb);
665
666

	/* do not change any thing if mounted read only */
667
	if (sb_rdonly(sb) && !force)
668
669
670
671
672
673
674
675
676
677
678
679
680
681
682
683
684
685
686
687
688
689
690
691
692
693
694
695
696
697
698
699
700
701
702
703
704
705
		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;

	if (sbi->fat_bits == 32) {
		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);
}

706
707
708
709
710
711
712
713
714
715
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);
	if (sbi->options.iocharset != fat_default_iocharset)
		kfree(sbi->options.iocharset);
	kfree(sbi);
}

716
717
718
static void fat_put_super(struct super_block *sb)
{
	struct msdos_sb_info *sbi = MSDOS_SB(sb);
Linus Torvalds's avatar
Linus Torvalds committed
719

720
721
	fat_set_state(sb, 0, 0);

722
	iput(sbi->fsinfo_inode);
Al Viro's avatar
Al Viro committed
723
724
	iput(sbi->fat_inode);

725
	call_rcu(&sbi->rcu, delayed_free);
Linus Torvalds's avatar
Linus Torvalds committed
726
727
}

728
static struct kmem_cache *fat_inode_cachep;
Linus Torvalds's avatar
Linus Torvalds committed
729
730
731
732

static struct inode *fat_alloc_inode(struct super_block *sb)
{
	struct msdos_inode_info *ei;
733
	ei = kmem_cache_alloc(fat_inode_cachep, GFP_NOFS);
Linus Torvalds's avatar
Linus Torvalds committed
734
735
	if (!ei)
		return NULL;
736
737

	init_rwsem(&ei->truncate_lock);
Linus Torvalds's avatar
Linus Torvalds committed
738
739
740
	return &ei->vfs_inode;
}

Nick Piggin's avatar
Nick Piggin committed
741
static void fat_i_callback(struct rcu_head *head)
Linus Torvalds's avatar
Linus Torvalds committed
742
{
Nick Piggin's avatar
Nick Piggin committed
743
	struct inode *inode = container_of(head, struct inode, i_rcu);
Linus Torvalds's avatar
Linus Torvalds committed
744
745
746
	kmem_cache_free(fat_inode_cachep, MSDOS_I(inode));
}

Nick Piggin's avatar
Nick Piggin committed
747
748
749
750
751
static void fat_destroy_inode(struct inode *inode)
{
	call_rcu(&inode->i_rcu, fat_i_callback);
}

752
static void init_once(void *foo)
Linus Torvalds's avatar
Linus Torvalds committed
753
754
755
{
	struct msdos_inode_info *ei = (struct msdos_inode_info *)foo;

756
757
758
759
760
	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);
761
	INIT_HLIST_NODE(&ei->i_dir_hash);
762
	inode_init_once(&ei->vfs_inode);
Linus Torvalds's avatar
Linus Torvalds committed
763
764
765
766
767
768
}

static int __init fat_init_inodecache(void)
{
	fat_inode_cachep = kmem_cache_create("fat_inode_cache",
					     sizeof(struct msdos_inode_info),
769
					     0, (SLAB_RECLAIM_ACCOUNT|
770
						SLAB_MEM_SPREAD|SLAB_ACCOUNT),
771
					     init_once);
Linus Torvalds's avatar
Linus Torvalds committed
772
773
774
775
776
777
778
	if (fat_inode_cachep == NULL)
		return -ENOMEM;
	return 0;
}

static void __exit fat_destroy_inodecache(void)
{
779
780
781
782
783
	/*
	 * Make sure all delayed rcu free inodes are flushed before we
	 * destroy cache.
	 */
	rcu_barrier();
784
	kmem_cache_destroy(fat_inode_cachep);
Linus Torvalds's avatar
Linus Torvalds committed
785
786
787
788
}

static int fat_remount(struct super_block *sb, int *flags, char *data)
{
789
	bool new_rdonly;
Linus Torvalds's avatar
Linus Torvalds committed
790
	struct msdos_sb_info *sbi = MSDOS_SB(sb);
791
	*flags |= SB_NODIRATIME | (sbi->options.isvfat ? 0 : SB_NOATIME);
792

793
794
	sync_filesystem(sb);

795
	/* make sure we update state on remount. */
796
	new_rdonly = *flags & SB_RDONLY;
797
	if (new_rdonly != sb_rdonly(sb)) {
798
799
800
801
802
		if (new_rdonly)
			fat_set_state(sb, 0, 0);
		else
			fat_set_state(sb, 1, 1);
	}
Linus Torvalds's avatar
Linus Torvalds committed
803
804
805
	return 0;
}

806
static int fat_statfs(struct dentry *dentry, struct kstatfs *buf)
Linus Torvalds's avatar
Linus Torvalds committed
807
{
Coly Li's avatar
Coly Li committed
808
809
810
	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);
Linus Torvalds's avatar
Linus Torvalds committed
811
812

	/* If the count of free cluster is still unknown, counts it here. */
813
	if (sbi->free_clusters == -1 || !sbi->free_clus_valid) {
814
		int err = fat_count_free_clusters(dentry->d_sb);
Linus Torvalds's avatar
Linus Torvalds committed
815
816
817
818
		if (err)
			return err;
	}

819
	buf->f_type = dentry->d_sb->s_magic;
Linus Torvalds's avatar
Linus Torvalds committed
820
821
822
823
	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;
Coly Li's avatar
Coly Li committed
824
825
	buf->f_fsid.val[0] = (u32)id;
	buf->f_fsid.val[1] = (u32)(id >> 32);
OGAWA Hirofumi's avatar
OGAWA Hirofumi committed
826
827
	buf->f_namelen =
		(sbi->options.isvfat ? FAT_LFN_LEN : 12) * NLS_MAX_CHARSET_SIZE;
Linus Torvalds's avatar
Linus Torvalds committed
828
829
830
831

	return 0;
}

832
static int __fat_write_inode(struct inode *inode, int wait)
Linus Torvalds's avatar
Linus Torvalds committed
833
834
835
836
837
838
{
	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;
839
840
	sector_t blocknr;
	int err, offset;
Linus Torvalds's avatar
Linus Torvalds committed
841

OGAWA Hirofumi's avatar
OGAWA Hirofumi committed
842
843
844
	if (inode->i_ino == MSDOS_ROOT_INO)
		return 0;

Linus Torvalds's avatar
Linus Torvalds committed
845
retry:
OGAWA Hirofumi's avatar
OGAWA Hirofumi committed
846
847
	i_pos = fat_i_pos_read(sbi, inode);
	if (!i_pos)
Linus Torvalds's avatar
Linus Torvalds committed
848
849
		return 0;

850
851
	fat_get_blknr_offset(sbi, i_pos, &blocknr, &offset);
	bh = sb_bread(sb, blocknr);
Linus Torvalds's avatar
Linus Torvalds committed
852
	if (!bh) {
853
854
		fat_msg(sb, KERN_ERR, "unable to read inode block "
		       "for updating (i_pos %lld)", i_pos);
855
		return -EIO;
Linus Torvalds's avatar
Linus Torvalds committed
856
857
858
859
860
861
862
863
	}
	spin_lock(&sbi->inode_hash_lock);
	if (i_pos != MSDOS_I(inode)->i_pos) {
		spin_unlock(&sbi->inode_hash_lock);
		brelse(bh);
		goto retry;
	}

864
	raw_entry = &((struct msdos_dir_entry *) (bh->b_data))[offset];
Linus Torvalds's avatar
Linus Torvalds committed
865
866
867
868
	if (S_ISDIR(inode->i_mode))
		raw_entry->size = 0;
	else
		raw_entry->size = cpu_to_le32(inode->i_size);
869
	raw_entry->attr = fat_make_attrs(inode);
870
	fat_set_start(raw_entry, MSDOS_I(inode)->i_logstart);
871
872
	fat_time_unix2fat(sbi, &inode->i_mtime, &raw_entry->time,
			  &raw_entry->date, NULL);
Linus Torvalds's avatar
Linus Torvalds committed
873
	if (sbi->options.isvfat) {
Stephane Kardas's avatar
Stephane Kardas committed
874
		__le16 atime;
875
876
877
878
		fat_time_unix2fat(sbi, &inode->i_ctime, &raw_entry->ctime,
				  &raw_entry->cdate, &raw_entry->ctime_cs);
		fat_time_unix2fat(sbi, &inode->i_atime, &atime,
				  &raw_entry->adate, NULL);
Linus Torvalds's avatar
Linus Torvalds committed
879
880
881
	}
	spin_unlock(&sbi->inode_hash_lock);
	mark_buffer_dirty(bh);
882
	err = 0;
Linus Torvalds's avatar
Linus Torvalds committed
883
884
885
886
887
888
	if (wait)
		err = sync_dirty_buffer(bh);
	brelse(bh);
	return err;
}

889
890
static int fat_write_inode(struct inode *inode, struct writeback_control *wbc)
{
Artem Bityutskiy's avatar
Artem Bityutskiy committed
891
892
893
894
895
	int err;

	if (inode->i_ino == MSDOS_FSINFO_INO) {
		struct super_block *sb = inode->i_sb;

Marco Stornelli's avatar
Marco Stornelli committed
896
		mutex_lock(&MSDOS_SB(sb)->s_lock);
Artem Bityutskiy's avatar
Artem Bityutskiy committed
897
		err = fat_clusters_flush(sb);
Marco Stornelli's avatar
Marco Stornelli committed
898
		mutex_unlock(&MSDOS_SB(sb)->s_lock);
Artem Bityutskiy's avatar
Artem Bityutskiy committed
899
900
901
902
	} else
		err = __fat_write_inode(inode, wbc->sync_mode == WB_SYNC_ALL);

	return err;
903
904
}

Linus Torvalds's avatar
Linus Torvalds committed
905
906
int fat_sync_inode(struct inode *inode)
{
907
	return __fat_write_inode(inode, 1);
Linus Torvalds's avatar
Linus Torvalds committed
908
909
}

910
EXPORT_SYMBOL_GPL(fat_sync_inode);
Linus Torvalds's avatar
Linus Torvalds committed
911

912
static int fat_show_options(struct seq_file *m, struct dentry *root);
913
static const struct super_operations fat_sops = {
Linus Torvalds's avatar
Linus Torvalds committed
914
915
916
	.alloc_inode	= fat_alloc_inode,
	.destroy_inode	= fat_destroy_inode,
	.write_inode	= fat_write_inode,
Al Viro's avatar
Al Viro committed
917
	.evict_inode	= fat_evict_inode,
Linus Torvalds's avatar
Linus Torvalds committed
918
919
920
921
922
923
924
	.put_super	= fat_put_super,
	.statfs		= fat_statfs,
	.remount_fs	= fat_remount,

	.show_options	= fat_show_options,
};

925
static int fat_show_options(struct seq_file *m, struct dentry *root)
Linus Torvalds's avatar
Linus Torvalds committed
926
{
927
	struct msdos_sb_info *sbi = MSDOS_SB(root->d_sb);
Linus Torvalds's avatar
Linus Torvalds committed
928
929
930
	struct fat_mount_options *opts = &sbi->options;
	int isvfat = opts->isvfat;

931
932
933
934
935
936
	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));
Linus Torvalds's avatar
Linus Torvalds committed
937
938
	seq_printf(m, ",fmask=%04o", opts->fs_fmask);
	seq_printf(m, ",dmask=%04o", opts->fs_dmask);
OGAWA Hirofumi's avatar
OGAWA Hirofumi committed
939
940
	if (opts->allow_utime)
		seq_printf(m, ",allow_utime=%04o", opts->allow_utime);
Linus Torvalds's avatar
Linus Torvalds committed
941
	if (sbi->nls_disk)
942
943
		/* strip "cp" prefix from displayed option */
		seq_printf(m, ",codepage=%s", &sbi->nls_disk->charset[2]);
Linus Torvalds's avatar
Linus Torvalds committed
944
945
946
947
948
949
950
951
952
953
954
955
956
957
958
	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:
959
			seq_puts(m, ",shortname=lower");
Linus Torvalds's avatar
Linus Torvalds committed
960
961
962
963
964
965
966
967
			break;
		default:
			seq_puts(m, ",shortname=unknown");
			break;
		}
	}
	if (opts->name_check != 'n')
		seq_printf(m, ",check=%c", opts->name_check);
968
969
	if (opts->usefree)
		seq_puts(m, ",usefree");
Linus Torvalds's avatar
Linus Torvalds committed
970
971
972
973
974
975
976
977
978
979
980
981
982
983
984
985
986
987
	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");
988
989
		if (opts->rodir)
			seq_puts(m, ",rodir");
Linus Torvalds's avatar
Linus Torvalds committed
990
	}
991
	if (opts->flush)
Miklos Szeredi's avatar
Miklos Szeredi committed
992
		seq_puts(m, ",flush");
993
994
995
996
997
998
	if (opts->tz_set) {
		if (opts->time_offset)
			seq_printf(m, ",time_offset=%d", opts->time_offset);
		else
			seq_puts(m, ",tz=UTC");
	}
Denis Karpov's avatar
Denis Karpov committed
999
1000
1001
1002
1003
1004
	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");
1005
1006
1007
1008
	if (opts->nfs == FAT_NFS_NOSTALE_RO)
		seq_puts(m, ",nfs=nostale_ro");
	else if (opts->nfs)
		seq_puts(m, ",nfs=stale_rw");
1009
1010
	if (opts->discard)
		seq_puts(m, ",discard");
1011
1012
	if (opts->dos1xfloppy)
		seq_puts(m, ",dos1xfloppy");
Linus Torvalds's avatar
Linus Torvalds committed
1013
1014
1015
1016
1017
1018

	return 0;
}

enum {
	Opt_check_n, Opt_check_r, Opt_check_s, Opt_uid, Opt_gid,
OGAWA Hirofumi's avatar
OGAWA Hirofumi committed
1019
1020
1021
	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,
Linus Torvalds's avatar
Linus Torvalds committed
1022
1023
1024
	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,
1025
	Opt_obsolete, Opt_flush, Opt_tz_utc, Opt_rodir, Opt_err_cont,
1026
	Opt_err_panic, Opt_err_ro, Opt_discard, Opt_nfs, Opt_time_offset,
1027
	Opt_nfs_stale_rw, Opt_nfs_nostale_ro, Opt_err, Opt_dos1xfloppy,
Linus Torvalds's avatar
Linus Torvalds committed
1028
1029
};

1030
static const match_table_t fat_tokens = {
Linus Torvalds's avatar
Linus Torvalds committed
1031
1032
1033
1034
1035
1036
1037
1038
1039
1040
1041
	{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"},
OGAWA Hirofumi's avatar
OGAWA Hirofumi committed
1042
	{Opt_allow_utime, "allow_utime=%o"},
Linus Torvalds's avatar
Linus Torvalds committed
1043
	{Opt_codepage, "codepage=%u"},
1044
	{Opt_usefree, "usefree"},
Linus Torvalds's avatar
Linus Torvalds committed
1045
1046
1047
1048
1049
	{Opt_nocase, "nocase"},
	{Opt_quiet, "quiet"},
	{Opt_showexec, "showexec"},
	{Opt_debug, "debug"},
	{Opt_immutable, "sys_immutable"},
Denis Karpov's avatar
Denis Karpov committed
1050
1051
	{Opt_flush, "flush"},
	{Opt_tz_utc, "tz=UTC"},
1052
	{Opt_time_offset, "time_offset=%d"},
Denis Karpov's avatar
Denis Karpov committed
1053
1054
1055
	{Opt_err_cont, "errors=continue"},
	{Opt_err_panic, "errors=panic"},
	{Opt_err_ro, "errors=remount-ro"},
1056
	{Opt_discard, "discard"},
1057
1058
1059
	{Opt_nfs_stale_rw, "nfs"},
	{Opt_nfs_stale_rw, "nfs=stale_rw"},
	{Opt_nfs_nostale_ro, "nfs=nostale_ro"},
1060
	{Opt_dos1xfloppy, "dos1xfloppy"},
1061
1062
1063
1064
1065
1066
1067
1068
1069
1070
1071
	{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"},
Chris Mason's avatar
Chris Mason committed
1072
	{Opt_err, NULL},
Linus Torvalds's avatar
Linus Torvalds committed
1073
};
1074
static const match_table_t msdos_tokens = {
Linus Torvalds's avatar
Linus Torvalds committed
1075
1076
1077
1078
1079
1080
	{Opt_nodots, "nodots"},
	{Opt_nodots, "dotsOK=no"},
	{Opt_dots, "dots"},
	{Opt_dots, "dotsOK=yes"},
	{Opt_err, NULL}
};
1081
static const match_table_t vfat_tokens = {
Linus Torvalds's avatar
Linus Torvalds committed
1082
1083
1084
1085
1086
1087
1088
1089
1090
1091
1092
1093
1094
1095
1096
1097
1098
1099
1100
1101
1102
1103
1104
1105
1106
1107
	{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"},
1108
	{Opt_rodir, "rodir"},
Linus Torvalds's avatar
Linus Torvalds committed
1109
1110
1111
	{Opt_err, NULL}
};

1112
1113
static int parse_options(struct super_block *sb, char *options, int is_vfat,
			 int silent, int *debug, struct fat_mount_options *opts)
Linus Torvalds's avatar
Linus Torvalds committed
1114
1115
1116
1117
1118
1119
1120
1121
{
	char *p;
	substring_t args[MAX_OPT_ARGS];
	int option;
	char *iocharset;

	opts->isvfat = is_vfat;

1122
1123
	opts->fs_uid = current_uid();
	opts->fs_gid = current_gid();
1124
	opts->fs_fmask = opts->fs_dmask = current_umask();
OGAWA Hirofumi's avatar
OGAWA Hirofumi committed
1125
	opts->allow_utime = -1;
Linus Torvalds's avatar
Linus Torvalds committed
1126
1127
	opts->codepage = fat_default_codepage;
	opts->iocharset = fat_default_iocharset;
1128
	if (is_vfat) {
1129
		opts->shortname = VFAT_SFN_DISPLAY_WINNT|VFAT_SFN_CREATE_WIN95;
1130
1131
		opts->rodir = 0;
	} else {
Linus Torvalds's avatar
Linus Torvalds committed
1132
		opts->shortname = 0;
1133
1134
		opts->rodir = 1;
	}
Linus Torvalds's avatar
Linus Torvalds committed
1135
1136
	opts->name_check = 'n';
	opts->quiet = opts->showexec = opts->sys_immutable = opts->dotsOK =  0;
1137
	opts->unicode_xlate = 0;
Linus Torvalds's avatar
Linus Torvalds committed
1138
	opts->numtail = 1;
1139
	opts->usefree = opts->nocase = 0;
1140
	opts->tz_set = 0;
1141
	opts->nfs = 0;
Denis Karpov's avatar
Denis Karpov committed
1142
	opts->errors = FAT_ERRORS_RO;
Linus Torvalds's avatar
Linus Torvalds committed
1143
1144
	*debug = 0;

1145
1146
	opts->utf8 = IS_ENABLED(CONFIG_FAT_DEFAULT_UTF8) && is_vfat;

Linus Torvalds's avatar
Linus Torvalds committed
1147
	if (!options)
OGAWA Hirofumi's avatar
OGAWA Hirofumi committed
1148
		goto out;
Linus Torvalds's avatar
Linus Torvalds committed
1149
1150
1151
1152
1153
1154
1155
1156
1157
1158
1159
1160
1161
1162
1163
1164
1165
1166
1167
1168
1169
1170
1171

	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;
1172
1173
1174
		case Opt_usefree:
			opts->usefree = 1;
			break;
Linus Torvalds's avatar
Linus Torvalds committed
1175
1176
1177
1178
1179
1180
1181
1182
1183
1184
1185
1186
1187
1188
1189
1190
1191
1192
1193
1194
1195
1196
1197
		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))
Jan Kara's avatar
Jan Kara committed
1198
				return -EINVAL;
1199
1200
			opts->fs_uid = make_kuid(current_user_ns(), option);
			if (!uid_valid(opts->fs_uid))
Jan Kara's avatar
Jan Kara committed
1201
				return -EINVAL;
Linus Torvalds's avatar
Linus Torvalds committed
1202
1203
1204
			break;
		case Opt_gid:
			if (match_int(&args[0], &option))
Jan Kara's avatar
Jan Kara committed
1205
				return -EINVAL;
1206
1207
			opts->fs_gid = make_kgid(current_user_ns(), option);
			if (!gid_valid(opts->fs_gid))
Jan Kara's avatar
Jan Kara committed
1208
				return -EINVAL;
Linus Torvalds's avatar
Linus Torvalds committed
1209
1210
1211
			break;
		case Opt_umask:
			if (match_octal(&args[0], &option))
Jan Kara's avatar
Jan Kara committed
1212
				return -EINVAL;
Linus Torvalds's avatar
Linus Torvalds committed
1213
1214
1215
1216
			opts->fs_fmask = opts->fs_dmask = option;
			break;
		case Opt_dmask:
			if (match_octal(&args[0], &option))
Jan Kara's avatar
Jan Kara committed
1217
				return -EINVAL;
Linus Torvalds's avatar
Linus Torvalds committed
1218
1219
1220
1221
			opts->fs_dmask = option;
			break;
		case Opt_fmask:
			if (match_octal(&args[0], &option))
Jan Kara's avatar
Jan Kara committed
1222
				return -EINVAL;
Linus Torvalds's avatar
Linus Torvalds committed
1223
1224
			opts->fs_fmask = option;
			break;
OGAWA Hirofumi's avatar
OGAWA Hirofumi committed
1225
1226
		case Opt_allow_utime:
			if (match_octal(&args[0], &option))
Jan Kara's avatar
Jan Kara committed
1227
				return -EINVAL;
OGAWA Hirofumi's avatar
OGAWA Hirofumi committed
1228
1229
			opts->allow_utime = option & (S_IWGRP | S_IWOTH);
			break;
Linus Torvalds's avatar
Linus Torvalds committed
1230
1231
		case Opt_codepage:
			if (match_int(&args[0], &option))
Jan Kara's avatar
Jan Kara committed
1232
				return -EINVAL;
Linus Torvalds's avatar
Linus Torvalds committed
1233
1234
			opts->codepage = option;
			break;
Chris Mason's avatar
Chris Mason committed
1235
1236
1237
		case Opt_flush:
			opts->flush = 1;
			break;
1238
1239
		case Opt_time_offset:
			if (match_int(&args[0], &option))
Jan Kara's avatar
Jan Kara committed
1240
				return -EINVAL;