aboutsummaryrefslogtreecommitdiffstats
path: root/mm/shmem.c
diff options
context:
space:
mode:
authorNick Piggin <npiggin@suse.de>2007-07-19 04:46:59 -0400
committerLinus Torvalds <torvalds@woody.linux-foundation.org>2007-07-19 13:04:41 -0400
commit54cb8821de07f2ffcd28c380ce9b93d5784b40d7 (patch)
tree1de676534963d96af42863b20191bc9f80060dea /mm/shmem.c
parentd00806b183152af6d24f46f0c33f14162ca1262a (diff)
mm: merge populate and nopage into fault (fixes nonlinear)
Nonlinear mappings are (AFAIKS) simply a virtual memory concept that encodes the virtual address -> file offset differently from linear mappings. ->populate is a layering violation because the filesystem/pagecache code should need to know anything about the virtual memory mapping. The hitch here is that the ->nopage handler didn't pass down enough information (ie. pgoff). But it is more logical to pass pgoff rather than have the ->nopage function calculate it itself anyway (because that's a similar layering violation). Having the populate handler install the pte itself is likewise a nasty thing to be doing. This patch introduces a new fault handler that replaces ->nopage and ->populate and (later) ->nopfn. Most of the old mechanism is still in place so there is a lot of duplication and nice cleanups that can be removed if everyone switches over. The rationale for doing this in the first place is that nonlinear mappings are subject to the pagefault vs invalidate/truncate race too, and it seemed stupid to duplicate the synchronisation logic rather than just consolidate the two. After this patch, MAP_NONBLOCK no longer sets up ptes for pages present in pagecache. Seems like a fringe functionality anyway. NOPAGE_REFAULT is removed. This should be implemented with ->fault, and no users have hit mainline yet. [akpm@linux-foundation.org: cleanup] [randy.dunlap@oracle.com: doc. fixes for readahead] [akpm@linux-foundation.org: build fix] Signed-off-by: Nick Piggin <npiggin@suse.de> Signed-off-by: Randy Dunlap <randy.dunlap@oracle.com> Cc: Mark Fasheh <mark.fasheh@oracle.com> Signed-off-by: Andrew Morton <akpm@linux-foundation.org> Signed-off-by: Linus Torvalds <torvalds@linux-foundation.org>
Diffstat (limited to 'mm/shmem.c')
-rw-r--r--mm/shmem.c82
1 files changed, 20 insertions, 62 deletions
diff --git a/mm/shmem.c b/mm/shmem.c
index 5808fadd3944..6b44440f1b24 100644
--- a/mm/shmem.c
+++ b/mm/shmem.c
@@ -83,7 +83,7 @@ enum sgp_type {
83 SGP_READ, /* don't exceed i_size, don't allocate page */ 83 SGP_READ, /* don't exceed i_size, don't allocate page */
84 SGP_CACHE, /* don't exceed i_size, may allocate page */ 84 SGP_CACHE, /* don't exceed i_size, may allocate page */
85 SGP_WRITE, /* may exceed i_size, may allocate page */ 85 SGP_WRITE, /* may exceed i_size, may allocate page */
86 SGP_NOPAGE, /* same as SGP_CACHE, return with page locked */ 86 SGP_FAULT, /* same as SGP_CACHE, return with page locked */
87}; 87};
88 88
89static int shmem_getpage(struct inode *inode, unsigned long idx, 89static int shmem_getpage(struct inode *inode, unsigned long idx,
@@ -1101,6 +1101,10 @@ static int shmem_getpage(struct inode *inode, unsigned long idx,
1101 1101
1102 if (idx >= SHMEM_MAX_INDEX) 1102 if (idx >= SHMEM_MAX_INDEX)
1103 return -EFBIG; 1103 return -EFBIG;
1104
1105 if (type)
1106 *type = VM_FAULT_MINOR;
1107
1104 /* 1108 /*
1105 * Normally, filepage is NULL on entry, and either found 1109 * Normally, filepage is NULL on entry, and either found
1106 * uptodate immediately, or allocated and zeroed, or read 1110 * uptodate immediately, or allocated and zeroed, or read
@@ -1291,7 +1295,7 @@ repeat:
1291done: 1295done:
1292 if (*pagep != filepage) { 1296 if (*pagep != filepage) {
1293 *pagep = filepage; 1297 *pagep = filepage;
1294 if (sgp != SGP_NOPAGE) 1298 if (sgp != SGP_FAULT)
1295 unlock_page(filepage); 1299 unlock_page(filepage);
1296 1300
1297 } 1301 }
@@ -1305,76 +1309,31 @@ failed:
1305 return error; 1309 return error;
1306} 1310}
1307 1311
1308static struct page *shmem_nopage(struct vm_area_struct *vma, 1312static struct page *shmem_fault(struct vm_area_struct *vma,
1309 unsigned long address, int *type) 1313 struct fault_data *fdata)
1310{ 1314{
1311 struct inode *inode = vma->vm_file->f_path.dentry->d_inode; 1315 struct inode *inode = vma->vm_file->f_path.dentry->d_inode;
1312 struct page *page = NULL; 1316 struct page *page = NULL;
1313 unsigned long idx;
1314 int error; 1317 int error;
1315 1318
1316 BUG_ON(!(vma->vm_flags & VM_CAN_INVALIDATE)); 1319 BUG_ON(!(vma->vm_flags & VM_CAN_INVALIDATE));
1317 1320
1318 idx = (address - vma->vm_start) >> PAGE_SHIFT; 1321 if (((loff_t)fdata->pgoff << PAGE_CACHE_SHIFT) >= i_size_read(inode)) {
1319 idx += vma->vm_pgoff; 1322 fdata->type = VM_FAULT_SIGBUS;
1320 idx >>= PAGE_CACHE_SHIFT - PAGE_SHIFT; 1323 return NULL;
1321 if (((loff_t) idx << PAGE_CACHE_SHIFT) >= i_size_read(inode)) 1324 }
1322 return NOPAGE_SIGBUS;
1323 1325
1324 error = shmem_getpage(inode, idx, &page, SGP_NOPAGE, type); 1326 error = shmem_getpage(inode, fdata->pgoff, &page,
1325 if (error) 1327 SGP_FAULT, &fdata->type);
1326 return (error == -ENOMEM)? NOPAGE_OOM: NOPAGE_SIGBUS; 1328 if (error) {
1329 fdata->type = ((error == -ENOMEM)?VM_FAULT_OOM:VM_FAULT_SIGBUS);
1330 return NULL;
1331 }
1327 1332
1328 mark_page_accessed(page); 1333 mark_page_accessed(page);
1329 return page; 1334 return page;
1330} 1335}
1331 1336
1332static int shmem_populate(struct vm_area_struct *vma,
1333 unsigned long addr, unsigned long len,
1334 pgprot_t prot, unsigned long pgoff, int nonblock)
1335{
1336 struct inode *inode = vma->vm_file->f_path.dentry->d_inode;
1337 struct mm_struct *mm = vma->vm_mm;
1338 enum sgp_type sgp = nonblock? SGP_QUICK: SGP_CACHE;
1339 unsigned long size;
1340
1341 size = (i_size_read(inode) + PAGE_SIZE - 1) >> PAGE_SHIFT;
1342 if (pgoff >= size || pgoff + (len >> PAGE_SHIFT) > size)
1343 return -EINVAL;
1344
1345 while ((long) len > 0) {
1346 struct page *page = NULL;
1347 int err;
1348 /*
1349 * Will need changing if PAGE_CACHE_SIZE != PAGE_SIZE
1350 */
1351 err = shmem_getpage(inode, pgoff, &page, sgp, NULL);
1352 if (err)
1353 return err;
1354 /* Page may still be null, but only if nonblock was set. */
1355 if (page) {
1356 mark_page_accessed(page);
1357 err = install_page(mm, vma, addr, page, prot);
1358 if (err) {
1359 page_cache_release(page);
1360 return err;
1361 }
1362 } else if (vma->vm_flags & VM_NONLINEAR) {
1363 /* No page was found just because we can't read it in
1364 * now (being here implies nonblock != 0), but the page
1365 * may exist, so set the PTE to fault it in later. */
1366 err = install_file_pte(mm, vma, addr, pgoff, prot);
1367 if (err)
1368 return err;
1369 }
1370
1371 len -= PAGE_SIZE;
1372 addr += PAGE_SIZE;
1373 pgoff++;
1374 }
1375 return 0;
1376}
1377
1378#ifdef CONFIG_NUMA 1337#ifdef CONFIG_NUMA
1379int shmem_set_policy(struct vm_area_struct *vma, struct mempolicy *new) 1338int shmem_set_policy(struct vm_area_struct *vma, struct mempolicy *new)
1380{ 1339{
@@ -1419,7 +1378,7 @@ static int shmem_mmap(struct file *file, struct vm_area_struct *vma)
1419{ 1378{
1420 file_accessed(file); 1379 file_accessed(file);
1421 vma->vm_ops = &shmem_vm_ops; 1380 vma->vm_ops = &shmem_vm_ops;
1422 vma->vm_flags |= VM_CAN_INVALIDATE; 1381 vma->vm_flags |= VM_CAN_INVALIDATE | VM_CAN_NONLINEAR;
1423 return 0; 1382 return 0;
1424} 1383}
1425 1384
@@ -2465,8 +2424,7 @@ static const struct super_operations shmem_ops = {
2465}; 2424};
2466 2425
2467static struct vm_operations_struct shmem_vm_ops = { 2426static struct vm_operations_struct shmem_vm_ops = {
2468 .nopage = shmem_nopage, 2427 .fault = shmem_fault,
2469 .populate = shmem_populate,
2470#ifdef CONFIG_NUMA 2428#ifdef CONFIG_NUMA
2471 .set_policy = shmem_set_policy, 2429 .set_policy = shmem_set_policy,
2472 .get_policy = shmem_get_policy, 2430 .get_policy = shmem_get_policy,