diff options
Diffstat (limited to 'mm/shmem.c')
-rw-r--r-- | mm/shmem.c | 74 |
1 files changed, 65 insertions, 9 deletions
diff --git a/mm/shmem.c b/mm/shmem.c index f484c276e994..1140f49b6ded 100644 --- a/mm/shmem.c +++ b/mm/shmem.c | |||
@@ -80,11 +80,12 @@ static struct vfsmount *shm_mnt; | |||
80 | #define SHORT_SYMLINK_LEN 128 | 80 | #define SHORT_SYMLINK_LEN 128 |
81 | 81 | ||
82 | /* | 82 | /* |
83 | * shmem_fallocate and shmem_writepage communicate via inode->i_private | 83 | * shmem_fallocate communicates with shmem_fault or shmem_writepage via |
84 | * (with i_mutex making sure that it has only one user at a time): | 84 | * inode->i_private (with i_mutex making sure that it has only one user at |
85 | * we would prefer not to enlarge the shmem inode just for that. | 85 | * a time): we would prefer not to enlarge the shmem inode just for that. |
86 | */ | 86 | */ |
87 | struct shmem_falloc { | 87 | struct shmem_falloc { |
88 | int mode; /* FALLOC_FL mode currently operating */ | ||
88 | pgoff_t start; /* start of range currently being fallocated */ | 89 | pgoff_t start; /* start of range currently being fallocated */ |
89 | pgoff_t next; /* the next page offset to be fallocated */ | 90 | pgoff_t next; /* the next page offset to be fallocated */ |
90 | pgoff_t nr_falloced; /* how many new pages have been fallocated */ | 91 | pgoff_t nr_falloced; /* how many new pages have been fallocated */ |
@@ -759,6 +760,7 @@ static int shmem_writepage(struct page *page, struct writeback_control *wbc) | |||
759 | spin_lock(&inode->i_lock); | 760 | spin_lock(&inode->i_lock); |
760 | shmem_falloc = inode->i_private; | 761 | shmem_falloc = inode->i_private; |
761 | if (shmem_falloc && | 762 | if (shmem_falloc && |
763 | !shmem_falloc->mode && | ||
762 | index >= shmem_falloc->start && | 764 | index >= shmem_falloc->start && |
763 | index < shmem_falloc->next) | 765 | index < shmem_falloc->next) |
764 | shmem_falloc->nr_unswapped++; | 766 | shmem_falloc->nr_unswapped++; |
@@ -1027,6 +1029,9 @@ repeat: | |||
1027 | goto failed; | 1029 | goto failed; |
1028 | } | 1030 | } |
1029 | 1031 | ||
1032 | if (page && sgp == SGP_WRITE) | ||
1033 | mark_page_accessed(page); | ||
1034 | |||
1030 | /* fallocated page? */ | 1035 | /* fallocated page? */ |
1031 | if (page && !PageUptodate(page)) { | 1036 | if (page && !PageUptodate(page)) { |
1032 | if (sgp != SGP_READ) | 1037 | if (sgp != SGP_READ) |
@@ -1108,6 +1113,9 @@ repeat: | |||
1108 | shmem_recalc_inode(inode); | 1113 | shmem_recalc_inode(inode); |
1109 | spin_unlock(&info->lock); | 1114 | spin_unlock(&info->lock); |
1110 | 1115 | ||
1116 | if (sgp == SGP_WRITE) | ||
1117 | mark_page_accessed(page); | ||
1118 | |||
1111 | delete_from_swap_cache(page); | 1119 | delete_from_swap_cache(page); |
1112 | set_page_dirty(page); | 1120 | set_page_dirty(page); |
1113 | swap_free(swap); | 1121 | swap_free(swap); |
@@ -1134,6 +1142,9 @@ repeat: | |||
1134 | 1142 | ||
1135 | __SetPageSwapBacked(page); | 1143 | __SetPageSwapBacked(page); |
1136 | __set_page_locked(page); | 1144 | __set_page_locked(page); |
1145 | if (sgp == SGP_WRITE) | ||
1146 | init_page_accessed(page); | ||
1147 | |||
1137 | error = mem_cgroup_charge_file(page, current->mm, | 1148 | error = mem_cgroup_charge_file(page, current->mm, |
1138 | gfp & GFP_RECLAIM_MASK); | 1149 | gfp & GFP_RECLAIM_MASK); |
1139 | if (error) | 1150 | if (error) |
@@ -1233,6 +1244,44 @@ static int shmem_fault(struct vm_area_struct *vma, struct vm_fault *vmf) | |||
1233 | int error; | 1244 | int error; |
1234 | int ret = VM_FAULT_LOCKED; | 1245 | int ret = VM_FAULT_LOCKED; |
1235 | 1246 | ||
1247 | /* | ||
1248 | * Trinity finds that probing a hole which tmpfs is punching can | ||
1249 | * prevent the hole-punch from ever completing: which in turn | ||
1250 | * locks writers out with its hold on i_mutex. So refrain from | ||
1251 | * faulting pages into the hole while it's being punched, and | ||
1252 | * wait on i_mutex to be released if vmf->flags permits. | ||
1253 | */ | ||
1254 | if (unlikely(inode->i_private)) { | ||
1255 | struct shmem_falloc *shmem_falloc; | ||
1256 | |||
1257 | spin_lock(&inode->i_lock); | ||
1258 | shmem_falloc = inode->i_private; | ||
1259 | if (!shmem_falloc || | ||
1260 | shmem_falloc->mode != FALLOC_FL_PUNCH_HOLE || | ||
1261 | vmf->pgoff < shmem_falloc->start || | ||
1262 | vmf->pgoff >= shmem_falloc->next) | ||
1263 | shmem_falloc = NULL; | ||
1264 | spin_unlock(&inode->i_lock); | ||
1265 | /* | ||
1266 | * i_lock has protected us from taking shmem_falloc seriously | ||
1267 | * once return from shmem_fallocate() went back up that stack. | ||
1268 | * i_lock does not serialize with i_mutex at all, but it does | ||
1269 | * not matter if sometimes we wait unnecessarily, or sometimes | ||
1270 | * miss out on waiting: we just need to make those cases rare. | ||
1271 | */ | ||
1272 | if (shmem_falloc) { | ||
1273 | if ((vmf->flags & FAULT_FLAG_ALLOW_RETRY) && | ||
1274 | !(vmf->flags & FAULT_FLAG_RETRY_NOWAIT)) { | ||
1275 | up_read(&vma->vm_mm->mmap_sem); | ||
1276 | mutex_lock(&inode->i_mutex); | ||
1277 | mutex_unlock(&inode->i_mutex); | ||
1278 | return VM_FAULT_RETRY; | ||
1279 | } | ||
1280 | /* cond_resched? Leave that to GUP or return to user */ | ||
1281 | return VM_FAULT_NOPAGE; | ||
1282 | } | ||
1283 | } | ||
1284 | |||
1236 | error = shmem_getpage(inode, vmf->pgoff, &vmf->page, SGP_CACHE, &ret); | 1285 | error = shmem_getpage(inode, vmf->pgoff, &vmf->page, SGP_CACHE, &ret); |
1237 | if (error) | 1286 | if (error) |
1238 | return ((error == -ENOMEM) ? VM_FAULT_OOM : VM_FAULT_SIGBUS); | 1287 | return ((error == -ENOMEM) ? VM_FAULT_OOM : VM_FAULT_SIGBUS); |
@@ -1372,13 +1421,9 @@ shmem_write_begin(struct file *file, struct address_space *mapping, | |||
1372 | loff_t pos, unsigned len, unsigned flags, | 1421 | loff_t pos, unsigned len, unsigned flags, |
1373 | struct page **pagep, void **fsdata) | 1422 | struct page **pagep, void **fsdata) |
1374 | { | 1423 | { |
1375 | int ret; | ||
1376 | struct inode *inode = mapping->host; | 1424 | struct inode *inode = mapping->host; |
1377 | pgoff_t index = pos >> PAGE_CACHE_SHIFT; | 1425 | pgoff_t index = pos >> PAGE_CACHE_SHIFT; |
1378 | ret = shmem_getpage(inode, index, pagep, SGP_WRITE, NULL); | 1426 | return shmem_getpage(inode, index, pagep, SGP_WRITE, NULL); |
1379 | if (ret == 0 && *pagep) | ||
1380 | init_page_accessed(*pagep); | ||
1381 | return ret; | ||
1382 | } | 1427 | } |
1383 | 1428 | ||
1384 | static int | 1429 | static int |
@@ -1724,20 +1769,31 @@ static long shmem_fallocate(struct file *file, int mode, loff_t offset, | |||
1724 | pgoff_t start, index, end; | 1769 | pgoff_t start, index, end; |
1725 | int error; | 1770 | int error; |
1726 | 1771 | ||
1772 | if (mode & ~(FALLOC_FL_KEEP_SIZE | FALLOC_FL_PUNCH_HOLE)) | ||
1773 | return -EOPNOTSUPP; | ||
1774 | |||
1727 | mutex_lock(&inode->i_mutex); | 1775 | mutex_lock(&inode->i_mutex); |
1728 | 1776 | ||
1777 | shmem_falloc.mode = mode & ~FALLOC_FL_KEEP_SIZE; | ||
1778 | |||
1729 | if (mode & FALLOC_FL_PUNCH_HOLE) { | 1779 | if (mode & FALLOC_FL_PUNCH_HOLE) { |
1730 | struct address_space *mapping = file->f_mapping; | 1780 | struct address_space *mapping = file->f_mapping; |
1731 | loff_t unmap_start = round_up(offset, PAGE_SIZE); | 1781 | loff_t unmap_start = round_up(offset, PAGE_SIZE); |
1732 | loff_t unmap_end = round_down(offset + len, PAGE_SIZE) - 1; | 1782 | loff_t unmap_end = round_down(offset + len, PAGE_SIZE) - 1; |
1733 | 1783 | ||
1784 | shmem_falloc.start = unmap_start >> PAGE_SHIFT; | ||
1785 | shmem_falloc.next = (unmap_end + 1) >> PAGE_SHIFT; | ||
1786 | spin_lock(&inode->i_lock); | ||
1787 | inode->i_private = &shmem_falloc; | ||
1788 | spin_unlock(&inode->i_lock); | ||
1789 | |||
1734 | if ((u64)unmap_end > (u64)unmap_start) | 1790 | if ((u64)unmap_end > (u64)unmap_start) |
1735 | unmap_mapping_range(mapping, unmap_start, | 1791 | unmap_mapping_range(mapping, unmap_start, |
1736 | 1 + unmap_end - unmap_start, 0); | 1792 | 1 + unmap_end - unmap_start, 0); |
1737 | shmem_truncate_range(inode, offset, offset + len - 1); | 1793 | shmem_truncate_range(inode, offset, offset + len - 1); |
1738 | /* No need to unmap again: hole-punching leaves COWed pages */ | 1794 | /* No need to unmap again: hole-punching leaves COWed pages */ |
1739 | error = 0; | 1795 | error = 0; |
1740 | goto out; | 1796 | goto undone; |
1741 | } | 1797 | } |
1742 | 1798 | ||
1743 | /* We need to check rlimit even when FALLOC_FL_KEEP_SIZE */ | 1799 | /* We need to check rlimit even when FALLOC_FL_KEEP_SIZE */ |