Blame view

mm/shmem.c 63.8 KB
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
1
2
3
4
5
6
7
8
  /*
   * Resizable virtual memory filesystem for Linux.
   *
   * Copyright (C) 2000 Linus Torvalds.
   *		 2000 Transmeta Corp.
   *		 2000-2001 Christoph Rohland
   *		 2000-2001 SAP AG
   *		 2002 Red Hat Inc.
6922c0c7a   Hugh Dickins   tmpfs: convert sh...
9
10
   * Copyright (C) 2002-2011 Hugh Dickins.
   * Copyright (C) 2011 Google Inc.
0edd73b33   Hugh Dickins   [PATCH] shmem: re...
11
   * Copyright (C) 2002-2005 VERITAS Software Corporation.
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
12
13
14
15
16
17
   * Copyright (C) 2004 Andi Kleen, SuSE Labs
   *
   * Extended attribute support for tmpfs:
   * Copyright (c) 2004, Luke Kenneth Casson Leighton <lkcl@lkcl.net>
   * Copyright (c) 2004 Red Hat, Inc., James Morris <jmorris@redhat.com>
   *
853ac43ab   Matt Mackall   shmem: unify regu...
18
19
20
   * tiny-shmem:
   * Copyright (c) 2004, 2008 Matt Mackall <mpm@selenic.com>
   *
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
21
22
   * This file is released under the GPL.
   */
853ac43ab   Matt Mackall   shmem: unify regu...
23
24
25
26
  #include <linux/fs.h>
  #include <linux/init.h>
  #include <linux/vfs.h>
  #include <linux/mount.h>
caefba174   Hugh Dickins   shmem: respect MA...
27
  #include <linux/pagemap.h>
853ac43ab   Matt Mackall   shmem: unify regu...
28
29
  #include <linux/file.h>
  #include <linux/mm.h>
b95f1b31b   Paul Gortmaker   mm: Map most file...
30
  #include <linux/export.h>
853ac43ab   Matt Mackall   shmem: unify regu...
31
32
33
34
35
  #include <linux/swap.h>
  
  static struct vfsmount *shm_mnt;
  
  #ifdef CONFIG_SHMEM
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
36
37
38
39
40
  /*
   * This virtual memory filesystem is heavily based on the ramfs. It
   * extends ramfs by the ability to use swap and honor resource limits
   * which makes it a completely usable filesystem.
   */
39f0247d3   Andreas Gruenbacher   [PATCH] Access Co...
41
  #include <linux/xattr.h>
a56942551   Christoph Hellwig   knfsd: exportfs: ...
42
  #include <linux/exportfs.h>
1c7c474c3   Christoph Hellwig   make generic_acl ...
43
  #include <linux/posix_acl.h>
39f0247d3   Andreas Gruenbacher   [PATCH] Access Co...
44
  #include <linux/generic_acl.h>
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
45
  #include <linux/mman.h>
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
46
47
48
49
  #include <linux/string.h>
  #include <linux/slab.h>
  #include <linux/backing-dev.h>
  #include <linux/shmem_fs.h>
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
50
  #include <linux/writeback.h>
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
51
  #include <linux/blkdev.h>
bda97eab0   Hugh Dickins   tmpfs: copy trunc...
52
  #include <linux/pagevec.h>
41ffe5d5c   Hugh Dickins   tmpfs: miscellane...
53
  #include <linux/percpu_counter.h>
708e3508c   Hugh Dickins   tmpfs: clone shme...
54
  #include <linux/splice.h>
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
55
56
57
58
  #include <linux/security.h>
  #include <linux/swapops.h>
  #include <linux/mempolicy.h>
  #include <linux/namei.h>
b00dc3ad7   Hugh Dickins   [PATCH] tmpfs: fi...
59
  #include <linux/ctype.h>
304dbdb7a   Lee Schermerhorn   [PATCH] add migra...
60
  #include <linux/migrate.h>
c1f60a5a4   Christoph Lameter   [PATCH] reduce MA...
61
  #include <linux/highmem.h>
680d794ba   akpm@linux-foundation.org   mount options: fi...
62
  #include <linux/seq_file.h>
925629278   Mimi Zohar   integrity: specia...
63
  #include <linux/magic.h>
304dbdb7a   Lee Schermerhorn   [PATCH] add migra...
64

1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
65
  #include <asm/uaccess.h>
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
66
  #include <asm/pgtable.h>
caefba174   Hugh Dickins   shmem: respect MA...
67
  #define BLOCKS_PER_PAGE  (PAGE_CACHE_SIZE/512)
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
68
  #define VM_ACCT(size)    (PAGE_CACHE_ALIGN(size) >> PAGE_SHIFT)
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
69
70
  /* Pretend that each entry is of this size in directory's i_size */
  #define BOGO_DIRENT_SIZE 20
69f07ec93   Hugh Dickins   tmpfs: use kmemdu...
71
72
  /* Symlink up to this size is kmalloc'ed instead of using a swappable page */
  #define SHORT_SYMLINK_LEN 128
b09e0fa4b   Eric Paris   tmpfs: implement ...
73
74
75
76
77
78
  struct shmem_xattr {
  	struct list_head list;	/* anchored by shmem_inode_info->xattr_list */
  	char *name;		/* xattr name */
  	size_t size;
  	char value[0];
  };
285b2c4fd   Hugh Dickins   tmpfs: demolish o...
79
  /* Flag allocation requirements to shmem_getpage */
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
80
  enum sgp_type {
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
81
82
  	SGP_READ,	/* don't exceed i_size, don't allocate page */
  	SGP_CACHE,	/* don't exceed i_size, may allocate page */
a0ee5ec52   Hugh Dickins   tmpfs: allocate o...
83
  	SGP_DIRTY,	/* like SGP_CACHE, but set new page dirty */
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
84
85
  	SGP_WRITE,	/* may exceed i_size, may allocate page */
  };
b76db7354   Andrew Morton   mount-options-fix...
86
  #ifdef CONFIG_TMPFS
680d794ba   akpm@linux-foundation.org   mount options: fi...
87
88
89
90
91
92
93
94
95
  static unsigned long shmem_default_max_blocks(void)
  {
  	return totalram_pages / 2;
  }
  
  static unsigned long shmem_default_max_inodes(void)
  {
  	return min(totalram_pages - totalhigh_pages, totalram_pages / 2);
  }
b76db7354   Andrew Morton   mount-options-fix...
96
  #endif
680d794ba   akpm@linux-foundation.org   mount options: fi...
97

68da9f055   Hugh Dickins   tmpfs: pass gfp t...
98
99
100
101
102
103
104
105
106
  static int shmem_getpage_gfp(struct inode *inode, pgoff_t index,
  	struct page **pagep, enum sgp_type sgp, gfp_t gfp, int *fault_type);
  
  static inline int shmem_getpage(struct inode *inode, pgoff_t index,
  	struct page **pagep, enum sgp_type sgp, int *fault_type)
  {
  	return shmem_getpage_gfp(inode, index, pagep, sgp,
  			mapping_gfp_mask(inode->i_mapping), fault_type);
  }
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
107

1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
108
109
110
111
112
113
114
115
116
117
118
119
120
  static inline struct shmem_sb_info *SHMEM_SB(struct super_block *sb)
  {
  	return sb->s_fs_info;
  }
  
  /*
   * shmem_file_setup pre-accounts the whole fixed size of a VM object,
   * for shared memory and for shared anonymous (/dev/zero) mappings
   * (unless MAP_NORESERVE and sysctl_overcommit_memory <= 1),
   * consistent with the pre-accounting of private mappings ...
   */
  static inline int shmem_acct_size(unsigned long flags, loff_t size)
  {
0b0a0806b   Hugh Dickins   shmem: fix shared...
121
122
  	return (flags & VM_NORESERVE) ?
  		0 : security_vm_enough_memory_kern(VM_ACCT(size));
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
123
124
125
126
  }
  
  static inline void shmem_unacct_size(unsigned long flags, loff_t size)
  {
0b0a0806b   Hugh Dickins   shmem: fix shared...
127
  	if (!(flags & VM_NORESERVE))
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
128
129
130
131
132
133
134
135
136
137
138
  		vm_unacct_memory(VM_ACCT(size));
  }
  
  /*
   * ... whereas tmpfs objects are accounted incrementally as
   * pages are allocated, in order to allow huge sparse files.
   * shmem_getpage reports shmem_acct_block failure as -ENOSPC not -ENOMEM,
   * so that a failure on a sparse tmpfs mapping will give SIGBUS not OOM.
   */
  static inline int shmem_acct_block(unsigned long flags)
  {
0b0a0806b   Hugh Dickins   shmem: fix shared...
139
140
  	return (flags & VM_NORESERVE) ?
  		security_vm_enough_memory_kern(VM_ACCT(PAGE_CACHE_SIZE)) : 0;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
141
142
143
144
  }
  
  static inline void shmem_unacct_blocks(unsigned long flags, long pages)
  {
0b0a0806b   Hugh Dickins   shmem: fix shared...
145
  	if (flags & VM_NORESERVE)
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
146
147
  		vm_unacct_memory(pages * VM_ACCT(PAGE_CACHE_SIZE));
  }
759b9775c   Hugh Dickins   [PATCH] shmem and...
148
  static const struct super_operations shmem_ops;
f5e54d6e5   Christoph Hellwig   [PATCH] mark addr...
149
  static const struct address_space_operations shmem_aops;
15ad7cdcf   Helge Deller   [PATCH] struct se...
150
  static const struct file_operations shmem_file_operations;
92e1d5be9   Arjan van de Ven   [PATCH] mark stru...
151
152
153
  static const struct inode_operations shmem_inode_operations;
  static const struct inode_operations shmem_dir_inode_operations;
  static const struct inode_operations shmem_special_inode_operations;
f0f37e2f7   Alexey Dobriyan   const: mark struc...
154
  static const struct vm_operations_struct shmem_vm_ops;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
155

6c231b7ba   Ravikiran G Thirumalai   [PATCH] Additions...
156
  static struct backing_dev_info shmem_backing_dev_info  __read_mostly = {
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
157
  	.ra_pages	= 0,	/* No readahead */
4f98a2fee   Rik van Riel   vmscan: split LRU...
158
  	.capabilities	= BDI_CAP_NO_ACCT_AND_WRITEBACK | BDI_CAP_SWAP_BACKED,
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
159
160
161
  };
  
  static LIST_HEAD(shmem_swaplist);
cb5f7b9a4   Hugh Dickins   tmpfs: make shmem...
162
  static DEFINE_MUTEX(shmem_swaplist_mutex);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
163

5b04c6890   Pavel Emelyanov   shmem: factor out...
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
  static int shmem_reserve_inode(struct super_block *sb)
  {
  	struct shmem_sb_info *sbinfo = SHMEM_SB(sb);
  	if (sbinfo->max_inodes) {
  		spin_lock(&sbinfo->stat_lock);
  		if (!sbinfo->free_inodes) {
  			spin_unlock(&sbinfo->stat_lock);
  			return -ENOSPC;
  		}
  		sbinfo->free_inodes--;
  		spin_unlock(&sbinfo->stat_lock);
  	}
  	return 0;
  }
  
  static void shmem_free_inode(struct super_block *sb)
  {
  	struct shmem_sb_info *sbinfo = SHMEM_SB(sb);
  	if (sbinfo->max_inodes) {
  		spin_lock(&sbinfo->stat_lock);
  		sbinfo->free_inodes++;
  		spin_unlock(&sbinfo->stat_lock);
  	}
  }
467118102   Randy Dunlap   mm/shmem and tiny...
188
  /**
41ffe5d5c   Hugh Dickins   tmpfs: miscellane...
189
   * shmem_recalc_inode - recalculate the block usage of an inode
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
   * @inode: inode to recalc
   *
   * We have to calculate the free blocks since the mm can drop
   * undirtied hole pages behind our back.
   *
   * But normally   info->alloced == inode->i_mapping->nrpages + info->swapped
   * So mm freed is info->alloced - (inode->i_mapping->nrpages + info->swapped)
   *
   * It has to be called with the spinlock held.
   */
  static void shmem_recalc_inode(struct inode *inode)
  {
  	struct shmem_inode_info *info = SHMEM_I(inode);
  	long freed;
  
  	freed = info->alloced - info->swapped - inode->i_mapping->nrpages;
  	if (freed > 0) {
54af60421   Hugh Dickins   tmpfs: convert sh...
207
208
209
  		struct shmem_sb_info *sbinfo = SHMEM_SB(inode->i_sb);
  		if (sbinfo->max_blocks)
  			percpu_counter_add(&sbinfo->used_blocks, -freed);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
210
  		info->alloced -= freed;
54af60421   Hugh Dickins   tmpfs: convert sh...
211
  		inode->i_blocks -= freed * BLOCKS_PER_PAGE;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
212
  		shmem_unacct_blocks(info->flags, freed);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
213
214
  	}
  }
7a5d0fbb2   Hugh Dickins   tmpfs: convert sh...
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
  /*
   * Replace item expected in radix tree by a new item, while holding tree lock.
   */
  static int shmem_radix_tree_replace(struct address_space *mapping,
  			pgoff_t index, void *expected, void *replacement)
  {
  	void **pslot;
  	void *item = NULL;
  
  	VM_BUG_ON(!expected);
  	pslot = radix_tree_lookup_slot(&mapping->page_tree, index);
  	if (pslot)
  		item = radix_tree_deref_slot_protected(pslot,
  							&mapping->tree_lock);
  	if (item != expected)
  		return -ENOENT;
  	if (replacement)
  		radix_tree_replace_slot(pslot, replacement);
  	else
  		radix_tree_delete(&mapping->page_tree, index);
  	return 0;
  }
  
  /*
46f65ec15   Hugh Dickins   tmpfs: convert sh...
239
240
241
242
243
244
   * Like add_to_page_cache_locked, but error if expected item has gone.
   */
  static int shmem_add_to_page_cache(struct page *page,
  				   struct address_space *mapping,
  				   pgoff_t index, gfp_t gfp, void *expected)
  {
aa3b18955   Hugh Dickins   tmpfs: convert me...
245
  	int error = 0;
46f65ec15   Hugh Dickins   tmpfs: convert sh...
246
247
248
  
  	VM_BUG_ON(!PageLocked(page));
  	VM_BUG_ON(!PageSwapBacked(page));
46f65ec15   Hugh Dickins   tmpfs: convert sh...
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
  	if (!expected)
  		error = radix_tree_preload(gfp & GFP_RECLAIM_MASK);
  	if (!error) {
  		page_cache_get(page);
  		page->mapping = mapping;
  		page->index = index;
  
  		spin_lock_irq(&mapping->tree_lock);
  		if (!expected)
  			error = radix_tree_insert(&mapping->page_tree,
  							index, page);
  		else
  			error = shmem_radix_tree_replace(mapping, index,
  							expected, page);
  		if (!error) {
  			mapping->nrpages++;
  			__inc_zone_page_state(page, NR_FILE_PAGES);
  			__inc_zone_page_state(page, NR_SHMEM);
  			spin_unlock_irq(&mapping->tree_lock);
  		} else {
  			page->mapping = NULL;
  			spin_unlock_irq(&mapping->tree_lock);
  			page_cache_release(page);
  		}
  		if (!expected)
  			radix_tree_preload_end();
  	}
  	if (error)
  		mem_cgroup_uncharge_cache_page(page);
46f65ec15   Hugh Dickins   tmpfs: convert sh...
278
279
280
281
  	return error;
  }
  
  /*
6922c0c7a   Hugh Dickins   tmpfs: convert sh...
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
   * Like delete_from_page_cache, but substitutes swap for page.
   */
  static void shmem_delete_from_page_cache(struct page *page, void *radswap)
  {
  	struct address_space *mapping = page->mapping;
  	int error;
  
  	spin_lock_irq(&mapping->tree_lock);
  	error = shmem_radix_tree_replace(mapping, page->index, page, radswap);
  	page->mapping = NULL;
  	mapping->nrpages--;
  	__dec_zone_page_state(page, NR_FILE_PAGES);
  	__dec_zone_page_state(page, NR_SHMEM);
  	spin_unlock_irq(&mapping->tree_lock);
  	page_cache_release(page);
  	BUG_ON(error);
  }
  
  /*
7a5d0fbb2   Hugh Dickins   tmpfs: convert sh...
301
302
303
304
305
306
307
308
309
310
311
312
313
314
315
316
317
318
319
320
321
322
   * Like find_get_pages, but collecting swap entries as well as pages.
   */
  static unsigned shmem_find_get_pages_and_swap(struct address_space *mapping,
  					pgoff_t start, unsigned int nr_pages,
  					struct page **pages, pgoff_t *indices)
  {
  	unsigned int i;
  	unsigned int ret;
  	unsigned int nr_found;
  
  	rcu_read_lock();
  restart:
  	nr_found = radix_tree_gang_lookup_slot(&mapping->page_tree,
  				(void ***)pages, indices, start, nr_pages);
  	ret = 0;
  	for (i = 0; i < nr_found; i++) {
  		struct page *page;
  repeat:
  		page = radix_tree_deref_slot((void **)pages[i]);
  		if (unlikely(!page))
  			continue;
  		if (radix_tree_exception(page)) {
8079b1c85   Hugh Dickins   mm: clarify the r...
323
324
325
326
327
328
329
330
  			if (radix_tree_deref_retry(page))
  				goto restart;
  			/*
  			 * Otherwise, we must be storing a swap entry
  			 * here as an exceptional entry: so return it
  			 * without attempting to raise page count.
  			 */
  			goto export;
7a5d0fbb2   Hugh Dickins   tmpfs: convert sh...
331
332
333
334
335
336
337
338
339
340
341
342
343
344
345
346
347
348
349
350
351
352
353
354
355
356
357
358
359
360
361
362
363
364
365
366
367
368
369
370
371
372
373
374
375
376
377
378
379
380
381
382
383
384
385
  		}
  		if (!page_cache_get_speculative(page))
  			goto repeat;
  
  		/* Has the page moved? */
  		if (unlikely(page != *((void **)pages[i]))) {
  			page_cache_release(page);
  			goto repeat;
  		}
  export:
  		indices[ret] = indices[i];
  		pages[ret] = page;
  		ret++;
  	}
  	if (unlikely(!ret && nr_found))
  		goto restart;
  	rcu_read_unlock();
  	return ret;
  }
  
  /*
   * Remove swap entry from radix tree, free the swap and its page cache.
   */
  static int shmem_free_swap(struct address_space *mapping,
  			   pgoff_t index, void *radswap)
  {
  	int error;
  
  	spin_lock_irq(&mapping->tree_lock);
  	error = shmem_radix_tree_replace(mapping, index, radswap, NULL);
  	spin_unlock_irq(&mapping->tree_lock);
  	if (!error)
  		free_swap_and_cache(radix_to_swp_entry(radswap));
  	return error;
  }
  
  /*
   * Pagevec may contain swap entries, so shuffle up pages before releasing.
   */
  static void shmem_pagevec_release(struct pagevec *pvec)
  {
  	int i, j;
  
  	for (i = 0, j = 0; i < pagevec_count(pvec); i++) {
  		struct page *page = pvec->pages[i];
  		if (!radix_tree_exceptional_entry(page))
  			pvec->pages[j++] = page;
  	}
  	pvec->nr = j;
  	pagevec_release(pvec);
  }
  
  /*
   * Remove range of pages and swap entries from radix tree, and free them.
   */
285b2c4fd   Hugh Dickins   tmpfs: demolish o...
386
  void shmem_truncate_range(struct inode *inode, loff_t lstart, loff_t lend)
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
387
  {
285b2c4fd   Hugh Dickins   tmpfs: demolish o...
388
  	struct address_space *mapping = inode->i_mapping;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
389
  	struct shmem_inode_info *info = SHMEM_I(inode);
285b2c4fd   Hugh Dickins   tmpfs: demolish o...
390
  	pgoff_t start = (lstart + PAGE_CACHE_SIZE - 1) >> PAGE_CACHE_SHIFT;
bda97eab0   Hugh Dickins   tmpfs: copy trunc...
391
  	unsigned partial = lstart & (PAGE_CACHE_SIZE - 1);
285b2c4fd   Hugh Dickins   tmpfs: demolish o...
392
  	pgoff_t end = (lend >> PAGE_CACHE_SHIFT);
bda97eab0   Hugh Dickins   tmpfs: copy trunc...
393
  	struct pagevec pvec;
7a5d0fbb2   Hugh Dickins   tmpfs: convert sh...
394
395
  	pgoff_t indices[PAGEVEC_SIZE];
  	long nr_swaps_freed = 0;
285b2c4fd   Hugh Dickins   tmpfs: demolish o...
396
  	pgoff_t index;
bda97eab0   Hugh Dickins   tmpfs: copy trunc...
397
398
399
400
401
402
  	int i;
  
  	BUG_ON((lend & (PAGE_CACHE_SIZE - 1)) != (PAGE_CACHE_SIZE - 1));
  
  	pagevec_init(&pvec, 0);
  	index = start;
7a5d0fbb2   Hugh Dickins   tmpfs: convert sh...
403
404
405
406
407
408
  	while (index <= end) {
  		pvec.nr = shmem_find_get_pages_and_swap(mapping, index,
  			min(end - index, (pgoff_t)PAGEVEC_SIZE - 1) + 1,
  							pvec.pages, indices);
  		if (!pvec.nr)
  			break;
bda97eab0   Hugh Dickins   tmpfs: copy trunc...
409
410
411
  		mem_cgroup_uncharge_start();
  		for (i = 0; i < pagevec_count(&pvec); i++) {
  			struct page *page = pvec.pages[i];
7a5d0fbb2   Hugh Dickins   tmpfs: convert sh...
412
  			index = indices[i];
bda97eab0   Hugh Dickins   tmpfs: copy trunc...
413
414
  			if (index > end)
  				break;
7a5d0fbb2   Hugh Dickins   tmpfs: convert sh...
415
416
417
  			if (radix_tree_exceptional_entry(page)) {
  				nr_swaps_freed += !shmem_free_swap(mapping,
  								index, page);
bda97eab0   Hugh Dickins   tmpfs: copy trunc...
418
  				continue;
7a5d0fbb2   Hugh Dickins   tmpfs: convert sh...
419
420
421
  			}
  
  			if (!trylock_page(page))
bda97eab0   Hugh Dickins   tmpfs: copy trunc...
422
  				continue;
7a5d0fbb2   Hugh Dickins   tmpfs: convert sh...
423
424
425
  			if (page->mapping == mapping) {
  				VM_BUG_ON(PageWriteback(page));
  				truncate_inode_page(mapping, page);
bda97eab0   Hugh Dickins   tmpfs: copy trunc...
426
  			}
bda97eab0   Hugh Dickins   tmpfs: copy trunc...
427
428
  			unlock_page(page);
  		}
7a5d0fbb2   Hugh Dickins   tmpfs: convert sh...
429
  		shmem_pagevec_release(&pvec);
bda97eab0   Hugh Dickins   tmpfs: copy trunc...
430
431
432
433
  		mem_cgroup_uncharge_end();
  		cond_resched();
  		index++;
  	}
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
434

bda97eab0   Hugh Dickins   tmpfs: copy trunc...
435
436
437
438
439
440
441
442
443
444
445
446
447
448
  	if (partial) {
  		struct page *page = NULL;
  		shmem_getpage(inode, start - 1, &page, SGP_READ, NULL);
  		if (page) {
  			zero_user_segment(page, partial, PAGE_CACHE_SIZE);
  			set_page_dirty(page);
  			unlock_page(page);
  			page_cache_release(page);
  		}
  	}
  
  	index = start;
  	for ( ; ; ) {
  		cond_resched();
7a5d0fbb2   Hugh Dickins   tmpfs: convert sh...
449
450
451
452
  		pvec.nr = shmem_find_get_pages_and_swap(mapping, index,
  			min(end - index, (pgoff_t)PAGEVEC_SIZE - 1) + 1,
  							pvec.pages, indices);
  		if (!pvec.nr) {
bda97eab0   Hugh Dickins   tmpfs: copy trunc...
453
454
455
456
457
  			if (index == start)
  				break;
  			index = start;
  			continue;
  		}
7a5d0fbb2   Hugh Dickins   tmpfs: convert sh...
458
459
  		if (index == start && indices[0] > end) {
  			shmem_pagevec_release(&pvec);
bda97eab0   Hugh Dickins   tmpfs: copy trunc...
460
461
462
463
464
  			break;
  		}
  		mem_cgroup_uncharge_start();
  		for (i = 0; i < pagevec_count(&pvec); i++) {
  			struct page *page = pvec.pages[i];
7a5d0fbb2   Hugh Dickins   tmpfs: convert sh...
465
  			index = indices[i];
bda97eab0   Hugh Dickins   tmpfs: copy trunc...
466
467
  			if (index > end)
  				break;
7a5d0fbb2   Hugh Dickins   tmpfs: convert sh...
468
469
470
471
472
  			if (radix_tree_exceptional_entry(page)) {
  				nr_swaps_freed += !shmem_free_swap(mapping,
  								index, page);
  				continue;
  			}
bda97eab0   Hugh Dickins   tmpfs: copy trunc...
473
  			lock_page(page);
7a5d0fbb2   Hugh Dickins   tmpfs: convert sh...
474
475
476
477
  			if (page->mapping == mapping) {
  				VM_BUG_ON(PageWriteback(page));
  				truncate_inode_page(mapping, page);
  			}
bda97eab0   Hugh Dickins   tmpfs: copy trunc...
478
479
  			unlock_page(page);
  		}
7a5d0fbb2   Hugh Dickins   tmpfs: convert sh...
480
  		shmem_pagevec_release(&pvec);
bda97eab0   Hugh Dickins   tmpfs: copy trunc...
481
482
483
  		mem_cgroup_uncharge_end();
  		index++;
  	}
94c1e62df   Hugh Dickins   tmpfs: take contr...
484

1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
485
  	spin_lock(&info->lock);
7a5d0fbb2   Hugh Dickins   tmpfs: convert sh...
486
  	info->swapped -= nr_swaps_freed;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
487
488
  	shmem_recalc_inode(inode);
  	spin_unlock(&info->lock);
285b2c4fd   Hugh Dickins   tmpfs: demolish o...
489
  	inode->i_ctime = inode->i_mtime = CURRENT_TIME;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
490
  }
94c1e62df   Hugh Dickins   tmpfs: take contr...
491
  EXPORT_SYMBOL_GPL(shmem_truncate_range);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
492

94c1e62df   Hugh Dickins   tmpfs: take contr...
493
  static int shmem_setattr(struct dentry *dentry, struct iattr *attr)
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
494
495
  {
  	struct inode *inode = dentry->d_inode;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
496
  	int error;
db78b877f   Christoph Hellwig   always call inode...
497
498
499
  	error = inode_change_ok(inode, attr);
  	if (error)
  		return error;
94c1e62df   Hugh Dickins   tmpfs: take contr...
500
501
502
  	if (S_ISREG(inode->i_mode) && (attr->ia_valid & ATTR_SIZE)) {
  		loff_t oldsize = inode->i_size;
  		loff_t newsize = attr->ia_size;
3889e6e76   npiggin@suse.de   tmpfs: convert to...
503

94c1e62df   Hugh Dickins   tmpfs: take contr...
504
505
506
507
508
509
510
511
512
513
514
  		if (newsize != oldsize) {
  			i_size_write(inode, newsize);
  			inode->i_ctime = inode->i_mtime = CURRENT_TIME;
  		}
  		if (newsize < oldsize) {
  			loff_t holebegin = round_up(newsize, PAGE_SIZE);
  			unmap_mapping_range(inode->i_mapping, holebegin, 0, 1);
  			shmem_truncate_range(inode, newsize, (loff_t)-1);
  			/* unmap again to remove racily COWed private pages */
  			unmap_mapping_range(inode->i_mapping, holebegin, 0, 1);
  		}
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
515
  	}
db78b877f   Christoph Hellwig   always call inode...
516
  	setattr_copy(inode, attr);
39f0247d3   Andreas Gruenbacher   [PATCH] Access Co...
517
  #ifdef CONFIG_TMPFS_POSIX_ACL
db78b877f   Christoph Hellwig   always call inode...
518
  	if (attr->ia_valid & ATTR_MODE)
1c7c474c3   Christoph Hellwig   make generic_acl ...
519
  		error = generic_acl_chmod(inode);
39f0247d3   Andreas Gruenbacher   [PATCH] Access Co...
520
  #endif
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
521
522
  	return error;
  }
1f895f75d   Al Viro   switch shmem.c to...
523
  static void shmem_evict_inode(struct inode *inode)
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
524
  {
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
525
  	struct shmem_inode_info *info = SHMEM_I(inode);
b09e0fa4b   Eric Paris   tmpfs: implement ...
526
  	struct shmem_xattr *xattr, *nxattr;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
527

3889e6e76   npiggin@suse.de   tmpfs: convert to...
528
  	if (inode->i_mapping->a_ops == &shmem_aops) {
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
529
530
  		shmem_unacct_size(info->flags, inode->i_size);
  		inode->i_size = 0;
3889e6e76   npiggin@suse.de   tmpfs: convert to...
531
  		shmem_truncate_range(inode, 0, (loff_t)-1);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
532
  		if (!list_empty(&info->swaplist)) {
cb5f7b9a4   Hugh Dickins   tmpfs: make shmem...
533
  			mutex_lock(&shmem_swaplist_mutex);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
534
  			list_del_init(&info->swaplist);
cb5f7b9a4   Hugh Dickins   tmpfs: make shmem...
535
  			mutex_unlock(&shmem_swaplist_mutex);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
536
  		}
69f07ec93   Hugh Dickins   tmpfs: use kmemdu...
537
538
  	} else
  		kfree(info->symlink);
b09e0fa4b   Eric Paris   tmpfs: implement ...
539
540
541
542
543
  
  	list_for_each_entry_safe(xattr, nxattr, &info->xattr_list, list) {
  		kfree(xattr->name);
  		kfree(xattr);
  	}
0edd73b33   Hugh Dickins   [PATCH] shmem: re...
544
  	BUG_ON(inode->i_blocks);
5b04c6890   Pavel Emelyanov   shmem: factor out...
545
  	shmem_free_inode(inode->i_sb);
1f895f75d   Al Viro   switch shmem.c to...
546
  	end_writeback(inode);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
547
  }
46f65ec15   Hugh Dickins   tmpfs: convert sh...
548
549
550
  /*
   * If swap found in inode, free it and move page from swapcache to filecache.
   */
41ffe5d5c   Hugh Dickins   tmpfs: miscellane...
551
552
  static int shmem_unuse_inode(struct shmem_inode_info *info,
  			     swp_entry_t swap, struct page *page)
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
553
  {
285b2c4fd   Hugh Dickins   tmpfs: demolish o...
554
  	struct address_space *mapping = info->vfs_inode.i_mapping;
46f65ec15   Hugh Dickins   tmpfs: convert sh...
555
  	void *radswap;
41ffe5d5c   Hugh Dickins   tmpfs: miscellane...
556
  	pgoff_t index;
d9fe526a8   Hugh Dickins   tmpfs: allow file...
557
  	int error;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
558

46f65ec15   Hugh Dickins   tmpfs: convert sh...
559
  	radswap = swp_to_radix_entry(swap);
e504f3fdd   Hugh Dickins   tmpfs radix_tree:...
560
  	index = radix_tree_locate_item(&mapping->page_tree, radswap);
46f65ec15   Hugh Dickins   tmpfs: convert sh...
561
  	if (index == -1)
285b2c4fd   Hugh Dickins   tmpfs: demolish o...
562
  		return 0;
2e0e26c76   Hugh Dickins   tmpfs: open a win...
563

1b1b32f2c   Hugh Dickins   tmpfs: fix shmem_...
564
565
  	/*
  	 * Move _head_ to start search for next from here.
1f895f75d   Al Viro   switch shmem.c to...
566
  	 * But be careful: shmem_evict_inode checks list_empty without taking
1b1b32f2c   Hugh Dickins   tmpfs: fix shmem_...
567
  	 * mutex, and there's an instant in list_move_tail when info->swaplist
285b2c4fd   Hugh Dickins   tmpfs: demolish o...
568
  	 * would appear empty, if it were the only one on shmem_swaplist.
1b1b32f2c   Hugh Dickins   tmpfs: fix shmem_...
569
570
571
  	 */
  	if (shmem_swaplist.next != &info->swaplist)
  		list_move_tail(&shmem_swaplist, &info->swaplist);
2e0e26c76   Hugh Dickins   tmpfs: open a win...
572

d13d14430   KAMEZAWA Hiroyuki   memcg: handle swa...
573
  	/*
778dd893a   Hugh Dickins   tmpfs: fix race b...
574
575
576
  	 * We rely on shmem_swaplist_mutex, not only to protect the swaplist,
  	 * but also to hold up shmem_evict_inode(): so inode cannot be freed
  	 * beneath us (pagelock doesn't help until the page is in pagecache).
d13d14430   KAMEZAWA Hiroyuki   memcg: handle swa...
577
  	 */
46f65ec15   Hugh Dickins   tmpfs: convert sh...
578
579
  	error = shmem_add_to_page_cache(page, mapping, index,
  						GFP_NOWAIT, radswap);
778dd893a   Hugh Dickins   tmpfs: fix race b...
580
  	/* which does mem_cgroup_uncharge_cache_page on error */
69029cd55   KAMEZAWA Hiroyuki   memcg: remove ref...
581

48f170fb7   Hugh Dickins   tmpfs: simplify u...
582
  	if (error != -ENOMEM) {
46f65ec15   Hugh Dickins   tmpfs: convert sh...
583
584
585
586
  		/*
  		 * Truncation and eviction use free_swap_and_cache(), which
  		 * only does trylock page: if we raced, best clean up here.
  		 */
73b1262fa   Hugh Dickins   tmpfs: move swap ...
587
588
  		delete_from_swap_cache(page);
  		set_page_dirty(page);
46f65ec15   Hugh Dickins   tmpfs: convert sh...
589
590
591
592
593
594
  		if (!error) {
  			spin_lock(&info->lock);
  			info->swapped--;
  			spin_unlock(&info->lock);
  			swap_free(swap);
  		}
2e0e26c76   Hugh Dickins   tmpfs: open a win...
595
  		error = 1;	/* not an error, but entry was found */
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
596
  	}
2e0e26c76   Hugh Dickins   tmpfs: open a win...
597
  	return error;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
598
599
600
  }
  
  /*
46f65ec15   Hugh Dickins   tmpfs: convert sh...
601
   * Search through swapped inodes to find and replace swap by page.
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
602
   */
41ffe5d5c   Hugh Dickins   tmpfs: miscellane...
603
  int shmem_unuse(swp_entry_t swap, struct page *page)
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
604
  {
41ffe5d5c   Hugh Dickins   tmpfs: miscellane...
605
  	struct list_head *this, *next;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
606
607
  	struct shmem_inode_info *info;
  	int found = 0;
778dd893a   Hugh Dickins   tmpfs: fix race b...
608
609
610
611
612
613
  	int error;
  
  	/*
  	 * Charge page using GFP_KERNEL while we can wait, before taking
  	 * the shmem_swaplist_mutex which might hold up shmem_writepage().
  	 * Charged back to the user (not to caller) when swap account is used.
778dd893a   Hugh Dickins   tmpfs: fix race b...
614
615
616
617
  	 */
  	error = mem_cgroup_cache_charge(page, current->mm, GFP_KERNEL);
  	if (error)
  		goto out;
46f65ec15   Hugh Dickins   tmpfs: convert sh...
618
  	/* No radix_tree_preload: swap entry keeps a place for page in tree */
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
619

cb5f7b9a4   Hugh Dickins   tmpfs: make shmem...
620
  	mutex_lock(&shmem_swaplist_mutex);
41ffe5d5c   Hugh Dickins   tmpfs: miscellane...
621
622
  	list_for_each_safe(this, next, &shmem_swaplist) {
  		info = list_entry(this, struct shmem_inode_info, swaplist);
285b2c4fd   Hugh Dickins   tmpfs: demolish o...
623
  		if (info->swapped)
41ffe5d5c   Hugh Dickins   tmpfs: miscellane...
624
  			found = shmem_unuse_inode(info, swap, page);
6922c0c7a   Hugh Dickins   tmpfs: convert sh...
625
626
  		else
  			list_del_init(&info->swaplist);
cb5f7b9a4   Hugh Dickins   tmpfs: make shmem...
627
  		cond_resched();
2e0e26c76   Hugh Dickins   tmpfs: open a win...
628
  		if (found)
778dd893a   Hugh Dickins   tmpfs: fix race b...
629
  			break;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
630
  	}
cb5f7b9a4   Hugh Dickins   tmpfs: make shmem...
631
  	mutex_unlock(&shmem_swaplist_mutex);
778dd893a   Hugh Dickins   tmpfs: fix race b...
632

778dd893a   Hugh Dickins   tmpfs: fix race b...
633
634
635
636
637
  	if (!found)
  		mem_cgroup_uncharge_cache_page(page);
  	if (found < 0)
  		error = found;
  out:
aaa468653   Hugh Dickins   swap_info: note S...
638
639
  	unlock_page(page);
  	page_cache_release(page);
778dd893a   Hugh Dickins   tmpfs: fix race b...
640
  	return error;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
641
642
643
644
645
646
647
648
  }
  
  /*
   * Move the page from the page cache to the swap cache.
   */
  static int shmem_writepage(struct page *page, struct writeback_control *wbc)
  {
  	struct shmem_inode_info *info;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
649
  	struct address_space *mapping;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
650
  	struct inode *inode;
6922c0c7a   Hugh Dickins   tmpfs: convert sh...
651
652
  	swp_entry_t swap;
  	pgoff_t index;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
653
654
  
  	BUG_ON(!PageLocked(page));
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
655
656
657
658
659
660
  	mapping = page->mapping;
  	index = page->index;
  	inode = mapping->host;
  	info = SHMEM_I(inode);
  	if (info->flags & VM_LOCKED)
  		goto redirty;
d9fe526a8   Hugh Dickins   tmpfs: allow file...
661
  	if (!total_swap_pages)
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
662
  		goto redirty;
d9fe526a8   Hugh Dickins   tmpfs: allow file...
663
664
665
  	/*
  	 * shmem_backing_dev_info's capabilities prevent regular writeback or
  	 * sync from ever calling shmem_writepage; but a stacking filesystem
48f170fb7   Hugh Dickins   tmpfs: simplify u...
666
  	 * might use ->writepage of its underlying filesystem, in which case
d9fe526a8   Hugh Dickins   tmpfs: allow file...
667
  	 * tmpfs should write out to swap only in response to memory pressure,
48f170fb7   Hugh Dickins   tmpfs: simplify u...
668
  	 * and not for the writeback threads or sync.
d9fe526a8   Hugh Dickins   tmpfs: allow file...
669
  	 */
48f170fb7   Hugh Dickins   tmpfs: simplify u...
670
671
672
673
674
675
676
  	if (!wbc->for_reclaim) {
  		WARN_ON_ONCE(1);	/* Still happens? Tell us about it! */
  		goto redirty;
  	}
  	swap = get_swap_page();
  	if (!swap.val)
  		goto redirty;
d9fe526a8   Hugh Dickins   tmpfs: allow file...
677

b1dea800a   Hugh Dickins   tmpfs: fix race b...
678
679
  	/*
  	 * Add inode to shmem_unuse()'s list of swapped-out inodes,
6922c0c7a   Hugh Dickins   tmpfs: convert sh...
680
681
  	 * if it's not already there.  Do it now before the page is
  	 * moved to swap cache, when its pagelock no longer protects
b1dea800a   Hugh Dickins   tmpfs: fix race b...
682
  	 * the inode from eviction.  But don't unlock the mutex until
6922c0c7a   Hugh Dickins   tmpfs: convert sh...
683
684
  	 * we've incremented swapped, because shmem_unuse_inode() will
  	 * prune a !swapped inode from the swaplist under this mutex.
b1dea800a   Hugh Dickins   tmpfs: fix race b...
685
  	 */
48f170fb7   Hugh Dickins   tmpfs: simplify u...
686
687
688
  	mutex_lock(&shmem_swaplist_mutex);
  	if (list_empty(&info->swaplist))
  		list_add_tail(&info->swaplist, &shmem_swaplist);
b1dea800a   Hugh Dickins   tmpfs: fix race b...
689

48f170fb7   Hugh Dickins   tmpfs: simplify u...
690
  	if (add_to_swap_cache(page, swap, GFP_ATOMIC) == 0) {
aaa468653   Hugh Dickins   swap_info: note S...
691
  		swap_shmem_alloc(swap);
6922c0c7a   Hugh Dickins   tmpfs: convert sh...
692
693
694
695
696
  		shmem_delete_from_page_cache(page, swp_to_radix_entry(swap));
  
  		spin_lock(&info->lock);
  		info->swapped++;
  		shmem_recalc_inode(inode);
826267cf1   Hugh Dickins   tmpfs: fix race b...
697
  		spin_unlock(&info->lock);
6922c0c7a   Hugh Dickins   tmpfs: convert sh...
698
699
  
  		mutex_unlock(&shmem_swaplist_mutex);
d9fe526a8   Hugh Dickins   tmpfs: allow file...
700
  		BUG_ON(page_mapped(page));
9fab5619b   Hugh Dickins   shmem: writepage ...
701
  		swap_writepage(page, wbc);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
702
703
  		return 0;
  	}
6922c0c7a   Hugh Dickins   tmpfs: convert sh...
704
  	mutex_unlock(&shmem_swaplist_mutex);
cb4b86ba4   KAMEZAWA Hiroyuki   mm: add swap cach...
705
  	swapcache_free(swap, NULL);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
706
707
  redirty:
  	set_page_dirty(page);
d9fe526a8   Hugh Dickins   tmpfs: allow file...
708
709
710
711
  	if (wbc->for_reclaim)
  		return AOP_WRITEPAGE_ACTIVATE;	/* Return with page locked */
  	unlock_page(page);
  	return 0;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
712
713
714
  }
  
  #ifdef CONFIG_NUMA
680d794ba   akpm@linux-foundation.org   mount options: fi...
715
  #ifdef CONFIG_TMPFS
71fe804b6   Lee Schermerhorn   mempolicy: use st...
716
  static void shmem_show_mpol(struct seq_file *seq, struct mempolicy *mpol)
680d794ba   akpm@linux-foundation.org   mount options: fi...
717
  {
095f1fc4e   Lee Schermerhorn   mempolicy: rework...
718
  	char buffer[64];
680d794ba   akpm@linux-foundation.org   mount options: fi...
719

71fe804b6   Lee Schermerhorn   mempolicy: use st...
720
  	if (!mpol || mpol->mode == MPOL_DEFAULT)
095f1fc4e   Lee Schermerhorn   mempolicy: rework...
721
  		return;		/* show nothing */
680d794ba   akpm@linux-foundation.org   mount options: fi...
722

71fe804b6   Lee Schermerhorn   mempolicy: use st...
723
  	mpol_to_str(buffer, sizeof(buffer), mpol, 1);
095f1fc4e   Lee Schermerhorn   mempolicy: rework...
724
725
  
  	seq_printf(seq, ",mpol=%s", buffer);
680d794ba   akpm@linux-foundation.org   mount options: fi...
726
  }
71fe804b6   Lee Schermerhorn   mempolicy: use st...
727
728
729
730
731
732
733
734
735
736
737
738
  
  static struct mempolicy *shmem_get_sbmpol(struct shmem_sb_info *sbinfo)
  {
  	struct mempolicy *mpol = NULL;
  	if (sbinfo->mpol) {
  		spin_lock(&sbinfo->stat_lock);	/* prevent replace/use races */
  		mpol = sbinfo->mpol;
  		mpol_get(mpol);
  		spin_unlock(&sbinfo->stat_lock);
  	}
  	return mpol;
  }
680d794ba   akpm@linux-foundation.org   mount options: fi...
739
  #endif /* CONFIG_TMPFS */
41ffe5d5c   Hugh Dickins   tmpfs: miscellane...
740
741
  static struct page *shmem_swapin(swp_entry_t swap, gfp_t gfp,
  			struct shmem_inode_info *info, pgoff_t index)
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
742
  {
52cd3b074   Lee Schermerhorn   mempolicy: rework...
743
  	struct mempolicy mpol, *spol;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
744
  	struct vm_area_struct pvma;
52cd3b074   Lee Schermerhorn   mempolicy: rework...
745
  	spol = mpol_cond_copy(&mpol,
41ffe5d5c   Hugh Dickins   tmpfs: miscellane...
746
  			mpol_shared_policy_lookup(&info->policy, index));
52cd3b074   Lee Schermerhorn   mempolicy: rework...
747

1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
748
  	/* Create a pseudo vma that just contains the policy */
c4cc6d07b   Hugh Dickins   swapin_readahead:...
749
  	pvma.vm_start = 0;
41ffe5d5c   Hugh Dickins   tmpfs: miscellane...
750
  	pvma.vm_pgoff = index;
c4cc6d07b   Hugh Dickins   swapin_readahead:...
751
  	pvma.vm_ops = NULL;
52cd3b074   Lee Schermerhorn   mempolicy: rework...
752
  	pvma.vm_policy = spol;
41ffe5d5c   Hugh Dickins   tmpfs: miscellane...
753
  	return swapin_readahead(swap, gfp, &pvma, 0);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
754
  }
02098feaa   Hugh Dickins   swapin needs gfp_...
755
  static struct page *shmem_alloc_page(gfp_t gfp,
41ffe5d5c   Hugh Dickins   tmpfs: miscellane...
756
  			struct shmem_inode_info *info, pgoff_t index)
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
757
758
  {
  	struct vm_area_struct pvma;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
759

c4cc6d07b   Hugh Dickins   swapin_readahead:...
760
761
  	/* Create a pseudo vma that just contains the policy */
  	pvma.vm_start = 0;
41ffe5d5c   Hugh Dickins   tmpfs: miscellane...
762
  	pvma.vm_pgoff = index;
c4cc6d07b   Hugh Dickins   swapin_readahead:...
763
  	pvma.vm_ops = NULL;
41ffe5d5c   Hugh Dickins   tmpfs: miscellane...
764
  	pvma.vm_policy = mpol_shared_policy_lookup(&info->policy, index);
52cd3b074   Lee Schermerhorn   mempolicy: rework...
765
766
767
768
769
  
  	/*
  	 * alloc_page_vma() will drop the shared policy reference
  	 */
  	return alloc_page_vma(gfp, &pvma, 0);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
770
  }
680d794ba   akpm@linux-foundation.org   mount options: fi...
771
772
  #else /* !CONFIG_NUMA */
  #ifdef CONFIG_TMPFS
41ffe5d5c   Hugh Dickins   tmpfs: miscellane...
773
  static inline void shmem_show_mpol(struct seq_file *seq, struct mempolicy *mpol)
680d794ba   akpm@linux-foundation.org   mount options: fi...
774
775
776
  {
  }
  #endif /* CONFIG_TMPFS */
41ffe5d5c   Hugh Dickins   tmpfs: miscellane...
777
778
  static inline struct page *shmem_swapin(swp_entry_t swap, gfp_t gfp,
  			struct shmem_inode_info *info, pgoff_t index)
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
779
  {
41ffe5d5c   Hugh Dickins   tmpfs: miscellane...
780
  	return swapin_readahead(swap, gfp, NULL, 0);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
781
  }
02098feaa   Hugh Dickins   swapin needs gfp_...
782
  static inline struct page *shmem_alloc_page(gfp_t gfp,
41ffe5d5c   Hugh Dickins   tmpfs: miscellane...
783
  			struct shmem_inode_info *info, pgoff_t index)
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
784
  {
e84e2e132   Hugh Dickins   tmpfs: restore mi...
785
  	return alloc_page(gfp);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
786
  }
680d794ba   akpm@linux-foundation.org   mount options: fi...
787
  #endif /* CONFIG_NUMA */
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
788

71fe804b6   Lee Schermerhorn   mempolicy: use st...
789
790
791
792
793
794
  #if !defined(CONFIG_NUMA) || !defined(CONFIG_TMPFS)
  static inline struct mempolicy *shmem_get_sbmpol(struct shmem_sb_info *sbinfo)
  {
  	return NULL;
  }
  #endif
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
795
  /*
68da9f055   Hugh Dickins   tmpfs: pass gfp t...
796
   * shmem_getpage_gfp - find page in cache, or get from swap, or allocate
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
797
798
799
800
801
   *
   * If we allocate a new one we do not mark it dirty. That's up to the
   * vm. If we swap it in we mark it dirty since we also free the swap
   * entry since a page cannot live in both the swap and page cache
   */
41ffe5d5c   Hugh Dickins   tmpfs: miscellane...
802
  static int shmem_getpage_gfp(struct inode *inode, pgoff_t index,
68da9f055   Hugh Dickins   tmpfs: pass gfp t...
803
  	struct page **pagep, enum sgp_type sgp, gfp_t gfp, int *fault_type)
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
804
805
  {
  	struct address_space *mapping = inode->i_mapping;
54af60421   Hugh Dickins   tmpfs: convert sh...
806
  	struct shmem_inode_info *info;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
807
  	struct shmem_sb_info *sbinfo;
27ab70062   Hugh Dickins   tmpfs: simplify f...
808
  	struct page *page;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
809
810
  	swp_entry_t swap;
  	int error;
54af60421   Hugh Dickins   tmpfs: convert sh...
811
  	int once = 0;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
812

41ffe5d5c   Hugh Dickins   tmpfs: miscellane...
813
  	if (index > (MAX_LFS_FILESIZE >> PAGE_CACHE_SHIFT))
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
814
  		return -EFBIG;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
815
  repeat:
54af60421   Hugh Dickins   tmpfs: convert sh...
816
  	swap.val = 0;
41ffe5d5c   Hugh Dickins   tmpfs: miscellane...
817
  	page = find_lock_page(mapping, index);
54af60421   Hugh Dickins   tmpfs: convert sh...
818
819
820
821
822
823
824
825
826
827
828
829
  	if (radix_tree_exceptional_entry(page)) {
  		swap = radix_to_swp_entry(page);
  		page = NULL;
  	}
  
  	if (sgp != SGP_WRITE &&
  	    ((loff_t)index << PAGE_CACHE_SHIFT) >= i_size_read(inode)) {
  		error = -EINVAL;
  		goto failed;
  	}
  
  	if (page || (sgp == SGP_READ && !swap.val)) {
b409f9fcf   Hugh Dickins   tmpfs: radix_tree...
830
  		/*
27ab70062   Hugh Dickins   tmpfs: simplify f...
831
832
833
  		 * Once we can get the page lock, it must be uptodate:
  		 * if there were an error in reading back from swap,
  		 * the page would not be inserted into the filecache.
b409f9fcf   Hugh Dickins   tmpfs: radix_tree...
834
  		 */
54af60421   Hugh Dickins   tmpfs: convert sh...
835
836
837
  		BUG_ON(page && !PageUptodate(page));
  		*pagep = page;
  		return 0;
27ab70062   Hugh Dickins   tmpfs: simplify f...
838
839
840
  	}
  
  	/*
54af60421   Hugh Dickins   tmpfs: convert sh...
841
842
  	 * Fast cache lookup did not find it:
  	 * bring it back from swap or allocate.
27ab70062   Hugh Dickins   tmpfs: simplify f...
843
  	 */
54af60421   Hugh Dickins   tmpfs: convert sh...
844
845
  	info = SHMEM_I(inode);
  	sbinfo = SHMEM_SB(inode->i_sb);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
846

1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
847
848
  	if (swap.val) {
  		/* Look it up and read it in.. */
27ab70062   Hugh Dickins   tmpfs: simplify f...
849
850
  		page = lookup_swap_cache(swap);
  		if (!page) {
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
851
  			/* here we actually do the io */
68da9f055   Hugh Dickins   tmpfs: pass gfp t...
852
853
  			if (fault_type)
  				*fault_type |= VM_FAULT_MAJOR;
41ffe5d5c   Hugh Dickins   tmpfs: miscellane...
854
  			page = shmem_swapin(swap, gfp, info, index);
27ab70062   Hugh Dickins   tmpfs: simplify f...
855
  			if (!page) {
54af60421   Hugh Dickins   tmpfs: convert sh...
856
857
  				error = -ENOMEM;
  				goto failed;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
858
  			}
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
859
860
861
  		}
  
  		/* We have to do this with page locked to prevent races */
54af60421   Hugh Dickins   tmpfs: convert sh...
862
  		lock_page(page);
27ab70062   Hugh Dickins   tmpfs: simplify f...
863
  		if (!PageUptodate(page)) {
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
864
  			error = -EIO;
54af60421   Hugh Dickins   tmpfs: convert sh...
865
  			goto failed;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
866
  		}
54af60421   Hugh Dickins   tmpfs: convert sh...
867
868
869
870
871
872
873
874
875
  		wait_on_page_writeback(page);
  
  		/* Someone may have already done it for us */
  		if (page->mapping) {
  			if (page->mapping == mapping &&
  			    page->index == index)
  				goto done;
  			error = -EEXIST;
  			goto failed;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
876
  		}
27ab70062   Hugh Dickins   tmpfs: simplify f...
877

aa3b18955   Hugh Dickins   tmpfs: convert me...
878
879
880
881
882
  		error = mem_cgroup_cache_charge(page, current->mm,
  						gfp & GFP_RECLAIM_MASK);
  		if (!error)
  			error = shmem_add_to_page_cache(page, mapping, index,
  						gfp, swp_to_radix_entry(swap));
54af60421   Hugh Dickins   tmpfs: convert sh...
883
884
885
886
  		if (error)
  			goto failed;
  
  		spin_lock(&info->lock);
285b2c4fd   Hugh Dickins   tmpfs: demolish o...
887
  		info->swapped--;
54af60421   Hugh Dickins   tmpfs: convert sh...
888
  		shmem_recalc_inode(inode);
27ab70062   Hugh Dickins   tmpfs: simplify f...
889
  		spin_unlock(&info->lock);
54af60421   Hugh Dickins   tmpfs: convert sh...
890
891
  
  		delete_from_swap_cache(page);
27ab70062   Hugh Dickins   tmpfs: simplify f...
892
893
  		set_page_dirty(page);
  		swap_free(swap);
54af60421   Hugh Dickins   tmpfs: convert sh...
894
895
896
897
  	} else {
  		if (shmem_acct_block(info->flags)) {
  			error = -ENOSPC;
  			goto failed;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
898
  		}
0edd73b33   Hugh Dickins   [PATCH] shmem: re...
899
  		if (sbinfo->max_blocks) {
fc5da22ae   Hugh Dickins   tmpfs: fix off-by...
900
  			if (percpu_counter_compare(&sbinfo->used_blocks,
54af60421   Hugh Dickins   tmpfs: convert sh...
901
902
903
904
  						sbinfo->max_blocks) >= 0) {
  				error = -ENOSPC;
  				goto unacct;
  			}
7e496299d   Tim Chen   tmpfs: make tmpfs...
905
  			percpu_counter_inc(&sbinfo->used_blocks);
54af60421   Hugh Dickins   tmpfs: convert sh...
906
  		}
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
907

54af60421   Hugh Dickins   tmpfs: convert sh...
908
909
910
911
  		page = shmem_alloc_page(gfp, info, index);
  		if (!page) {
  			error = -ENOMEM;
  			goto decused;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
912
  		}
54af60421   Hugh Dickins   tmpfs: convert sh...
913
914
  		SetPageSwapBacked(page);
  		__set_page_locked(page);
aa3b18955   Hugh Dickins   tmpfs: convert me...
915
916
917
918
919
  		error = mem_cgroup_cache_charge(page, current->mm,
  						gfp & GFP_RECLAIM_MASK);
  		if (!error)
  			error = shmem_add_to_page_cache(page, mapping, index,
  						gfp, NULL);
54af60421   Hugh Dickins   tmpfs: convert sh...
920
921
922
923
924
  		if (error)
  			goto decused;
  		lru_cache_add_anon(page);
  
  		spin_lock(&info->lock);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
925
  		info->alloced++;
54af60421   Hugh Dickins   tmpfs: convert sh...
926
927
  		inode->i_blocks += BLOCKS_PER_PAGE;
  		shmem_recalc_inode(inode);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
928
  		spin_unlock(&info->lock);
54af60421   Hugh Dickins   tmpfs: convert sh...
929

27ab70062   Hugh Dickins   tmpfs: simplify f...
930
931
932
  		clear_highpage(page);
  		flush_dcache_page(page);
  		SetPageUptodate(page);
a0ee5ec52   Hugh Dickins   tmpfs: allocate o...
933
  		if (sgp == SGP_DIRTY)
27ab70062   Hugh Dickins   tmpfs: simplify f...
934
  			set_page_dirty(page);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
935
936
  	}
  done:
54af60421   Hugh Dickins   tmpfs: convert sh...
937
938
939
940
941
  	/* Perhaps the file has been truncated since we checked */
  	if (sgp != SGP_WRITE &&
  	    ((loff_t)index << PAGE_CACHE_SHIFT) >= i_size_read(inode)) {
  		error = -EINVAL;
  		goto trunc;
e83c32e8f   Hugh Dickins   tmpfs: simplify p...
942
  	}
54af60421   Hugh Dickins   tmpfs: convert sh...
943
944
  	*pagep = page;
  	return 0;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
945

59a16ead5   Hugh Dickins   tmpfs: fix spurio...
946
  	/*
54af60421   Hugh Dickins   tmpfs: convert sh...
947
  	 * Error recovery.
59a16ead5   Hugh Dickins   tmpfs: fix spurio...
948
  	 */
54af60421   Hugh Dickins   tmpfs: convert sh...
949
950
951
952
953
954
  trunc:
  	ClearPageDirty(page);
  	delete_from_page_cache(page);
  	spin_lock(&info->lock);
  	info->alloced--;
  	inode->i_blocks -= BLOCKS_PER_PAGE;
59a16ead5   Hugh Dickins   tmpfs: fix spurio...
955
  	spin_unlock(&info->lock);
54af60421   Hugh Dickins   tmpfs: convert sh...
956
957
958
959
960
961
962
963
964
965
966
967
968
969
  decused:
  	if (sbinfo->max_blocks)
  		percpu_counter_add(&sbinfo->used_blocks, -1);
  unacct:
  	shmem_unacct_blocks(info->flags, 1);
  failed:
  	if (swap.val && error != -EINVAL) {
  		struct page *test = find_get_page(mapping, index);
  		if (test && !radix_tree_exceptional_entry(test))
  			page_cache_release(test);
  		/* Have another try if the entry has changed */
  		if (test != swp_to_radix_entry(swap))
  			error = -EEXIST;
  	}
27ab70062   Hugh Dickins   tmpfs: simplify f...
970
  	if (page) {
54af60421   Hugh Dickins   tmpfs: convert sh...
971
  		unlock_page(page);
27ab70062   Hugh Dickins   tmpfs: simplify f...
972
  		page_cache_release(page);
54af60421   Hugh Dickins   tmpfs: convert sh...
973
974
975
976
977
978
  	}
  	if (error == -ENOSPC && !once++) {
  		info = SHMEM_I(inode);
  		spin_lock(&info->lock);
  		shmem_recalc_inode(inode);
  		spin_unlock(&info->lock);
27ab70062   Hugh Dickins   tmpfs: simplify f...
979
  		goto repeat;
ff36b8016   Shaohua Li   shmem: reduce pag...
980
  	}
54af60421   Hugh Dickins   tmpfs: convert sh...
981
982
983
  	if (error == -EEXIST)
  		goto repeat;
  	return error;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
984
  }
d0217ac04   Nick Piggin   mm: fault feedbac...
985
  static int shmem_fault(struct vm_area_struct *vma, struct vm_fault *vmf)
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
986
  {
d3ac7f892   Josef "Jeff" Sipek   [PATCH] mm: chang...
987
  	struct inode *inode = vma->vm_file->f_path.dentry->d_inode;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
988
  	int error;
68da9f055   Hugh Dickins   tmpfs: pass gfp t...
989
  	int ret = VM_FAULT_LOCKED;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
990

27d54b398   Hugh Dickins   shmem: SGP_QUICK ...
991
  	error = shmem_getpage(inode, vmf->pgoff, &vmf->page, SGP_CACHE, &ret);
d0217ac04   Nick Piggin   mm: fault feedbac...
992
993
  	if (error)
  		return ((error == -ENOMEM) ? VM_FAULT_OOM : VM_FAULT_SIGBUS);
68da9f055   Hugh Dickins   tmpfs: pass gfp t...
994

456f998ec   Ying Han   memcg: add the pa...
995
996
997
998
  	if (ret & VM_FAULT_MAJOR) {
  		count_vm_event(PGMAJFAULT);
  		mem_cgroup_count_vm_event(vma->vm_mm, PGMAJFAULT);
  	}
68da9f055   Hugh Dickins   tmpfs: pass gfp t...
999
  	return ret;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
1000
  }
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
1001
  #ifdef CONFIG_NUMA
41ffe5d5c   Hugh Dickins   tmpfs: miscellane...
1002
  static int shmem_set_policy(struct vm_area_struct *vma, struct mempolicy *mpol)
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
1003
  {
41ffe5d5c   Hugh Dickins   tmpfs: miscellane...
1004
1005
  	struct inode *inode = vma->vm_file->f_path.dentry->d_inode;
  	return mpol_set_shared_policy(&SHMEM_I(inode)->policy, vma, mpol);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
1006
  }
d8dc74f21   Adrian Bunk   mm/shmem.c: make ...
1007
1008
  static struct mempolicy *shmem_get_policy(struct vm_area_struct *vma,
  					  unsigned long addr)
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
1009
  {
41ffe5d5c   Hugh Dickins   tmpfs: miscellane...
1010
1011
  	struct inode *inode = vma->vm_file->f_path.dentry->d_inode;
  	pgoff_t index;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
1012

41ffe5d5c   Hugh Dickins   tmpfs: miscellane...
1013
1014
  	index = ((addr - vma->vm_start) >> PAGE_SHIFT) + vma->vm_pgoff;
  	return mpol_shared_policy_lookup(&SHMEM_I(inode)->policy, index);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
1015
1016
1017
1018
1019
  }
  #endif
  
  int shmem_lock(struct file *file, int lock, struct user_struct *user)
  {
d3ac7f892   Josef "Jeff" Sipek   [PATCH] mm: chang...
1020
  	struct inode *inode = file->f_path.dentry->d_inode;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
1021
1022
1023
1024
1025
1026
1027
1028
  	struct shmem_inode_info *info = SHMEM_I(inode);
  	int retval = -ENOMEM;
  
  	spin_lock(&info->lock);
  	if (lock && !(info->flags & VM_LOCKED)) {
  		if (!user_shm_lock(inode->i_size, user))
  			goto out_nomem;
  		info->flags |= VM_LOCKED;
89e004ea5   Lee Schermerhorn   SHM_LOCKED pages ...
1029
  		mapping_set_unevictable(file->f_mapping);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
1030
1031
1032
1033
  	}
  	if (!lock && (info->flags & VM_LOCKED) && user) {
  		user_shm_unlock(inode->i_size, user);
  		info->flags &= ~VM_LOCKED;
89e004ea5   Lee Schermerhorn   SHM_LOCKED pages ...
1034
  		mapping_clear_unevictable(file->f_mapping);
21ee9f398   Minchan Kim   vmscan: add barri...
1035
1036
1037
1038
1039
1040
  		/*
  		 * Ensure that a racing putback_lru_page() can see
  		 * the pages of this mapping are evictable when we
  		 * skip them due to !PageLRU during the scan.
  		 */
  		smp_mb__after_clear_bit();
89e004ea5   Lee Schermerhorn   SHM_LOCKED pages ...
1041
  		scan_mapping_unevictable_pages(file->f_mapping);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
1042
1043
  	}
  	retval = 0;
89e004ea5   Lee Schermerhorn   SHM_LOCKED pages ...
1044

1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
1045
1046
1047
1048
  out_nomem:
  	spin_unlock(&info->lock);
  	return retval;
  }
9b83a6a85   Adrian Bunk   [PATCH] mm/{,tiny...
1049
  static int shmem_mmap(struct file *file, struct vm_area_struct *vma)
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
1050
1051
1052
  {
  	file_accessed(file);
  	vma->vm_ops = &shmem_vm_ops;
d0217ac04   Nick Piggin   mm: fault feedbac...
1053
  	vma->vm_flags |= VM_CAN_NONLINEAR;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
1054
1055
  	return 0;
  }
454abafe9   Dmitry Monakhov   ramfs: replace in...
1056
1057
  static struct inode *shmem_get_inode(struct super_block *sb, const struct inode *dir,
  				     int mode, dev_t dev, unsigned long flags)
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
1058
1059
1060
1061
  {
  	struct inode *inode;
  	struct shmem_inode_info *info;
  	struct shmem_sb_info *sbinfo = SHMEM_SB(sb);
5b04c6890   Pavel Emelyanov   shmem: factor out...
1062
1063
  	if (shmem_reserve_inode(sb))
  		return NULL;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
1064
1065
1066
  
  	inode = new_inode(sb);
  	if (inode) {
85fe4025c   Christoph Hellwig   fs: do not assign...
1067
  		inode->i_ino = get_next_ino();
454abafe9   Dmitry Monakhov   ramfs: replace in...
1068
  		inode_init_owner(inode, dir, mode);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
1069
  		inode->i_blocks = 0;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
1070
1071
  		inode->i_mapping->backing_dev_info = &shmem_backing_dev_info;
  		inode->i_atime = inode->i_mtime = inode->i_ctime = CURRENT_TIME;
91828a405   David M. Grimes   [PATCH] knfsd: ad...
1072
  		inode->i_generation = get_seconds();
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
1073
1074
1075
  		info = SHMEM_I(inode);
  		memset(info, 0, (char *)inode - (char *)info);
  		spin_lock_init(&info->lock);
0b0a0806b   Hugh Dickins   shmem: fix shared...
1076
  		info->flags = flags & VM_NORESERVE;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
1077
  		INIT_LIST_HEAD(&info->swaplist);
b09e0fa4b   Eric Paris   tmpfs: implement ...
1078
  		INIT_LIST_HEAD(&info->xattr_list);
72c04902d   Al Viro   Get "no acls for ...
1079
  		cache_no_acl(inode);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
1080
1081
1082
  
  		switch (mode & S_IFMT) {
  		default:
39f0247d3   Andreas Gruenbacher   [PATCH] Access Co...
1083
  			inode->i_op = &shmem_special_inode_operations;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
1084
1085
1086
  			init_special_inode(inode, mode, dev);
  			break;
  		case S_IFREG:
14fcc23fd   Hugh Dickins   tmpfs: fix kernel...
1087
  			inode->i_mapping->a_ops = &shmem_aops;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
1088
1089
  			inode->i_op = &shmem_inode_operations;
  			inode->i_fop = &shmem_file_operations;
71fe804b6   Lee Schermerhorn   mempolicy: use st...
1090
1091
  			mpol_shared_policy_init(&info->policy,
  						 shmem_get_sbmpol(sbinfo));
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
1092
1093
  			break;
  		case S_IFDIR:
d8c76e6f4   Dave Hansen   [PATCH] r/o bind ...
1094
  			inc_nlink(inode);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
1095
1096
1097
1098
1099
1100
1101
1102
1103
1104
  			/* Some things misbehave if size == 0 on a directory */
  			inode->i_size = 2 * BOGO_DIRENT_SIZE;
  			inode->i_op = &shmem_dir_inode_operations;
  			inode->i_fop = &simple_dir_operations;
  			break;
  		case S_IFLNK:
  			/*
  			 * Must not load anything in the rbtree,
  			 * mpol_free_shared_policy will not be called.
  			 */
71fe804b6   Lee Schermerhorn   mempolicy: use st...
1105
  			mpol_shared_policy_init(&info->policy, NULL);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
1106
1107
  			break;
  		}
5b04c6890   Pavel Emelyanov   shmem: factor out...
1108
1109
  	} else
  		shmem_free_inode(sb);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
1110
1111
1112
1113
  	return inode;
  }
  
  #ifdef CONFIG_TMPFS
92e1d5be9   Arjan van de Ven   [PATCH] mark stru...
1114
  static const struct inode_operations shmem_symlink_inode_operations;
69f07ec93   Hugh Dickins   tmpfs: use kmemdu...
1115
  static const struct inode_operations shmem_short_symlink_operations;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
1116

1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
1117
  static int
800d15a53   Nick Piggin   implement simple ...
1118
1119
1120
  shmem_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
1121
  {
800d15a53   Nick Piggin   implement simple ...
1122
1123
  	struct inode *inode = mapping->host;
  	pgoff_t index = pos >> PAGE_CACHE_SHIFT;
800d15a53   Nick Piggin   implement simple ...
1124
1125
1126
1127
1128
1129
1130
1131
1132
  	return shmem_getpage(inode, index, pagep, SGP_WRITE, NULL);
  }
  
  static int
  shmem_write_end(struct file *file, struct address_space *mapping,
  			loff_t pos, unsigned len, unsigned copied,
  			struct page *page, void *fsdata)
  {
  	struct inode *inode = mapping->host;
d3602444e   Hugh Dickins   shmem_getpage ret...
1133
1134
  	if (pos + copied > inode->i_size)
  		i_size_write(inode, pos + copied);
800d15a53   Nick Piggin   implement simple ...
1135
  	set_page_dirty(page);
6746aff74   Wu Fengguang   HWPOISON: shmem: ...
1136
  	unlock_page(page);
800d15a53   Nick Piggin   implement simple ...
1137
  	page_cache_release(page);
800d15a53   Nick Piggin   implement simple ...
1138
  	return copied;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
1139
  }
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
1140
1141
  static void do_shmem_file_read(struct file *filp, loff_t *ppos, read_descriptor_t *desc, read_actor_t actor)
  {
d3ac7f892   Josef "Jeff" Sipek   [PATCH] mm: chang...
1142
  	struct inode *inode = filp->f_path.dentry->d_inode;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
1143
  	struct address_space *mapping = inode->i_mapping;
41ffe5d5c   Hugh Dickins   tmpfs: miscellane...
1144
1145
  	pgoff_t index;
  	unsigned long offset;
a0ee5ec52   Hugh Dickins   tmpfs: allocate o...
1146
1147
1148
1149
1150
1151
1152
1153
1154
  	enum sgp_type sgp = SGP_READ;
  
  	/*
  	 * Might this read be for a stacking filesystem?  Then when reading
  	 * holes of a sparse file, we actually need to allocate those pages,
  	 * and even mark them dirty, so it cannot exceed the max_blocks limit.
  	 */
  	if (segment_eq(get_fs(), KERNEL_DS))
  		sgp = SGP_DIRTY;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
1155
1156
1157
1158
1159
1160
  
  	index = *ppos >> PAGE_CACHE_SHIFT;
  	offset = *ppos & ~PAGE_CACHE_MASK;
  
  	for (;;) {
  		struct page *page = NULL;
41ffe5d5c   Hugh Dickins   tmpfs: miscellane...
1161
1162
  		pgoff_t end_index;
  		unsigned long nr, ret;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
1163
1164
1165
1166
1167
1168
1169
1170
1171
1172
  		loff_t i_size = i_size_read(inode);
  
  		end_index = i_size >> PAGE_CACHE_SHIFT;
  		if (index > end_index)
  			break;
  		if (index == end_index) {
  			nr = i_size & ~PAGE_CACHE_MASK;
  			if (nr <= offset)
  				break;
  		}
a0ee5ec52   Hugh Dickins   tmpfs: allocate o...
1173
  		desc->error = shmem_getpage(inode, index, &page, sgp, NULL);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
1174
1175
1176
1177
1178
  		if (desc->error) {
  			if (desc->error == -EINVAL)
  				desc->error = 0;
  			break;
  		}
d3602444e   Hugh Dickins   shmem_getpage ret...
1179
1180
  		if (page)
  			unlock_page(page);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
1181
1182
1183
  
  		/*
  		 * We must evaluate after, since reads (unlike writes)
1b1dcc1b5   Jes Sorensen   [PATCH] mutex sub...
1184
  		 * are called without i_mutex protection against truncate
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
1185
1186
1187
1188
1189
1190
1191
1192
1193
1194
1195
1196
1197
1198
1199
1200
1201
1202
1203
1204
1205
1206
1207
1208
1209
1210
1211
  		 */
  		nr = PAGE_CACHE_SIZE;
  		i_size = i_size_read(inode);
  		end_index = i_size >> PAGE_CACHE_SHIFT;
  		if (index == end_index) {
  			nr = i_size & ~PAGE_CACHE_MASK;
  			if (nr <= offset) {
  				if (page)
  					page_cache_release(page);
  				break;
  			}
  		}
  		nr -= offset;
  
  		if (page) {
  			/*
  			 * If users can be writing to this page using arbitrary
  			 * virtual addresses, take care about potential aliasing
  			 * before reading the page on the kernel side.
  			 */
  			if (mapping_writably_mapped(mapping))
  				flush_dcache_page(page);
  			/*
  			 * Mark the page accessed if we read the beginning.
  			 */
  			if (!offset)
  				mark_page_accessed(page);
b5810039a   Nick Piggin   [PATCH] core remo...
1212
  		} else {
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
1213
  			page = ZERO_PAGE(0);
b5810039a   Nick Piggin   [PATCH] core remo...
1214
1215
  			page_cache_get(page);
  		}
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
1216
1217
1218
1219
1220
1221
1222
1223
1224
1225
1226
1227
1228
1229
1230
1231
1232
1233
1234
1235
1236
1237
1238
1239
1240
1241
  
  		/*
  		 * Ok, we have the page, and it's up-to-date, so
  		 * now we can copy it to user space...
  		 *
  		 * The actor routine returns how many bytes were actually used..
  		 * NOTE! This may not be the same as how much of a user buffer
  		 * we filled up (we may be padding etc), so we can only update
  		 * "pos" here (the actor routine has to update the user buffer
  		 * pointers and the remaining count).
  		 */
  		ret = actor(desc, page, offset, nr);
  		offset += ret;
  		index += offset >> PAGE_CACHE_SHIFT;
  		offset &= ~PAGE_CACHE_MASK;
  
  		page_cache_release(page);
  		if (ret != nr || !desc->count)
  			break;
  
  		cond_resched();
  	}
  
  	*ppos = ((loff_t) index << PAGE_CACHE_SHIFT) + offset;
  	file_accessed(filp);
  }
bcd78e496   Hugh Dickins   tmpfs: support aio
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
1272
1273
  static ssize_t shmem_file_aio_read(struct kiocb *iocb,
  		const struct iovec *iov, unsigned long nr_segs, loff_t pos)
  {
  	struct file *filp = iocb->ki_filp;
  	ssize_t retval;
  	unsigned long seg;
  	size_t count;
  	loff_t *ppos = &iocb->ki_pos;
  
  	retval = generic_segment_checks(iov, &nr_segs, &count, VERIFY_WRITE);
  	if (retval)
  		return retval;
  
  	for (seg = 0; seg < nr_segs; seg++) {
  		read_descriptor_t desc;
  
  		desc.written = 0;
  		desc.arg.buf = iov[seg].iov_base;
  		desc.count = iov[seg].iov_len;
  		if (desc.count == 0)
  			continue;
  		desc.error = 0;
  		do_shmem_file_read(filp, ppos, &desc, file_read_actor);
  		retval += desc.written;
  		if (desc.error) {
  			retval = retval ?: desc.error;
  			break;
  		}
  		if (desc.count > 0)
  			break;
  	}
  	return retval;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
1274
  }
708e3508c   Hugh Dickins   tmpfs: clone shme...
1275
1276
1277
1278
1279
  static ssize_t shmem_file_splice_read(struct file *in, loff_t *ppos,
  				struct pipe_inode_info *pipe, size_t len,
  				unsigned int flags)
  {
  	struct address_space *mapping = in->f_mapping;
71f0e07a6   Hugh Dickins   tmpfs: refine shm...
1280
  	struct inode *inode = mapping->host;
708e3508c   Hugh Dickins   tmpfs: clone shme...
1281
1282
1283
1284
1285
1286
1287
1288
1289
1290
1291
1292
1293
1294
  	unsigned int loff, nr_pages, req_pages;
  	struct page *pages[PIPE_DEF_BUFFERS];
  	struct partial_page partial[PIPE_DEF_BUFFERS];
  	struct page *page;
  	pgoff_t index, end_index;
  	loff_t isize, left;
  	int error, page_nr;
  	struct splice_pipe_desc spd = {
  		.pages = pages,
  		.partial = partial,
  		.flags = flags,
  		.ops = &page_cache_pipe_buf_ops,
  		.spd_release = spd_release_page,
  	};
71f0e07a6   Hugh Dickins   tmpfs: refine shm...
1295
  	isize = i_size_read(inode);
708e3508c   Hugh Dickins   tmpfs: clone shme...
1296
1297
1298
1299
1300
1301
1302
1303
1304
1305
1306
1307
1308
1309
  	if (unlikely(*ppos >= isize))
  		return 0;
  
  	left = isize - *ppos;
  	if (unlikely(left < len))
  		len = left;
  
  	if (splice_grow_spd(pipe, &spd))
  		return -ENOMEM;
  
  	index = *ppos >> PAGE_CACHE_SHIFT;
  	loff = *ppos & ~PAGE_CACHE_MASK;
  	req_pages = (len + loff + PAGE_CACHE_SIZE - 1) >> PAGE_CACHE_SHIFT;
  	nr_pages = min(req_pages, pipe->buffers);
708e3508c   Hugh Dickins   tmpfs: clone shme...
1310
1311
1312
  	spd.nr_pages = find_get_pages_contig(mapping, index,
  						nr_pages, spd.pages);
  	index += spd.nr_pages;
708e3508c   Hugh Dickins   tmpfs: clone shme...
1313
  	error = 0;
708e3508c   Hugh Dickins   tmpfs: clone shme...
1314

71f0e07a6   Hugh Dickins   tmpfs: refine shm...
1315
  	while (spd.nr_pages < nr_pages) {
71f0e07a6   Hugh Dickins   tmpfs: refine shm...
1316
1317
1318
1319
  		error = shmem_getpage(inode, index, &page, SGP_CACHE, NULL);
  		if (error)
  			break;
  		unlock_page(page);
708e3508c   Hugh Dickins   tmpfs: clone shme...
1320
1321
1322
  		spd.pages[spd.nr_pages++] = page;
  		index++;
  	}
708e3508c   Hugh Dickins   tmpfs: clone shme...
1323
1324
1325
  	index = *ppos >> PAGE_CACHE_SHIFT;
  	nr_pages = spd.nr_pages;
  	spd.nr_pages = 0;
71f0e07a6   Hugh Dickins   tmpfs: refine shm...
1326

708e3508c   Hugh Dickins   tmpfs: clone shme...
1327
1328
1329
1330
1331
  	for (page_nr = 0; page_nr < nr_pages; page_nr++) {
  		unsigned int this_len;
  
  		if (!len)
  			break;
708e3508c   Hugh Dickins   tmpfs: clone shme...
1332
1333
  		this_len = min_t(unsigned long, len, PAGE_CACHE_SIZE - loff);
  		page = spd.pages[page_nr];
71f0e07a6   Hugh Dickins   tmpfs: refine shm...
1334
  		if (!PageUptodate(page) || page->mapping != mapping) {
71f0e07a6   Hugh Dickins   tmpfs: refine shm...
1335
1336
1337
  			error = shmem_getpage(inode, index, &page,
  							SGP_CACHE, NULL);
  			if (error)
708e3508c   Hugh Dickins   tmpfs: clone shme...
1338
  				break;
71f0e07a6   Hugh Dickins   tmpfs: refine shm...
1339
1340
1341
  			unlock_page(page);
  			page_cache_release(spd.pages[page_nr]);
  			spd.pages[page_nr] = page;
708e3508c   Hugh Dickins   tmpfs: clone shme...
1342
  		}
71f0e07a6   Hugh Dickins   tmpfs: refine shm...
1343
1344
  
  		isize = i_size_read(inode);
708e3508c   Hugh Dickins   tmpfs: clone shme...
1345
1346
1347
  		end_index = (isize - 1) >> PAGE_CACHE_SHIFT;
  		if (unlikely(!isize || index > end_index))
  			break;
708e3508c   Hugh Dickins   tmpfs: clone shme...
1348
1349
  		if (end_index == index) {
  			unsigned int plen;
708e3508c   Hugh Dickins   tmpfs: clone shme...
1350
1351
1352
  			plen = ((isize - 1) & ~PAGE_CACHE_MASK) + 1;
  			if (plen <= loff)
  				break;
708e3508c   Hugh Dickins   tmpfs: clone shme...
1353
1354
1355
1356
1357
1358
1359
1360
1361
1362
1363
  			this_len = min(this_len, plen - loff);
  			len = this_len;
  		}
  
  		spd.partial[page_nr].offset = loff;
  		spd.partial[page_nr].len = this_len;
  		len -= this_len;
  		loff = 0;
  		spd.nr_pages++;
  		index++;
  	}
708e3508c   Hugh Dickins   tmpfs: clone shme...
1364
1365
  	while (page_nr < nr_pages)
  		page_cache_release(spd.pages[page_nr++]);
708e3508c   Hugh Dickins   tmpfs: clone shme...
1366
1367
1368
1369
1370
1371
1372
1373
1374
1375
1376
1377
  
  	if (spd.nr_pages)
  		error = splice_to_pipe(pipe, &spd);
  
  	splice_shrink_spd(pipe, &spd);
  
  	if (error > 0) {
  		*ppos += error;
  		file_accessed(in);
  	}
  	return error;
  }
726c33422   David Howells   [PATCH] VFS: Perm...
1378
  static int shmem_statfs(struct dentry *dentry, struct kstatfs *buf)
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
1379
  {
726c33422   David Howells   [PATCH] VFS: Perm...
1380
  	struct shmem_sb_info *sbinfo = SHMEM_SB(dentry->d_sb);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
1381
1382
1383
1384
  
  	buf->f_type = TMPFS_MAGIC;
  	buf->f_bsize = PAGE_CACHE_SIZE;
  	buf->f_namelen = NAME_MAX;
0edd73b33   Hugh Dickins   [PATCH] shmem: re...
1385
  	if (sbinfo->max_blocks) {
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
1386
  		buf->f_blocks = sbinfo->max_blocks;
41ffe5d5c   Hugh Dickins   tmpfs: miscellane...
1387
1388
1389
  		buf->f_bavail =
  		buf->f_bfree  = sbinfo->max_blocks -
  				percpu_counter_sum(&sbinfo->used_blocks);
0edd73b33   Hugh Dickins   [PATCH] shmem: re...
1390
1391
  	}
  	if (sbinfo->max_inodes) {
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
1392
1393
  		buf->f_files = sbinfo->max_inodes;
  		buf->f_ffree = sbinfo->free_inodes;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
1394
1395
1396
1397
1398
1399
1400
1401
1402
1403
1404
  	}
  	/* else leave those fields 0 like simple_statfs */
  	return 0;
  }
  
  /*
   * File creation. Allocate an inode, and we're done..
   */
  static int
  shmem_mknod(struct inode *dir, struct dentry *dentry, int mode, dev_t dev)
  {
0b0a0806b   Hugh Dickins   shmem: fix shared...
1405
  	struct inode *inode;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
1406
  	int error = -ENOSPC;
454abafe9   Dmitry Monakhov   ramfs: replace in...
1407
  	inode = shmem_get_inode(dir->i_sb, dir, mode, dev, VM_NORESERVE);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
1408
  	if (inode) {
2a7dba391   Eric Paris   fs/vfs/security: ...
1409
  		error = security_inode_init_security(inode, dir,
9d8f13ba3   Mimi Zohar   security: new sec...
1410
  						     &dentry->d_name,
2a7dba391   Eric Paris   fs/vfs/security: ...
1411
  						     NULL, NULL);
570bc1c2e   Stephen Smalley   [PATCH] tmpfs: En...
1412
1413
1414
1415
1416
  		if (error) {
  			if (error != -EOPNOTSUPP) {
  				iput(inode);
  				return error;
  			}
39f0247d3   Andreas Gruenbacher   [PATCH] Access Co...
1417
  		}
1c7c474c3   Christoph Hellwig   make generic_acl ...
1418
1419
  #ifdef CONFIG_TMPFS_POSIX_ACL
  		error = generic_acl_init(inode, dir);
39f0247d3   Andreas Gruenbacher   [PATCH] Access Co...
1420
1421
1422
  		if (error) {
  			iput(inode);
  			return error;
570bc1c2e   Stephen Smalley   [PATCH] tmpfs: En...
1423
  		}
718deb6b6   Al Viro   Fix breakage in s...
1424
1425
  #else
  		error = 0;
1c7c474c3   Christoph Hellwig   make generic_acl ...
1426
  #endif
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
1427
1428
1429
1430
  		dir->i_size += BOGO_DIRENT_SIZE;
  		dir->i_ctime = dir->i_mtime = CURRENT_TIME;
  		d_instantiate(dentry, inode);
  		dget(dentry); /* Extra count - pin the dentry in core */
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
1431
1432
1433
1434
1435
1436
1437
1438
1439
1440
  	}
  	return error;
  }
  
  static int shmem_mkdir(struct inode *dir, struct dentry *dentry, int mode)
  {
  	int error;
  
  	if ((error = shmem_mknod(dir, dentry, mode | S_IFDIR, 0)))
  		return error;
d8c76e6f4   Dave Hansen   [PATCH] r/o bind ...
1441
  	inc_nlink(dir);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
1442
1443
1444
1445
1446
1447
1448
1449
1450
1451
1452
1453
1454
1455
1456
  	return 0;
  }
  
  static int shmem_create(struct inode *dir, struct dentry *dentry, int mode,
  		struct nameidata *nd)
  {
  	return shmem_mknod(dir, dentry, mode | S_IFREG, 0);
  }
  
  /*
   * Link a file..
   */
  static int shmem_link(struct dentry *old_dentry, struct inode *dir, struct dentry *dentry)
  {
  	struct inode *inode = old_dentry->d_inode;
5b04c6890   Pavel Emelyanov   shmem: factor out...
1457
  	int ret;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
1458
1459
1460
1461
1462
1463
  
  	/*
  	 * No ordinary (disk based) filesystem counts links as inodes;
  	 * but each new link needs a new dentry, pinning lowmem, and
  	 * tmpfs dentries cannot be pruned until they are unlinked.
  	 */
5b04c6890   Pavel Emelyanov   shmem: factor out...
1464
1465
1466
  	ret = shmem_reserve_inode(inode->i_sb);
  	if (ret)
  		goto out;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
1467
1468
1469
  
  	dir->i_size += BOGO_DIRENT_SIZE;
  	inode->i_ctime = dir->i_ctime = dir->i_mtime = CURRENT_TIME;
d8c76e6f4   Dave Hansen   [PATCH] r/o bind ...
1470
  	inc_nlink(inode);
7de9c6ee3   Al Viro   new helper: ihold()
1471
  	ihold(inode);	/* New dentry reference */
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
1472
1473
  	dget(dentry);		/* Extra pinning count for the created dentry */
  	d_instantiate(dentry, inode);
5b04c6890   Pavel Emelyanov   shmem: factor out...
1474
1475
  out:
  	return ret;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
1476
1477
1478
1479
1480
  }
  
  static int shmem_unlink(struct inode *dir, struct dentry *dentry)
  {
  	struct inode *inode = dentry->d_inode;
5b04c6890   Pavel Emelyanov   shmem: factor out...
1481
1482
  	if (inode->i_nlink > 1 && !S_ISDIR(inode->i_mode))
  		shmem_free_inode(inode->i_sb);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
1483
1484
1485
  
  	dir->i_size -= BOGO_DIRENT_SIZE;
  	inode->i_ctime = dir->i_ctime = dir->i_mtime = CURRENT_TIME;
9a53c3a78   Dave Hansen   [PATCH] r/o bind ...
1486
  	drop_nlink(inode);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
1487
1488
1489
1490
1491
1492
1493
1494
  	dput(dentry);	/* Undo the count from "create" - this does all the work */
  	return 0;
  }
  
  static int shmem_rmdir(struct inode *dir, struct dentry *dentry)
  {
  	if (!simple_empty(dentry))
  		return -ENOTEMPTY;
9a53c3a78   Dave Hansen   [PATCH] r/o bind ...
1495
1496
  	drop_nlink(dentry->d_inode);
  	drop_nlink(dir);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
1497
1498
1499
1500
1501
1502
1503
1504
1505
1506
1507
1508
1509
1510
1511
1512
1513
1514
1515
1516
  	return shmem_unlink(dir, dentry);
  }
  
  /*
   * The VFS layer already does all the dentry stuff for rename,
   * we just have to decrement the usage count for the target if
   * it exists so that the VFS layer correctly free's it when it
   * gets overwritten.
   */
  static int shmem_rename(struct inode *old_dir, struct dentry *old_dentry, struct inode *new_dir, struct dentry *new_dentry)
  {
  	struct inode *inode = old_dentry->d_inode;
  	int they_are_dirs = S_ISDIR(inode->i_mode);
  
  	if (!simple_empty(new_dentry))
  		return -ENOTEMPTY;
  
  	if (new_dentry->d_inode) {
  		(void) shmem_unlink(new_dir, new_dentry);
  		if (they_are_dirs)
9a53c3a78   Dave Hansen   [PATCH] r/o bind ...
1517
  			drop_nlink(old_dir);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
1518
  	} else if (they_are_dirs) {
9a53c3a78   Dave Hansen   [PATCH] r/o bind ...
1519
  		drop_nlink(old_dir);
d8c76e6f4   Dave Hansen   [PATCH] r/o bind ...
1520
  		inc_nlink(new_dir);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
1521
1522
1523
1524
1525
1526
1527
1528
1529
1530
1531
1532
1533
1534
1535
  	}
  
  	old_dir->i_size -= BOGO_DIRENT_SIZE;
  	new_dir->i_size += BOGO_DIRENT_SIZE;
  	old_dir->i_ctime = old_dir->i_mtime =
  	new_dir->i_ctime = new_dir->i_mtime =
  	inode->i_ctime = CURRENT_TIME;
  	return 0;
  }
  
  static int shmem_symlink(struct inode *dir, struct dentry *dentry, const char *symname)
  {
  	int error;
  	int len;
  	struct inode *inode;
9276aad6c   Hugh Dickins   tmpfs: remove_shm...
1536
  	struct page *page;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
1537
1538
1539
1540
1541
1542
  	char *kaddr;
  	struct shmem_inode_info *info;
  
  	len = strlen(symname) + 1;
  	if (len > PAGE_CACHE_SIZE)
  		return -ENAMETOOLONG;
454abafe9   Dmitry Monakhov   ramfs: replace in...
1543
  	inode = shmem_get_inode(dir->i_sb, dir, S_IFLNK|S_IRWXUGO, 0, VM_NORESERVE);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
1544
1545
  	if (!inode)
  		return -ENOSPC;
9d8f13ba3   Mimi Zohar   security: new sec...
1546
  	error = security_inode_init_security(inode, dir, &dentry->d_name,
2a7dba391   Eric Paris   fs/vfs/security: ...
1547
  					     NULL, NULL);
570bc1c2e   Stephen Smalley   [PATCH] tmpfs: En...
1548
1549
1550
1551
1552
1553
1554
  	if (error) {
  		if (error != -EOPNOTSUPP) {
  			iput(inode);
  			return error;
  		}
  		error = 0;
  	}
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
1555
1556
  	info = SHMEM_I(inode);
  	inode->i_size = len-1;
69f07ec93   Hugh Dickins   tmpfs: use kmemdu...
1557
1558
1559
1560
1561
1562
1563
  	if (len <= SHORT_SYMLINK_LEN) {
  		info->symlink = kmemdup(symname, len, GFP_KERNEL);
  		if (!info->symlink) {
  			iput(inode);
  			return -ENOMEM;
  		}
  		inode->i_op = &shmem_short_symlink_operations;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
1564
1565
1566
1567
1568
1569
  	} else {
  		error = shmem_getpage(inode, 0, &page, SGP_WRITE, NULL);
  		if (error) {
  			iput(inode);
  			return error;
  		}
14fcc23fd   Hugh Dickins   tmpfs: fix kernel...
1570
  		inode->i_mapping->a_ops = &shmem_aops;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
1571
1572
1573
1574
1575
  		inode->i_op = &shmem_symlink_inode_operations;
  		kaddr = kmap_atomic(page, KM_USER0);
  		memcpy(kaddr, symname, len);
  		kunmap_atomic(kaddr, KM_USER0);
  		set_page_dirty(page);
6746aff74   Wu Fengguang   HWPOISON: shmem: ...
1576
  		unlock_page(page);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
1577
1578
  		page_cache_release(page);
  	}
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
1579
1580
1581
1582
1583
1584
  	dir->i_size += BOGO_DIRENT_SIZE;
  	dir->i_ctime = dir->i_mtime = CURRENT_TIME;
  	d_instantiate(dentry, inode);
  	dget(dentry);
  	return 0;
  }
69f07ec93   Hugh Dickins   tmpfs: use kmemdu...
1585
  static void *shmem_follow_short_symlink(struct dentry *dentry, struct nameidata *nd)
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
1586
  {
69f07ec93   Hugh Dickins   tmpfs: use kmemdu...
1587
  	nd_set_link(nd, SHMEM_I(dentry->d_inode)->symlink);
cc314eef0   Linus Torvalds   Fix nasty ncpfs s...
1588
  	return NULL;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
1589
  }
cc314eef0   Linus Torvalds   Fix nasty ncpfs s...
1590
  static void *shmem_follow_link(struct dentry *dentry, struct nameidata *nd)
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
1591
1592
  {
  	struct page *page = NULL;
41ffe5d5c   Hugh Dickins   tmpfs: miscellane...
1593
1594
  	int error = shmem_getpage(dentry->d_inode, 0, &page, SGP_READ, NULL);
  	nd_set_link(nd, error ? ERR_PTR(error) : kmap(page));
d3602444e   Hugh Dickins   shmem_getpage ret...
1595
1596
  	if (page)
  		unlock_page(page);
cc314eef0   Linus Torvalds   Fix nasty ncpfs s...
1597
  	return page;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
1598
  }
cc314eef0   Linus Torvalds   Fix nasty ncpfs s...
1599
  static void shmem_put_link(struct dentry *dentry, struct nameidata *nd, void *cookie)
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
1600
1601
  {
  	if (!IS_ERR(nd_get_link(nd))) {
cc314eef0   Linus Torvalds   Fix nasty ncpfs s...
1602
  		struct page *page = cookie;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
1603
1604
1605
  		kunmap(page);
  		mark_page_accessed(page);
  		page_cache_release(page);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
1606
1607
  	}
  }
b09e0fa4b   Eric Paris   tmpfs: implement ...
1608
  #ifdef CONFIG_TMPFS_XATTR
467118102   Randy Dunlap   mm/shmem and tiny...
1609
  /*
b09e0fa4b   Eric Paris   tmpfs: implement ...
1610
1611
   * Superblocks without xattr inode operations may get some security.* xattr
   * support from the LSM "for free". As soon as we have any other xattrs
39f0247d3   Andreas Gruenbacher   [PATCH] Access Co...
1612
1613
1614
   * like ACLs, we also need to implement the security.* handlers at
   * filesystem level, though.
   */
b09e0fa4b   Eric Paris   tmpfs: implement ...
1615
1616
  static int shmem_xattr_get(struct dentry *dentry, const char *name,
  			   void *buffer, size_t size)
39f0247d3   Andreas Gruenbacher   [PATCH] Access Co...
1617
  {
b09e0fa4b   Eric Paris   tmpfs: implement ...
1618
1619
1620
  	struct shmem_inode_info *info;
  	struct shmem_xattr *xattr;
  	int ret = -ENODATA;
39f0247d3   Andreas Gruenbacher   [PATCH] Access Co...
1621

b09e0fa4b   Eric Paris   tmpfs: implement ...
1622
1623
1624
1625
1626
1627
1628
1629
1630
1631
1632
1633
1634
1635
1636
1637
1638
1639
  	info = SHMEM_I(dentry->d_inode);
  
  	spin_lock(&info->lock);
  	list_for_each_entry(xattr, &info->xattr_list, list) {
  		if (strcmp(name, xattr->name))
  			continue;
  
  		ret = xattr->size;
  		if (buffer) {
  			if (size < xattr->size)
  				ret = -ERANGE;
  			else
  				memcpy(buffer, xattr->value, xattr->size);
  		}
  		break;
  	}
  	spin_unlock(&info->lock);
  	return ret;
39f0247d3   Andreas Gruenbacher   [PATCH] Access Co...
1640
  }
b09e0fa4b   Eric Paris   tmpfs: implement ...
1641
1642
  static int shmem_xattr_set(struct dentry *dentry, const char *name,
  			   const void *value, size_t size, int flags)
39f0247d3   Andreas Gruenbacher   [PATCH] Access Co...
1643
  {
b09e0fa4b   Eric Paris   tmpfs: implement ...
1644
1645
1646
1647
1648
1649
1650
1651
1652
1653
1654
1655
1656
1657
1658
1659
1660
1661
1662
1663
1664
1665
1666
1667
1668
1669
1670
1671
1672
1673
1674
1675
1676
1677
1678
1679
1680
1681
1682
1683
1684
1685
1686
1687
1688
1689
1690
1691
1692
1693
1694
1695
1696
1697
1698
  	struct inode *inode = dentry->d_inode;
  	struct shmem_inode_info *info = SHMEM_I(inode);
  	struct shmem_xattr *xattr;
  	struct shmem_xattr *new_xattr = NULL;
  	size_t len;
  	int err = 0;
  
  	/* value == NULL means remove */
  	if (value) {
  		/* wrap around? */
  		len = sizeof(*new_xattr) + size;
  		if (len <= sizeof(*new_xattr))
  			return -ENOMEM;
  
  		new_xattr = kmalloc(len, GFP_KERNEL);
  		if (!new_xattr)
  			return -ENOMEM;
  
  		new_xattr->name = kstrdup(name, GFP_KERNEL);
  		if (!new_xattr->name) {
  			kfree(new_xattr);
  			return -ENOMEM;
  		}
  
  		new_xattr->size = size;
  		memcpy(new_xattr->value, value, size);
  	}
  
  	spin_lock(&info->lock);
  	list_for_each_entry(xattr, &info->xattr_list, list) {
  		if (!strcmp(name, xattr->name)) {
  			if (flags & XATTR_CREATE) {
  				xattr = new_xattr;
  				err = -EEXIST;
  			} else if (new_xattr) {
  				list_replace(&xattr->list, &new_xattr->list);
  			} else {
  				list_del(&xattr->list);
  			}
  			goto out;
  		}
  	}
  	if (flags & XATTR_REPLACE) {
  		xattr = new_xattr;
  		err = -ENODATA;
  	} else {
  		list_add(&new_xattr->list, &info->xattr_list);
  		xattr = NULL;
  	}
  out:
  	spin_unlock(&info->lock);
  	if (xattr)
  		kfree(xattr->name);
  	kfree(xattr);
  	return err;
39f0247d3   Andreas Gruenbacher   [PATCH] Access Co...
1699
  }
bb4354538   Stephen Hemminger   fs: xattr_handler...
1700
  static const struct xattr_handler *shmem_xattr_handlers[] = {
b09e0fa4b   Eric Paris   tmpfs: implement ...
1701
  #ifdef CONFIG_TMPFS_POSIX_ACL
1c7c474c3   Christoph Hellwig   make generic_acl ...
1702
1703
  	&generic_acl_access_handler,
  	&generic_acl_default_handler,
b09e0fa4b   Eric Paris   tmpfs: implement ...
1704
  #endif
39f0247d3   Andreas Gruenbacher   [PATCH] Access Co...
1705
1706
  	NULL
  };
b09e0fa4b   Eric Paris   tmpfs: implement ...
1707
1708
1709
1710
1711
1712
1713
1714
1715
1716
1717
1718
1719
1720
1721
1722
1723
1724
1725
1726
1727
1728
1729
1730
1731
1732
1733
1734
1735
1736
1737
1738
1739
1740
1741
1742
1743
1744
1745
1746
1747
1748
1749
1750
1751
1752
1753
1754
1755
1756
1757
1758
1759
1760
1761
1762
1763
1764
1765
1766
1767
1768
1769
1770
1771
1772
1773
1774
1775
1776
1777
1778
1779
1780
1781
1782
1783
1784
1785
1786
1787
1788
1789
1790
1791
1792
1793
1794
1795
1796
1797
1798
1799
1800
1801
1802
1803
1804
1805
1806
1807
1808
1809
1810
1811
1812
1813
1814
1815
1816
1817
1818
1819
1820
1821
1822
1823
1824
1825
1826
1827
  
  static int shmem_xattr_validate(const char *name)
  {
  	struct { const char *prefix; size_t len; } arr[] = {
  		{ XATTR_SECURITY_PREFIX, XATTR_SECURITY_PREFIX_LEN },
  		{ XATTR_TRUSTED_PREFIX, XATTR_TRUSTED_PREFIX_LEN }
  	};
  	int i;
  
  	for (i = 0; i < ARRAY_SIZE(arr); i++) {
  		size_t preflen = arr[i].len;
  		if (strncmp(name, arr[i].prefix, preflen) == 0) {
  			if (!name[preflen])
  				return -EINVAL;
  			return 0;
  		}
  	}
  	return -EOPNOTSUPP;
  }
  
  static ssize_t shmem_getxattr(struct dentry *dentry, const char *name,
  			      void *buffer, size_t size)
  {
  	int err;
  
  	/*
  	 * If this is a request for a synthetic attribute in the system.*
  	 * namespace use the generic infrastructure to resolve a handler
  	 * for it via sb->s_xattr.
  	 */
  	if (!strncmp(name, XATTR_SYSTEM_PREFIX, XATTR_SYSTEM_PREFIX_LEN))
  		return generic_getxattr(dentry, name, buffer, size);
  
  	err = shmem_xattr_validate(name);
  	if (err)
  		return err;
  
  	return shmem_xattr_get(dentry, name, buffer, size);
  }
  
  static int shmem_setxattr(struct dentry *dentry, const char *name,
  			  const void *value, size_t size, int flags)
  {
  	int err;
  
  	/*
  	 * If this is a request for a synthetic attribute in the system.*
  	 * namespace use the generic infrastructure to resolve a handler
  	 * for it via sb->s_xattr.
  	 */
  	if (!strncmp(name, XATTR_SYSTEM_PREFIX, XATTR_SYSTEM_PREFIX_LEN))
  		return generic_setxattr(dentry, name, value, size, flags);
  
  	err = shmem_xattr_validate(name);
  	if (err)
  		return err;
  
  	if (size == 0)
  		value = "";  /* empty EA, do not remove */
  
  	return shmem_xattr_set(dentry, name, value, size, flags);
  
  }
  
  static int shmem_removexattr(struct dentry *dentry, const char *name)
  {
  	int err;
  
  	/*
  	 * If this is a request for a synthetic attribute in the system.*
  	 * namespace use the generic infrastructure to resolve a handler
  	 * for it via sb->s_xattr.
  	 */
  	if (!strncmp(name, XATTR_SYSTEM_PREFIX, XATTR_SYSTEM_PREFIX_LEN))
  		return generic_removexattr(dentry, name);
  
  	err = shmem_xattr_validate(name);
  	if (err)
  		return err;
  
  	return shmem_xattr_set(dentry, name, NULL, 0, XATTR_REPLACE);
  }
  
  static bool xattr_is_trusted(const char *name)
  {
  	return !strncmp(name, XATTR_TRUSTED_PREFIX, XATTR_TRUSTED_PREFIX_LEN);
  }
  
  static ssize_t shmem_listxattr(struct dentry *dentry, char *buffer, size_t size)
  {
  	bool trusted = capable(CAP_SYS_ADMIN);
  	struct shmem_xattr *xattr;
  	struct shmem_inode_info *info;
  	size_t used = 0;
  
  	info = SHMEM_I(dentry->d_inode);
  
  	spin_lock(&info->lock);
  	list_for_each_entry(xattr, &info->xattr_list, list) {
  		size_t len;
  
  		/* skip "trusted." attributes for unprivileged callers */
  		if (!trusted && xattr_is_trusted(xattr->name))
  			continue;
  
  		len = strlen(xattr->name) + 1;
  		used += len;
  		if (buffer) {
  			if (size < used) {
  				used = -ERANGE;
  				break;
  			}
  			memcpy(buffer, xattr->name, len);
  			buffer += len;
  		}
  	}
  	spin_unlock(&info->lock);
  
  	return used;
  }
  #endif /* CONFIG_TMPFS_XATTR */
69f07ec93   Hugh Dickins   tmpfs: use kmemdu...
1828
  static const struct inode_operations shmem_short_symlink_operations = {
b09e0fa4b   Eric Paris   tmpfs: implement ...
1829
  	.readlink	= generic_readlink,
69f07ec93   Hugh Dickins   tmpfs: use kmemdu...
1830
  	.follow_link	= shmem_follow_short_symlink,
b09e0fa4b   Eric Paris   tmpfs: implement ...
1831
1832
1833
1834
1835
1836
1837
1838
1839
1840
1841
1842
1843
1844
1845
1846
1847
  #ifdef CONFIG_TMPFS_XATTR
  	.setxattr	= shmem_setxattr,
  	.getxattr	= shmem_getxattr,
  	.listxattr	= shmem_listxattr,
  	.removexattr	= shmem_removexattr,
  #endif
  };
  
  static const struct inode_operations shmem_symlink_inode_operations = {
  	.readlink	= generic_readlink,
  	.follow_link	= shmem_follow_link,
  	.put_link	= shmem_put_link,
  #ifdef CONFIG_TMPFS_XATTR
  	.setxattr	= shmem_setxattr,
  	.getxattr	= shmem_getxattr,
  	.listxattr	= shmem_listxattr,
  	.removexattr	= shmem_removexattr,
39f0247d3   Andreas Gruenbacher   [PATCH] Access Co...
1848
  #endif
b09e0fa4b   Eric Paris   tmpfs: implement ...
1849
  };
39f0247d3   Andreas Gruenbacher   [PATCH] Access Co...
1850

91828a405   David M. Grimes   [PATCH] knfsd: ad...
1851
1852
1853
1854
1855
1856
1857
1858
1859
1860
1861
1862
  static struct dentry *shmem_get_parent(struct dentry *child)
  {
  	return ERR_PTR(-ESTALE);
  }
  
  static int shmem_match(struct inode *ino, void *vfh)
  {
  	__u32 *fh = vfh;
  	__u64 inum = fh[2];
  	inum = (inum << 32) | fh[1];
  	return ino->i_ino == inum && fh[0] == ino->i_generation;
  }
480b116c9   Christoph Hellwig   shmem: new export...
1863
1864
  static struct dentry *shmem_fh_to_dentry(struct super_block *sb,
  		struct fid *fid, int fh_len, int fh_type)
91828a405   David M. Grimes   [PATCH] knfsd: ad...
1865
  {
91828a405   David M. Grimes   [PATCH] knfsd: ad...
1866
  	struct inode *inode;
480b116c9   Christoph Hellwig   shmem: new export...
1867
1868
1869
1870
1871
1872
  	struct dentry *dentry = NULL;
  	u64 inum = fid->raw[2];
  	inum = (inum << 32) | fid->raw[1];
  
  	if (fh_len < 3)
  		return NULL;
91828a405   David M. Grimes   [PATCH] knfsd: ad...
1873

480b116c9   Christoph Hellwig   shmem: new export...
1874
1875
  	inode = ilookup5(sb, (unsigned long)(inum + fid->raw[0]),
  			shmem_match, fid->raw);
91828a405   David M. Grimes   [PATCH] knfsd: ad...
1876
  	if (inode) {
480b116c9   Christoph Hellwig   shmem: new export...
1877
  		dentry = d_find_alias(inode);
91828a405   David M. Grimes   [PATCH] knfsd: ad...
1878
1879
  		iput(inode);
  	}
480b116c9   Christoph Hellwig   shmem: new export...
1880
  	return dentry;
91828a405   David M. Grimes   [PATCH] knfsd: ad...
1881
1882
1883
1884
1885
1886
  }
  
  static int shmem_encode_fh(struct dentry *dentry, __u32 *fh, int *len,
  				int connectable)
  {
  	struct inode *inode = dentry->d_inode;
5fe0c2378   Aneesh Kumar K.V   exportfs: Return ...
1887
1888
  	if (*len < 3) {
  		*len = 3;
91828a405   David M. Grimes   [PATCH] knfsd: ad...
1889
  		return 255;
5fe0c2378   Aneesh Kumar K.V   exportfs: Return ...
1890
  	}
91828a405   David M. Grimes   [PATCH] knfsd: ad...
1891

1d3382cbf   Al Viro   new helper: inode...
1892
  	if (inode_unhashed(inode)) {
91828a405   David M. Grimes   [PATCH] knfsd: ad...
1893
1894
1895
1896
1897
1898
1899
  		/* Unfortunately insert_inode_hash is not idempotent,
  		 * so as we hash inodes here rather than at creation
  		 * time, we need a lock to ensure we only try
  		 * to do it once
  		 */
  		static DEFINE_SPINLOCK(lock);
  		spin_lock(&lock);
1d3382cbf   Al Viro   new helper: inode...
1900
  		if (inode_unhashed(inode))
91828a405   David M. Grimes   [PATCH] knfsd: ad...
1901
1902
1903
1904
1905
1906
1907
1908
1909
1910
1911
1912
  			__insert_inode_hash(inode,
  					    inode->i_ino + inode->i_generation);
  		spin_unlock(&lock);
  	}
  
  	fh[0] = inode->i_generation;
  	fh[1] = inode->i_ino;
  	fh[2] = ((__u64)inode->i_ino) >> 32;
  
  	*len = 3;
  	return 1;
  }
396551644   Christoph Hellwig   exportfs: make st...
1913
  static const struct export_operations shmem_export_ops = {
91828a405   David M. Grimes   [PATCH] knfsd: ad...
1914
  	.get_parent     = shmem_get_parent,
91828a405   David M. Grimes   [PATCH] knfsd: ad...
1915
  	.encode_fh      = shmem_encode_fh,
480b116c9   Christoph Hellwig   shmem: new export...
1916
  	.fh_to_dentry	= shmem_fh_to_dentry,
91828a405   David M. Grimes   [PATCH] knfsd: ad...
1917
  };
680d794ba   akpm@linux-foundation.org   mount options: fi...
1918
1919
  static int shmem_parse_options(char *options, struct shmem_sb_info *sbinfo,
  			       bool remount)
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
1920
1921
  {
  	char *this_char, *value, *rest;
b00dc3ad7   Hugh Dickins   [PATCH] tmpfs: fi...
1922
1923
1924
1925
1926
1927
1928
1929
1930
1931
1932
1933
1934
1935
1936
1937
1938
  	while (options != NULL) {
  		this_char = options;
  		for (;;) {
  			/*
  			 * NUL-terminate this option: unfortunately,
  			 * mount options form a comma-separated list,
  			 * but mpol's nodelist may also contain commas.
  			 */
  			options = strchr(options, ',');
  			if (options == NULL)
  				break;
  			options++;
  			if (!isdigit(*options)) {
  				options[-1] = '\0';
  				break;
  			}
  		}
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
1939
1940
1941
1942
1943
1944
1945
1946
1947
1948
1949
1950
1951
1952
1953
1954
1955
1956
1957
1958
1959
1960
1961
  		if (!*this_char)
  			continue;
  		if ((value = strchr(this_char,'=')) != NULL) {
  			*value++ = 0;
  		} else {
  			printk(KERN_ERR
  			    "tmpfs: No value for mount option '%s'
  ",
  			    this_char);
  			return 1;
  		}
  
  		if (!strcmp(this_char,"size")) {
  			unsigned long long size;
  			size = memparse(value,&rest);
  			if (*rest == '%') {
  				size <<= PAGE_SHIFT;
  				size *= totalram_pages;
  				do_div(size, 100);
  				rest++;
  			}
  			if (*rest)
  				goto bad_val;
680d794ba   akpm@linux-foundation.org   mount options: fi...
1962
1963
  			sbinfo->max_blocks =
  				DIV_ROUND_UP(size, PAGE_CACHE_SIZE);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
1964
  		} else if (!strcmp(this_char,"nr_blocks")) {
680d794ba   akpm@linux-foundation.org   mount options: fi...
1965
  			sbinfo->max_blocks = memparse(value, &rest);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
1966
1967
1968
  			if (*rest)
  				goto bad_val;
  		} else if (!strcmp(this_char,"nr_inodes")) {
680d794ba   akpm@linux-foundation.org   mount options: fi...
1969
  			sbinfo->max_inodes = memparse(value, &rest);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
1970
1971
1972
  			if (*rest)
  				goto bad_val;
  		} else if (!strcmp(this_char,"mode")) {
680d794ba   akpm@linux-foundation.org   mount options: fi...
1973
  			if (remount)
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
1974
  				continue;
680d794ba   akpm@linux-foundation.org   mount options: fi...
1975
  			sbinfo->mode = simple_strtoul(value, &rest, 8) & 07777;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
1976
1977
1978
  			if (*rest)
  				goto bad_val;
  		} else if (!strcmp(this_char,"uid")) {
680d794ba   akpm@linux-foundation.org   mount options: fi...
1979
  			if (remount)
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
1980
  				continue;
680d794ba   akpm@linux-foundation.org   mount options: fi...
1981
  			sbinfo->uid = simple_strtoul(value, &rest, 0);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
1982
1983
1984
  			if (*rest)
  				goto bad_val;
  		} else if (!strcmp(this_char,"gid")) {
680d794ba   akpm@linux-foundation.org   mount options: fi...
1985
  			if (remount)
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
1986
  				continue;
680d794ba   akpm@linux-foundation.org   mount options: fi...
1987
  			sbinfo->gid = simple_strtoul(value, &rest, 0);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
1988
1989
  			if (*rest)
  				goto bad_val;
7339ff830   Robin Holt   [PATCH] Add tmpfs...
1990
  		} else if (!strcmp(this_char,"mpol")) {
71fe804b6   Lee Schermerhorn   mempolicy: use st...
1991
  			if (mpol_parse_str(value, &sbinfo->mpol, 1))
7339ff830   Robin Holt   [PATCH] Add tmpfs...
1992
  				goto bad_val;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
1993
1994
1995
1996
1997
1998
1999
2000
2001
2002
2003
2004
2005
2006
2007
2008
2009
2010
2011
2012
  		} else {
  			printk(KERN_ERR "tmpfs: Bad mount option %s
  ",
  			       this_char);
  			return 1;
  		}
  	}
  	return 0;
  
  bad_val:
  	printk(KERN_ERR "tmpfs: Bad value '%s' for mount option '%s'
  ",
  	       value, this_char);
  	return 1;
  
  }
  
  static int shmem_remount_fs(struct super_block *sb, int *flags, char *data)
  {
  	struct shmem_sb_info *sbinfo = SHMEM_SB(sb);
680d794ba   akpm@linux-foundation.org   mount options: fi...
2013
  	struct shmem_sb_info config = *sbinfo;
0edd73b33   Hugh Dickins   [PATCH] shmem: re...
2014
2015
  	unsigned long inodes;
  	int error = -EINVAL;
680d794ba   akpm@linux-foundation.org   mount options: fi...
2016
  	if (shmem_parse_options(data, &config, true))
0edd73b33   Hugh Dickins   [PATCH] shmem: re...
2017
  		return error;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
2018

0edd73b33   Hugh Dickins   [PATCH] shmem: re...
2019
  	spin_lock(&sbinfo->stat_lock);
0edd73b33   Hugh Dickins   [PATCH] shmem: re...
2020
  	inodes = sbinfo->max_inodes - sbinfo->free_inodes;
7e496299d   Tim Chen   tmpfs: make tmpfs...
2021
  	if (percpu_counter_compare(&sbinfo->used_blocks, config.max_blocks) > 0)
0edd73b33   Hugh Dickins   [PATCH] shmem: re...
2022
  		goto out;
680d794ba   akpm@linux-foundation.org   mount options: fi...
2023
  	if (config.max_inodes < inodes)
0edd73b33   Hugh Dickins   [PATCH] shmem: re...
2024
2025
  		goto out;
  	/*
54af60421   Hugh Dickins   tmpfs: convert sh...
2026
  	 * Those tests disallow limited->unlimited while any are in use;
0edd73b33   Hugh Dickins   [PATCH] shmem: re...
2027
2028
2029
  	 * but we must separately disallow unlimited->limited, because
  	 * in that case we have no record of how much is already in use.
  	 */
680d794ba   akpm@linux-foundation.org   mount options: fi...
2030
  	if (config.max_blocks && !sbinfo->max_blocks)
0edd73b33   Hugh Dickins   [PATCH] shmem: re...
2031
  		goto out;
680d794ba   akpm@linux-foundation.org   mount options: fi...
2032
  	if (config.max_inodes && !sbinfo->max_inodes)
0edd73b33   Hugh Dickins   [PATCH] shmem: re...
2033
2034
2035
  		goto out;
  
  	error = 0;
680d794ba   akpm@linux-foundation.org   mount options: fi...
2036
  	sbinfo->max_blocks  = config.max_blocks;
680d794ba   akpm@linux-foundation.org   mount options: fi...
2037
2038
  	sbinfo->max_inodes  = config.max_inodes;
  	sbinfo->free_inodes = config.max_inodes - inodes;
71fe804b6   Lee Schermerhorn   mempolicy: use st...
2039
2040
2041
  
  	mpol_put(sbinfo->mpol);
  	sbinfo->mpol        = config.mpol;	/* transfers initial ref */
0edd73b33   Hugh Dickins   [PATCH] shmem: re...
2042
2043
2044
  out:
  	spin_unlock(&sbinfo->stat_lock);
  	return error;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
2045
  }
680d794ba   akpm@linux-foundation.org   mount options: fi...
2046
2047
2048
2049
2050
2051
2052
2053
2054
2055
2056
2057
2058
2059
2060
2061
  
  static int shmem_show_options(struct seq_file *seq, struct vfsmount *vfs)
  {
  	struct shmem_sb_info *sbinfo = SHMEM_SB(vfs->mnt_sb);
  
  	if (sbinfo->max_blocks != shmem_default_max_blocks())
  		seq_printf(seq, ",size=%luk",
  			sbinfo->max_blocks << (PAGE_CACHE_SHIFT - 10));
  	if (sbinfo->max_inodes != shmem_default_max_inodes())
  		seq_printf(seq, ",nr_inodes=%lu", sbinfo->max_inodes);
  	if (sbinfo->mode != (S_IRWXUGO | S_ISVTX))
  		seq_printf(seq, ",mode=%03o", sbinfo->mode);
  	if (sbinfo->uid != 0)
  		seq_printf(seq, ",uid=%u", sbinfo->uid);
  	if (sbinfo->gid != 0)
  		seq_printf(seq, ",gid=%u", sbinfo->gid);
71fe804b6   Lee Schermerhorn   mempolicy: use st...
2062
  	shmem_show_mpol(seq, sbinfo->mpol);
680d794ba   akpm@linux-foundation.org   mount options: fi...
2063
2064
2065
  	return 0;
  }
  #endif /* CONFIG_TMPFS */
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
2066
2067
2068
  
  static void shmem_put_super(struct super_block *sb)
  {
602586a83   Hugh Dickins   shmem: put_super ...
2069
2070
2071
2072
  	struct shmem_sb_info *sbinfo = SHMEM_SB(sb);
  
  	percpu_counter_destroy(&sbinfo->used_blocks);
  	kfree(sbinfo);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
2073
2074
  	sb->s_fs_info = NULL;
  }
2b2af54a5   Kay Sievers   Driver Core: devt...
2075
  int shmem_fill_super(struct super_block *sb, void *data, int silent)
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
2076
2077
2078
  {
  	struct inode *inode;
  	struct dentry *root;
0edd73b33   Hugh Dickins   [PATCH] shmem: re...
2079
  	struct shmem_sb_info *sbinfo;
680d794ba   akpm@linux-foundation.org   mount options: fi...
2080
2081
2082
  	int err = -ENOMEM;
  
  	/* Round up to L1_CACHE_BYTES to resist false sharing */
425fbf047   Pekka Enberg   shmem: initialize...
2083
  	sbinfo = kzalloc(max((int)sizeof(struct shmem_sb_info),
680d794ba   akpm@linux-foundation.org   mount options: fi...
2084
2085
2086
  				L1_CACHE_BYTES), GFP_KERNEL);
  	if (!sbinfo)
  		return -ENOMEM;
680d794ba   akpm@linux-foundation.org   mount options: fi...
2087
  	sbinfo->mode = S_IRWXUGO | S_ISVTX;
76aac0e9a   David Howells   CRED: Wrap task c...
2088
2089
  	sbinfo->uid = current_fsuid();
  	sbinfo->gid = current_fsgid();
680d794ba   akpm@linux-foundation.org   mount options: fi...
2090
  	sb->s_fs_info = sbinfo;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
2091

0edd73b33   Hugh Dickins   [PATCH] shmem: re...
2092
  #ifdef CONFIG_TMPFS
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
2093
2094
2095
2096
2097
2098
  	/*
  	 * Per default we only allow half of the physical ram per
  	 * tmpfs instance, limiting inodes to one per page of lowmem;
  	 * but the internal instance is left unlimited.
  	 */
  	if (!(sb->s_flags & MS_NOUSER)) {
680d794ba   akpm@linux-foundation.org   mount options: fi...
2099
2100
2101
2102
2103
2104
  		sbinfo->max_blocks = shmem_default_max_blocks();
  		sbinfo->max_inodes = shmem_default_max_inodes();
  		if (shmem_parse_options(data, sbinfo, false)) {
  			err = -EINVAL;
  			goto failed;
  		}
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
2105
  	}
91828a405   David M. Grimes   [PATCH] knfsd: ad...
2106
  	sb->s_export_op = &shmem_export_ops;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
2107
2108
2109
  #else
  	sb->s_flags |= MS_NOUSER;
  #endif
0edd73b33   Hugh Dickins   [PATCH] shmem: re...
2110
  	spin_lock_init(&sbinfo->stat_lock);
602586a83   Hugh Dickins   shmem: put_super ...
2111
2112
  	if (percpu_counter_init(&sbinfo->used_blocks, 0))
  		goto failed;
680d794ba   akpm@linux-foundation.org   mount options: fi...
2113
  	sbinfo->free_inodes = sbinfo->max_inodes;
0edd73b33   Hugh Dickins   [PATCH] shmem: re...
2114

285b2c4fd   Hugh Dickins   tmpfs: demolish o...
2115
  	sb->s_maxbytes = MAX_LFS_FILESIZE;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
2116
2117
2118
2119
  	sb->s_blocksize = PAGE_CACHE_SIZE;
  	sb->s_blocksize_bits = PAGE_CACHE_SHIFT;
  	sb->s_magic = TMPFS_MAGIC;
  	sb->s_op = &shmem_ops;
cfd95a9cf   Robin H. Johnson   [PATCH] tmpfs: ti...
2120
  	sb->s_time_gran = 1;
b09e0fa4b   Eric Paris   tmpfs: implement ...
2121
  #ifdef CONFIG_TMPFS_XATTR
39f0247d3   Andreas Gruenbacher   [PATCH] Access Co...
2122
  	sb->s_xattr = shmem_xattr_handlers;
b09e0fa4b   Eric Paris   tmpfs: implement ...
2123
2124
  #endif
  #ifdef CONFIG_TMPFS_POSIX_ACL
39f0247d3   Andreas Gruenbacher   [PATCH] Access Co...
2125
2126
  	sb->s_flags |= MS_POSIXACL;
  #endif
0edd73b33   Hugh Dickins   [PATCH] shmem: re...
2127

454abafe9   Dmitry Monakhov   ramfs: replace in...
2128
  	inode = shmem_get_inode(sb, NULL, S_IFDIR | sbinfo->mode, 0, VM_NORESERVE);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
2129
2130
  	if (!inode)
  		goto failed;
680d794ba   akpm@linux-foundation.org   mount options: fi...
2131
2132
  	inode->i_uid = sbinfo->uid;
  	inode->i_gid = sbinfo->gid;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
2133
2134
2135
2136
2137
2138
2139
2140
2141
2142
2143
2144
  	root = d_alloc_root(inode);
  	if (!root)
  		goto failed_iput;
  	sb->s_root = root;
  	return 0;
  
  failed_iput:
  	iput(inode);
  failed:
  	shmem_put_super(sb);
  	return err;
  }
fcc234f88   Pekka Enberg   [PATCH] mm: kill ...
2145
  static struct kmem_cache *shmem_inode_cachep;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
2146
2147
2148
  
  static struct inode *shmem_alloc_inode(struct super_block *sb)
  {
41ffe5d5c   Hugh Dickins   tmpfs: miscellane...
2149
2150
2151
  	struct shmem_inode_info *info;
  	info = kmem_cache_alloc(shmem_inode_cachep, GFP_KERNEL);
  	if (!info)
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
2152
  		return NULL;
41ffe5d5c   Hugh Dickins   tmpfs: miscellane...
2153
  	return &info->vfs_inode;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
2154
  }
41ffe5d5c   Hugh Dickins   tmpfs: miscellane...
2155
  static void shmem_destroy_callback(struct rcu_head *head)
fa0d7e3de   Nick Piggin   fs: icache RCU fr...
2156
2157
2158
2159
2160
  {
  	struct inode *inode = container_of(head, struct inode, i_rcu);
  	INIT_LIST_HEAD(&inode->i_dentry);
  	kmem_cache_free(shmem_inode_cachep, SHMEM_I(inode));
  }
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
2161
2162
  static void shmem_destroy_inode(struct inode *inode)
  {
69f07ec93   Hugh Dickins   tmpfs: use kmemdu...
2163
  	if ((inode->i_mode & S_IFMT) == S_IFREG)
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
2164
  		mpol_free_shared_policy(&SHMEM_I(inode)->policy);
41ffe5d5c   Hugh Dickins   tmpfs: miscellane...
2165
  	call_rcu(&inode->i_rcu, shmem_destroy_callback);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
2166
  }
41ffe5d5c   Hugh Dickins   tmpfs: miscellane...
2167
  static void shmem_init_inode(void *foo)
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
2168
  {
41ffe5d5c   Hugh Dickins   tmpfs: miscellane...
2169
2170
  	struct shmem_inode_info *info = foo;
  	inode_init_once(&info->vfs_inode);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
2171
  }
41ffe5d5c   Hugh Dickins   tmpfs: miscellane...
2172
  static int shmem_init_inodecache(void)
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
2173
2174
2175
  {
  	shmem_inode_cachep = kmem_cache_create("shmem_inode_cache",
  				sizeof(struct shmem_inode_info),
41ffe5d5c   Hugh Dickins   tmpfs: miscellane...
2176
  				0, SLAB_PANIC, shmem_init_inode);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
2177
2178
  	return 0;
  }
41ffe5d5c   Hugh Dickins   tmpfs: miscellane...
2179
  static void shmem_destroy_inodecache(void)
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
2180
  {
1a1d92c10   Alexey Dobriyan   [PATCH] Really ig...
2181
  	kmem_cache_destroy(shmem_inode_cachep);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
2182
  }
f5e54d6e5   Christoph Hellwig   [PATCH] mark addr...
2183
  static const struct address_space_operations shmem_aops = {
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
2184
  	.writepage	= shmem_writepage,
767193253   Ken Chen   [PATCH] simplify ...
2185
  	.set_page_dirty	= __set_page_dirty_no_writeback,
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
2186
  #ifdef CONFIG_TMPFS
800d15a53   Nick Piggin   implement simple ...
2187
2188
  	.write_begin	= shmem_write_begin,
  	.write_end	= shmem_write_end,
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
2189
  #endif
304dbdb7a   Lee Schermerhorn   [PATCH] add migra...
2190
  	.migratepage	= migrate_page,
aa261f549   Andi Kleen   HWPOISON: Enable ...
2191
  	.error_remove_page = generic_error_remove_page,
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
2192
  };
15ad7cdcf   Helge Deller   [PATCH] struct se...
2193
  static const struct file_operations shmem_file_operations = {
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
2194
2195
2196
  	.mmap		= shmem_mmap,
  #ifdef CONFIG_TMPFS
  	.llseek		= generic_file_llseek,
bcd78e496   Hugh Dickins   tmpfs: support aio
2197
  	.read		= do_sync_read,
5402b976a   Hugh Dickins   shmem_file_write ...
2198
  	.write		= do_sync_write,
bcd78e496   Hugh Dickins   tmpfs: support aio
2199
  	.aio_read	= shmem_file_aio_read,
5402b976a   Hugh Dickins   shmem_file_write ...
2200
  	.aio_write	= generic_file_aio_write,
1b061d924   Christoph Hellwig   rename the generi...
2201
  	.fsync		= noop_fsync,
708e3508c   Hugh Dickins   tmpfs: clone shme...
2202
  	.splice_read	= shmem_file_splice_read,
ae9764164   Hugh Dickins   shmem: convert to...
2203
  	.splice_write	= generic_file_splice_write,
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
2204
2205
  #endif
  };
92e1d5be9   Arjan van de Ven   [PATCH] mark stru...
2206
  static const struct inode_operations shmem_inode_operations = {
94c1e62df   Hugh Dickins   tmpfs: take contr...
2207
  	.setattr	= shmem_setattr,
f6b3ec238   Badari Pulavarty   [PATCH] madvise(M...
2208
  	.truncate_range	= shmem_truncate_range,
b09e0fa4b   Eric Paris   tmpfs: implement ...
2209
2210
2211
2212
2213
2214
  #ifdef CONFIG_TMPFS_XATTR
  	.setxattr	= shmem_setxattr,
  	.getxattr	= shmem_getxattr,
  	.listxattr	= shmem_listxattr,
  	.removexattr	= shmem_removexattr,
  #endif
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
2215
  };
92e1d5be9   Arjan van de Ven   [PATCH] mark stru...
2216
  static const struct inode_operations shmem_dir_inode_operations = {
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
2217
2218
2219
2220
2221
2222
2223
2224
2225
2226
  #ifdef CONFIG_TMPFS
  	.create		= shmem_create,
  	.lookup		= simple_lookup,
  	.link		= shmem_link,
  	.unlink		= shmem_unlink,
  	.symlink	= shmem_symlink,
  	.mkdir		= shmem_mkdir,
  	.rmdir		= shmem_rmdir,
  	.mknod		= shmem_mknod,
  	.rename		= shmem_rename,
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
2227
  #endif
b09e0fa4b   Eric Paris   tmpfs: implement ...
2228
2229
2230
2231
2232
2233
  #ifdef CONFIG_TMPFS_XATTR
  	.setxattr	= shmem_setxattr,
  	.getxattr	= shmem_getxattr,
  	.listxattr	= shmem_listxattr,
  	.removexattr	= shmem_removexattr,
  #endif
39f0247d3   Andreas Gruenbacher   [PATCH] Access Co...
2234
  #ifdef CONFIG_TMPFS_POSIX_ACL
94c1e62df   Hugh Dickins   tmpfs: take contr...
2235
  	.setattr	= shmem_setattr,
39f0247d3   Andreas Gruenbacher   [PATCH] Access Co...
2236
2237
  #endif
  };
92e1d5be9   Arjan van de Ven   [PATCH] mark stru...
2238
  static const struct inode_operations shmem_special_inode_operations = {
b09e0fa4b   Eric Paris   tmpfs: implement ...
2239
2240
2241
2242
2243
2244
  #ifdef CONFIG_TMPFS_XATTR
  	.setxattr	= shmem_setxattr,
  	.getxattr	= shmem_getxattr,
  	.listxattr	= shmem_listxattr,
  	.removexattr	= shmem_removexattr,
  #endif
39f0247d3   Andreas Gruenbacher   [PATCH] Access Co...
2245
  #ifdef CONFIG_TMPFS_POSIX_ACL
94c1e62df   Hugh Dickins   tmpfs: take contr...
2246
  	.setattr	= shmem_setattr,
39f0247d3   Andreas Gruenbacher   [PATCH] Access Co...
2247
  #endif
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
2248
  };
759b9775c   Hugh Dickins   [PATCH] shmem and...
2249
  static const struct super_operations shmem_ops = {
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
2250
2251
2252
2253
2254
  	.alloc_inode	= shmem_alloc_inode,
  	.destroy_inode	= shmem_destroy_inode,
  #ifdef CONFIG_TMPFS
  	.statfs		= shmem_statfs,
  	.remount_fs	= shmem_remount_fs,
680d794ba   akpm@linux-foundation.org   mount options: fi...
2255
  	.show_options	= shmem_show_options,
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
2256
  #endif
1f895f75d   Al Viro   switch shmem.c to...
2257
  	.evict_inode	= shmem_evict_inode,
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
2258
2259
2260
  	.drop_inode	= generic_delete_inode,
  	.put_super	= shmem_put_super,
  };
f0f37e2f7   Alexey Dobriyan   const: mark struc...
2261
  static const struct vm_operations_struct shmem_vm_ops = {
54cb8821d   Nick Piggin   mm: merge populat...
2262
  	.fault		= shmem_fault,
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
2263
2264
2265
2266
2267
  #ifdef CONFIG_NUMA
  	.set_policy     = shmem_set_policy,
  	.get_policy     = shmem_get_policy,
  #endif
  };
3c26ff6e4   Al Viro   convert get_sb_no...
2268
2269
  static struct dentry *shmem_mount(struct file_system_type *fs_type,
  	int flags, const char *dev_name, void *data)
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
2270
  {
3c26ff6e4   Al Viro   convert get_sb_no...
2271
  	return mount_nodev(fs_type, flags, data, shmem_fill_super);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
2272
  }
41ffe5d5c   Hugh Dickins   tmpfs: miscellane...
2273
  static struct file_system_type shmem_fs_type = {
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
2274
2275
  	.owner		= THIS_MODULE,
  	.name		= "tmpfs",
3c26ff6e4   Al Viro   convert get_sb_no...
2276
  	.mount		= shmem_mount,
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
2277
2278
  	.kill_sb	= kill_litter_super,
  };
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
2279

41ffe5d5c   Hugh Dickins   tmpfs: miscellane...
2280
  int __init shmem_init(void)
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
2281
2282
  {
  	int error;
e0bf68dde   Peter Zijlstra   mm: bdi init hooks
2283
2284
2285
  	error = bdi_init(&shmem_backing_dev_info);
  	if (error)
  		goto out4;
41ffe5d5c   Hugh Dickins   tmpfs: miscellane...
2286
  	error = shmem_init_inodecache();
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
2287
2288
  	if (error)
  		goto out3;
41ffe5d5c   Hugh Dickins   tmpfs: miscellane...
2289
  	error = register_filesystem(&shmem_fs_type);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
2290
2291
2292
2293
2294
  	if (error) {
  		printk(KERN_ERR "Could not register tmpfs
  ");
  		goto out2;
  	}
95dc112a5   Greg Kroah-Hartman   [PATCH] devfs: Re...
2295

41ffe5d5c   Hugh Dickins   tmpfs: miscellane...
2296
2297
  	shm_mnt = vfs_kern_mount(&shmem_fs_type, MS_NOUSER,
  				 shmem_fs_type.name, NULL);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
2298
2299
2300
2301
2302
2303
2304
2305
2306
  	if (IS_ERR(shm_mnt)) {
  		error = PTR_ERR(shm_mnt);
  		printk(KERN_ERR "Could not kern_mount tmpfs
  ");
  		goto out1;
  	}
  	return 0;
  
  out1:
41ffe5d5c   Hugh Dickins   tmpfs: miscellane...
2307
  	unregister_filesystem(&shmem_fs_type);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
2308
  out2:
41ffe5d5c   Hugh Dickins   tmpfs: miscellane...
2309
  	shmem_destroy_inodecache();
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
2310
  out3:
e0bf68dde   Peter Zijlstra   mm: bdi init hooks
2311
2312
  	bdi_destroy(&shmem_backing_dev_info);
  out4:
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
2313
2314
2315
  	shm_mnt = ERR_PTR(error);
  	return error;
  }
853ac43ab   Matt Mackall   shmem: unify regu...
2316
2317
2318
2319
2320
2321
2322
2323
2324
2325
2326
2327
2328
  
  #else /* !CONFIG_SHMEM */
  
  /*
   * tiny-shmem: simple shmemfs and tmpfs using ramfs code
   *
   * This is intended for small system where the benefits of the full
   * shmem code (swap-backed and resource-limited) are outweighed by
   * their complexity. On systems without swap this code should be
   * effectively equivalent, but much lighter weight.
   */
  
  #include <linux/ramfs.h>
41ffe5d5c   Hugh Dickins   tmpfs: miscellane...
2329
  static struct file_system_type shmem_fs_type = {
853ac43ab   Matt Mackall   shmem: unify regu...
2330
  	.name		= "tmpfs",
3c26ff6e4   Al Viro   convert get_sb_no...
2331
  	.mount		= ramfs_mount,
853ac43ab   Matt Mackall   shmem: unify regu...
2332
2333
  	.kill_sb	= kill_litter_super,
  };
41ffe5d5c   Hugh Dickins   tmpfs: miscellane...
2334
  int __init shmem_init(void)
853ac43ab   Matt Mackall   shmem: unify regu...
2335
  {
41ffe5d5c   Hugh Dickins   tmpfs: miscellane...
2336
  	BUG_ON(register_filesystem(&shmem_fs_type) != 0);
853ac43ab   Matt Mackall   shmem: unify regu...
2337

41ffe5d5c   Hugh Dickins   tmpfs: miscellane...
2338
  	shm_mnt = kern_mount(&shmem_fs_type);
853ac43ab   Matt Mackall   shmem: unify regu...
2339
2340
2341
2342
  	BUG_ON(IS_ERR(shm_mnt));
  
  	return 0;
  }
41ffe5d5c   Hugh Dickins   tmpfs: miscellane...
2343
  int shmem_unuse(swp_entry_t swap, struct page *page)
853ac43ab   Matt Mackall   shmem: unify regu...
2344
2345
2346
  {
  	return 0;
  }
3f96b79ad   Hugh Dickins   tmpfs: depend on ...
2347
2348
2349
2350
  int shmem_lock(struct file *file, int lock, struct user_struct *user)
  {
  	return 0;
  }
41ffe5d5c   Hugh Dickins   tmpfs: miscellane...
2351
  void shmem_truncate_range(struct inode *inode, loff_t lstart, loff_t lend)
94c1e62df   Hugh Dickins   tmpfs: take contr...
2352
  {
41ffe5d5c   Hugh Dickins   tmpfs: miscellane...
2353
  	truncate_inode_pages_range(inode->i_mapping, lstart, lend);
94c1e62df   Hugh Dickins   tmpfs: take contr...
2354
2355
  }
  EXPORT_SYMBOL_GPL(shmem_truncate_range);
0b0a0806b   Hugh Dickins   shmem: fix shared...
2356
2357
  #define shmem_vm_ops				generic_file_vm_ops
  #define shmem_file_operations			ramfs_file_operations
454abafe9   Dmitry Monakhov   ramfs: replace in...
2358
  #define shmem_get_inode(sb, dir, mode, dev, flags)	ramfs_get_inode(sb, dir, mode, dev)
0b0a0806b   Hugh Dickins   shmem: fix shared...
2359
2360
  #define shmem_acct_size(flags, size)		0
  #define shmem_unacct_size(flags, size)		do {} while (0)
853ac43ab   Matt Mackall   shmem: unify regu...
2361
2362
2363
2364
  
  #endif /* CONFIG_SHMEM */
  
  /* common code */
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
2365

467118102   Randy Dunlap   mm/shmem and tiny...
2366
  /**
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
2367
   * shmem_file_setup - get an unlinked file living in tmpfs
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
2368
2369
   * @name: name for dentry (to be seen in /proc/<pid>/maps
   * @size: size to be set for the file
0b0a0806b   Hugh Dickins   shmem: fix shared...
2370
   * @flags: VM_NORESERVE suppresses pre-accounting of the entire object size
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
2371
   */
168f5ac66   Sergei Trofimovich   mm cleanup: shmem...
2372
  struct file *shmem_file_setup(const char *name, loff_t size, unsigned long flags)
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
2373
2374
2375
2376
  {
  	int error;
  	struct file *file;
  	struct inode *inode;
2c48b9c45   Al Viro   switch alloc_file...
2377
2378
  	struct path path;
  	struct dentry *root;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
2379
2380
2381
2382
  	struct qstr this;
  
  	if (IS_ERR(shm_mnt))
  		return (void *)shm_mnt;
285b2c4fd   Hugh Dickins   tmpfs: demolish o...
2383
  	if (size < 0 || size > MAX_LFS_FILESIZE)
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
2384
2385
2386
2387
2388
2389
2390
2391
2392
2393
  		return ERR_PTR(-EINVAL);
  
  	if (shmem_acct_size(flags, size))
  		return ERR_PTR(-ENOMEM);
  
  	error = -ENOMEM;
  	this.name = name;
  	this.len = strlen(name);
  	this.hash = 0; /* will go */
  	root = shm_mnt->mnt_root;
2c48b9c45   Al Viro   switch alloc_file...
2394
2395
  	path.dentry = d_alloc(root, &this);
  	if (!path.dentry)
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
2396
  		goto put_memory;
2c48b9c45   Al Viro   switch alloc_file...
2397
  	path.mnt = mntget(shm_mnt);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
2398

1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
2399
  	error = -ENOSPC;
454abafe9   Dmitry Monakhov   ramfs: replace in...
2400
  	inode = shmem_get_inode(root->d_sb, NULL, S_IFREG | S_IRWXUGO, 0, flags);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
2401
  	if (!inode)
4b42af81f   Al Viro   switch shmem_file...
2402
  		goto put_dentry;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
2403

2c48b9c45   Al Viro   switch alloc_file...
2404
  	d_instantiate(path.dentry, inode);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
2405
  	inode->i_size = size;
6d6b77f16   Miklos Szeredi   filesystems: add ...
2406
  	clear_nlink(inode);	/* It is unlinked */
853ac43ab   Matt Mackall   shmem: unify regu...
2407
2408
2409
  #ifndef CONFIG_MMU
  	error = ramfs_nommu_expand_for_mapping(inode, size);
  	if (error)
4b42af81f   Al Viro   switch shmem_file...
2410
  		goto put_dentry;
853ac43ab   Matt Mackall   shmem: unify regu...
2411
  #endif
4b42af81f   Al Viro   switch shmem_file...
2412
2413
  
  	error = -ENFILE;
2c48b9c45   Al Viro   switch alloc_file...
2414
  	file = alloc_file(&path, FMODE_WRITE | FMODE_READ,
4b42af81f   Al Viro   switch shmem_file...
2415
2416
2417
  		  &shmem_file_operations);
  	if (!file)
  		goto put_dentry;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
2418
  	return file;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
2419
  put_dentry:
2c48b9c45   Al Viro   switch alloc_file...
2420
  	path_put(&path);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
2421
2422
2423
2424
  put_memory:
  	shmem_unacct_size(flags, size);
  	return ERR_PTR(error);
  }
395e0ddc4   Keith Packard   Export shmem_file...
2425
  EXPORT_SYMBOL_GPL(shmem_file_setup);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
2426

467118102   Randy Dunlap   mm/shmem and tiny...
2427
  /**
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
2428
   * shmem_zero_setup - setup a shared anonymous mapping
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
2429
2430
2431
2432
2433
2434
2435
2436
2437
2438
2439
2440
2441
2442
2443
   * @vma: the vma to be mmapped is prepared by do_mmap_pgoff
   */
  int shmem_zero_setup(struct vm_area_struct *vma)
  {
  	struct file *file;
  	loff_t size = vma->vm_end - vma->vm_start;
  
  	file = shmem_file_setup("dev/zero", size, vma->vm_flags);
  	if (IS_ERR(file))
  		return PTR_ERR(file);
  
  	if (vma->vm_file)
  		fput(vma->vm_file);
  	vma->vm_file = file;
  	vma->vm_ops = &shmem_vm_ops;
bee4c36a5   Hugh Dickins   shmem: let shared...
2444
  	vma->vm_flags |= VM_CAN_NONLINEAR;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
2445
2446
  	return 0;
  }
d9d90e5eb   Hugh Dickins   tmpfs: add shmem_...
2447
2448
2449
2450
2451
2452
2453
2454
2455
2456
2457
2458
2459
  
  /**
   * shmem_read_mapping_page_gfp - read into page cache, using specified page allocation flags.
   * @mapping:	the page's address_space
   * @index:	the page index
   * @gfp:	the page allocator flags to use if allocating
   *
   * This behaves as a tmpfs "read_cache_page_gfp(mapping, index, gfp)",
   * with any new page allocations done using the specified allocation flags.
   * But read_cache_page_gfp() uses the ->readpage() method: which does not
   * suit tmpfs, since it may have pages in swapcache, and needs to find those
   * for itself; although drivers/gpu/drm i915 and ttm rely upon this support.
   *
68da9f055   Hugh Dickins   tmpfs: pass gfp t...
2460
2461
   * i915_gem_object_get_pages_gtt() mixes __GFP_NORETRY | __GFP_NOWARN in
   * with the mapping_gfp_mask(), to avoid OOMing the machine unnecessarily.
d9d90e5eb   Hugh Dickins   tmpfs: add shmem_...
2462
2463
2464
2465
   */
  struct page *shmem_read_mapping_page_gfp(struct address_space *mapping,
  					 pgoff_t index, gfp_t gfp)
  {
68da9f055   Hugh Dickins   tmpfs: pass gfp t...
2466
2467
  #ifdef CONFIG_SHMEM
  	struct inode *inode = mapping->host;
9276aad6c   Hugh Dickins   tmpfs: remove_shm...
2468
  	struct page *page;
68da9f055   Hugh Dickins   tmpfs: pass gfp t...
2469
2470
2471
2472
2473
2474
2475
2476
2477
2478
2479
2480
2481
  	int error;
  
  	BUG_ON(mapping->a_ops != &shmem_aops);
  	error = shmem_getpage_gfp(inode, index, &page, SGP_CACHE, gfp, NULL);
  	if (error)
  		page = ERR_PTR(error);
  	else
  		unlock_page(page);
  	return page;
  #else
  	/*
  	 * The tiny !SHMEM case uses ramfs without swap
  	 */
d9d90e5eb   Hugh Dickins   tmpfs: add shmem_...
2482
  	return read_cache_page_gfp(mapping, index, gfp);
68da9f055   Hugh Dickins   tmpfs: pass gfp t...
2483
  #endif
d9d90e5eb   Hugh Dickins   tmpfs: add shmem_...
2484
2485
  }
  EXPORT_SYMBOL_GPL(shmem_read_mapping_page_gfp);