Blame view

fs/hugetlbfs/inode.c 24.1 KB
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
  /*
   * hugetlbpage-backed filesystem.  Based on ramfs.
   *
   * William Irwin, 2002
   *
   * Copyright (C) 2002 Linus Torvalds.
   */
  
  #include <linux/module.h>
  #include <linux/thread_info.h>
  #include <asm/current.h>
  #include <linux/sched.h>		/* remove ASAP */
  #include <linux/fs.h>
  #include <linux/mount.h>
  #include <linux/file.h>
e73a75fa7   Randy Dunlap   hugetlbfs: use li...
16
  #include <linux/kernel.h>
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
17
18
19
20
21
  #include <linux/writeback.h>
  #include <linux/pagemap.h>
  #include <linux/highmem.h>
  #include <linux/init.h>
  #include <linux/string.h>
16f7e0fe2   Randy Dunlap   [PATCH] capable/c...
22
  #include <linux/capability.h>
e73a75fa7   Randy Dunlap   hugetlbfs: use li...
23
  #include <linux/ctype.h>
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
24
25
26
  #include <linux/backing-dev.h>
  #include <linux/hugetlb.h>
  #include <linux/pagevec.h>
e73a75fa7   Randy Dunlap   hugetlbfs: use li...
27
  #include <linux/parser.h>
036e08568   Benjamin Herrenschmidt   get_unmapped_area...
28
  #include <linux/mman.h>
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
29
30
31
32
  #include <linux/slab.h>
  #include <linux/dnotify.h>
  #include <linux/statfs.h>
  #include <linux/security.h>
1fd7317d0   Nick Black   Move magic number...
33
  #include <linux/magic.h>
290408d4a   Naoya Horiguchi   hugetlb: hugepage...
34
  #include <linux/migrate.h>
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
35
36
  
  #include <asm/uaccess.h>
ee9b6d61a   Josef 'Jeff' Sipek   [PATCH] Mark stru...
37
  static const struct super_operations hugetlbfs_ops;
f5e54d6e5   Christoph Hellwig   [PATCH] mark addr...
38
  static const struct address_space_operations hugetlbfs_aops;
4b6f5d20b   Arjan van de Ven   [PATCH] Make most...
39
  const struct file_operations hugetlbfs_file_operations;
92e1d5be9   Arjan van de Ven   [PATCH] mark stru...
40
41
  static const struct inode_operations hugetlbfs_dir_inode_operations;
  static const struct inode_operations hugetlbfs_inode_operations;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
42
43
  
  static struct backing_dev_info hugetlbfs_backing_dev_info = {
d993831fa   Jens Axboe   writeback: add na...
44
  	.name		= "hugetlbfs",
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
45
  	.ra_pages	= 0,	/* No readahead */
e4ad08fe6   Miklos Szeredi   mm: bdi: add sepa...
46
  	.capabilities	= BDI_CAP_NO_ACCT_AND_WRITEBACK,
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
47
48
49
  };
  
  int sysctl_hugetlb_shm_group;
e73a75fa7   Randy Dunlap   hugetlbfs: use li...
50
51
52
  enum {
  	Opt_size, Opt_nr_inodes,
  	Opt_mode, Opt_uid, Opt_gid,
a137e1cc6   Andi Kleen   hugetlbfs: per mo...
53
  	Opt_pagesize,
e73a75fa7   Randy Dunlap   hugetlbfs: use li...
54
55
  	Opt_err,
  };
a447c0932   Steven Whitehouse   vfs: Use const fo...
56
  static const match_table_t tokens = {
e73a75fa7   Randy Dunlap   hugetlbfs: use li...
57
58
59
60
61
  	{Opt_size,	"size=%s"},
  	{Opt_nr_inodes,	"nr_inodes=%s"},
  	{Opt_mode,	"mode=%o"},
  	{Opt_uid,	"uid=%u"},
  	{Opt_gid,	"gid=%u"},
a137e1cc6   Andi Kleen   hugetlbfs: per mo...
62
  	{Opt_pagesize,	"pagesize=%s"},
e73a75fa7   Randy Dunlap   hugetlbfs: use li...
63
64
  	{Opt_err,	NULL},
  };
2e9b367c2   Adam Litke   [PATCH] hugetlb: ...
65
66
67
68
69
70
71
72
73
  static void huge_pagevec_release(struct pagevec *pvec)
  {
  	int i;
  
  	for (i = 0; i < pagevec_count(pvec); ++i)
  		put_page(pvec->pages[i]);
  
  	pagevec_reinit(pvec);
  }
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
74
75
  static int hugetlbfs_file_mmap(struct file *file, struct vm_area_struct *vma)
  {
b39424e27   Josef Sipek   [PATCH] struct pa...
76
  	struct inode *inode = file->f_path.dentry->d_inode;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
77
78
  	loff_t len, vma_len;
  	int ret;
a55164389   Andi Kleen   hugetlb: modular ...
79
  	struct hstate *h = hstate_file(file);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
80

68589bc35   Hugh Dickins   [PATCH] hugetlb: ...
81
  	/*
dec4ad86c   David Gibson   hugepage: fix bro...
82
83
84
85
86
87
  	 * vma address alignment (but not the pgoff alignment) has
  	 * already been checked by prepare_hugepage_range.  If you add
  	 * any error returns here, do so after setting VM_HUGETLB, so
  	 * is_vm_hugetlb_page tests below unmap_region go the right
  	 * way when do_mmap_pgoff unwinds (may be important on powerpc
  	 * and ia64).
68589bc35   Hugh Dickins   [PATCH] hugetlb: ...
88
89
90
  	 */
  	vma->vm_flags |= VM_HUGETLB | VM_RESERVED;
  	vma->vm_ops = &hugetlb_vm_ops;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
91

2b37c35e6   Becky Bruce   fs/hugetlbfs/inod...
92
  	if (vma->vm_pgoff & (~huge_page_mask(h) >> PAGE_SHIFT))
dec4ad86c   David Gibson   hugepage: fix bro...
93
  		return -EINVAL;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
94
  	vma_len = (loff_t)(vma->vm_end - vma->vm_start);
1b1dcc1b5   Jes Sorensen   [PATCH] mutex sub...
95
  	mutex_lock(&inode->i_mutex);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
96
  	file_accessed(file);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
97
98
99
  
  	ret = -ENOMEM;
  	len = vma_len + ((loff_t)vma->vm_pgoff << PAGE_SHIFT);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
100

a1e78772d   Mel Gorman   hugetlb: reserve ...
101
  	if (hugetlb_reserve_pages(inode,
a55164389   Andi Kleen   hugetlb: modular ...
102
  				vma->vm_pgoff >> huge_page_order(h),
5a6fe1259   Mel Gorman   Do not account fo...
103
104
  				len >> huge_page_shift(h), vma,
  				vma->vm_flags))
a43a8c39b   Kenneth W Chen   [PATCH] tightenin...
105
  		goto out;
b45b5bd65   David Gibson   [PATCH] hugepage:...
106

4c8872659   Adam Litke   [PATCH] hugetlb: ...
107
108
  	ret = 0;
  	hugetlb_prefault_arch_hook(vma->vm_mm);
b6174df5e   Zhang, Yanmin   [PATCH] mmap zero...
109
  	if (vma->vm_flags & VM_WRITE && inode->i_size < len)
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
110
111
  		inode->i_size = len;
  out:
1b1dcc1b5   Jes Sorensen   [PATCH] mutex sub...
112
  	mutex_unlock(&inode->i_mutex);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
113
114
115
116
117
  
  	return ret;
  }
  
  /*
508034a32   Hugh Dickins   [PATCH] mm: unmap...
118
   * Called under down_write(mmap_sem).
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
119
   */
d2ba27e80   Adrian Bunk   proper prototype ...
120
  #ifndef HAVE_ARCH_HUGETLB_UNMAPPED_AREA
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
121
122
123
124
125
126
127
  static unsigned long
  hugetlb_get_unmapped_area(struct file *file, unsigned long addr,
  		unsigned long len, unsigned long pgoff, unsigned long flags)
  {
  	struct mm_struct *mm = current->mm;
  	struct vm_area_struct *vma;
  	unsigned long start_addr;
a55164389   Andi Kleen   hugetlb: modular ...
128
  	struct hstate *h = hstate_file(file);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
129

a55164389   Andi Kleen   hugetlb: modular ...
130
  	if (len & ~huge_page_mask(h))
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
131
132
133
  		return -EINVAL;
  	if (len > TASK_SIZE)
  		return -ENOMEM;
036e08568   Benjamin Herrenschmidt   get_unmapped_area...
134
  	if (flags & MAP_FIXED) {
a55164389   Andi Kleen   hugetlb: modular ...
135
  		if (prepare_hugepage_range(file, addr, len))
036e08568   Benjamin Herrenschmidt   get_unmapped_area...
136
137
138
  			return -EINVAL;
  		return addr;
  	}
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
139
  	if (addr) {
a55164389   Andi Kleen   hugetlb: modular ...
140
  		addr = ALIGN(addr, huge_page_size(h));
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
141
142
143
144
145
146
147
  		vma = find_vma(mm, addr);
  		if (TASK_SIZE - len >= addr &&
  		    (!vma || addr + len <= vma->vm_start))
  			return addr;
  	}
  
  	start_addr = mm->free_area_cache;
1363c3cd8   Wolfgang Wander   [PATCH] Avoiding ...
148
149
  	if (len <= mm->cached_hole_size)
  		start_addr = TASK_UNMAPPED_BASE;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
150
  full_search:
a55164389   Andi Kleen   hugetlb: modular ...
151
  	addr = ALIGN(start_addr, huge_page_size(h));
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
  
  	for (vma = find_vma(mm, addr); ; vma = vma->vm_next) {
  		/* At this point:  (!vma || addr < vma->vm_end). */
  		if (TASK_SIZE - len < addr) {
  			/*
  			 * Start a new search - just in case we missed
  			 * some holes.
  			 */
  			if (start_addr != TASK_UNMAPPED_BASE) {
  				start_addr = TASK_UNMAPPED_BASE;
  				goto full_search;
  			}
  			return -ENOMEM;
  		}
  
  		if (!vma || addr + len <= vma->vm_start)
  			return addr;
a55164389   Andi Kleen   hugetlb: modular ...
169
  		addr = ALIGN(vma->vm_end, huge_page_size(h));
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
170
171
172
  	}
  }
  #endif
e63e1e5a6   Badari Pulavarty   hugetlbfs read() ...
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
  static int
  hugetlbfs_read_actor(struct page *page, unsigned long offset,
  			char __user *buf, unsigned long count,
  			unsigned long size)
  {
  	char *kaddr;
  	unsigned long left, copied = 0;
  	int i, chunksize;
  
  	if (size > count)
  		size = count;
  
  	/* Find which 4k chunk and offset with in that chunk */
  	i = offset >> PAGE_CACHE_SHIFT;
  	offset = offset & ~PAGE_CACHE_MASK;
  
  	while (size) {
  		chunksize = PAGE_CACHE_SIZE;
  		if (offset)
  			chunksize -= offset;
  		if (chunksize > size)
  			chunksize = size;
  		kaddr = kmap(&page[i]);
  		left = __copy_to_user(buf, kaddr + offset, chunksize);
  		kunmap(&page[i]);
  		if (left) {
  			copied += (chunksize - left);
  			break;
  		}
  		offset = 0;
  		size -= chunksize;
  		buf += chunksize;
  		copied += chunksize;
  		i++;
  	}
  	return copied ? copied : -EFAULT;
  }
  
  /*
   * Support for read() - Find the page attached to f_mapping and copy out the
   * data. Its *very* similar to do_generic_mapping_read(), we can't use that
   * since it has PAGE_CACHE_SIZE assumptions.
   */
  static ssize_t hugetlbfs_read(struct file *filp, char __user *buf,
  			      size_t len, loff_t *ppos)
  {
a55164389   Andi Kleen   hugetlb: modular ...
219
  	struct hstate *h = hstate_file(filp);
e63e1e5a6   Badari Pulavarty   hugetlbfs read() ...
220
221
  	struct address_space *mapping = filp->f_mapping;
  	struct inode *inode = mapping->host;
a55164389   Andi Kleen   hugetlb: modular ...
222
223
  	unsigned long index = *ppos >> huge_page_shift(h);
  	unsigned long offset = *ppos & ~huge_page_mask(h);
e63e1e5a6   Badari Pulavarty   hugetlbfs read() ...
224
225
226
227
228
229
230
231
232
233
234
235
236
  	unsigned long end_index;
  	loff_t isize;
  	ssize_t retval = 0;
  
  	mutex_lock(&inode->i_mutex);
  
  	/* validate length */
  	if (len == 0)
  		goto out;
  
  	isize = i_size_read(inode);
  	if (!isize)
  		goto out;
a55164389   Andi Kleen   hugetlb: modular ...
237
  	end_index = (isize - 1) >> huge_page_shift(h);
e63e1e5a6   Badari Pulavarty   hugetlbfs read() ...
238
239
  	for (;;) {
  		struct page *page;
a55164389   Andi Kleen   hugetlb: modular ...
240
  		unsigned long nr, ret;
91bf189c3   Roel Kluin   hugetlb: unsigned...
241
  		int ra;
e63e1e5a6   Badari Pulavarty   hugetlbfs read() ...
242
243
  
  		/* nr is the maximum number of bytes to copy from this page */
a55164389   Andi Kleen   hugetlb: modular ...
244
  		nr = huge_page_size(h);
e63e1e5a6   Badari Pulavarty   hugetlbfs read() ...
245
246
247
  		if (index >= end_index) {
  			if (index > end_index)
  				goto out;
a55164389   Andi Kleen   hugetlb: modular ...
248
  			nr = ((isize - 1) & ~huge_page_mask(h)) + 1;
e63e1e5a6   Badari Pulavarty   hugetlbfs read() ...
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
  			if (nr <= offset) {
  				goto out;
  			}
  		}
  		nr = nr - offset;
  
  		/* Find the page */
  		page = find_get_page(mapping, index);
  		if (unlikely(page == NULL)) {
  			/*
  			 * We have a HOLE, zero out the user-buffer for the
  			 * length of the hole or request.
  			 */
  			ret = len < nr ? len : nr;
  			if (clear_user(buf, ret))
91bf189c3   Roel Kluin   hugetlb: unsigned...
264
265
266
  				ra = -EFAULT;
  			else
  				ra = 0;
e63e1e5a6   Badari Pulavarty   hugetlbfs read() ...
267
268
269
270
  		} else {
  			/*
  			 * We have the page, copy it to user space buffer.
  			 */
91bf189c3   Roel Kluin   hugetlb: unsigned...
271
272
  			ra = hugetlbfs_read_actor(page, offset, buf, len, nr);
  			ret = ra;
e63e1e5a6   Badari Pulavarty   hugetlbfs read() ...
273
  		}
91bf189c3   Roel Kluin   hugetlb: unsigned...
274
  		if (ra < 0) {
e63e1e5a6   Badari Pulavarty   hugetlbfs read() ...
275
  			if (retval == 0)
91bf189c3   Roel Kluin   hugetlb: unsigned...
276
  				retval = ra;
e63e1e5a6   Badari Pulavarty   hugetlbfs read() ...
277
278
279
280
281
282
283
284
  			if (page)
  				page_cache_release(page);
  			goto out;
  		}
  
  		offset += ret;
  		retval += ret;
  		len -= ret;
a55164389   Andi Kleen   hugetlb: modular ...
285
286
  		index += offset >> huge_page_shift(h);
  		offset &= ~huge_page_mask(h);
e63e1e5a6   Badari Pulavarty   hugetlbfs read() ...
287
288
289
290
291
292
293
294
295
  
  		if (page)
  			page_cache_release(page);
  
  		/* short read or no more work */
  		if ((ret != nr) || (len == 0))
  			break;
  	}
  out:
a55164389   Andi Kleen   hugetlb: modular ...
296
  	*ppos = ((loff_t)index << huge_page_shift(h)) + offset;
e63e1e5a6   Badari Pulavarty   hugetlbfs read() ...
297
298
299
  	mutex_unlock(&inode->i_mutex);
  	return retval;
  }
800d15a53   Nick Piggin   implement simple ...
300
301
302
303
  static int hugetlbfs_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
304
305
306
  {
  	return -EINVAL;
  }
800d15a53   Nick Piggin   implement simple ...
307
308
309
  static int hugetlbfs_write_end(struct file *file, struct address_space *mapping,
  			loff_t pos, unsigned len, unsigned copied,
  			struct page *page, void *fsdata)
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
310
  {
800d15a53   Nick Piggin   implement simple ...
311
  	BUG();
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
312
313
  	return -EINVAL;
  }
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
314
315
  static void truncate_huge_page(struct page *page)
  {
fba2591bf   Linus Torvalds   VM: Remove "clear...
316
  	cancel_dirty_page(page, /* No IO accounting for huge pages? */0);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
317
  	ClearPageUptodate(page);
bd65cb86c   Minchan Kim   mm: hugetlbfs: ch...
318
  	delete_from_page_cache(page);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
319
  }
b45b5bd65   David Gibson   [PATCH] hugepage:...
320
  static void truncate_hugepages(struct inode *inode, loff_t lstart)
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
321
  {
a55164389   Andi Kleen   hugetlb: modular ...
322
  	struct hstate *h = hstate_inode(inode);
b45b5bd65   David Gibson   [PATCH] hugepage:...
323
  	struct address_space *mapping = &inode->i_data;
a55164389   Andi Kleen   hugetlb: modular ...
324
  	const pgoff_t start = lstart >> huge_page_shift(h);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
325
326
  	struct pagevec pvec;
  	pgoff_t next;
a43a8c39b   Kenneth W Chen   [PATCH] tightenin...
327
  	int i, freed = 0;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
328
329
330
331
332
333
334
335
336
337
338
339
340
341
342
343
344
345
346
347
  
  	pagevec_init(&pvec, 0);
  	next = start;
  	while (1) {
  		if (!pagevec_lookup(&pvec, mapping, next, PAGEVEC_SIZE)) {
  			if (next == start)
  				break;
  			next = start;
  			continue;
  		}
  
  		for (i = 0; i < pagevec_count(&pvec); ++i) {
  			struct page *page = pvec.pages[i];
  
  			lock_page(page);
  			if (page->index > next)
  				next = page->index;
  			++next;
  			truncate_huge_page(page);
  			unlock_page(page);
a43a8c39b   Kenneth W Chen   [PATCH] tightenin...
348
  			freed++;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
349
350
351
352
  		}
  		huge_pagevec_release(&pvec);
  	}
  	BUG_ON(!lstart && mapping->nrpages);
a43a8c39b   Kenneth W Chen   [PATCH] tightenin...
353
  	hugetlb_unreserve_pages(inode, start, freed);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
354
  }
2bbbda308   Al Viro   switch hugetlbfs ...
355
  static void hugetlbfs_evict_inode(struct inode *inode)
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
356
  {
b45b5bd65   David Gibson   [PATCH] hugepage:...
357
  	truncate_hugepages(inode, 0);
b0683aa63   Al Viro   new helper: end_w...
358
  	end_writeback(inode);
149f4211a   Christoph Hellwig   [PATCH] hugetlbfs...
359
  }
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
360
  static inline void
856fc2950   Hugh Dickins   [PATCH] hugetlb: ...
361
  hugetlb_vmtruncate_list(struct prio_tree_root *root, pgoff_t pgoff)
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
362
363
364
  {
  	struct vm_area_struct *vma;
  	struct prio_tree_iter iter;
856fc2950   Hugh Dickins   [PATCH] hugetlb: ...
365
  	vma_prio_tree_foreach(vma, &iter, root, pgoff, ULONG_MAX) {
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
366
  		unsigned long v_offset;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
367
  		/*
856fc2950   Hugh Dickins   [PATCH] hugetlb: ...
368
369
370
371
  		 * Can the expression below overflow on 32-bit arches?
  		 * No, because the prio_tree returns us only those vmas
  		 * which overlap the truncated area starting at pgoff,
  		 * and no vma on a 32-bit arch can span beyond the 4GB.
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
372
  		 */
856fc2950   Hugh Dickins   [PATCH] hugetlb: ...
373
374
375
  		if (vma->vm_pgoff < pgoff)
  			v_offset = (pgoff - vma->vm_pgoff) << PAGE_SHIFT;
  		else
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
376
  			v_offset = 0;
502717f4e   Kenneth W Chen   [PATCH] hugetlb: ...
377
  		__unmap_hugepage_range(vma,
04f2cbe35   Mel Gorman   hugetlb: guarante...
378
  				vma->vm_start + v_offset, vma->vm_end, NULL);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
379
380
  	}
  }
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
381
382
  static int hugetlb_vmtruncate(struct inode *inode, loff_t offset)
  {
856fc2950   Hugh Dickins   [PATCH] hugetlb: ...
383
  	pgoff_t pgoff;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
384
  	struct address_space *mapping = inode->i_mapping;
a55164389   Andi Kleen   hugetlb: modular ...
385
  	struct hstate *h = hstate_inode(inode);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
386

a55164389   Andi Kleen   hugetlb: modular ...
387
  	BUG_ON(offset & ~huge_page_mask(h));
856fc2950   Hugh Dickins   [PATCH] hugetlb: ...
388
  	pgoff = offset >> PAGE_SHIFT;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
389

7aa91e104   Ken Chen   hugetlb: allow ex...
390
  	i_size_write(inode, offset);
3d48ae45e   Peter Zijlstra   mm: Convert i_mma...
391
  	mutex_lock(&mapping->i_mmap_mutex);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
392
393
  	if (!prio_tree_empty(&mapping->i_mmap))
  		hugetlb_vmtruncate_list(&mapping->i_mmap, pgoff);
3d48ae45e   Peter Zijlstra   mm: Convert i_mma...
394
  	mutex_unlock(&mapping->i_mmap_mutex);
b45b5bd65   David Gibson   [PATCH] hugepage:...
395
  	truncate_hugepages(inode, offset);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
396
397
398
399
400
401
  	return 0;
  }
  
  static int hugetlbfs_setattr(struct dentry *dentry, struct iattr *attr)
  {
  	struct inode *inode = dentry->d_inode;
a55164389   Andi Kleen   hugetlb: modular ...
402
  	struct hstate *h = hstate_inode(inode);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
403
404
405
406
407
408
409
  	int error;
  	unsigned int ia_valid = attr->ia_valid;
  
  	BUG_ON(!inode);
  
  	error = inode_change_ok(inode, attr);
  	if (error)
1025774ce   Christoph Hellwig   remove inode_setattr
410
  		return error;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
411
412
413
  
  	if (ia_valid & ATTR_SIZE) {
  		error = -EINVAL;
1025774ce   Christoph Hellwig   remove inode_setattr
414
415
416
  		if (attr->ia_size & ~huge_page_mask(h))
  			return -EINVAL;
  		error = hugetlb_vmtruncate(inode, attr->ia_size);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
417
  		if (error)
1025774ce   Christoph Hellwig   remove inode_setattr
418
  			return error;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
419
  	}
1025774ce   Christoph Hellwig   remove inode_setattr
420
421
422
423
  
  	setattr_copy(inode, attr);
  	mark_inode_dirty(inode);
  	return 0;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
424
425
426
427
428
429
  }
  
  static struct inode *hugetlbfs_get_inode(struct super_block *sb, uid_t uid, 
  					gid_t gid, int mode, dev_t dev)
  {
  	struct inode *inode;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
430
431
432
433
  
  	inode = new_inode(sb);
  	if (inode) {
  		struct hugetlbfs_inode_info *info;
85fe4025c   Christoph Hellwig   fs: do not assign...
434
  		inode->i_ino = get_next_ino();
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
435
436
437
  		inode->i_mode = mode;
  		inode->i_uid = uid;
  		inode->i_gid = gid;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
438
439
440
  		inode->i_mapping->a_ops = &hugetlbfs_aops;
  		inode->i_mapping->backing_dev_info =&hugetlbfs_backing_dev_info;
  		inode->i_atime = inode->i_mtime = inode->i_ctime = CURRENT_TIME;
a43a8c39b   Kenneth W Chen   [PATCH] tightenin...
441
  		INIT_LIST_HEAD(&inode->i_mapping->private_list);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
442
  		info = HUGETLBFS_I(inode);
6bfde05bf   Eric B Munson   hugetlbfs: allow ...
443
444
445
446
447
448
449
  		/*
  		 * The policy is initialized here even if we are creating a
  		 * private inode because initialization simply creates an
  		 * an empty rb tree and calls spin_lock_init(), later when we
  		 * call mpol_free_shared_policy() it will just return because
  		 * the rb tree will still be empty.
  		 */
71fe804b6   Lee Schermerhorn   mempolicy: use st...
450
  		mpol_shared_policy_init(&info->policy, NULL);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
451
452
453
454
455
456
457
458
459
460
461
462
463
  		switch (mode & S_IFMT) {
  		default:
  			init_special_inode(inode, mode, dev);
  			break;
  		case S_IFREG:
  			inode->i_op = &hugetlbfs_inode_operations;
  			inode->i_fop = &hugetlbfs_file_operations;
  			break;
  		case S_IFDIR:
  			inode->i_op = &hugetlbfs_dir_inode_operations;
  			inode->i_fop = &simple_dir_operations;
  
  			/* directory inodes start off with i_nlink == 2 (for "." entry) */
d8c76e6f4   Dave Hansen   [PATCH] r/o bind ...
464
  			inc_nlink(inode);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
465
466
467
468
469
  			break;
  		case S_IFLNK:
  			inode->i_op = &page_symlink_inode_operations;
  			break;
  		}
e096d0c7e   Josh Boyer   lockdep: Add help...
470
  		lockdep_annotate_inode_mutex_key(inode);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
471
472
473
474
475
476
477
478
479
480
481
482
483
484
485
486
487
488
489
  	}
  	return inode;
  }
  
  /*
   * File creation. Allocate an inode, and we're done..
   */
  static int hugetlbfs_mknod(struct inode *dir,
  			struct dentry *dentry, int mode, dev_t dev)
  {
  	struct inode *inode;
  	int error = -ENOSPC;
  	gid_t gid;
  
  	if (dir->i_mode & S_ISGID) {
  		gid = dir->i_gid;
  		if (S_ISDIR(mode))
  			mode |= S_ISGID;
  	} else {
77c70de15   David Howells   CRED: Wrap task c...
490
  		gid = current_fsgid();
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
491
  	}
77c70de15   David Howells   CRED: Wrap task c...
492
  	inode = hugetlbfs_get_inode(dir->i_sb, current_fsuid(), gid, mode, dev);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
493
494
495
496
497
498
499
500
501
502
503
504
505
  	if (inode) {
  		dir->i_ctime = dir->i_mtime = CURRENT_TIME;
  		d_instantiate(dentry, inode);
  		dget(dentry);	/* Extra count - pin the dentry in core */
  		error = 0;
  	}
  	return error;
  }
  
  static int hugetlbfs_mkdir(struct inode *dir, struct dentry *dentry, int mode)
  {
  	int retval = hugetlbfs_mknod(dir, dentry, mode | S_IFDIR, 0);
  	if (!retval)
d8c76e6f4   Dave Hansen   [PATCH] r/o bind ...
506
  		inc_nlink(dir);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
507
508
509
510
511
512
513
514
515
516
517
518
519
520
521
522
523
524
  	return retval;
  }
  
  static int hugetlbfs_create(struct inode *dir, struct dentry *dentry, int mode, struct nameidata *nd)
  {
  	return hugetlbfs_mknod(dir, dentry, mode | S_IFREG, 0);
  }
  
  static int hugetlbfs_symlink(struct inode *dir,
  			struct dentry *dentry, const char *symname)
  {
  	struct inode *inode;
  	int error = -ENOSPC;
  	gid_t gid;
  
  	if (dir->i_mode & S_ISGID)
  		gid = dir->i_gid;
  	else
77c70de15   David Howells   CRED: Wrap task c...
525
  		gid = current_fsgid();
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
526

77c70de15   David Howells   CRED: Wrap task c...
527
  	inode = hugetlbfs_get_inode(dir->i_sb, current_fsuid(),
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
528
529
530
531
532
533
534
535
536
537
538
539
540
541
542
543
  					gid, S_IFLNK|S_IRWXUGO, 0);
  	if (inode) {
  		int l = strlen(symname)+1;
  		error = page_symlink(inode, symname, l);
  		if (!error) {
  			d_instantiate(dentry, inode);
  			dget(dentry);
  		} else
  			iput(inode);
  	}
  	dir->i_ctime = dir->i_mtime = CURRENT_TIME;
  
  	return error;
  }
  
  /*
6649a3863   Ken Chen   [PATCH] hugetlb: ...
544
   * mark the head page dirty
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
545
546
547
   */
  static int hugetlbfs_set_page_dirty(struct page *page)
  {
d85f33855   Christoph Lameter   Make page->privat...
548
  	struct page *head = compound_head(page);
6649a3863   Ken Chen   [PATCH] hugetlb: ...
549
550
  
  	SetPageDirty(head);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
551
552
  	return 0;
  }
290408d4a   Naoya Horiguchi   hugetlb: hugepage...
553
554
555
556
557
558
559
560
561
562
563
564
  static int hugetlbfs_migrate_page(struct address_space *mapping,
  				struct page *newpage, struct page *page)
  {
  	int rc;
  
  	rc = migrate_huge_page_move_mapping(mapping, newpage, page);
  	if (rc)
  		return rc;
  	migrate_page_copy(newpage, page);
  
  	return 0;
  }
726c33422   David Howells   [PATCH] VFS: Perm...
565
  static int hugetlbfs_statfs(struct dentry *dentry, struct kstatfs *buf)
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
566
  {
726c33422   David Howells   [PATCH] VFS: Perm...
567
  	struct hugetlbfs_sb_info *sbinfo = HUGETLBFS_SB(dentry->d_sb);
a55164389   Andi Kleen   hugetlb: modular ...
568
  	struct hstate *h = hstate_inode(dentry->d_inode);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
569
570
  
  	buf->f_type = HUGETLBFS_MAGIC;
a55164389   Andi Kleen   hugetlb: modular ...
571
  	buf->f_bsize = huge_page_size(h);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
572
573
  	if (sbinfo) {
  		spin_lock(&sbinfo->stat_lock);
74a8a65c5   David Gibson   [PATCH] Fix huget...
574
575
576
577
578
579
580
581
  		/* If no limits set, just report 0 for max/free/used
  		 * blocks, like simple_statfs() */
  		if (sbinfo->max_blocks >= 0) {
  			buf->f_blocks = sbinfo->max_blocks;
  			buf->f_bavail = buf->f_bfree = sbinfo->free_blocks;
  			buf->f_files = sbinfo->max_inodes;
  			buf->f_ffree = sbinfo->free_inodes;
  		}
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
582
583
584
585
586
587
588
589
590
591
592
593
594
595
596
  		spin_unlock(&sbinfo->stat_lock);
  	}
  	buf->f_namelen = NAME_MAX;
  	return 0;
  }
  
  static void hugetlbfs_put_super(struct super_block *sb)
  {
  	struct hugetlbfs_sb_info *sbi = HUGETLBFS_SB(sb);
  
  	if (sbi) {
  		sb->s_fs_info = NULL;
  		kfree(sbi);
  	}
  }
96527980d   Christoph Hellwig   [PATCH] hugetlbfs...
597
598
599
600
601
602
603
604
605
606
607
608
609
610
611
612
613
614
615
616
617
618
619
  static inline int hugetlbfs_dec_free_inodes(struct hugetlbfs_sb_info *sbinfo)
  {
  	if (sbinfo->free_inodes >= 0) {
  		spin_lock(&sbinfo->stat_lock);
  		if (unlikely(!sbinfo->free_inodes)) {
  			spin_unlock(&sbinfo->stat_lock);
  			return 0;
  		}
  		sbinfo->free_inodes--;
  		spin_unlock(&sbinfo->stat_lock);
  	}
  
  	return 1;
  }
  
  static void hugetlbfs_inc_free_inodes(struct hugetlbfs_sb_info *sbinfo)
  {
  	if (sbinfo->free_inodes >= 0) {
  		spin_lock(&sbinfo->stat_lock);
  		sbinfo->free_inodes++;
  		spin_unlock(&sbinfo->stat_lock);
  	}
  }
e18b890bb   Christoph Lameter   [PATCH] slab: rem...
620
  static struct kmem_cache *hugetlbfs_inode_cachep;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
621
622
623
  
  static struct inode *hugetlbfs_alloc_inode(struct super_block *sb)
  {
96527980d   Christoph Hellwig   [PATCH] hugetlbfs...
624
  	struct hugetlbfs_sb_info *sbinfo = HUGETLBFS_SB(sb);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
625
  	struct hugetlbfs_inode_info *p;
96527980d   Christoph Hellwig   [PATCH] hugetlbfs...
626
627
  	if (unlikely(!hugetlbfs_dec_free_inodes(sbinfo)))
  		return NULL;
e94b17660   Christoph Lameter   [PATCH] slab: rem...
628
  	p = kmem_cache_alloc(hugetlbfs_inode_cachep, GFP_KERNEL);
96527980d   Christoph Hellwig   [PATCH] hugetlbfs...
629
630
  	if (unlikely(!p)) {
  		hugetlbfs_inc_free_inodes(sbinfo);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
631
  		return NULL;
96527980d   Christoph Hellwig   [PATCH] hugetlbfs...
632
  	}
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
633
634
  	return &p->vfs_inode;
  }
fa0d7e3de   Nick Piggin   fs: icache RCU fr...
635
636
637
638
639
640
  static void hugetlbfs_i_callback(struct rcu_head *head)
  {
  	struct inode *inode = container_of(head, struct inode, i_rcu);
  	INIT_LIST_HEAD(&inode->i_dentry);
  	kmem_cache_free(hugetlbfs_inode_cachep, HUGETLBFS_I(inode));
  }
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
641
642
  static void hugetlbfs_destroy_inode(struct inode *inode)
  {
96527980d   Christoph Hellwig   [PATCH] hugetlbfs...
643
  	hugetlbfs_inc_free_inodes(HUGETLBFS_SB(inode->i_sb));
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
644
  	mpol_free_shared_policy(&HUGETLBFS_I(inode)->policy);
fa0d7e3de   Nick Piggin   fs: icache RCU fr...
645
  	call_rcu(&inode->i_rcu, hugetlbfs_i_callback);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
646
  }
f5e54d6e5   Christoph Hellwig   [PATCH] mark addr...
647
  static const struct address_space_operations hugetlbfs_aops = {
800d15a53   Nick Piggin   implement simple ...
648
649
  	.write_begin	= hugetlbfs_write_begin,
  	.write_end	= hugetlbfs_write_end,
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
650
  	.set_page_dirty	= hugetlbfs_set_page_dirty,
290408d4a   Naoya Horiguchi   hugetlb: hugepage...
651
  	.migratepage    = hugetlbfs_migrate_page,
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
652
  };
96527980d   Christoph Hellwig   [PATCH] hugetlbfs...
653

51cc50685   Alexey Dobriyan   SL*B: drop kmem c...
654
  static void init_once(void *foo)
96527980d   Christoph Hellwig   [PATCH] hugetlbfs...
655
656
  {
  	struct hugetlbfs_inode_info *ei = (struct hugetlbfs_inode_info *)foo;
a35afb830   Christoph Lameter   Remove SLAB_CTOR_...
657
  	inode_init_once(&ei->vfs_inode);
96527980d   Christoph Hellwig   [PATCH] hugetlbfs...
658
  }
4b6f5d20b   Arjan van de Ven   [PATCH] Make most...
659
  const struct file_operations hugetlbfs_file_operations = {
e63e1e5a6   Badari Pulavarty   hugetlbfs read() ...
660
  	.read			= hugetlbfs_read,
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
661
  	.mmap			= hugetlbfs_file_mmap,
1b061d924   Christoph Hellwig   rename the generi...
662
  	.fsync			= noop_fsync,
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
663
  	.get_unmapped_area	= hugetlb_get_unmapped_area,
6038f373a   Arnd Bergmann   llseek: automatic...
664
  	.llseek		= default_llseek,
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
665
  };
92e1d5be9   Arjan van de Ven   [PATCH] mark stru...
666
  static const struct inode_operations hugetlbfs_dir_inode_operations = {
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
667
668
669
670
671
672
673
674
675
676
677
  	.create		= hugetlbfs_create,
  	.lookup		= simple_lookup,
  	.link		= simple_link,
  	.unlink		= simple_unlink,
  	.symlink	= hugetlbfs_symlink,
  	.mkdir		= hugetlbfs_mkdir,
  	.rmdir		= simple_rmdir,
  	.mknod		= hugetlbfs_mknod,
  	.rename		= simple_rename,
  	.setattr	= hugetlbfs_setattr,
  };
92e1d5be9   Arjan van de Ven   [PATCH] mark stru...
678
  static const struct inode_operations hugetlbfs_inode_operations = {
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
679
680
  	.setattr	= hugetlbfs_setattr,
  };
ee9b6d61a   Josef 'Jeff' Sipek   [PATCH] Mark stru...
681
  static const struct super_operations hugetlbfs_ops = {
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
682
683
  	.alloc_inode    = hugetlbfs_alloc_inode,
  	.destroy_inode  = hugetlbfs_destroy_inode,
2bbbda308   Al Viro   switch hugetlbfs ...
684
  	.evict_inode	= hugetlbfs_evict_inode,
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
685
  	.statfs		= hugetlbfs_statfs,
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
686
  	.put_super	= hugetlbfs_put_super,
10f19a86a   Miklos Szeredi   mount options: fi...
687
  	.show_options	= generic_show_options,
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
688
689
690
691
692
  };
  
  static int
  hugetlbfs_parse_options(char *options, struct hugetlbfs_config *pconfig)
  {
e73a75fa7   Randy Dunlap   hugetlbfs: use li...
693
694
695
  	char *p, *rest;
  	substring_t args[MAX_OPT_ARGS];
  	int option;
a137e1cc6   Andi Kleen   hugetlbfs: per mo...
696
697
  	unsigned long long size = 0;
  	enum { NO_SIZE, SIZE_STD, SIZE_PERCENT } setsize = NO_SIZE;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
698
699
700
  
  	if (!options)
  		return 0;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
701

e73a75fa7   Randy Dunlap   hugetlbfs: use li...
702
703
  	while ((p = strsep(&options, ",")) != NULL) {
  		int token;
b4c07bce7   Lee Schermerhorn   hugetlbfs: handle...
704
705
  		if (!*p)
  			continue;
e73a75fa7   Randy Dunlap   hugetlbfs: use li...
706
707
708
709
710
711
712
713
714
715
716
717
718
719
720
721
722
723
  
  		token = match_token(p, tokens, args);
  		switch (token) {
  		case Opt_uid:
  			if (match_int(&args[0], &option))
   				goto bad_val;
  			pconfig->uid = option;
  			break;
  
  		case Opt_gid:
  			if (match_int(&args[0], &option))
   				goto bad_val;
  			pconfig->gid = option;
  			break;
  
  		case Opt_mode:
  			if (match_octal(&args[0], &option))
   				goto bad_val;
75897d60a   Ken Chen   hugetlb: allow st...
724
  			pconfig->mode = option & 01777U;
e73a75fa7   Randy Dunlap   hugetlbfs: use li...
725
726
727
  			break;
  
  		case Opt_size: {
e73a75fa7   Randy Dunlap   hugetlbfs: use li...
728
729
730
731
  			/* memparse() will accept a K/M/G without a digit */
  			if (!isdigit(*args[0].from))
  				goto bad_val;
  			size = memparse(args[0].from, &rest);
a137e1cc6   Andi Kleen   hugetlbfs: per mo...
732
733
734
  			setsize = SIZE_STD;
  			if (*rest == '%')
  				setsize = SIZE_PERCENT;
e73a75fa7   Randy Dunlap   hugetlbfs: use li...
735
736
  			break;
  		}
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
737

e73a75fa7   Randy Dunlap   hugetlbfs: use li...
738
739
740
741
742
743
  		case Opt_nr_inodes:
  			/* memparse() will accept a K/M/G without a digit */
  			if (!isdigit(*args[0].from))
  				goto bad_val;
  			pconfig->nr_inodes = memparse(args[0].from, &rest);
  			break;
a137e1cc6   Andi Kleen   hugetlbfs: per mo...
744
745
746
747
748
749
750
751
752
753
754
755
756
  		case Opt_pagesize: {
  			unsigned long ps;
  			ps = memparse(args[0].from, &rest);
  			pconfig->hstate = size_to_hstate(ps);
  			if (!pconfig->hstate) {
  				printk(KERN_ERR
  				"hugetlbfs: Unsupported page size %lu MB
  ",
  					ps >> 20);
  				return -EINVAL;
  			}
  			break;
  		}
e73a75fa7   Randy Dunlap   hugetlbfs: use li...
757
  		default:
b4c07bce7   Lee Schermerhorn   hugetlbfs: handle...
758
759
760
761
  			printk(KERN_ERR "hugetlbfs: Bad mount option: \"%s\"
  ",
  				 p);
  			return -EINVAL;
e73a75fa7   Randy Dunlap   hugetlbfs: use li...
762
763
  			break;
  		}
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
764
  	}
a137e1cc6   Andi Kleen   hugetlbfs: per mo...
765
766
767
768
769
770
771
772
773
774
775
  
  	/* Do size after hstate is set up */
  	if (setsize > NO_SIZE) {
  		struct hstate *h = pconfig->hstate;
  		if (setsize == SIZE_PERCENT) {
  			size <<= huge_page_shift(h);
  			size *= h->max_huge_pages;
  			do_div(size, 100);
  		}
  		pconfig->nr_blocks = (size >> huge_page_shift(h));
  	}
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
776
  	return 0;
e73a75fa7   Randy Dunlap   hugetlbfs: use li...
777
778
779
780
781
  
  bad_val:
   	printk(KERN_ERR "hugetlbfs: Bad value '%s' for mount option '%s'
  ",
  	       args[0].from, p);
c12ddba09   Akinobu Mita   hugetlbfs: return...
782
   	return -EINVAL;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
783
784
785
786
787
788
789
790
791
792
  }
  
  static int
  hugetlbfs_fill_super(struct super_block *sb, void *data, int silent)
  {
  	struct inode * inode;
  	struct dentry * root;
  	int ret;
  	struct hugetlbfs_config config;
  	struct hugetlbfs_sb_info *sbinfo;
10f19a86a   Miklos Szeredi   mount options: fi...
793
  	save_mount_options(sb, data);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
794
795
  	config.nr_blocks = -1; /* No limit on size by default */
  	config.nr_inodes = -1; /* No limit on number of inodes by default */
77c70de15   David Howells   CRED: Wrap task c...
796
797
  	config.uid = current_fsuid();
  	config.gid = current_fsgid();
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
798
  	config.mode = 0755;
a137e1cc6   Andi Kleen   hugetlbfs: per mo...
799
  	config.hstate = &default_hstate;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
800
  	ret = hugetlbfs_parse_options(data, &config);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
801
802
803
804
805
806
807
  	if (ret)
  		return ret;
  
  	sbinfo = kmalloc(sizeof(struct hugetlbfs_sb_info), GFP_KERNEL);
  	if (!sbinfo)
  		return -ENOMEM;
  	sb->s_fs_info = sbinfo;
a137e1cc6   Andi Kleen   hugetlbfs: per mo...
808
  	sbinfo->hstate = config.hstate;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
809
810
811
812
813
814
  	spin_lock_init(&sbinfo->stat_lock);
  	sbinfo->max_blocks = config.nr_blocks;
  	sbinfo->free_blocks = config.nr_blocks;
  	sbinfo->max_inodes = config.nr_inodes;
  	sbinfo->free_inodes = config.nr_inodes;
  	sb->s_maxbytes = MAX_LFS_FILESIZE;
a137e1cc6   Andi Kleen   hugetlbfs: per mo...
815
816
  	sb->s_blocksize = huge_page_size(config.hstate);
  	sb->s_blocksize_bits = huge_page_shift(config.hstate);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
817
818
819
820
821
822
823
824
825
826
827
828
829
830
831
832
833
834
835
  	sb->s_magic = HUGETLBFS_MAGIC;
  	sb->s_op = &hugetlbfs_ops;
  	sb->s_time_gran = 1;
  	inode = hugetlbfs_get_inode(sb, config.uid, config.gid,
  					S_IFDIR | config.mode, 0);
  	if (!inode)
  		goto out_free;
  
  	root = d_alloc_root(inode);
  	if (!root) {
  		iput(inode);
  		goto out_free;
  	}
  	sb->s_root = root;
  	return 0;
  out_free:
  	kfree(sbinfo);
  	return -ENOMEM;
  }
9a119c056   Adam Litke   hugetlb: allow bu...
836
  int hugetlb_get_quota(struct address_space *mapping, long delta)
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
837
838
839
840
841
842
  {
  	int ret = 0;
  	struct hugetlbfs_sb_info *sbinfo = HUGETLBFS_SB(mapping->host->i_sb);
  
  	if (sbinfo->free_blocks > -1) {
  		spin_lock(&sbinfo->stat_lock);
9a119c056   Adam Litke   hugetlb: allow bu...
843
844
  		if (sbinfo->free_blocks - delta >= 0)
  			sbinfo->free_blocks -= delta;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
845
846
847
848
849
850
851
  		else
  			ret = -ENOMEM;
  		spin_unlock(&sbinfo->stat_lock);
  	}
  
  	return ret;
  }
9a119c056   Adam Litke   hugetlb: allow bu...
852
  void hugetlb_put_quota(struct address_space *mapping, long delta)
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
853
854
855
856
857
  {
  	struct hugetlbfs_sb_info *sbinfo = HUGETLBFS_SB(mapping->host->i_sb);
  
  	if (sbinfo->free_blocks > -1) {
  		spin_lock(&sbinfo->stat_lock);
9a119c056   Adam Litke   hugetlb: allow bu...
858
  		sbinfo->free_blocks += delta;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
859
860
861
  		spin_unlock(&sbinfo->stat_lock);
  	}
  }
3c26ff6e4   Al Viro   convert get_sb_no...
862
863
  static struct dentry *hugetlbfs_mount(struct file_system_type *fs_type,
  	int flags, const char *dev_name, void *data)
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
864
  {
3c26ff6e4   Al Viro   convert get_sb_no...
865
  	return mount_nodev(fs_type, flags, data, hugetlbfs_fill_super);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
866
867
868
869
  }
  
  static struct file_system_type hugetlbfs_fs_type = {
  	.name		= "hugetlbfs",
3c26ff6e4   Al Viro   convert get_sb_no...
870
  	.mount		= hugetlbfs_mount,
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
871
872
873
874
  	.kill_sb	= kill_litter_super,
  };
  
  static struct vfsmount *hugetlbfs_vfsmount;
ef1ff6b8c   From: Mel Gorman   hugetlbfs: do not...
875
  static int can_do_hugetlb_shm(void)
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
876
  {
ef1ff6b8c   From: Mel Gorman   hugetlbfs: do not...
877
  	return capable(CAP_IPC_LOCK) || in_group_p(sysctl_hugetlb_shm_group);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
878
  }
ca16d140a   KOSAKI Motohiro   mm: don't access ...
879
880
  struct file *hugetlb_file_setup(const char *name, size_t size,
  				vm_flags_t acctflag,
6bfde05bf   Eric B Munson   hugetlbfs: allow ...
881
  				struct user_struct **user, int creat_flags)
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
882
883
884
885
  {
  	int error = -ENOMEM;
  	struct file *file;
  	struct inode *inode;
2c48b9c45   Al Viro   switch alloc_file...
886
887
  	struct path path;
  	struct dentry *root;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
888
  	struct qstr quick_string;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
889

353d5c30c   Hugh Dickins   mm: fix hugetlb b...
890
  	*user = NULL;
5bc98594d   Akinobu Mita   hugetlbfs: add NU...
891
892
  	if (!hugetlbfs_vfsmount)
  		return ERR_PTR(-ENOENT);
ef1ff6b8c   From: Mel Gorman   hugetlbfs: do not...
893
  	if (creat_flags == HUGETLB_SHMFS_INODE && !can_do_hugetlb_shm()) {
353d5c30c   Hugh Dickins   mm: fix hugetlb b...
894
895
  		*user = current_user();
  		if (user_shm_lock(size, *user)) {
52ca0e84b   Dave Jones   hugetlbfs: lessen...
896
897
  			printk_once(KERN_WARNING "Using mlock ulimits for SHM_HUGETLB is deprecated
  ");
353d5c30c   Hugh Dickins   mm: fix hugetlb b...
898
899
  		} else {
  			*user = NULL;
2584e5173   Ravikiran G Thirumalai   mm: reintroduce a...
900
  			return ERR_PTR(-EPERM);
353d5c30c   Hugh Dickins   mm: fix hugetlb b...
901
  		}
2584e5173   Ravikiran G Thirumalai   mm: reintroduce a...
902
  	}
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
903

1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
904
  	root = hugetlbfs_vfsmount->mnt_root;
9d66586f7   Eric W. Biederman   shm: fix the file...
905
  	quick_string.name = name;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
906
907
  	quick_string.len = strlen(quick_string.name);
  	quick_string.hash = 0;
2c48b9c45   Al Viro   switch alloc_file...
908
909
  	path.dentry = d_alloc(root, &quick_string);
  	if (!path.dentry)
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
910
  		goto out_shm_unlock;
2c48b9c45   Al Viro   switch alloc_file...
911
  	path.mnt = mntget(hugetlbfs_vfsmount);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
912
  	error = -ENOSPC;
77c70de15   David Howells   CRED: Wrap task c...
913
914
  	inode = hugetlbfs_get_inode(root->d_sb, current_fsuid(),
  				current_fsgid(), S_IFREG | S_IRWXUGO, 0);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
915
  	if (!inode)
ce8d2cdf3   Dave Hansen   r/o bind mounts: ...
916
  		goto out_dentry;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
917

b45b5bd65   David Gibson   [PATCH] hugepage:...
918
  	error = -ENOMEM;
a55164389   Andi Kleen   hugetlb: modular ...
919
  	if (hugetlb_reserve_pages(inode, 0,
5a6fe1259   Mel Gorman   Do not account fo...
920
921
  			size >> huge_page_shift(hstate_inode(inode)), NULL,
  			acctflag))
b45b5bd65   David Gibson   [PATCH] hugepage:...
922
  		goto out_inode;
2c48b9c45   Al Viro   switch alloc_file...
923
  	d_instantiate(path.dentry, inode);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
924
  	inode->i_size = size;
6d6b77f16   Miklos Szeredi   filesystems: add ...
925
  	clear_nlink(inode);
ce8d2cdf3   Dave Hansen   r/o bind mounts: ...
926
927
  
  	error = -ENFILE;
2c48b9c45   Al Viro   switch alloc_file...
928
  	file = alloc_file(&path, FMODE_WRITE | FMODE_READ,
ce8d2cdf3   Dave Hansen   r/o bind mounts: ...
929
930
  			&hugetlbfs_file_operations);
  	if (!file)
b4d232e65   Al Viro   [PATCH] double ip...
931
  		goto out_dentry; /* inode is already attached */
ce8d2cdf3   Dave Hansen   r/o bind mounts: ...
932

1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
933
  	return file;
b45b5bd65   David Gibson   [PATCH] hugepage:...
934
935
  out_inode:
  	iput(inode);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
936
  out_dentry:
2c48b9c45   Al Viro   switch alloc_file...
937
  	path_put(&path);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
938
  out_shm_unlock:
353d5c30c   Hugh Dickins   mm: fix hugetlb b...
939
940
941
942
  	if (*user) {
  		user_shm_unlock(size, *user);
  		*user = NULL;
  	}
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
943
944
945
946
947
948
949
  	return ERR_PTR(error);
  }
  
  static int __init init_hugetlbfs_fs(void)
  {
  	int error;
  	struct vfsmount *vfsmount;
e0bf68dde   Peter Zijlstra   mm: bdi init hooks
950
951
952
  	error = bdi_init(&hugetlbfs_backing_dev_info);
  	if (error)
  		return error;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
953
954
  	hugetlbfs_inode_cachep = kmem_cache_create("hugetlbfs_inode_cache",
  					sizeof(struct hugetlbfs_inode_info),
20c2df83d   Paul Mundt   mm: Remove slab d...
955
  					0, 0, init_once);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
956
  	if (hugetlbfs_inode_cachep == NULL)
e0bf68dde   Peter Zijlstra   mm: bdi init hooks
957
  		goto out2;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
958
959
960
961
962
963
964
965
966
967
968
969
970
971
972
973
974
  
  	error = register_filesystem(&hugetlbfs_fs_type);
  	if (error)
  		goto out;
  
  	vfsmount = kern_mount(&hugetlbfs_fs_type);
  
  	if (!IS_ERR(vfsmount)) {
  		hugetlbfs_vfsmount = vfsmount;
  		return 0;
  	}
  
  	error = PTR_ERR(vfsmount);
  
   out:
  	if (error)
  		kmem_cache_destroy(hugetlbfs_inode_cachep);
e0bf68dde   Peter Zijlstra   mm: bdi init hooks
975
976
   out2:
  	bdi_destroy(&hugetlbfs_backing_dev_info);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
977
978
979
980
981
982
  	return error;
  }
  
  static void __exit exit_hugetlbfs_fs(void)
  {
  	kmem_cache_destroy(hugetlbfs_inode_cachep);
423e0ab08   Tim Chen   VFS : mount lock ...
983
  	kern_unmount(hugetlbfs_vfsmount);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
984
  	unregister_filesystem(&hugetlbfs_fs_type);
e0bf68dde   Peter Zijlstra   mm: bdi init hooks
985
  	bdi_destroy(&hugetlbfs_backing_dev_info);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
986
987
988
989
990
991
  }
  
  module_init(init_hugetlbfs_fs)
  module_exit(exit_hugetlbfs_fs)
  
  MODULE_LICENSE("GPL");