diff options
Diffstat (limited to 'mm/shmem.c')
-rw-r--r-- | mm/shmem.c | 11 |
1 files changed, 9 insertions, 2 deletions
diff --git a/mm/shmem.c b/mm/shmem.c index 96fa79fb6ad3..5808fadd3944 100644 --- a/mm/shmem.c +++ b/mm/shmem.c | |||
@@ -83,6 +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 | }; | 87 | }; |
87 | 88 | ||
88 | static int shmem_getpage(struct inode *inode, unsigned long idx, | 89 | static int shmem_getpage(struct inode *inode, unsigned long idx, |
@@ -1289,8 +1290,10 @@ repeat: | |||
1289 | } | 1290 | } |
1290 | done: | 1291 | done: |
1291 | if (*pagep != filepage) { | 1292 | if (*pagep != filepage) { |
1292 | unlock_page(filepage); | ||
1293 | *pagep = filepage; | 1293 | *pagep = filepage; |
1294 | if (sgp != SGP_NOPAGE) | ||
1295 | unlock_page(filepage); | ||
1296 | |||
1294 | } | 1297 | } |
1295 | return 0; | 1298 | return 0; |
1296 | 1299 | ||
@@ -1310,13 +1313,15 @@ static struct page *shmem_nopage(struct vm_area_struct *vma, | |||
1310 | unsigned long idx; | 1313 | unsigned long idx; |
1311 | int error; | 1314 | int error; |
1312 | 1315 | ||
1316 | BUG_ON(!(vma->vm_flags & VM_CAN_INVALIDATE)); | ||
1317 | |||
1313 | idx = (address - vma->vm_start) >> PAGE_SHIFT; | 1318 | idx = (address - vma->vm_start) >> PAGE_SHIFT; |
1314 | idx += vma->vm_pgoff; | 1319 | idx += vma->vm_pgoff; |
1315 | idx >>= PAGE_CACHE_SHIFT - PAGE_SHIFT; | 1320 | idx >>= PAGE_CACHE_SHIFT - PAGE_SHIFT; |
1316 | if (((loff_t) idx << PAGE_CACHE_SHIFT) >= i_size_read(inode)) | 1321 | if (((loff_t) idx << PAGE_CACHE_SHIFT) >= i_size_read(inode)) |
1317 | return NOPAGE_SIGBUS; | 1322 | return NOPAGE_SIGBUS; |
1318 | 1323 | ||
1319 | error = shmem_getpage(inode, idx, &page, SGP_CACHE, type); | 1324 | error = shmem_getpage(inode, idx, &page, SGP_NOPAGE, type); |
1320 | if (error) | 1325 | if (error) |
1321 | return (error == -ENOMEM)? NOPAGE_OOM: NOPAGE_SIGBUS; | 1326 | return (error == -ENOMEM)? NOPAGE_OOM: NOPAGE_SIGBUS; |
1322 | 1327 | ||
@@ -1414,6 +1419,7 @@ static int shmem_mmap(struct file *file, struct vm_area_struct *vma) | |||
1414 | { | 1419 | { |
1415 | file_accessed(file); | 1420 | file_accessed(file); |
1416 | vma->vm_ops = &shmem_vm_ops; | 1421 | vma->vm_ops = &shmem_vm_ops; |
1422 | vma->vm_flags |= VM_CAN_INVALIDATE; | ||
1417 | return 0; | 1423 | return 0; |
1418 | } | 1424 | } |
1419 | 1425 | ||
@@ -2596,5 +2602,6 @@ int shmem_zero_setup(struct vm_area_struct *vma) | |||
2596 | fput(vma->vm_file); | 2602 | fput(vma->vm_file); |
2597 | vma->vm_file = file; | 2603 | vma->vm_file = file; |
2598 | vma->vm_ops = &shmem_vm_ops; | 2604 | vma->vm_ops = &shmem_vm_ops; |
2605 | vma->vm_flags |= VM_CAN_INVALIDATE; | ||
2599 | return 0; | 2606 | return 0; |
2600 | } | 2607 | } |