Commit 423bad600443c590f34ed7ce357591f76f48f137

Authored by Nick Piggin
Committed by Linus Torvalds
1 parent 7e675137a8

mm: add vm_insert_mixed

vm_insert_mixed will insert either a raw pfn or a refcounted struct page into
the page tables, depending on whether vm_normal_page() will return the page or
not.  With the introduction of the new pte bit, this is now a too tricky for
drivers to be doing themselves.

filemap_xip uses this in a subsequent patch.

Signed-off-by: Nick Piggin <npiggin@suse.de>
Cc: Jared Hulbert <jaredeh@gmail.com>
Cc: Carsten Otte <cotte@de.ibm.com>
Cc: Martin Schwidefsky <schwidefsky@de.ibm.com>
Cc: Heiko Carstens <heiko.carstens@de.ibm.com>
Signed-off-by: Andrew Morton <akpm@linux-foundation.org>
Signed-off-by: Linus Torvalds <torvalds@linux-foundation.org>

Showing 2 changed files with 62 additions and 26 deletions Side-by-side Diff

... ... @@ -1152,6 +1152,8 @@
1152 1152 int vm_insert_page(struct vm_area_struct *, unsigned long addr, struct page *);
1153 1153 int vm_insert_pfn(struct vm_area_struct *vma, unsigned long addr,
1154 1154 unsigned long pfn);
  1155 +int vm_insert_mixed(struct vm_area_struct *vma, unsigned long addr,
  1156 + unsigned long pfn);
1155 1157  
1156 1158 struct page *follow_page(struct vm_area_struct *, unsigned long address,
1157 1159 unsigned int foll_flags);
... ... @@ -1176,8 +1176,10 @@
1176 1176 * old drivers should use this, and they needed to mark their
1177 1177 * pages reserved for the old functions anyway.
1178 1178 */
1179   -static int insert_page(struct mm_struct *mm, unsigned long addr, struct page *page, pgprot_t prot)
  1179 +static int insert_page(struct vm_area_struct *vma, unsigned long addr,
  1180 + struct page *page, pgprot_t prot)
1180 1181 {
  1182 + struct mm_struct *mm = vma->vm_mm;
1181 1183 int retval;
1182 1184 pte_t *pte;
1183 1185 spinlock_t *ptl;
1184 1186  
1185 1187  
... ... @@ -1237,17 +1239,46 @@
1237 1239 *
1238 1240 * The page does not need to be reserved.
1239 1241 */
1240   -int vm_insert_page(struct vm_area_struct *vma, unsigned long addr, struct page *page)
  1242 +int vm_insert_page(struct vm_area_struct *vma, unsigned long addr,
  1243 + struct page *page)
1241 1244 {
1242 1245 if (addr < vma->vm_start || addr >= vma->vm_end)
1243 1246 return -EFAULT;
1244 1247 if (!page_count(page))
1245 1248 return -EINVAL;
1246 1249 vma->vm_flags |= VM_INSERTPAGE;
1247   - return insert_page(vma->vm_mm, addr, page, vma->vm_page_prot);
  1250 + return insert_page(vma, addr, page, vma->vm_page_prot);
1248 1251 }
1249 1252 EXPORT_SYMBOL(vm_insert_page);
1250 1253  
  1254 +static int insert_pfn(struct vm_area_struct *vma, unsigned long addr,
  1255 + unsigned long pfn, pgprot_t prot)
  1256 +{
  1257 + struct mm_struct *mm = vma->vm_mm;
  1258 + int retval;
  1259 + pte_t *pte, entry;
  1260 + spinlock_t *ptl;
  1261 +
  1262 + retval = -ENOMEM;
  1263 + pte = get_locked_pte(mm, addr, &ptl);
  1264 + if (!pte)
  1265 + goto out;
  1266 + retval = -EBUSY;
  1267 + if (!pte_none(*pte))
  1268 + goto out_unlock;
  1269 +
  1270 + /* Ok, finally just insert the thing.. */
  1271 + entry = pte_mkspecial(pfn_pte(pfn, prot));
  1272 + set_pte_at(mm, addr, pte, entry);
  1273 + update_mmu_cache(vma, addr, entry); /* XXX: why not for insert_page? */
  1274 +
  1275 + retval = 0;
  1276 +out_unlock:
  1277 + pte_unmap_unlock(pte, ptl);
  1278 +out:
  1279 + return retval;
  1280 +}
  1281 +
1251 1282 /**
1252 1283 * vm_insert_pfn - insert single pfn into user vma
1253 1284 * @vma: user vma to map to
1254 1285  
... ... @@ -1261,13 +1292,8 @@
1261 1292 * in that case the handler should return NULL.
1262 1293 */
1263 1294 int vm_insert_pfn(struct vm_area_struct *vma, unsigned long addr,
1264   - unsigned long pfn)
  1295 + unsigned long pfn)
1265 1296 {
1266   - struct mm_struct *mm = vma->vm_mm;
1267   - int retval;
1268   - pte_t *pte, entry;
1269   - spinlock_t *ptl;
1270   -
1271 1297 /*
1272 1298 * Technically, architectures with pte_special can avoid all these
1273 1299 * restrictions (same for remap_pfn_range). However we would like
1274 1300  
1275 1301  
1276 1302  
1277 1303  
... ... @@ -1280,27 +1306,35 @@
1280 1306 BUG_ON((vma->vm_flags & VM_PFNMAP) && is_cow_mapping(vma->vm_flags));
1281 1307 BUG_ON((vma->vm_flags & VM_MIXEDMAP) && pfn_valid(pfn));
1282 1308  
1283   - retval = -ENOMEM;
1284   - pte = get_locked_pte(mm, addr, &ptl);
1285   - if (!pte)
1286   - goto out;
1287   - retval = -EBUSY;
1288   - if (!pte_none(*pte))
1289   - goto out_unlock;
  1309 + if (addr < vma->vm_start || addr >= vma->vm_end)
  1310 + return -EFAULT;
  1311 + return insert_pfn(vma, addr, pfn, vma->vm_page_prot);
  1312 +}
  1313 +EXPORT_SYMBOL(vm_insert_pfn);
1290 1314  
1291   - /* Ok, finally just insert the thing.. */
1292   - entry = pte_mkspecial(pfn_pte(pfn, vma->vm_page_prot));
1293   - set_pte_at(mm, addr, pte, entry);
1294   - update_mmu_cache(vma, addr, entry);
  1315 +int vm_insert_mixed(struct vm_area_struct *vma, unsigned long addr,
  1316 + unsigned long pfn)
  1317 +{
  1318 + BUG_ON(!(vma->vm_flags & VM_MIXEDMAP));
1295 1319  
1296   - retval = 0;
1297   -out_unlock:
1298   - pte_unmap_unlock(pte, ptl);
  1320 + if (addr < vma->vm_start || addr >= vma->vm_end)
  1321 + return -EFAULT;
1299 1322  
1300   -out:
1301   - return retval;
  1323 + /*
  1324 + * If we don't have pte special, then we have to use the pfn_valid()
  1325 + * based VM_MIXEDMAP scheme (see vm_normal_page), and thus we *must*
  1326 + * refcount the page if pfn_valid is true (hence insert_page rather
  1327 + * than insert_pfn).
  1328 + */
  1329 + if (!HAVE_PTE_SPECIAL && pfn_valid(pfn)) {
  1330 + struct page *page;
  1331 +
  1332 + page = pfn_to_page(pfn);
  1333 + return insert_page(vma, addr, page, vma->vm_page_prot);
  1334 + }
  1335 + return insert_pfn(vma, addr, pfn, vma->vm_page_prot);
1302 1336 }
1303   -EXPORT_SYMBOL(vm_insert_pfn);
  1337 +EXPORT_SYMBOL(vm_insert_mixed);
1304 1338  
1305 1339 /*
1306 1340 * maps a range of physical memory into the requested pages. the old