diff options
Diffstat (limited to 'mm/shmem.c')
-rw-r--r-- | mm/shmem.c | 82 |
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 | ||
89 | static int shmem_getpage(struct inode *inode, unsigned long idx, | 89 | static 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: | |||
1291 | done: | 1295 | done: |
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 | ||
1308 | static struct page *shmem_nopage(struct vm_area_struct *vma, | 1312 | static 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 | ||
1332 | static 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 |
1379 | int shmem_set_policy(struct vm_area_struct *vma, struct mempolicy *new) | 1338 | int 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 | ||
2467 | static struct vm_operations_struct shmem_vm_ops = { | 2426 | static 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, |