Groups | Search | Server Info | Keyboard shortcuts | Login | Register [http] [https] [nntp] [nntps]
Groups > linux.kernel > #1170310 > unrolled thread
| Started by | Mike Kravetz <mike.kravetz@oracle.com> |
|---|---|
| First post | 2015-06-23 02:40 +0200 |
| Last post | 2015-06-29 23:50 +0200 |
| Articles | 2 — 1 participant |
Back to article view | Back to linux.kernel
This discussion starts older than the indexed window; earlier articles aren't shown. The article labeled Started by
below is the oldest one visible, not the original post.
[RFC v5 PATCH 1/9] mm/hugetlb: add region_del() to delete a specific range of entries Mike Kravetz <mike.kravetz@oracle.com> - 2015-06-23 02:40 +0200
Re: [RFC v5 PATCH 1/9] mm/hugetlb: add region_del() to delete a specific range of entries Mike Kravetz <mike.kravetz@oracle.com> - 2015-06-29 23:50 +0200
| From | Mike Kravetz <mike.kravetz@oracle.com> |
|---|---|
| Date | 2015-06-23 02:40 +0200 |
| Subject | [RFC v5 PATCH 1/9] mm/hugetlb: add region_del() to delete a specific range of entries |
| Message-ID | <pEkpQ-3gZ-5@gated-at.bofh.it> |
fallocate hole punch will want to remove a specific range of pages.
The existing region_truncate() routine deletes all region/reserve
map entries after a specified offset. region_del() will provide
this same functionality if the end of region is specified as -1.
Hence, region_del() can replace region_truncate().
Unlike region_truncate(), region_del() can return an error in the
rare case where it can not allocate memory for a region descriptor.
This ONLY happens in the case where an existing region must be split.
Current callers passing -1 as end of range will never experience
this error and do not need to deal with error handling. Future
callers of region_del() (such as fallocate hole punch) will need to
handle this error.
Signed-off-by: Mike Kravetz <mike.kravetz@oracle.com>
---
mm/hugetlb.c | 88 ++++++++++++++++++++++++++++++++++++++++++------------------
1 file changed, 62 insertions(+), 26 deletions(-)
diff --git a/mm/hugetlb.c b/mm/hugetlb.c
index a8c3087..3fc2359 100644
--- a/mm/hugetlb.c
+++ b/mm/hugetlb.c
@@ -385,43 +385,79 @@ out_nrg:
}
/*
- * Truncate the reserve map at index 'end'. Modify/truncate any
- * region which contains end. Delete any regions past end.
- * Return the number of huge pages removed from the map.
+ * Delete the specified range [f, t) from the reserve map. If the
+ * t parameter is -1, this indicates that ALL regions after f should
+ * be deleted. Locate the regions which intersect [f, t) and either
+ * trim, delete or split the existing regions.
+ *
+ * Returns the number of huge pages deleted from the reserve map.
+ * In the normal case, the return value is zero or more. In the
+ * case where a region must be split, a new region descriptor must
+ * be allocated. If the allocation fails, -ENOMEM will be returned.
+ * NOTE: If the parameter t == -1, then we will never split a region
+ * and possibly return -ENOMEM. Callers specifying t == -1 do not
+ * need to check for -ENOMEM error.
*/
-static long region_truncate(struct resv_map *resv, long end)
+static long region_del(struct resv_map *resv, long f, long t)
{
struct list_head *head = &resv->regions;
struct file_region *rg, *trg;
- long chg = 0;
+ struct file_region *nrg = NULL;
+ long del = 0;
+ if (t == -1)
+ t = LONG_MAX;
+retry:
spin_lock(&resv->lock);
- /* Locate the region we are either in or before. */
- list_for_each_entry(rg, head, link)
- if (end <= rg->to)
+ list_for_each_entry_safe(rg, trg, head, link) {
+ if (rg->to <= f)
+ continue;
+ if (rg->from >= t)
break;
- if (&rg->link == head)
- goto out;
- /* If we are in the middle of a region then adjust it. */
- if (end > rg->from) {
- chg = rg->to - end;
- rg->to = end;
- rg = list_entry(rg->link.next, typeof(*rg), link);
- }
+ if (f > rg->from && t < rg->to) { /* Must split region */
+ if (!nrg) {
+ spin_unlock(&resv->lock);
+ nrg = kmalloc(sizeof(*nrg), GFP_KERNEL);
+ if (!nrg)
+ return -ENOMEM;
+ goto retry;
+ }
- /* Drop any remaining regions. */
- list_for_each_entry_safe(rg, trg, rg->link.prev, link) {
- if (&rg->link == head)
+ del += t - f;
+
+ /* New entry for end of split region */
+ nrg->from = t;
+ nrg->to = rg->to;
+ INIT_LIST_HEAD(&nrg->link);
+
+ /* Original entry is trimmed */
+ rg->to = f;
+
+ list_add(&nrg->link, &rg->link);
+ nrg = NULL;
break;
- chg += rg->to - rg->from;
- list_del(&rg->link);
- kfree(rg);
+ }
+
+ if (f <= rg->from && t >= rg->to) { /* Remove entire region */
+ del += rg->to - rg->from;
+ list_del(&rg->link);
+ kfree(rg);
+ continue;
+ }
+
+ if (f <= rg->from) { /* Trim beginning of region */
+ del += t - rg->from;
+ rg->from = t;
+ } else { /* Trim end of region */
+ del += rg->to - f;
+ rg->to = f;
+ }
}
-out:
spin_unlock(&resv->lock);
- return chg;
+ kfree(nrg);
+ return del;
}
/*
@@ -559,7 +595,7 @@ void resv_map_release(struct kref *ref)
struct resv_map *resv_map = container_of(ref, struct resv_map, refs);
/* Clear out any active regions before we release the map. */
- region_truncate(resv_map, 0);
+ region_del(resv_map, 0, -1);
kfree(resv_map);
}
@@ -3740,7 +3776,7 @@ void hugetlb_unreserve_pages(struct inode *inode, long offset, long freed)
long gbl_reserve;
if (resv_map)
- chg = region_truncate(resv_map, offset);
+ chg = region_del(resv_map, offset, -1);
spin_lock(&inode->i_lock);
inode->i_blocks -= (blocks_per_huge_page(h) * freed);
spin_unlock(&inode->i_lock);
--
2.1.0
--
To unsubscribe from this list: send the line "unsubscribe linux-kernel" in
Please read the FAQ at http://www.tux.org/lkml/
[toc] | [next] | [standalone]
| From | Mike Kravetz <mike.kravetz@oracle.com> |
|---|---|
| Date | 2015-06-29 23:50 +0200 |
| Subject | Re: [RFC v5 PATCH 1/9] mm/hugetlb: add region_del() to delete a specific range of entries |
| Message-ID | <pGP6g-79Z-143@gated-at.bofh.it> |
| In reply to | #1170310 |
On 06/22/2015 05:38 PM, Mike Kravetz wrote: > fallocate hole punch will want to remove a specific range of pages. > The existing region_truncate() routine deletes all region/reserve > map entries after a specified offset. region_del() will provide > this same functionality if the end of region is specified as -1. > Hence, region_del() can replace region_truncate(). > > Unlike region_truncate(), region_del() can return an error in the > rare case where it can not allocate memory for a region descriptor. > This ONLY happens in the case where an existing region must be split. > Current callers passing -1 as end of range will never experience > this error and do not need to deal with error handling. Future > callers of region_del() (such as fallocate hole punch) will need to > handle this error. Unfortunately, this new region_del() functionality required for hole punch conflicts with existing region_chg()/region_add() assumptions. region_chg/region_add is something like a two step commit process for adding new region entries. region_chg is first called to determine the changes required for the new entry. If the new entry can be represented by expanding an existing region, no changes are made to the map in region_chg. If the new entry is not adjacent to an existing region, a placeholder is created during region_chg. Later when region_add is called, the assumption is that a region (real or placeholder) can be expanded to represent the new entry. Since all required entries already exist in the map, region_add can not fail. It is possible for the new region_del to modify the map between the region_chg and region_add calls. It can not modify the same map entry being added by region_chg/region_add as that is protected by the fault mutex. However, it can modify an entry adjacent to the new entry. The entry could be modified so that it is no longer adjacent to the new entry. As a result, when region_add is called it will not find a region which can be expanded to represent the new entry. In this situation, region_add only needs to add a new region to the map. However, to do so would require allocating a new region descriptor. The allocation could fail which would result in region_add failing. I'm thinking about having a cache of region descriptors pre-allocated to handle this (rare) situation. The number of descriptors needed in the cache would correspond to the number of page faults in progress (between region_chg and region_add). region_chg would make sure there are sufficient descriptors and allocate one if needed. Error handling for region_chg ENOMEM already exists. A sufficient number of entries would be pre-allocated such that in the normal case no allocation would be necessary. Thoughts? -- Mike Kravetz -- To unsubscribe from this list: send the line "unsubscribe linux-kernel" in the body of a message to majordomo@vger.kernel.org More majordomo info at http://vger.kernel.org/majordomo-info.html Please read the FAQ at http://www.tux.org/lkml/
[toc] | [prev] | [standalone]
Back to top | Article view | linux.kernel
csiph-web