Blame view

mm/shmem.c 76.6 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>
250297edf   Andrew Morton   mm/shmem.c: remov...
27
  #include <linux/ramfs.h>
caefba174   Hugh Dickins   shmem: respect MA...
28
  #include <linux/pagemap.h>
853ac43ab   Matt Mackall   shmem: unify regu...
29
30
  #include <linux/file.h>
  #include <linux/mm.h>
b95f1b31b   Paul Gortmaker   mm: Map most file...
31
  #include <linux/export.h>
853ac43ab   Matt Mackall   shmem: unify regu...
32
  #include <linux/swap.h>
a27bb332c   Kent Overstreet   aio: don't includ...
33
  #include <linux/aio.h>
853ac43ab   Matt Mackall   shmem: unify regu...
34
35
36
37
  
  static struct vfsmount *shm_mnt;
  
  #ifdef CONFIG_SHMEM
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
38
39
40
41
42
  /*
   * 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...
43
  #include <linux/xattr.h>
a56942551   Christoph Hellwig   knfsd: exportfs: ...
44
  #include <linux/exportfs.h>
1c7c474c3   Christoph Hellwig   make generic_acl ...
45
  #include <linux/posix_acl.h>
feda821e7   Christoph Hellwig   fs: remove generi...
46
  #include <linux/posix_acl_xattr.h>
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
47
  #include <linux/mman.h>
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
48
49
50
51
  #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
52
  #include <linux/writeback.h>
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
53
  #include <linux/blkdev.h>
bda97eab0   Hugh Dickins   tmpfs: copy trunc...
54
  #include <linux/pagevec.h>
41ffe5d5c   Hugh Dickins   tmpfs: miscellane...
55
  #include <linux/percpu_counter.h>
83e4fa9c1   Hugh Dickins   tmpfs: support fa...
56
  #include <linux/falloc.h>
708e3508c   Hugh Dickins   tmpfs: clone shme...
57
  #include <linux/splice.h>
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
58
59
60
61
  #include <linux/security.h>
  #include <linux/swapops.h>
  #include <linux/mempolicy.h>
  #include <linux/namei.h>
b00dc3ad7   Hugh Dickins   [PATCH] tmpfs: fi...
62
  #include <linux/ctype.h>
304dbdb7a   Lee Schermerhorn   [PATCH] add migra...
63
  #include <linux/migrate.h>
c1f60a5a4   Christoph Lameter   [PATCH] reduce MA...
64
  #include <linux/highmem.h>
680d794ba   akpm@linux-foundation.org   mount options: fi...
65
  #include <linux/seq_file.h>
925629278   Mimi Zohar   integrity: specia...
66
  #include <linux/magic.h>
304dbdb7a   Lee Schermerhorn   [PATCH] add migra...
67

1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
68
  #include <asm/uaccess.h>
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
69
  #include <asm/pgtable.h>
caefba174   Hugh Dickins   shmem: respect MA...
70
  #define BLOCKS_PER_PAGE  (PAGE_CACHE_SIZE/512)
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
71
  #define VM_ACCT(size)    (PAGE_CACHE_ALIGN(size) >> PAGE_SHIFT)
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
72
73
  /* Pretend that each entry is of this size in directory's i_size */
  #define BOGO_DIRENT_SIZE 20
69f07ec93   Hugh Dickins   tmpfs: use kmemdu...
74
75
  /* Symlink up to this size is kmalloc'ed instead of using a swappable page */
  #define SHORT_SYMLINK_LEN 128
1aac14003   Hugh Dickins   tmpfs: quit when ...
76
77
78
79
80
81
82
83
84
85
86
  /*
   * shmem_fallocate and shmem_writepage communicate via inode->i_private
   * (with i_mutex making sure that it has only one user at a time):
   * we would prefer not to enlarge the shmem inode just for that.
   */
  struct shmem_falloc {
  	pgoff_t start;		/* start of range currently being fallocated */
  	pgoff_t next;		/* the next page offset to be fallocated */
  	pgoff_t nr_falloced;	/* how many new pages have been fallocated */
  	pgoff_t nr_unswapped;	/* how often writepage refused to swap out */
  };
285b2c4fd   Hugh Dickins   tmpfs: demolish o...
87
  /* Flag allocation requirements to shmem_getpage */
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
88
  enum sgp_type {
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
89
90
  	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...
91
  	SGP_DIRTY,	/* like SGP_CACHE, but set new page dirty */
1635f6a74   Hugh Dickins   tmpfs: undo fallo...
92
93
  	SGP_WRITE,	/* may exceed i_size, may allocate !Uptodate page */
  	SGP_FALLOC,	/* like SGP_WRITE, but make existing page Uptodate */
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
94
  };
b76db7354   Andrew Morton   mount-options-fix...
95
  #ifdef CONFIG_TMPFS
680d794ba   akpm@linux-foundation.org   mount options: fi...
96
97
98
99
100
101
102
103
104
  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...
105
  #endif
680d794ba   akpm@linux-foundation.org   mount options: fi...
106

bde05d1cc   Hugh Dickins   shmem: replace pa...
107
108
109
  static bool shmem_should_replace_page(struct page *page, gfp_t gfp);
  static int shmem_replace_page(struct page **pagep, gfp_t gfp,
  				struct shmem_inode_info *info, pgoff_t index);
68da9f055   Hugh Dickins   tmpfs: pass gfp t...
110
111
112
113
114
115
116
117
118
  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
119

1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
120
121
122
123
124
125
126
127
128
129
130
131
132
  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...
133
  	return (flags & VM_NORESERVE) ?
191c54244   Al Viro   mm: collapse secu...
134
  		0 : security_vm_enough_memory_mm(current->mm, VM_ACCT(size));
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
135
136
137
138
  }
  
  static inline void shmem_unacct_size(unsigned long flags, loff_t size)
  {
0b0a0806b   Hugh Dickins   shmem: fix shared...
139
  	if (!(flags & VM_NORESERVE))
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
140
141
142
143
144
145
146
147
148
149
150
  		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...
151
  	return (flags & VM_NORESERVE) ?
191c54244   Al Viro   mm: collapse secu...
152
  		security_vm_enough_memory_mm(current->mm, VM_ACCT(PAGE_CACHE_SIZE)) : 0;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
153
154
155
156
  }
  
  static inline void shmem_unacct_blocks(unsigned long flags, long pages)
  {
0b0a0806b   Hugh Dickins   shmem: fix shared...
157
  	if (flags & VM_NORESERVE)
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
158
159
  		vm_unacct_memory(pages * VM_ACCT(PAGE_CACHE_SIZE));
  }
759b9775c   Hugh Dickins   [PATCH] shmem and...
160
  static const struct super_operations shmem_ops;
f5e54d6e5   Christoph Hellwig   [PATCH] mark addr...
161
  static const struct address_space_operations shmem_aops;
15ad7cdcf   Helge Deller   [PATCH] struct se...
162
  static const struct file_operations shmem_file_operations;
92e1d5be9   Arjan van de Ven   [PATCH] mark stru...
163
164
165
  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...
166
  static const struct vm_operations_struct shmem_vm_ops;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
167

6c231b7ba   Ravikiran G Thirumalai   [PATCH] Additions...
168
  static struct backing_dev_info shmem_backing_dev_info  __read_mostly = {
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
169
  	.ra_pages	= 0,	/* No readahead */
4f98a2fee   Rik van Riel   vmscan: split LRU...
170
  	.capabilities	= BDI_CAP_NO_ACCT_AND_WRITEBACK | BDI_CAP_SWAP_BACKED,
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
171
172
173
  };
  
  static LIST_HEAD(shmem_swaplist);
cb5f7b9a4   Hugh Dickins   tmpfs: make shmem...
174
  static DEFINE_MUTEX(shmem_swaplist_mutex);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
175

5b04c6890   Pavel Emelyanov   shmem: factor out...
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
  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...
200
  /**
41ffe5d5c   Hugh Dickins   tmpfs: miscellane...
201
   * shmem_recalc_inode - recalculate the block usage of an inode
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
   * @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...
219
220
221
  		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
222
  		info->alloced -= freed;
54af60421   Hugh Dickins   tmpfs: convert sh...
223
  		inode->i_blocks -= freed * BLOCKS_PER_PAGE;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
224
  		shmem_unacct_blocks(info->flags, freed);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
225
226
  	}
  }
7a5d0fbb2   Hugh Dickins   tmpfs: convert sh...
227
228
229
230
231
232
233
  /*
   * 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;
6dbaf22ce   Johannes Weiner   mm: shmem: save o...
234
  	void *item;
7a5d0fbb2   Hugh Dickins   tmpfs: convert sh...
235
236
  
  	VM_BUG_ON(!expected);
6dbaf22ce   Johannes Weiner   mm: shmem: save o...
237
  	VM_BUG_ON(!replacement);
7a5d0fbb2   Hugh Dickins   tmpfs: convert sh...
238
  	pslot = radix_tree_lookup_slot(&mapping->page_tree, index);
6dbaf22ce   Johannes Weiner   mm: shmem: save o...
239
240
241
  	if (!pslot)
  		return -ENOENT;
  	item = radix_tree_deref_slot_protected(pslot, &mapping->tree_lock);
7a5d0fbb2   Hugh Dickins   tmpfs: convert sh...
242
243
  	if (item != expected)
  		return -ENOENT;
6dbaf22ce   Johannes Weiner   mm: shmem: save o...
244
  	radix_tree_replace_slot(pslot, replacement);
7a5d0fbb2   Hugh Dickins   tmpfs: convert sh...
245
246
247
248
  	return 0;
  }
  
  /*
d18992286   Hugh Dickins   shmem: fix negati...
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
   * Sometimes, before we decide whether to proceed or to fail, we must check
   * that an entry was not already brought back from swap by a racing thread.
   *
   * Checking page is not enough: by the time a SwapCache page is locked, it
   * might be reused, and again be SwapCache, using the same swap as before.
   */
  static bool shmem_confirm_swap(struct address_space *mapping,
  			       pgoff_t index, swp_entry_t swap)
  {
  	void *item;
  
  	rcu_read_lock();
  	item = radix_tree_lookup(&mapping->page_tree, index);
  	rcu_read_unlock();
  	return item == swp_to_radix_entry(swap);
  }
  
  /*
46f65ec15   Hugh Dickins   tmpfs: convert sh...
267
268
269
270
271
272
   * 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)
  {
b065b4321   Hugh Dickins   shmem: cleanup sh...
273
  	int error;
46f65ec15   Hugh Dickins   tmpfs: convert sh...
274

309381fea   Sasha Levin   mm: dump page whe...
275
276
  	VM_BUG_ON_PAGE(!PageLocked(page), page);
  	VM_BUG_ON_PAGE(!PageSwapBacked(page), page);
46f65ec15   Hugh Dickins   tmpfs: convert sh...
277

b065b4321   Hugh Dickins   shmem: cleanup sh...
278
279
280
281
282
  	page_cache_get(page);
  	page->mapping = mapping;
  	page->index = index;
  
  	spin_lock_irq(&mapping->tree_lock);
46f65ec15   Hugh Dickins   tmpfs: convert sh...
283
  	if (!expected)
b065b4321   Hugh Dickins   shmem: cleanup sh...
284
285
286
287
  		error = radix_tree_insert(&mapping->page_tree, index, page);
  	else
  		error = shmem_radix_tree_replace(mapping, index, expected,
  								 page);
46f65ec15   Hugh Dickins   tmpfs: convert sh...
288
  	if (!error) {
b065b4321   Hugh Dickins   shmem: cleanup sh...
289
290
291
292
293
294
295
296
  		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);
46f65ec15   Hugh Dickins   tmpfs: convert sh...
297
  	}
46f65ec15   Hugh Dickins   tmpfs: convert sh...
298
299
300
301
  	return error;
  }
  
  /*
6922c0c7a   Hugh Dickins   tmpfs: convert sh...
302
303
304
305
306
307
308
309
310
311
312
313
314
315
316
317
318
319
320
   * 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...
321
322
323
324
325
   * 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)
  {
6dbaf22ce   Johannes Weiner   mm: shmem: save o...
326
  	void *old;
7a5d0fbb2   Hugh Dickins   tmpfs: convert sh...
327
328
  
  	spin_lock_irq(&mapping->tree_lock);
6dbaf22ce   Johannes Weiner   mm: shmem: save o...
329
  	old = radix_tree_delete_item(&mapping->page_tree, index, radswap);
7a5d0fbb2   Hugh Dickins   tmpfs: convert sh...
330
  	spin_unlock_irq(&mapping->tree_lock);
6dbaf22ce   Johannes Weiner   mm: shmem: save o...
331
332
333
334
  	if (old != radswap)
  		return -ENOENT;
  	free_swap_and_cache(radix_to_swp_entry(radswap));
  	return 0;
7a5d0fbb2   Hugh Dickins   tmpfs: convert sh...
335
336
337
  }
  
  /*
245132643   Hugh Dickins   SHM_UNLOCK: fix U...
338
339
340
341
342
343
344
345
346
347
348
349
350
351
352
353
354
   * 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.
  		 */
0cd6144aa   Johannes Weiner   mm + fs: prepare ...
355
356
  		pvec.nr = find_get_entries(mapping, index,
  					   PAGEVEC_SIZE, pvec.pages, indices);
245132643   Hugh Dickins   SHM_UNLOCK: fix U...
357
358
359
  		if (!pvec.nr)
  			break;
  		index = indices[pvec.nr - 1] + 1;
0cd6144aa   Johannes Weiner   mm + fs: prepare ...
360
  		pagevec_remove_exceptionals(&pvec);
245132643   Hugh Dickins   SHM_UNLOCK: fix U...
361
362
363
364
  		check_move_unevictable_pages(pvec.pages, pvec.nr);
  		pagevec_release(&pvec);
  		cond_resched();
  	}
7a5d0fbb2   Hugh Dickins   tmpfs: convert sh...
365
366
367
368
  }
  
  /*
   * Remove range of pages and swap entries from radix tree, and free them.
1635f6a74   Hugh Dickins   tmpfs: undo fallo...
369
   * If !unfalloc, truncate or punch hole; if unfalloc, undo failed fallocate.
7a5d0fbb2   Hugh Dickins   tmpfs: convert sh...
370
   */
1635f6a74   Hugh Dickins   tmpfs: undo fallo...
371
372
  static void shmem_undo_range(struct inode *inode, loff_t lstart, loff_t lend,
  								 bool unfalloc)
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
373
  {
285b2c4fd   Hugh Dickins   tmpfs: demolish o...
374
  	struct address_space *mapping = inode->i_mapping;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
375
  	struct shmem_inode_info *info = SHMEM_I(inode);
285b2c4fd   Hugh Dickins   tmpfs: demolish o...
376
  	pgoff_t start = (lstart + PAGE_CACHE_SIZE - 1) >> PAGE_CACHE_SHIFT;
83e4fa9c1   Hugh Dickins   tmpfs: support fa...
377
378
379
  	pgoff_t end = (lend + 1) >> PAGE_CACHE_SHIFT;
  	unsigned int partial_start = lstart & (PAGE_CACHE_SIZE - 1);
  	unsigned int partial_end = (lend + 1) & (PAGE_CACHE_SIZE - 1);
bda97eab0   Hugh Dickins   tmpfs: copy trunc...
380
  	struct pagevec pvec;
7a5d0fbb2   Hugh Dickins   tmpfs: convert sh...
381
382
  	pgoff_t indices[PAGEVEC_SIZE];
  	long nr_swaps_freed = 0;
285b2c4fd   Hugh Dickins   tmpfs: demolish o...
383
  	pgoff_t index;
bda97eab0   Hugh Dickins   tmpfs: copy trunc...
384
  	int i;
83e4fa9c1   Hugh Dickins   tmpfs: support fa...
385
386
  	if (lend == -1)
  		end = -1;	/* unsigned, so actually very big */
bda97eab0   Hugh Dickins   tmpfs: copy trunc...
387
388
389
  
  	pagevec_init(&pvec, 0);
  	index = start;
83e4fa9c1   Hugh Dickins   tmpfs: support fa...
390
  	while (index < end) {
0cd6144aa   Johannes Weiner   mm + fs: prepare ...
391
392
393
  		pvec.nr = find_get_entries(mapping, index,
  			min(end - index, (pgoff_t)PAGEVEC_SIZE),
  			pvec.pages, indices);
7a5d0fbb2   Hugh Dickins   tmpfs: convert sh...
394
395
  		if (!pvec.nr)
  			break;
bda97eab0   Hugh Dickins   tmpfs: copy trunc...
396
397
398
  		mem_cgroup_uncharge_start();
  		for (i = 0; i < pagevec_count(&pvec); i++) {
  			struct page *page = pvec.pages[i];
7a5d0fbb2   Hugh Dickins   tmpfs: convert sh...
399
  			index = indices[i];
83e4fa9c1   Hugh Dickins   tmpfs: support fa...
400
  			if (index >= end)
bda97eab0   Hugh Dickins   tmpfs: copy trunc...
401
  				break;
7a5d0fbb2   Hugh Dickins   tmpfs: convert sh...
402
  			if (radix_tree_exceptional_entry(page)) {
1635f6a74   Hugh Dickins   tmpfs: undo fallo...
403
404
  				if (unfalloc)
  					continue;
7a5d0fbb2   Hugh Dickins   tmpfs: convert sh...
405
406
  				nr_swaps_freed += !shmem_free_swap(mapping,
  								index, page);
bda97eab0   Hugh Dickins   tmpfs: copy trunc...
407
  				continue;
7a5d0fbb2   Hugh Dickins   tmpfs: convert sh...
408
409
410
  			}
  
  			if (!trylock_page(page))
bda97eab0   Hugh Dickins   tmpfs: copy trunc...
411
  				continue;
1635f6a74   Hugh Dickins   tmpfs: undo fallo...
412
413
  			if (!unfalloc || !PageUptodate(page)) {
  				if (page->mapping == mapping) {
309381fea   Sasha Levin   mm: dump page whe...
414
  					VM_BUG_ON_PAGE(PageWriteback(page), page);
1635f6a74   Hugh Dickins   tmpfs: undo fallo...
415
416
  					truncate_inode_page(mapping, page);
  				}
bda97eab0   Hugh Dickins   tmpfs: copy trunc...
417
  			}
bda97eab0   Hugh Dickins   tmpfs: copy trunc...
418
419
  			unlock_page(page);
  		}
0cd6144aa   Johannes Weiner   mm + fs: prepare ...
420
  		pagevec_remove_exceptionals(&pvec);
245132643   Hugh Dickins   SHM_UNLOCK: fix U...
421
  		pagevec_release(&pvec);
bda97eab0   Hugh Dickins   tmpfs: copy trunc...
422
423
424
425
  		mem_cgroup_uncharge_end();
  		cond_resched();
  		index++;
  	}
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
426

83e4fa9c1   Hugh Dickins   tmpfs: support fa...
427
  	if (partial_start) {
bda97eab0   Hugh Dickins   tmpfs: copy trunc...
428
429
430
  		struct page *page = NULL;
  		shmem_getpage(inode, start - 1, &page, SGP_READ, NULL);
  		if (page) {
83e4fa9c1   Hugh Dickins   tmpfs: support fa...
431
432
433
434
435
436
437
438
439
440
441
442
443
444
445
446
  			unsigned int top = PAGE_CACHE_SIZE;
  			if (start > end) {
  				top = partial_end;
  				partial_end = 0;
  			}
  			zero_user_segment(page, partial_start, top);
  			set_page_dirty(page);
  			unlock_page(page);
  			page_cache_release(page);
  		}
  	}
  	if (partial_end) {
  		struct page *page = NULL;
  		shmem_getpage(inode, end, &page, SGP_READ, NULL);
  		if (page) {
  			zero_user_segment(page, 0, partial_end);
bda97eab0   Hugh Dickins   tmpfs: copy trunc...
447
448
449
450
451
  			set_page_dirty(page);
  			unlock_page(page);
  			page_cache_release(page);
  		}
  	}
83e4fa9c1   Hugh Dickins   tmpfs: support fa...
452
453
  	if (start >= end)
  		return;
bda97eab0   Hugh Dickins   tmpfs: copy trunc...
454
455
456
457
  
  	index = start;
  	for ( ; ; ) {
  		cond_resched();
0cd6144aa   Johannes Weiner   mm + fs: prepare ...
458
459
  
  		pvec.nr = find_get_entries(mapping, index,
83e4fa9c1   Hugh Dickins   tmpfs: support fa...
460
  				min(end - index, (pgoff_t)PAGEVEC_SIZE),
0cd6144aa   Johannes Weiner   mm + fs: prepare ...
461
  				pvec.pages, indices);
7a5d0fbb2   Hugh Dickins   tmpfs: convert sh...
462
  		if (!pvec.nr) {
1635f6a74   Hugh Dickins   tmpfs: undo fallo...
463
  			if (index == start || unfalloc)
bda97eab0   Hugh Dickins   tmpfs: copy trunc...
464
465
466
467
  				break;
  			index = start;
  			continue;
  		}
1635f6a74   Hugh Dickins   tmpfs: undo fallo...
468
  		if ((index == start || unfalloc) && indices[0] >= end) {
0cd6144aa   Johannes Weiner   mm + fs: prepare ...
469
  			pagevec_remove_exceptionals(&pvec);
245132643   Hugh Dickins   SHM_UNLOCK: fix U...
470
  			pagevec_release(&pvec);
bda97eab0   Hugh Dickins   tmpfs: copy trunc...
471
472
473
474
475
  			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...
476
  			index = indices[i];
83e4fa9c1   Hugh Dickins   tmpfs: support fa...
477
  			if (index >= end)
bda97eab0   Hugh Dickins   tmpfs: copy trunc...
478
  				break;
7a5d0fbb2   Hugh Dickins   tmpfs: convert sh...
479
  			if (radix_tree_exceptional_entry(page)) {
1635f6a74   Hugh Dickins   tmpfs: undo fallo...
480
481
  				if (unfalloc)
  					continue;
7a5d0fbb2   Hugh Dickins   tmpfs: convert sh...
482
483
484
485
  				nr_swaps_freed += !shmem_free_swap(mapping,
  								index, page);
  				continue;
  			}
bda97eab0   Hugh Dickins   tmpfs: copy trunc...
486
  			lock_page(page);
1635f6a74   Hugh Dickins   tmpfs: undo fallo...
487
488
  			if (!unfalloc || !PageUptodate(page)) {
  				if (page->mapping == mapping) {
309381fea   Sasha Levin   mm: dump page whe...
489
  					VM_BUG_ON_PAGE(PageWriteback(page), page);
1635f6a74   Hugh Dickins   tmpfs: undo fallo...
490
491
  					truncate_inode_page(mapping, page);
  				}
7a5d0fbb2   Hugh Dickins   tmpfs: convert sh...
492
  			}
bda97eab0   Hugh Dickins   tmpfs: copy trunc...
493
494
  			unlock_page(page);
  		}
0cd6144aa   Johannes Weiner   mm + fs: prepare ...
495
  		pagevec_remove_exceptionals(&pvec);
245132643   Hugh Dickins   SHM_UNLOCK: fix U...
496
  		pagevec_release(&pvec);
bda97eab0   Hugh Dickins   tmpfs: copy trunc...
497
498
499
  		mem_cgroup_uncharge_end();
  		index++;
  	}
94c1e62df   Hugh Dickins   tmpfs: take contr...
500

1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
501
  	spin_lock(&info->lock);
7a5d0fbb2   Hugh Dickins   tmpfs: convert sh...
502
  	info->swapped -= nr_swaps_freed;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
503
504
  	shmem_recalc_inode(inode);
  	spin_unlock(&info->lock);
1635f6a74   Hugh Dickins   tmpfs: undo fallo...
505
  }
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
506

1635f6a74   Hugh Dickins   tmpfs: undo fallo...
507
508
509
  void shmem_truncate_range(struct inode *inode, loff_t lstart, loff_t lend)
  {
  	shmem_undo_range(inode, lstart, lend, false);
285b2c4fd   Hugh Dickins   tmpfs: demolish o...
510
  	inode->i_ctime = inode->i_mtime = CURRENT_TIME;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
511
  }
94c1e62df   Hugh Dickins   tmpfs: take contr...
512
  EXPORT_SYMBOL_GPL(shmem_truncate_range);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
513

94c1e62df   Hugh Dickins   tmpfs: take contr...
514
  static int shmem_setattr(struct dentry *dentry, struct iattr *attr)
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
515
516
  {
  	struct inode *inode = dentry->d_inode;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
517
  	int error;
db78b877f   Christoph Hellwig   always call inode...
518
519
520
  	error = inode_change_ok(inode, attr);
  	if (error)
  		return error;
94c1e62df   Hugh Dickins   tmpfs: take contr...
521
522
523
  	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...
524

94c1e62df   Hugh Dickins   tmpfs: take contr...
525
526
527
528
529
530
531
532
533
534
535
  		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
536
  	}
db78b877f   Christoph Hellwig   always call inode...
537
  	setattr_copy(inode, attr);
db78b877f   Christoph Hellwig   always call inode...
538
  	if (attr->ia_valid & ATTR_MODE)
feda821e7   Christoph Hellwig   fs: remove generi...
539
  		error = posix_acl_chmod(inode, inode->i_mode);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
540
541
  	return error;
  }
1f895f75d   Al Viro   switch shmem.c to...
542
  static void shmem_evict_inode(struct inode *inode)
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
543
  {
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
544
  	struct shmem_inode_info *info = SHMEM_I(inode);
3889e6e76   npiggin@suse.de   tmpfs: convert to...
545
  	if (inode->i_mapping->a_ops == &shmem_aops) {
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
546
547
  		shmem_unacct_size(info->flags, inode->i_size);
  		inode->i_size = 0;
3889e6e76   npiggin@suse.de   tmpfs: convert to...
548
  		shmem_truncate_range(inode, 0, (loff_t)-1);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
549
  		if (!list_empty(&info->swaplist)) {
cb5f7b9a4   Hugh Dickins   tmpfs: make shmem...
550
  			mutex_lock(&shmem_swaplist_mutex);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
551
  			list_del_init(&info->swaplist);
cb5f7b9a4   Hugh Dickins   tmpfs: make shmem...
552
  			mutex_unlock(&shmem_swaplist_mutex);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
553
  		}
69f07ec93   Hugh Dickins   tmpfs: use kmemdu...
554
555
  	} else
  		kfree(info->symlink);
b09e0fa4b   Eric Paris   tmpfs: implement ...
556

38f386574   Aristeu Rozanski   xattr: extract si...
557
  	simple_xattrs_free(&info->xattrs);
0f3c42f52   Hugh Dickins   tmpfs: change fin...
558
  	WARN_ON(inode->i_blocks);
5b04c6890   Pavel Emelyanov   shmem: factor out...
559
  	shmem_free_inode(inode->i_sb);
dbd5768f8   Jan Kara   vfs: Rename end_w...
560
  	clear_inode(inode);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
561
  }
46f65ec15   Hugh Dickins   tmpfs: convert sh...
562
563
564
  /*
   * If swap found in inode, free it and move page from swapcache to filecache.
   */
41ffe5d5c   Hugh Dickins   tmpfs: miscellane...
565
  static int shmem_unuse_inode(struct shmem_inode_info *info,
bde05d1cc   Hugh Dickins   shmem: replace pa...
566
  			     swp_entry_t swap, struct page **pagep)
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
567
  {
285b2c4fd   Hugh Dickins   tmpfs: demolish o...
568
  	struct address_space *mapping = info->vfs_inode.i_mapping;
46f65ec15   Hugh Dickins   tmpfs: convert sh...
569
  	void *radswap;
41ffe5d5c   Hugh Dickins   tmpfs: miscellane...
570
  	pgoff_t index;
bde05d1cc   Hugh Dickins   shmem: replace pa...
571
572
  	gfp_t gfp;
  	int error = 0;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
573

46f65ec15   Hugh Dickins   tmpfs: convert sh...
574
  	radswap = swp_to_radix_entry(swap);
e504f3fdd   Hugh Dickins   tmpfs radix_tree:...
575
  	index = radix_tree_locate_item(&mapping->page_tree, radswap);
46f65ec15   Hugh Dickins   tmpfs: convert sh...
576
  	if (index == -1)
285b2c4fd   Hugh Dickins   tmpfs: demolish o...
577
  		return 0;
2e0e26c76   Hugh Dickins   tmpfs: open a win...
578

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

bde05d1cc   Hugh Dickins   shmem: replace pa...
588
589
590
591
592
593
594
  	gfp = mapping_gfp_mask(mapping);
  	if (shmem_should_replace_page(*pagep, gfp)) {
  		mutex_unlock(&shmem_swaplist_mutex);
  		error = shmem_replace_page(pagep, gfp, info, index);
  		mutex_lock(&shmem_swaplist_mutex);
  		/*
  		 * We needed to drop mutex to make that restrictive page
0142ef6cd   Hugh Dickins   shmem: replace_pa...
595
596
597
598
599
600
601
602
603
604
605
606
607
608
609
  		 * allocation, but the inode might have been freed while we
  		 * dropped it: although a racing shmem_evict_inode() cannot
  		 * complete without emptying the radix_tree, our page lock
  		 * on this swapcache page is not enough to prevent that -
  		 * free_swap_and_cache() of our swap entry will only
  		 * trylock_page(), removing swap from radix_tree whatever.
  		 *
  		 * We must not proceed to shmem_add_to_page_cache() if the
  		 * inode has been freed, but of course we cannot rely on
  		 * inode or mapping or info to check that.  However, we can
  		 * safely check if our swap entry is still in use (and here
  		 * it can't have got reused for another page): if it's still
  		 * in use, then the inode cannot have been freed yet, and we
  		 * can safely proceed (if it's no longer in use, that tells
  		 * nothing about the inode, but we don't need to unuse swap).
bde05d1cc   Hugh Dickins   shmem: replace pa...
610
611
612
613
  		 */
  		if (!page_swapcount(*pagep))
  			error = -ENOENT;
  	}
d13d14430   KAMEZAWA Hiroyuki   memcg: handle swa...
614
  	/*
778dd893a   Hugh Dickins   tmpfs: fix race b...
615
616
617
  	 * 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...
618
  	 */
bde05d1cc   Hugh Dickins   shmem: replace pa...
619
620
  	if (!error)
  		error = shmem_add_to_page_cache(*pagep, mapping, index,
46f65ec15   Hugh Dickins   tmpfs: convert sh...
621
  						GFP_NOWAIT, radswap);
48f170fb7   Hugh Dickins   tmpfs: simplify u...
622
  	if (error != -ENOMEM) {
46f65ec15   Hugh Dickins   tmpfs: convert sh...
623
624
625
626
  		/*
  		 * Truncation and eviction use free_swap_and_cache(), which
  		 * only does trylock page: if we raced, best clean up here.
  		 */
bde05d1cc   Hugh Dickins   shmem: replace pa...
627
628
  		delete_from_swap_cache(*pagep);
  		set_page_dirty(*pagep);
46f65ec15   Hugh Dickins   tmpfs: convert sh...
629
630
631
632
633
634
  		if (!error) {
  			spin_lock(&info->lock);
  			info->swapped--;
  			spin_unlock(&info->lock);
  			swap_free(swap);
  		}
2e0e26c76   Hugh Dickins   tmpfs: open a win...
635
  		error = 1;	/* not an error, but entry was found */
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
636
  	}
2e0e26c76   Hugh Dickins   tmpfs: open a win...
637
  	return error;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
638
639
640
  }
  
  /*
46f65ec15   Hugh Dickins   tmpfs: convert sh...
641
   * Search through swapped inodes to find and replace swap by page.
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
642
   */
41ffe5d5c   Hugh Dickins   tmpfs: miscellane...
643
  int shmem_unuse(swp_entry_t swap, struct page *page)
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
644
  {
41ffe5d5c   Hugh Dickins   tmpfs: miscellane...
645
  	struct list_head *this, *next;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
646
647
  	struct shmem_inode_info *info;
  	int found = 0;
bde05d1cc   Hugh Dickins   shmem: replace pa...
648
649
650
651
  	int error = 0;
  
  	/*
  	 * There's a faint possibility that swap page was replaced before
0142ef6cd   Hugh Dickins   shmem: replace_pa...
652
  	 * caller locked it: caller will come back later with the right page.
bde05d1cc   Hugh Dickins   shmem: replace pa...
653
  	 */
0142ef6cd   Hugh Dickins   shmem: replace_pa...
654
  	if (unlikely(!PageSwapCache(page) || page_private(page) != swap.val))
bde05d1cc   Hugh Dickins   shmem: replace pa...
655
  		goto out;
778dd893a   Hugh Dickins   tmpfs: fix race b...
656
657
658
659
660
  
  	/*
  	 * 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...
661
  	 */
d715ae08f   Michal Hocko   memcg: rename hig...
662
  	error = mem_cgroup_charge_file(page, current->mm, GFP_KERNEL);
778dd893a   Hugh Dickins   tmpfs: fix race b...
663
664
  	if (error)
  		goto out;
46f65ec15   Hugh Dickins   tmpfs: convert sh...
665
  	/* No radix_tree_preload: swap entry keeps a place for page in tree */
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
666

cb5f7b9a4   Hugh Dickins   tmpfs: make shmem...
667
  	mutex_lock(&shmem_swaplist_mutex);
41ffe5d5c   Hugh Dickins   tmpfs: miscellane...
668
669
  	list_for_each_safe(this, next, &shmem_swaplist) {
  		info = list_entry(this, struct shmem_inode_info, swaplist);
285b2c4fd   Hugh Dickins   tmpfs: demolish o...
670
  		if (info->swapped)
bde05d1cc   Hugh Dickins   shmem: replace pa...
671
  			found = shmem_unuse_inode(info, swap, &page);
6922c0c7a   Hugh Dickins   tmpfs: convert sh...
672
673
  		else
  			list_del_init(&info->swaplist);
cb5f7b9a4   Hugh Dickins   tmpfs: make shmem...
674
  		cond_resched();
2e0e26c76   Hugh Dickins   tmpfs: open a win...
675
  		if (found)
778dd893a   Hugh Dickins   tmpfs: fix race b...
676
  			break;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
677
  	}
cb5f7b9a4   Hugh Dickins   tmpfs: make shmem...
678
  	mutex_unlock(&shmem_swaplist_mutex);
778dd893a   Hugh Dickins   tmpfs: fix race b...
679

778dd893a   Hugh Dickins   tmpfs: fix race b...
680
681
682
  	if (found < 0)
  		error = found;
  out:
aaa468653   Hugh Dickins   swap_info: note S...
683
684
  	unlock_page(page);
  	page_cache_release(page);
778dd893a   Hugh Dickins   tmpfs: fix race b...
685
  	return error;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
686
687
688
689
690
691
692
693
  }
  
  /*
   * 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
694
  	struct address_space *mapping;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
695
  	struct inode *inode;
6922c0c7a   Hugh Dickins   tmpfs: convert sh...
696
697
  	swp_entry_t swap;
  	pgoff_t index;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
698
699
  
  	BUG_ON(!PageLocked(page));
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
700
701
702
703
704
705
  	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...
706
  	if (!total_swap_pages)
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
707
  		goto redirty;
d9fe526a8   Hugh Dickins   tmpfs: allow file...
708
709
710
  	/*
  	 * 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...
711
  	 * might use ->writepage of its underlying filesystem, in which case
d9fe526a8   Hugh Dickins   tmpfs: allow file...
712
  	 * tmpfs should write out to swap only in response to memory pressure,
48f170fb7   Hugh Dickins   tmpfs: simplify u...
713
  	 * and not for the writeback threads or sync.
d9fe526a8   Hugh Dickins   tmpfs: allow file...
714
  	 */
48f170fb7   Hugh Dickins   tmpfs: simplify u...
715
716
717
718
  	if (!wbc->for_reclaim) {
  		WARN_ON_ONCE(1);	/* Still happens? Tell us about it! */
  		goto redirty;
  	}
1635f6a74   Hugh Dickins   tmpfs: undo fallo...
719
720
721
722
723
  
  	/*
  	 * This is somewhat ridiculous, but without plumbing a SWAP_MAP_FALLOC
  	 * value into swapfile.c, the only way we can correctly account for a
  	 * fallocated page arriving here is now to initialize it and write it.
1aac14003   Hugh Dickins   tmpfs: quit when ...
724
725
726
727
728
729
  	 *
  	 * That's okay for a page already fallocated earlier, but if we have
  	 * not yet completed the fallocation, then (a) we want to keep track
  	 * of this page in case we have to undo it, and (b) it may not be a
  	 * good idea to continue anyway, once we're pushing into swap.  So
  	 * reactivate the page, and let shmem_fallocate() quit when too many.
1635f6a74   Hugh Dickins   tmpfs: undo fallo...
730
731
  	 */
  	if (!PageUptodate(page)) {
1aac14003   Hugh Dickins   tmpfs: quit when ...
732
733
734
735
736
737
738
739
740
741
742
743
744
745
  		if (inode->i_private) {
  			struct shmem_falloc *shmem_falloc;
  			spin_lock(&inode->i_lock);
  			shmem_falloc = inode->i_private;
  			if (shmem_falloc &&
  			    index >= shmem_falloc->start &&
  			    index < shmem_falloc->next)
  				shmem_falloc->nr_unswapped++;
  			else
  				shmem_falloc = NULL;
  			spin_unlock(&inode->i_lock);
  			if (shmem_falloc)
  				goto redirty;
  		}
1635f6a74   Hugh Dickins   tmpfs: undo fallo...
746
747
748
749
  		clear_highpage(page);
  		flush_dcache_page(page);
  		SetPageUptodate(page);
  	}
48f170fb7   Hugh Dickins   tmpfs: simplify u...
750
751
752
  	swap = get_swap_page();
  	if (!swap.val)
  		goto redirty;
d9fe526a8   Hugh Dickins   tmpfs: allow file...
753

b1dea800a   Hugh Dickins   tmpfs: fix race b...
754
755
  	/*
  	 * Add inode to shmem_unuse()'s list of swapped-out inodes,
6922c0c7a   Hugh Dickins   tmpfs: convert sh...
756
757
  	 * 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...
758
  	 * the inode from eviction.  But don't unlock the mutex until
6922c0c7a   Hugh Dickins   tmpfs: convert sh...
759
760
  	 * 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...
761
  	 */
48f170fb7   Hugh Dickins   tmpfs: simplify u...
762
763
764
  	mutex_lock(&shmem_swaplist_mutex);
  	if (list_empty(&info->swaplist))
  		list_add_tail(&info->swaplist, &shmem_swaplist);
b1dea800a   Hugh Dickins   tmpfs: fix race b...
765

48f170fb7   Hugh Dickins   tmpfs: simplify u...
766
  	if (add_to_swap_cache(page, swap, GFP_ATOMIC) == 0) {
aaa468653   Hugh Dickins   swap_info: note S...
767
  		swap_shmem_alloc(swap);
6922c0c7a   Hugh Dickins   tmpfs: convert sh...
768
769
770
771
772
  		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...
773
  		spin_unlock(&info->lock);
6922c0c7a   Hugh Dickins   tmpfs: convert sh...
774
775
  
  		mutex_unlock(&shmem_swaplist_mutex);
d9fe526a8   Hugh Dickins   tmpfs: allow file...
776
  		BUG_ON(page_mapped(page));
9fab5619b   Hugh Dickins   shmem: writepage ...
777
  		swap_writepage(page, wbc);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
778
779
  		return 0;
  	}
6922c0c7a   Hugh Dickins   tmpfs: convert sh...
780
  	mutex_unlock(&shmem_swaplist_mutex);
cb4b86ba4   KAMEZAWA Hiroyuki   mm: add swap cach...
781
  	swapcache_free(swap, NULL);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
782
783
  redirty:
  	set_page_dirty(page);
d9fe526a8   Hugh Dickins   tmpfs: allow file...
784
785
786
787
  	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
788
789
790
  }
  
  #ifdef CONFIG_NUMA
680d794ba   akpm@linux-foundation.org   mount options: fi...
791
  #ifdef CONFIG_TMPFS
71fe804b6   Lee Schermerhorn   mempolicy: use st...
792
  static void shmem_show_mpol(struct seq_file *seq, struct mempolicy *mpol)
680d794ba   akpm@linux-foundation.org   mount options: fi...
793
  {
095f1fc4e   Lee Schermerhorn   mempolicy: rework...
794
  	char buffer[64];
680d794ba   akpm@linux-foundation.org   mount options: fi...
795

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

a7a88b237   Hugh Dickins   mempolicy: remove...
799
  	mpol_to_str(buffer, sizeof(buffer), mpol);
095f1fc4e   Lee Schermerhorn   mempolicy: rework...
800
801
  
  	seq_printf(seq, ",mpol=%s", buffer);
680d794ba   akpm@linux-foundation.org   mount options: fi...
802
  }
71fe804b6   Lee Schermerhorn   mempolicy: use st...
803
804
805
806
807
808
809
810
811
812
813
814
  
  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...
815
  #endif /* CONFIG_TMPFS */
41ffe5d5c   Hugh Dickins   tmpfs: miscellane...
816
817
  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
818
  {
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
819
  	struct vm_area_struct pvma;
18a2f371f   Mel Gorman   tmpfs: fix shared...
820
  	struct page *page;
52cd3b074   Lee Schermerhorn   mempolicy: rework...
821

1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
822
  	/* Create a pseudo vma that just contains the policy */
c4cc6d07b   Hugh Dickins   swapin_readahead:...
823
  	pvma.vm_start = 0;
09c231cb8   Nathan Zimmer   tmpfs: distribute...
824
825
  	/* Bias interleave by inode number to distribute better across nodes */
  	pvma.vm_pgoff = index + info->vfs_inode.i_ino;
c4cc6d07b   Hugh Dickins   swapin_readahead:...
826
  	pvma.vm_ops = NULL;
18a2f371f   Mel Gorman   tmpfs: fix shared...
827
828
829
830
831
832
833
834
  	pvma.vm_policy = mpol_shared_policy_lookup(&info->policy, index);
  
  	page = swapin_readahead(swap, gfp, &pvma, 0);
  
  	/* Drop reference taken by mpol_shared_policy_lookup() */
  	mpol_cond_put(pvma.vm_policy);
  
  	return page;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
835
  }
02098feaa   Hugh Dickins   swapin needs gfp_...
836
  static struct page *shmem_alloc_page(gfp_t gfp,
41ffe5d5c   Hugh Dickins   tmpfs: miscellane...
837
  			struct shmem_inode_info *info, pgoff_t index)
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
838
839
  {
  	struct vm_area_struct pvma;
18a2f371f   Mel Gorman   tmpfs: fix shared...
840
  	struct page *page;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
841

c4cc6d07b   Hugh Dickins   swapin_readahead:...
842
843
  	/* Create a pseudo vma that just contains the policy */
  	pvma.vm_start = 0;
09c231cb8   Nathan Zimmer   tmpfs: distribute...
844
845
  	/* Bias interleave by inode number to distribute better across nodes */
  	pvma.vm_pgoff = index + info->vfs_inode.i_ino;
c4cc6d07b   Hugh Dickins   swapin_readahead:...
846
  	pvma.vm_ops = NULL;
41ffe5d5c   Hugh Dickins   tmpfs: miscellane...
847
  	pvma.vm_policy = mpol_shared_policy_lookup(&info->policy, index);
52cd3b074   Lee Schermerhorn   mempolicy: rework...
848

18a2f371f   Mel Gorman   tmpfs: fix shared...
849
850
851
852
853
854
  	page = alloc_page_vma(gfp, &pvma, 0);
  
  	/* Drop reference taken by mpol_shared_policy_lookup() */
  	mpol_cond_put(pvma.vm_policy);
  
  	return page;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
855
  }
680d794ba   akpm@linux-foundation.org   mount options: fi...
856
857
  #else /* !CONFIG_NUMA */
  #ifdef CONFIG_TMPFS
41ffe5d5c   Hugh Dickins   tmpfs: miscellane...
858
  static inline void shmem_show_mpol(struct seq_file *seq, struct mempolicy *mpol)
680d794ba   akpm@linux-foundation.org   mount options: fi...
859
860
861
  {
  }
  #endif /* CONFIG_TMPFS */
41ffe5d5c   Hugh Dickins   tmpfs: miscellane...
862
863
  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
864
  {
41ffe5d5c   Hugh Dickins   tmpfs: miscellane...
865
  	return swapin_readahead(swap, gfp, NULL, 0);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
866
  }
02098feaa   Hugh Dickins   swapin needs gfp_...
867
  static inline struct page *shmem_alloc_page(gfp_t gfp,
41ffe5d5c   Hugh Dickins   tmpfs: miscellane...
868
  			struct shmem_inode_info *info, pgoff_t index)
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
869
  {
e84e2e132   Hugh Dickins   tmpfs: restore mi...
870
  	return alloc_page(gfp);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
871
  }
680d794ba   akpm@linux-foundation.org   mount options: fi...
872
  #endif /* CONFIG_NUMA */
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
873

71fe804b6   Lee Schermerhorn   mempolicy: use st...
874
875
876
877
878
879
  #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
880
  /*
bde05d1cc   Hugh Dickins   shmem: replace pa...
881
882
883
884
885
886
887
888
889
890
891
892
893
894
895
896
897
898
899
900
901
902
903
904
905
906
907
908
909
910
911
912
913
914
915
916
   * When a page is moved from swapcache to shmem filecache (either by the
   * usual swapin of shmem_getpage_gfp(), or by the less common swapoff of
   * shmem_unuse_inode()), it may have been read in earlier from swap, in
   * ignorance of the mapping it belongs to.  If that mapping has special
   * constraints (like the gma500 GEM driver, which requires RAM below 4GB),
   * we may need to copy to a suitable page before moving to filecache.
   *
   * In a future release, this may well be extended to respect cpuset and
   * NUMA mempolicy, and applied also to anonymous pages in do_swap_page();
   * but for now it is a simple matter of zone.
   */
  static bool shmem_should_replace_page(struct page *page, gfp_t gfp)
  {
  	return page_zonenum(page) > gfp_zone(gfp);
  }
  
  static int shmem_replace_page(struct page **pagep, gfp_t gfp,
  				struct shmem_inode_info *info, pgoff_t index)
  {
  	struct page *oldpage, *newpage;
  	struct address_space *swap_mapping;
  	pgoff_t swap_index;
  	int error;
  
  	oldpage = *pagep;
  	swap_index = page_private(oldpage);
  	swap_mapping = page_mapping(oldpage);
  
  	/*
  	 * We have arrived here because our zones are constrained, so don't
  	 * limit chance of success by further cpuset and node constraints.
  	 */
  	gfp &= ~GFP_CONSTRAINT_MASK;
  	newpage = shmem_alloc_page(gfp, info, index);
  	if (!newpage)
  		return -ENOMEM;
bde05d1cc   Hugh Dickins   shmem: replace pa...
917

bde05d1cc   Hugh Dickins   shmem: replace pa...
918
919
  	page_cache_get(newpage);
  	copy_highpage(newpage, oldpage);
0142ef6cd   Hugh Dickins   shmem: replace_pa...
920
  	flush_dcache_page(newpage);
bde05d1cc   Hugh Dickins   shmem: replace pa...
921

bde05d1cc   Hugh Dickins   shmem: replace pa...
922
  	__set_page_locked(newpage);
bde05d1cc   Hugh Dickins   shmem: replace pa...
923
  	SetPageUptodate(newpage);
bde05d1cc   Hugh Dickins   shmem: replace pa...
924
  	SetPageSwapBacked(newpage);
bde05d1cc   Hugh Dickins   shmem: replace pa...
925
  	set_page_private(newpage, swap_index);
bde05d1cc   Hugh Dickins   shmem: replace pa...
926
927
928
929
930
931
932
933
934
  	SetPageSwapCache(newpage);
  
  	/*
  	 * Our caller will very soon move newpage out of swapcache, but it's
  	 * a nice clean interface for us to replace oldpage by newpage there.
  	 */
  	spin_lock_irq(&swap_mapping->tree_lock);
  	error = shmem_radix_tree_replace(swap_mapping, swap_index, oldpage,
  								   newpage);
0142ef6cd   Hugh Dickins   shmem: replace_pa...
935
936
937
938
  	if (!error) {
  		__inc_zone_page_state(newpage, NR_FILE_PAGES);
  		__dec_zone_page_state(oldpage, NR_FILE_PAGES);
  	}
bde05d1cc   Hugh Dickins   shmem: replace pa...
939
  	spin_unlock_irq(&swap_mapping->tree_lock);
bde05d1cc   Hugh Dickins   shmem: replace pa...
940

0142ef6cd   Hugh Dickins   shmem: replace_pa...
941
942
943
944
945
946
947
948
949
950
951
952
  	if (unlikely(error)) {
  		/*
  		 * Is this possible?  I think not, now that our callers check
  		 * both PageSwapCache and page_private after getting page lock;
  		 * but be defensive.  Reverse old to newpage for clear and free.
  		 */
  		oldpage = newpage;
  	} else {
  		mem_cgroup_replace_page_cache(oldpage, newpage);
  		lru_cache_add_anon(newpage);
  		*pagep = newpage;
  	}
bde05d1cc   Hugh Dickins   shmem: replace pa...
953
954
955
956
957
958
959
  
  	ClearPageSwapCache(oldpage);
  	set_page_private(oldpage, 0);
  
  	unlock_page(oldpage);
  	page_cache_release(oldpage);
  	page_cache_release(oldpage);
0142ef6cd   Hugh Dickins   shmem: replace_pa...
960
  	return error;
bde05d1cc   Hugh Dickins   shmem: replace pa...
961
962
963
  }
  
  /*
68da9f055   Hugh Dickins   tmpfs: pass gfp t...
964
   * shmem_getpage_gfp - find page in cache, or get from swap, or allocate
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
965
966
967
968
969
   *
   * 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...
970
  static int shmem_getpage_gfp(struct inode *inode, pgoff_t index,
68da9f055   Hugh Dickins   tmpfs: pass gfp t...
971
  	struct page **pagep, enum sgp_type sgp, gfp_t gfp, int *fault_type)
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
972
973
  {
  	struct address_space *mapping = inode->i_mapping;
54af60421   Hugh Dickins   tmpfs: convert sh...
974
  	struct shmem_inode_info *info;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
975
  	struct shmem_sb_info *sbinfo;
27ab70062   Hugh Dickins   tmpfs: simplify f...
976
  	struct page *page;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
977
978
  	swp_entry_t swap;
  	int error;
54af60421   Hugh Dickins   tmpfs: convert sh...
979
  	int once = 0;
1635f6a74   Hugh Dickins   tmpfs: undo fallo...
980
  	int alloced = 0;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
981

41ffe5d5c   Hugh Dickins   tmpfs: miscellane...
982
  	if (index > (MAX_LFS_FILESIZE >> PAGE_CACHE_SHIFT))
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
983
  		return -EFBIG;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
984
  repeat:
54af60421   Hugh Dickins   tmpfs: convert sh...
985
  	swap.val = 0;
0cd6144aa   Johannes Weiner   mm + fs: prepare ...
986
  	page = find_lock_entry(mapping, index);
54af60421   Hugh Dickins   tmpfs: convert sh...
987
988
989
990
  	if (radix_tree_exceptional_entry(page)) {
  		swap = radix_to_swp_entry(page);
  		page = NULL;
  	}
1635f6a74   Hugh Dickins   tmpfs: undo fallo...
991
  	if (sgp != SGP_WRITE && sgp != SGP_FALLOC &&
54af60421   Hugh Dickins   tmpfs: convert sh...
992
993
994
995
  	    ((loff_t)index << PAGE_CACHE_SHIFT) >= i_size_read(inode)) {
  		error = -EINVAL;
  		goto failed;
  	}
1635f6a74   Hugh Dickins   tmpfs: undo fallo...
996
997
998
999
1000
1001
1002
1003
  	/* fallocated page? */
  	if (page && !PageUptodate(page)) {
  		if (sgp != SGP_READ)
  			goto clear;
  		unlock_page(page);
  		page_cache_release(page);
  		page = NULL;
  	}
54af60421   Hugh Dickins   tmpfs: convert sh...
1004
  	if (page || (sgp == SGP_READ && !swap.val)) {
54af60421   Hugh Dickins   tmpfs: convert sh...
1005
1006
  		*pagep = page;
  		return 0;
27ab70062   Hugh Dickins   tmpfs: simplify f...
1007
1008
1009
  	}
  
  	/*
54af60421   Hugh Dickins   tmpfs: convert sh...
1010
1011
  	 * Fast cache lookup did not find it:
  	 * bring it back from swap or allocate.
27ab70062   Hugh Dickins   tmpfs: simplify f...
1012
  	 */
54af60421   Hugh Dickins   tmpfs: convert sh...
1013
1014
  	info = SHMEM_I(inode);
  	sbinfo = SHMEM_SB(inode->i_sb);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
1015

1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
1016
1017
  	if (swap.val) {
  		/* Look it up and read it in.. */
27ab70062   Hugh Dickins   tmpfs: simplify f...
1018
1019
  		page = lookup_swap_cache(swap);
  		if (!page) {
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
1020
  			/* here we actually do the io */
68da9f055   Hugh Dickins   tmpfs: pass gfp t...
1021
1022
  			if (fault_type)
  				*fault_type |= VM_FAULT_MAJOR;
41ffe5d5c   Hugh Dickins   tmpfs: miscellane...
1023
  			page = shmem_swapin(swap, gfp, info, index);
27ab70062   Hugh Dickins   tmpfs: simplify f...
1024
  			if (!page) {
54af60421   Hugh Dickins   tmpfs: convert sh...
1025
1026
  				error = -ENOMEM;
  				goto failed;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
1027
  			}
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
1028
1029
1030
  		}
  
  		/* We have to do this with page locked to prevent races */
54af60421   Hugh Dickins   tmpfs: convert sh...
1031
  		lock_page(page);
0142ef6cd   Hugh Dickins   shmem: replace_pa...
1032
  		if (!PageSwapCache(page) || page_private(page) != swap.val ||
d18992286   Hugh Dickins   shmem: fix negati...
1033
  		    !shmem_confirm_swap(mapping, index, swap)) {
bde05d1cc   Hugh Dickins   shmem: replace pa...
1034
  			error = -EEXIST;	/* try again */
d18992286   Hugh Dickins   shmem: fix negati...
1035
  			goto unlock;
bde05d1cc   Hugh Dickins   shmem: replace pa...
1036
  		}
27ab70062   Hugh Dickins   tmpfs: simplify f...
1037
  		if (!PageUptodate(page)) {
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
1038
  			error = -EIO;
54af60421   Hugh Dickins   tmpfs: convert sh...
1039
  			goto failed;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
1040
  		}
54af60421   Hugh Dickins   tmpfs: convert sh...
1041
  		wait_on_page_writeback(page);
bde05d1cc   Hugh Dickins   shmem: replace pa...
1042
1043
1044
1045
  		if (shmem_should_replace_page(page, gfp)) {
  			error = shmem_replace_page(&page, gfp, info, index);
  			if (error)
  				goto failed;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
1046
  		}
27ab70062   Hugh Dickins   tmpfs: simplify f...
1047

d715ae08f   Michal Hocko   memcg: rename hig...
1048
  		error = mem_cgroup_charge_file(page, current->mm,
aa3b18955   Hugh Dickins   tmpfs: convert me...
1049
  						gfp & GFP_RECLAIM_MASK);
d18992286   Hugh Dickins   shmem: fix negati...
1050
  		if (!error) {
aa3b18955   Hugh Dickins   tmpfs: convert me...
1051
1052
  			error = shmem_add_to_page_cache(page, mapping, index,
  						gfp, swp_to_radix_entry(swap));
215c02bc3   Hugh Dickins   tmpfs: fix shmem_...
1053
1054
1055
1056
1057
1058
1059
1060
1061
1062
1063
1064
1065
1066
  			/*
  			 * We already confirmed swap under page lock, and make
  			 * no memory allocation here, so usually no possibility
  			 * of error; but free_swap_and_cache() only trylocks a
  			 * page, so it is just possible that the entry has been
  			 * truncated or holepunched since swap was confirmed.
  			 * shmem_undo_range() will have done some of the
  			 * unaccounting, now delete_from_swap_cache() will do
  			 * the rest (including mem_cgroup_uncharge_swapcache).
  			 * Reset swap.val? No, leave it so "failed" goes back to
  			 * "repeat": reading a hole and writing should succeed.
  			 */
  			if (error)
  				delete_from_swap_cache(page);
d18992286   Hugh Dickins   shmem: fix negati...
1067
  		}
54af60421   Hugh Dickins   tmpfs: convert sh...
1068
1069
1070
1071
  		if (error)
  			goto failed;
  
  		spin_lock(&info->lock);
285b2c4fd   Hugh Dickins   tmpfs: demolish o...
1072
  		info->swapped--;
54af60421   Hugh Dickins   tmpfs: convert sh...
1073
  		shmem_recalc_inode(inode);
27ab70062   Hugh Dickins   tmpfs: simplify f...
1074
  		spin_unlock(&info->lock);
54af60421   Hugh Dickins   tmpfs: convert sh...
1075
1076
  
  		delete_from_swap_cache(page);
27ab70062   Hugh Dickins   tmpfs: simplify f...
1077
1078
  		set_page_dirty(page);
  		swap_free(swap);
54af60421   Hugh Dickins   tmpfs: convert sh...
1079
1080
1081
1082
  	} else {
  		if (shmem_acct_block(info->flags)) {
  			error = -ENOSPC;
  			goto failed;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
1083
  		}
0edd73b33   Hugh Dickins   [PATCH] shmem: re...
1084
  		if (sbinfo->max_blocks) {
fc5da22ae   Hugh Dickins   tmpfs: fix off-by...
1085
  			if (percpu_counter_compare(&sbinfo->used_blocks,
54af60421   Hugh Dickins   tmpfs: convert sh...
1086
1087
1088
1089
  						sbinfo->max_blocks) >= 0) {
  				error = -ENOSPC;
  				goto unacct;
  			}
7e496299d   Tim Chen   tmpfs: make tmpfs...
1090
  			percpu_counter_inc(&sbinfo->used_blocks);
54af60421   Hugh Dickins   tmpfs: convert sh...
1091
  		}
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
1092

54af60421   Hugh Dickins   tmpfs: convert sh...
1093
1094
1095
1096
  		page = shmem_alloc_page(gfp, info, index);
  		if (!page) {
  			error = -ENOMEM;
  			goto decused;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
1097
  		}
54af60421   Hugh Dickins   tmpfs: convert sh...
1098
1099
  		SetPageSwapBacked(page);
  		__set_page_locked(page);
d715ae08f   Michal Hocko   memcg: rename hig...
1100
  		error = mem_cgroup_charge_file(page, current->mm,
aa3b18955   Hugh Dickins   tmpfs: convert me...
1101
  						gfp & GFP_RECLAIM_MASK);
54af60421   Hugh Dickins   tmpfs: convert sh...
1102
1103
  		if (error)
  			goto decused;
5e4c0d974   Jan Kara   lib/radix-tree.c:...
1104
  		error = radix_tree_maybe_preload(gfp & GFP_RECLAIM_MASK);
b065b4321   Hugh Dickins   shmem: cleanup sh...
1105
1106
1107
1108
1109
1110
1111
1112
1113
  		if (!error) {
  			error = shmem_add_to_page_cache(page, mapping, index,
  							gfp, NULL);
  			radix_tree_preload_end();
  		}
  		if (error) {
  			mem_cgroup_uncharge_cache_page(page);
  			goto decused;
  		}
54af60421   Hugh Dickins   tmpfs: convert sh...
1114
1115
1116
  		lru_cache_add_anon(page);
  
  		spin_lock(&info->lock);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
1117
  		info->alloced++;
54af60421   Hugh Dickins   tmpfs: convert sh...
1118
1119
  		inode->i_blocks += BLOCKS_PER_PAGE;
  		shmem_recalc_inode(inode);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
1120
  		spin_unlock(&info->lock);
1635f6a74   Hugh Dickins   tmpfs: undo fallo...
1121
  		alloced = true;
54af60421   Hugh Dickins   tmpfs: convert sh...
1122

ec9516fbc   Hugh Dickins   tmpfs: optimize c...
1123
  		/*
1635f6a74   Hugh Dickins   tmpfs: undo fallo...
1124
1125
1126
1127
1128
1129
1130
1131
1132
  		 * Let SGP_FALLOC use the SGP_WRITE optimization on a new page.
  		 */
  		if (sgp == SGP_FALLOC)
  			sgp = SGP_WRITE;
  clear:
  		/*
  		 * Let SGP_WRITE caller clear ends if write does not fill page;
  		 * but SGP_FALLOC on a page fallocated earlier must initialize
  		 * it now, lest undo on failure cancel our earlier guarantee.
ec9516fbc   Hugh Dickins   tmpfs: optimize c...
1133
1134
1135
1136
1137
1138
  		 */
  		if (sgp != SGP_WRITE) {
  			clear_highpage(page);
  			flush_dcache_page(page);
  			SetPageUptodate(page);
  		}
a0ee5ec52   Hugh Dickins   tmpfs: allocate o...
1139
  		if (sgp == SGP_DIRTY)
27ab70062   Hugh Dickins   tmpfs: simplify f...
1140
  			set_page_dirty(page);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
1141
  	}
bde05d1cc   Hugh Dickins   shmem: replace pa...
1142

54af60421   Hugh Dickins   tmpfs: convert sh...
1143
  	/* Perhaps the file has been truncated since we checked */
1635f6a74   Hugh Dickins   tmpfs: undo fallo...
1144
  	if (sgp != SGP_WRITE && sgp != SGP_FALLOC &&
54af60421   Hugh Dickins   tmpfs: convert sh...
1145
1146
  	    ((loff_t)index << PAGE_CACHE_SHIFT) >= i_size_read(inode)) {
  		error = -EINVAL;
1635f6a74   Hugh Dickins   tmpfs: undo fallo...
1147
1148
1149
1150
  		if (alloced)
  			goto trunc;
  		else
  			goto failed;
e83c32e8f   Hugh Dickins   tmpfs: simplify p...
1151
  	}
54af60421   Hugh Dickins   tmpfs: convert sh...
1152
1153
  	*pagep = page;
  	return 0;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
1154

59a16ead5   Hugh Dickins   tmpfs: fix spurio...
1155
  	/*
54af60421   Hugh Dickins   tmpfs: convert sh...
1156
  	 * Error recovery.
59a16ead5   Hugh Dickins   tmpfs: fix spurio...
1157
  	 */
54af60421   Hugh Dickins   tmpfs: convert sh...
1158
  trunc:
1635f6a74   Hugh Dickins   tmpfs: undo fallo...
1159
  	info = SHMEM_I(inode);
54af60421   Hugh Dickins   tmpfs: convert sh...
1160
1161
1162
1163
1164
  	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...
1165
  	spin_unlock(&info->lock);
54af60421   Hugh Dickins   tmpfs: convert sh...
1166
  decused:
1635f6a74   Hugh Dickins   tmpfs: undo fallo...
1167
  	sbinfo = SHMEM_SB(inode->i_sb);
54af60421   Hugh Dickins   tmpfs: convert sh...
1168
1169
1170
1171
1172
  	if (sbinfo->max_blocks)
  		percpu_counter_add(&sbinfo->used_blocks, -1);
  unacct:
  	shmem_unacct_blocks(info->flags, 1);
  failed:
d18992286   Hugh Dickins   shmem: fix negati...
1173
1174
1175
1176
  	if (swap.val && error != -EINVAL &&
  	    !shmem_confirm_swap(mapping, index, swap))
  		error = -EEXIST;
  unlock:
27ab70062   Hugh Dickins   tmpfs: simplify f...
1177
  	if (page) {
54af60421   Hugh Dickins   tmpfs: convert sh...
1178
  		unlock_page(page);
27ab70062   Hugh Dickins   tmpfs: simplify f...
1179
  		page_cache_release(page);
54af60421   Hugh Dickins   tmpfs: convert sh...
1180
1181
1182
1183
1184
1185
  	}
  	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...
1186
  		goto repeat;
ff36b8016   Shaohua Li   shmem: reduce pag...
1187
  	}
d18992286   Hugh Dickins   shmem: fix negati...
1188
  	if (error == -EEXIST)	/* from above or from radix_tree_insert */
54af60421   Hugh Dickins   tmpfs: convert sh...
1189
1190
  		goto repeat;
  	return error;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
1191
  }
d0217ac04   Nick Piggin   mm: fault feedbac...
1192
  static int shmem_fault(struct vm_area_struct *vma, struct vm_fault *vmf)
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
1193
  {
496ad9aa8   Al Viro   new helper: file_...
1194
  	struct inode *inode = file_inode(vma->vm_file);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
1195
  	int error;
68da9f055   Hugh Dickins   tmpfs: pass gfp t...
1196
  	int ret = VM_FAULT_LOCKED;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
1197

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

456f998ec   Ying Han   memcg: add the pa...
1202
1203
1204
1205
  	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...
1206
  	return ret;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
1207
  }
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
1208
  #ifdef CONFIG_NUMA
41ffe5d5c   Hugh Dickins   tmpfs: miscellane...
1209
  static int shmem_set_policy(struct vm_area_struct *vma, struct mempolicy *mpol)
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
1210
  {
496ad9aa8   Al Viro   new helper: file_...
1211
  	struct inode *inode = file_inode(vma->vm_file);
41ffe5d5c   Hugh Dickins   tmpfs: miscellane...
1212
  	return mpol_set_shared_policy(&SHMEM_I(inode)->policy, vma, mpol);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
1213
  }
d8dc74f21   Adrian Bunk   mm/shmem.c: make ...
1214
1215
  static struct mempolicy *shmem_get_policy(struct vm_area_struct *vma,
  					  unsigned long addr)
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
1216
  {
496ad9aa8   Al Viro   new helper: file_...
1217
  	struct inode *inode = file_inode(vma->vm_file);
41ffe5d5c   Hugh Dickins   tmpfs: miscellane...
1218
  	pgoff_t index;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
1219

41ffe5d5c   Hugh Dickins   tmpfs: miscellane...
1220
1221
  	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
1222
1223
1224
1225
1226
  }
  #endif
  
  int shmem_lock(struct file *file, int lock, struct user_struct *user)
  {
496ad9aa8   Al Viro   new helper: file_...
1227
  	struct inode *inode = file_inode(file);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
1228
1229
1230
1231
1232
1233
1234
1235
  	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 ...
1236
  		mapping_set_unevictable(file->f_mapping);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
1237
1238
1239
1240
  	}
  	if (!lock && (info->flags & VM_LOCKED) && user) {
  		user_shm_unlock(inode->i_size, user);
  		info->flags &= ~VM_LOCKED;
89e004ea5   Lee Schermerhorn   SHM_LOCKED pages ...
1241
  		mapping_clear_unevictable(file->f_mapping);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
1242
1243
  	}
  	retval = 0;
89e004ea5   Lee Schermerhorn   SHM_LOCKED pages ...
1244

1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
1245
1246
1247
1248
  out_nomem:
  	spin_unlock(&info->lock);
  	return retval;
  }
9b83a6a85   Adrian Bunk   [PATCH] mm/{,tiny...
1249
  static int shmem_mmap(struct file *file, struct vm_area_struct *vma)
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
1250
1251
1252
1253
1254
  {
  	file_accessed(file);
  	vma->vm_ops = &shmem_vm_ops;
  	return 0;
  }
454abafe9   Dmitry Monakhov   ramfs: replace in...
1255
  static struct inode *shmem_get_inode(struct super_block *sb, const struct inode *dir,
09208d150   Al Viro   shmem, ramfs: pro...
1256
  				     umode_t mode, dev_t dev, unsigned long flags)
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
1257
1258
1259
1260
  {
  	struct inode *inode;
  	struct shmem_inode_info *info;
  	struct shmem_sb_info *sbinfo = SHMEM_SB(sb);
5b04c6890   Pavel Emelyanov   shmem: factor out...
1261
1262
  	if (shmem_reserve_inode(sb))
  		return NULL;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
1263
1264
1265
  
  	inode = new_inode(sb);
  	if (inode) {
85fe4025c   Christoph Hellwig   fs: do not assign...
1266
  		inode->i_ino = get_next_ino();
454abafe9   Dmitry Monakhov   ramfs: replace in...
1267
  		inode_init_owner(inode, dir, mode);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
1268
  		inode->i_blocks = 0;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
1269
1270
  		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...
1271
  		inode->i_generation = get_seconds();
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
1272
1273
1274
  		info = SHMEM_I(inode);
  		memset(info, 0, (char *)inode - (char *)info);
  		spin_lock_init(&info->lock);
0b0a0806b   Hugh Dickins   shmem: fix shared...
1275
  		info->flags = flags & VM_NORESERVE;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
1276
  		INIT_LIST_HEAD(&info->swaplist);
38f386574   Aristeu Rozanski   xattr: extract si...
1277
  		simple_xattrs_init(&info->xattrs);
72c04902d   Al Viro   Get "no acls for ...
1278
  		cache_no_acl(inode);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
1279
1280
1281
  
  		switch (mode & S_IFMT) {
  		default:
39f0247d3   Andreas Gruenbacher   [PATCH] Access Co...
1282
  			inode->i_op = &shmem_special_inode_operations;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
1283
1284
1285
  			init_special_inode(inode, mode, dev);
  			break;
  		case S_IFREG:
14fcc23fd   Hugh Dickins   tmpfs: fix kernel...
1286
  			inode->i_mapping->a_ops = &shmem_aops;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
1287
1288
  			inode->i_op = &shmem_inode_operations;
  			inode->i_fop = &shmem_file_operations;
71fe804b6   Lee Schermerhorn   mempolicy: use st...
1289
1290
  			mpol_shared_policy_init(&info->policy,
  						 shmem_get_sbmpol(sbinfo));
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
1291
1292
  			break;
  		case S_IFDIR:
d8c76e6f4   Dave Hansen   [PATCH] r/o bind ...
1293
  			inc_nlink(inode);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
1294
1295
1296
1297
1298
1299
1300
1301
1302
1303
  			/* 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...
1304
  			mpol_shared_policy_init(&info->policy, NULL);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
1305
1306
  			break;
  		}
5b04c6890   Pavel Emelyanov   shmem: factor out...
1307
1308
  	} else
  		shmem_free_inode(sb);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
1309
1310
  	return inode;
  }
0cd6144aa   Johannes Weiner   mm + fs: prepare ...
1311
1312
1313
1314
  bool shmem_mapping(struct address_space *mapping)
  {
  	return mapping->backing_dev_info == &shmem_backing_dev_info;
  }
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
1315
  #ifdef CONFIG_TMPFS
92e1d5be9   Arjan van de Ven   [PATCH] mark stru...
1316
  static const struct inode_operations shmem_symlink_inode_operations;
69f07ec93   Hugh Dickins   tmpfs: use kmemdu...
1317
  static const struct inode_operations shmem_short_symlink_operations;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
1318

6d9d88d07   Jarkko Sakkinen   tmpfs: security x...
1319
1320
1321
1322
1323
  #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
1324
  static int
800d15a53   Nick Piggin   implement simple ...
1325
1326
1327
  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
1328
  {
800d15a53   Nick Piggin   implement simple ...
1329
1330
  	struct inode *inode = mapping->host;
  	pgoff_t index = pos >> PAGE_CACHE_SHIFT;
800d15a53   Nick Piggin   implement simple ...
1331
1332
1333
1334
1335
1336
1337
1338
1339
  	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...
1340
1341
  	if (pos + copied > inode->i_size)
  		i_size_write(inode, pos + copied);
ec9516fbc   Hugh Dickins   tmpfs: optimize c...
1342
1343
1344
1345
1346
1347
1348
1349
  	if (!PageUptodate(page)) {
  		if (copied < PAGE_CACHE_SIZE) {
  			unsigned from = pos & (PAGE_CACHE_SIZE - 1);
  			zero_user_segments(page, 0, from,
  					from + copied, PAGE_CACHE_SIZE);
  		}
  		SetPageUptodate(page);
  	}
800d15a53   Nick Piggin   implement simple ...
1350
  	set_page_dirty(page);
6746aff74   Wu Fengguang   HWPOISON: shmem: ...
1351
  	unlock_page(page);
800d15a53   Nick Piggin   implement simple ...
1352
  	page_cache_release(page);
800d15a53   Nick Piggin   implement simple ...
1353
  	return copied;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
1354
  }
6e58e79db   Al Viro   introduce copy_pa...
1355
1356
  static ssize_t shmem_file_aio_read(struct kiocb *iocb,
  		const struct iovec *iov, unsigned long nr_segs, loff_t pos)
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
1357
  {
6e58e79db   Al Viro   introduce copy_pa...
1358
1359
  	struct file *file = iocb->ki_filp;
  	struct inode *inode = file_inode(file);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
1360
  	struct address_space *mapping = inode->i_mapping;
41ffe5d5c   Hugh Dickins   tmpfs: miscellane...
1361
1362
  	pgoff_t index;
  	unsigned long offset;
a0ee5ec52   Hugh Dickins   tmpfs: allocate o...
1363
  	enum sgp_type sgp = SGP_READ;
f7c1d0742   Geert Uytterhoeven   mm: Initialize er...
1364
  	int error = 0;
6e58e79db   Al Viro   introduce copy_pa...
1365
1366
1367
1368
1369
1370
1371
1372
1373
  	ssize_t retval;
  	size_t count;
  	loff_t *ppos = &iocb->ki_pos;
  	struct iov_iter iter;
  
  	retval = generic_segment_checks(iov, &nr_segs, &count, VERIFY_WRITE);
  	if (retval)
  		return retval;
  	iov_iter_init(&iter, iov, nr_segs, count, 0);
a0ee5ec52   Hugh Dickins   tmpfs: allocate o...
1374
1375
1376
1377
1378
1379
1380
1381
  
  	/*
  	 * 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
1382
1383
1384
1385
1386
1387
  
  	index = *ppos >> PAGE_CACHE_SHIFT;
  	offset = *ppos & ~PAGE_CACHE_MASK;
  
  	for (;;) {
  		struct page *page = NULL;
41ffe5d5c   Hugh Dickins   tmpfs: miscellane...
1388
1389
  		pgoff_t end_index;
  		unsigned long nr, ret;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
1390
1391
1392
1393
1394
1395
1396
1397
1398
1399
  		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;
  		}
6e58e79db   Al Viro   introduce copy_pa...
1400
1401
1402
1403
  		error = shmem_getpage(inode, index, &page, sgp, NULL);
  		if (error) {
  			if (error == -EINVAL)
  				error = 0;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
1404
1405
  			break;
  		}
d3602444e   Hugh Dickins   shmem_getpage ret...
1406
1407
  		if (page)
  			unlock_page(page);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
1408
1409
1410
  
  		/*
  		 * We must evaluate after, since reads (unlike writes)
1b1dcc1b5   Jes Sorensen   [PATCH] mutex sub...
1411
  		 * are called without i_mutex protection against truncate
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
1412
1413
1414
1415
1416
1417
1418
1419
1420
1421
1422
1423
1424
1425
1426
1427
1428
1429
1430
1431
1432
1433
1434
1435
1436
1437
1438
  		 */
  		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...
1439
  		} else {
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
1440
  			page = ZERO_PAGE(0);
b5810039a   Nick Piggin   [PATCH] core remo...
1441
1442
  			page_cache_get(page);
  		}
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
1443
1444
1445
1446
  
  		/*
  		 * Ok, we have the page, and it's up-to-date, so
  		 * now we can copy it to user space...
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
1447
  		 */
6e58e79db   Al Viro   introduce copy_pa...
1448
1449
  		ret = copy_page_to_iter(page, offset, nr, &iter);
  		retval += ret;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
1450
1451
1452
1453
1454
  		offset += ret;
  		index += offset >> PAGE_CACHE_SHIFT;
  		offset &= ~PAGE_CACHE_MASK;
  
  		page_cache_release(page);
6e58e79db   Al Viro   introduce copy_pa...
1455
  		if (!iov_iter_count(&iter))
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
1456
  			break;
6e58e79db   Al Viro   introduce copy_pa...
1457
1458
1459
1460
  		if (ret < nr) {
  			error = -EFAULT;
  			break;
  		}
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
1461
1462
1463
1464
  		cond_resched();
  	}
  
  	*ppos = ((loff_t) index << PAGE_CACHE_SHIFT) + offset;
6e58e79db   Al Viro   introduce copy_pa...
1465
1466
  	file_accessed(file);
  	return retval ? retval : error;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
1467
  }
708e3508c   Hugh Dickins   tmpfs: clone shme...
1468
1469
1470
1471
1472
  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...
1473
  	struct inode *inode = mapping->host;
708e3508c   Hugh Dickins   tmpfs: clone shme...
1474
1475
1476
1477
1478
1479
1480
1481
1482
1483
  	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,
047fe3605   Eric Dumazet   splice: fix racy ...
1484
  		.nr_pages_max = PIPE_DEF_BUFFERS,
708e3508c   Hugh Dickins   tmpfs: clone shme...
1485
1486
1487
1488
  		.flags = flags,
  		.ops = &page_cache_pipe_buf_ops,
  		.spd_release = spd_release_page,
  	};
71f0e07a6   Hugh Dickins   tmpfs: refine shm...
1489
  	isize = i_size_read(inode);
708e3508c   Hugh Dickins   tmpfs: clone shme...
1490
1491
1492
1493
1494
1495
1496
1497
1498
1499
1500
1501
1502
  	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;
a786c06d9   Al Viro   missing bits of "...
1503
  	nr_pages = min(req_pages, spd.nr_pages_max);
708e3508c   Hugh Dickins   tmpfs: clone shme...
1504

708e3508c   Hugh Dickins   tmpfs: clone shme...
1505
1506
1507
  	spd.nr_pages = find_get_pages_contig(mapping, index,
  						nr_pages, spd.pages);
  	index += spd.nr_pages;
708e3508c   Hugh Dickins   tmpfs: clone shme...
1508
  	error = 0;
708e3508c   Hugh Dickins   tmpfs: clone shme...
1509

71f0e07a6   Hugh Dickins   tmpfs: refine shm...
1510
  	while (spd.nr_pages < nr_pages) {
71f0e07a6   Hugh Dickins   tmpfs: refine shm...
1511
1512
1513
1514
  		error = shmem_getpage(inode, index, &page, SGP_CACHE, NULL);
  		if (error)
  			break;
  		unlock_page(page);
708e3508c   Hugh Dickins   tmpfs: clone shme...
1515
1516
1517
  		spd.pages[spd.nr_pages++] = page;
  		index++;
  	}
708e3508c   Hugh Dickins   tmpfs: clone shme...
1518
1519
1520
  	index = *ppos >> PAGE_CACHE_SHIFT;
  	nr_pages = spd.nr_pages;
  	spd.nr_pages = 0;
71f0e07a6   Hugh Dickins   tmpfs: refine shm...
1521

708e3508c   Hugh Dickins   tmpfs: clone shme...
1522
1523
1524
1525
1526
  	for (page_nr = 0; page_nr < nr_pages; page_nr++) {
  		unsigned int this_len;
  
  		if (!len)
  			break;
708e3508c   Hugh Dickins   tmpfs: clone shme...
1527
1528
  		this_len = min_t(unsigned long, len, PAGE_CACHE_SIZE - loff);
  		page = spd.pages[page_nr];
71f0e07a6   Hugh Dickins   tmpfs: refine shm...
1529
  		if (!PageUptodate(page) || page->mapping != mapping) {
71f0e07a6   Hugh Dickins   tmpfs: refine shm...
1530
1531
1532
  			error = shmem_getpage(inode, index, &page,
  							SGP_CACHE, NULL);
  			if (error)
708e3508c   Hugh Dickins   tmpfs: clone shme...
1533
  				break;
71f0e07a6   Hugh Dickins   tmpfs: refine shm...
1534
1535
1536
  			unlock_page(page);
  			page_cache_release(spd.pages[page_nr]);
  			spd.pages[page_nr] = page;
708e3508c   Hugh Dickins   tmpfs: clone shme...
1537
  		}
71f0e07a6   Hugh Dickins   tmpfs: refine shm...
1538
1539
  
  		isize = i_size_read(inode);
708e3508c   Hugh Dickins   tmpfs: clone shme...
1540
1541
1542
  		end_index = (isize - 1) >> PAGE_CACHE_SHIFT;
  		if (unlikely(!isize || index > end_index))
  			break;
708e3508c   Hugh Dickins   tmpfs: clone shme...
1543
1544
  		if (end_index == index) {
  			unsigned int plen;
708e3508c   Hugh Dickins   tmpfs: clone shme...
1545
1546
1547
  			plen = ((isize - 1) & ~PAGE_CACHE_MASK) + 1;
  			if (plen <= loff)
  				break;
708e3508c   Hugh Dickins   tmpfs: clone shme...
1548
1549
1550
1551
1552
1553
1554
1555
1556
1557
1558
  			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...
1559
1560
  	while (page_nr < nr_pages)
  		page_cache_release(spd.pages[page_nr++]);
708e3508c   Hugh Dickins   tmpfs: clone shme...
1561
1562
1563
  
  	if (spd.nr_pages)
  		error = splice_to_pipe(pipe, &spd);
047fe3605   Eric Dumazet   splice: fix racy ...
1564
  	splice_shrink_spd(&spd);
708e3508c   Hugh Dickins   tmpfs: clone shme...
1565
1566
1567
1568
1569
1570
1571
  
  	if (error > 0) {
  		*ppos += error;
  		file_accessed(in);
  	}
  	return error;
  }
220f2ac91   Hugh Dickins   tmpfs: support SE...
1572
1573
1574
1575
  /*
   * llseek SEEK_DATA or SEEK_HOLE through the radix_tree.
   */
  static pgoff_t shmem_seek_hole_data(struct address_space *mapping,
965c8e59c   Andrew Morton   lseek: the "whenc...
1576
  				    pgoff_t index, pgoff_t end, int whence)
220f2ac91   Hugh Dickins   tmpfs: support SE...
1577
1578
1579
1580
1581
1582
1583
1584
1585
1586
  {
  	struct page *page;
  	struct pagevec pvec;
  	pgoff_t indices[PAGEVEC_SIZE];
  	bool done = false;
  	int i;
  
  	pagevec_init(&pvec, 0);
  	pvec.nr = 1;		/* start small: we may be there already */
  	while (!done) {
0cd6144aa   Johannes Weiner   mm + fs: prepare ...
1587
  		pvec.nr = find_get_entries(mapping, index,
220f2ac91   Hugh Dickins   tmpfs: support SE...
1588
1589
  					pvec.nr, pvec.pages, indices);
  		if (!pvec.nr) {
965c8e59c   Andrew Morton   lseek: the "whenc...
1590
  			if (whence == SEEK_DATA)
220f2ac91   Hugh Dickins   tmpfs: support SE...
1591
1592
1593
1594
1595
  				index = end;
  			break;
  		}
  		for (i = 0; i < pvec.nr; i++, index++) {
  			if (index < indices[i]) {
965c8e59c   Andrew Morton   lseek: the "whenc...
1596
  				if (whence == SEEK_HOLE) {
220f2ac91   Hugh Dickins   tmpfs: support SE...
1597
1598
1599
1600
1601
1602
1603
1604
1605
1606
1607
  					done = true;
  					break;
  				}
  				index = indices[i];
  			}
  			page = pvec.pages[i];
  			if (page && !radix_tree_exceptional_entry(page)) {
  				if (!PageUptodate(page))
  					page = NULL;
  			}
  			if (index >= end ||
965c8e59c   Andrew Morton   lseek: the "whenc...
1608
1609
  			    (page && whence == SEEK_DATA) ||
  			    (!page && whence == SEEK_HOLE)) {
220f2ac91   Hugh Dickins   tmpfs: support SE...
1610
1611
1612
1613
  				done = true;
  				break;
  			}
  		}
0cd6144aa   Johannes Weiner   mm + fs: prepare ...
1614
  		pagevec_remove_exceptionals(&pvec);
220f2ac91   Hugh Dickins   tmpfs: support SE...
1615
1616
1617
1618
1619
1620
  		pagevec_release(&pvec);
  		pvec.nr = PAGEVEC_SIZE;
  		cond_resched();
  	}
  	return index;
  }
965c8e59c   Andrew Morton   lseek: the "whenc...
1621
  static loff_t shmem_file_llseek(struct file *file, loff_t offset, int whence)
220f2ac91   Hugh Dickins   tmpfs: support SE...
1622
1623
1624
1625
1626
  {
  	struct address_space *mapping = file->f_mapping;
  	struct inode *inode = mapping->host;
  	pgoff_t start, end;
  	loff_t new_offset;
965c8e59c   Andrew Morton   lseek: the "whenc...
1627
1628
  	if (whence != SEEK_DATA && whence != SEEK_HOLE)
  		return generic_file_llseek_size(file, offset, whence,
220f2ac91   Hugh Dickins   tmpfs: support SE...
1629
1630
1631
1632
1633
1634
1635
1636
1637
1638
1639
  					MAX_LFS_FILESIZE, i_size_read(inode));
  	mutex_lock(&inode->i_mutex);
  	/* We're holding i_mutex so we can access i_size directly */
  
  	if (offset < 0)
  		offset = -EINVAL;
  	else if (offset >= inode->i_size)
  		offset = -ENXIO;
  	else {
  		start = offset >> PAGE_CACHE_SHIFT;
  		end = (inode->i_size + PAGE_CACHE_SIZE - 1) >> PAGE_CACHE_SHIFT;
965c8e59c   Andrew Morton   lseek: the "whenc...
1640
  		new_offset = shmem_seek_hole_data(mapping, start, end, whence);
220f2ac91   Hugh Dickins   tmpfs: support SE...
1641
1642
1643
1644
  		new_offset <<= PAGE_CACHE_SHIFT;
  		if (new_offset > offset) {
  			if (new_offset < inode->i_size)
  				offset = new_offset;
965c8e59c   Andrew Morton   lseek: the "whenc...
1645
  			else if (whence == SEEK_DATA)
220f2ac91   Hugh Dickins   tmpfs: support SE...
1646
1647
1648
1649
1650
  				offset = -ENXIO;
  			else
  				offset = inode->i_size;
  		}
  	}
387aae6fd   Hugh Dickins   tmpfs: fix SEEK_D...
1651
1652
  	if (offset >= 0)
  		offset = vfs_setpos(file, offset, MAX_LFS_FILESIZE);
220f2ac91   Hugh Dickins   tmpfs: support SE...
1653
1654
1655
  	mutex_unlock(&inode->i_mutex);
  	return offset;
  }
83e4fa9c1   Hugh Dickins   tmpfs: support fa...
1656
1657
1658
  static long shmem_fallocate(struct file *file, int mode, loff_t offset,
  							 loff_t len)
  {
496ad9aa8   Al Viro   new helper: file_...
1659
  	struct inode *inode = file_inode(file);
e2d12e22c   Hugh Dickins   tmpfs: support fa...
1660
  	struct shmem_sb_info *sbinfo = SHMEM_SB(inode->i_sb);
1aac14003   Hugh Dickins   tmpfs: quit when ...
1661
  	struct shmem_falloc shmem_falloc;
e2d12e22c   Hugh Dickins   tmpfs: support fa...
1662
1663
  	pgoff_t start, index, end;
  	int error;
83e4fa9c1   Hugh Dickins   tmpfs: support fa...
1664
1665
1666
1667
1668
1669
1670
1671
1672
1673
1674
1675
1676
1677
  
  	mutex_lock(&inode->i_mutex);
  
  	if (mode & FALLOC_FL_PUNCH_HOLE) {
  		struct address_space *mapping = file->f_mapping;
  		loff_t unmap_start = round_up(offset, PAGE_SIZE);
  		loff_t unmap_end = round_down(offset + len, PAGE_SIZE) - 1;
  
  		if ((u64)unmap_end > (u64)unmap_start)
  			unmap_mapping_range(mapping, unmap_start,
  					    1 + unmap_end - unmap_start, 0);
  		shmem_truncate_range(inode, offset, offset + len - 1);
  		/* No need to unmap again: hole-punching leaves COWed pages */
  		error = 0;
e2d12e22c   Hugh Dickins   tmpfs: support fa...
1678
1679
1680
1681
1682
1683
1684
1685
1686
1687
1688
1689
1690
1691
  		goto out;
  	}
  
  	/* We need to check rlimit even when FALLOC_FL_KEEP_SIZE */
  	error = inode_newsize_ok(inode, offset + len);
  	if (error)
  		goto out;
  
  	start = offset >> PAGE_CACHE_SHIFT;
  	end = (offset + len + PAGE_CACHE_SIZE - 1) >> PAGE_CACHE_SHIFT;
  	/* Try to avoid a swapstorm if len is impossible to satisfy */
  	if (sbinfo->max_blocks && end - start > sbinfo->max_blocks) {
  		error = -ENOSPC;
  		goto out;
83e4fa9c1   Hugh Dickins   tmpfs: support fa...
1692
  	}
1aac14003   Hugh Dickins   tmpfs: quit when ...
1693
1694
1695
1696
1697
1698
1699
  	shmem_falloc.start = start;
  	shmem_falloc.next  = start;
  	shmem_falloc.nr_falloced = 0;
  	shmem_falloc.nr_unswapped = 0;
  	spin_lock(&inode->i_lock);
  	inode->i_private = &shmem_falloc;
  	spin_unlock(&inode->i_lock);
e2d12e22c   Hugh Dickins   tmpfs: support fa...
1700
1701
1702
1703
1704
1705
1706
1707
1708
  	for (index = start; index < end; index++) {
  		struct page *page;
  
  		/*
  		 * Good, the fallocate(2) manpage permits EINTR: we may have
  		 * been interrupted because we are using up too much memory.
  		 */
  		if (signal_pending(current))
  			error = -EINTR;
1aac14003   Hugh Dickins   tmpfs: quit when ...
1709
1710
  		else if (shmem_falloc.nr_unswapped > shmem_falloc.nr_falloced)
  			error = -ENOMEM;
e2d12e22c   Hugh Dickins   tmpfs: support fa...
1711
  		else
1635f6a74   Hugh Dickins   tmpfs: undo fallo...
1712
  			error = shmem_getpage(inode, index, &page, SGP_FALLOC,
e2d12e22c   Hugh Dickins   tmpfs: support fa...
1713
1714
  									NULL);
  		if (error) {
1635f6a74   Hugh Dickins   tmpfs: undo fallo...
1715
1716
1717
1718
  			/* Remove the !PageUptodate pages we added */
  			shmem_undo_range(inode,
  				(loff_t)start << PAGE_CACHE_SHIFT,
  				(loff_t)index << PAGE_CACHE_SHIFT, true);
1aac14003   Hugh Dickins   tmpfs: quit when ...
1719
  			goto undone;
e2d12e22c   Hugh Dickins   tmpfs: support fa...
1720
  		}
e2d12e22c   Hugh Dickins   tmpfs: support fa...
1721
  		/*
1aac14003   Hugh Dickins   tmpfs: quit when ...
1722
1723
1724
1725
1726
1727
1728
1729
  		 * Inform shmem_writepage() how far we have reached.
  		 * No need for lock or barrier: we have the page lock.
  		 */
  		shmem_falloc.next++;
  		if (!PageUptodate(page))
  			shmem_falloc.nr_falloced++;
  
  		/*
1635f6a74   Hugh Dickins   tmpfs: undo fallo...
1730
1731
1732
  		 * If !PageUptodate, leave it that way so that freeable pages
  		 * can be recognized if we need to rollback on error later.
  		 * But set_page_dirty so that memory pressure will swap rather
e2d12e22c   Hugh Dickins   tmpfs: support fa...
1733
1734
1735
1736
1737
1738
1739
1740
1741
1742
1743
  		 * than free the pages we are allocating (and SGP_CACHE pages
  		 * might still be clean: we now need to mark those dirty too).
  		 */
  		set_page_dirty(page);
  		unlock_page(page);
  		page_cache_release(page);
  		cond_resched();
  	}
  
  	if (!(mode & FALLOC_FL_KEEP_SIZE) && offset + len > inode->i_size)
  		i_size_write(inode, offset + len);
e2d12e22c   Hugh Dickins   tmpfs: support fa...
1744
  	inode->i_ctime = CURRENT_TIME;
1aac14003   Hugh Dickins   tmpfs: quit when ...
1745
1746
1747
1748
  undone:
  	spin_lock(&inode->i_lock);
  	inode->i_private = NULL;
  	spin_unlock(&inode->i_lock);
e2d12e22c   Hugh Dickins   tmpfs: support fa...
1749
  out:
83e4fa9c1   Hugh Dickins   tmpfs: support fa...
1750
1751
1752
  	mutex_unlock(&inode->i_mutex);
  	return error;
  }
726c33422   David Howells   [PATCH] VFS: Perm...
1753
  static int shmem_statfs(struct dentry *dentry, struct kstatfs *buf)
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
1754
  {
726c33422   David Howells   [PATCH] VFS: Perm...
1755
  	struct shmem_sb_info *sbinfo = SHMEM_SB(dentry->d_sb);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
1756
1757
1758
1759
  
  	buf->f_type = TMPFS_MAGIC;
  	buf->f_bsize = PAGE_CACHE_SIZE;
  	buf->f_namelen = NAME_MAX;
0edd73b33   Hugh Dickins   [PATCH] shmem: re...
1760
  	if (sbinfo->max_blocks) {
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
1761
  		buf->f_blocks = sbinfo->max_blocks;
41ffe5d5c   Hugh Dickins   tmpfs: miscellane...
1762
1763
1764
  		buf->f_bavail =
  		buf->f_bfree  = sbinfo->max_blocks -
  				percpu_counter_sum(&sbinfo->used_blocks);
0edd73b33   Hugh Dickins   [PATCH] shmem: re...
1765
1766
  	}
  	if (sbinfo->max_inodes) {
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
1767
1768
  		buf->f_files = sbinfo->max_inodes;
  		buf->f_ffree = sbinfo->free_inodes;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
1769
1770
1771
1772
1773
1774
1775
1776
1777
  	}
  	/* 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() ...
1778
  shmem_mknod(struct inode *dir, struct dentry *dentry, umode_t mode, dev_t dev)
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
1779
  {
0b0a0806b   Hugh Dickins   shmem: fix shared...
1780
  	struct inode *inode;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
1781
  	int error = -ENOSPC;
454abafe9   Dmitry Monakhov   ramfs: replace in...
1782
  	inode = shmem_get_inode(dir->i_sb, dir, mode, dev, VM_NORESERVE);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
1783
  	if (inode) {
feda821e7   Christoph Hellwig   fs: remove generi...
1784
1785
1786
  		error = simple_acl_create(dir, inode);
  		if (error)
  			goto out_iput;
2a7dba391   Eric Paris   fs/vfs/security: ...
1787
  		error = security_inode_init_security(inode, dir,
9d8f13ba3   Mimi Zohar   security: new sec...
1788
  						     &dentry->d_name,
6d9d88d07   Jarkko Sakkinen   tmpfs: security x...
1789
  						     shmem_initxattrs, NULL);
feda821e7   Christoph Hellwig   fs: remove generi...
1790
1791
  		if (error && error != -EOPNOTSUPP)
  			goto out_iput;
37ec43cdc   Mimi Zohar   evm: calculate HM...
1792

718deb6b6   Al Viro   Fix breakage in s...
1793
  		error = 0;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
1794
1795
1796
1797
  		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
1798
1799
  	}
  	return error;
feda821e7   Christoph Hellwig   fs: remove generi...
1800
1801
1802
  out_iput:
  	iput(inode);
  	return error;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
1803
  }
60545d0d4   Al Viro   [O_TMPFILE] it's ...
1804
1805
1806
1807
1808
1809
1810
1811
1812
1813
1814
  static int
  shmem_tmpfile(struct inode *dir, struct dentry *dentry, umode_t mode)
  {
  	struct inode *inode;
  	int error = -ENOSPC;
  
  	inode = shmem_get_inode(dir->i_sb, dir, mode, 0, VM_NORESERVE);
  	if (inode) {
  		error = security_inode_init_security(inode, dir,
  						     NULL,
  						     shmem_initxattrs, NULL);
feda821e7   Christoph Hellwig   fs: remove generi...
1815
1816
1817
1818
1819
  		if (error && error != -EOPNOTSUPP)
  			goto out_iput;
  		error = simple_acl_create(dir, inode);
  		if (error)
  			goto out_iput;
60545d0d4   Al Viro   [O_TMPFILE] it's ...
1820
1821
1822
  		d_tmpfile(dentry, inode);
  	}
  	return error;
feda821e7   Christoph Hellwig   fs: remove generi...
1823
1824
1825
  out_iput:
  	iput(inode);
  	return error;
60545d0d4   Al Viro   [O_TMPFILE] it's ...
1826
  }
18bb1db3e   Al Viro   switch vfs_mkdir(...
1827
  static int shmem_mkdir(struct inode *dir, struct dentry *dentry, umode_t mode)
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
1828
1829
1830
1831
1832
  {
  	int error;
  
  	if ((error = shmem_mknod(dir, dentry, mode | S_IFDIR, 0)))
  		return error;
d8c76e6f4   Dave Hansen   [PATCH] r/o bind ...
1833
  	inc_nlink(dir);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
1834
1835
  	return 0;
  }
4acdaf27e   Al Viro   switch ->create()...
1836
  static int shmem_create(struct inode *dir, struct dentry *dentry, umode_t mode,
ebfc3b49a   Al Viro   don't pass nameid...
1837
  		bool excl)
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
1838
1839
1840
1841
1842
1843
1844
1845
1846
1847
  {
  	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...
1848
  	int ret;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
1849
1850
1851
1852
1853
1854
  
  	/*
  	 * 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...
1855
1856
1857
  	ret = shmem_reserve_inode(inode->i_sb);
  	if (ret)
  		goto out;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
1858
1859
1860
  
  	dir->i_size += BOGO_DIRENT_SIZE;
  	inode->i_ctime = dir->i_ctime = dir->i_mtime = CURRENT_TIME;
d8c76e6f4   Dave Hansen   [PATCH] r/o bind ...
1861
  	inc_nlink(inode);
7de9c6ee3   Al Viro   new helper: ihold()
1862
  	ihold(inode);	/* New dentry reference */
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
1863
1864
  	dget(dentry);		/* Extra pinning count for the created dentry */
  	d_instantiate(dentry, inode);
5b04c6890   Pavel Emelyanov   shmem: factor out...
1865
1866
  out:
  	return ret;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
1867
1868
1869
1870
1871
  }
  
  static int shmem_unlink(struct inode *dir, struct dentry *dentry)
  {
  	struct inode *inode = dentry->d_inode;
5b04c6890   Pavel Emelyanov   shmem: factor out...
1872
1873
  	if (inode->i_nlink > 1 && !S_ISDIR(inode->i_mode))
  		shmem_free_inode(inode->i_sb);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
1874
1875
1876
  
  	dir->i_size -= BOGO_DIRENT_SIZE;
  	inode->i_ctime = dir->i_ctime = dir->i_mtime = CURRENT_TIME;
9a53c3a78   Dave Hansen   [PATCH] r/o bind ...
1877
  	drop_nlink(inode);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
1878
1879
1880
1881
1882
1883
1884
1885
  	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 ...
1886
1887
  	drop_nlink(dentry->d_inode);
  	drop_nlink(dir);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
1888
1889
1890
1891
1892
1893
1894
1895
1896
1897
1898
1899
1900
1901
1902
1903
1904
1905
1906
1907
  	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 ...
1908
  			drop_nlink(old_dir);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
1909
  	} else if (they_are_dirs) {
9a53c3a78   Dave Hansen   [PATCH] r/o bind ...
1910
  		drop_nlink(old_dir);
d8c76e6f4   Dave Hansen   [PATCH] r/o bind ...
1911
  		inc_nlink(new_dir);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
1912
1913
1914
1915
1916
1917
1918
1919
1920
1921
1922
1923
1924
1925
1926
  	}
  
  	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...
1927
  	struct page *page;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
1928
1929
1930
1931
1932
1933
  	char *kaddr;
  	struct shmem_inode_info *info;
  
  	len = strlen(symname) + 1;
  	if (len > PAGE_CACHE_SIZE)
  		return -ENAMETOOLONG;
454abafe9   Dmitry Monakhov   ramfs: replace in...
1934
  	inode = shmem_get_inode(dir->i_sb, dir, S_IFLNK|S_IRWXUGO, 0, VM_NORESERVE);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
1935
1936
  	if (!inode)
  		return -ENOSPC;
9d8f13ba3   Mimi Zohar   security: new sec...
1937
  	error = security_inode_init_security(inode, dir, &dentry->d_name,
6d9d88d07   Jarkko Sakkinen   tmpfs: security x...
1938
  					     shmem_initxattrs, NULL);
570bc1c2e   Stephen Smalley   [PATCH] tmpfs: En...
1939
1940
1941
1942
1943
1944
1945
  	if (error) {
  		if (error != -EOPNOTSUPP) {
  			iput(inode);
  			return error;
  		}
  		error = 0;
  	}
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
1946
1947
  	info = SHMEM_I(inode);
  	inode->i_size = len-1;
69f07ec93   Hugh Dickins   tmpfs: use kmemdu...
1948
1949
1950
1951
1952
1953
1954
  	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
1955
1956
1957
1958
1959
1960
  	} else {
  		error = shmem_getpage(inode, 0, &page, SGP_WRITE, NULL);
  		if (error) {
  			iput(inode);
  			return error;
  		}
14fcc23fd   Hugh Dickins   tmpfs: fix kernel...
1961
  		inode->i_mapping->a_ops = &shmem_aops;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
1962
  		inode->i_op = &shmem_symlink_inode_operations;
9b04c5fec   Cong Wang   mm: remove the se...
1963
  		kaddr = kmap_atomic(page);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
1964
  		memcpy(kaddr, symname, len);
9b04c5fec   Cong Wang   mm: remove the se...
1965
  		kunmap_atomic(kaddr);
ec9516fbc   Hugh Dickins   tmpfs: optimize c...
1966
  		SetPageUptodate(page);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
1967
  		set_page_dirty(page);
6746aff74   Wu Fengguang   HWPOISON: shmem: ...
1968
  		unlock_page(page);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
1969
1970
  		page_cache_release(page);
  	}
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
1971
1972
1973
1974
1975
1976
  	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...
1977
  static void *shmem_follow_short_symlink(struct dentry *dentry, struct nameidata *nd)
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
1978
  {
69f07ec93   Hugh Dickins   tmpfs: use kmemdu...
1979
  	nd_set_link(nd, SHMEM_I(dentry->d_inode)->symlink);
cc314eef0   Linus Torvalds   Fix nasty ncpfs s...
1980
  	return NULL;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
1981
  }
cc314eef0   Linus Torvalds   Fix nasty ncpfs s...
1982
  static void *shmem_follow_link(struct dentry *dentry, struct nameidata *nd)
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
1983
1984
  {
  	struct page *page = NULL;
41ffe5d5c   Hugh Dickins   tmpfs: miscellane...
1985
1986
  	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...
1987
1988
  	if (page)
  		unlock_page(page);
cc314eef0   Linus Torvalds   Fix nasty ncpfs s...
1989
  	return page;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
1990
  }
cc314eef0   Linus Torvalds   Fix nasty ncpfs s...
1991
  static void shmem_put_link(struct dentry *dentry, struct nameidata *nd, void *cookie)
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
1992
1993
  {
  	if (!IS_ERR(nd_get_link(nd))) {
cc314eef0   Linus Torvalds   Fix nasty ncpfs s...
1994
  		struct page *page = cookie;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
1995
1996
1997
  		kunmap(page);
  		mark_page_accessed(page);
  		page_cache_release(page);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
1998
1999
  	}
  }
b09e0fa4b   Eric Paris   tmpfs: implement ...
2000
  #ifdef CONFIG_TMPFS_XATTR
467118102   Randy Dunlap   mm/shmem and tiny...
2001
  /*
b09e0fa4b   Eric Paris   tmpfs: implement ...
2002
2003
   * 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...
2004
2005
2006
   * like ACLs, we also need to implement the security.* handlers at
   * filesystem level, though.
   */
6d9d88d07   Jarkko Sakkinen   tmpfs: security x...
2007
  /*
6d9d88d07   Jarkko Sakkinen   tmpfs: security x...
2008
2009
2010
2011
2012
2013
2014
2015
   * 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;
38f386574   Aristeu Rozanski   xattr: extract si...
2016
  	struct simple_xattr *new_xattr;
6d9d88d07   Jarkko Sakkinen   tmpfs: security x...
2017
2018
2019
  	size_t len;
  
  	for (xattr = xattr_array; xattr->name != NULL; xattr++) {
38f386574   Aristeu Rozanski   xattr: extract si...
2020
  		new_xattr = simple_xattr_alloc(xattr->value, xattr->value_len);
6d9d88d07   Jarkko Sakkinen   tmpfs: security x...
2021
2022
2023
2024
2025
2026
2027
2028
2029
2030
2031
2032
2033
2034
2035
  		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);
38f386574   Aristeu Rozanski   xattr: extract si...
2036
  		simple_xattr_list_add(&info->xattrs, new_xattr);
6d9d88d07   Jarkko Sakkinen   tmpfs: security x...
2037
2038
2039
2040
  	}
  
  	return 0;
  }
bb4354538   Stephen Hemminger   fs: xattr_handler...
2041
  static const struct xattr_handler *shmem_xattr_handlers[] = {
b09e0fa4b   Eric Paris   tmpfs: implement ...
2042
  #ifdef CONFIG_TMPFS_POSIX_ACL
feda821e7   Christoph Hellwig   fs: remove generi...
2043
2044
  	&posix_acl_access_xattr_handler,
  	&posix_acl_default_xattr_handler,
b09e0fa4b   Eric Paris   tmpfs: implement ...
2045
  #endif
39f0247d3   Andreas Gruenbacher   [PATCH] Access Co...
2046
2047
  	NULL
  };
b09e0fa4b   Eric Paris   tmpfs: implement ...
2048
2049
2050
2051
2052
2053
2054
2055
2056
2057
2058
2059
2060
2061
2062
2063
2064
2065
2066
2067
2068
2069
2070
  
  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)
  {
38f386574   Aristeu Rozanski   xattr: extract si...
2071
  	struct shmem_inode_info *info = SHMEM_I(dentry->d_inode);
b09e0fa4b   Eric Paris   tmpfs: implement ...
2072
2073
2074
2075
2076
2077
2078
2079
2080
2081
2082
2083
2084
  	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;
38f386574   Aristeu Rozanski   xattr: extract si...
2085
  	return simple_xattr_get(&info->xattrs, name, buffer, size);
b09e0fa4b   Eric Paris   tmpfs: implement ...
2086
2087
2088
2089
2090
  }
  
  static int shmem_setxattr(struct dentry *dentry, const char *name,
  			  const void *value, size_t size, int flags)
  {
38f386574   Aristeu Rozanski   xattr: extract si...
2091
  	struct shmem_inode_info *info = SHMEM_I(dentry->d_inode);
b09e0fa4b   Eric Paris   tmpfs: implement ...
2092
2093
2094
2095
2096
2097
2098
2099
2100
2101
2102
2103
2104
  	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;
38f386574   Aristeu Rozanski   xattr: extract si...
2105
  	return simple_xattr_set(&info->xattrs, name, value, size, flags);
b09e0fa4b   Eric Paris   tmpfs: implement ...
2106
2107
2108
2109
  }
  
  static int shmem_removexattr(struct dentry *dentry, const char *name)
  {
38f386574   Aristeu Rozanski   xattr: extract si...
2110
  	struct shmem_inode_info *info = SHMEM_I(dentry->d_inode);
b09e0fa4b   Eric Paris   tmpfs: implement ...
2111
2112
2113
2114
2115
2116
2117
2118
2119
2120
2121
2122
2123
  	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;
38f386574   Aristeu Rozanski   xattr: extract si...
2124
  	return simple_xattr_remove(&info->xattrs, name);
b09e0fa4b   Eric Paris   tmpfs: implement ...
2125
2126
2127
2128
  }
  
  static ssize_t shmem_listxattr(struct dentry *dentry, char *buffer, size_t size)
  {
38f386574   Aristeu Rozanski   xattr: extract si...
2129
2130
  	struct shmem_inode_info *info = SHMEM_I(dentry->d_inode);
  	return simple_xattr_list(&info->xattrs, buffer, size);
b09e0fa4b   Eric Paris   tmpfs: implement ...
2131
2132
  }
  #endif /* CONFIG_TMPFS_XATTR */
69f07ec93   Hugh Dickins   tmpfs: use kmemdu...
2133
  static const struct inode_operations shmem_short_symlink_operations = {
b09e0fa4b   Eric Paris   tmpfs: implement ...
2134
  	.readlink	= generic_readlink,
69f07ec93   Hugh Dickins   tmpfs: use kmemdu...
2135
  	.follow_link	= shmem_follow_short_symlink,
b09e0fa4b   Eric Paris   tmpfs: implement ...
2136
2137
2138
2139
2140
2141
2142
2143
2144
2145
2146
2147
2148
2149
2150
2151
2152
  #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...
2153
  #endif
b09e0fa4b   Eric Paris   tmpfs: implement ...
2154
  };
39f0247d3   Andreas Gruenbacher   [PATCH] Access Co...
2155

91828a405   David M. Grimes   [PATCH] knfsd: ad...
2156
2157
2158
2159
2160
2161
2162
2163
2164
2165
2166
2167
  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...
2168
2169
  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...
2170
  {
91828a405   David M. Grimes   [PATCH] knfsd: ad...
2171
  	struct inode *inode;
480b116c9   Christoph Hellwig   shmem: new export...
2172
  	struct dentry *dentry = NULL;
35c2a7f49   Hugh Dickins   tmpfs,ceph,gfs2,i...
2173
  	u64 inum;
480b116c9   Christoph Hellwig   shmem: new export...
2174
2175
2176
  
  	if (fh_len < 3)
  		return NULL;
91828a405   David M. Grimes   [PATCH] knfsd: ad...
2177

35c2a7f49   Hugh Dickins   tmpfs,ceph,gfs2,i...
2178
2179
  	inum = fid->raw[2];
  	inum = (inum << 32) | fid->raw[1];
480b116c9   Christoph Hellwig   shmem: new export...
2180
2181
  	inode = ilookup5(sb, (unsigned long)(inum + fid->raw[0]),
  			shmem_match, fid->raw);
91828a405   David M. Grimes   [PATCH] knfsd: ad...
2182
  	if (inode) {
480b116c9   Christoph Hellwig   shmem: new export...
2183
  		dentry = d_find_alias(inode);
91828a405   David M. Grimes   [PATCH] knfsd: ad...
2184
2185
  		iput(inode);
  	}
480b116c9   Christoph Hellwig   shmem: new export...
2186
  	return dentry;
91828a405   David M. Grimes   [PATCH] knfsd: ad...
2187
  }
b0b0382bb   Al Viro   ->encode_fh() API...
2188
2189
  static int shmem_encode_fh(struct inode *inode, __u32 *fh, int *len,
  				struct inode *parent)
91828a405   David M. Grimes   [PATCH] knfsd: ad...
2190
  {
5fe0c2378   Aneesh Kumar K.V   exportfs: Return ...
2191
2192
  	if (*len < 3) {
  		*len = 3;
94e07a759   Namjae Jeon   fs: encode_fh: re...
2193
  		return FILEID_INVALID;
5fe0c2378   Aneesh Kumar K.V   exportfs: Return ...
2194
  	}
91828a405   David M. Grimes   [PATCH] knfsd: ad...
2195

1d3382cbf   Al Viro   new helper: inode...
2196
  	if (inode_unhashed(inode)) {
91828a405   David M. Grimes   [PATCH] knfsd: ad...
2197
2198
2199
2200
2201
2202
2203
  		/* 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...
2204
  		if (inode_unhashed(inode))
91828a405   David M. Grimes   [PATCH] knfsd: ad...
2205
2206
2207
2208
2209
2210
2211
2212
2213
2214
2215
2216
  			__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...
2217
  static const struct export_operations shmem_export_ops = {
91828a405   David M. Grimes   [PATCH] knfsd: ad...
2218
  	.get_parent     = shmem_get_parent,
91828a405   David M. Grimes   [PATCH] knfsd: ad...
2219
  	.encode_fh      = shmem_encode_fh,
480b116c9   Christoph Hellwig   shmem: new export...
2220
  	.fh_to_dentry	= shmem_fh_to_dentry,
91828a405   David M. Grimes   [PATCH] knfsd: ad...
2221
  };
680d794ba   akpm@linux-foundation.org   mount options: fi...
2222
2223
  static int shmem_parse_options(char *options, struct shmem_sb_info *sbinfo,
  			       bool remount)
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
2224
2225
  {
  	char *this_char, *value, *rest;
49cd0a5c2   Greg Thelen   tmpfs: fix mempol...
2226
  	struct mempolicy *mpol = NULL;
8751e0395   Eric W. Biederman   userns: Convert t...
2227
2228
  	uid_t uid;
  	gid_t gid;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
2229

b00dc3ad7   Hugh Dickins   [PATCH] tmpfs: fi...
2230
2231
2232
2233
2234
2235
2236
2237
2238
2239
2240
2241
2242
2243
2244
2245
2246
  	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
2247
2248
2249
2250
2251
2252
2253
2254
2255
  		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);
49cd0a5c2   Greg Thelen   tmpfs: fix mempol...
2256
  			goto error;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
2257
2258
2259
2260
2261
2262
2263
2264
2265
2266
2267
2268
2269
  		}
  
  		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...
2270
2271
  			sbinfo->max_blocks =
  				DIV_ROUND_UP(size, PAGE_CACHE_SIZE);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
2272
  		} else if (!strcmp(this_char,"nr_blocks")) {
680d794ba   akpm@linux-foundation.org   mount options: fi...
2273
  			sbinfo->max_blocks = memparse(value, &rest);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
2274
2275
2276
  			if (*rest)
  				goto bad_val;
  		} else if (!strcmp(this_char,"nr_inodes")) {
680d794ba   akpm@linux-foundation.org   mount options: fi...
2277
  			sbinfo->max_inodes = memparse(value, &rest);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
2278
2279
2280
  			if (*rest)
  				goto bad_val;
  		} else if (!strcmp(this_char,"mode")) {
680d794ba   akpm@linux-foundation.org   mount options: fi...
2281
  			if (remount)
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
2282
  				continue;
680d794ba   akpm@linux-foundation.org   mount options: fi...
2283
  			sbinfo->mode = simple_strtoul(value, &rest, 8) & 07777;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
2284
2285
2286
  			if (*rest)
  				goto bad_val;
  		} else if (!strcmp(this_char,"uid")) {
680d794ba   akpm@linux-foundation.org   mount options: fi...
2287
  			if (remount)
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
2288
  				continue;
8751e0395   Eric W. Biederman   userns: Convert t...
2289
  			uid = simple_strtoul(value, &rest, 0);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
2290
2291
  			if (*rest)
  				goto bad_val;
8751e0395   Eric W. Biederman   userns: Convert t...
2292
2293
2294
  			sbinfo->uid = make_kuid(current_user_ns(), uid);
  			if (!uid_valid(sbinfo->uid))
  				goto bad_val;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
2295
  		} else if (!strcmp(this_char,"gid")) {
680d794ba   akpm@linux-foundation.org   mount options: fi...
2296
  			if (remount)
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
2297
  				continue;
8751e0395   Eric W. Biederman   userns: Convert t...
2298
  			gid = simple_strtoul(value, &rest, 0);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
2299
2300
  			if (*rest)
  				goto bad_val;
8751e0395   Eric W. Biederman   userns: Convert t...
2301
2302
2303
  			sbinfo->gid = make_kgid(current_user_ns(), gid);
  			if (!gid_valid(sbinfo->gid))
  				goto bad_val;
7339ff830   Robin Holt   [PATCH] Add tmpfs...
2304
  		} else if (!strcmp(this_char,"mpol")) {
49cd0a5c2   Greg Thelen   tmpfs: fix mempol...
2305
2306
2307
  			mpol_put(mpol);
  			mpol = NULL;
  			if (mpol_parse_str(value, &mpol))
7339ff830   Robin Holt   [PATCH] Add tmpfs...
2308
  				goto bad_val;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
2309
2310
2311
2312
  		} else {
  			printk(KERN_ERR "tmpfs: Bad mount option %s
  ",
  			       this_char);
49cd0a5c2   Greg Thelen   tmpfs: fix mempol...
2313
  			goto error;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
2314
2315
  		}
  	}
49cd0a5c2   Greg Thelen   tmpfs: fix mempol...
2316
  	sbinfo->mpol = mpol;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
2317
2318
2319
2320
2321
2322
  	return 0;
  
  bad_val:
  	printk(KERN_ERR "tmpfs: Bad value '%s' for mount option '%s'
  ",
  	       value, this_char);
49cd0a5c2   Greg Thelen   tmpfs: fix mempol...
2323
2324
  error:
  	mpol_put(mpol);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
2325
2326
2327
2328
2329
2330
2331
  	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...
2332
  	struct shmem_sb_info config = *sbinfo;
0edd73b33   Hugh Dickins   [PATCH] shmem: re...
2333
2334
  	unsigned long inodes;
  	int error = -EINVAL;
5f00110f7   Greg Thelen   tmpfs: fix use-af...
2335
  	config.mpol = NULL;
680d794ba   akpm@linux-foundation.org   mount options: fi...
2336
  	if (shmem_parse_options(data, &config, true))
0edd73b33   Hugh Dickins   [PATCH] shmem: re...
2337
  		return error;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
2338

0edd73b33   Hugh Dickins   [PATCH] shmem: re...
2339
  	spin_lock(&sbinfo->stat_lock);
0edd73b33   Hugh Dickins   [PATCH] shmem: re...
2340
  	inodes = sbinfo->max_inodes - sbinfo->free_inodes;
7e496299d   Tim Chen   tmpfs: make tmpfs...
2341
  	if (percpu_counter_compare(&sbinfo->used_blocks, config.max_blocks) > 0)
0edd73b33   Hugh Dickins   [PATCH] shmem: re...
2342
  		goto out;
680d794ba   akpm@linux-foundation.org   mount options: fi...
2343
  	if (config.max_inodes < inodes)
0edd73b33   Hugh Dickins   [PATCH] shmem: re...
2344
2345
  		goto out;
  	/*
54af60421   Hugh Dickins   tmpfs: convert sh...
2346
  	 * Those tests disallow limited->unlimited while any are in use;
0edd73b33   Hugh Dickins   [PATCH] shmem: re...
2347
2348
2349
  	 * 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...
2350
  	if (config.max_blocks && !sbinfo->max_blocks)
0edd73b33   Hugh Dickins   [PATCH] shmem: re...
2351
  		goto out;
680d794ba   akpm@linux-foundation.org   mount options: fi...
2352
  	if (config.max_inodes && !sbinfo->max_inodes)
0edd73b33   Hugh Dickins   [PATCH] shmem: re...
2353
2354
2355
  		goto out;
  
  	error = 0;
680d794ba   akpm@linux-foundation.org   mount options: fi...
2356
  	sbinfo->max_blocks  = config.max_blocks;
680d794ba   akpm@linux-foundation.org   mount options: fi...
2357
2358
  	sbinfo->max_inodes  = config.max_inodes;
  	sbinfo->free_inodes = config.max_inodes - inodes;
71fe804b6   Lee Schermerhorn   mempolicy: use st...
2359

5f00110f7   Greg Thelen   tmpfs: fix use-af...
2360
2361
2362
2363
2364
2365
2366
  	/*
  	 * Preserve previous mempolicy unless mpol remount option was specified.
  	 */
  	if (config.mpol) {
  		mpol_put(sbinfo->mpol);
  		sbinfo->mpol = config.mpol;	/* transfers initial ref */
  	}
0edd73b33   Hugh Dickins   [PATCH] shmem: re...
2367
2368
2369
  out:
  	spin_unlock(&sbinfo->stat_lock);
  	return error;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
2370
  }
680d794ba   akpm@linux-foundation.org   mount options: fi...
2371

34c80b1d9   Al Viro   vfs: switch ->sho...
2372
  static int shmem_show_options(struct seq_file *seq, struct dentry *root)
680d794ba   akpm@linux-foundation.org   mount options: fi...
2373
  {
34c80b1d9   Al Viro   vfs: switch ->sho...
2374
  	struct shmem_sb_info *sbinfo = SHMEM_SB(root->d_sb);
680d794ba   akpm@linux-foundation.org   mount options: fi...
2375
2376
2377
2378
2379
2380
2381
  
  	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...
2382
  		seq_printf(seq, ",mode=%03ho", sbinfo->mode);
8751e0395   Eric W. Biederman   userns: Convert t...
2383
2384
2385
2386
2387
2388
  	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...
2389
  	shmem_show_mpol(seq, sbinfo->mpol);
680d794ba   akpm@linux-foundation.org   mount options: fi...
2390
2391
2392
  	return 0;
  }
  #endif /* CONFIG_TMPFS */
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
2393
2394
2395
  
  static void shmem_put_super(struct super_block *sb)
  {
602586a83   Hugh Dickins   shmem: put_super ...
2396
2397
2398
  	struct shmem_sb_info *sbinfo = SHMEM_SB(sb);
  
  	percpu_counter_destroy(&sbinfo->used_blocks);
49cd0a5c2   Greg Thelen   tmpfs: fix mempol...
2399
  	mpol_put(sbinfo->mpol);
602586a83   Hugh Dickins   shmem: put_super ...
2400
  	kfree(sbinfo);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
2401
2402
  	sb->s_fs_info = NULL;
  }
2b2af54a5   Kay Sievers   Driver Core: devt...
2403
  int shmem_fill_super(struct super_block *sb, void *data, int silent)
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
2404
2405
  {
  	struct inode *inode;
0edd73b33   Hugh Dickins   [PATCH] shmem: re...
2406
  	struct shmem_sb_info *sbinfo;
680d794ba   akpm@linux-foundation.org   mount options: fi...
2407
2408
2409
  	int err = -ENOMEM;
  
  	/* Round up to L1_CACHE_BYTES to resist false sharing */
425fbf047   Pekka Enberg   shmem: initialize...
2410
  	sbinfo = kzalloc(max((int)sizeof(struct shmem_sb_info),
680d794ba   akpm@linux-foundation.org   mount options: fi...
2411
2412
2413
  				L1_CACHE_BYTES), GFP_KERNEL);
  	if (!sbinfo)
  		return -ENOMEM;
680d794ba   akpm@linux-foundation.org   mount options: fi...
2414
  	sbinfo->mode = S_IRWXUGO | S_ISVTX;
76aac0e9a   David Howells   CRED: Wrap task c...
2415
2416
  	sbinfo->uid = current_fsuid();
  	sbinfo->gid = current_fsgid();
680d794ba   akpm@linux-foundation.org   mount options: fi...
2417
  	sb->s_fs_info = sbinfo;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
2418

0edd73b33   Hugh Dickins   [PATCH] shmem: re...
2419
  #ifdef CONFIG_TMPFS
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
2420
2421
2422
2423
2424
  	/*
  	 * 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.
  	 */
ca4e05195   Al Viro   shm_mnt is as lon...
2425
  	if (!(sb->s_flags & MS_KERNMOUNT)) {
680d794ba   akpm@linux-foundation.org   mount options: fi...
2426
2427
2428
2429
2430
2431
  		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;
  		}
ca4e05195   Al Viro   shm_mnt is as lon...
2432
2433
  	} else {
  		sb->s_flags |= MS_NOUSER;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
2434
  	}
91828a405   David M. Grimes   [PATCH] knfsd: ad...
2435
  	sb->s_export_op = &shmem_export_ops;
2f6e38f3c   Hugh Dickins   tmpfs: enable NOS...
2436
  	sb->s_flags |= MS_NOSEC;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
2437
2438
2439
  #else
  	sb->s_flags |= MS_NOUSER;
  #endif
0edd73b33   Hugh Dickins   [PATCH] shmem: re...
2440
  	spin_lock_init(&sbinfo->stat_lock);
602586a83   Hugh Dickins   shmem: put_super ...
2441
2442
  	if (percpu_counter_init(&sbinfo->used_blocks, 0))
  		goto failed;
680d794ba   akpm@linux-foundation.org   mount options: fi...
2443
  	sbinfo->free_inodes = sbinfo->max_inodes;
0edd73b33   Hugh Dickins   [PATCH] shmem: re...
2444

285b2c4fd   Hugh Dickins   tmpfs: demolish o...
2445
  	sb->s_maxbytes = MAX_LFS_FILESIZE;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
2446
2447
2448
2449
  	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...
2450
  	sb->s_time_gran = 1;
b09e0fa4b   Eric Paris   tmpfs: implement ...
2451
  #ifdef CONFIG_TMPFS_XATTR
39f0247d3   Andreas Gruenbacher   [PATCH] Access Co...
2452
  	sb->s_xattr = shmem_xattr_handlers;
b09e0fa4b   Eric Paris   tmpfs: implement ...
2453
2454
  #endif
  #ifdef CONFIG_TMPFS_POSIX_ACL
39f0247d3   Andreas Gruenbacher   [PATCH] Access Co...
2455
2456
  	sb->s_flags |= MS_POSIXACL;
  #endif
0edd73b33   Hugh Dickins   [PATCH] shmem: re...
2457

454abafe9   Dmitry Monakhov   ramfs: replace in...
2458
  	inode = shmem_get_inode(sb, NULL, S_IFDIR | sbinfo->mode, 0, VM_NORESERVE);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
2459
2460
  	if (!inode)
  		goto failed;
680d794ba   akpm@linux-foundation.org   mount options: fi...
2461
2462
  	inode->i_uid = sbinfo->uid;
  	inode->i_gid = sbinfo->gid;
318ceed08   Al Viro   tidy up after d_m...
2463
2464
  	sb->s_root = d_make_root(inode);
  	if (!sb->s_root)
48fde701a   Al Viro   switch open-coded...
2465
  		goto failed;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
2466
  	return 0;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
2467
2468
2469
2470
  failed:
  	shmem_put_super(sb);
  	return err;
  }
fcc234f88   Pekka Enberg   [PATCH] mm: kill ...
2471
  static struct kmem_cache *shmem_inode_cachep;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
2472
2473
2474
  
  static struct inode *shmem_alloc_inode(struct super_block *sb)
  {
41ffe5d5c   Hugh Dickins   tmpfs: miscellane...
2475
2476
2477
  	struct shmem_inode_info *info;
  	info = kmem_cache_alloc(shmem_inode_cachep, GFP_KERNEL);
  	if (!info)
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
2478
  		return NULL;
41ffe5d5c   Hugh Dickins   tmpfs: miscellane...
2479
  	return &info->vfs_inode;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
2480
  }
41ffe5d5c   Hugh Dickins   tmpfs: miscellane...
2481
  static void shmem_destroy_callback(struct rcu_head *head)
fa0d7e3de   Nick Piggin   fs: icache RCU fr...
2482
2483
  {
  	struct inode *inode = container_of(head, struct inode, i_rcu);
fa0d7e3de   Nick Piggin   fs: icache RCU fr...
2484
2485
  	kmem_cache_free(shmem_inode_cachep, SHMEM_I(inode));
  }
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
2486
2487
  static void shmem_destroy_inode(struct inode *inode)
  {
09208d150   Al Viro   shmem, ramfs: pro...
2488
  	if (S_ISREG(inode->i_mode))
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
2489
  		mpol_free_shared_policy(&SHMEM_I(inode)->policy);
41ffe5d5c   Hugh Dickins   tmpfs: miscellane...
2490
  	call_rcu(&inode->i_rcu, shmem_destroy_callback);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
2491
  }
41ffe5d5c   Hugh Dickins   tmpfs: miscellane...
2492
  static void shmem_init_inode(void *foo)
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
2493
  {
41ffe5d5c   Hugh Dickins   tmpfs: miscellane...
2494
2495
  	struct shmem_inode_info *info = foo;
  	inode_init_once(&info->vfs_inode);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
2496
  }
41ffe5d5c   Hugh Dickins   tmpfs: miscellane...
2497
  static int shmem_init_inodecache(void)
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
2498
2499
2500
  {
  	shmem_inode_cachep = kmem_cache_create("shmem_inode_cache",
  				sizeof(struct shmem_inode_info),
41ffe5d5c   Hugh Dickins   tmpfs: miscellane...
2501
  				0, SLAB_PANIC, shmem_init_inode);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
2502
2503
  	return 0;
  }
41ffe5d5c   Hugh Dickins   tmpfs: miscellane...
2504
  static void shmem_destroy_inodecache(void)
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
2505
  {
1a1d92c10   Alexey Dobriyan   [PATCH] Really ig...
2506
  	kmem_cache_destroy(shmem_inode_cachep);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
2507
  }
f5e54d6e5   Christoph Hellwig   [PATCH] mark addr...
2508
  static const struct address_space_operations shmem_aops = {
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
2509
  	.writepage	= shmem_writepage,
767193253   Ken Chen   [PATCH] simplify ...
2510
  	.set_page_dirty	= __set_page_dirty_no_writeback,
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
2511
  #ifdef CONFIG_TMPFS
800d15a53   Nick Piggin   implement simple ...
2512
2513
  	.write_begin	= shmem_write_begin,
  	.write_end	= shmem_write_end,
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
2514
  #endif
304dbdb7a   Lee Schermerhorn   [PATCH] add migra...
2515
  	.migratepage	= migrate_page,
aa261f549   Andi Kleen   HWPOISON: Enable ...
2516
  	.error_remove_page = generic_error_remove_page,
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
2517
  };
15ad7cdcf   Helge Deller   [PATCH] struct se...
2518
  static const struct file_operations shmem_file_operations = {
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
2519
2520
  	.mmap		= shmem_mmap,
  #ifdef CONFIG_TMPFS
220f2ac91   Hugh Dickins   tmpfs: support SE...
2521
  	.llseek		= shmem_file_llseek,
bcd78e496   Hugh Dickins   tmpfs: support aio
2522
  	.read		= do_sync_read,
5402b976a   Hugh Dickins   shmem_file_write ...
2523
  	.write		= do_sync_write,
bcd78e496   Hugh Dickins   tmpfs: support aio
2524
  	.aio_read	= shmem_file_aio_read,
5402b976a   Hugh Dickins   shmem_file_write ...
2525
  	.aio_write	= generic_file_aio_write,
1b061d924   Christoph Hellwig   rename the generi...
2526
  	.fsync		= noop_fsync,
708e3508c   Hugh Dickins   tmpfs: clone shme...
2527
  	.splice_read	= shmem_file_splice_read,
ae9764164   Hugh Dickins   shmem: convert to...
2528
  	.splice_write	= generic_file_splice_write,
83e4fa9c1   Hugh Dickins   tmpfs: support fa...
2529
  	.fallocate	= shmem_fallocate,
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
2530
2531
  #endif
  };
92e1d5be9   Arjan van de Ven   [PATCH] mark stru...
2532
  static const struct inode_operations shmem_inode_operations = {
94c1e62df   Hugh Dickins   tmpfs: take contr...
2533
  	.setattr	= shmem_setattr,
b09e0fa4b   Eric Paris   tmpfs: implement ...
2534
2535
2536
2537
2538
  #ifdef CONFIG_TMPFS_XATTR
  	.setxattr	= shmem_setxattr,
  	.getxattr	= shmem_getxattr,
  	.listxattr	= shmem_listxattr,
  	.removexattr	= shmem_removexattr,
feda821e7   Christoph Hellwig   fs: remove generi...
2539
  	.set_acl	= simple_set_acl,
b09e0fa4b   Eric Paris   tmpfs: implement ...
2540
  #endif
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
2541
  };
92e1d5be9   Arjan van de Ven   [PATCH] mark stru...
2542
  static const struct inode_operations shmem_dir_inode_operations = {
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
2543
2544
2545
2546
2547
2548
2549
2550
2551
2552
  #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,
60545d0d4   Al Viro   [O_TMPFILE] it's ...
2553
  	.tmpfile	= shmem_tmpfile,
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
2554
  #endif
b09e0fa4b   Eric Paris   tmpfs: implement ...
2555
2556
2557
2558
2559
2560
  #ifdef CONFIG_TMPFS_XATTR
  	.setxattr	= shmem_setxattr,
  	.getxattr	= shmem_getxattr,
  	.listxattr	= shmem_listxattr,
  	.removexattr	= shmem_removexattr,
  #endif
39f0247d3   Andreas Gruenbacher   [PATCH] Access Co...
2561
  #ifdef CONFIG_TMPFS_POSIX_ACL
94c1e62df   Hugh Dickins   tmpfs: take contr...
2562
  	.setattr	= shmem_setattr,
feda821e7   Christoph Hellwig   fs: remove generi...
2563
  	.set_acl	= simple_set_acl,
39f0247d3   Andreas Gruenbacher   [PATCH] Access Co...
2564
2565
  #endif
  };
92e1d5be9   Arjan van de Ven   [PATCH] mark stru...
2566
  static const struct inode_operations shmem_special_inode_operations = {
b09e0fa4b   Eric Paris   tmpfs: implement ...
2567
2568
2569
2570
2571
2572
  #ifdef CONFIG_TMPFS_XATTR
  	.setxattr	= shmem_setxattr,
  	.getxattr	= shmem_getxattr,
  	.listxattr	= shmem_listxattr,
  	.removexattr	= shmem_removexattr,
  #endif
39f0247d3   Andreas Gruenbacher   [PATCH] Access Co...
2573
  #ifdef CONFIG_TMPFS_POSIX_ACL
94c1e62df   Hugh Dickins   tmpfs: take contr...
2574
  	.setattr	= shmem_setattr,
feda821e7   Christoph Hellwig   fs: remove generi...
2575
  	.set_acl	= simple_set_acl,
39f0247d3   Andreas Gruenbacher   [PATCH] Access Co...
2576
  #endif
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
2577
  };
759b9775c   Hugh Dickins   [PATCH] shmem and...
2578
  static const struct super_operations shmem_ops = {
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
2579
2580
2581
2582
2583
  	.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...
2584
  	.show_options	= shmem_show_options,
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
2585
  #endif
1f895f75d   Al Viro   switch shmem.c to...
2586
  	.evict_inode	= shmem_evict_inode,
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
2587
2588
2589
  	.drop_inode	= generic_delete_inode,
  	.put_super	= shmem_put_super,
  };
f0f37e2f7   Alexey Dobriyan   const: mark struc...
2590
  static const struct vm_operations_struct shmem_vm_ops = {
54cb8821d   Nick Piggin   mm: merge populat...
2591
  	.fault		= shmem_fault,
d7c175517   Ning Qu   mm: implement ->m...
2592
  	.map_pages	= filemap_map_pages,
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
2593
2594
2595
2596
  #ifdef CONFIG_NUMA
  	.set_policy     = shmem_set_policy,
  	.get_policy     = shmem_get_policy,
  #endif
0b173bc4d   Konstantin Khlebnikov   mm: kill vma flag...
2597
  	.remap_pages	= generic_file_remap_pages,
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
2598
  };
3c26ff6e4   Al Viro   convert get_sb_no...
2599
2600
  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
2601
  {
3c26ff6e4   Al Viro   convert get_sb_no...
2602
  	return mount_nodev(fs_type, flags, data, shmem_fill_super);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
2603
  }
41ffe5d5c   Hugh Dickins   tmpfs: miscellane...
2604
  static struct file_system_type shmem_fs_type = {
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
2605
2606
  	.owner		= THIS_MODULE,
  	.name		= "tmpfs",
3c26ff6e4   Al Viro   convert get_sb_no...
2607
  	.mount		= shmem_mount,
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
2608
  	.kill_sb	= kill_litter_super,
2b8576cb0   Eric W. Biederman   userns: Allow the...
2609
  	.fs_flags	= FS_USERNS_MOUNT,
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
2610
  };
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
2611

41ffe5d5c   Hugh Dickins   tmpfs: miscellane...
2612
  int __init shmem_init(void)
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
2613
2614
  {
  	int error;
16203a7a9   Rob Landley   initmpfs: make ro...
2615
2616
2617
  	/* If rootfs called this, don't re-init */
  	if (shmem_inode_cachep)
  		return 0;
e0bf68dde   Peter Zijlstra   mm: bdi init hooks
2618
2619
2620
  	error = bdi_init(&shmem_backing_dev_info);
  	if (error)
  		goto out4;
41ffe5d5c   Hugh Dickins   tmpfs: miscellane...
2621
  	error = shmem_init_inodecache();
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
2622
2623
  	if (error)
  		goto out3;
41ffe5d5c   Hugh Dickins   tmpfs: miscellane...
2624
  	error = register_filesystem(&shmem_fs_type);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
2625
2626
2627
2628
2629
  	if (error) {
  		printk(KERN_ERR "Could not register tmpfs
  ");
  		goto out2;
  	}
95dc112a5   Greg Kroah-Hartman   [PATCH] devfs: Re...
2630

ca4e05195   Al Viro   shm_mnt is as lon...
2631
  	shm_mnt = kern_mount(&shmem_fs_type);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
2632
2633
2634
2635
2636
2637
2638
2639
2640
  	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...
2641
  	unregister_filesystem(&shmem_fs_type);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
2642
  out2:
41ffe5d5c   Hugh Dickins   tmpfs: miscellane...
2643
  	shmem_destroy_inodecache();
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
2644
  out3:
e0bf68dde   Peter Zijlstra   mm: bdi init hooks
2645
2646
  	bdi_destroy(&shmem_backing_dev_info);
  out4:
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
2647
2648
2649
  	shm_mnt = ERR_PTR(error);
  	return error;
  }
853ac43ab   Matt Mackall   shmem: unify regu...
2650
2651
2652
2653
2654
2655
2656
2657
2658
2659
2660
  
  #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.
   */
41ffe5d5c   Hugh Dickins   tmpfs: miscellane...
2661
  static struct file_system_type shmem_fs_type = {
853ac43ab   Matt Mackall   shmem: unify regu...
2662
  	.name		= "tmpfs",
3c26ff6e4   Al Viro   convert get_sb_no...
2663
  	.mount		= ramfs_mount,
853ac43ab   Matt Mackall   shmem: unify regu...
2664
  	.kill_sb	= kill_litter_super,
2b8576cb0   Eric W. Biederman   userns: Allow the...
2665
  	.fs_flags	= FS_USERNS_MOUNT,
853ac43ab   Matt Mackall   shmem: unify regu...
2666
  };
41ffe5d5c   Hugh Dickins   tmpfs: miscellane...
2667
  int __init shmem_init(void)
853ac43ab   Matt Mackall   shmem: unify regu...
2668
  {
41ffe5d5c   Hugh Dickins   tmpfs: miscellane...
2669
  	BUG_ON(register_filesystem(&shmem_fs_type) != 0);
853ac43ab   Matt Mackall   shmem: unify regu...
2670

41ffe5d5c   Hugh Dickins   tmpfs: miscellane...
2671
  	shm_mnt = kern_mount(&shmem_fs_type);
853ac43ab   Matt Mackall   shmem: unify regu...
2672
2673
2674
2675
  	BUG_ON(IS_ERR(shm_mnt));
  
  	return 0;
  }
41ffe5d5c   Hugh Dickins   tmpfs: miscellane...
2676
  int shmem_unuse(swp_entry_t swap, struct page *page)
853ac43ab   Matt Mackall   shmem: unify regu...
2677
2678
2679
  {
  	return 0;
  }
3f96b79ad   Hugh Dickins   tmpfs: depend on ...
2680
2681
2682
2683
  int shmem_lock(struct file *file, int lock, struct user_struct *user)
  {
  	return 0;
  }
245132643   Hugh Dickins   SHM_UNLOCK: fix U...
2684
2685
2686
  void shmem_unlock_mapping(struct address_space *mapping)
  {
  }
41ffe5d5c   Hugh Dickins   tmpfs: miscellane...
2687
  void shmem_truncate_range(struct inode *inode, loff_t lstart, loff_t lend)
94c1e62df   Hugh Dickins   tmpfs: take contr...
2688
  {
41ffe5d5c   Hugh Dickins   tmpfs: miscellane...
2689
  	truncate_inode_pages_range(inode->i_mapping, lstart, lend);
94c1e62df   Hugh Dickins   tmpfs: take contr...
2690
2691
  }
  EXPORT_SYMBOL_GPL(shmem_truncate_range);
0b0a0806b   Hugh Dickins   shmem: fix shared...
2692
2693
  #define shmem_vm_ops				generic_file_vm_ops
  #define shmem_file_operations			ramfs_file_operations
454abafe9   Dmitry Monakhov   ramfs: replace in...
2694
  #define shmem_get_inode(sb, dir, mode, dev, flags)	ramfs_get_inode(sb, dir, mode, dev)
0b0a0806b   Hugh Dickins   shmem: fix shared...
2695
2696
  #define shmem_acct_size(flags, size)		0
  #define shmem_unacct_size(flags, size)		do {} while (0)
853ac43ab   Matt Mackall   shmem: unify regu...
2697
2698
2699
2700
  
  #endif /* CONFIG_SHMEM */
  
  /* common code */
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
2701

3451538a1   Al Viro   shmem_setup_file(...
2702
  static struct dentry_operations anon_ops = {
118b23022   Al Viro   cope with potenti...
2703
  	.d_dname = simple_dname
3451538a1   Al Viro   shmem_setup_file(...
2704
  };
c72770909   Eric Paris   security: shmem: ...
2705
2706
  static struct file *__shmem_file_setup(const char *name, loff_t size,
  				       unsigned long flags, unsigned int i_flags)
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
2707
  {
6b4d0b279   Al Viro   clean shmem_file_...
2708
  	struct file *res;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
2709
  	struct inode *inode;
2c48b9c45   Al Viro   switch alloc_file...
2710
  	struct path path;
3451538a1   Al Viro   shmem_setup_file(...
2711
  	struct super_block *sb;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
2712
2713
2714
  	struct qstr this;
  
  	if (IS_ERR(shm_mnt))
6b4d0b279   Al Viro   clean shmem_file_...
2715
  		return ERR_CAST(shm_mnt);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
2716

285b2c4fd   Hugh Dickins   tmpfs: demolish o...
2717
  	if (size < 0 || size > MAX_LFS_FILESIZE)
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
2718
2719
2720
2721
  		return ERR_PTR(-EINVAL);
  
  	if (shmem_acct_size(flags, size))
  		return ERR_PTR(-ENOMEM);
6b4d0b279   Al Viro   clean shmem_file_...
2722
  	res = ERR_PTR(-ENOMEM);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
2723
2724
2725
  	this.name = name;
  	this.len = strlen(name);
  	this.hash = 0; /* will go */
3451538a1   Al Viro   shmem_setup_file(...
2726
2727
  	sb = shm_mnt->mnt_sb;
  	path.dentry = d_alloc_pseudo(sb, &this);
2c48b9c45   Al Viro   switch alloc_file...
2728
  	if (!path.dentry)
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
2729
  		goto put_memory;
3451538a1   Al Viro   shmem_setup_file(...
2730
  	d_set_d_op(path.dentry, &anon_ops);
2c48b9c45   Al Viro   switch alloc_file...
2731
  	path.mnt = mntget(shm_mnt);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
2732

6b4d0b279   Al Viro   clean shmem_file_...
2733
  	res = ERR_PTR(-ENOSPC);
3451538a1   Al Viro   shmem_setup_file(...
2734
  	inode = shmem_get_inode(sb, NULL, S_IFREG | S_IRWXUGO, 0, flags);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
2735
  	if (!inode)
4b42af81f   Al Viro   switch shmem_file...
2736
  		goto put_dentry;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
2737

c72770909   Eric Paris   security: shmem: ...
2738
  	inode->i_flags |= i_flags;
2c48b9c45   Al Viro   switch alloc_file...
2739
  	d_instantiate(path.dentry, inode);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
2740
  	inode->i_size = size;
6d6b77f16   Miklos Szeredi   filesystems: add ...
2741
  	clear_nlink(inode);	/* It is unlinked */
26567cdbb   Al Viro   fix nommu breakag...
2742
2743
  	res = ERR_PTR(ramfs_nommu_expand_for_mapping(inode, size));
  	if (IS_ERR(res))
4b42af81f   Al Viro   switch shmem_file...
2744
  		goto put_dentry;
4b42af81f   Al Viro   switch shmem_file...
2745

6b4d0b279   Al Viro   clean shmem_file_...
2746
  	res = alloc_file(&path, FMODE_WRITE | FMODE_READ,
4b42af81f   Al Viro   switch shmem_file...
2747
  		  &shmem_file_operations);
6b4d0b279   Al Viro   clean shmem_file_...
2748
  	if (IS_ERR(res))
4b42af81f   Al Viro   switch shmem_file...
2749
  		goto put_dentry;
6b4d0b279   Al Viro   clean shmem_file_...
2750
  	return res;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
2751

1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
2752
  put_dentry:
2c48b9c45   Al Viro   switch alloc_file...
2753
  	path_put(&path);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
2754
2755
  put_memory:
  	shmem_unacct_size(flags, size);
6b4d0b279   Al Viro   clean shmem_file_...
2756
  	return res;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
2757
  }
c72770909   Eric Paris   security: shmem: ...
2758
2759
2760
2761
2762
2763
2764
2765
2766
2767
2768
2769
2770
2771
2772
2773
2774
2775
2776
2777
2778
2779
2780
2781
2782
2783
  
  /**
   * shmem_kernel_file_setup - get an unlinked file living in tmpfs which must be
   * 	kernel internal.  There will be NO LSM permission checks against the
   * 	underlying inode.  So users of this interface must do LSM checks at a
   * 	higher layer.  The one user is the big_key implementation.  LSM checks
   * 	are provided at the key level rather than the inode level.
   * @name: name for dentry (to be seen in /proc/<pid>/maps
   * @size: size to be set for the file
   * @flags: VM_NORESERVE suppresses pre-accounting of the entire object size
   */
  struct file *shmem_kernel_file_setup(const char *name, loff_t size, unsigned long flags)
  {
  	return __shmem_file_setup(name, size, flags, S_PRIVATE);
  }
  
  /**
   * shmem_file_setup - get an unlinked file living in tmpfs
   * @name: name for dentry (to be seen in /proc/<pid>/maps
   * @size: size to be set for the file
   * @flags: VM_NORESERVE suppresses pre-accounting of the entire object size
   */
  struct file *shmem_file_setup(const char *name, loff_t size, unsigned long flags)
  {
  	return __shmem_file_setup(name, size, flags, 0);
  }
395e0ddc4   Keith Packard   Export shmem_file...
2784
  EXPORT_SYMBOL_GPL(shmem_file_setup);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
2785

467118102   Randy Dunlap   mm/shmem and tiny...
2786
  /**
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
2787
   * shmem_zero_setup - setup a shared anonymous mapping
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
2788
2789
2790
2791
2792
2793
2794
2795
2796
2797
2798
2799
2800
2801
2802
2803
2804
   * @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;
  	return 0;
  }
d9d90e5eb   Hugh Dickins   tmpfs: add shmem_...
2805
2806
2807
2808
2809
2810
2811
2812
2813
2814
2815
2816
2817
  
  /**
   * 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...
2818
2819
   * 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_...
2820
2821
2822
2823
   */
  struct page *shmem_read_mapping_page_gfp(struct address_space *mapping,
  					 pgoff_t index, gfp_t gfp)
  {
68da9f055   Hugh Dickins   tmpfs: pass gfp t...
2824
2825
  #ifdef CONFIG_SHMEM
  	struct inode *inode = mapping->host;
9276aad6c   Hugh Dickins   tmpfs: remove_shm...
2826
  	struct page *page;
68da9f055   Hugh Dickins   tmpfs: pass gfp t...
2827
2828
2829
2830
2831
2832
2833
2834
2835
2836
2837
2838
2839
  	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_...
2840
  	return read_cache_page_gfp(mapping, index, gfp);
68da9f055   Hugh Dickins   tmpfs: pass gfp t...
2841
  #endif
d9d90e5eb   Hugh Dickins   tmpfs: add shmem_...
2842
2843
  }
  EXPORT_SYMBOL_GPL(shmem_read_mapping_page_gfp);