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
  static struct inode *shmem_get_inode(struct super_block *sb, const struct inode *dir,
09208d150   Al Viro   shmem, ramfs: pro...
1057
  				     umode_t 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
  	}
  	/* else leave those fields 0 like simple_statfs */
  	return 0;
  }
  
  /*
   * File creation. Allocate an inode, and we're done..
   */
  static int
1a67aafb5   Al Viro   switch ->mknod() ...
1403
  shmem_mknod(struct inode *dir, struct dentry *dentry, umode_t mode, dev_t dev)
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
1404
  {
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
  	}
  	return error;
  }
18bb1db3e   Al Viro   switch vfs_mkdir(...
1434
  static int shmem_mkdir(struct inode *dir, struct dentry *dentry, umode_t mode)
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
1435
1436
1437
1438
1439
  {
  	int error;
  
  	if ((error = shmem_mknod(dir, dentry, mode | S_IFDIR, 0)))
  		return error;
d8c76e6f4   Dave Hansen   [PATCH] r/o bind ...
1440
  	inc_nlink(dir);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
1441
1442
  	return 0;
  }
4acdaf27e   Al Viro   switch ->create()...
1443
  static int shmem_create(struct inode *dir, struct dentry *dentry, umode_t mode,
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
1444
1445
1446
1447
1448
1449
1450
1451
1452
1453
1454
  		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...
1455
  	int ret;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
1456
1457
1458
1459
1460
1461
  
  	/*
  	 * 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...
1462
1463
1464
  	ret = shmem_reserve_inode(inode->i_sb);
  	if (ret)
  		goto out;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
1465
1466
1467
  
  	dir->i_size += BOGO_DIRENT_SIZE;
  	inode->i_ctime = dir->i_ctime = dir->i_mtime = CURRENT_TIME;
d8c76e6f4   Dave Hansen   [PATCH] r/o bind ...
1468
  	inc_nlink(inode);
7de9c6ee3   Al Viro   new helper: ihold()
1469
  	ihold(inode);	/* New dentry reference */
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
1470
1471
  	dget(dentry);		/* Extra pinning count for the created dentry */
  	d_instantiate(dentry, inode);
5b04c6890   Pavel Emelyanov   shmem: factor out...
1472
1473
  out:
  	return ret;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
1474
1475
1476
1477
1478
  }
  
  static int shmem_unlink(struct inode *dir, struct dentry *dentry)
  {
  	struct inode *inode = dentry->d_inode;
5b04c6890   Pavel Emelyanov   shmem: factor out...
1479
1480
  	if (inode->i_nlink > 1 && !S_ISDIR(inode->i_mode))
  		shmem_free_inode(inode->i_sb);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
1481
1482
1483
  
  	dir->i_size -= BOGO_DIRENT_SIZE;
  	inode->i_ctime = dir->i_ctime = dir->i_mtime = CURRENT_TIME;
9a53c3a78   Dave Hansen   [PATCH] r/o bind ...
1484
  	drop_nlink(inode);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
1485
1486
1487
1488
1489
1490
1491
1492
  	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 ...
1493
1494
  	drop_nlink(dentry->d_inode);
  	drop_nlink(dir);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
1495
1496
1497
1498
1499
1500
1501
1502
1503
1504
1505
1506
1507
1508
1509
1510
1511
1512
1513
1514
  	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 ...
1515
  			drop_nlink(old_dir);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
1516
  	} else if (they_are_dirs) {
9a53c3a78   Dave Hansen   [PATCH] r/o bind ...
1517
  		drop_nlink(old_dir);
d8c76e6f4   Dave Hansen   [PATCH] r/o bind ...
1518
  		inc_nlink(new_dir);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
1519
1520
1521
1522
1523
1524
1525
1526
1527
1528
1529
1530
1531
1532
1533
  	}
  
  	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...
1534
  	struct page *page;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
1535
1536
1537
1538
1539
1540
  	char *kaddr;
  	struct shmem_inode_info *info;
  
  	len = strlen(symname) + 1;
  	if (len > PAGE_CACHE_SIZE)
  		return -ENAMETOOLONG;
454abafe9   Dmitry Monakhov   ramfs: replace in...
1541
  	inode = shmem_get_inode(dir->i_sb, dir, S_IFLNK|S_IRWXUGO, 0, VM_NORESERVE);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
1542
1543
  	if (!inode)
  		return -ENOSPC;
9d8f13ba3   Mimi Zohar   security: new sec...
1544
  	error = security_inode_init_security(inode, dir, &dentry->d_name,
2a7dba391   Eric Paris   fs/vfs/security: ...
1545
  					     NULL, NULL);
570bc1c2e   Stephen Smalley   [PATCH] tmpfs: En...
1546
1547
1548
1549
1550
1551
1552
  	if (error) {
  		if (error != -EOPNOTSUPP) {
  			iput(inode);
  			return error;
  		}
  		error = 0;
  	}
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
1553
1554
  	info = SHMEM_I(inode);
  	inode->i_size = len-1;
69f07ec93   Hugh Dickins   tmpfs: use kmemdu...
1555
1556
1557
1558
1559
1560
1561
  	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
1562
1563
1564
1565
1566
1567
  	} else {
  		error = shmem_getpage(inode, 0, &page, SGP_WRITE, NULL);
  		if (error) {
  			iput(inode);
  			return error;
  		}
14fcc23fd   Hugh Dickins   tmpfs: fix kernel...
1568
  		inode->i_mapping->a_ops = &shmem_aops;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
1569
1570
1571
1572
1573
  		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: ...
1574
  		unlock_page(page);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
1575
1576
  		page_cache_release(page);
  	}
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
1577
1578
1579
1580
1581
1582
  	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...
1583
  static void *shmem_follow_short_symlink(struct dentry *dentry, struct nameidata *nd)
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
1584
  {
69f07ec93   Hugh Dickins   tmpfs: use kmemdu...
1585
  	nd_set_link(nd, SHMEM_I(dentry->d_inode)->symlink);
cc314eef0   Linus Torvalds   Fix nasty ncpfs s...
1586
  	return NULL;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
1587
  }
cc314eef0   Linus Torvalds   Fix nasty ncpfs s...
1588
  static void *shmem_follow_link(struct dentry *dentry, struct nameidata *nd)
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
1589
1590
  {
  	struct page *page = NULL;
41ffe5d5c   Hugh Dickins   tmpfs: miscellane...
1591
1592
  	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...
1593
1594
  	if (page)
  		unlock_page(page);
cc314eef0   Linus Torvalds   Fix nasty ncpfs s...
1595
  	return page;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
1596
  }
cc314eef0   Linus Torvalds   Fix nasty ncpfs s...
1597
  static void shmem_put_link(struct dentry *dentry, struct nameidata *nd, void *cookie)
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
1598
1599
  {
  	if (!IS_ERR(nd_get_link(nd))) {
cc314eef0   Linus Torvalds   Fix nasty ncpfs s...
1600
  		struct page *page = cookie;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
1601
1602
1603
  		kunmap(page);
  		mark_page_accessed(page);
  		page_cache_release(page);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
1604
1605
  	}
  }
b09e0fa4b   Eric Paris   tmpfs: implement ...
1606
  #ifdef CONFIG_TMPFS_XATTR
467118102   Randy Dunlap   mm/shmem and tiny...
1607
  /*
b09e0fa4b   Eric Paris   tmpfs: implement ...
1608
1609
   * 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...
1610
1611
1612
   * like ACLs, we also need to implement the security.* handlers at
   * filesystem level, though.
   */
b09e0fa4b   Eric Paris   tmpfs: implement ...
1613
1614
  static int shmem_xattr_get(struct dentry *dentry, const char *name,
  			   void *buffer, size_t size)
39f0247d3   Andreas Gruenbacher   [PATCH] Access Co...
1615
  {
b09e0fa4b   Eric Paris   tmpfs: implement ...
1616
1617
1618
  	struct shmem_inode_info *info;
  	struct shmem_xattr *xattr;
  	int ret = -ENODATA;
39f0247d3   Andreas Gruenbacher   [PATCH] Access Co...
1619

b09e0fa4b   Eric Paris   tmpfs: implement ...
1620
1621
1622
1623
1624
1625
1626
1627
1628
1629
1630
1631
1632
1633
1634
1635
1636
1637
  	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...
1638
  }
b09e0fa4b   Eric Paris   tmpfs: implement ...
1639
1640
  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...
1641
  {
b09e0fa4b   Eric Paris   tmpfs: implement ...
1642
1643
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
  	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...
1697
  }
bb4354538   Stephen Hemminger   fs: xattr_handler...
1698
  static const struct xattr_handler *shmem_xattr_handlers[] = {
b09e0fa4b   Eric Paris   tmpfs: implement ...
1699
  #ifdef CONFIG_TMPFS_POSIX_ACL
1c7c474c3   Christoph Hellwig   make generic_acl ...
1700
1701
  	&generic_acl_access_handler,
  	&generic_acl_default_handler,
b09e0fa4b   Eric Paris   tmpfs: implement ...
1702
  #endif
39f0247d3   Andreas Gruenbacher   [PATCH] Access Co...
1703
1704
  	NULL
  };
b09e0fa4b   Eric Paris   tmpfs: implement ...
1705
1706
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
  
  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...
1826
  static const struct inode_operations shmem_short_symlink_operations = {
b09e0fa4b   Eric Paris   tmpfs: implement ...
1827
  	.readlink	= generic_readlink,
69f07ec93   Hugh Dickins   tmpfs: use kmemdu...
1828
  	.follow_link	= shmem_follow_short_symlink,
b09e0fa4b   Eric Paris   tmpfs: implement ...
1829
1830
1831
1832
1833
1834
1835
1836
1837
1838
1839
1840
1841
1842
1843
1844
1845
  #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...
1846
  #endif
b09e0fa4b   Eric Paris   tmpfs: implement ...
1847
  };
39f0247d3   Andreas Gruenbacher   [PATCH] Access Co...
1848

91828a405   David M. Grimes   [PATCH] knfsd: ad...
1849
1850
1851
1852
1853
1854
1855
1856
1857
1858
1859
1860
  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...
1861
1862
  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...
1863
  {
91828a405   David M. Grimes   [PATCH] knfsd: ad...
1864
  	struct inode *inode;
480b116c9   Christoph Hellwig   shmem: new export...
1865
1866
1867
1868
1869
1870
  	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...
1871

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

1d3382cbf   Al Viro   new helper: inode...
1890
  	if (inode_unhashed(inode)) {
91828a405   David M. Grimes   [PATCH] knfsd: ad...
1891
1892
1893
1894
1895
1896
1897
  		/* 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...
1898
  		if (inode_unhashed(inode))
91828a405   David M. Grimes   [PATCH] knfsd: ad...
1899
1900
1901
1902
1903
1904
1905
1906
1907
1908
1909
1910
  			__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...
1911
  static const struct export_operations shmem_export_ops = {
91828a405   David M. Grimes   [PATCH] knfsd: ad...
1912
  	.get_parent     = shmem_get_parent,
91828a405   David M. Grimes   [PATCH] knfsd: ad...
1913
  	.encode_fh      = shmem_encode_fh,
480b116c9   Christoph Hellwig   shmem: new export...
1914
  	.fh_to_dentry	= shmem_fh_to_dentry,
91828a405   David M. Grimes   [PATCH] knfsd: ad...
1915
  };
680d794ba   akpm@linux-foundation.org   mount options: fi...
1916
1917
  static int shmem_parse_options(char *options, struct shmem_sb_info *sbinfo,
  			       bool remount)
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
1918
1919
  {
  	char *this_char, *value, *rest;
b00dc3ad7   Hugh Dickins   [PATCH] tmpfs: fi...
1920
1921
1922
1923
1924
1925
1926
1927
1928
1929
1930
1931
1932
1933
1934
1935
1936
  	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
1937
1938
1939
1940
1941
1942
1943
1944
1945
1946
1947
1948
1949
1950
1951
1952
1953
1954
1955
1956
1957
1958
1959
  		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...
1960
1961
  			sbinfo->max_blocks =
  				DIV_ROUND_UP(size, PAGE_CACHE_SIZE);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
1962
  		} else if (!strcmp(this_char,"nr_blocks")) {
680d794ba   akpm@linux-foundation.org   mount options: fi...
1963
  			sbinfo->max_blocks = memparse(value, &rest);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
1964
1965
1966
  			if (*rest)
  				goto bad_val;
  		} else if (!strcmp(this_char,"nr_inodes")) {
680d794ba   akpm@linux-foundation.org   mount options: fi...
1967
  			sbinfo->max_inodes = memparse(value, &rest);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
1968
1969
1970
  			if (*rest)
  				goto bad_val;
  		} else if (!strcmp(this_char,"mode")) {
680d794ba   akpm@linux-foundation.org   mount options: fi...
1971
  			if (remount)
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
1972
  				continue;
680d794ba   akpm@linux-foundation.org   mount options: fi...
1973
  			sbinfo->mode = simple_strtoul(value, &rest, 8) & 07777;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
1974
1975
1976
  			if (*rest)
  				goto bad_val;
  		} else if (!strcmp(this_char,"uid")) {
680d794ba   akpm@linux-foundation.org   mount options: fi...
1977
  			if (remount)
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
1978
  				continue;
680d794ba   akpm@linux-foundation.org   mount options: fi...
1979
  			sbinfo->uid = simple_strtoul(value, &rest, 0);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
1980
1981
1982
  			if (*rest)
  				goto bad_val;
  		} else if (!strcmp(this_char,"gid")) {
680d794ba   akpm@linux-foundation.org   mount options: fi...
1983
  			if (remount)
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
1984
  				continue;
680d794ba   akpm@linux-foundation.org   mount options: fi...
1985
  			sbinfo->gid = simple_strtoul(value, &rest, 0);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
1986
1987
  			if (*rest)
  				goto bad_val;
7339ff830   Robin Holt   [PATCH] Add tmpfs...
1988
  		} else if (!strcmp(this_char,"mpol")) {
71fe804b6   Lee Schermerhorn   mempolicy: use st...
1989
  			if (mpol_parse_str(value, &sbinfo->mpol, 1))
7339ff830   Robin Holt   [PATCH] Add tmpfs...
1990
  				goto bad_val;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
1991
1992
1993
1994
1995
1996
1997
1998
1999
2000
2001
2002
2003
2004
2005
2006
2007
2008
2009
2010
  		} 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...
2011
  	struct shmem_sb_info config = *sbinfo;
0edd73b33   Hugh Dickins   [PATCH] shmem: re...
2012
2013
  	unsigned long inodes;
  	int error = -EINVAL;
680d794ba   akpm@linux-foundation.org   mount options: fi...
2014
  	if (shmem_parse_options(data, &config, true))
0edd73b33   Hugh Dickins   [PATCH] shmem: re...
2015
  		return error;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
2016

0edd73b33   Hugh Dickins   [PATCH] shmem: re...
2017
  	spin_lock(&sbinfo->stat_lock);
0edd73b33   Hugh Dickins   [PATCH] shmem: re...
2018
  	inodes = sbinfo->max_inodes - sbinfo->free_inodes;
7e496299d   Tim Chen   tmpfs: make tmpfs...
2019
  	if (percpu_counter_compare(&sbinfo->used_blocks, config.max_blocks) > 0)
0edd73b33   Hugh Dickins   [PATCH] shmem: re...
2020
  		goto out;
680d794ba   akpm@linux-foundation.org   mount options: fi...
2021
  	if (config.max_inodes < inodes)
0edd73b33   Hugh Dickins   [PATCH] shmem: re...
2022
2023
  		goto out;
  	/*
54af60421   Hugh Dickins   tmpfs: convert sh...
2024
  	 * Those tests disallow limited->unlimited while any are in use;
0edd73b33   Hugh Dickins   [PATCH] shmem: re...
2025
2026
2027
  	 * 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...
2028
  	if (config.max_blocks && !sbinfo->max_blocks)
0edd73b33   Hugh Dickins   [PATCH] shmem: re...
2029
  		goto out;
680d794ba   akpm@linux-foundation.org   mount options: fi...
2030
  	if (config.max_inodes && !sbinfo->max_inodes)
0edd73b33   Hugh Dickins   [PATCH] shmem: re...
2031
2032
2033
  		goto out;
  
  	error = 0;
680d794ba   akpm@linux-foundation.org   mount options: fi...
2034
  	sbinfo->max_blocks  = config.max_blocks;
680d794ba   akpm@linux-foundation.org   mount options: fi...
2035
2036
  	sbinfo->max_inodes  = config.max_inodes;
  	sbinfo->free_inodes = config.max_inodes - inodes;
71fe804b6   Lee Schermerhorn   mempolicy: use st...
2037
2038
2039
  
  	mpol_put(sbinfo->mpol);
  	sbinfo->mpol        = config.mpol;	/* transfers initial ref */
0edd73b33   Hugh Dickins   [PATCH] shmem: re...
2040
2041
2042
  out:
  	spin_unlock(&sbinfo->stat_lock);
  	return error;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
2043
  }
680d794ba   akpm@linux-foundation.org   mount options: fi...
2044

34c80b1d9   Al Viro   vfs: switch ->sho...
2045
  static int shmem_show_options(struct seq_file *seq, struct dentry *root)
680d794ba   akpm@linux-foundation.org   mount options: fi...
2046
  {
34c80b1d9   Al Viro   vfs: switch ->sho...
2047
  	struct shmem_sb_info *sbinfo = SHMEM_SB(root->d_sb);
680d794ba   akpm@linux-foundation.org   mount options: fi...
2048
2049
2050
2051
2052
2053
2054
  
  	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))
09208d150   Al Viro   shmem, ramfs: pro...
2055
  		seq_printf(seq, ",mode=%03ho", sbinfo->mode);
680d794ba   akpm@linux-foundation.org   mount options: fi...
2056
2057
2058
2059
  	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...
2060
  	shmem_show_mpol(seq, sbinfo->mpol);
680d794ba   akpm@linux-foundation.org   mount options: fi...
2061
2062
2063
  	return 0;
  }
  #endif /* CONFIG_TMPFS */
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
2064
2065
2066
  
  static void shmem_put_super(struct super_block *sb)
  {
602586a83   Hugh Dickins   shmem: put_super ...
2067
2068
2069
2070
  	struct shmem_sb_info *sbinfo = SHMEM_SB(sb);
  
  	percpu_counter_destroy(&sbinfo->used_blocks);
  	kfree(sbinfo);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
2071
2072
  	sb->s_fs_info = NULL;
  }
2b2af54a5   Kay Sievers   Driver Core: devt...
2073
  int shmem_fill_super(struct super_block *sb, void *data, int silent)
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
2074
2075
2076
  {
  	struct inode *inode;
  	struct dentry *root;
0edd73b33   Hugh Dickins   [PATCH] shmem: re...
2077
  	struct shmem_sb_info *sbinfo;
680d794ba   akpm@linux-foundation.org   mount options: fi...
2078
2079
2080
  	int err = -ENOMEM;
  
  	/* Round up to L1_CACHE_BYTES to resist false sharing */
425fbf047   Pekka Enberg   shmem: initialize...
2081
  	sbinfo = kzalloc(max((int)sizeof(struct shmem_sb_info),
680d794ba   akpm@linux-foundation.org   mount options: fi...
2082
2083
2084
  				L1_CACHE_BYTES), GFP_KERNEL);
  	if (!sbinfo)
  		return -ENOMEM;
680d794ba   akpm@linux-foundation.org   mount options: fi...
2085
  	sbinfo->mode = S_IRWXUGO | S_ISVTX;
76aac0e9a   David Howells   CRED: Wrap task c...
2086
2087
  	sbinfo->uid = current_fsuid();
  	sbinfo->gid = current_fsgid();
680d794ba   akpm@linux-foundation.org   mount options: fi...
2088
  	sb->s_fs_info = sbinfo;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
2089

0edd73b33   Hugh Dickins   [PATCH] shmem: re...
2090
  #ifdef CONFIG_TMPFS
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
2091
2092
2093
2094
2095
2096
  	/*
  	 * 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...
2097
2098
2099
2100
2101
2102
  		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
2103
  	}
91828a405   David M. Grimes   [PATCH] knfsd: ad...
2104
  	sb->s_export_op = &shmem_export_ops;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
2105
2106
2107
  #else
  	sb->s_flags |= MS_NOUSER;
  #endif
0edd73b33   Hugh Dickins   [PATCH] shmem: re...
2108
  	spin_lock_init(&sbinfo->stat_lock);
602586a83   Hugh Dickins   shmem: put_super ...
2109
2110
  	if (percpu_counter_init(&sbinfo->used_blocks, 0))
  		goto failed;
680d794ba   akpm@linux-foundation.org   mount options: fi...
2111
  	sbinfo->free_inodes = sbinfo->max_inodes;
0edd73b33   Hugh Dickins   [PATCH] shmem: re...
2112

285b2c4fd   Hugh Dickins   tmpfs: demolish o...
2113
  	sb->s_maxbytes = MAX_LFS_FILESIZE;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
2114
2115
2116
2117
  	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...
2118
  	sb->s_time_gran = 1;
b09e0fa4b   Eric Paris   tmpfs: implement ...
2119
  #ifdef CONFIG_TMPFS_XATTR
39f0247d3   Andreas Gruenbacher   [PATCH] Access Co...
2120
  	sb->s_xattr = shmem_xattr_handlers;
b09e0fa4b   Eric Paris   tmpfs: implement ...
2121
2122
  #endif
  #ifdef CONFIG_TMPFS_POSIX_ACL
39f0247d3   Andreas Gruenbacher   [PATCH] Access Co...
2123
2124
  	sb->s_flags |= MS_POSIXACL;
  #endif
0edd73b33   Hugh Dickins   [PATCH] shmem: re...
2125

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

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

41ffe5d5c   Hugh Dickins   tmpfs: miscellane...
2293
2294
  	shm_mnt = vfs_kern_mount(&shmem_fs_type, MS_NOUSER,
  				 shmem_fs_type.name, NULL);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
2295
2296
2297
2298
2299
2300
2301
2302
2303
  	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...
2304
  	unregister_filesystem(&shmem_fs_type);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
2305
  out2:
41ffe5d5c   Hugh Dickins   tmpfs: miscellane...
2306
  	shmem_destroy_inodecache();
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
2307
  out3:
e0bf68dde   Peter Zijlstra   mm: bdi init hooks
2308
2309
  	bdi_destroy(&shmem_backing_dev_info);
  out4:
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
2310
2311
2312
  	shm_mnt = ERR_PTR(error);
  	return error;
  }
853ac43ab   Matt Mackall   shmem: unify regu...
2313
2314
2315
2316
2317
2318
2319
2320
2321
2322
2323
2324
2325
  
  #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...
2326
  static struct file_system_type shmem_fs_type = {
853ac43ab   Matt Mackall   shmem: unify regu...
2327
  	.name		= "tmpfs",
3c26ff6e4   Al Viro   convert get_sb_no...
2328
  	.mount		= ramfs_mount,
853ac43ab   Matt Mackall   shmem: unify regu...
2329
2330
  	.kill_sb	= kill_litter_super,
  };
41ffe5d5c   Hugh Dickins   tmpfs: miscellane...
2331
  int __init shmem_init(void)
853ac43ab   Matt Mackall   shmem: unify regu...
2332
  {
41ffe5d5c   Hugh Dickins   tmpfs: miscellane...
2333
  	BUG_ON(register_filesystem(&shmem_fs_type) != 0);
853ac43ab   Matt Mackall   shmem: unify regu...
2334

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

467118102   Randy Dunlap   mm/shmem and tiny...
2363
  /**
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
2364
   * shmem_file_setup - get an unlinked file living in tmpfs
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
2365
2366
   * @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...
2367
   * @flags: VM_NORESERVE suppresses pre-accounting of the entire object size
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
2368
   */
168f5ac66   Sergei Trofimovich   mm cleanup: shmem...
2369
  struct file *shmem_file_setup(const char *name, loff_t size, unsigned long flags)
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
2370
2371
2372
2373
  {
  	int error;
  	struct file *file;
  	struct inode *inode;
2c48b9c45   Al Viro   switch alloc_file...
2374
2375
  	struct path path;
  	struct dentry *root;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
2376
2377
2378
2379
  	struct qstr this;
  
  	if (IS_ERR(shm_mnt))
  		return (void *)shm_mnt;
285b2c4fd   Hugh Dickins   tmpfs: demolish o...
2380
  	if (size < 0 || size > MAX_LFS_FILESIZE)
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
2381
2382
2383
2384
2385
2386
2387
2388
2389
2390
  		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...
2391
2392
  	path.dentry = d_alloc(root, &this);
  	if (!path.dentry)
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
2393
  		goto put_memory;
2c48b9c45   Al Viro   switch alloc_file...
2394
  	path.mnt = mntget(shm_mnt);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
2395

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

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

467118102   Randy Dunlap   mm/shmem and tiny...
2424
  /**
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
2425
   * shmem_zero_setup - setup a shared anonymous mapping
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
2426
2427
2428
2429
2430
2431
2432
2433
2434
2435
2436
2437
2438
2439
2440
   * @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...
2441
  	vma->vm_flags |= VM_CAN_NONLINEAR;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
2442
2443
  	return 0;
  }
d9d90e5eb   Hugh Dickins   tmpfs: add shmem_...
2444
2445
2446
2447
2448
2449
2450
2451
2452
2453
2454
2455
2456
  
  /**
   * 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...
2457
2458
   * 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_...
2459
2460
2461
2462
   */
  struct page *shmem_read_mapping_page_gfp(struct address_space *mapping,
  					 pgoff_t index, gfp_t gfp)
  {
68da9f055   Hugh Dickins   tmpfs: pass gfp t...
2463
2464
  #ifdef CONFIG_SHMEM
  	struct inode *inode = mapping->host;
9276aad6c   Hugh Dickins   tmpfs: remove_shm...
2465
  	struct page *page;
68da9f055   Hugh Dickins   tmpfs: pass gfp t...
2466
2467
2468
2469
2470
2471
2472
2473
2474
2475
2476
2477
2478
  	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_...
2479
  	return read_cache_page_gfp(mapping, index, gfp);
68da9f055   Hugh Dickins   tmpfs: pass gfp t...
2480
  #endif
d9d90e5eb   Hugh Dickins   tmpfs: add shmem_...
2481
2482
  }
  EXPORT_SYMBOL_GPL(shmem_read_mapping_page_gfp);