Blame view

mm/shmem.c 66 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
  	return (flags & VM_NORESERVE) ?
191c54244   Al Viro   mm: collapse secu...
122
  		0 : security_vm_enough_memory_mm(current->mm, 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
  	return (flags & VM_NORESERVE) ?
191c54244   Al Viro   mm: collapse secu...
140
  		security_vm_enough_memory_mm(current->mm, 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
  		}
  		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.
   */
245132643   Hugh Dickins   SHM_UNLOCK: fix U...
370
  static void shmem_deswap_pagevec(struct pagevec *pvec)
7a5d0fbb2   Hugh Dickins   tmpfs: convert sh...
371
372
373
374
375
376
377
378
379
  {
  	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;
245132643   Hugh Dickins   SHM_UNLOCK: fix U...
380
381
382
383
384
385
386
387
388
389
390
391
392
393
394
395
396
397
398
399
400
401
402
403
404
405
406
407
408
409
  }
  
  /*
   * SysV IPC SHM_UNLOCK restore Unevictable pages to their evictable lists.
   */
  void shmem_unlock_mapping(struct address_space *mapping)
  {
  	struct pagevec pvec;
  	pgoff_t indices[PAGEVEC_SIZE];
  	pgoff_t index = 0;
  
  	pagevec_init(&pvec, 0);
  	/*
  	 * Minor point, but we might as well stop if someone else SHM_LOCKs it.
  	 */
  	while (!mapping_unevictable(mapping)) {
  		/*
  		 * Avoid pagevec_lookup(): find_get_pages() returns 0 as if it
  		 * has finished, if it hits a row of PAGEVEC_SIZE swap entries.
  		 */
  		pvec.nr = shmem_find_get_pages_and_swap(mapping, index,
  					PAGEVEC_SIZE, pvec.pages, indices);
  		if (!pvec.nr)
  			break;
  		index = indices[pvec.nr - 1] + 1;
  		shmem_deswap_pagevec(&pvec);
  		check_move_unevictable_pages(pvec.pages, pvec.nr);
  		pagevec_release(&pvec);
  		cond_resched();
  	}
7a5d0fbb2   Hugh Dickins   tmpfs: convert sh...
410
411
412
413
414
  }
  
  /*
   * Remove range of pages and swap entries from radix tree, and free them.
   */
285b2c4fd   Hugh Dickins   tmpfs: demolish o...
415
  void shmem_truncate_range(struct inode *inode, loff_t lstart, loff_t lend)
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
416
  {
285b2c4fd   Hugh Dickins   tmpfs: demolish o...
417
  	struct address_space *mapping = inode->i_mapping;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
418
  	struct shmem_inode_info *info = SHMEM_I(inode);
285b2c4fd   Hugh Dickins   tmpfs: demolish o...
419
  	pgoff_t start = (lstart + PAGE_CACHE_SIZE - 1) >> PAGE_CACHE_SHIFT;
bda97eab0   Hugh Dickins   tmpfs: copy trunc...
420
  	unsigned partial = lstart & (PAGE_CACHE_SIZE - 1);
285b2c4fd   Hugh Dickins   tmpfs: demolish o...
421
  	pgoff_t end = (lend >> PAGE_CACHE_SHIFT);
bda97eab0   Hugh Dickins   tmpfs: copy trunc...
422
  	struct pagevec pvec;
7a5d0fbb2   Hugh Dickins   tmpfs: convert sh...
423
424
  	pgoff_t indices[PAGEVEC_SIZE];
  	long nr_swaps_freed = 0;
285b2c4fd   Hugh Dickins   tmpfs: demolish o...
425
  	pgoff_t index;
bda97eab0   Hugh Dickins   tmpfs: copy trunc...
426
427
428
429
430
431
  	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...
432
433
434
435
436
437
  	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...
438
439
440
  		mem_cgroup_uncharge_start();
  		for (i = 0; i < pagevec_count(&pvec); i++) {
  			struct page *page = pvec.pages[i];
7a5d0fbb2   Hugh Dickins   tmpfs: convert sh...
441
  			index = indices[i];
bda97eab0   Hugh Dickins   tmpfs: copy trunc...
442
443
  			if (index > end)
  				break;
7a5d0fbb2   Hugh Dickins   tmpfs: convert sh...
444
445
446
  			if (radix_tree_exceptional_entry(page)) {
  				nr_swaps_freed += !shmem_free_swap(mapping,
  								index, page);
bda97eab0   Hugh Dickins   tmpfs: copy trunc...
447
  				continue;
7a5d0fbb2   Hugh Dickins   tmpfs: convert sh...
448
449
450
  			}
  
  			if (!trylock_page(page))
bda97eab0   Hugh Dickins   tmpfs: copy trunc...
451
  				continue;
7a5d0fbb2   Hugh Dickins   tmpfs: convert sh...
452
453
454
  			if (page->mapping == mapping) {
  				VM_BUG_ON(PageWriteback(page));
  				truncate_inode_page(mapping, page);
bda97eab0   Hugh Dickins   tmpfs: copy trunc...
455
  			}
bda97eab0   Hugh Dickins   tmpfs: copy trunc...
456
457
  			unlock_page(page);
  		}
245132643   Hugh Dickins   SHM_UNLOCK: fix U...
458
459
  		shmem_deswap_pagevec(&pvec);
  		pagevec_release(&pvec);
bda97eab0   Hugh Dickins   tmpfs: copy trunc...
460
461
462
463
  		mem_cgroup_uncharge_end();
  		cond_resched();
  		index++;
  	}
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
464

bda97eab0   Hugh Dickins   tmpfs: copy trunc...
465
466
467
468
469
470
471
472
473
474
475
476
477
478
  	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...
479
480
481
482
  		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...
483
484
485
486
487
  			if (index == start)
  				break;
  			index = start;
  			continue;
  		}
7a5d0fbb2   Hugh Dickins   tmpfs: convert sh...
488
  		if (index == start && indices[0] > end) {
245132643   Hugh Dickins   SHM_UNLOCK: fix U...
489
490
  			shmem_deswap_pagevec(&pvec);
  			pagevec_release(&pvec);
bda97eab0   Hugh Dickins   tmpfs: copy trunc...
491
492
493
494
495
  			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...
496
  			index = indices[i];
bda97eab0   Hugh Dickins   tmpfs: copy trunc...
497
498
  			if (index > end)
  				break;
7a5d0fbb2   Hugh Dickins   tmpfs: convert sh...
499
500
501
502
503
  			if (radix_tree_exceptional_entry(page)) {
  				nr_swaps_freed += !shmem_free_swap(mapping,
  								index, page);
  				continue;
  			}
bda97eab0   Hugh Dickins   tmpfs: copy trunc...
504
  			lock_page(page);
7a5d0fbb2   Hugh Dickins   tmpfs: convert sh...
505
506
507
508
  			if (page->mapping == mapping) {
  				VM_BUG_ON(PageWriteback(page));
  				truncate_inode_page(mapping, page);
  			}
bda97eab0   Hugh Dickins   tmpfs: copy trunc...
509
510
  			unlock_page(page);
  		}
245132643   Hugh Dickins   SHM_UNLOCK: fix U...
511
512
  		shmem_deswap_pagevec(&pvec);
  		pagevec_release(&pvec);
bda97eab0   Hugh Dickins   tmpfs: copy trunc...
513
514
515
  		mem_cgroup_uncharge_end();
  		index++;
  	}
94c1e62df   Hugh Dickins   tmpfs: take contr...
516

1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
517
  	spin_lock(&info->lock);
7a5d0fbb2   Hugh Dickins   tmpfs: convert sh...
518
  	info->swapped -= nr_swaps_freed;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
519
520
  	shmem_recalc_inode(inode);
  	spin_unlock(&info->lock);
285b2c4fd   Hugh Dickins   tmpfs: demolish o...
521
  	inode->i_ctime = inode->i_mtime = CURRENT_TIME;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
522
  }
94c1e62df   Hugh Dickins   tmpfs: take contr...
523
  EXPORT_SYMBOL_GPL(shmem_truncate_range);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
524

94c1e62df   Hugh Dickins   tmpfs: take contr...
525
  static int shmem_setattr(struct dentry *dentry, struct iattr *attr)
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
526
527
  {
  	struct inode *inode = dentry->d_inode;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
528
  	int error;
db78b877f   Christoph Hellwig   always call inode...
529
530
531
  	error = inode_change_ok(inode, attr);
  	if (error)
  		return error;
94c1e62df   Hugh Dickins   tmpfs: take contr...
532
533
534
  	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...
535

94c1e62df   Hugh Dickins   tmpfs: take contr...
536
537
538
539
540
541
542
543
544
545
546
  		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
547
  	}
db78b877f   Christoph Hellwig   always call inode...
548
  	setattr_copy(inode, attr);
39f0247d3   Andreas Gruenbacher   [PATCH] Access Co...
549
  #ifdef CONFIG_TMPFS_POSIX_ACL
db78b877f   Christoph Hellwig   always call inode...
550
  	if (attr->ia_valid & ATTR_MODE)
1c7c474c3   Christoph Hellwig   make generic_acl ...
551
  		error = generic_acl_chmod(inode);
39f0247d3   Andreas Gruenbacher   [PATCH] Access Co...
552
  #endif
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
553
554
  	return error;
  }
1f895f75d   Al Viro   switch shmem.c to...
555
  static void shmem_evict_inode(struct inode *inode)
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
556
  {
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
557
  	struct shmem_inode_info *info = SHMEM_I(inode);
b09e0fa4b   Eric Paris   tmpfs: implement ...
558
  	struct shmem_xattr *xattr, *nxattr;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
559

3889e6e76   npiggin@suse.de   tmpfs: convert to...
560
  	if (inode->i_mapping->a_ops == &shmem_aops) {
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
561
562
  		shmem_unacct_size(info->flags, inode->i_size);
  		inode->i_size = 0;
3889e6e76   npiggin@suse.de   tmpfs: convert to...
563
  		shmem_truncate_range(inode, 0, (loff_t)-1);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
564
  		if (!list_empty(&info->swaplist)) {
cb5f7b9a4   Hugh Dickins   tmpfs: make shmem...
565
  			mutex_lock(&shmem_swaplist_mutex);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
566
  			list_del_init(&info->swaplist);
cb5f7b9a4   Hugh Dickins   tmpfs: make shmem...
567
  			mutex_unlock(&shmem_swaplist_mutex);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
568
  		}
69f07ec93   Hugh Dickins   tmpfs: use kmemdu...
569
570
  	} else
  		kfree(info->symlink);
b09e0fa4b   Eric Paris   tmpfs: implement ...
571
572
573
574
575
  
  	list_for_each_entry_safe(xattr, nxattr, &info->xattr_list, list) {
  		kfree(xattr->name);
  		kfree(xattr);
  	}
0edd73b33   Hugh Dickins   [PATCH] shmem: re...
576
  	BUG_ON(inode->i_blocks);
5b04c6890   Pavel Emelyanov   shmem: factor out...
577
  	shmem_free_inode(inode->i_sb);
dbd5768f8   Jan Kara   vfs: Rename end_w...
578
  	clear_inode(inode);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
579
  }
46f65ec15   Hugh Dickins   tmpfs: convert sh...
580
581
582
  /*
   * If swap found in inode, free it and move page from swapcache to filecache.
   */
41ffe5d5c   Hugh Dickins   tmpfs: miscellane...
583
584
  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
585
  {
285b2c4fd   Hugh Dickins   tmpfs: demolish o...
586
  	struct address_space *mapping = info->vfs_inode.i_mapping;
46f65ec15   Hugh Dickins   tmpfs: convert sh...
587
  	void *radswap;
41ffe5d5c   Hugh Dickins   tmpfs: miscellane...
588
  	pgoff_t index;
d9fe526a8   Hugh Dickins   tmpfs: allow file...
589
  	int error;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
590

46f65ec15   Hugh Dickins   tmpfs: convert sh...
591
  	radswap = swp_to_radix_entry(swap);
e504f3fdd   Hugh Dickins   tmpfs radix_tree:...
592
  	index = radix_tree_locate_item(&mapping->page_tree, radswap);
46f65ec15   Hugh Dickins   tmpfs: convert sh...
593
  	if (index == -1)
285b2c4fd   Hugh Dickins   tmpfs: demolish o...
594
  		return 0;
2e0e26c76   Hugh Dickins   tmpfs: open a win...
595

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

d13d14430   KAMEZAWA Hiroyuki   memcg: handle swa...
605
  	/*
778dd893a   Hugh Dickins   tmpfs: fix race b...
606
607
608
  	 * 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...
609
  	 */
46f65ec15   Hugh Dickins   tmpfs: convert sh...
610
611
  	error = shmem_add_to_page_cache(page, mapping, index,
  						GFP_NOWAIT, radswap);
778dd893a   Hugh Dickins   tmpfs: fix race b...
612
  	/* which does mem_cgroup_uncharge_cache_page on error */
69029cd55   KAMEZAWA Hiroyuki   memcg: remove ref...
613

48f170fb7   Hugh Dickins   tmpfs: simplify u...
614
  	if (error != -ENOMEM) {
46f65ec15   Hugh Dickins   tmpfs: convert sh...
615
616
617
618
  		/*
  		 * 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 ...
619
620
  		delete_from_swap_cache(page);
  		set_page_dirty(page);
46f65ec15   Hugh Dickins   tmpfs: convert sh...
621
622
623
624
625
626
  		if (!error) {
  			spin_lock(&info->lock);
  			info->swapped--;
  			spin_unlock(&info->lock);
  			swap_free(swap);
  		}
2e0e26c76   Hugh Dickins   tmpfs: open a win...
627
  		error = 1;	/* not an error, but entry was found */
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
628
  	}
2e0e26c76   Hugh Dickins   tmpfs: open a win...
629
  	return error;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
630
631
632
  }
  
  /*
46f65ec15   Hugh Dickins   tmpfs: convert sh...
633
   * Search through swapped inodes to find and replace swap by page.
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
634
   */
41ffe5d5c   Hugh Dickins   tmpfs: miscellane...
635
  int shmem_unuse(swp_entry_t swap, struct page *page)
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
636
  {
41ffe5d5c   Hugh Dickins   tmpfs: miscellane...
637
  	struct list_head *this, *next;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
638
639
  	struct shmem_inode_info *info;
  	int found = 0;
778dd893a   Hugh Dickins   tmpfs: fix race b...
640
641
642
643
644
645
  	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...
646
647
648
649
  	 */
  	error = mem_cgroup_cache_charge(page, current->mm, GFP_KERNEL);
  	if (error)
  		goto out;
46f65ec15   Hugh Dickins   tmpfs: convert sh...
650
  	/* No radix_tree_preload: swap entry keeps a place for page in tree */
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
651

cb5f7b9a4   Hugh Dickins   tmpfs: make shmem...
652
  	mutex_lock(&shmem_swaplist_mutex);
41ffe5d5c   Hugh Dickins   tmpfs: miscellane...
653
654
  	list_for_each_safe(this, next, &shmem_swaplist) {
  		info = list_entry(this, struct shmem_inode_info, swaplist);
285b2c4fd   Hugh Dickins   tmpfs: demolish o...
655
  		if (info->swapped)
41ffe5d5c   Hugh Dickins   tmpfs: miscellane...
656
  			found = shmem_unuse_inode(info, swap, page);
6922c0c7a   Hugh Dickins   tmpfs: convert sh...
657
658
  		else
  			list_del_init(&info->swaplist);
cb5f7b9a4   Hugh Dickins   tmpfs: make shmem...
659
  		cond_resched();
2e0e26c76   Hugh Dickins   tmpfs: open a win...
660
  		if (found)
778dd893a   Hugh Dickins   tmpfs: fix race b...
661
  			break;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
662
  	}
cb5f7b9a4   Hugh Dickins   tmpfs: make shmem...
663
  	mutex_unlock(&shmem_swaplist_mutex);
778dd893a   Hugh Dickins   tmpfs: fix race b...
664

778dd893a   Hugh Dickins   tmpfs: fix race b...
665
666
667
668
669
  	if (!found)
  		mem_cgroup_uncharge_cache_page(page);
  	if (found < 0)
  		error = found;
  out:
aaa468653   Hugh Dickins   swap_info: note S...
670
671
  	unlock_page(page);
  	page_cache_release(page);
778dd893a   Hugh Dickins   tmpfs: fix race b...
672
  	return error;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
673
674
675
676
677
678
679
680
  }
  
  /*
   * 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
681
  	struct address_space *mapping;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
682
  	struct inode *inode;
6922c0c7a   Hugh Dickins   tmpfs: convert sh...
683
684
  	swp_entry_t swap;
  	pgoff_t index;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
685
686
  
  	BUG_ON(!PageLocked(page));
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
687
688
689
690
691
692
  	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...
693
  	if (!total_swap_pages)
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
694
  		goto redirty;
d9fe526a8   Hugh Dickins   tmpfs: allow file...
695
696
697
  	/*
  	 * 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...
698
  	 * might use ->writepage of its underlying filesystem, in which case
d9fe526a8   Hugh Dickins   tmpfs: allow file...
699
  	 * tmpfs should write out to swap only in response to memory pressure,
48f170fb7   Hugh Dickins   tmpfs: simplify u...
700
  	 * and not for the writeback threads or sync.
d9fe526a8   Hugh Dickins   tmpfs: allow file...
701
  	 */
48f170fb7   Hugh Dickins   tmpfs: simplify u...
702
703
704
705
706
707
708
  	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...
709

b1dea800a   Hugh Dickins   tmpfs: fix race b...
710
711
  	/*
  	 * Add inode to shmem_unuse()'s list of swapped-out inodes,
6922c0c7a   Hugh Dickins   tmpfs: convert sh...
712
713
  	 * 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...
714
  	 * the inode from eviction.  But don't unlock the mutex until
6922c0c7a   Hugh Dickins   tmpfs: convert sh...
715
716
  	 * 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...
717
  	 */
48f170fb7   Hugh Dickins   tmpfs: simplify u...
718
719
720
  	mutex_lock(&shmem_swaplist_mutex);
  	if (list_empty(&info->swaplist))
  		list_add_tail(&info->swaplist, &shmem_swaplist);
b1dea800a   Hugh Dickins   tmpfs: fix race b...
721

48f170fb7   Hugh Dickins   tmpfs: simplify u...
722
  	if (add_to_swap_cache(page, swap, GFP_ATOMIC) == 0) {
aaa468653   Hugh Dickins   swap_info: note S...
723
  		swap_shmem_alloc(swap);
6922c0c7a   Hugh Dickins   tmpfs: convert sh...
724
725
726
727
728
  		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...
729
  		spin_unlock(&info->lock);
6922c0c7a   Hugh Dickins   tmpfs: convert sh...
730
731
  
  		mutex_unlock(&shmem_swaplist_mutex);
d9fe526a8   Hugh Dickins   tmpfs: allow file...
732
  		BUG_ON(page_mapped(page));
9fab5619b   Hugh Dickins   shmem: writepage ...
733
  		swap_writepage(page, wbc);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
734
735
  		return 0;
  	}
6922c0c7a   Hugh Dickins   tmpfs: convert sh...
736
  	mutex_unlock(&shmem_swaplist_mutex);
cb4b86ba4   KAMEZAWA Hiroyuki   mm: add swap cach...
737
  	swapcache_free(swap, NULL);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
738
739
  redirty:
  	set_page_dirty(page);
d9fe526a8   Hugh Dickins   tmpfs: allow file...
740
741
742
743
  	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
744
745
746
  }
  
  #ifdef CONFIG_NUMA
680d794ba   akpm@linux-foundation.org   mount options: fi...
747
  #ifdef CONFIG_TMPFS
71fe804b6   Lee Schermerhorn   mempolicy: use st...
748
  static void shmem_show_mpol(struct seq_file *seq, struct mempolicy *mpol)
680d794ba   akpm@linux-foundation.org   mount options: fi...
749
  {
095f1fc4e   Lee Schermerhorn   mempolicy: rework...
750
  	char buffer[64];
680d794ba   akpm@linux-foundation.org   mount options: fi...
751

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

71fe804b6   Lee Schermerhorn   mempolicy: use st...
755
  	mpol_to_str(buffer, sizeof(buffer), mpol, 1);
095f1fc4e   Lee Schermerhorn   mempolicy: rework...
756
757
  
  	seq_printf(seq, ",mpol=%s", buffer);
680d794ba   akpm@linux-foundation.org   mount options: fi...
758
  }
71fe804b6   Lee Schermerhorn   mempolicy: use st...
759
760
761
762
763
764
765
766
767
768
769
770
  
  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...
771
  #endif /* CONFIG_TMPFS */
41ffe5d5c   Hugh Dickins   tmpfs: miscellane...
772
773
  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
774
  {
52cd3b074   Lee Schermerhorn   mempolicy: rework...
775
  	struct mempolicy mpol, *spol;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
776
  	struct vm_area_struct pvma;
52cd3b074   Lee Schermerhorn   mempolicy: rework...
777
  	spol = mpol_cond_copy(&mpol,
41ffe5d5c   Hugh Dickins   tmpfs: miscellane...
778
  			mpol_shared_policy_lookup(&info->policy, index));
52cd3b074   Lee Schermerhorn   mempolicy: rework...
779

1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
780
  	/* Create a pseudo vma that just contains the policy */
c4cc6d07b   Hugh Dickins   swapin_readahead:...
781
  	pvma.vm_start = 0;
41ffe5d5c   Hugh Dickins   tmpfs: miscellane...
782
  	pvma.vm_pgoff = index;
c4cc6d07b   Hugh Dickins   swapin_readahead:...
783
  	pvma.vm_ops = NULL;
52cd3b074   Lee Schermerhorn   mempolicy: rework...
784
  	pvma.vm_policy = spol;
41ffe5d5c   Hugh Dickins   tmpfs: miscellane...
785
  	return swapin_readahead(swap, gfp, &pvma, 0);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
786
  }
02098feaa   Hugh Dickins   swapin needs gfp_...
787
  static struct page *shmem_alloc_page(gfp_t gfp,
41ffe5d5c   Hugh Dickins   tmpfs: miscellane...
788
  			struct shmem_inode_info *info, pgoff_t index)
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
789
790
  {
  	struct vm_area_struct pvma;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
791

c4cc6d07b   Hugh Dickins   swapin_readahead:...
792
793
  	/* Create a pseudo vma that just contains the policy */
  	pvma.vm_start = 0;
41ffe5d5c   Hugh Dickins   tmpfs: miscellane...
794
  	pvma.vm_pgoff = index;
c4cc6d07b   Hugh Dickins   swapin_readahead:...
795
  	pvma.vm_ops = NULL;
41ffe5d5c   Hugh Dickins   tmpfs: miscellane...
796
  	pvma.vm_policy = mpol_shared_policy_lookup(&info->policy, index);
52cd3b074   Lee Schermerhorn   mempolicy: rework...
797
798
799
800
801
  
  	/*
  	 * alloc_page_vma() will drop the shared policy reference
  	 */
  	return alloc_page_vma(gfp, &pvma, 0);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
802
  }
680d794ba   akpm@linux-foundation.org   mount options: fi...
803
804
  #else /* !CONFIG_NUMA */
  #ifdef CONFIG_TMPFS
41ffe5d5c   Hugh Dickins   tmpfs: miscellane...
805
  static inline void shmem_show_mpol(struct seq_file *seq, struct mempolicy *mpol)
680d794ba   akpm@linux-foundation.org   mount options: fi...
806
807
808
  {
  }
  #endif /* CONFIG_TMPFS */
41ffe5d5c   Hugh Dickins   tmpfs: miscellane...
809
810
  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
811
  {
41ffe5d5c   Hugh Dickins   tmpfs: miscellane...
812
  	return swapin_readahead(swap, gfp, NULL, 0);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
813
  }
02098feaa   Hugh Dickins   swapin needs gfp_...
814
  static inline struct page *shmem_alloc_page(gfp_t gfp,
41ffe5d5c   Hugh Dickins   tmpfs: miscellane...
815
  			struct shmem_inode_info *info, pgoff_t index)
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
816
  {
e84e2e132   Hugh Dickins   tmpfs: restore mi...
817
  	return alloc_page(gfp);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
818
  }
680d794ba   akpm@linux-foundation.org   mount options: fi...
819
  #endif /* CONFIG_NUMA */
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
820

71fe804b6   Lee Schermerhorn   mempolicy: use st...
821
822
823
824
825
826
  #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
827
  /*
68da9f055   Hugh Dickins   tmpfs: pass gfp t...
828
   * shmem_getpage_gfp - find page in cache, or get from swap, or allocate
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
829
830
831
832
833
   *
   * 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...
834
  static int shmem_getpage_gfp(struct inode *inode, pgoff_t index,
68da9f055   Hugh Dickins   tmpfs: pass gfp t...
835
  	struct page **pagep, enum sgp_type sgp, gfp_t gfp, int *fault_type)
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
836
837
  {
  	struct address_space *mapping = inode->i_mapping;
54af60421   Hugh Dickins   tmpfs: convert sh...
838
  	struct shmem_inode_info *info;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
839
  	struct shmem_sb_info *sbinfo;
27ab70062   Hugh Dickins   tmpfs: simplify f...
840
  	struct page *page;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
841
842
  	swp_entry_t swap;
  	int error;
54af60421   Hugh Dickins   tmpfs: convert sh...
843
  	int once = 0;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
844

41ffe5d5c   Hugh Dickins   tmpfs: miscellane...
845
  	if (index > (MAX_LFS_FILESIZE >> PAGE_CACHE_SHIFT))
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
846
  		return -EFBIG;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
847
  repeat:
54af60421   Hugh Dickins   tmpfs: convert sh...
848
  	swap.val = 0;
41ffe5d5c   Hugh Dickins   tmpfs: miscellane...
849
  	page = find_lock_page(mapping, index);
54af60421   Hugh Dickins   tmpfs: convert sh...
850
851
852
853
854
855
856
857
858
859
860
861
  	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...
862
  		/*
27ab70062   Hugh Dickins   tmpfs: simplify f...
863
864
865
  		 * 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...
866
  		 */
54af60421   Hugh Dickins   tmpfs: convert sh...
867
868
869
  		BUG_ON(page && !PageUptodate(page));
  		*pagep = page;
  		return 0;
27ab70062   Hugh Dickins   tmpfs: simplify f...
870
871
872
  	}
  
  	/*
54af60421   Hugh Dickins   tmpfs: convert sh...
873
874
  	 * Fast cache lookup did not find it:
  	 * bring it back from swap or allocate.
27ab70062   Hugh Dickins   tmpfs: simplify f...
875
  	 */
54af60421   Hugh Dickins   tmpfs: convert sh...
876
877
  	info = SHMEM_I(inode);
  	sbinfo = SHMEM_SB(inode->i_sb);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
878

1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
879
880
  	if (swap.val) {
  		/* Look it up and read it in.. */
27ab70062   Hugh Dickins   tmpfs: simplify f...
881
882
  		page = lookup_swap_cache(swap);
  		if (!page) {
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
883
  			/* here we actually do the io */
68da9f055   Hugh Dickins   tmpfs: pass gfp t...
884
885
  			if (fault_type)
  				*fault_type |= VM_FAULT_MAJOR;
41ffe5d5c   Hugh Dickins   tmpfs: miscellane...
886
  			page = shmem_swapin(swap, gfp, info, index);
27ab70062   Hugh Dickins   tmpfs: simplify f...
887
  			if (!page) {
54af60421   Hugh Dickins   tmpfs: convert sh...
888
889
  				error = -ENOMEM;
  				goto failed;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
890
  			}
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
891
892
893
  		}
  
  		/* We have to do this with page locked to prevent races */
54af60421   Hugh Dickins   tmpfs: convert sh...
894
  		lock_page(page);
27ab70062   Hugh Dickins   tmpfs: simplify f...
895
  		if (!PageUptodate(page)) {
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
896
  			error = -EIO;
54af60421   Hugh Dickins   tmpfs: convert sh...
897
  			goto failed;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
898
  		}
54af60421   Hugh Dickins   tmpfs: convert sh...
899
900
901
902
903
904
905
906
907
  		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
908
  		}
27ab70062   Hugh Dickins   tmpfs: simplify f...
909

aa3b18955   Hugh Dickins   tmpfs: convert me...
910
911
912
913
914
  		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...
915
916
917
918
  		if (error)
  			goto failed;
  
  		spin_lock(&info->lock);
285b2c4fd   Hugh Dickins   tmpfs: demolish o...
919
  		info->swapped--;
54af60421   Hugh Dickins   tmpfs: convert sh...
920
  		shmem_recalc_inode(inode);
27ab70062   Hugh Dickins   tmpfs: simplify f...
921
  		spin_unlock(&info->lock);
54af60421   Hugh Dickins   tmpfs: convert sh...
922
923
  
  		delete_from_swap_cache(page);
27ab70062   Hugh Dickins   tmpfs: simplify f...
924
925
  		set_page_dirty(page);
  		swap_free(swap);
54af60421   Hugh Dickins   tmpfs: convert sh...
926
927
928
929
  	} else {
  		if (shmem_acct_block(info->flags)) {
  			error = -ENOSPC;
  			goto failed;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
930
  		}
0edd73b33   Hugh Dickins   [PATCH] shmem: re...
931
  		if (sbinfo->max_blocks) {
fc5da22ae   Hugh Dickins   tmpfs: fix off-by...
932
  			if (percpu_counter_compare(&sbinfo->used_blocks,
54af60421   Hugh Dickins   tmpfs: convert sh...
933
934
935
936
  						sbinfo->max_blocks) >= 0) {
  				error = -ENOSPC;
  				goto unacct;
  			}
7e496299d   Tim Chen   tmpfs: make tmpfs...
937
  			percpu_counter_inc(&sbinfo->used_blocks);
54af60421   Hugh Dickins   tmpfs: convert sh...
938
  		}
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
939

54af60421   Hugh Dickins   tmpfs: convert sh...
940
941
942
943
  		page = shmem_alloc_page(gfp, info, index);
  		if (!page) {
  			error = -ENOMEM;
  			goto decused;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
944
  		}
54af60421   Hugh Dickins   tmpfs: convert sh...
945
946
  		SetPageSwapBacked(page);
  		__set_page_locked(page);
aa3b18955   Hugh Dickins   tmpfs: convert me...
947
948
949
950
951
  		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...
952
953
954
955
956
  		if (error)
  			goto decused;
  		lru_cache_add_anon(page);
  
  		spin_lock(&info->lock);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
957
  		info->alloced++;
54af60421   Hugh Dickins   tmpfs: convert sh...
958
959
  		inode->i_blocks += BLOCKS_PER_PAGE;
  		shmem_recalc_inode(inode);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
960
  		spin_unlock(&info->lock);
54af60421   Hugh Dickins   tmpfs: convert sh...
961

27ab70062   Hugh Dickins   tmpfs: simplify f...
962
963
964
  		clear_highpage(page);
  		flush_dcache_page(page);
  		SetPageUptodate(page);
a0ee5ec52   Hugh Dickins   tmpfs: allocate o...
965
  		if (sgp == SGP_DIRTY)
27ab70062   Hugh Dickins   tmpfs: simplify f...
966
  			set_page_dirty(page);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
967
968
  	}
  done:
54af60421   Hugh Dickins   tmpfs: convert sh...
969
970
971
972
973
  	/* 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...
974
  	}
54af60421   Hugh Dickins   tmpfs: convert sh...
975
976
  	*pagep = page;
  	return 0;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
977

59a16ead5   Hugh Dickins   tmpfs: fix spurio...
978
  	/*
54af60421   Hugh Dickins   tmpfs: convert sh...
979
  	 * Error recovery.
59a16ead5   Hugh Dickins   tmpfs: fix spurio...
980
  	 */
54af60421   Hugh Dickins   tmpfs: convert sh...
981
982
983
984
985
986
  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...
987
  	spin_unlock(&info->lock);
54af60421   Hugh Dickins   tmpfs: convert sh...
988
989
990
991
992
993
994
995
996
997
998
999
1000
1001
  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...
1002
  	if (page) {
54af60421   Hugh Dickins   tmpfs: convert sh...
1003
  		unlock_page(page);
27ab70062   Hugh Dickins   tmpfs: simplify f...
1004
  		page_cache_release(page);
54af60421   Hugh Dickins   tmpfs: convert sh...
1005
1006
1007
1008
1009
1010
  	}
  	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...
1011
  		goto repeat;
ff36b8016   Shaohua Li   shmem: reduce pag...
1012
  	}
54af60421   Hugh Dickins   tmpfs: convert sh...
1013
1014
1015
  	if (error == -EEXIST)
  		goto repeat;
  	return error;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
1016
  }
d0217ac04   Nick Piggin   mm: fault feedbac...
1017
  static int shmem_fault(struct vm_area_struct *vma, struct vm_fault *vmf)
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
1018
  {
d3ac7f892   Josef "Jeff" Sipek   [PATCH] mm: chang...
1019
  	struct inode *inode = vma->vm_file->f_path.dentry->d_inode;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
1020
  	int error;
68da9f055   Hugh Dickins   tmpfs: pass gfp t...
1021
  	int ret = VM_FAULT_LOCKED;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
1022

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

456f998ec   Ying Han   memcg: add the pa...
1027
1028
1029
1030
  	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...
1031
  	return ret;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
1032
  }
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
1033
  #ifdef CONFIG_NUMA
41ffe5d5c   Hugh Dickins   tmpfs: miscellane...
1034
  static int shmem_set_policy(struct vm_area_struct *vma, struct mempolicy *mpol)
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
1035
  {
41ffe5d5c   Hugh Dickins   tmpfs: miscellane...
1036
1037
  	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
1038
  }
d8dc74f21   Adrian Bunk   mm/shmem.c: make ...
1039
1040
  static struct mempolicy *shmem_get_policy(struct vm_area_struct *vma,
  					  unsigned long addr)
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
1041
  {
41ffe5d5c   Hugh Dickins   tmpfs: miscellane...
1042
1043
  	struct inode *inode = vma->vm_file->f_path.dentry->d_inode;
  	pgoff_t index;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
1044

41ffe5d5c   Hugh Dickins   tmpfs: miscellane...
1045
1046
  	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
1047
1048
1049
1050
1051
  }
  #endif
  
  int shmem_lock(struct file *file, int lock, struct user_struct *user)
  {
d3ac7f892   Josef "Jeff" Sipek   [PATCH] mm: chang...
1052
  	struct inode *inode = file->f_path.dentry->d_inode;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
1053
1054
1055
1056
1057
1058
1059
1060
  	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 ...
1061
  		mapping_set_unevictable(file->f_mapping);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
1062
1063
1064
1065
  	}
  	if (!lock && (info->flags & VM_LOCKED) && user) {
  		user_shm_unlock(inode->i_size, user);
  		info->flags &= ~VM_LOCKED;
89e004ea5   Lee Schermerhorn   SHM_LOCKED pages ...
1066
  		mapping_clear_unevictable(file->f_mapping);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
1067
1068
  	}
  	retval = 0;
89e004ea5   Lee Schermerhorn   SHM_LOCKED pages ...
1069

1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
1070
1071
1072
1073
  out_nomem:
  	spin_unlock(&info->lock);
  	return retval;
  }
9b83a6a85   Adrian Bunk   [PATCH] mm/{,tiny...
1074
  static int shmem_mmap(struct file *file, struct vm_area_struct *vma)
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
1075
1076
1077
  {
  	file_accessed(file);
  	vma->vm_ops = &shmem_vm_ops;
d0217ac04   Nick Piggin   mm: fault feedbac...
1078
  	vma->vm_flags |= VM_CAN_NONLINEAR;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
1079
1080
  	return 0;
  }
454abafe9   Dmitry Monakhov   ramfs: replace in...
1081
  static struct inode *shmem_get_inode(struct super_block *sb, const struct inode *dir,
09208d150   Al Viro   shmem, ramfs: pro...
1082
  				     umode_t mode, dev_t dev, unsigned long flags)
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
1083
1084
1085
1086
  {
  	struct inode *inode;
  	struct shmem_inode_info *info;
  	struct shmem_sb_info *sbinfo = SHMEM_SB(sb);
5b04c6890   Pavel Emelyanov   shmem: factor out...
1087
1088
  	if (shmem_reserve_inode(sb))
  		return NULL;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
1089
1090
1091
  
  	inode = new_inode(sb);
  	if (inode) {
85fe4025c   Christoph Hellwig   fs: do not assign...
1092
  		inode->i_ino = get_next_ino();
454abafe9   Dmitry Monakhov   ramfs: replace in...
1093
  		inode_init_owner(inode, dir, mode);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
1094
  		inode->i_blocks = 0;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
1095
1096
  		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...
1097
  		inode->i_generation = get_seconds();
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
1098
1099
1100
  		info = SHMEM_I(inode);
  		memset(info, 0, (char *)inode - (char *)info);
  		spin_lock_init(&info->lock);
0b0a0806b   Hugh Dickins   shmem: fix shared...
1101
  		info->flags = flags & VM_NORESERVE;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
1102
  		INIT_LIST_HEAD(&info->swaplist);
b09e0fa4b   Eric Paris   tmpfs: implement ...
1103
  		INIT_LIST_HEAD(&info->xattr_list);
72c04902d   Al Viro   Get "no acls for ...
1104
  		cache_no_acl(inode);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
1105
1106
1107
  
  		switch (mode & S_IFMT) {
  		default:
39f0247d3   Andreas Gruenbacher   [PATCH] Access Co...
1108
  			inode->i_op = &shmem_special_inode_operations;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
1109
1110
1111
  			init_special_inode(inode, mode, dev);
  			break;
  		case S_IFREG:
14fcc23fd   Hugh Dickins   tmpfs: fix kernel...
1112
  			inode->i_mapping->a_ops = &shmem_aops;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
1113
1114
  			inode->i_op = &shmem_inode_operations;
  			inode->i_fop = &shmem_file_operations;
71fe804b6   Lee Schermerhorn   mempolicy: use st...
1115
1116
  			mpol_shared_policy_init(&info->policy,
  						 shmem_get_sbmpol(sbinfo));
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
1117
1118
  			break;
  		case S_IFDIR:
d8c76e6f4   Dave Hansen   [PATCH] r/o bind ...
1119
  			inc_nlink(inode);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
1120
1121
1122
1123
1124
1125
1126
1127
1128
1129
  			/* 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...
1130
  			mpol_shared_policy_init(&info->policy, NULL);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
1131
1132
  			break;
  		}
5b04c6890   Pavel Emelyanov   shmem: factor out...
1133
1134
  	} else
  		shmem_free_inode(sb);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
1135
1136
1137
1138
  	return inode;
  }
  
  #ifdef CONFIG_TMPFS
92e1d5be9   Arjan van de Ven   [PATCH] mark stru...
1139
  static const struct inode_operations shmem_symlink_inode_operations;
69f07ec93   Hugh Dickins   tmpfs: use kmemdu...
1140
  static const struct inode_operations shmem_short_symlink_operations;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
1141

6d9d88d07   Jarkko Sakkinen   tmpfs: security x...
1142
1143
1144
1145
1146
  #ifdef CONFIG_TMPFS_XATTR
  static int shmem_initxattrs(struct inode *, const struct xattr *, void *);
  #else
  #define shmem_initxattrs NULL
  #endif
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
1147
  static int
800d15a53   Nick Piggin   implement simple ...
1148
1149
1150
  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
1151
  {
800d15a53   Nick Piggin   implement simple ...
1152
1153
  	struct inode *inode = mapping->host;
  	pgoff_t index = pos >> PAGE_CACHE_SHIFT;
800d15a53   Nick Piggin   implement simple ...
1154
1155
1156
1157
1158
1159
1160
1161
1162
  	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...
1163
1164
  	if (pos + copied > inode->i_size)
  		i_size_write(inode, pos + copied);
800d15a53   Nick Piggin   implement simple ...
1165
  	set_page_dirty(page);
6746aff74   Wu Fengguang   HWPOISON: shmem: ...
1166
  	unlock_page(page);
800d15a53   Nick Piggin   implement simple ...
1167
  	page_cache_release(page);
800d15a53   Nick Piggin   implement simple ...
1168
  	return copied;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
1169
  }
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
1170
1171
  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...
1172
  	struct inode *inode = filp->f_path.dentry->d_inode;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
1173
  	struct address_space *mapping = inode->i_mapping;
41ffe5d5c   Hugh Dickins   tmpfs: miscellane...
1174
1175
  	pgoff_t index;
  	unsigned long offset;
a0ee5ec52   Hugh Dickins   tmpfs: allocate o...
1176
1177
1178
1179
1180
1181
1182
1183
1184
  	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
1185
1186
1187
1188
1189
1190
  
  	index = *ppos >> PAGE_CACHE_SHIFT;
  	offset = *ppos & ~PAGE_CACHE_MASK;
  
  	for (;;) {
  		struct page *page = NULL;
41ffe5d5c   Hugh Dickins   tmpfs: miscellane...
1191
1192
  		pgoff_t end_index;
  		unsigned long nr, ret;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
1193
1194
1195
1196
1197
1198
1199
1200
1201
1202
  		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...
1203
  		desc->error = shmem_getpage(inode, index, &page, sgp, NULL);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
1204
1205
1206
1207
1208
  		if (desc->error) {
  			if (desc->error == -EINVAL)
  				desc->error = 0;
  			break;
  		}
d3602444e   Hugh Dickins   shmem_getpage ret...
1209
1210
  		if (page)
  			unlock_page(page);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
1211
1212
1213
  
  		/*
  		 * We must evaluate after, since reads (unlike writes)
1b1dcc1b5   Jes Sorensen   [PATCH] mutex sub...
1214
  		 * are called without i_mutex protection against truncate
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
1215
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
  		 */
  		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...
1242
  		} else {
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
1243
  			page = ZERO_PAGE(0);
b5810039a   Nick Piggin   [PATCH] core remo...
1244
1245
  			page_cache_get(page);
  		}
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
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
  
  		/*
  		 * 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
1272
1273
1274
1275
1276
1277
1278
1279
1280
1281
1282
1283
1284
1285
1286
1287
1288
1289
1290
1291
1292
1293
1294
1295
1296
1297
1298
1299
1300
1301
1302
1303
  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
1304
  }
708e3508c   Hugh Dickins   tmpfs: clone shme...
1305
1306
1307
1308
1309
  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...
1310
  	struct inode *inode = mapping->host;
708e3508c   Hugh Dickins   tmpfs: clone shme...
1311
1312
1313
1314
1315
1316
1317
1318
1319
1320
1321
1322
1323
1324
  	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...
1325
  	isize = i_size_read(inode);
708e3508c   Hugh Dickins   tmpfs: clone shme...
1326
1327
1328
1329
1330
1331
1332
1333
1334
1335
1336
1337
1338
1339
  	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...
1340
1341
1342
  	spd.nr_pages = find_get_pages_contig(mapping, index,
  						nr_pages, spd.pages);
  	index += spd.nr_pages;
708e3508c   Hugh Dickins   tmpfs: clone shme...
1343
  	error = 0;
708e3508c   Hugh Dickins   tmpfs: clone shme...
1344

71f0e07a6   Hugh Dickins   tmpfs: refine shm...
1345
  	while (spd.nr_pages < nr_pages) {
71f0e07a6   Hugh Dickins   tmpfs: refine shm...
1346
1347
1348
1349
  		error = shmem_getpage(inode, index, &page, SGP_CACHE, NULL);
  		if (error)
  			break;
  		unlock_page(page);
708e3508c   Hugh Dickins   tmpfs: clone shme...
1350
1351
1352
  		spd.pages[spd.nr_pages++] = page;
  		index++;
  	}
708e3508c   Hugh Dickins   tmpfs: clone shme...
1353
1354
1355
  	index = *ppos >> PAGE_CACHE_SHIFT;
  	nr_pages = spd.nr_pages;
  	spd.nr_pages = 0;
71f0e07a6   Hugh Dickins   tmpfs: refine shm...
1356

708e3508c   Hugh Dickins   tmpfs: clone shme...
1357
1358
1359
1360
1361
  	for (page_nr = 0; page_nr < nr_pages; page_nr++) {
  		unsigned int this_len;
  
  		if (!len)
  			break;
708e3508c   Hugh Dickins   tmpfs: clone shme...
1362
1363
  		this_len = min_t(unsigned long, len, PAGE_CACHE_SIZE - loff);
  		page = spd.pages[page_nr];
71f0e07a6   Hugh Dickins   tmpfs: refine shm...
1364
  		if (!PageUptodate(page) || page->mapping != mapping) {
71f0e07a6   Hugh Dickins   tmpfs: refine shm...
1365
1366
1367
  			error = shmem_getpage(inode, index, &page,
  							SGP_CACHE, NULL);
  			if (error)
708e3508c   Hugh Dickins   tmpfs: clone shme...
1368
  				break;
71f0e07a6   Hugh Dickins   tmpfs: refine shm...
1369
1370
1371
  			unlock_page(page);
  			page_cache_release(spd.pages[page_nr]);
  			spd.pages[page_nr] = page;
708e3508c   Hugh Dickins   tmpfs: clone shme...
1372
  		}
71f0e07a6   Hugh Dickins   tmpfs: refine shm...
1373
1374
  
  		isize = i_size_read(inode);
708e3508c   Hugh Dickins   tmpfs: clone shme...
1375
1376
1377
  		end_index = (isize - 1) >> PAGE_CACHE_SHIFT;
  		if (unlikely(!isize || index > end_index))
  			break;
708e3508c   Hugh Dickins   tmpfs: clone shme...
1378
1379
  		if (end_index == index) {
  			unsigned int plen;
708e3508c   Hugh Dickins   tmpfs: clone shme...
1380
1381
1382
  			plen = ((isize - 1) & ~PAGE_CACHE_MASK) + 1;
  			if (plen <= loff)
  				break;
708e3508c   Hugh Dickins   tmpfs: clone shme...
1383
1384
1385
1386
1387
1388
1389
1390
1391
1392
1393
  			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...
1394
1395
  	while (page_nr < nr_pages)
  		page_cache_release(spd.pages[page_nr++]);
708e3508c   Hugh Dickins   tmpfs: clone shme...
1396
1397
1398
1399
1400
1401
1402
1403
1404
1405
1406
1407
  
  	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...
1408
  static int shmem_statfs(struct dentry *dentry, struct kstatfs *buf)
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
1409
  {
726c33422   David Howells   [PATCH] VFS: Perm...
1410
  	struct shmem_sb_info *sbinfo = SHMEM_SB(dentry->d_sb);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
1411
1412
1413
1414
  
  	buf->f_type = TMPFS_MAGIC;
  	buf->f_bsize = PAGE_CACHE_SIZE;
  	buf->f_namelen = NAME_MAX;
0edd73b33   Hugh Dickins   [PATCH] shmem: re...
1415
  	if (sbinfo->max_blocks) {
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
1416
  		buf->f_blocks = sbinfo->max_blocks;
41ffe5d5c   Hugh Dickins   tmpfs: miscellane...
1417
1418
1419
  		buf->f_bavail =
  		buf->f_bfree  = sbinfo->max_blocks -
  				percpu_counter_sum(&sbinfo->used_blocks);
0edd73b33   Hugh Dickins   [PATCH] shmem: re...
1420
1421
  	}
  	if (sbinfo->max_inodes) {
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
1422
1423
  		buf->f_files = sbinfo->max_inodes;
  		buf->f_ffree = sbinfo->free_inodes;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
1424
1425
1426
1427
1428
1429
1430
1431
1432
  	}
  	/* 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() ...
1433
  shmem_mknod(struct inode *dir, struct dentry *dentry, umode_t mode, dev_t dev)
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
1434
  {
0b0a0806b   Hugh Dickins   shmem: fix shared...
1435
  	struct inode *inode;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
1436
  	int error = -ENOSPC;
454abafe9   Dmitry Monakhov   ramfs: replace in...
1437
  	inode = shmem_get_inode(dir->i_sb, dir, mode, dev, VM_NORESERVE);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
1438
  	if (inode) {
2a7dba391   Eric Paris   fs/vfs/security: ...
1439
  		error = security_inode_init_security(inode, dir,
9d8f13ba3   Mimi Zohar   security: new sec...
1440
  						     &dentry->d_name,
6d9d88d07   Jarkko Sakkinen   tmpfs: security x...
1441
  						     shmem_initxattrs, NULL);
570bc1c2e   Stephen Smalley   [PATCH] tmpfs: En...
1442
1443
1444
1445
1446
  		if (error) {
  			if (error != -EOPNOTSUPP) {
  				iput(inode);
  				return error;
  			}
39f0247d3   Andreas Gruenbacher   [PATCH] Access Co...
1447
  		}
1c7c474c3   Christoph Hellwig   make generic_acl ...
1448
1449
  #ifdef CONFIG_TMPFS_POSIX_ACL
  		error = generic_acl_init(inode, dir);
39f0247d3   Andreas Gruenbacher   [PATCH] Access Co...
1450
1451
1452
  		if (error) {
  			iput(inode);
  			return error;
570bc1c2e   Stephen Smalley   [PATCH] tmpfs: En...
1453
  		}
718deb6b6   Al Viro   Fix breakage in s...
1454
1455
  #else
  		error = 0;
1c7c474c3   Christoph Hellwig   make generic_acl ...
1456
  #endif
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
1457
1458
1459
1460
  		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
1461
1462
1463
  	}
  	return error;
  }
18bb1db3e   Al Viro   switch vfs_mkdir(...
1464
  static int shmem_mkdir(struct inode *dir, struct dentry *dentry, umode_t mode)
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
1465
1466
1467
1468
1469
  {
  	int error;
  
  	if ((error = shmem_mknod(dir, dentry, mode | S_IFDIR, 0)))
  		return error;
d8c76e6f4   Dave Hansen   [PATCH] r/o bind ...
1470
  	inc_nlink(dir);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
1471
1472
  	return 0;
  }
4acdaf27e   Al Viro   switch ->create()...
1473
  static int shmem_create(struct inode *dir, struct dentry *dentry, umode_t mode,
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
1474
1475
1476
1477
1478
1479
1480
1481
1482
1483
1484
  		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...
1485
  	int ret;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
1486
1487
1488
1489
1490
1491
  
  	/*
  	 * 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...
1492
1493
1494
  	ret = shmem_reserve_inode(inode->i_sb);
  	if (ret)
  		goto out;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
1495
1496
1497
  
  	dir->i_size += BOGO_DIRENT_SIZE;
  	inode->i_ctime = dir->i_ctime = dir->i_mtime = CURRENT_TIME;
d8c76e6f4   Dave Hansen   [PATCH] r/o bind ...
1498
  	inc_nlink(inode);
7de9c6ee3   Al Viro   new helper: ihold()
1499
  	ihold(inode);	/* New dentry reference */
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
1500
1501
  	dget(dentry);		/* Extra pinning count for the created dentry */
  	d_instantiate(dentry, inode);
5b04c6890   Pavel Emelyanov   shmem: factor out...
1502
1503
  out:
  	return ret;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
1504
1505
1506
1507
1508
  }
  
  static int shmem_unlink(struct inode *dir, struct dentry *dentry)
  {
  	struct inode *inode = dentry->d_inode;
5b04c6890   Pavel Emelyanov   shmem: factor out...
1509
1510
  	if (inode->i_nlink > 1 && !S_ISDIR(inode->i_mode))
  		shmem_free_inode(inode->i_sb);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
1511
1512
1513
  
  	dir->i_size -= BOGO_DIRENT_SIZE;
  	inode->i_ctime = dir->i_ctime = dir->i_mtime = CURRENT_TIME;
9a53c3a78   Dave Hansen   [PATCH] r/o bind ...
1514
  	drop_nlink(inode);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
1515
1516
1517
1518
1519
1520
1521
1522
  	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 ...
1523
1524
  	drop_nlink(dentry->d_inode);
  	drop_nlink(dir);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
1525
1526
1527
1528
1529
1530
1531
1532
1533
1534
1535
1536
1537
1538
1539
1540
1541
1542
1543
1544
  	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 ...
1545
  			drop_nlink(old_dir);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
1546
  	} else if (they_are_dirs) {
9a53c3a78   Dave Hansen   [PATCH] r/o bind ...
1547
  		drop_nlink(old_dir);
d8c76e6f4   Dave Hansen   [PATCH] r/o bind ...
1548
  		inc_nlink(new_dir);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
1549
1550
1551
1552
1553
1554
1555
1556
1557
1558
1559
1560
1561
1562
1563
  	}
  
  	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...
1564
  	struct page *page;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
1565
1566
1567
1568
1569
1570
  	char *kaddr;
  	struct shmem_inode_info *info;
  
  	len = strlen(symname) + 1;
  	if (len > PAGE_CACHE_SIZE)
  		return -ENAMETOOLONG;
454abafe9   Dmitry Monakhov   ramfs: replace in...
1571
  	inode = shmem_get_inode(dir->i_sb, dir, S_IFLNK|S_IRWXUGO, 0, VM_NORESERVE);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
1572
1573
  	if (!inode)
  		return -ENOSPC;
9d8f13ba3   Mimi Zohar   security: new sec...
1574
  	error = security_inode_init_security(inode, dir, &dentry->d_name,
6d9d88d07   Jarkko Sakkinen   tmpfs: security x...
1575
  					     shmem_initxattrs, NULL);
570bc1c2e   Stephen Smalley   [PATCH] tmpfs: En...
1576
1577
1578
1579
1580
1581
1582
  	if (error) {
  		if (error != -EOPNOTSUPP) {
  			iput(inode);
  			return error;
  		}
  		error = 0;
  	}
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
1583
1584
  	info = SHMEM_I(inode);
  	inode->i_size = len-1;
69f07ec93   Hugh Dickins   tmpfs: use kmemdu...
1585
1586
1587
1588
1589
1590
1591
  	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
1592
1593
1594
1595
1596
1597
  	} else {
  		error = shmem_getpage(inode, 0, &page, SGP_WRITE, NULL);
  		if (error) {
  			iput(inode);
  			return error;
  		}
14fcc23fd   Hugh Dickins   tmpfs: fix kernel...
1598
  		inode->i_mapping->a_ops = &shmem_aops;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
1599
  		inode->i_op = &shmem_symlink_inode_operations;
9b04c5fec   Cong Wang   mm: remove the se...
1600
  		kaddr = kmap_atomic(page);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
1601
  		memcpy(kaddr, symname, len);
9b04c5fec   Cong Wang   mm: remove the se...
1602
  		kunmap_atomic(kaddr);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
1603
  		set_page_dirty(page);
6746aff74   Wu Fengguang   HWPOISON: shmem: ...
1604
  		unlock_page(page);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
1605
1606
  		page_cache_release(page);
  	}
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
1607
1608
1609
1610
1611
1612
  	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...
1613
  static void *shmem_follow_short_symlink(struct dentry *dentry, struct nameidata *nd)
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
1614
  {
69f07ec93   Hugh Dickins   tmpfs: use kmemdu...
1615
  	nd_set_link(nd, SHMEM_I(dentry->d_inode)->symlink);
cc314eef0   Linus Torvalds   Fix nasty ncpfs s...
1616
  	return NULL;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
1617
  }
cc314eef0   Linus Torvalds   Fix nasty ncpfs s...
1618
  static void *shmem_follow_link(struct dentry *dentry, struct nameidata *nd)
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
1619
1620
  {
  	struct page *page = NULL;
41ffe5d5c   Hugh Dickins   tmpfs: miscellane...
1621
1622
  	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...
1623
1624
  	if (page)
  		unlock_page(page);
cc314eef0   Linus Torvalds   Fix nasty ncpfs s...
1625
  	return page;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
1626
  }
cc314eef0   Linus Torvalds   Fix nasty ncpfs s...
1627
  static void shmem_put_link(struct dentry *dentry, struct nameidata *nd, void *cookie)
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
1628
1629
  {
  	if (!IS_ERR(nd_get_link(nd))) {
cc314eef0   Linus Torvalds   Fix nasty ncpfs s...
1630
  		struct page *page = cookie;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
1631
1632
1633
  		kunmap(page);
  		mark_page_accessed(page);
  		page_cache_release(page);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
1634
1635
  	}
  }
b09e0fa4b   Eric Paris   tmpfs: implement ...
1636
  #ifdef CONFIG_TMPFS_XATTR
467118102   Randy Dunlap   mm/shmem and tiny...
1637
  /*
b09e0fa4b   Eric Paris   tmpfs: implement ...
1638
1639
   * 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...
1640
1641
1642
   * like ACLs, we also need to implement the security.* handlers at
   * filesystem level, though.
   */
6d9d88d07   Jarkko Sakkinen   tmpfs: security x...
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
1697
1698
1699
1700
1701
  /*
   * Allocate new xattr and copy in the value; but leave the name to callers.
   */
  static struct shmem_xattr *shmem_xattr_alloc(const void *value, size_t size)
  {
  	struct shmem_xattr *new_xattr;
  	size_t len;
  
  	/* wrap around? */
  	len = sizeof(*new_xattr) + size;
  	if (len <= sizeof(*new_xattr))
  		return NULL;
  
  	new_xattr = kmalloc(len, GFP_KERNEL);
  	if (!new_xattr)
  		return NULL;
  
  	new_xattr->size = size;
  	memcpy(new_xattr->value, value, size);
  	return new_xattr;
  }
  
  /*
   * Callback for security_inode_init_security() for acquiring xattrs.
   */
  static int shmem_initxattrs(struct inode *inode,
  			    const struct xattr *xattr_array,
  			    void *fs_info)
  {
  	struct shmem_inode_info *info = SHMEM_I(inode);
  	const struct xattr *xattr;
  	struct shmem_xattr *new_xattr;
  	size_t len;
  
  	for (xattr = xattr_array; xattr->name != NULL; xattr++) {
  		new_xattr = shmem_xattr_alloc(xattr->value, xattr->value_len);
  		if (!new_xattr)
  			return -ENOMEM;
  
  		len = strlen(xattr->name) + 1;
  		new_xattr->name = kmalloc(XATTR_SECURITY_PREFIX_LEN + len,
  					  GFP_KERNEL);
  		if (!new_xattr->name) {
  			kfree(new_xattr);
  			return -ENOMEM;
  		}
  
  		memcpy(new_xattr->name, XATTR_SECURITY_PREFIX,
  		       XATTR_SECURITY_PREFIX_LEN);
  		memcpy(new_xattr->name + XATTR_SECURITY_PREFIX_LEN,
  		       xattr->name, len);
  
  		spin_lock(&info->lock);
  		list_add(&new_xattr->list, &info->xattr_list);
  		spin_unlock(&info->lock);
  	}
  
  	return 0;
  }
b09e0fa4b   Eric Paris   tmpfs: implement ...
1702
1703
  static int shmem_xattr_get(struct dentry *dentry, const char *name,
  			   void *buffer, size_t size)
39f0247d3   Andreas Gruenbacher   [PATCH] Access Co...
1704
  {
b09e0fa4b   Eric Paris   tmpfs: implement ...
1705
1706
1707
  	struct shmem_inode_info *info;
  	struct shmem_xattr *xattr;
  	int ret = -ENODATA;
39f0247d3   Andreas Gruenbacher   [PATCH] Access Co...
1708

b09e0fa4b   Eric Paris   tmpfs: implement ...
1709
1710
1711
1712
1713
1714
1715
1716
1717
1718
1719
1720
1721
1722
1723
1724
1725
1726
  	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...
1727
  }
6d9d88d07   Jarkko Sakkinen   tmpfs: security x...
1728
  static int shmem_xattr_set(struct inode *inode, const char *name,
b09e0fa4b   Eric Paris   tmpfs: implement ...
1729
  			   const void *value, size_t size, int flags)
39f0247d3   Andreas Gruenbacher   [PATCH] Access Co...
1730
  {
b09e0fa4b   Eric Paris   tmpfs: implement ...
1731
1732
1733
  	struct shmem_inode_info *info = SHMEM_I(inode);
  	struct shmem_xattr *xattr;
  	struct shmem_xattr *new_xattr = NULL;
b09e0fa4b   Eric Paris   tmpfs: implement ...
1734
1735
1736
1737
  	int err = 0;
  
  	/* value == NULL means remove */
  	if (value) {
6d9d88d07   Jarkko Sakkinen   tmpfs: security x...
1738
  		new_xattr = shmem_xattr_alloc(value, size);
b09e0fa4b   Eric Paris   tmpfs: implement ...
1739
1740
1741
1742
1743
1744
1745
1746
  		if (!new_xattr)
  			return -ENOMEM;
  
  		new_xattr->name = kstrdup(name, GFP_KERNEL);
  		if (!new_xattr->name) {
  			kfree(new_xattr);
  			return -ENOMEM;
  		}
b09e0fa4b   Eric Paris   tmpfs: implement ...
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
  	}
  
  	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...
1776
  }
bb4354538   Stephen Hemminger   fs: xattr_handler...
1777
  static const struct xattr_handler *shmem_xattr_handlers[] = {
b09e0fa4b   Eric Paris   tmpfs: implement ...
1778
  #ifdef CONFIG_TMPFS_POSIX_ACL
1c7c474c3   Christoph Hellwig   make generic_acl ...
1779
1780
  	&generic_acl_access_handler,
  	&generic_acl_default_handler,
b09e0fa4b   Eric Paris   tmpfs: implement ...
1781
  #endif
39f0247d3   Andreas Gruenbacher   [PATCH] Access Co...
1782
1783
  	NULL
  };
b09e0fa4b   Eric Paris   tmpfs: implement ...
1784
1785
1786
1787
1788
1789
1790
1791
1792
1793
1794
1795
1796
1797
1798
1799
1800
1801
1802
1803
1804
1805
1806
1807
1808
1809
1810
1811
1812
1813
1814
1815
1816
1817
1818
1819
1820
1821
1822
1823
1824
1825
1826
1827
1828
1829
1830
1831
1832
1833
1834
1835
1836
1837
1838
1839
1840
1841
1842
  
  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 */
6d9d88d07   Jarkko Sakkinen   tmpfs: security x...
1843
  	return shmem_xattr_set(dentry->d_inode, name, value, size, flags);
b09e0fa4b   Eric Paris   tmpfs: implement ...
1844
1845
1846
1847
1848
1849
1850
1851
1852
1853
1854
1855
1856
1857
1858
1859
1860
1861
  
  }
  
  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;
6d9d88d07   Jarkko Sakkinen   tmpfs: security x...
1862
  	return shmem_xattr_set(dentry->d_inode, name, NULL, 0, XATTR_REPLACE);
b09e0fa4b   Eric Paris   tmpfs: implement ...
1863
1864
1865
1866
1867
1868
1869
1870
1871
1872
1873
1874
1875
1876
1877
1878
1879
1880
1881
1882
1883
1884
1885
1886
1887
1888
1889
1890
1891
1892
1893
1894
1895
1896
1897
1898
1899
1900
1901
1902
  }
  
  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...
1903
  static const struct inode_operations shmem_short_symlink_operations = {
b09e0fa4b   Eric Paris   tmpfs: implement ...
1904
  	.readlink	= generic_readlink,
69f07ec93   Hugh Dickins   tmpfs: use kmemdu...
1905
  	.follow_link	= shmem_follow_short_symlink,
b09e0fa4b   Eric Paris   tmpfs: implement ...
1906
1907
1908
1909
1910
1911
1912
1913
1914
1915
1916
1917
1918
1919
1920
1921
1922
  #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...
1923
  #endif
b09e0fa4b   Eric Paris   tmpfs: implement ...
1924
  };
39f0247d3   Andreas Gruenbacher   [PATCH] Access Co...
1925

91828a405   David M. Grimes   [PATCH] knfsd: ad...
1926
1927
1928
1929
1930
1931
1932
1933
1934
1935
1936
1937
  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...
1938
1939
  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...
1940
  {
91828a405   David M. Grimes   [PATCH] knfsd: ad...
1941
  	struct inode *inode;
480b116c9   Christoph Hellwig   shmem: new export...
1942
1943
1944
1945
1946
1947
  	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...
1948

480b116c9   Christoph Hellwig   shmem: new export...
1949
1950
  	inode = ilookup5(sb, (unsigned long)(inum + fid->raw[0]),
  			shmem_match, fid->raw);
91828a405   David M. Grimes   [PATCH] knfsd: ad...
1951
  	if (inode) {
480b116c9   Christoph Hellwig   shmem: new export...
1952
  		dentry = d_find_alias(inode);
91828a405   David M. Grimes   [PATCH] knfsd: ad...
1953
1954
  		iput(inode);
  	}
480b116c9   Christoph Hellwig   shmem: new export...
1955
  	return dentry;
91828a405   David M. Grimes   [PATCH] knfsd: ad...
1956
1957
1958
1959
1960
1961
  }
  
  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 ...
1962
1963
  	if (*len < 3) {
  		*len = 3;
91828a405   David M. Grimes   [PATCH] knfsd: ad...
1964
  		return 255;
5fe0c2378   Aneesh Kumar K.V   exportfs: Return ...
1965
  	}
91828a405   David M. Grimes   [PATCH] knfsd: ad...
1966

1d3382cbf   Al Viro   new helper: inode...
1967
  	if (inode_unhashed(inode)) {
91828a405   David M. Grimes   [PATCH] knfsd: ad...
1968
1969
1970
1971
1972
1973
1974
  		/* 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...
1975
  		if (inode_unhashed(inode))
91828a405   David M. Grimes   [PATCH] knfsd: ad...
1976
1977
1978
1979
1980
1981
1982
1983
1984
1985
1986
1987
  			__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...
1988
  static const struct export_operations shmem_export_ops = {
91828a405   David M. Grimes   [PATCH] knfsd: ad...
1989
  	.get_parent     = shmem_get_parent,
91828a405   David M. Grimes   [PATCH] knfsd: ad...
1990
  	.encode_fh      = shmem_encode_fh,
480b116c9   Christoph Hellwig   shmem: new export...
1991
  	.fh_to_dentry	= shmem_fh_to_dentry,
91828a405   David M. Grimes   [PATCH] knfsd: ad...
1992
  };
680d794ba   akpm@linux-foundation.org   mount options: fi...
1993
1994
  static int shmem_parse_options(char *options, struct shmem_sb_info *sbinfo,
  			       bool remount)
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
1995
1996
  {
  	char *this_char, *value, *rest;
8751e0395   Eric W. Biederman   userns: Convert t...
1997
1998
  	uid_t uid;
  	gid_t gid;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
1999

b00dc3ad7   Hugh Dickins   [PATCH] tmpfs: fi...
2000
2001
2002
2003
2004
2005
2006
2007
2008
2009
2010
2011
2012
2013
2014
2015
2016
  	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
2017
2018
2019
2020
2021
2022
2023
2024
2025
2026
2027
2028
2029
2030
2031
2032
2033
2034
2035
2036
2037
2038
2039
  		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...
2040
2041
  			sbinfo->max_blocks =
  				DIV_ROUND_UP(size, PAGE_CACHE_SIZE);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
2042
  		} else if (!strcmp(this_char,"nr_blocks")) {
680d794ba   akpm@linux-foundation.org   mount options: fi...
2043
  			sbinfo->max_blocks = memparse(value, &rest);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
2044
2045
2046
  			if (*rest)
  				goto bad_val;
  		} else if (!strcmp(this_char,"nr_inodes")) {
680d794ba   akpm@linux-foundation.org   mount options: fi...
2047
  			sbinfo->max_inodes = memparse(value, &rest);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
2048
2049
2050
  			if (*rest)
  				goto bad_val;
  		} else if (!strcmp(this_char,"mode")) {
680d794ba   akpm@linux-foundation.org   mount options: fi...
2051
  			if (remount)
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
2052
  				continue;
680d794ba   akpm@linux-foundation.org   mount options: fi...
2053
  			sbinfo->mode = simple_strtoul(value, &rest, 8) & 07777;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
2054
2055
2056
  			if (*rest)
  				goto bad_val;
  		} else if (!strcmp(this_char,"uid")) {
680d794ba   akpm@linux-foundation.org   mount options: fi...
2057
  			if (remount)
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
2058
  				continue;
8751e0395   Eric W. Biederman   userns: Convert t...
2059
  			uid = simple_strtoul(value, &rest, 0);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
2060
2061
  			if (*rest)
  				goto bad_val;
8751e0395   Eric W. Biederman   userns: Convert t...
2062
2063
2064
  			sbinfo->uid = make_kuid(current_user_ns(), uid);
  			if (!uid_valid(sbinfo->uid))
  				goto bad_val;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
2065
  		} else if (!strcmp(this_char,"gid")) {
680d794ba   akpm@linux-foundation.org   mount options: fi...
2066
  			if (remount)
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
2067
  				continue;
8751e0395   Eric W. Biederman   userns: Convert t...
2068
  			gid = simple_strtoul(value, &rest, 0);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
2069
2070
  			if (*rest)
  				goto bad_val;
8751e0395   Eric W. Biederman   userns: Convert t...
2071
2072
2073
  			sbinfo->gid = make_kgid(current_user_ns(), gid);
  			if (!gid_valid(sbinfo->gid))
  				goto bad_val;
7339ff830   Robin Holt   [PATCH] Add tmpfs...
2074
  		} else if (!strcmp(this_char,"mpol")) {
71fe804b6   Lee Schermerhorn   mempolicy: use st...
2075
  			if (mpol_parse_str(value, &sbinfo->mpol, 1))
7339ff830   Robin Holt   [PATCH] Add tmpfs...
2076
  				goto bad_val;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
2077
2078
2079
2080
2081
2082
2083
2084
2085
2086
2087
2088
2089
2090
2091
2092
2093
2094
2095
2096
  		} 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...
2097
  	struct shmem_sb_info config = *sbinfo;
0edd73b33   Hugh Dickins   [PATCH] shmem: re...
2098
2099
  	unsigned long inodes;
  	int error = -EINVAL;
680d794ba   akpm@linux-foundation.org   mount options: fi...
2100
  	if (shmem_parse_options(data, &config, true))
0edd73b33   Hugh Dickins   [PATCH] shmem: re...
2101
  		return error;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
2102

0edd73b33   Hugh Dickins   [PATCH] shmem: re...
2103
  	spin_lock(&sbinfo->stat_lock);
0edd73b33   Hugh Dickins   [PATCH] shmem: re...
2104
  	inodes = sbinfo->max_inodes - sbinfo->free_inodes;
7e496299d   Tim Chen   tmpfs: make tmpfs...
2105
  	if (percpu_counter_compare(&sbinfo->used_blocks, config.max_blocks) > 0)
0edd73b33   Hugh Dickins   [PATCH] shmem: re...
2106
  		goto out;
680d794ba   akpm@linux-foundation.org   mount options: fi...
2107
  	if (config.max_inodes < inodes)
0edd73b33   Hugh Dickins   [PATCH] shmem: re...
2108
2109
  		goto out;
  	/*
54af60421   Hugh Dickins   tmpfs: convert sh...
2110
  	 * Those tests disallow limited->unlimited while any are in use;
0edd73b33   Hugh Dickins   [PATCH] shmem: re...
2111
2112
2113
  	 * 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...
2114
  	if (config.max_blocks && !sbinfo->max_blocks)
0edd73b33   Hugh Dickins   [PATCH] shmem: re...
2115
  		goto out;
680d794ba   akpm@linux-foundation.org   mount options: fi...
2116
  	if (config.max_inodes && !sbinfo->max_inodes)
0edd73b33   Hugh Dickins   [PATCH] shmem: re...
2117
2118
2119
  		goto out;
  
  	error = 0;
680d794ba   akpm@linux-foundation.org   mount options: fi...
2120
  	sbinfo->max_blocks  = config.max_blocks;
680d794ba   akpm@linux-foundation.org   mount options: fi...
2121
2122
  	sbinfo->max_inodes  = config.max_inodes;
  	sbinfo->free_inodes = config.max_inodes - inodes;
71fe804b6   Lee Schermerhorn   mempolicy: use st...
2123
2124
2125
  
  	mpol_put(sbinfo->mpol);
  	sbinfo->mpol        = config.mpol;	/* transfers initial ref */
0edd73b33   Hugh Dickins   [PATCH] shmem: re...
2126
2127
2128
  out:
  	spin_unlock(&sbinfo->stat_lock);
  	return error;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
2129
  }
680d794ba   akpm@linux-foundation.org   mount options: fi...
2130

34c80b1d9   Al Viro   vfs: switch ->sho...
2131
  static int shmem_show_options(struct seq_file *seq, struct dentry *root)
680d794ba   akpm@linux-foundation.org   mount options: fi...
2132
  {
34c80b1d9   Al Viro   vfs: switch ->sho...
2133
  	struct shmem_sb_info *sbinfo = SHMEM_SB(root->d_sb);
680d794ba   akpm@linux-foundation.org   mount options: fi...
2134
2135
2136
2137
2138
2139
2140
  
  	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...
2141
  		seq_printf(seq, ",mode=%03ho", sbinfo->mode);
8751e0395   Eric W. Biederman   userns: Convert t...
2142
2143
2144
2145
2146
2147
  	if (!uid_eq(sbinfo->uid, GLOBAL_ROOT_UID))
  		seq_printf(seq, ",uid=%u",
  				from_kuid_munged(&init_user_ns, sbinfo->uid));
  	if (!gid_eq(sbinfo->gid, GLOBAL_ROOT_GID))
  		seq_printf(seq, ",gid=%u",
  				from_kgid_munged(&init_user_ns, sbinfo->gid));
71fe804b6   Lee Schermerhorn   mempolicy: use st...
2148
  	shmem_show_mpol(seq, sbinfo->mpol);
680d794ba   akpm@linux-foundation.org   mount options: fi...
2149
2150
2151
  	return 0;
  }
  #endif /* CONFIG_TMPFS */
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
2152
2153
2154
  
  static void shmem_put_super(struct super_block *sb)
  {
602586a83   Hugh Dickins   shmem: put_super ...
2155
2156
2157
2158
  	struct shmem_sb_info *sbinfo = SHMEM_SB(sb);
  
  	percpu_counter_destroy(&sbinfo->used_blocks);
  	kfree(sbinfo);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
2159
2160
  	sb->s_fs_info = NULL;
  }
2b2af54a5   Kay Sievers   Driver Core: devt...
2161
  int shmem_fill_super(struct super_block *sb, void *data, int silent)
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
2162
2163
  {
  	struct inode *inode;
0edd73b33   Hugh Dickins   [PATCH] shmem: re...
2164
  	struct shmem_sb_info *sbinfo;
680d794ba   akpm@linux-foundation.org   mount options: fi...
2165
2166
2167
  	int err = -ENOMEM;
  
  	/* Round up to L1_CACHE_BYTES to resist false sharing */
425fbf047   Pekka Enberg   shmem: initialize...
2168
  	sbinfo = kzalloc(max((int)sizeof(struct shmem_sb_info),
680d794ba   akpm@linux-foundation.org   mount options: fi...
2169
2170
2171
  				L1_CACHE_BYTES), GFP_KERNEL);
  	if (!sbinfo)
  		return -ENOMEM;
680d794ba   akpm@linux-foundation.org   mount options: fi...
2172
  	sbinfo->mode = S_IRWXUGO | S_ISVTX;
76aac0e9a   David Howells   CRED: Wrap task c...
2173
2174
  	sbinfo->uid = current_fsuid();
  	sbinfo->gid = current_fsgid();
680d794ba   akpm@linux-foundation.org   mount options: fi...
2175
  	sb->s_fs_info = sbinfo;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
2176

0edd73b33   Hugh Dickins   [PATCH] shmem: re...
2177
  #ifdef CONFIG_TMPFS
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
2178
2179
2180
2181
2182
2183
  	/*
  	 * 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...
2184
2185
2186
2187
2188
2189
  		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
2190
  	}
91828a405   David M. Grimes   [PATCH] knfsd: ad...
2191
  	sb->s_export_op = &shmem_export_ops;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
2192
2193
2194
  #else
  	sb->s_flags |= MS_NOUSER;
  #endif
0edd73b33   Hugh Dickins   [PATCH] shmem: re...
2195
  	spin_lock_init(&sbinfo->stat_lock);
602586a83   Hugh Dickins   shmem: put_super ...
2196
2197
  	if (percpu_counter_init(&sbinfo->used_blocks, 0))
  		goto failed;
680d794ba   akpm@linux-foundation.org   mount options: fi...
2198
  	sbinfo->free_inodes = sbinfo->max_inodes;
0edd73b33   Hugh Dickins   [PATCH] shmem: re...
2199

285b2c4fd   Hugh Dickins   tmpfs: demolish o...
2200
  	sb->s_maxbytes = MAX_LFS_FILESIZE;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
2201
2202
2203
2204
  	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...
2205
  	sb->s_time_gran = 1;
b09e0fa4b   Eric Paris   tmpfs: implement ...
2206
  #ifdef CONFIG_TMPFS_XATTR
39f0247d3   Andreas Gruenbacher   [PATCH] Access Co...
2207
  	sb->s_xattr = shmem_xattr_handlers;
b09e0fa4b   Eric Paris   tmpfs: implement ...
2208
2209
  #endif
  #ifdef CONFIG_TMPFS_POSIX_ACL
39f0247d3   Andreas Gruenbacher   [PATCH] Access Co...
2210
2211
  	sb->s_flags |= MS_POSIXACL;
  #endif
0edd73b33   Hugh Dickins   [PATCH] shmem: re...
2212

454abafe9   Dmitry Monakhov   ramfs: replace in...
2213
  	inode = shmem_get_inode(sb, NULL, S_IFDIR | sbinfo->mode, 0, VM_NORESERVE);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
2214
2215
  	if (!inode)
  		goto failed;
680d794ba   akpm@linux-foundation.org   mount options: fi...
2216
2217
  	inode->i_uid = sbinfo->uid;
  	inode->i_gid = sbinfo->gid;
318ceed08   Al Viro   tidy up after d_m...
2218
2219
  	sb->s_root = d_make_root(inode);
  	if (!sb->s_root)
48fde701a   Al Viro   switch open-coded...
2220
  		goto failed;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
2221
  	return 0;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
2222
2223
2224
2225
  failed:
  	shmem_put_super(sb);
  	return err;
  }
fcc234f88   Pekka Enberg   [PATCH] mm: kill ...
2226
  static struct kmem_cache *shmem_inode_cachep;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
2227
2228
2229
  
  static struct inode *shmem_alloc_inode(struct super_block *sb)
  {
41ffe5d5c   Hugh Dickins   tmpfs: miscellane...
2230
2231
2232
  	struct shmem_inode_info *info;
  	info = kmem_cache_alloc(shmem_inode_cachep, GFP_KERNEL);
  	if (!info)
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
2233
  		return NULL;
41ffe5d5c   Hugh Dickins   tmpfs: miscellane...
2234
  	return &info->vfs_inode;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
2235
  }
41ffe5d5c   Hugh Dickins   tmpfs: miscellane...
2236
  static void shmem_destroy_callback(struct rcu_head *head)
fa0d7e3de   Nick Piggin   fs: icache RCU fr...
2237
2238
  {
  	struct inode *inode = container_of(head, struct inode, i_rcu);
fa0d7e3de   Nick Piggin   fs: icache RCU fr...
2239
2240
  	kmem_cache_free(shmem_inode_cachep, SHMEM_I(inode));
  }
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
2241
2242
  static void shmem_destroy_inode(struct inode *inode)
  {
09208d150   Al Viro   shmem, ramfs: pro...
2243
  	if (S_ISREG(inode->i_mode))
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
2244
  		mpol_free_shared_policy(&SHMEM_I(inode)->policy);
41ffe5d5c   Hugh Dickins   tmpfs: miscellane...
2245
  	call_rcu(&inode->i_rcu, shmem_destroy_callback);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
2246
  }
41ffe5d5c   Hugh Dickins   tmpfs: miscellane...
2247
  static void shmem_init_inode(void *foo)
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
2248
  {
41ffe5d5c   Hugh Dickins   tmpfs: miscellane...
2249
2250
  	struct shmem_inode_info *info = foo;
  	inode_init_once(&info->vfs_inode);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
2251
  }
41ffe5d5c   Hugh Dickins   tmpfs: miscellane...
2252
  static int shmem_init_inodecache(void)
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
2253
2254
2255
  {
  	shmem_inode_cachep = kmem_cache_create("shmem_inode_cache",
  				sizeof(struct shmem_inode_info),
41ffe5d5c   Hugh Dickins   tmpfs: miscellane...
2256
  				0, SLAB_PANIC, shmem_init_inode);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
2257
2258
  	return 0;
  }
41ffe5d5c   Hugh Dickins   tmpfs: miscellane...
2259
  static void shmem_destroy_inodecache(void)
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
2260
  {
1a1d92c10   Alexey Dobriyan   [PATCH] Really ig...
2261
  	kmem_cache_destroy(shmem_inode_cachep);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
2262
  }
f5e54d6e5   Christoph Hellwig   [PATCH] mark addr...
2263
  static const struct address_space_operations shmem_aops = {
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
2264
  	.writepage	= shmem_writepage,
767193253   Ken Chen   [PATCH] simplify ...
2265
  	.set_page_dirty	= __set_page_dirty_no_writeback,
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
2266
  #ifdef CONFIG_TMPFS
800d15a53   Nick Piggin   implement simple ...
2267
2268
  	.write_begin	= shmem_write_begin,
  	.write_end	= shmem_write_end,
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
2269
  #endif
304dbdb7a   Lee Schermerhorn   [PATCH] add migra...
2270
  	.migratepage	= migrate_page,
aa261f549   Andi Kleen   HWPOISON: Enable ...
2271
  	.error_remove_page = generic_error_remove_page,
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
2272
  };
15ad7cdcf   Helge Deller   [PATCH] struct se...
2273
  static const struct file_operations shmem_file_operations = {
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
2274
2275
2276
  	.mmap		= shmem_mmap,
  #ifdef CONFIG_TMPFS
  	.llseek		= generic_file_llseek,
bcd78e496   Hugh Dickins   tmpfs: support aio
2277
  	.read		= do_sync_read,
5402b976a   Hugh Dickins   shmem_file_write ...
2278
  	.write		= do_sync_write,
bcd78e496   Hugh Dickins   tmpfs: support aio
2279
  	.aio_read	= shmem_file_aio_read,
5402b976a   Hugh Dickins   shmem_file_write ...
2280
  	.aio_write	= generic_file_aio_write,
1b061d924   Christoph Hellwig   rename the generi...
2281
  	.fsync		= noop_fsync,
708e3508c   Hugh Dickins   tmpfs: clone shme...
2282
  	.splice_read	= shmem_file_splice_read,
ae9764164   Hugh Dickins   shmem: convert to...
2283
  	.splice_write	= generic_file_splice_write,
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
2284
2285
  #endif
  };
92e1d5be9   Arjan van de Ven   [PATCH] mark stru...
2286
  static const struct inode_operations shmem_inode_operations = {
94c1e62df   Hugh Dickins   tmpfs: take contr...
2287
  	.setattr	= shmem_setattr,
f6b3ec238   Badari Pulavarty   [PATCH] madvise(M...
2288
  	.truncate_range	= shmem_truncate_range,
b09e0fa4b   Eric Paris   tmpfs: implement ...
2289
2290
2291
2292
2293
2294
  #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
2295
  };
92e1d5be9   Arjan van de Ven   [PATCH] mark stru...
2296
  static const struct inode_operations shmem_dir_inode_operations = {
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
2297
2298
2299
2300
2301
2302
2303
2304
2305
2306
  #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
2307
  #endif
b09e0fa4b   Eric Paris   tmpfs: implement ...
2308
2309
2310
2311
2312
2313
  #ifdef CONFIG_TMPFS_XATTR
  	.setxattr	= shmem_setxattr,
  	.getxattr	= shmem_getxattr,
  	.listxattr	= shmem_listxattr,
  	.removexattr	= shmem_removexattr,
  #endif
39f0247d3   Andreas Gruenbacher   [PATCH] Access Co...
2314
  #ifdef CONFIG_TMPFS_POSIX_ACL
94c1e62df   Hugh Dickins   tmpfs: take contr...
2315
  	.setattr	= shmem_setattr,
39f0247d3   Andreas Gruenbacher   [PATCH] Access Co...
2316
2317
  #endif
  };
92e1d5be9   Arjan van de Ven   [PATCH] mark stru...
2318
  static const struct inode_operations shmem_special_inode_operations = {
b09e0fa4b   Eric Paris   tmpfs: implement ...
2319
2320
2321
2322
2323
2324
  #ifdef CONFIG_TMPFS_XATTR
  	.setxattr	= shmem_setxattr,
  	.getxattr	= shmem_getxattr,
  	.listxattr	= shmem_listxattr,
  	.removexattr	= shmem_removexattr,
  #endif
39f0247d3   Andreas Gruenbacher   [PATCH] Access Co...
2325
  #ifdef CONFIG_TMPFS_POSIX_ACL
94c1e62df   Hugh Dickins   tmpfs: take contr...
2326
  	.setattr	= shmem_setattr,
39f0247d3   Andreas Gruenbacher   [PATCH] Access Co...
2327
  #endif
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
2328
  };
759b9775c   Hugh Dickins   [PATCH] shmem and...
2329
  static const struct super_operations shmem_ops = {
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
2330
2331
2332
2333
2334
  	.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...
2335
  	.show_options	= shmem_show_options,
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
2336
  #endif
1f895f75d   Al Viro   switch shmem.c to...
2337
  	.evict_inode	= shmem_evict_inode,
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
2338
2339
2340
  	.drop_inode	= generic_delete_inode,
  	.put_super	= shmem_put_super,
  };
f0f37e2f7   Alexey Dobriyan   const: mark struc...
2341
  static const struct vm_operations_struct shmem_vm_ops = {
54cb8821d   Nick Piggin   mm: merge populat...
2342
  	.fault		= shmem_fault,
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
2343
2344
2345
2346
2347
  #ifdef CONFIG_NUMA
  	.set_policy     = shmem_set_policy,
  	.get_policy     = shmem_get_policy,
  #endif
  };
3c26ff6e4   Al Viro   convert get_sb_no...
2348
2349
  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
2350
  {
3c26ff6e4   Al Viro   convert get_sb_no...
2351
  	return mount_nodev(fs_type, flags, data, shmem_fill_super);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
2352
  }
41ffe5d5c   Hugh Dickins   tmpfs: miscellane...
2353
  static struct file_system_type shmem_fs_type = {
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
2354
2355
  	.owner		= THIS_MODULE,
  	.name		= "tmpfs",
3c26ff6e4   Al Viro   convert get_sb_no...
2356
  	.mount		= shmem_mount,
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
2357
2358
  	.kill_sb	= kill_litter_super,
  };
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
2359

41ffe5d5c   Hugh Dickins   tmpfs: miscellane...
2360
  int __init shmem_init(void)
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
2361
2362
  {
  	int error;
e0bf68dde   Peter Zijlstra   mm: bdi init hooks
2363
2364
2365
  	error = bdi_init(&shmem_backing_dev_info);
  	if (error)
  		goto out4;
41ffe5d5c   Hugh Dickins   tmpfs: miscellane...
2366
  	error = shmem_init_inodecache();
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
2367
2368
  	if (error)
  		goto out3;
41ffe5d5c   Hugh Dickins   tmpfs: miscellane...
2369
  	error = register_filesystem(&shmem_fs_type);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
2370
2371
2372
2373
2374
  	if (error) {
  		printk(KERN_ERR "Could not register tmpfs
  ");
  		goto out2;
  	}
95dc112a5   Greg Kroah-Hartman   [PATCH] devfs: Re...
2375

41ffe5d5c   Hugh Dickins   tmpfs: miscellane...
2376
2377
  	shm_mnt = vfs_kern_mount(&shmem_fs_type, MS_NOUSER,
  				 shmem_fs_type.name, NULL);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
2378
2379
2380
2381
2382
2383
2384
2385
2386
  	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...
2387
  	unregister_filesystem(&shmem_fs_type);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
2388
  out2:
41ffe5d5c   Hugh Dickins   tmpfs: miscellane...
2389
  	shmem_destroy_inodecache();
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
2390
  out3:
e0bf68dde   Peter Zijlstra   mm: bdi init hooks
2391
2392
  	bdi_destroy(&shmem_backing_dev_info);
  out4:
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
2393
2394
2395
  	shm_mnt = ERR_PTR(error);
  	return error;
  }
853ac43ab   Matt Mackall   shmem: unify regu...
2396
2397
2398
2399
2400
2401
2402
2403
2404
2405
2406
2407
2408
  
  #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...
2409
  static struct file_system_type shmem_fs_type = {
853ac43ab   Matt Mackall   shmem: unify regu...
2410
  	.name		= "tmpfs",
3c26ff6e4   Al Viro   convert get_sb_no...
2411
  	.mount		= ramfs_mount,
853ac43ab   Matt Mackall   shmem: unify regu...
2412
2413
  	.kill_sb	= kill_litter_super,
  };
41ffe5d5c   Hugh Dickins   tmpfs: miscellane...
2414
  int __init shmem_init(void)
853ac43ab   Matt Mackall   shmem: unify regu...
2415
  {
41ffe5d5c   Hugh Dickins   tmpfs: miscellane...
2416
  	BUG_ON(register_filesystem(&shmem_fs_type) != 0);
853ac43ab   Matt Mackall   shmem: unify regu...
2417

41ffe5d5c   Hugh Dickins   tmpfs: miscellane...
2418
  	shm_mnt = kern_mount(&shmem_fs_type);
853ac43ab   Matt Mackall   shmem: unify regu...
2419
2420
2421
2422
  	BUG_ON(IS_ERR(shm_mnt));
  
  	return 0;
  }
41ffe5d5c   Hugh Dickins   tmpfs: miscellane...
2423
  int shmem_unuse(swp_entry_t swap, struct page *page)
853ac43ab   Matt Mackall   shmem: unify regu...
2424
2425
2426
  {
  	return 0;
  }
3f96b79ad   Hugh Dickins   tmpfs: depend on ...
2427
2428
2429
2430
  int shmem_lock(struct file *file, int lock, struct user_struct *user)
  {
  	return 0;
  }
245132643   Hugh Dickins   SHM_UNLOCK: fix U...
2431
2432
2433
  void shmem_unlock_mapping(struct address_space *mapping)
  {
  }
41ffe5d5c   Hugh Dickins   tmpfs: miscellane...
2434
  void shmem_truncate_range(struct inode *inode, loff_t lstart, loff_t lend)
94c1e62df   Hugh Dickins   tmpfs: take contr...
2435
  {
41ffe5d5c   Hugh Dickins   tmpfs: miscellane...
2436
  	truncate_inode_pages_range(inode->i_mapping, lstart, lend);
94c1e62df   Hugh Dickins   tmpfs: take contr...
2437
2438
  }
  EXPORT_SYMBOL_GPL(shmem_truncate_range);
0b0a0806b   Hugh Dickins   shmem: fix shared...
2439
2440
  #define shmem_vm_ops				generic_file_vm_ops
  #define shmem_file_operations			ramfs_file_operations
454abafe9   Dmitry Monakhov   ramfs: replace in...
2441
  #define shmem_get_inode(sb, dir, mode, dev, flags)	ramfs_get_inode(sb, dir, mode, dev)
0b0a0806b   Hugh Dickins   shmem: fix shared...
2442
2443
  #define shmem_acct_size(flags, size)		0
  #define shmem_unacct_size(flags, size)		do {} while (0)
853ac43ab   Matt Mackall   shmem: unify regu...
2444
2445
2446
2447
  
  #endif /* CONFIG_SHMEM */
  
  /* common code */
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
2448

467118102   Randy Dunlap   mm/shmem and tiny...
2449
  /**
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
2450
   * shmem_file_setup - get an unlinked file living in tmpfs
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
2451
2452
   * @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...
2453
   * @flags: VM_NORESERVE suppresses pre-accounting of the entire object size
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
2454
   */
168f5ac66   Sergei Trofimovich   mm cleanup: shmem...
2455
  struct file *shmem_file_setup(const char *name, loff_t size, unsigned long flags)
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
2456
2457
2458
2459
  {
  	int error;
  	struct file *file;
  	struct inode *inode;
2c48b9c45   Al Viro   switch alloc_file...
2460
2461
  	struct path path;
  	struct dentry *root;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
2462
2463
2464
2465
  	struct qstr this;
  
  	if (IS_ERR(shm_mnt))
  		return (void *)shm_mnt;
285b2c4fd   Hugh Dickins   tmpfs: demolish o...
2466
  	if (size < 0 || size > MAX_LFS_FILESIZE)
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
2467
2468
2469
2470
2471
2472
2473
2474
2475
2476
  		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...
2477
2478
  	path.dentry = d_alloc(root, &this);
  	if (!path.dentry)
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
2479
  		goto put_memory;
2c48b9c45   Al Viro   switch alloc_file...
2480
  	path.mnt = mntget(shm_mnt);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
2481

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

2c48b9c45   Al Viro   switch alloc_file...
2487
  	d_instantiate(path.dentry, inode);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
2488
  	inode->i_size = size;
6d6b77f16   Miklos Szeredi   filesystems: add ...
2489
  	clear_nlink(inode);	/* It is unlinked */
853ac43ab   Matt Mackall   shmem: unify regu...
2490
2491
2492
  #ifndef CONFIG_MMU
  	error = ramfs_nommu_expand_for_mapping(inode, size);
  	if (error)
4b42af81f   Al Viro   switch shmem_file...
2493
  		goto put_dentry;
853ac43ab   Matt Mackall   shmem: unify regu...
2494
  #endif
4b42af81f   Al Viro   switch shmem_file...
2495
2496
  
  	error = -ENFILE;
2c48b9c45   Al Viro   switch alloc_file...
2497
  	file = alloc_file(&path, FMODE_WRITE | FMODE_READ,
4b42af81f   Al Viro   switch shmem_file...
2498
2499
2500
  		  &shmem_file_operations);
  	if (!file)
  		goto put_dentry;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
2501
  	return file;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
2502
  put_dentry:
2c48b9c45   Al Viro   switch alloc_file...
2503
  	path_put(&path);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
2504
2505
2506
2507
  put_memory:
  	shmem_unacct_size(flags, size);
  	return ERR_PTR(error);
  }
395e0ddc4   Keith Packard   Export shmem_file...
2508
  EXPORT_SYMBOL_GPL(shmem_file_setup);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
2509

467118102   Randy Dunlap   mm/shmem and tiny...
2510
  /**
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
2511
   * shmem_zero_setup - setup a shared anonymous mapping
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
2512
2513
2514
2515
2516
2517
2518
2519
2520
2521
2522
2523
2524
2525
2526
   * @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...
2527
  	vma->vm_flags |= VM_CAN_NONLINEAR;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
2528
2529
  	return 0;
  }
d9d90e5eb   Hugh Dickins   tmpfs: add shmem_...
2530
2531
2532
2533
2534
2535
2536
2537
2538
2539
2540
2541
2542
  
  /**
   * 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...
2543
2544
   * 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_...
2545
2546
2547
2548
   */
  struct page *shmem_read_mapping_page_gfp(struct address_space *mapping,
  					 pgoff_t index, gfp_t gfp)
  {
68da9f055   Hugh Dickins   tmpfs: pass gfp t...
2549
2550
  #ifdef CONFIG_SHMEM
  	struct inode *inode = mapping->host;
9276aad6c   Hugh Dickins   tmpfs: remove_shm...
2551
  	struct page *page;
68da9f055   Hugh Dickins   tmpfs: pass gfp t...
2552
2553
2554
2555
2556
2557
2558
2559
2560
2561
2562
2563
2564
  	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_...
2565
  	return read_cache_page_gfp(mapping, index, gfp);
68da9f055   Hugh Dickins   tmpfs: pass gfp t...
2566
  #endif
d9d90e5eb   Hugh Dickins   tmpfs: add shmem_...
2567
2568
  }
  EXPORT_SYMBOL_GPL(shmem_read_mapping_page_gfp);