Blame view

mm/shmem.c 89.7 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>
9183df25f   David Herrmann   shm: add memfd_cr...
67
  #include <linux/syscalls.h>
40e041a2c   David Herrmann   shm: add sealing API
68
  #include <linux/fcntl.h>
9183df25f   David Herrmann   shm: add memfd_cr...
69
  #include <uapi/linux/memfd.h>
304dbdb7a   Lee Schermerhorn   [PATCH] add migra...
70

1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
71
  #include <asm/uaccess.h>
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
72
  #include <asm/pgtable.h>
caefba174   Hugh Dickins   shmem: respect MA...
73
  #define BLOCKS_PER_PAGE  (PAGE_CACHE_SIZE/512)
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
74
  #define VM_ACCT(size)    (PAGE_CACHE_ALIGN(size) >> PAGE_SHIFT)
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
75
76
  /* Pretend that each entry is of this size in directory's i_size */
  #define BOGO_DIRENT_SIZE 20
69f07ec93   Hugh Dickins   tmpfs: use kmemdu...
77
78
  /* 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 ...
79
  /*
f00cdc6df   Hugh Dickins   shmem: fix faulti...
80
81
82
   * shmem_fallocate communicates with shmem_fault or shmem_writepage 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.
1aac14003   Hugh Dickins   tmpfs: quit when ...
83
84
   */
  struct shmem_falloc {
8e205f779   Hugh Dickins   shmem: fix faulti...
85
  	wait_queue_head_t *waitq; /* faults into hole wait for punch to end */
1aac14003   Hugh Dickins   tmpfs: quit when ...
86
87
88
89
90
  	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...
91
  /* Flag allocation requirements to shmem_getpage */
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
92
  enum sgp_type {
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
93
94
  	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...
95
  	SGP_DIRTY,	/* like SGP_CACHE, but set new page dirty */
1635f6a74   Hugh Dickins   tmpfs: undo fallo...
96
97
  	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
98
  };
b76db7354   Andrew Morton   mount-options-fix...
99
  #ifdef CONFIG_TMPFS
680d794ba   akpm@linux-foundation.org   mount options: fi...
100
101
102
103
104
105
106
107
108
  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...
109
  #endif
680d794ba   akpm@linux-foundation.org   mount options: fi...
110

bde05d1cc   Hugh Dickins   shmem: replace pa...
111
112
113
  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...
114
115
116
117
118
119
120
121
122
  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
123

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

6c231b7ba   Ravikiran G Thirumalai   [PATCH] Additions...
183
  static struct backing_dev_info shmem_backing_dev_info  __read_mostly = {
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
184
  	.ra_pages	= 0,	/* No readahead */
4f98a2fee   Rik van Riel   vmscan: split LRU...
185
  	.capabilities	= BDI_CAP_NO_ACCT_AND_WRITEBACK | BDI_CAP_SWAP_BACKED,
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
186
187
188
  };
  
  static LIST_HEAD(shmem_swaplist);
cb5f7b9a4   Hugh Dickins   tmpfs: make shmem...
189
  static DEFINE_MUTEX(shmem_swaplist_mutex);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
190

5b04c6890   Pavel Emelyanov   shmem: factor out...
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
  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...
215
  /**
41ffe5d5c   Hugh Dickins   tmpfs: miscellane...
216
   * shmem_recalc_inode - recalculate the block usage of an inode
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
   * @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...
234
235
236
  		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
237
  		info->alloced -= freed;
54af60421   Hugh Dickins   tmpfs: convert sh...
238
  		inode->i_blocks -= freed * BLOCKS_PER_PAGE;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
239
  		shmem_unacct_blocks(info->flags, freed);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
240
241
  	}
  }
7a5d0fbb2   Hugh Dickins   tmpfs: convert sh...
242
243
244
245
246
247
248
  /*
   * 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...
249
  	void *item;
7a5d0fbb2   Hugh Dickins   tmpfs: convert sh...
250
251
  
  	VM_BUG_ON(!expected);
6dbaf22ce   Johannes Weiner   mm: shmem: save o...
252
  	VM_BUG_ON(!replacement);
7a5d0fbb2   Hugh Dickins   tmpfs: convert sh...
253
  	pslot = radix_tree_lookup_slot(&mapping->page_tree, index);
6dbaf22ce   Johannes Weiner   mm: shmem: save o...
254
255
256
  	if (!pslot)
  		return -ENOENT;
  	item = radix_tree_deref_slot_protected(pslot, &mapping->tree_lock);
7a5d0fbb2   Hugh Dickins   tmpfs: convert sh...
257
258
  	if (item != expected)
  		return -ENOENT;
6dbaf22ce   Johannes Weiner   mm: shmem: save o...
259
  	radix_tree_replace_slot(pslot, replacement);
7a5d0fbb2   Hugh Dickins   tmpfs: convert sh...
260
261
262
263
  	return 0;
  }
  
  /*
d18992286   Hugh Dickins   shmem: fix negati...
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
   * 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...
282
283
284
285
   * 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,
fed400a18   Wang Sheng-Hui   mm/shmem.c: remov...
286
  				   pgoff_t index, void *expected)
46f65ec15   Hugh Dickins   tmpfs: convert sh...
287
  {
b065b4321   Hugh Dickins   shmem: cleanup sh...
288
  	int error;
46f65ec15   Hugh Dickins   tmpfs: convert sh...
289

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

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

83e4fa9c1   Hugh Dickins   tmpfs: support fa...
440
  	if (partial_start) {
bda97eab0   Hugh Dickins   tmpfs: copy trunc...
441
442
443
  		struct page *page = NULL;
  		shmem_getpage(inode, start - 1, &page, SGP_READ, NULL);
  		if (page) {
83e4fa9c1   Hugh Dickins   tmpfs: support fa...
444
445
446
447
448
449
450
451
452
453
454
455
456
457
458
459
  			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...
460
461
462
463
464
  			set_page_dirty(page);
  			unlock_page(page);
  			page_cache_release(page);
  		}
  	}
83e4fa9c1   Hugh Dickins   tmpfs: support fa...
465
466
  	if (start >= end)
  		return;
bda97eab0   Hugh Dickins   tmpfs: copy trunc...
467
468
  
  	index = start;
b1a366500   Hugh Dickins   shmem: fix splici...
469
  	while (index < end) {
bda97eab0   Hugh Dickins   tmpfs: copy trunc...
470
  		cond_resched();
0cd6144aa   Johannes Weiner   mm + fs: prepare ...
471
472
  
  		pvec.nr = find_get_entries(mapping, index,
83e4fa9c1   Hugh Dickins   tmpfs: support fa...
473
  				min(end - index, (pgoff_t)PAGEVEC_SIZE),
0cd6144aa   Johannes Weiner   mm + fs: prepare ...
474
  				pvec.pages, indices);
7a5d0fbb2   Hugh Dickins   tmpfs: convert sh...
475
  		if (!pvec.nr) {
b1a366500   Hugh Dickins   shmem: fix splici...
476
477
  			/* If all gone or hole-punch or unfalloc, we're done */
  			if (index == start || end != -1)
bda97eab0   Hugh Dickins   tmpfs: copy trunc...
478
  				break;
b1a366500   Hugh Dickins   shmem: fix splici...
479
  			/* But if truncating, restart to make sure all gone */
bda97eab0   Hugh Dickins   tmpfs: copy trunc...
480
481
482
  			index = start;
  			continue;
  		}
bda97eab0   Hugh Dickins   tmpfs: copy trunc...
483
484
  		for (i = 0; i < pagevec_count(&pvec); i++) {
  			struct page *page = pvec.pages[i];
7a5d0fbb2   Hugh Dickins   tmpfs: convert sh...
485
  			index = indices[i];
83e4fa9c1   Hugh Dickins   tmpfs: support fa...
486
  			if (index >= end)
bda97eab0   Hugh Dickins   tmpfs: copy trunc...
487
  				break;
7a5d0fbb2   Hugh Dickins   tmpfs: convert sh...
488
  			if (radix_tree_exceptional_entry(page)) {
1635f6a74   Hugh Dickins   tmpfs: undo fallo...
489
490
  				if (unfalloc)
  					continue;
b1a366500   Hugh Dickins   shmem: fix splici...
491
492
493
494
495
496
  				if (shmem_free_swap(mapping, index, page)) {
  					/* Swap was replaced by page: retry */
  					index--;
  					break;
  				}
  				nr_swaps_freed++;
7a5d0fbb2   Hugh Dickins   tmpfs: convert sh...
497
498
  				continue;
  			}
bda97eab0   Hugh Dickins   tmpfs: copy trunc...
499
  			lock_page(page);
1635f6a74   Hugh Dickins   tmpfs: undo fallo...
500
501
  			if (!unfalloc || !PageUptodate(page)) {
  				if (page->mapping == mapping) {
309381fea   Sasha Levin   mm: dump page whe...
502
  					VM_BUG_ON_PAGE(PageWriteback(page), page);
1635f6a74   Hugh Dickins   tmpfs: undo fallo...
503
  					truncate_inode_page(mapping, page);
b1a366500   Hugh Dickins   shmem: fix splici...
504
505
506
507
508
  				} else {
  					/* Page was replaced by swap: retry */
  					unlock_page(page);
  					index--;
  					break;
1635f6a74   Hugh Dickins   tmpfs: undo fallo...
509
  				}
7a5d0fbb2   Hugh Dickins   tmpfs: convert sh...
510
  			}
bda97eab0   Hugh Dickins   tmpfs: copy trunc...
511
512
  			unlock_page(page);
  		}
0cd6144aa   Johannes Weiner   mm + fs: prepare ...
513
  		pagevec_remove_exceptionals(&pvec);
245132643   Hugh Dickins   SHM_UNLOCK: fix U...
514
  		pagevec_release(&pvec);
bda97eab0   Hugh Dickins   tmpfs: copy trunc...
515
516
  		index++;
  	}
94c1e62df   Hugh Dickins   tmpfs: take contr...
517

1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
518
  	spin_lock(&info->lock);
7a5d0fbb2   Hugh Dickins   tmpfs: convert sh...
519
  	info->swapped -= nr_swaps_freed;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
520
521
  	shmem_recalc_inode(inode);
  	spin_unlock(&info->lock);
1635f6a74   Hugh Dickins   tmpfs: undo fallo...
522
  }
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
523

1635f6a74   Hugh Dickins   tmpfs: undo fallo...
524
525
526
  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...
527
  	inode->i_ctime = inode->i_mtime = CURRENT_TIME;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
528
  }
94c1e62df   Hugh Dickins   tmpfs: take contr...
529
  EXPORT_SYMBOL_GPL(shmem_truncate_range);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
530

94c1e62df   Hugh Dickins   tmpfs: take contr...
531
  static int shmem_setattr(struct dentry *dentry, struct iattr *attr)
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
532
533
  {
  	struct inode *inode = dentry->d_inode;
40e041a2c   David Herrmann   shm: add sealing API
534
  	struct shmem_inode_info *info = SHMEM_I(inode);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
535
  	int error;
db78b877f   Christoph Hellwig   always call inode...
536
537
538
  	error = inode_change_ok(inode, attr);
  	if (error)
  		return error;
94c1e62df   Hugh Dickins   tmpfs: take contr...
539
540
541
  	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...
542

40e041a2c   David Herrmann   shm: add sealing API
543
544
545
546
  		/* protected by i_mutex */
  		if ((newsize < oldsize && (info->seals & F_SEAL_SHRINK)) ||
  		    (newsize > oldsize && (info->seals & F_SEAL_GROW)))
  			return -EPERM;
94c1e62df   Hugh Dickins   tmpfs: take contr...
547
  		if (newsize != oldsize) {
771425179   Konstantin Khlebnikov   shmem: update mem...
548
549
550
551
  			error = shmem_reacct_size(SHMEM_I(inode)->flags,
  					oldsize, newsize);
  			if (error)
  				return error;
94c1e62df   Hugh Dickins   tmpfs: take contr...
552
553
554
555
556
557
558
559
560
561
  			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
562
  	}
db78b877f   Christoph Hellwig   always call inode...
563
  	setattr_copy(inode, attr);
db78b877f   Christoph Hellwig   always call inode...
564
  	if (attr->ia_valid & ATTR_MODE)
feda821e7   Christoph Hellwig   fs: remove generi...
565
  		error = posix_acl_chmod(inode, inode->i_mode);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
566
567
  	return error;
  }
1f895f75d   Al Viro   switch shmem.c to...
568
  static void shmem_evict_inode(struct inode *inode)
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
569
  {
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
570
  	struct shmem_inode_info *info = SHMEM_I(inode);
3889e6e76   npiggin@suse.de   tmpfs: convert to...
571
  	if (inode->i_mapping->a_ops == &shmem_aops) {
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
572
573
  		shmem_unacct_size(info->flags, inode->i_size);
  		inode->i_size = 0;
3889e6e76   npiggin@suse.de   tmpfs: convert to...
574
  		shmem_truncate_range(inode, 0, (loff_t)-1);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
575
  		if (!list_empty(&info->swaplist)) {
cb5f7b9a4   Hugh Dickins   tmpfs: make shmem...
576
  			mutex_lock(&shmem_swaplist_mutex);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
577
  			list_del_init(&info->swaplist);
cb5f7b9a4   Hugh Dickins   tmpfs: make shmem...
578
  			mutex_unlock(&shmem_swaplist_mutex);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
579
  		}
69f07ec93   Hugh Dickins   tmpfs: use kmemdu...
580
581
  	} else
  		kfree(info->symlink);
b09e0fa4b   Eric Paris   tmpfs: implement ...
582

38f386574   Aristeu Rozanski   xattr: extract si...
583
  	simple_xattrs_free(&info->xattrs);
0f3c42f52   Hugh Dickins   tmpfs: change fin...
584
  	WARN_ON(inode->i_blocks);
5b04c6890   Pavel Emelyanov   shmem: factor out...
585
  	shmem_free_inode(inode->i_sb);
dbd5768f8   Jan Kara   vfs: Rename end_w...
586
  	clear_inode(inode);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
587
  }
46f65ec15   Hugh Dickins   tmpfs: convert sh...
588
589
590
  /*
   * If swap found in inode, free it and move page from swapcache to filecache.
   */
41ffe5d5c   Hugh Dickins   tmpfs: miscellane...
591
  static int shmem_unuse_inode(struct shmem_inode_info *info,
bde05d1cc   Hugh Dickins   shmem: replace pa...
592
  			     swp_entry_t swap, struct page **pagep)
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
593
  {
285b2c4fd   Hugh Dickins   tmpfs: demolish o...
594
  	struct address_space *mapping = info->vfs_inode.i_mapping;
46f65ec15   Hugh Dickins   tmpfs: convert sh...
595
  	void *radswap;
41ffe5d5c   Hugh Dickins   tmpfs: miscellane...
596
  	pgoff_t index;
bde05d1cc   Hugh Dickins   shmem: replace pa...
597
598
  	gfp_t gfp;
  	int error = 0;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
599

46f65ec15   Hugh Dickins   tmpfs: convert sh...
600
  	radswap = swp_to_radix_entry(swap);
e504f3fdd   Hugh Dickins   tmpfs radix_tree:...
601
  	index = radix_tree_locate_item(&mapping->page_tree, radswap);
46f65ec15   Hugh Dickins   tmpfs: convert sh...
602
  	if (index == -1)
00501b531   Johannes Weiner   mm: memcontrol: r...
603
  		return -EAGAIN;	/* tell shmem_unuse we found nothing */
2e0e26c76   Hugh Dickins   tmpfs: open a win...
604

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

bde05d1cc   Hugh Dickins   shmem: replace pa...
614
615
616
617
618
619
620
  	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...
621
622
623
624
625
626
627
628
629
630
631
632
633
634
635
  		 * 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...
636
637
638
639
  		 */
  		if (!page_swapcount(*pagep))
  			error = -ENOENT;
  	}
d13d14430   KAMEZAWA Hiroyuki   memcg: handle swa...
640
  	/*
778dd893a   Hugh Dickins   tmpfs: fix race b...
641
642
643
  	 * 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...
644
  	 */
bde05d1cc   Hugh Dickins   shmem: replace pa...
645
646
  	if (!error)
  		error = shmem_add_to_page_cache(*pagep, mapping, index,
fed400a18   Wang Sheng-Hui   mm/shmem.c: remov...
647
  						radswap);
48f170fb7   Hugh Dickins   tmpfs: simplify u...
648
  	if (error != -ENOMEM) {
46f65ec15   Hugh Dickins   tmpfs: convert sh...
649
650
651
652
  		/*
  		 * 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...
653
654
  		delete_from_swap_cache(*pagep);
  		set_page_dirty(*pagep);
46f65ec15   Hugh Dickins   tmpfs: convert sh...
655
656
657
658
659
660
  		if (!error) {
  			spin_lock(&info->lock);
  			info->swapped--;
  			spin_unlock(&info->lock);
  			swap_free(swap);
  		}
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
661
  	}
2e0e26c76   Hugh Dickins   tmpfs: open a win...
662
  	return error;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
663
664
665
  }
  
  /*
46f65ec15   Hugh Dickins   tmpfs: convert sh...
666
   * Search through swapped inodes to find and replace swap by page.
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
667
   */
41ffe5d5c   Hugh Dickins   tmpfs: miscellane...
668
  int shmem_unuse(swp_entry_t swap, struct page *page)
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
669
  {
41ffe5d5c   Hugh Dickins   tmpfs: miscellane...
670
  	struct list_head *this, *next;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
671
  	struct shmem_inode_info *info;
00501b531   Johannes Weiner   mm: memcontrol: r...
672
  	struct mem_cgroup *memcg;
bde05d1cc   Hugh Dickins   shmem: replace pa...
673
674
675
676
  	int error = 0;
  
  	/*
  	 * There's a faint possibility that swap page was replaced before
0142ef6cd   Hugh Dickins   shmem: replace_pa...
677
  	 * caller locked it: caller will come back later with the right page.
bde05d1cc   Hugh Dickins   shmem: replace pa...
678
  	 */
0142ef6cd   Hugh Dickins   shmem: replace_pa...
679
  	if (unlikely(!PageSwapCache(page) || page_private(page) != swap.val))
bde05d1cc   Hugh Dickins   shmem: replace pa...
680
  		goto out;
778dd893a   Hugh Dickins   tmpfs: fix race b...
681
682
683
684
685
  
  	/*
  	 * 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...
686
  	 */
00501b531   Johannes Weiner   mm: memcontrol: r...
687
  	error = mem_cgroup_try_charge(page, current->mm, GFP_KERNEL, &memcg);
778dd893a   Hugh Dickins   tmpfs: fix race b...
688
689
  	if (error)
  		goto out;
46f65ec15   Hugh Dickins   tmpfs: convert sh...
690
  	/* No radix_tree_preload: swap entry keeps a place for page in tree */
00501b531   Johannes Weiner   mm: memcontrol: r...
691
  	error = -EAGAIN;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
692

cb5f7b9a4   Hugh Dickins   tmpfs: make shmem...
693
  	mutex_lock(&shmem_swaplist_mutex);
41ffe5d5c   Hugh Dickins   tmpfs: miscellane...
694
695
  	list_for_each_safe(this, next, &shmem_swaplist) {
  		info = list_entry(this, struct shmem_inode_info, swaplist);
285b2c4fd   Hugh Dickins   tmpfs: demolish o...
696
  		if (info->swapped)
00501b531   Johannes Weiner   mm: memcontrol: r...
697
  			error = shmem_unuse_inode(info, swap, &page);
6922c0c7a   Hugh Dickins   tmpfs: convert sh...
698
699
  		else
  			list_del_init(&info->swaplist);
cb5f7b9a4   Hugh Dickins   tmpfs: make shmem...
700
  		cond_resched();
00501b531   Johannes Weiner   mm: memcontrol: r...
701
  		if (error != -EAGAIN)
778dd893a   Hugh Dickins   tmpfs: fix race b...
702
  			break;
00501b531   Johannes Weiner   mm: memcontrol: r...
703
  		/* found nothing in this: move on to search the next */
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
704
  	}
cb5f7b9a4   Hugh Dickins   tmpfs: make shmem...
705
  	mutex_unlock(&shmem_swaplist_mutex);
778dd893a   Hugh Dickins   tmpfs: fix race b...
706

00501b531   Johannes Weiner   mm: memcontrol: r...
707
708
709
710
711
712
  	if (error) {
  		if (error != -ENOMEM)
  			error = 0;
  		mem_cgroup_cancel_charge(page, memcg);
  	} else
  		mem_cgroup_commit_charge(page, memcg, true);
778dd893a   Hugh Dickins   tmpfs: fix race b...
713
  out:
aaa468653   Hugh Dickins   swap_info: note S...
714
715
  	unlock_page(page);
  	page_cache_release(page);
778dd893a   Hugh Dickins   tmpfs: fix race b...
716
  	return error;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
717
718
719
720
721
722
723
724
  }
  
  /*
   * 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
725
  	struct address_space *mapping;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
726
  	struct inode *inode;
6922c0c7a   Hugh Dickins   tmpfs: convert sh...
727
728
  	swp_entry_t swap;
  	pgoff_t index;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
729
730
  
  	BUG_ON(!PageLocked(page));
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
731
732
733
734
735
736
  	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...
737
  	if (!total_swap_pages)
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
738
  		goto redirty;
d9fe526a8   Hugh Dickins   tmpfs: allow file...
739
740
741
  	/*
  	 * 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...
742
  	 * might use ->writepage of its underlying filesystem, in which case
d9fe526a8   Hugh Dickins   tmpfs: allow file...
743
  	 * tmpfs should write out to swap only in response to memory pressure,
48f170fb7   Hugh Dickins   tmpfs: simplify u...
744
  	 * and not for the writeback threads or sync.
d9fe526a8   Hugh Dickins   tmpfs: allow file...
745
  	 */
48f170fb7   Hugh Dickins   tmpfs: simplify u...
746
747
748
749
  	if (!wbc->for_reclaim) {
  		WARN_ON_ONCE(1);	/* Still happens? Tell us about it! */
  		goto redirty;
  	}
1635f6a74   Hugh Dickins   tmpfs: undo fallo...
750
751
752
753
754
  
  	/*
  	 * 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 ...
755
756
757
758
759
760
  	 *
  	 * 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...
761
762
  	 */
  	if (!PageUptodate(page)) {
1aac14003   Hugh Dickins   tmpfs: quit when ...
763
764
765
766
767
  		if (inode->i_private) {
  			struct shmem_falloc *shmem_falloc;
  			spin_lock(&inode->i_lock);
  			shmem_falloc = inode->i_private;
  			if (shmem_falloc &&
8e205f779   Hugh Dickins   shmem: fix faulti...
768
  			    !shmem_falloc->waitq &&
1aac14003   Hugh Dickins   tmpfs: quit when ...
769
770
771
772
773
774
775
776
777
  			    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...
778
779
780
781
  		clear_highpage(page);
  		flush_dcache_page(page);
  		SetPageUptodate(page);
  	}
48f170fb7   Hugh Dickins   tmpfs: simplify u...
782
783
784
  	swap = get_swap_page();
  	if (!swap.val)
  		goto redirty;
d9fe526a8   Hugh Dickins   tmpfs: allow file...
785

b1dea800a   Hugh Dickins   tmpfs: fix race b...
786
787
  	/*
  	 * Add inode to shmem_unuse()'s list of swapped-out inodes,
6922c0c7a   Hugh Dickins   tmpfs: convert sh...
788
789
  	 * 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...
790
  	 * the inode from eviction.  But don't unlock the mutex until
6922c0c7a   Hugh Dickins   tmpfs: convert sh...
791
792
  	 * 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...
793
  	 */
48f170fb7   Hugh Dickins   tmpfs: simplify u...
794
795
796
  	mutex_lock(&shmem_swaplist_mutex);
  	if (list_empty(&info->swaplist))
  		list_add_tail(&info->swaplist, &shmem_swaplist);
b1dea800a   Hugh Dickins   tmpfs: fix race b...
797

48f170fb7   Hugh Dickins   tmpfs: simplify u...
798
  	if (add_to_swap_cache(page, swap, GFP_ATOMIC) == 0) {
aaa468653   Hugh Dickins   swap_info: note S...
799
  		swap_shmem_alloc(swap);
6922c0c7a   Hugh Dickins   tmpfs: convert sh...
800
801
802
803
804
  		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...
805
  		spin_unlock(&info->lock);
6922c0c7a   Hugh Dickins   tmpfs: convert sh...
806
807
  
  		mutex_unlock(&shmem_swaplist_mutex);
d9fe526a8   Hugh Dickins   tmpfs: allow file...
808
  		BUG_ON(page_mapped(page));
9fab5619b   Hugh Dickins   shmem: writepage ...
809
  		swap_writepage(page, wbc);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
810
811
  		return 0;
  	}
6922c0c7a   Hugh Dickins   tmpfs: convert sh...
812
  	mutex_unlock(&shmem_swaplist_mutex);
0a31bc97c   Johannes Weiner   mm: memcontrol: r...
813
  	swapcache_free(swap);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
814
815
  redirty:
  	set_page_dirty(page);
d9fe526a8   Hugh Dickins   tmpfs: allow file...
816
817
818
819
  	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
820
821
822
  }
  
  #ifdef CONFIG_NUMA
680d794ba   akpm@linux-foundation.org   mount options: fi...
823
  #ifdef CONFIG_TMPFS
71fe804b6   Lee Schermerhorn   mempolicy: use st...
824
  static void shmem_show_mpol(struct seq_file *seq, struct mempolicy *mpol)
680d794ba   akpm@linux-foundation.org   mount options: fi...
825
  {
095f1fc4e   Lee Schermerhorn   mempolicy: rework...
826
  	char buffer[64];
680d794ba   akpm@linux-foundation.org   mount options: fi...
827

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

a7a88b237   Hugh Dickins   mempolicy: remove...
831
  	mpol_to_str(buffer, sizeof(buffer), mpol);
095f1fc4e   Lee Schermerhorn   mempolicy: rework...
832
833
  
  	seq_printf(seq, ",mpol=%s", buffer);
680d794ba   akpm@linux-foundation.org   mount options: fi...
834
  }
71fe804b6   Lee Schermerhorn   mempolicy: use st...
835
836
837
838
839
840
841
842
843
844
845
846
  
  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...
847
  #endif /* CONFIG_TMPFS */
41ffe5d5c   Hugh Dickins   tmpfs: miscellane...
848
849
  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
850
  {
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
851
  	struct vm_area_struct pvma;
18a2f371f   Mel Gorman   tmpfs: fix shared...
852
  	struct page *page;
52cd3b074   Lee Schermerhorn   mempolicy: rework...
853

1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
854
  	/* Create a pseudo vma that just contains the policy */
c4cc6d07b   Hugh Dickins   swapin_readahead:...
855
  	pvma.vm_start = 0;
09c231cb8   Nathan Zimmer   tmpfs: distribute...
856
857
  	/* Bias interleave by inode number to distribute better across nodes */
  	pvma.vm_pgoff = index + info->vfs_inode.i_ino;
c4cc6d07b   Hugh Dickins   swapin_readahead:...
858
  	pvma.vm_ops = NULL;
18a2f371f   Mel Gorman   tmpfs: fix shared...
859
860
861
862
863
864
865
866
  	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
867
  }
02098feaa   Hugh Dickins   swapin needs gfp_...
868
  static struct page *shmem_alloc_page(gfp_t gfp,
41ffe5d5c   Hugh Dickins   tmpfs: miscellane...
869
  			struct shmem_inode_info *info, pgoff_t index)
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
870
871
  {
  	struct vm_area_struct pvma;
18a2f371f   Mel Gorman   tmpfs: fix shared...
872
  	struct page *page;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
873

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

18a2f371f   Mel Gorman   tmpfs: fix shared...
881
882
883
884
885
886
  	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
887
  }
680d794ba   akpm@linux-foundation.org   mount options: fi...
888
889
  #else /* !CONFIG_NUMA */
  #ifdef CONFIG_TMPFS
41ffe5d5c   Hugh Dickins   tmpfs: miscellane...
890
  static inline void shmem_show_mpol(struct seq_file *seq, struct mempolicy *mpol)
680d794ba   akpm@linux-foundation.org   mount options: fi...
891
892
893
  {
  }
  #endif /* CONFIG_TMPFS */
41ffe5d5c   Hugh Dickins   tmpfs: miscellane...
894
895
  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
896
  {
41ffe5d5c   Hugh Dickins   tmpfs: miscellane...
897
  	return swapin_readahead(swap, gfp, NULL, 0);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
898
  }
02098feaa   Hugh Dickins   swapin needs gfp_...
899
  static inline struct page *shmem_alloc_page(gfp_t gfp,
41ffe5d5c   Hugh Dickins   tmpfs: miscellane...
900
  			struct shmem_inode_info *info, pgoff_t index)
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
901
  {
e84e2e132   Hugh Dickins   tmpfs: restore mi...
902
  	return alloc_page(gfp);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
903
  }
680d794ba   akpm@linux-foundation.org   mount options: fi...
904
  #endif /* CONFIG_NUMA */
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
905

71fe804b6   Lee Schermerhorn   mempolicy: use st...
906
907
908
909
910
911
  #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
912
  /*
bde05d1cc   Hugh Dickins   shmem: replace pa...
913
914
915
916
917
918
919
920
921
922
923
924
925
926
927
928
929
930
931
932
933
934
935
936
937
938
939
940
941
942
943
944
945
946
947
948
   * 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...
949

bde05d1cc   Hugh Dickins   shmem: replace pa...
950
951
  	page_cache_get(newpage);
  	copy_highpage(newpage, oldpage);
0142ef6cd   Hugh Dickins   shmem: replace_pa...
952
  	flush_dcache_page(newpage);
bde05d1cc   Hugh Dickins   shmem: replace pa...
953

bde05d1cc   Hugh Dickins   shmem: replace pa...
954
  	__set_page_locked(newpage);
bde05d1cc   Hugh Dickins   shmem: replace pa...
955
  	SetPageUptodate(newpage);
bde05d1cc   Hugh Dickins   shmem: replace pa...
956
  	SetPageSwapBacked(newpage);
bde05d1cc   Hugh Dickins   shmem: replace pa...
957
  	set_page_private(newpage, swap_index);
bde05d1cc   Hugh Dickins   shmem: replace pa...
958
959
960
961
962
963
964
965
966
  	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...
967
968
969
970
  	if (!error) {
  		__inc_zone_page_state(newpage, NR_FILE_PAGES);
  		__dec_zone_page_state(oldpage, NR_FILE_PAGES);
  	}
bde05d1cc   Hugh Dickins   shmem: replace pa...
971
  	spin_unlock_irq(&swap_mapping->tree_lock);
bde05d1cc   Hugh Dickins   shmem: replace pa...
972

0142ef6cd   Hugh Dickins   shmem: replace_pa...
973
974
975
976
977
978
979
980
  	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 {
0a31bc97c   Johannes Weiner   mm: memcontrol: r...
981
  		mem_cgroup_migrate(oldpage, newpage, false);
0142ef6cd   Hugh Dickins   shmem: replace_pa...
982
983
984
  		lru_cache_add_anon(newpage);
  		*pagep = newpage;
  	}
bde05d1cc   Hugh Dickins   shmem: replace pa...
985
986
987
988
989
990
991
  
  	ClearPageSwapCache(oldpage);
  	set_page_private(oldpage, 0);
  
  	unlock_page(oldpage);
  	page_cache_release(oldpage);
  	page_cache_release(oldpage);
0142ef6cd   Hugh Dickins   shmem: replace_pa...
992
  	return error;
bde05d1cc   Hugh Dickins   shmem: replace pa...
993
994
995
  }
  
  /*
68da9f055   Hugh Dickins   tmpfs: pass gfp t...
996
   * shmem_getpage_gfp - find page in cache, or get from swap, or allocate
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
997
998
999
1000
1001
   *
   * 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...
1002
  static int shmem_getpage_gfp(struct inode *inode, pgoff_t index,
68da9f055   Hugh Dickins   tmpfs: pass gfp t...
1003
  	struct page **pagep, enum sgp_type sgp, gfp_t gfp, int *fault_type)
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
1004
1005
  {
  	struct address_space *mapping = inode->i_mapping;
54af60421   Hugh Dickins   tmpfs: convert sh...
1006
  	struct shmem_inode_info *info;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
1007
  	struct shmem_sb_info *sbinfo;
00501b531   Johannes Weiner   mm: memcontrol: r...
1008
  	struct mem_cgroup *memcg;
27ab70062   Hugh Dickins   tmpfs: simplify f...
1009
  	struct page *page;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
1010
1011
  	swp_entry_t swap;
  	int error;
54af60421   Hugh Dickins   tmpfs: convert sh...
1012
  	int once = 0;
1635f6a74   Hugh Dickins   tmpfs: undo fallo...
1013
  	int alloced = 0;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
1014

41ffe5d5c   Hugh Dickins   tmpfs: miscellane...
1015
  	if (index > (MAX_LFS_FILESIZE >> PAGE_CACHE_SHIFT))
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
1016
  		return -EFBIG;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
1017
  repeat:
54af60421   Hugh Dickins   tmpfs: convert sh...
1018
  	swap.val = 0;
0cd6144aa   Johannes Weiner   mm + fs: prepare ...
1019
  	page = find_lock_entry(mapping, index);
54af60421   Hugh Dickins   tmpfs: convert sh...
1020
1021
1022
1023
  	if (radix_tree_exceptional_entry(page)) {
  		swap = radix_to_swp_entry(page);
  		page = NULL;
  	}
1635f6a74   Hugh Dickins   tmpfs: undo fallo...
1024
  	if (sgp != SGP_WRITE && sgp != SGP_FALLOC &&
54af60421   Hugh Dickins   tmpfs: convert sh...
1025
1026
1027
1028
  	    ((loff_t)index << PAGE_CACHE_SHIFT) >= i_size_read(inode)) {
  		error = -EINVAL;
  		goto failed;
  	}
66d2f4d28   Hugh Dickins   shmem: fix init_p...
1029
1030
  	if (page && sgp == SGP_WRITE)
  		mark_page_accessed(page);
1635f6a74   Hugh Dickins   tmpfs: undo fallo...
1031
1032
1033
1034
1035
1036
1037
1038
  	/* 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...
1039
  	if (page || (sgp == SGP_READ && !swap.val)) {
54af60421   Hugh Dickins   tmpfs: convert sh...
1040
1041
  		*pagep = page;
  		return 0;
27ab70062   Hugh Dickins   tmpfs: simplify f...
1042
1043
1044
  	}
  
  	/*
54af60421   Hugh Dickins   tmpfs: convert sh...
1045
1046
  	 * Fast cache lookup did not find it:
  	 * bring it back from swap or allocate.
27ab70062   Hugh Dickins   tmpfs: simplify f...
1047
  	 */
54af60421   Hugh Dickins   tmpfs: convert sh...
1048
1049
  	info = SHMEM_I(inode);
  	sbinfo = SHMEM_SB(inode->i_sb);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
1050

1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
1051
1052
  	if (swap.val) {
  		/* Look it up and read it in.. */
27ab70062   Hugh Dickins   tmpfs: simplify f...
1053
1054
  		page = lookup_swap_cache(swap);
  		if (!page) {
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
1055
  			/* here we actually do the io */
68da9f055   Hugh Dickins   tmpfs: pass gfp t...
1056
1057
  			if (fault_type)
  				*fault_type |= VM_FAULT_MAJOR;
41ffe5d5c   Hugh Dickins   tmpfs: miscellane...
1058
  			page = shmem_swapin(swap, gfp, info, index);
27ab70062   Hugh Dickins   tmpfs: simplify f...
1059
  			if (!page) {
54af60421   Hugh Dickins   tmpfs: convert sh...
1060
1061
  				error = -ENOMEM;
  				goto failed;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
1062
  			}
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
1063
1064
1065
  		}
  
  		/* We have to do this with page locked to prevent races */
54af60421   Hugh Dickins   tmpfs: convert sh...
1066
  		lock_page(page);
0142ef6cd   Hugh Dickins   shmem: replace_pa...
1067
  		if (!PageSwapCache(page) || page_private(page) != swap.val ||
d18992286   Hugh Dickins   shmem: fix negati...
1068
  		    !shmem_confirm_swap(mapping, index, swap)) {
bde05d1cc   Hugh Dickins   shmem: replace pa...
1069
  			error = -EEXIST;	/* try again */
d18992286   Hugh Dickins   shmem: fix negati...
1070
  			goto unlock;
bde05d1cc   Hugh Dickins   shmem: replace pa...
1071
  		}
27ab70062   Hugh Dickins   tmpfs: simplify f...
1072
  		if (!PageUptodate(page)) {
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
1073
  			error = -EIO;
54af60421   Hugh Dickins   tmpfs: convert sh...
1074
  			goto failed;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
1075
  		}
54af60421   Hugh Dickins   tmpfs: convert sh...
1076
  		wait_on_page_writeback(page);
bde05d1cc   Hugh Dickins   shmem: replace pa...
1077
1078
1079
1080
  		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
1081
  		}
27ab70062   Hugh Dickins   tmpfs: simplify f...
1082

00501b531   Johannes Weiner   mm: memcontrol: r...
1083
  		error = mem_cgroup_try_charge(page, current->mm, gfp, &memcg);
d18992286   Hugh Dickins   shmem: fix negati...
1084
  		if (!error) {
aa3b18955   Hugh Dickins   tmpfs: convert me...
1085
  			error = shmem_add_to_page_cache(page, mapping, index,
fed400a18   Wang Sheng-Hui   mm/shmem.c: remov...
1086
  						swp_to_radix_entry(swap));
215c02bc3   Hugh Dickins   tmpfs: fix shmem_...
1087
1088
1089
1090
1091
1092
1093
1094
1095
1096
1097
1098
  			/*
  			 * 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.
  			 */
00501b531   Johannes Weiner   mm: memcontrol: r...
1099
1100
  			if (error) {
  				mem_cgroup_cancel_charge(page, memcg);
215c02bc3   Hugh Dickins   tmpfs: fix shmem_...
1101
  				delete_from_swap_cache(page);
00501b531   Johannes Weiner   mm: memcontrol: r...
1102
  			}
d18992286   Hugh Dickins   shmem: fix negati...
1103
  		}
54af60421   Hugh Dickins   tmpfs: convert sh...
1104
1105
  		if (error)
  			goto failed;
00501b531   Johannes Weiner   mm: memcontrol: r...
1106
  		mem_cgroup_commit_charge(page, memcg, true);
54af60421   Hugh Dickins   tmpfs: convert sh...
1107
  		spin_lock(&info->lock);
285b2c4fd   Hugh Dickins   tmpfs: demolish o...
1108
  		info->swapped--;
54af60421   Hugh Dickins   tmpfs: convert sh...
1109
  		shmem_recalc_inode(inode);
27ab70062   Hugh Dickins   tmpfs: simplify f...
1110
  		spin_unlock(&info->lock);
54af60421   Hugh Dickins   tmpfs: convert sh...
1111

66d2f4d28   Hugh Dickins   shmem: fix init_p...
1112
1113
  		if (sgp == SGP_WRITE)
  			mark_page_accessed(page);
54af60421   Hugh Dickins   tmpfs: convert sh...
1114
  		delete_from_swap_cache(page);
27ab70062   Hugh Dickins   tmpfs: simplify f...
1115
1116
  		set_page_dirty(page);
  		swap_free(swap);
54af60421   Hugh Dickins   tmpfs: convert sh...
1117
1118
1119
1120
  	} else {
  		if (shmem_acct_block(info->flags)) {
  			error = -ENOSPC;
  			goto failed;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
1121
  		}
0edd73b33   Hugh Dickins   [PATCH] shmem: re...
1122
  		if (sbinfo->max_blocks) {
fc5da22ae   Hugh Dickins   tmpfs: fix off-by...
1123
  			if (percpu_counter_compare(&sbinfo->used_blocks,
54af60421   Hugh Dickins   tmpfs: convert sh...
1124
1125
1126
1127
  						sbinfo->max_blocks) >= 0) {
  				error = -ENOSPC;
  				goto unacct;
  			}
7e496299d   Tim Chen   tmpfs: make tmpfs...
1128
  			percpu_counter_inc(&sbinfo->used_blocks);
54af60421   Hugh Dickins   tmpfs: convert sh...
1129
  		}
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
1130

54af60421   Hugh Dickins   tmpfs: convert sh...
1131
1132
1133
1134
  		page = shmem_alloc_page(gfp, info, index);
  		if (!page) {
  			error = -ENOMEM;
  			goto decused;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
1135
  		}
07a427884   Mel Gorman   mm: shmem: avoid ...
1136
  		__SetPageSwapBacked(page);
54af60421   Hugh Dickins   tmpfs: convert sh...
1137
  		__set_page_locked(page);
66d2f4d28   Hugh Dickins   shmem: fix init_p...
1138
  		if (sgp == SGP_WRITE)
eb39d618f   Hugh Dickins   mm: replace init_...
1139
  			__SetPageReferenced(page);
66d2f4d28   Hugh Dickins   shmem: fix init_p...
1140

00501b531   Johannes Weiner   mm: memcontrol: r...
1141
  		error = mem_cgroup_try_charge(page, current->mm, gfp, &memcg);
54af60421   Hugh Dickins   tmpfs: convert sh...
1142
1143
  		if (error)
  			goto decused;
5e4c0d974   Jan Kara   lib/radix-tree.c:...
1144
  		error = radix_tree_maybe_preload(gfp & GFP_RECLAIM_MASK);
b065b4321   Hugh Dickins   shmem: cleanup sh...
1145
1146
  		if (!error) {
  			error = shmem_add_to_page_cache(page, mapping, index,
fed400a18   Wang Sheng-Hui   mm/shmem.c: remov...
1147
  							NULL);
b065b4321   Hugh Dickins   shmem: cleanup sh...
1148
1149
1150
  			radix_tree_preload_end();
  		}
  		if (error) {
00501b531   Johannes Weiner   mm: memcontrol: r...
1151
  			mem_cgroup_cancel_charge(page, memcg);
b065b4321   Hugh Dickins   shmem: cleanup sh...
1152
1153
  			goto decused;
  		}
00501b531   Johannes Weiner   mm: memcontrol: r...
1154
  		mem_cgroup_commit_charge(page, memcg, false);
54af60421   Hugh Dickins   tmpfs: convert sh...
1155
1156
1157
  		lru_cache_add_anon(page);
  
  		spin_lock(&info->lock);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
1158
  		info->alloced++;
54af60421   Hugh Dickins   tmpfs: convert sh...
1159
1160
  		inode->i_blocks += BLOCKS_PER_PAGE;
  		shmem_recalc_inode(inode);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
1161
  		spin_unlock(&info->lock);
1635f6a74   Hugh Dickins   tmpfs: undo fallo...
1162
  		alloced = true;
54af60421   Hugh Dickins   tmpfs: convert sh...
1163

ec9516fbc   Hugh Dickins   tmpfs: optimize c...
1164
  		/*
1635f6a74   Hugh Dickins   tmpfs: undo fallo...
1165
1166
1167
1168
1169
1170
1171
1172
1173
  		 * 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...
1174
1175
1176
1177
1178
1179
  		 */
  		if (sgp != SGP_WRITE) {
  			clear_highpage(page);
  			flush_dcache_page(page);
  			SetPageUptodate(page);
  		}
a0ee5ec52   Hugh Dickins   tmpfs: allocate o...
1180
  		if (sgp == SGP_DIRTY)
27ab70062   Hugh Dickins   tmpfs: simplify f...
1181
  			set_page_dirty(page);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
1182
  	}
bde05d1cc   Hugh Dickins   shmem: replace pa...
1183

54af60421   Hugh Dickins   tmpfs: convert sh...
1184
  	/* Perhaps the file has been truncated since we checked */
1635f6a74   Hugh Dickins   tmpfs: undo fallo...
1185
  	if (sgp != SGP_WRITE && sgp != SGP_FALLOC &&
54af60421   Hugh Dickins   tmpfs: convert sh...
1186
1187
  	    ((loff_t)index << PAGE_CACHE_SHIFT) >= i_size_read(inode)) {
  		error = -EINVAL;
1635f6a74   Hugh Dickins   tmpfs: undo fallo...
1188
1189
1190
1191
  		if (alloced)
  			goto trunc;
  		else
  			goto failed;
e83c32e8f   Hugh Dickins   tmpfs: simplify p...
1192
  	}
54af60421   Hugh Dickins   tmpfs: convert sh...
1193
1194
  	*pagep = page;
  	return 0;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
1195

59a16ead5   Hugh Dickins   tmpfs: fix spurio...
1196
  	/*
54af60421   Hugh Dickins   tmpfs: convert sh...
1197
  	 * Error recovery.
59a16ead5   Hugh Dickins   tmpfs: fix spurio...
1198
  	 */
54af60421   Hugh Dickins   tmpfs: convert sh...
1199
  trunc:
1635f6a74   Hugh Dickins   tmpfs: undo fallo...
1200
  	info = SHMEM_I(inode);
54af60421   Hugh Dickins   tmpfs: convert sh...
1201
1202
1203
1204
1205
  	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...
1206
  	spin_unlock(&info->lock);
54af60421   Hugh Dickins   tmpfs: convert sh...
1207
  decused:
1635f6a74   Hugh Dickins   tmpfs: undo fallo...
1208
  	sbinfo = SHMEM_SB(inode->i_sb);
54af60421   Hugh Dickins   tmpfs: convert sh...
1209
1210
1211
1212
1213
  	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...
1214
1215
1216
1217
  	if (swap.val && error != -EINVAL &&
  	    !shmem_confirm_swap(mapping, index, swap))
  		error = -EEXIST;
  unlock:
27ab70062   Hugh Dickins   tmpfs: simplify f...
1218
  	if (page) {
54af60421   Hugh Dickins   tmpfs: convert sh...
1219
  		unlock_page(page);
27ab70062   Hugh Dickins   tmpfs: simplify f...
1220
  		page_cache_release(page);
54af60421   Hugh Dickins   tmpfs: convert sh...
1221
1222
1223
1224
1225
1226
  	}
  	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...
1227
  		goto repeat;
ff36b8016   Shaohua Li   shmem: reduce pag...
1228
  	}
d18992286   Hugh Dickins   shmem: fix negati...
1229
  	if (error == -EEXIST)	/* from above or from radix_tree_insert */
54af60421   Hugh Dickins   tmpfs: convert sh...
1230
1231
  		goto repeat;
  	return error;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
1232
  }
d0217ac04   Nick Piggin   mm: fault feedbac...
1233
  static int shmem_fault(struct vm_area_struct *vma, struct vm_fault *vmf)
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
1234
  {
496ad9aa8   Al Viro   new helper: file_...
1235
  	struct inode *inode = file_inode(vma->vm_file);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
1236
  	int error;
68da9f055   Hugh Dickins   tmpfs: pass gfp t...
1237
  	int ret = VM_FAULT_LOCKED;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
1238

f00cdc6df   Hugh Dickins   shmem: fix faulti...
1239
1240
1241
1242
  	/*
  	 * Trinity finds that probing a hole which tmpfs is punching can
  	 * prevent the hole-punch from ever completing: which in turn
  	 * locks writers out with its hold on i_mutex.  So refrain from
8e205f779   Hugh Dickins   shmem: fix faulti...
1243
1244
1245
1246
1247
1248
1249
1250
1251
1252
1253
1254
  	 * faulting pages into the hole while it's being punched.  Although
  	 * shmem_undo_range() does remove the additions, it may be unable to
  	 * keep up, as each new page needs its own unmap_mapping_range() call,
  	 * and the i_mmap tree grows ever slower to scan if new vmas are added.
  	 *
  	 * It does not matter if we sometimes reach this check just before the
  	 * hole-punch begins, so that one fault then races with the punch:
  	 * we just need to make racing faults a rare case.
  	 *
  	 * The implementation below would be much simpler if we just used a
  	 * standard mutex or completion: but we cannot take i_mutex in fault,
  	 * and bloating every shmem inode for this unlikely case would be sad.
f00cdc6df   Hugh Dickins   shmem: fix faulti...
1255
1256
1257
1258
1259
1260
  	 */
  	if (unlikely(inode->i_private)) {
  		struct shmem_falloc *shmem_falloc;
  
  		spin_lock(&inode->i_lock);
  		shmem_falloc = inode->i_private;
8e205f779   Hugh Dickins   shmem: fix faulti...
1261
1262
1263
1264
1265
1266
1267
1268
  		if (shmem_falloc &&
  		    shmem_falloc->waitq &&
  		    vmf->pgoff >= shmem_falloc->start &&
  		    vmf->pgoff < shmem_falloc->next) {
  			wait_queue_head_t *shmem_falloc_waitq;
  			DEFINE_WAIT(shmem_fault_wait);
  
  			ret = VM_FAULT_NOPAGE;
f00cdc6df   Hugh Dickins   shmem: fix faulti...
1269
1270
  			if ((vmf->flags & FAULT_FLAG_ALLOW_RETRY) &&
  			   !(vmf->flags & FAULT_FLAG_RETRY_NOWAIT)) {
8e205f779   Hugh Dickins   shmem: fix faulti...
1271
  				/* It's polite to up mmap_sem if we can */
f00cdc6df   Hugh Dickins   shmem: fix faulti...
1272
  				up_read(&vma->vm_mm->mmap_sem);
8e205f779   Hugh Dickins   shmem: fix faulti...
1273
  				ret = VM_FAULT_RETRY;
f00cdc6df   Hugh Dickins   shmem: fix faulti...
1274
  			}
8e205f779   Hugh Dickins   shmem: fix faulti...
1275
1276
1277
1278
1279
1280
1281
1282
1283
1284
1285
1286
1287
1288
1289
1290
1291
1292
  
  			shmem_falloc_waitq = shmem_falloc->waitq;
  			prepare_to_wait(shmem_falloc_waitq, &shmem_fault_wait,
  					TASK_UNINTERRUPTIBLE);
  			spin_unlock(&inode->i_lock);
  			schedule();
  
  			/*
  			 * shmem_falloc_waitq points into the shmem_fallocate()
  			 * stack of the hole-punching task: shmem_falloc_waitq
  			 * is usually invalid by the time we reach here, but
  			 * finish_wait() does not dereference it in that case;
  			 * though i_lock needed lest racing with wake_up_all().
  			 */
  			spin_lock(&inode->i_lock);
  			finish_wait(shmem_falloc_waitq, &shmem_fault_wait);
  			spin_unlock(&inode->i_lock);
  			return ret;
f00cdc6df   Hugh Dickins   shmem: fix faulti...
1293
  		}
8e205f779   Hugh Dickins   shmem: fix faulti...
1294
  		spin_unlock(&inode->i_lock);
f00cdc6df   Hugh Dickins   shmem: fix faulti...
1295
  	}
27d54b398   Hugh Dickins   shmem: SGP_QUICK ...
1296
  	error = shmem_getpage(inode, vmf->pgoff, &vmf->page, SGP_CACHE, &ret);
d0217ac04   Nick Piggin   mm: fault feedbac...
1297
1298
  	if (error)
  		return ((error == -ENOMEM) ? VM_FAULT_OOM : VM_FAULT_SIGBUS);
68da9f055   Hugh Dickins   tmpfs: pass gfp t...
1299

456f998ec   Ying Han   memcg: add the pa...
1300
1301
1302
1303
  	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...
1304
  	return ret;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
1305
  }
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
1306
  #ifdef CONFIG_NUMA
41ffe5d5c   Hugh Dickins   tmpfs: miscellane...
1307
  static int shmem_set_policy(struct vm_area_struct *vma, struct mempolicy *mpol)
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
1308
  {
496ad9aa8   Al Viro   new helper: file_...
1309
  	struct inode *inode = file_inode(vma->vm_file);
41ffe5d5c   Hugh Dickins   tmpfs: miscellane...
1310
  	return mpol_set_shared_policy(&SHMEM_I(inode)->policy, vma, mpol);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
1311
  }
d8dc74f21   Adrian Bunk   mm/shmem.c: make ...
1312
1313
  static struct mempolicy *shmem_get_policy(struct vm_area_struct *vma,
  					  unsigned long addr)
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
1314
  {
496ad9aa8   Al Viro   new helper: file_...
1315
  	struct inode *inode = file_inode(vma->vm_file);
41ffe5d5c   Hugh Dickins   tmpfs: miscellane...
1316
  	pgoff_t index;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
1317

41ffe5d5c   Hugh Dickins   tmpfs: miscellane...
1318
1319
  	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
1320
1321
1322
1323
1324
  }
  #endif
  
  int shmem_lock(struct file *file, int lock, struct user_struct *user)
  {
496ad9aa8   Al Viro   new helper: file_...
1325
  	struct inode *inode = file_inode(file);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
1326
1327
1328
1329
1330
1331
1332
1333
  	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 ...
1334
  		mapping_set_unevictable(file->f_mapping);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
1335
1336
1337
1338
  	}
  	if (!lock && (info->flags & VM_LOCKED) && user) {
  		user_shm_unlock(inode->i_size, user);
  		info->flags &= ~VM_LOCKED;
89e004ea5   Lee Schermerhorn   SHM_LOCKED pages ...
1339
  		mapping_clear_unevictable(file->f_mapping);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
1340
1341
  	}
  	retval = 0;
89e004ea5   Lee Schermerhorn   SHM_LOCKED pages ...
1342

1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
1343
1344
1345
1346
  out_nomem:
  	spin_unlock(&info->lock);
  	return retval;
  }
9b83a6a85   Adrian Bunk   [PATCH] mm/{,tiny...
1347
  static int shmem_mmap(struct file *file, struct vm_area_struct *vma)
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
1348
1349
1350
1351
1352
  {
  	file_accessed(file);
  	vma->vm_ops = &shmem_vm_ops;
  	return 0;
  }
454abafe9   Dmitry Monakhov   ramfs: replace in...
1353
  static struct inode *shmem_get_inode(struct super_block *sb, const struct inode *dir,
09208d150   Al Viro   shmem, ramfs: pro...
1354
  				     umode_t mode, dev_t dev, unsigned long flags)
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
1355
1356
1357
1358
  {
  	struct inode *inode;
  	struct shmem_inode_info *info;
  	struct shmem_sb_info *sbinfo = SHMEM_SB(sb);
5b04c6890   Pavel Emelyanov   shmem: factor out...
1359
1360
  	if (shmem_reserve_inode(sb))
  		return NULL;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
1361
1362
1363
  
  	inode = new_inode(sb);
  	if (inode) {
85fe4025c   Christoph Hellwig   fs: do not assign...
1364
  		inode->i_ino = get_next_ino();
454abafe9   Dmitry Monakhov   ramfs: replace in...
1365
  		inode_init_owner(inode, dir, mode);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
1366
  		inode->i_blocks = 0;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
1367
1368
  		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...
1369
  		inode->i_generation = get_seconds();
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
1370
1371
1372
  		info = SHMEM_I(inode);
  		memset(info, 0, (char *)inode - (char *)info);
  		spin_lock_init(&info->lock);
40e041a2c   David Herrmann   shm: add sealing API
1373
  		info->seals = F_SEAL_SEAL;
0b0a0806b   Hugh Dickins   shmem: fix shared...
1374
  		info->flags = flags & VM_NORESERVE;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
1375
  		INIT_LIST_HEAD(&info->swaplist);
38f386574   Aristeu Rozanski   xattr: extract si...
1376
  		simple_xattrs_init(&info->xattrs);
72c04902d   Al Viro   Get "no acls for ...
1377
  		cache_no_acl(inode);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
1378
1379
1380
  
  		switch (mode & S_IFMT) {
  		default:
39f0247d3   Andreas Gruenbacher   [PATCH] Access Co...
1381
  			inode->i_op = &shmem_special_inode_operations;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
1382
1383
1384
  			init_special_inode(inode, mode, dev);
  			break;
  		case S_IFREG:
14fcc23fd   Hugh Dickins   tmpfs: fix kernel...
1385
  			inode->i_mapping->a_ops = &shmem_aops;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
1386
1387
  			inode->i_op = &shmem_inode_operations;
  			inode->i_fop = &shmem_file_operations;
71fe804b6   Lee Schermerhorn   mempolicy: use st...
1388
1389
  			mpol_shared_policy_init(&info->policy,
  						 shmem_get_sbmpol(sbinfo));
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
1390
1391
  			break;
  		case S_IFDIR:
d8c76e6f4   Dave Hansen   [PATCH] r/o bind ...
1392
  			inc_nlink(inode);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
1393
1394
1395
1396
1397
1398
1399
1400
1401
1402
  			/* 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...
1403
  			mpol_shared_policy_init(&info->policy, NULL);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
1404
1405
  			break;
  		}
5b04c6890   Pavel Emelyanov   shmem: factor out...
1406
1407
  	} else
  		shmem_free_inode(sb);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
1408
1409
  	return inode;
  }
0cd6144aa   Johannes Weiner   mm + fs: prepare ...
1410
1411
1412
1413
  bool shmem_mapping(struct address_space *mapping)
  {
  	return mapping->backing_dev_info == &shmem_backing_dev_info;
  }
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
1414
  #ifdef CONFIG_TMPFS
92e1d5be9   Arjan van de Ven   [PATCH] mark stru...
1415
  static const struct inode_operations shmem_symlink_inode_operations;
69f07ec93   Hugh Dickins   tmpfs: use kmemdu...
1416
  static const struct inode_operations shmem_short_symlink_operations;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
1417

6d9d88d07   Jarkko Sakkinen   tmpfs: security x...
1418
1419
1420
1421
1422
  #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
1423
  static int
800d15a53   Nick Piggin   implement simple ...
1424
1425
1426
  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
1427
  {
800d15a53   Nick Piggin   implement simple ...
1428
  	struct inode *inode = mapping->host;
40e041a2c   David Herrmann   shm: add sealing API
1429
  	struct shmem_inode_info *info = SHMEM_I(inode);
800d15a53   Nick Piggin   implement simple ...
1430
  	pgoff_t index = pos >> PAGE_CACHE_SHIFT;
40e041a2c   David Herrmann   shm: add sealing API
1431
1432
1433
1434
1435
1436
1437
1438
  
  	/* i_mutex is held by caller */
  	if (unlikely(info->seals)) {
  		if (info->seals & F_SEAL_WRITE)
  			return -EPERM;
  		if ((info->seals & F_SEAL_GROW) && pos + len > inode->i_size)
  			return -EPERM;
  	}
66d2f4d28   Hugh Dickins   shmem: fix init_p...
1439
  	return shmem_getpage(inode, index, pagep, SGP_WRITE, NULL);
800d15a53   Nick Piggin   implement simple ...
1440
1441
1442
1443
1444
1445
1446
1447
  }
  
  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...
1448
1449
  	if (pos + copied > inode->i_size)
  		i_size_write(inode, pos + copied);
ec9516fbc   Hugh Dickins   tmpfs: optimize c...
1450
1451
1452
1453
1454
1455
1456
1457
  	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 ...
1458
  	set_page_dirty(page);
6746aff74   Wu Fengguang   HWPOISON: shmem: ...
1459
  	unlock_page(page);
800d15a53   Nick Piggin   implement simple ...
1460
  	page_cache_release(page);
800d15a53   Nick Piggin   implement simple ...
1461
  	return copied;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
1462
  }
2ba5bbed0   Al Viro   shmem: switch to ...
1463
  static ssize_t shmem_file_read_iter(struct kiocb *iocb, struct iov_iter *to)
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
1464
  {
6e58e79db   Al Viro   introduce copy_pa...
1465
1466
  	struct file *file = iocb->ki_filp;
  	struct inode *inode = file_inode(file);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
1467
  	struct address_space *mapping = inode->i_mapping;
41ffe5d5c   Hugh Dickins   tmpfs: miscellane...
1468
1469
  	pgoff_t index;
  	unsigned long offset;
a0ee5ec52   Hugh Dickins   tmpfs: allocate o...
1470
  	enum sgp_type sgp = SGP_READ;
f7c1d0742   Geert Uytterhoeven   mm: Initialize er...
1471
  	int error = 0;
cb66a7a1f   Al Viro   kill generic_segm...
1472
  	ssize_t retval = 0;
6e58e79db   Al Viro   introduce copy_pa...
1473
  	loff_t *ppos = &iocb->ki_pos;
a0ee5ec52   Hugh Dickins   tmpfs: allocate o...
1474
1475
1476
1477
1478
1479
1480
1481
  
  	/*
  	 * 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
1482
1483
1484
1485
1486
1487
  
  	index = *ppos >> PAGE_CACHE_SHIFT;
  	offset = *ppos & ~PAGE_CACHE_MASK;
  
  	for (;;) {
  		struct page *page = NULL;
41ffe5d5c   Hugh Dickins   tmpfs: miscellane...
1488
1489
  		pgoff_t end_index;
  		unsigned long nr, ret;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
1490
1491
1492
1493
1494
1495
1496
1497
1498
1499
  		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...
1500
1501
1502
1503
  		error = shmem_getpage(inode, index, &page, sgp, NULL);
  		if (error) {
  			if (error == -EINVAL)
  				error = 0;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
1504
1505
  			break;
  		}
d3602444e   Hugh Dickins   shmem_getpage ret...
1506
1507
  		if (page)
  			unlock_page(page);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
1508
1509
1510
  
  		/*
  		 * We must evaluate after, since reads (unlike writes)
1b1dcc1b5   Jes Sorensen   [PATCH] mutex sub...
1511
  		 * are called without i_mutex protection against truncate
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
1512
1513
1514
1515
1516
1517
1518
1519
1520
1521
1522
1523
1524
1525
1526
1527
1528
1529
1530
1531
1532
1533
1534
1535
1536
1537
1538
  		 */
  		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...
1539
  		} else {
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
1540
  			page = ZERO_PAGE(0);
b5810039a   Nick Piggin   [PATCH] core remo...
1541
1542
  			page_cache_get(page);
  		}
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
1543
1544
1545
1546
  
  		/*
  		 * 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
1547
  		 */
2ba5bbed0   Al Viro   shmem: switch to ...
1548
  		ret = copy_page_to_iter(page, offset, nr, to);
6e58e79db   Al Viro   introduce copy_pa...
1549
  		retval += ret;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
1550
1551
1552
1553
1554
  		offset += ret;
  		index += offset >> PAGE_CACHE_SHIFT;
  		offset &= ~PAGE_CACHE_MASK;
  
  		page_cache_release(page);
2ba5bbed0   Al Viro   shmem: switch to ...
1555
  		if (!iov_iter_count(to))
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
1556
  			break;
6e58e79db   Al Viro   introduce copy_pa...
1557
1558
1559
1560
  		if (ret < nr) {
  			error = -EFAULT;
  			break;
  		}
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
1561
1562
1563
1564
  		cond_resched();
  	}
  
  	*ppos = ((loff_t) index << PAGE_CACHE_SHIFT) + offset;
6e58e79db   Al Viro   introduce copy_pa...
1565
1566
  	file_accessed(file);
  	return retval ? retval : error;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
1567
  }
708e3508c   Hugh Dickins   tmpfs: clone shme...
1568
1569
1570
1571
1572
  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...
1573
  	struct inode *inode = mapping->host;
708e3508c   Hugh Dickins   tmpfs: clone shme...
1574
1575
1576
1577
1578
1579
1580
1581
1582
1583
  	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 ...
1584
  		.nr_pages_max = PIPE_DEF_BUFFERS,
708e3508c   Hugh Dickins   tmpfs: clone shme...
1585
1586
1587
1588
  		.flags = flags,
  		.ops = &page_cache_pipe_buf_ops,
  		.spd_release = spd_release_page,
  	};
71f0e07a6   Hugh Dickins   tmpfs: refine shm...
1589
  	isize = i_size_read(inode);
708e3508c   Hugh Dickins   tmpfs: clone shme...
1590
1591
1592
1593
1594
1595
1596
1597
1598
1599
1600
1601
1602
  	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 "...
1603
  	nr_pages = min(req_pages, spd.nr_pages_max);
708e3508c   Hugh Dickins   tmpfs: clone shme...
1604

708e3508c   Hugh Dickins   tmpfs: clone shme...
1605
1606
1607
  	spd.nr_pages = find_get_pages_contig(mapping, index,
  						nr_pages, spd.pages);
  	index += spd.nr_pages;
708e3508c   Hugh Dickins   tmpfs: clone shme...
1608
  	error = 0;
708e3508c   Hugh Dickins   tmpfs: clone shme...
1609

71f0e07a6   Hugh Dickins   tmpfs: refine shm...
1610
  	while (spd.nr_pages < nr_pages) {
71f0e07a6   Hugh Dickins   tmpfs: refine shm...
1611
1612
1613
1614
  		error = shmem_getpage(inode, index, &page, SGP_CACHE, NULL);
  		if (error)
  			break;
  		unlock_page(page);
708e3508c   Hugh Dickins   tmpfs: clone shme...
1615
1616
1617
  		spd.pages[spd.nr_pages++] = page;
  		index++;
  	}
708e3508c   Hugh Dickins   tmpfs: clone shme...
1618
1619
1620
  	index = *ppos >> PAGE_CACHE_SHIFT;
  	nr_pages = spd.nr_pages;
  	spd.nr_pages = 0;
71f0e07a6   Hugh Dickins   tmpfs: refine shm...
1621

708e3508c   Hugh Dickins   tmpfs: clone shme...
1622
1623
1624
1625
1626
  	for (page_nr = 0; page_nr < nr_pages; page_nr++) {
  		unsigned int this_len;
  
  		if (!len)
  			break;
708e3508c   Hugh Dickins   tmpfs: clone shme...
1627
1628
  		this_len = min_t(unsigned long, len, PAGE_CACHE_SIZE - loff);
  		page = spd.pages[page_nr];
71f0e07a6   Hugh Dickins   tmpfs: refine shm...
1629
  		if (!PageUptodate(page) || page->mapping != mapping) {
71f0e07a6   Hugh Dickins   tmpfs: refine shm...
1630
1631
1632
  			error = shmem_getpage(inode, index, &page,
  							SGP_CACHE, NULL);
  			if (error)
708e3508c   Hugh Dickins   tmpfs: clone shme...
1633
  				break;
71f0e07a6   Hugh Dickins   tmpfs: refine shm...
1634
1635
1636
  			unlock_page(page);
  			page_cache_release(spd.pages[page_nr]);
  			spd.pages[page_nr] = page;
708e3508c   Hugh Dickins   tmpfs: clone shme...
1637
  		}
71f0e07a6   Hugh Dickins   tmpfs: refine shm...
1638
1639
  
  		isize = i_size_read(inode);
708e3508c   Hugh Dickins   tmpfs: clone shme...
1640
1641
1642
  		end_index = (isize - 1) >> PAGE_CACHE_SHIFT;
  		if (unlikely(!isize || index > end_index))
  			break;
708e3508c   Hugh Dickins   tmpfs: clone shme...
1643
1644
  		if (end_index == index) {
  			unsigned int plen;
708e3508c   Hugh Dickins   tmpfs: clone shme...
1645
1646
1647
  			plen = ((isize - 1) & ~PAGE_CACHE_MASK) + 1;
  			if (plen <= loff)
  				break;
708e3508c   Hugh Dickins   tmpfs: clone shme...
1648
1649
1650
1651
1652
1653
1654
1655
1656
1657
1658
  			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...
1659
1660
  	while (page_nr < nr_pages)
  		page_cache_release(spd.pages[page_nr++]);
708e3508c   Hugh Dickins   tmpfs: clone shme...
1661
1662
1663
  
  	if (spd.nr_pages)
  		error = splice_to_pipe(pipe, &spd);
047fe3605   Eric Dumazet   splice: fix racy ...
1664
  	splice_shrink_spd(&spd);
708e3508c   Hugh Dickins   tmpfs: clone shme...
1665
1666
1667
1668
1669
1670
1671
  
  	if (error > 0) {
  		*ppos += error;
  		file_accessed(in);
  	}
  	return error;
  }
220f2ac91   Hugh Dickins   tmpfs: support SE...
1672
1673
1674
1675
  /*
   * 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...
1676
  				    pgoff_t index, pgoff_t end, int whence)
220f2ac91   Hugh Dickins   tmpfs: support SE...
1677
1678
1679
1680
1681
1682
1683
1684
1685
1686
  {
  	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 ...
1687
  		pvec.nr = find_get_entries(mapping, index,
220f2ac91   Hugh Dickins   tmpfs: support SE...
1688
1689
  					pvec.nr, pvec.pages, indices);
  		if (!pvec.nr) {
965c8e59c   Andrew Morton   lseek: the "whenc...
1690
  			if (whence == SEEK_DATA)
220f2ac91   Hugh Dickins   tmpfs: support SE...
1691
1692
1693
1694
1695
  				index = end;
  			break;
  		}
  		for (i = 0; i < pvec.nr; i++, index++) {
  			if (index < indices[i]) {
965c8e59c   Andrew Morton   lseek: the "whenc...
1696
  				if (whence == SEEK_HOLE) {
220f2ac91   Hugh Dickins   tmpfs: support SE...
1697
1698
1699
1700
1701
1702
1703
1704
1705
1706
1707
  					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...
1708
1709
  			    (page && whence == SEEK_DATA) ||
  			    (!page && whence == SEEK_HOLE)) {
220f2ac91   Hugh Dickins   tmpfs: support SE...
1710
1711
1712
1713
  				done = true;
  				break;
  			}
  		}
0cd6144aa   Johannes Weiner   mm + fs: prepare ...
1714
  		pagevec_remove_exceptionals(&pvec);
220f2ac91   Hugh Dickins   tmpfs: support SE...
1715
1716
1717
1718
1719
1720
  		pagevec_release(&pvec);
  		pvec.nr = PAGEVEC_SIZE;
  		cond_resched();
  	}
  	return index;
  }
965c8e59c   Andrew Morton   lseek: the "whenc...
1721
  static loff_t shmem_file_llseek(struct file *file, loff_t offset, int whence)
220f2ac91   Hugh Dickins   tmpfs: support SE...
1722
1723
1724
1725
1726
  {
  	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...
1727
1728
  	if (whence != SEEK_DATA && whence != SEEK_HOLE)
  		return generic_file_llseek_size(file, offset, whence,
220f2ac91   Hugh Dickins   tmpfs: support SE...
1729
1730
1731
1732
1733
1734
1735
1736
1737
1738
1739
  					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...
1740
  		new_offset = shmem_seek_hole_data(mapping, start, end, whence);
220f2ac91   Hugh Dickins   tmpfs: support SE...
1741
1742
1743
1744
  		new_offset <<= PAGE_CACHE_SHIFT;
  		if (new_offset > offset) {
  			if (new_offset < inode->i_size)
  				offset = new_offset;
965c8e59c   Andrew Morton   lseek: the "whenc...
1745
  			else if (whence == SEEK_DATA)
220f2ac91   Hugh Dickins   tmpfs: support SE...
1746
1747
1748
1749
1750
  				offset = -ENXIO;
  			else
  				offset = inode->i_size;
  		}
  	}
387aae6fd   Hugh Dickins   tmpfs: fix SEEK_D...
1751
1752
  	if (offset >= 0)
  		offset = vfs_setpos(file, offset, MAX_LFS_FILESIZE);
220f2ac91   Hugh Dickins   tmpfs: support SE...
1753
1754
1755
  	mutex_unlock(&inode->i_mutex);
  	return offset;
  }
05f65b5c7   David Herrmann   shm: wait for pin...
1756
1757
1758
1759
1760
1761
1762
1763
1764
1765
1766
1767
1768
1769
1770
1771
1772
1773
1774
1775
1776
1777
1778
1779
1780
1781
1782
1783
1784
1785
1786
1787
1788
1789
1790
1791
1792
1793
1794
1795
1796
1797
1798
1799
1800
1801
1802
1803
1804
  /*
   * We need a tag: a new tag would expand every radix_tree_node by 8 bytes,
   * so reuse a tag which we firmly believe is never set or cleared on shmem.
   */
  #define SHMEM_TAG_PINNED        PAGECACHE_TAG_TOWRITE
  #define LAST_SCAN               4       /* about 150ms max */
  
  static void shmem_tag_pins(struct address_space *mapping)
  {
  	struct radix_tree_iter iter;
  	void **slot;
  	pgoff_t start;
  	struct page *page;
  
  	lru_add_drain();
  	start = 0;
  	rcu_read_lock();
  
  restart:
  	radix_tree_for_each_slot(slot, &mapping->page_tree, &iter, start) {
  		page = radix_tree_deref_slot(slot);
  		if (!page || radix_tree_exception(page)) {
  			if (radix_tree_deref_retry(page))
  				goto restart;
  		} else if (page_count(page) - page_mapcount(page) > 1) {
  			spin_lock_irq(&mapping->tree_lock);
  			radix_tree_tag_set(&mapping->page_tree, iter.index,
  					   SHMEM_TAG_PINNED);
  			spin_unlock_irq(&mapping->tree_lock);
  		}
  
  		if (need_resched()) {
  			cond_resched_rcu();
  			start = iter.index + 1;
  			goto restart;
  		}
  	}
  	rcu_read_unlock();
  }
  
  /*
   * Setting SEAL_WRITE requires us to verify there's no pending writer. However,
   * via get_user_pages(), drivers might have some pending I/O without any active
   * user-space mappings (eg., direct-IO, AIO). Therefore, we look at all pages
   * and see whether it has an elevated ref-count. If so, we tag them and wait for
   * them to be dropped.
   * The caller must guarantee that no new user will acquire writable references
   * to those pages to avoid races.
   */
40e041a2c   David Herrmann   shm: add sealing API
1805
1806
  static int shmem_wait_for_pins(struct address_space *mapping)
  {
05f65b5c7   David Herrmann   shm: wait for pin...
1807
1808
1809
1810
1811
1812
1813
1814
1815
1816
1817
1818
1819
1820
1821
1822
1823
1824
1825
1826
1827
1828
1829
1830
1831
1832
1833
1834
1835
1836
1837
1838
1839
1840
1841
1842
1843
1844
1845
1846
1847
1848
1849
1850
1851
1852
1853
1854
1855
1856
1857
1858
1859
1860
1861
1862
1863
1864
1865
1866
  	struct radix_tree_iter iter;
  	void **slot;
  	pgoff_t start;
  	struct page *page;
  	int error, scan;
  
  	shmem_tag_pins(mapping);
  
  	error = 0;
  	for (scan = 0; scan <= LAST_SCAN; scan++) {
  		if (!radix_tree_tagged(&mapping->page_tree, SHMEM_TAG_PINNED))
  			break;
  
  		if (!scan)
  			lru_add_drain_all();
  		else if (schedule_timeout_killable((HZ << scan) / 200))
  			scan = LAST_SCAN;
  
  		start = 0;
  		rcu_read_lock();
  restart:
  		radix_tree_for_each_tagged(slot, &mapping->page_tree, &iter,
  					   start, SHMEM_TAG_PINNED) {
  
  			page = radix_tree_deref_slot(slot);
  			if (radix_tree_exception(page)) {
  				if (radix_tree_deref_retry(page))
  					goto restart;
  
  				page = NULL;
  			}
  
  			if (page &&
  			    page_count(page) - page_mapcount(page) != 1) {
  				if (scan < LAST_SCAN)
  					goto continue_resched;
  
  				/*
  				 * On the last scan, we clean up all those tags
  				 * we inserted; but make a note that we still
  				 * found pages pinned.
  				 */
  				error = -EBUSY;
  			}
  
  			spin_lock_irq(&mapping->tree_lock);
  			radix_tree_tag_clear(&mapping->page_tree,
  					     iter.index, SHMEM_TAG_PINNED);
  			spin_unlock_irq(&mapping->tree_lock);
  continue_resched:
  			if (need_resched()) {
  				cond_resched_rcu();
  				start = iter.index + 1;
  				goto restart;
  			}
  		}
  		rcu_read_unlock();
  	}
  
  	return error;
40e041a2c   David Herrmann   shm: add sealing API
1867
1868
1869
1870
1871
1872
1873
1874
1875
1876
1877
1878
1879
1880
1881
1882
1883
1884
1885
1886
1887
1888
1889
1890
1891
1892
1893
1894
1895
1896
1897
1898
1899
1900
1901
1902
1903
1904
1905
1906
1907
1908
1909
1910
1911
1912
1913
1914
1915
1916
1917
1918
1919
1920
1921
1922
1923
1924
1925
1926
1927
1928
1929
1930
1931
1932
1933
1934
1935
1936
1937
1938
1939
1940
1941
1942
1943
1944
1945
1946
1947
1948
1949
1950
1951
1952
1953
1954
1955
1956
1957
1958
1959
1960
1961
1962
1963
1964
1965
1966
1967
1968
1969
1970
1971
1972
1973
1974
1975
  }
  
  #define F_ALL_SEALS (F_SEAL_SEAL | \
  		     F_SEAL_SHRINK | \
  		     F_SEAL_GROW | \
  		     F_SEAL_WRITE)
  
  int shmem_add_seals(struct file *file, unsigned int seals)
  {
  	struct inode *inode = file_inode(file);
  	struct shmem_inode_info *info = SHMEM_I(inode);
  	int error;
  
  	/*
  	 * SEALING
  	 * Sealing allows multiple parties to share a shmem-file but restrict
  	 * access to a specific subset of file operations. Seals can only be
  	 * added, but never removed. This way, mutually untrusted parties can
  	 * share common memory regions with a well-defined policy. A malicious
  	 * peer can thus never perform unwanted operations on a shared object.
  	 *
  	 * Seals are only supported on special shmem-files and always affect
  	 * the whole underlying inode. Once a seal is set, it may prevent some
  	 * kinds of access to the file. Currently, the following seals are
  	 * defined:
  	 *   SEAL_SEAL: Prevent further seals from being set on this file
  	 *   SEAL_SHRINK: Prevent the file from shrinking
  	 *   SEAL_GROW: Prevent the file from growing
  	 *   SEAL_WRITE: Prevent write access to the file
  	 *
  	 * As we don't require any trust relationship between two parties, we
  	 * must prevent seals from being removed. Therefore, sealing a file
  	 * only adds a given set of seals to the file, it never touches
  	 * existing seals. Furthermore, the "setting seals"-operation can be
  	 * sealed itself, which basically prevents any further seal from being
  	 * added.
  	 *
  	 * Semantics of sealing are only defined on volatile files. Only
  	 * anonymous shmem files support sealing. More importantly, seals are
  	 * never written to disk. Therefore, there's no plan to support it on
  	 * other file types.
  	 */
  
  	if (file->f_op != &shmem_file_operations)
  		return -EINVAL;
  	if (!(file->f_mode & FMODE_WRITE))
  		return -EPERM;
  	if (seals & ~(unsigned int)F_ALL_SEALS)
  		return -EINVAL;
  
  	mutex_lock(&inode->i_mutex);
  
  	if (info->seals & F_SEAL_SEAL) {
  		error = -EPERM;
  		goto unlock;
  	}
  
  	if ((seals & F_SEAL_WRITE) && !(info->seals & F_SEAL_WRITE)) {
  		error = mapping_deny_writable(file->f_mapping);
  		if (error)
  			goto unlock;
  
  		error = shmem_wait_for_pins(file->f_mapping);
  		if (error) {
  			mapping_allow_writable(file->f_mapping);
  			goto unlock;
  		}
  	}
  
  	info->seals |= seals;
  	error = 0;
  
  unlock:
  	mutex_unlock(&inode->i_mutex);
  	return error;
  }
  EXPORT_SYMBOL_GPL(shmem_add_seals);
  
  int shmem_get_seals(struct file *file)
  {
  	if (file->f_op != &shmem_file_operations)
  		return -EINVAL;
  
  	return SHMEM_I(file_inode(file))->seals;
  }
  EXPORT_SYMBOL_GPL(shmem_get_seals);
  
  long shmem_fcntl(struct file *file, unsigned int cmd, unsigned long arg)
  {
  	long error;
  
  	switch (cmd) {
  	case F_ADD_SEALS:
  		/* disallow upper 32bit */
  		if (arg > UINT_MAX)
  			return -EINVAL;
  
  		error = shmem_add_seals(file, arg);
  		break;
  	case F_GET_SEALS:
  		error = shmem_get_seals(file);
  		break;
  	default:
  		error = -EINVAL;
  		break;
  	}
  
  	return error;
  }
83e4fa9c1   Hugh Dickins   tmpfs: support fa...
1976
1977
1978
  static long shmem_fallocate(struct file *file, int mode, loff_t offset,
  							 loff_t len)
  {
496ad9aa8   Al Viro   new helper: file_...
1979
  	struct inode *inode = file_inode(file);
e2d12e22c   Hugh Dickins   tmpfs: support fa...
1980
  	struct shmem_sb_info *sbinfo = SHMEM_SB(inode->i_sb);
40e041a2c   David Herrmann   shm: add sealing API
1981
  	struct shmem_inode_info *info = SHMEM_I(inode);
1aac14003   Hugh Dickins   tmpfs: quit when ...
1982
  	struct shmem_falloc shmem_falloc;
e2d12e22c   Hugh Dickins   tmpfs: support fa...
1983
1984
  	pgoff_t start, index, end;
  	int error;
83e4fa9c1   Hugh Dickins   tmpfs: support fa...
1985

13ace4d0d   Hugh Dickins   tmpfs: ZERO_RANGE...
1986
1987
  	if (mode & ~(FALLOC_FL_KEEP_SIZE | FALLOC_FL_PUNCH_HOLE))
  		return -EOPNOTSUPP;
83e4fa9c1   Hugh Dickins   tmpfs: support fa...
1988
1989
1990
1991
1992
1993
  	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;
8e205f779   Hugh Dickins   shmem: fix faulti...
1994
  		DECLARE_WAIT_QUEUE_HEAD_ONSTACK(shmem_falloc_waitq);
83e4fa9c1   Hugh Dickins   tmpfs: support fa...
1995

40e041a2c   David Herrmann   shm: add sealing API
1996
1997
1998
1999
2000
  		/* protected by i_mutex */
  		if (info->seals & F_SEAL_WRITE) {
  			error = -EPERM;
  			goto out;
  		}
8e205f779   Hugh Dickins   shmem: fix faulti...
2001
  		shmem_falloc.waitq = &shmem_falloc_waitq;
f00cdc6df   Hugh Dickins   shmem: fix faulti...
2002
2003
2004
2005
2006
  		shmem_falloc.start = unmap_start >> PAGE_SHIFT;
  		shmem_falloc.next = (unmap_end + 1) >> PAGE_SHIFT;
  		spin_lock(&inode->i_lock);
  		inode->i_private = &shmem_falloc;
  		spin_unlock(&inode->i_lock);
83e4fa9c1   Hugh Dickins   tmpfs: support fa...
2007
2008
2009
2010
2011
  		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 */
8e205f779   Hugh Dickins   shmem: fix faulti...
2012
2013
2014
2015
2016
  
  		spin_lock(&inode->i_lock);
  		inode->i_private = NULL;
  		wake_up_all(&shmem_falloc_waitq);
  		spin_unlock(&inode->i_lock);
83e4fa9c1   Hugh Dickins   tmpfs: support fa...
2017
  		error = 0;
8e205f779   Hugh Dickins   shmem: fix faulti...
2018
  		goto out;
e2d12e22c   Hugh Dickins   tmpfs: support fa...
2019
2020
2021
2022
2023
2024
  	}
  
  	/* We need to check rlimit even when FALLOC_FL_KEEP_SIZE */
  	error = inode_newsize_ok(inode, offset + len);
  	if (error)
  		goto out;
40e041a2c   David Herrmann   shm: add sealing API
2025
2026
2027
2028
  	if ((info->seals & F_SEAL_GROW) && offset + len > inode->i_size) {
  		error = -EPERM;
  		goto out;
  	}
e2d12e22c   Hugh Dickins   tmpfs: support fa...
2029
2030
2031
2032
2033
2034
  	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...
2035
  	}
8e205f779   Hugh Dickins   shmem: fix faulti...
2036
  	shmem_falloc.waitq = NULL;
1aac14003   Hugh Dickins   tmpfs: quit when ...
2037
2038
2039
2040
2041
2042
2043
  	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...
2044
2045
2046
2047
2048
2049
2050
2051
2052
  	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 ...
2053
2054
  		else if (shmem_falloc.nr_unswapped > shmem_falloc.nr_falloced)
  			error = -ENOMEM;
e2d12e22c   Hugh Dickins   tmpfs: support fa...
2055
  		else
1635f6a74   Hugh Dickins   tmpfs: undo fallo...
2056
  			error = shmem_getpage(inode, index, &page, SGP_FALLOC,
e2d12e22c   Hugh Dickins   tmpfs: support fa...
2057
2058
  									NULL);
  		if (error) {
1635f6a74   Hugh Dickins   tmpfs: undo fallo...
2059
2060
2061
2062
  			/* 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 ...
2063
  			goto undone;
e2d12e22c   Hugh Dickins   tmpfs: support fa...
2064
  		}
e2d12e22c   Hugh Dickins   tmpfs: support fa...
2065
  		/*
1aac14003   Hugh Dickins   tmpfs: quit when ...
2066
2067
2068
2069
2070
2071
2072
2073
  		 * 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...
2074
2075
2076
  		 * 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...
2077
2078
2079
2080
2081
2082
2083
2084
2085
2086
2087
  		 * 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...
2088
  	inode->i_ctime = CURRENT_TIME;
1aac14003   Hugh Dickins   tmpfs: quit when ...
2089
2090
2091
2092
  undone:
  	spin_lock(&inode->i_lock);
  	inode->i_private = NULL;
  	spin_unlock(&inode->i_lock);
e2d12e22c   Hugh Dickins   tmpfs: support fa...
2093
  out:
83e4fa9c1   Hugh Dickins   tmpfs: support fa...
2094
2095
2096
  	mutex_unlock(&inode->i_mutex);
  	return error;
  }
726c33422   David Howells   [PATCH] VFS: Perm...
2097
  static int shmem_statfs(struct dentry *dentry, struct kstatfs *buf)
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
2098
  {
726c33422   David Howells   [PATCH] VFS: Perm...
2099
  	struct shmem_sb_info *sbinfo = SHMEM_SB(dentry->d_sb);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
2100
2101
2102
2103
  
  	buf->f_type = TMPFS_MAGIC;
  	buf->f_bsize = PAGE_CACHE_SIZE;
  	buf->f_namelen = NAME_MAX;
0edd73b33   Hugh Dickins   [PATCH] shmem: re...
2104
  	if (sbinfo->max_blocks) {
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
2105
  		buf->f_blocks = sbinfo->max_blocks;
41ffe5d5c   Hugh Dickins   tmpfs: miscellane...
2106
2107
2108
  		buf->f_bavail =
  		buf->f_bfree  = sbinfo->max_blocks -
  				percpu_counter_sum(&sbinfo->used_blocks);
0edd73b33   Hugh Dickins   [PATCH] shmem: re...
2109
2110
  	}
  	if (sbinfo->max_inodes) {
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
2111
2112
  		buf->f_files = sbinfo->max_inodes;
  		buf->f_ffree = sbinfo->free_inodes;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
2113
2114
2115
2116
2117
2118
2119
2120
2121
  	}
  	/* 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() ...
2122
  shmem_mknod(struct inode *dir, struct dentry *dentry, umode_t mode, dev_t dev)
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
2123
  {
0b0a0806b   Hugh Dickins   shmem: fix shared...
2124
  	struct inode *inode;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
2125
  	int error = -ENOSPC;
454abafe9   Dmitry Monakhov   ramfs: replace in...
2126
  	inode = shmem_get_inode(dir->i_sb, dir, mode, dev, VM_NORESERVE);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
2127
  	if (inode) {
feda821e7   Christoph Hellwig   fs: remove generi...
2128
2129
2130
  		error = simple_acl_create(dir, inode);
  		if (error)
  			goto out_iput;
2a7dba391   Eric Paris   fs/vfs/security: ...
2131
  		error = security_inode_init_security(inode, dir,
9d8f13ba3   Mimi Zohar   security: new sec...
2132
  						     &dentry->d_name,
6d9d88d07   Jarkko Sakkinen   tmpfs: security x...
2133
  						     shmem_initxattrs, NULL);
feda821e7   Christoph Hellwig   fs: remove generi...
2134
2135
  		if (error && error != -EOPNOTSUPP)
  			goto out_iput;
37ec43cdc   Mimi Zohar   evm: calculate HM...
2136

718deb6b6   Al Viro   Fix breakage in s...
2137
  		error = 0;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
2138
2139
2140
2141
  		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
2142
2143
  	}
  	return error;
feda821e7   Christoph Hellwig   fs: remove generi...
2144
2145
2146
  out_iput:
  	iput(inode);
  	return error;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
2147
  }
60545d0d4   Al Viro   [O_TMPFILE] it's ...
2148
2149
2150
2151
2152
2153
2154
2155
2156
2157
2158
  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...
2159
2160
2161
2162
2163
  		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 ...
2164
2165
2166
  		d_tmpfile(dentry, inode);
  	}
  	return error;
feda821e7   Christoph Hellwig   fs: remove generi...
2167
2168
2169
  out_iput:
  	iput(inode);
  	return error;
60545d0d4   Al Viro   [O_TMPFILE] it's ...
2170
  }
18bb1db3e   Al Viro   switch vfs_mkdir(...
2171
  static int shmem_mkdir(struct inode *dir, struct dentry *dentry, umode_t mode)
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
2172
2173
2174
2175
2176
  {
  	int error;
  
  	if ((error = shmem_mknod(dir, dentry, mode | S_IFDIR, 0)))
  		return error;
d8c76e6f4   Dave Hansen   [PATCH] r/o bind ...
2177
  	inc_nlink(dir);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
2178
2179
  	return 0;
  }
4acdaf27e   Al Viro   switch ->create()...
2180
  static int shmem_create(struct inode *dir, struct dentry *dentry, umode_t mode,
ebfc3b49a   Al Viro   don't pass nameid...
2181
  		bool excl)
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
2182
2183
2184
2185
2186
2187
2188
2189
2190
2191
  {
  	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...
2192
  	int ret;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
2193
2194
2195
2196
2197
2198
  
  	/*
  	 * 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...
2199
2200
2201
  	ret = shmem_reserve_inode(inode->i_sb);
  	if (ret)
  		goto out;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
2202
2203
2204
  
  	dir->i_size += BOGO_DIRENT_SIZE;
  	inode->i_ctime = dir->i_ctime = dir->i_mtime = CURRENT_TIME;
d8c76e6f4   Dave Hansen   [PATCH] r/o bind ...
2205
  	inc_nlink(inode);
7de9c6ee3   Al Viro   new helper: ihold()
2206
  	ihold(inode);	/* New dentry reference */
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
2207
2208
  	dget(dentry);		/* Extra pinning count for the created dentry */
  	d_instantiate(dentry, inode);
5b04c6890   Pavel Emelyanov   shmem: factor out...
2209
2210
  out:
  	return ret;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
2211
2212
2213
2214
2215
  }
  
  static int shmem_unlink(struct inode *dir, struct dentry *dentry)
  {
  	struct inode *inode = dentry->d_inode;
5b04c6890   Pavel Emelyanov   shmem: factor out...
2216
2217
  	if (inode->i_nlink > 1 && !S_ISDIR(inode->i_mode))
  		shmem_free_inode(inode->i_sb);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
2218
2219
2220
  
  	dir->i_size -= BOGO_DIRENT_SIZE;
  	inode->i_ctime = dir->i_ctime = dir->i_mtime = CURRENT_TIME;
9a53c3a78   Dave Hansen   [PATCH] r/o bind ...
2221
  	drop_nlink(inode);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
2222
2223
2224
2225
2226
2227
2228
2229
  	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 ...
2230
2231
  	drop_nlink(dentry->d_inode);
  	drop_nlink(dir);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
2232
2233
  	return shmem_unlink(dir, dentry);
  }
37456771c   Miklos Szeredi   shmem: support RE...
2234
2235
2236
2237
2238
2239
2240
2241
2242
2243
2244
2245
2246
2247
2248
2249
2250
2251
2252
2253
2254
  static int shmem_exchange(struct inode *old_dir, struct dentry *old_dentry, struct inode *new_dir, struct dentry *new_dentry)
  {
  	bool old_is_dir = S_ISDIR(old_dentry->d_inode->i_mode);
  	bool new_is_dir = S_ISDIR(new_dentry->d_inode->i_mode);
  
  	if (old_dir != new_dir && old_is_dir != new_is_dir) {
  		if (old_is_dir) {
  			drop_nlink(old_dir);
  			inc_nlink(new_dir);
  		} else {
  			drop_nlink(new_dir);
  			inc_nlink(old_dir);
  		}
  	}
  	old_dir->i_ctime = old_dir->i_mtime =
  	new_dir->i_ctime = new_dir->i_mtime =
  	old_dentry->d_inode->i_ctime =
  	new_dentry->d_inode->i_ctime = CURRENT_TIME;
  
  	return 0;
  }
46fdb794e   Miklos Szeredi   shmem: support RE...
2255
2256
2257
2258
2259
2260
2261
2262
2263
2264
2265
2266
2267
2268
2269
2270
2271
2272
2273
2274
2275
2276
2277
2278
2279
  static int shmem_whiteout(struct inode *old_dir, struct dentry *old_dentry)
  {
  	struct dentry *whiteout;
  	int error;
  
  	whiteout = d_alloc(old_dentry->d_parent, &old_dentry->d_name);
  	if (!whiteout)
  		return -ENOMEM;
  
  	error = shmem_mknod(old_dir, whiteout,
  			    S_IFCHR | WHITEOUT_MODE, WHITEOUT_DEV);
  	dput(whiteout);
  	if (error)
  		return error;
  
  	/*
  	 * Cheat and hash the whiteout while the old dentry is still in
  	 * place, instead of playing games with FS_RENAME_DOES_D_MOVE.
  	 *
  	 * d_lookup() will consistently find one of them at this point,
  	 * not sure which one, but that isn't even important.
  	 */
  	d_rehash(whiteout);
  	return 0;
  }
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
2280
2281
2282
2283
2284
2285
  /*
   * 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.
   */
3b69ff51d   Miklos Szeredi   shmem: support RE...
2286
  static int shmem_rename2(struct inode *old_dir, struct dentry *old_dentry, struct inode *new_dir, struct dentry *new_dentry, unsigned int flags)
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
2287
2288
2289
  {
  	struct inode *inode = old_dentry->d_inode;
  	int they_are_dirs = S_ISDIR(inode->i_mode);
46fdb794e   Miklos Szeredi   shmem: support RE...
2290
  	if (flags & ~(RENAME_NOREPLACE | RENAME_EXCHANGE | RENAME_WHITEOUT))
3b69ff51d   Miklos Szeredi   shmem: support RE...
2291
  		return -EINVAL;
37456771c   Miklos Szeredi   shmem: support RE...
2292
2293
  	if (flags & RENAME_EXCHANGE)
  		return shmem_exchange(old_dir, old_dentry, new_dir, new_dentry);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
2294
2295
  	if (!simple_empty(new_dentry))
  		return -ENOTEMPTY;
46fdb794e   Miklos Szeredi   shmem: support RE...
2296
2297
2298
2299
2300
2301
2302
  	if (flags & RENAME_WHITEOUT) {
  		int error;
  
  		error = shmem_whiteout(old_dir, old_dentry);
  		if (error)
  			return error;
  	}
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
2303
2304
  	if (new_dentry->d_inode) {
  		(void) shmem_unlink(new_dir, new_dentry);
b928095b0   Miklos Szeredi   shmem: fix nlink ...
2305
2306
  		if (they_are_dirs) {
  			drop_nlink(new_dentry->d_inode);
9a53c3a78   Dave Hansen   [PATCH] r/o bind ...
2307
  			drop_nlink(old_dir);
b928095b0   Miklos Szeredi   shmem: fix nlink ...
2308
  		}
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
2309
  	} else if (they_are_dirs) {
9a53c3a78   Dave Hansen   [PATCH] r/o bind ...
2310
  		drop_nlink(old_dir);
d8c76e6f4   Dave Hansen   [PATCH] r/o bind ...
2311
  		inc_nlink(new_dir);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
2312
2313
2314
2315
2316
2317
2318
2319
2320
2321
2322
2323
2324
2325
2326
  	}
  
  	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...
2327
  	struct page *page;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
2328
2329
2330
2331
2332
2333
  	char *kaddr;
  	struct shmem_inode_info *info;
  
  	len = strlen(symname) + 1;
  	if (len > PAGE_CACHE_SIZE)
  		return -ENAMETOOLONG;
454abafe9   Dmitry Monakhov   ramfs: replace in...
2334
  	inode = shmem_get_inode(dir->i_sb, dir, S_IFLNK|S_IRWXUGO, 0, VM_NORESERVE);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
2335
2336
  	if (!inode)
  		return -ENOSPC;
9d8f13ba3   Mimi Zohar   security: new sec...
2337
  	error = security_inode_init_security(inode, dir, &dentry->d_name,
6d9d88d07   Jarkko Sakkinen   tmpfs: security x...
2338
  					     shmem_initxattrs, NULL);
570bc1c2e   Stephen Smalley   [PATCH] tmpfs: En...
2339
2340
2341
2342
2343
2344
2345
  	if (error) {
  		if (error != -EOPNOTSUPP) {
  			iput(inode);
  			return error;
  		}
  		error = 0;
  	}
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
2346
2347
  	info = SHMEM_I(inode);
  	inode->i_size = len-1;
69f07ec93   Hugh Dickins   tmpfs: use kmemdu...
2348
2349
2350
2351
2352
2353
2354
  	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
2355
2356
2357
2358
2359
2360
  	} else {
  		error = shmem_getpage(inode, 0, &page, SGP_WRITE, NULL);
  		if (error) {
  			iput(inode);
  			return error;
  		}
14fcc23fd   Hugh Dickins   tmpfs: fix kernel...
2361
  		inode->i_mapping->a_ops = &shmem_aops;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
2362
  		inode->i_op = &shmem_symlink_inode_operations;
9b04c5fec   Cong Wang   mm: remove the se...
2363
  		kaddr = kmap_atomic(page);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
2364
  		memcpy(kaddr, symname, len);
9b04c5fec   Cong Wang   mm: remove the se...
2365
  		kunmap_atomic(kaddr);
ec9516fbc   Hugh Dickins   tmpfs: optimize c...
2366
  		SetPageUptodate(page);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
2367
  		set_page_dirty(page);
6746aff74   Wu Fengguang   HWPOISON: shmem: ...
2368
  		unlock_page(page);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
2369
2370
  		page_cache_release(page);
  	}
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
2371
2372
2373
2374
2375
2376
  	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...
2377
  static void *shmem_follow_short_symlink(struct dentry *dentry, struct nameidata *nd)
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
2378
  {
69f07ec93   Hugh Dickins   tmpfs: use kmemdu...
2379
  	nd_set_link(nd, SHMEM_I(dentry->d_inode)->symlink);
cc314eef0   Linus Torvalds   Fix nasty ncpfs s...
2380
  	return NULL;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
2381
  }
cc314eef0   Linus Torvalds   Fix nasty ncpfs s...
2382
  static void *shmem_follow_link(struct dentry *dentry, struct nameidata *nd)
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
2383
2384
  {
  	struct page *page = NULL;
41ffe5d5c   Hugh Dickins   tmpfs: miscellane...
2385
2386
  	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...
2387
2388
  	if (page)
  		unlock_page(page);
cc314eef0   Linus Torvalds   Fix nasty ncpfs s...
2389
  	return page;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
2390
  }
cc314eef0   Linus Torvalds   Fix nasty ncpfs s...
2391
  static void shmem_put_link(struct dentry *dentry, struct nameidata *nd, void *cookie)
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
2392
2393
  {
  	if (!IS_ERR(nd_get_link(nd))) {
cc314eef0   Linus Torvalds   Fix nasty ncpfs s...
2394
  		struct page *page = cookie;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
2395
2396
2397
  		kunmap(page);
  		mark_page_accessed(page);
  		page_cache_release(page);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
2398
2399
  	}
  }
b09e0fa4b   Eric Paris   tmpfs: implement ...
2400
  #ifdef CONFIG_TMPFS_XATTR
467118102   Randy Dunlap   mm/shmem and tiny...
2401
  /*
b09e0fa4b   Eric Paris   tmpfs: implement ...
2402
2403
   * 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...
2404
2405
2406
   * like ACLs, we also need to implement the security.* handlers at
   * filesystem level, though.
   */
6d9d88d07   Jarkko Sakkinen   tmpfs: security x...
2407
  /*
6d9d88d07   Jarkko Sakkinen   tmpfs: security x...
2408
2409
2410
2411
2412
2413
2414
2415
   * 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...
2416
  	struct simple_xattr *new_xattr;
6d9d88d07   Jarkko Sakkinen   tmpfs: security x...
2417
2418
2419
  	size_t len;
  
  	for (xattr = xattr_array; xattr->name != NULL; xattr++) {
38f386574   Aristeu Rozanski   xattr: extract si...
2420
  		new_xattr = simple_xattr_alloc(xattr->value, xattr->value_len);
6d9d88d07   Jarkko Sakkinen   tmpfs: security x...
2421
2422
2423
2424
2425
2426
2427
2428
2429
2430
2431
2432
2433
2434
2435
  		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...
2436
  		simple_xattr_list_add(&info->xattrs, new_xattr);
6d9d88d07   Jarkko Sakkinen   tmpfs: security x...
2437
2438
2439
2440
  	}
  
  	return 0;
  }
bb4354538   Stephen Hemminger   fs: xattr_handler...
2441
  static const struct xattr_handler *shmem_xattr_handlers[] = {
b09e0fa4b   Eric Paris   tmpfs: implement ...
2442
  #ifdef CONFIG_TMPFS_POSIX_ACL
feda821e7   Christoph Hellwig   fs: remove generi...
2443
2444
  	&posix_acl_access_xattr_handler,
  	&posix_acl_default_xattr_handler,
b09e0fa4b   Eric Paris   tmpfs: implement ...
2445
  #endif
39f0247d3   Andreas Gruenbacher   [PATCH] Access Co...
2446
2447
  	NULL
  };
b09e0fa4b   Eric Paris   tmpfs: implement ...
2448
2449
2450
2451
2452
2453
2454
2455
2456
2457
2458
2459
2460
2461
2462
2463
2464
2465
2466
2467
2468
2469
2470
  
  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...
2471
  	struct shmem_inode_info *info = SHMEM_I(dentry->d_inode);
b09e0fa4b   Eric Paris   tmpfs: implement ...
2472
2473
2474
2475
2476
2477
2478
2479
2480
2481
2482
2483
2484
  	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...
2485
  	return simple_xattr_get(&info->xattrs, name, buffer, size);
b09e0fa4b   Eric Paris   tmpfs: implement ...
2486
2487
2488
2489
2490
  }
  
  static int shmem_setxattr(struct dentry *dentry, const char *name,
  			  const void *value, size_t size, int flags)
  {
38f386574   Aristeu Rozanski   xattr: extract si...
2491
  	struct shmem_inode_info *info = SHMEM_I(dentry->d_inode);
b09e0fa4b   Eric Paris   tmpfs: implement ...
2492
2493
2494
2495
2496
2497
2498
2499
2500
2501
2502
2503
2504
  	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...
2505
  	return simple_xattr_set(&info->xattrs, name, value, size, flags);
b09e0fa4b   Eric Paris   tmpfs: implement ...
2506
2507
2508
2509
  }
  
  static int shmem_removexattr(struct dentry *dentry, const char *name)
  {
38f386574   Aristeu Rozanski   xattr: extract si...
2510
  	struct shmem_inode_info *info = SHMEM_I(dentry->d_inode);
b09e0fa4b   Eric Paris   tmpfs: implement ...
2511
2512
2513
2514
2515
2516
2517
2518
2519
2520
2521
2522
2523
  	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...
2524
  	return simple_xattr_remove(&info->xattrs, name);
b09e0fa4b   Eric Paris   tmpfs: implement ...
2525
2526
2527
2528
  }
  
  static ssize_t shmem_listxattr(struct dentry *dentry, char *buffer, size_t size)
  {
38f386574   Aristeu Rozanski   xattr: extract si...
2529
2530
  	struct shmem_inode_info *info = SHMEM_I(dentry->d_inode);
  	return simple_xattr_list(&info->xattrs, buffer, size);
b09e0fa4b   Eric Paris   tmpfs: implement ...
2531
2532
  }
  #endif /* CONFIG_TMPFS_XATTR */
69f07ec93   Hugh Dickins   tmpfs: use kmemdu...
2533
  static const struct inode_operations shmem_short_symlink_operations = {
b09e0fa4b   Eric Paris   tmpfs: implement ...
2534
  	.readlink	= generic_readlink,
69f07ec93   Hugh Dickins   tmpfs: use kmemdu...
2535
  	.follow_link	= shmem_follow_short_symlink,
b09e0fa4b   Eric Paris   tmpfs: implement ...
2536
2537
2538
2539
2540
2541
2542
2543
2544
2545
2546
2547
2548
2549
2550
2551
2552
  #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...
2553
  #endif
b09e0fa4b   Eric Paris   tmpfs: implement ...
2554
  };
39f0247d3   Andreas Gruenbacher   [PATCH] Access Co...
2555

91828a405   David M. Grimes   [PATCH] knfsd: ad...
2556
2557
2558
2559
2560
2561
2562
2563
2564
2565
2566
2567
  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...
2568
2569
  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...
2570
  {
91828a405   David M. Grimes   [PATCH] knfsd: ad...
2571
  	struct inode *inode;
480b116c9   Christoph Hellwig   shmem: new export...
2572
  	struct dentry *dentry = NULL;
35c2a7f49   Hugh Dickins   tmpfs,ceph,gfs2,i...
2573
  	u64 inum;
480b116c9   Christoph Hellwig   shmem: new export...
2574
2575
2576
  
  	if (fh_len < 3)
  		return NULL;
91828a405   David M. Grimes   [PATCH] knfsd: ad...
2577

35c2a7f49   Hugh Dickins   tmpfs,ceph,gfs2,i...
2578
2579
  	inum = fid->raw[2];
  	inum = (inum << 32) | fid->raw[1];
480b116c9   Christoph Hellwig   shmem: new export...
2580
2581
  	inode = ilookup5(sb, (unsigned long)(inum + fid->raw[0]),
  			shmem_match, fid->raw);
91828a405   David M. Grimes   [PATCH] knfsd: ad...
2582
  	if (inode) {
480b116c9   Christoph Hellwig   shmem: new export...
2583
  		dentry = d_find_alias(inode);
91828a405   David M. Grimes   [PATCH] knfsd: ad...
2584
2585
  		iput(inode);
  	}
480b116c9   Christoph Hellwig   shmem: new export...
2586
  	return dentry;
91828a405   David M. Grimes   [PATCH] knfsd: ad...
2587
  }
b0b0382bb   Al Viro   ->encode_fh() API...
2588
2589
  static int shmem_encode_fh(struct inode *inode, __u32 *fh, int *len,
  				struct inode *parent)
91828a405   David M. Grimes   [PATCH] knfsd: ad...
2590
  {
5fe0c2378   Aneesh Kumar K.V   exportfs: Return ...
2591
2592
  	if (*len < 3) {
  		*len = 3;
94e07a759   Namjae Jeon   fs: encode_fh: re...
2593
  		return FILEID_INVALID;
5fe0c2378   Aneesh Kumar K.V   exportfs: Return ...
2594
  	}
91828a405   David M. Grimes   [PATCH] knfsd: ad...
2595

1d3382cbf   Al Viro   new helper: inode...
2596
  	if (inode_unhashed(inode)) {
91828a405   David M. Grimes   [PATCH] knfsd: ad...
2597
2598
2599
2600
2601
2602
2603
  		/* 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...
2604
  		if (inode_unhashed(inode))
91828a405   David M. Grimes   [PATCH] knfsd: ad...
2605
2606
2607
2608
2609
2610
2611
2612
2613
2614
2615
2616
  			__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...
2617
  static const struct export_operations shmem_export_ops = {
91828a405   David M. Grimes   [PATCH] knfsd: ad...
2618
  	.get_parent     = shmem_get_parent,
91828a405   David M. Grimes   [PATCH] knfsd: ad...
2619
  	.encode_fh      = shmem_encode_fh,
480b116c9   Christoph Hellwig   shmem: new export...
2620
  	.fh_to_dentry	= shmem_fh_to_dentry,
91828a405   David M. Grimes   [PATCH] knfsd: ad...
2621
  };
680d794ba   akpm@linux-foundation.org   mount options: fi...
2622
2623
  static int shmem_parse_options(char *options, struct shmem_sb_info *sbinfo,
  			       bool remount)
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
2624
2625
  {
  	char *this_char, *value, *rest;
49cd0a5c2   Greg Thelen   tmpfs: fix mempol...
2626
  	struct mempolicy *mpol = NULL;
8751e0395   Eric W. Biederman   userns: Convert t...
2627
2628
  	uid_t uid;
  	gid_t gid;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
2629

b00dc3ad7   Hugh Dickins   [PATCH] tmpfs: fi...
2630
2631
2632
2633
2634
2635
2636
2637
2638
2639
2640
2641
2642
2643
2644
2645
2646
  	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
2647
2648
2649
2650
2651
2652
2653
2654
2655
  		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...
2656
  			goto error;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
2657
2658
2659
2660
2661
2662
2663
2664
2665
2666
2667
2668
2669
  		}
  
  		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...
2670
2671
  			sbinfo->max_blocks =
  				DIV_ROUND_UP(size, PAGE_CACHE_SIZE);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
2672
  		} else if (!strcmp(this_char,"nr_blocks")) {
680d794ba   akpm@linux-foundation.org   mount options: fi...
2673
  			sbinfo->max_blocks = memparse(value, &rest);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
2674
2675
2676
  			if (*rest)
  				goto bad_val;
  		} else if (!strcmp(this_char,"nr_inodes")) {
680d794ba   akpm@linux-foundation.org   mount options: fi...
2677
  			sbinfo->max_inodes = memparse(value, &rest);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
2678
2679
2680
  			if (*rest)
  				goto bad_val;
  		} else if (!strcmp(this_char,"mode")) {
680d794ba   akpm@linux-foundation.org   mount options: fi...
2681
  			if (remount)
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
2682
  				continue;
680d794ba   akpm@linux-foundation.org   mount options: fi...
2683
  			sbinfo->mode = simple_strtoul(value, &rest, 8) & 07777;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
2684
2685
2686
  			if (*rest)
  				goto bad_val;
  		} else if (!strcmp(this_char,"uid")) {
680d794ba   akpm@linux-foundation.org   mount options: fi...
2687
  			if (remount)
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
2688
  				continue;
8751e0395   Eric W. Biederman   userns: Convert t...
2689
  			uid = simple_strtoul(value, &rest, 0);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
2690
2691
  			if (*rest)
  				goto bad_val;
8751e0395   Eric W. Biederman   userns: Convert t...
2692
2693
2694
  			sbinfo->uid = make_kuid(current_user_ns(), uid);
  			if (!uid_valid(sbinfo->uid))
  				goto bad_val;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
2695
  		} else if (!strcmp(this_char,"gid")) {
680d794ba   akpm@linux-foundation.org   mount options: fi...
2696
  			if (remount)
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
2697
  				continue;
8751e0395   Eric W. Biederman   userns: Convert t...
2698
  			gid = simple_strtoul(value, &rest, 0);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
2699
2700
  			if (*rest)
  				goto bad_val;
8751e0395   Eric W. Biederman   userns: Convert t...
2701
2702
2703
  			sbinfo->gid = make_kgid(current_user_ns(), gid);
  			if (!gid_valid(sbinfo->gid))
  				goto bad_val;
7339ff830   Robin Holt   [PATCH] Add tmpfs...
2704
  		} else if (!strcmp(this_char,"mpol")) {
49cd0a5c2   Greg Thelen   tmpfs: fix mempol...
2705
2706
2707
  			mpol_put(mpol);
  			mpol = NULL;
  			if (mpol_parse_str(value, &mpol))
7339ff830   Robin Holt   [PATCH] Add tmpfs...
2708
  				goto bad_val;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
2709
2710
2711
2712
  		} else {
  			printk(KERN_ERR "tmpfs: Bad mount option %s
  ",
  			       this_char);
49cd0a5c2   Greg Thelen   tmpfs: fix mempol...
2713
  			goto error;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
2714
2715
  		}
  	}
49cd0a5c2   Greg Thelen   tmpfs: fix mempol...
2716
  	sbinfo->mpol = mpol;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
2717
2718
2719
2720
2721
2722
  	return 0;
  
  bad_val:
  	printk(KERN_ERR "tmpfs: Bad value '%s' for mount option '%s'
  ",
  	       value, this_char);
49cd0a5c2   Greg Thelen   tmpfs: fix mempol...
2723
2724
  error:
  	mpol_put(mpol);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
2725
2726
2727
2728
2729
2730
2731
  	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...
2732
  	struct shmem_sb_info config = *sbinfo;
0edd73b33   Hugh Dickins   [PATCH] shmem: re...
2733
2734
  	unsigned long inodes;
  	int error = -EINVAL;
5f00110f7   Greg Thelen   tmpfs: fix use-af...
2735
  	config.mpol = NULL;
680d794ba   akpm@linux-foundation.org   mount options: fi...
2736
  	if (shmem_parse_options(data, &config, true))
0edd73b33   Hugh Dickins   [PATCH] shmem: re...
2737
  		return error;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
2738

0edd73b33   Hugh Dickins   [PATCH] shmem: re...
2739
  	spin_lock(&sbinfo->stat_lock);
0edd73b33   Hugh Dickins   [PATCH] shmem: re...
2740
  	inodes = sbinfo->max_inodes - sbinfo->free_inodes;
7e496299d   Tim Chen   tmpfs: make tmpfs...
2741
  	if (percpu_counter_compare(&sbinfo->used_blocks, config.max_blocks) > 0)
0edd73b33   Hugh Dickins   [PATCH] shmem: re...
2742
  		goto out;
680d794ba   akpm@linux-foundation.org   mount options: fi...
2743
  	if (config.max_inodes < inodes)
0edd73b33   Hugh Dickins   [PATCH] shmem: re...
2744
2745
  		goto out;
  	/*
54af60421   Hugh Dickins   tmpfs: convert sh...
2746
  	 * Those tests disallow limited->unlimited while any are in use;
0edd73b33   Hugh Dickins   [PATCH] shmem: re...
2747
2748
2749
  	 * 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...
2750
  	if (config.max_blocks && !sbinfo->max_blocks)
0edd73b33   Hugh Dickins   [PATCH] shmem: re...
2751
  		goto out;
680d794ba   akpm@linux-foundation.org   mount options: fi...
2752
  	if (config.max_inodes && !sbinfo->max_inodes)
0edd73b33   Hugh Dickins   [PATCH] shmem: re...
2753
2754
2755
  		goto out;
  
  	error = 0;
680d794ba   akpm@linux-foundation.org   mount options: fi...
2756
  	sbinfo->max_blocks  = config.max_blocks;
680d794ba   akpm@linux-foundation.org   mount options: fi...
2757
2758
  	sbinfo->max_inodes  = config.max_inodes;
  	sbinfo->free_inodes = config.max_inodes - inodes;
71fe804b6   Lee Schermerhorn   mempolicy: use st...
2759

5f00110f7   Greg Thelen   tmpfs: fix use-af...
2760
2761
2762
2763
2764
2765
2766
  	/*
  	 * 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...
2767
2768
2769
  out:
  	spin_unlock(&sbinfo->stat_lock);
  	return error;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
2770
  }
680d794ba   akpm@linux-foundation.org   mount options: fi...
2771

34c80b1d9   Al Viro   vfs: switch ->sho...
2772
  static int shmem_show_options(struct seq_file *seq, struct dentry *root)
680d794ba   akpm@linux-foundation.org   mount options: fi...
2773
  {
34c80b1d9   Al Viro   vfs: switch ->sho...
2774
  	struct shmem_sb_info *sbinfo = SHMEM_SB(root->d_sb);
680d794ba   akpm@linux-foundation.org   mount options: fi...
2775
2776
2777
2778
2779
2780
2781
  
  	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...
2782
  		seq_printf(seq, ",mode=%03ho", sbinfo->mode);
8751e0395   Eric W. Biederman   userns: Convert t...
2783
2784
2785
2786
2787
2788
  	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...
2789
  	shmem_show_mpol(seq, sbinfo->mpol);
680d794ba   akpm@linux-foundation.org   mount options: fi...
2790
2791
  	return 0;
  }
9183df25f   David Herrmann   shm: add memfd_cr...
2792
2793
2794
2795
2796
2797
2798
2799
2800
2801
2802
2803
2804
2805
2806
2807
2808
2809
2810
2811
2812
2813
2814
2815
2816
2817
2818
2819
2820
2821
2822
2823
2824
2825
2826
2827
2828
2829
2830
2831
2832
2833
2834
2835
2836
2837
2838
2839
2840
2841
2842
2843
2844
2845
2846
2847
2848
2849
2850
2851
2852
2853
2854
2855
2856
2857
2858
2859
2860
2861
  
  #define MFD_NAME_PREFIX "memfd:"
  #define MFD_NAME_PREFIX_LEN (sizeof(MFD_NAME_PREFIX) - 1)
  #define MFD_NAME_MAX_LEN (NAME_MAX - MFD_NAME_PREFIX_LEN)
  
  #define MFD_ALL_FLAGS (MFD_CLOEXEC | MFD_ALLOW_SEALING)
  
  SYSCALL_DEFINE2(memfd_create,
  		const char __user *, uname,
  		unsigned int, flags)
  {
  	struct shmem_inode_info *info;
  	struct file *file;
  	int fd, error;
  	char *name;
  	long len;
  
  	if (flags & ~(unsigned int)MFD_ALL_FLAGS)
  		return -EINVAL;
  
  	/* length includes terminating zero */
  	len = strnlen_user(uname, MFD_NAME_MAX_LEN + 1);
  	if (len <= 0)
  		return -EFAULT;
  	if (len > MFD_NAME_MAX_LEN + 1)
  		return -EINVAL;
  
  	name = kmalloc(len + MFD_NAME_PREFIX_LEN, GFP_TEMPORARY);
  	if (!name)
  		return -ENOMEM;
  
  	strcpy(name, MFD_NAME_PREFIX);
  	if (copy_from_user(&name[MFD_NAME_PREFIX_LEN], uname, len)) {
  		error = -EFAULT;
  		goto err_name;
  	}
  
  	/* terminating-zero may have changed after strnlen_user() returned */
  	if (name[len + MFD_NAME_PREFIX_LEN - 1]) {
  		error = -EFAULT;
  		goto err_name;
  	}
  
  	fd = get_unused_fd_flags((flags & MFD_CLOEXEC) ? O_CLOEXEC : 0);
  	if (fd < 0) {
  		error = fd;
  		goto err_name;
  	}
  
  	file = shmem_file_setup(name, 0, VM_NORESERVE);
  	if (IS_ERR(file)) {
  		error = PTR_ERR(file);
  		goto err_fd;
  	}
  	info = SHMEM_I(file_inode(file));
  	file->f_mode |= FMODE_LSEEK | FMODE_PREAD | FMODE_PWRITE;
  	file->f_flags |= O_RDWR | O_LARGEFILE;
  	if (flags & MFD_ALLOW_SEALING)
  		info->seals &= ~F_SEAL_SEAL;
  
  	fd_install(fd, file);
  	kfree(name);
  	return fd;
  
  err_fd:
  	put_unused_fd(fd);
  err_name:
  	kfree(name);
  	return error;
  }
680d794ba   akpm@linux-foundation.org   mount options: fi...
2862
  #endif /* CONFIG_TMPFS */
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
2863
2864
2865
  
  static void shmem_put_super(struct super_block *sb)
  {
602586a83   Hugh Dickins   shmem: put_super ...
2866
2867
2868
  	struct shmem_sb_info *sbinfo = SHMEM_SB(sb);
  
  	percpu_counter_destroy(&sbinfo->used_blocks);
49cd0a5c2   Greg Thelen   tmpfs: fix mempol...
2869
  	mpol_put(sbinfo->mpol);
602586a83   Hugh Dickins   shmem: put_super ...
2870
  	kfree(sbinfo);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
2871
2872
  	sb->s_fs_info = NULL;
  }
2b2af54a5   Kay Sievers   Driver Core: devt...
2873
  int shmem_fill_super(struct super_block *sb, void *data, int silent)
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
2874
2875
  {
  	struct inode *inode;
0edd73b33   Hugh Dickins   [PATCH] shmem: re...
2876
  	struct shmem_sb_info *sbinfo;
680d794ba   akpm@linux-foundation.org   mount options: fi...
2877
2878
2879
  	int err = -ENOMEM;
  
  	/* Round up to L1_CACHE_BYTES to resist false sharing */
425fbf047   Pekka Enberg   shmem: initialize...
2880
  	sbinfo = kzalloc(max((int)sizeof(struct shmem_sb_info),
680d794ba   akpm@linux-foundation.org   mount options: fi...
2881
2882
2883
  				L1_CACHE_BYTES), GFP_KERNEL);
  	if (!sbinfo)
  		return -ENOMEM;
680d794ba   akpm@linux-foundation.org   mount options: fi...
2884
  	sbinfo->mode = S_IRWXUGO | S_ISVTX;
76aac0e9a   David Howells   CRED: Wrap task c...
2885
2886
  	sbinfo->uid = current_fsuid();
  	sbinfo->gid = current_fsgid();
680d794ba   akpm@linux-foundation.org   mount options: fi...
2887
  	sb->s_fs_info = sbinfo;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
2888

0edd73b33   Hugh Dickins   [PATCH] shmem: re...
2889
  #ifdef CONFIG_TMPFS
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
2890
2891
2892
2893
2894
  	/*
  	 * 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...
2895
  	if (!(sb->s_flags & MS_KERNMOUNT)) {
680d794ba   akpm@linux-foundation.org   mount options: fi...
2896
2897
2898
2899
2900
2901
  		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...
2902
2903
  	} else {
  		sb->s_flags |= MS_NOUSER;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
2904
  	}
91828a405   David M. Grimes   [PATCH] knfsd: ad...
2905
  	sb->s_export_op = &shmem_export_ops;
2f6e38f3c   Hugh Dickins   tmpfs: enable NOS...
2906
  	sb->s_flags |= MS_NOSEC;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
2907
2908
2909
  #else
  	sb->s_flags |= MS_NOUSER;
  #endif
0edd73b33   Hugh Dickins   [PATCH] shmem: re...
2910
  	spin_lock_init(&sbinfo->stat_lock);
908c7f194   Tejun Heo   percpu_counter: a...
2911
  	if (percpu_counter_init(&sbinfo->used_blocks, 0, GFP_KERNEL))
602586a83   Hugh Dickins   shmem: put_super ...
2912
  		goto failed;
680d794ba   akpm@linux-foundation.org   mount options: fi...
2913
  	sbinfo->free_inodes = sbinfo->max_inodes;
0edd73b33   Hugh Dickins   [PATCH] shmem: re...
2914

285b2c4fd   Hugh Dickins   tmpfs: demolish o...
2915
  	sb->s_maxbytes = MAX_LFS_FILESIZE;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
2916
2917
2918
2919
  	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...
2920
  	sb->s_time_gran = 1;
b09e0fa4b   Eric Paris   tmpfs: implement ...
2921
  #ifdef CONFIG_TMPFS_XATTR
39f0247d3   Andreas Gruenbacher   [PATCH] Access Co...
2922
  	sb->s_xattr = shmem_xattr_handlers;
b09e0fa4b   Eric Paris   tmpfs: implement ...
2923
2924
  #endif
  #ifdef CONFIG_TMPFS_POSIX_ACL
39f0247d3   Andreas Gruenbacher   [PATCH] Access Co...
2925
2926
  	sb->s_flags |= MS_POSIXACL;
  #endif
0edd73b33   Hugh Dickins   [PATCH] shmem: re...
2927

454abafe9   Dmitry Monakhov   ramfs: replace in...
2928
  	inode = shmem_get_inode(sb, NULL, S_IFDIR | sbinfo->mode, 0, VM_NORESERVE);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
2929
2930
  	if (!inode)
  		goto failed;
680d794ba   akpm@linux-foundation.org   mount options: fi...
2931
2932
  	inode->i_uid = sbinfo->uid;
  	inode->i_gid = sbinfo->gid;
318ceed08   Al Viro   tidy up after d_m...
2933
2934
  	sb->s_root = d_make_root(inode);
  	if (!sb->s_root)
48fde701a   Al Viro   switch open-coded...
2935
  		goto failed;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
2936
  	return 0;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
2937
2938
2939
2940
  failed:
  	shmem_put_super(sb);
  	return err;
  }
fcc234f88   Pekka Enberg   [PATCH] mm: kill ...
2941
  static struct kmem_cache *shmem_inode_cachep;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
2942
2943
2944
  
  static struct inode *shmem_alloc_inode(struct super_block *sb)
  {
41ffe5d5c   Hugh Dickins   tmpfs: miscellane...
2945
2946
2947
  	struct shmem_inode_info *info;
  	info = kmem_cache_alloc(shmem_inode_cachep, GFP_KERNEL);
  	if (!info)
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
2948
  		return NULL;
41ffe5d5c   Hugh Dickins   tmpfs: miscellane...
2949
  	return &info->vfs_inode;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
2950
  }
41ffe5d5c   Hugh Dickins   tmpfs: miscellane...
2951
  static void shmem_destroy_callback(struct rcu_head *head)
fa0d7e3de   Nick Piggin   fs: icache RCU fr...
2952
2953
  {
  	struct inode *inode = container_of(head, struct inode, i_rcu);
fa0d7e3de   Nick Piggin   fs: icache RCU fr...
2954
2955
  	kmem_cache_free(shmem_inode_cachep, SHMEM_I(inode));
  }
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
2956
2957
  static void shmem_destroy_inode(struct inode *inode)
  {
09208d150   Al Viro   shmem, ramfs: pro...
2958
  	if (S_ISREG(inode->i_mode))
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
2959
  		mpol_free_shared_policy(&SHMEM_I(inode)->policy);
41ffe5d5c   Hugh Dickins   tmpfs: miscellane...
2960
  	call_rcu(&inode->i_rcu, shmem_destroy_callback);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
2961
  }
41ffe5d5c   Hugh Dickins   tmpfs: miscellane...
2962
  static void shmem_init_inode(void *foo)
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
2963
  {
41ffe5d5c   Hugh Dickins   tmpfs: miscellane...
2964
2965
  	struct shmem_inode_info *info = foo;
  	inode_init_once(&info->vfs_inode);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
2966
  }
41ffe5d5c   Hugh Dickins   tmpfs: miscellane...
2967
  static int shmem_init_inodecache(void)
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
2968
2969
2970
  {
  	shmem_inode_cachep = kmem_cache_create("shmem_inode_cache",
  				sizeof(struct shmem_inode_info),
41ffe5d5c   Hugh Dickins   tmpfs: miscellane...
2971
  				0, SLAB_PANIC, shmem_init_inode);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
2972
2973
  	return 0;
  }
41ffe5d5c   Hugh Dickins   tmpfs: miscellane...
2974
  static void shmem_destroy_inodecache(void)
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
2975
  {
1a1d92c10   Alexey Dobriyan   [PATCH] Really ig...
2976
  	kmem_cache_destroy(shmem_inode_cachep);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
2977
  }
f5e54d6e5   Christoph Hellwig   [PATCH] mark addr...
2978
  static const struct address_space_operations shmem_aops = {
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
2979
  	.writepage	= shmem_writepage,
767193253   Ken Chen   [PATCH] simplify ...
2980
  	.set_page_dirty	= __set_page_dirty_no_writeback,
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
2981
  #ifdef CONFIG_TMPFS
800d15a53   Nick Piggin   implement simple ...
2982
2983
  	.write_begin	= shmem_write_begin,
  	.write_end	= shmem_write_end,
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
2984
  #endif
1c93923cc   Andrew Morton   include/linux/mig...
2985
  #ifdef CONFIG_MIGRATION
304dbdb7a   Lee Schermerhorn   [PATCH] add migra...
2986
  	.migratepage	= migrate_page,
1c93923cc   Andrew Morton   include/linux/mig...
2987
  #endif
aa261f549   Andi Kleen   HWPOISON: Enable ...
2988
  	.error_remove_page = generic_error_remove_page,
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
2989
  };
15ad7cdcf   Helge Deller   [PATCH] struct se...
2990
  static const struct file_operations shmem_file_operations = {
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
2991
2992
  	.mmap		= shmem_mmap,
  #ifdef CONFIG_TMPFS
220f2ac91   Hugh Dickins   tmpfs: support SE...
2993
  	.llseek		= shmem_file_llseek,
2ba5bbed0   Al Viro   shmem: switch to ...
2994
  	.read		= new_sync_read,
8174202b3   Al Viro   write_iter varian...
2995
  	.write		= new_sync_write,
2ba5bbed0   Al Viro   shmem: switch to ...
2996
  	.read_iter	= shmem_file_read_iter,
8174202b3   Al Viro   write_iter varian...
2997
  	.write_iter	= generic_file_write_iter,
1b061d924   Christoph Hellwig   rename the generi...
2998
  	.fsync		= noop_fsync,
708e3508c   Hugh Dickins   tmpfs: clone shme...
2999
  	.splice_read	= shmem_file_splice_read,
f6cb85d00   Al Viro   shmem: switch to ...
3000
  	.splice_write	= iter_file_splice_write,
83e4fa9c1   Hugh Dickins   tmpfs: support fa...
3001
  	.fallocate	= shmem_fallocate,
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
3002
3003
  #endif
  };
92e1d5be9   Arjan van de Ven   [PATCH] mark stru...
3004
  static const struct inode_operations shmem_inode_operations = {
94c1e62df   Hugh Dickins   tmpfs: take contr...
3005
  	.setattr	= shmem_setattr,
b09e0fa4b   Eric Paris   tmpfs: implement ...
3006
3007
3008
3009
3010
  #ifdef CONFIG_TMPFS_XATTR
  	.setxattr	= shmem_setxattr,
  	.getxattr	= shmem_getxattr,
  	.listxattr	= shmem_listxattr,
  	.removexattr	= shmem_removexattr,
feda821e7   Christoph Hellwig   fs: remove generi...
3011
  	.set_acl	= simple_set_acl,
b09e0fa4b   Eric Paris   tmpfs: implement ...
3012
  #endif
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
3013
  };
92e1d5be9   Arjan van de Ven   [PATCH] mark stru...
3014
  static const struct inode_operations shmem_dir_inode_operations = {
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
3015
3016
3017
3018
3019
3020
3021
3022
3023
  #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,
3b69ff51d   Miklos Szeredi   shmem: support RE...
3024
  	.rename2	= shmem_rename2,
60545d0d4   Al Viro   [O_TMPFILE] it's ...
3025
  	.tmpfile	= shmem_tmpfile,
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
3026
  #endif
b09e0fa4b   Eric Paris   tmpfs: implement ...
3027
3028
3029
3030
3031
3032
  #ifdef CONFIG_TMPFS_XATTR
  	.setxattr	= shmem_setxattr,
  	.getxattr	= shmem_getxattr,
  	.listxattr	= shmem_listxattr,
  	.removexattr	= shmem_removexattr,
  #endif
39f0247d3   Andreas Gruenbacher   [PATCH] Access Co...
3033
  #ifdef CONFIG_TMPFS_POSIX_ACL
94c1e62df   Hugh Dickins   tmpfs: take contr...
3034
  	.setattr	= shmem_setattr,
feda821e7   Christoph Hellwig   fs: remove generi...
3035
  	.set_acl	= simple_set_acl,
39f0247d3   Andreas Gruenbacher   [PATCH] Access Co...
3036
3037
  #endif
  };
92e1d5be9   Arjan van de Ven   [PATCH] mark stru...
3038
  static const struct inode_operations shmem_special_inode_operations = {
b09e0fa4b   Eric Paris   tmpfs: implement ...
3039
3040
3041
3042
3043
3044
  #ifdef CONFIG_TMPFS_XATTR
  	.setxattr	= shmem_setxattr,
  	.getxattr	= shmem_getxattr,
  	.listxattr	= shmem_listxattr,
  	.removexattr	= shmem_removexattr,
  #endif
39f0247d3   Andreas Gruenbacher   [PATCH] Access Co...
3045
  #ifdef CONFIG_TMPFS_POSIX_ACL
94c1e62df   Hugh Dickins   tmpfs: take contr...
3046
  	.setattr	= shmem_setattr,
feda821e7   Christoph Hellwig   fs: remove generi...
3047
  	.set_acl	= simple_set_acl,
39f0247d3   Andreas Gruenbacher   [PATCH] Access Co...
3048
  #endif
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
3049
  };
759b9775c   Hugh Dickins   [PATCH] shmem and...
3050
  static const struct super_operations shmem_ops = {
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
3051
3052
3053
3054
3055
  	.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...
3056
  	.show_options	= shmem_show_options,
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
3057
  #endif
1f895f75d   Al Viro   switch shmem.c to...
3058
  	.evict_inode	= shmem_evict_inode,
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
3059
3060
3061
  	.drop_inode	= generic_delete_inode,
  	.put_super	= shmem_put_super,
  };
f0f37e2f7   Alexey Dobriyan   const: mark struc...
3062
  static const struct vm_operations_struct shmem_vm_ops = {
54cb8821d   Nick Piggin   mm: merge populat...
3063
  	.fault		= shmem_fault,
d7c175517   Ning Qu   mm: implement ->m...
3064
  	.map_pages	= filemap_map_pages,
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
3065
3066
3067
3068
  #ifdef CONFIG_NUMA
  	.set_policy     = shmem_set_policy,
  	.get_policy     = shmem_get_policy,
  #endif
0b173bc4d   Konstantin Khlebnikov   mm: kill vma flag...
3069
  	.remap_pages	= generic_file_remap_pages,
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
3070
  };
3c26ff6e4   Al Viro   convert get_sb_no...
3071
3072
  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
3073
  {
3c26ff6e4   Al Viro   convert get_sb_no...
3074
  	return mount_nodev(fs_type, flags, data, shmem_fill_super);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
3075
  }
41ffe5d5c   Hugh Dickins   tmpfs: miscellane...
3076
  static struct file_system_type shmem_fs_type = {
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
3077
3078
  	.owner		= THIS_MODULE,
  	.name		= "tmpfs",
3c26ff6e4   Al Viro   convert get_sb_no...
3079
  	.mount		= shmem_mount,
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
3080
  	.kill_sb	= kill_litter_super,
2b8576cb0   Eric W. Biederman   userns: Allow the...
3081
  	.fs_flags	= FS_USERNS_MOUNT,
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
3082
  };
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
3083

41ffe5d5c   Hugh Dickins   tmpfs: miscellane...
3084
  int __init shmem_init(void)
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
3085
3086
  {
  	int error;
16203a7a9   Rob Landley   initmpfs: make ro...
3087
3088
3089
  	/* If rootfs called this, don't re-init */
  	if (shmem_inode_cachep)
  		return 0;
e0bf68dde   Peter Zijlstra   mm: bdi init hooks
3090
3091
3092
  	error = bdi_init(&shmem_backing_dev_info);
  	if (error)
  		goto out4;
41ffe5d5c   Hugh Dickins   tmpfs: miscellane...
3093
  	error = shmem_init_inodecache();
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
3094
3095
  	if (error)
  		goto out3;
41ffe5d5c   Hugh Dickins   tmpfs: miscellane...
3096
  	error = register_filesystem(&shmem_fs_type);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
3097
3098
3099
3100
3101
  	if (error) {
  		printk(KERN_ERR "Could not register tmpfs
  ");
  		goto out2;
  	}
95dc112a5   Greg Kroah-Hartman   [PATCH] devfs: Re...
3102

ca4e05195   Al Viro   shm_mnt is as lon...
3103
  	shm_mnt = kern_mount(&shmem_fs_type);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
3104
3105
3106
3107
3108
3109
3110
3111
3112
  	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...
3113
  	unregister_filesystem(&shmem_fs_type);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
3114
  out2:
41ffe5d5c   Hugh Dickins   tmpfs: miscellane...
3115
  	shmem_destroy_inodecache();
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
3116
  out3:
e0bf68dde   Peter Zijlstra   mm: bdi init hooks
3117
3118
  	bdi_destroy(&shmem_backing_dev_info);
  out4:
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
3119
3120
3121
  	shm_mnt = ERR_PTR(error);
  	return error;
  }
853ac43ab   Matt Mackall   shmem: unify regu...
3122
3123
3124
3125
3126
3127
3128
3129
3130
3131
3132
  
  #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...
3133
  static struct file_system_type shmem_fs_type = {
853ac43ab   Matt Mackall   shmem: unify regu...
3134
  	.name		= "tmpfs",
3c26ff6e4   Al Viro   convert get_sb_no...
3135
  	.mount		= ramfs_mount,
853ac43ab   Matt Mackall   shmem: unify regu...
3136
  	.kill_sb	= kill_litter_super,
2b8576cb0   Eric W. Biederman   userns: Allow the...
3137
  	.fs_flags	= FS_USERNS_MOUNT,
853ac43ab   Matt Mackall   shmem: unify regu...
3138
  };
41ffe5d5c   Hugh Dickins   tmpfs: miscellane...
3139
  int __init shmem_init(void)
853ac43ab   Matt Mackall   shmem: unify regu...
3140
  {
41ffe5d5c   Hugh Dickins   tmpfs: miscellane...
3141
  	BUG_ON(register_filesystem(&shmem_fs_type) != 0);
853ac43ab   Matt Mackall   shmem: unify regu...
3142

41ffe5d5c   Hugh Dickins   tmpfs: miscellane...
3143
  	shm_mnt = kern_mount(&shmem_fs_type);
853ac43ab   Matt Mackall   shmem: unify regu...
3144
3145
3146
3147
  	BUG_ON(IS_ERR(shm_mnt));
  
  	return 0;
  }
41ffe5d5c   Hugh Dickins   tmpfs: miscellane...
3148
  int shmem_unuse(swp_entry_t swap, struct page *page)
853ac43ab   Matt Mackall   shmem: unify regu...
3149
3150
3151
  {
  	return 0;
  }
3f96b79ad   Hugh Dickins   tmpfs: depend on ...
3152
3153
3154
3155
  int shmem_lock(struct file *file, int lock, struct user_struct *user)
  {
  	return 0;
  }
245132643   Hugh Dickins   SHM_UNLOCK: fix U...
3156
3157
3158
  void shmem_unlock_mapping(struct address_space *mapping)
  {
  }
41ffe5d5c   Hugh Dickins   tmpfs: miscellane...
3159
  void shmem_truncate_range(struct inode *inode, loff_t lstart, loff_t lend)
94c1e62df   Hugh Dickins   tmpfs: take contr...
3160
  {
41ffe5d5c   Hugh Dickins   tmpfs: miscellane...
3161
  	truncate_inode_pages_range(inode->i_mapping, lstart, lend);
94c1e62df   Hugh Dickins   tmpfs: take contr...
3162
3163
  }
  EXPORT_SYMBOL_GPL(shmem_truncate_range);
0b0a0806b   Hugh Dickins   shmem: fix shared...
3164
3165
  #define shmem_vm_ops				generic_file_vm_ops
  #define shmem_file_operations			ramfs_file_operations
454abafe9   Dmitry Monakhov   ramfs: replace in...
3166
  #define shmem_get_inode(sb, dir, mode, dev, flags)	ramfs_get_inode(sb, dir, mode, dev)
0b0a0806b   Hugh Dickins   shmem: fix shared...
3167
3168
  #define shmem_acct_size(flags, size)		0
  #define shmem_unacct_size(flags, size)		do {} while (0)
853ac43ab   Matt Mackall   shmem: unify regu...
3169
3170
3171
3172
  
  #endif /* CONFIG_SHMEM */
  
  /* common code */
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
3173

3451538a1   Al Viro   shmem_setup_file(...
3174
  static struct dentry_operations anon_ops = {
118b23022   Al Viro   cope with potenti...
3175
  	.d_dname = simple_dname
3451538a1   Al Viro   shmem_setup_file(...
3176
  };
c72770909   Eric Paris   security: shmem: ...
3177
3178
  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
3179
  {
6b4d0b279   Al Viro   clean shmem_file_...
3180
  	struct file *res;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
3181
  	struct inode *inode;
2c48b9c45   Al Viro   switch alloc_file...
3182
  	struct path path;
3451538a1   Al Viro   shmem_setup_file(...
3183
  	struct super_block *sb;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
3184
3185
3186
  	struct qstr this;
  
  	if (IS_ERR(shm_mnt))
6b4d0b279   Al Viro   clean shmem_file_...
3187
  		return ERR_CAST(shm_mnt);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
3188

285b2c4fd   Hugh Dickins   tmpfs: demolish o...
3189
  	if (size < 0 || size > MAX_LFS_FILESIZE)
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
3190
3191
3192
3193
  		return ERR_PTR(-EINVAL);
  
  	if (shmem_acct_size(flags, size))
  		return ERR_PTR(-ENOMEM);
6b4d0b279   Al Viro   clean shmem_file_...
3194
  	res = ERR_PTR(-ENOMEM);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
3195
3196
3197
  	this.name = name;
  	this.len = strlen(name);
  	this.hash = 0; /* will go */
3451538a1   Al Viro   shmem_setup_file(...
3198
  	sb = shm_mnt->mnt_sb;
66ee4b888   Konstantin Khlebnikov   shmem: fix double...
3199
  	path.mnt = mntget(shm_mnt);
3451538a1   Al Viro   shmem_setup_file(...
3200
  	path.dentry = d_alloc_pseudo(sb, &this);
2c48b9c45   Al Viro   switch alloc_file...
3201
  	if (!path.dentry)
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
3202
  		goto put_memory;
3451538a1   Al Viro   shmem_setup_file(...
3203
  	d_set_d_op(path.dentry, &anon_ops);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
3204

6b4d0b279   Al Viro   clean shmem_file_...
3205
  	res = ERR_PTR(-ENOSPC);
3451538a1   Al Viro   shmem_setup_file(...
3206
  	inode = shmem_get_inode(sb, NULL, S_IFREG | S_IRWXUGO, 0, flags);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
3207
  	if (!inode)
66ee4b888   Konstantin Khlebnikov   shmem: fix double...
3208
  		goto put_memory;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
3209

c72770909   Eric Paris   security: shmem: ...
3210
  	inode->i_flags |= i_flags;
2c48b9c45   Al Viro   switch alloc_file...
3211
  	d_instantiate(path.dentry, inode);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
3212
  	inode->i_size = size;
6d6b77f16   Miklos Szeredi   filesystems: add ...
3213
  	clear_nlink(inode);	/* It is unlinked */
26567cdbb   Al Viro   fix nommu breakag...
3214
3215
  	res = ERR_PTR(ramfs_nommu_expand_for_mapping(inode, size));
  	if (IS_ERR(res))
66ee4b888   Konstantin Khlebnikov   shmem: fix double...
3216
  		goto put_path;
4b42af81f   Al Viro   switch shmem_file...
3217

6b4d0b279   Al Viro   clean shmem_file_...
3218
  	res = alloc_file(&path, FMODE_WRITE | FMODE_READ,
4b42af81f   Al Viro   switch shmem_file...
3219
  		  &shmem_file_operations);
6b4d0b279   Al Viro   clean shmem_file_...
3220
  	if (IS_ERR(res))
66ee4b888   Konstantin Khlebnikov   shmem: fix double...
3221
  		goto put_path;
4b42af81f   Al Viro   switch shmem_file...
3222

6b4d0b279   Al Viro   clean shmem_file_...
3223
  	return res;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
3224

1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
3225
3226
  put_memory:
  	shmem_unacct_size(flags, size);
66ee4b888   Konstantin Khlebnikov   shmem: fix double...
3227
3228
  put_path:
  	path_put(&path);
6b4d0b279   Al Viro   clean shmem_file_...
3229
  	return res;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
3230
  }
c72770909   Eric Paris   security: shmem: ...
3231
3232
3233
3234
3235
3236
3237
3238
3239
3240
3241
3242
3243
3244
3245
3246
3247
3248
3249
3250
3251
3252
3253
3254
3255
3256
  
  /**
   * 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...
3257
  EXPORT_SYMBOL_GPL(shmem_file_setup);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
3258

467118102   Randy Dunlap   mm/shmem and tiny...
3259
  /**
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
3260
   * shmem_zero_setup - setup a shared anonymous mapping
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
3261
3262
3263
3264
3265
3266
3267
3268
3269
3270
3271
3272
3273
3274
3275
3276
3277
   * @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_...
3278
3279
3280
3281
3282
3283
3284
3285
3286
3287
3288
3289
3290
  
  /**
   * 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...
3291
3292
   * 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_...
3293
3294
3295
3296
   */
  struct page *shmem_read_mapping_page_gfp(struct address_space *mapping,
  					 pgoff_t index, gfp_t gfp)
  {
68da9f055   Hugh Dickins   tmpfs: pass gfp t...
3297
3298
  #ifdef CONFIG_SHMEM
  	struct inode *inode = mapping->host;
9276aad6c   Hugh Dickins   tmpfs: remove_shm...
3299
  	struct page *page;
68da9f055   Hugh Dickins   tmpfs: pass gfp t...
3300
3301
3302
3303
3304
3305
3306
3307
3308
3309
3310
3311
3312
  	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_...
3313
  	return read_cache_page_gfp(mapping, index, gfp);
68da9f055   Hugh Dickins   tmpfs: pass gfp t...
3314
  #endif
d9d90e5eb   Hugh Dickins   tmpfs: add shmem_...
3315
3316
  }
  EXPORT_SYMBOL_GPL(shmem_read_mapping_page_gfp);