Release 4.15 kernel/resource.c
/*
* linux/kernel/resource.c
*
* Copyright (C) 1999 Linus Torvalds
* Copyright (C) 1999 Martin Mares <mj@ucw.cz>
*
* Arbitrary resource management.
*/
#define pr_fmt(fmt) KBUILD_MODNAME ": " fmt
#include <linux/export.h>
#include <linux/errno.h>
#include <linux/ioport.h>
#include <linux/init.h>
#include <linux/slab.h>
#include <linux/spinlock.h>
#include <linux/fs.h>
#include <linux/proc_fs.h>
#include <linux/sched.h>
#include <linux/seq_file.h>
#include <linux/device.h>
#include <linux/pfn.h>
#include <linux/mm.h>
#include <linux/resource_ext.h>
#include <asm/io.h>
struct resource ioport_resource = {
.name = "PCI IO",
.start = 0,
.end = IO_SPACE_LIMIT,
.flags = IORESOURCE_IO,
};
EXPORT_SYMBOL(ioport_resource);
struct resource iomem_resource = {
.name = "PCI mem",
.start = 0,
.end = -1,
.flags = IORESOURCE_MEM,
};
EXPORT_SYMBOL(iomem_resource);
/* constraints to be met while allocating resources */
struct resource_constraint {
resource_size_t min, max, align;
resource_size_t (*alignf)(void *, const struct resource *,
resource_size_t, resource_size_t);
void *alignf_data;
};
static DEFINE_RWLOCK(resource_lock);
/*
* For memory hotplug, there is no way to free resource entries allocated
* by boot mem after the system is up. So for reusing the resource entry
* we need to remember the resource.
*/
static struct resource *bootmem_resource_free;
static DEFINE_SPINLOCK(bootmem_resource_lock);
static struct resource *next_resource(struct resource *p, bool sibling_only)
{
/* Caller wants to traverse through siblings only */
if (sibling_only)
return p->sibling;
if (p->child)
return p->child;
while (!p->sibling && p->parent)
p = p->parent;
return p->sibling;
}
Contributors
Person | Tokens | Prop | Commits | CommitProp |
Al Viro | 30 | 50.85% | 1 | 20.00% |
Vivek Goyal | 16 | 27.12% | 1 | 20.00% |
Linus Torvalds (pre-git) | 12 | 20.34% | 2 | 40.00% |
Randy Dunlap | 1 | 1.69% | 1 | 20.00% |
Total | 59 | 100.00% | 5 | 100.00% |
static void *r_next(struct seq_file *m, void *v, loff_t *pos)
{
struct resource *p = v;
(*pos)++;
return (void *)next_resource(p, false);
}
Contributors
Person | Tokens | Prop | Commits | CommitProp |
Vivek Goyal | 45 | 100.00% | 1 | 100.00% |
Total | 45 | 100.00% | 1 | 100.00% |
#ifdef CONFIG_PROC_FS
enum { MAX_IORES_LEVEL = 5 };
static void *r_start(struct seq_file *m, loff_t *pos)
__acquires(resource_lock)
{
struct resource *p = m->private;
loff_t l = 0;
read_lock(&resource_lock);
for (p = p->child; p && l < *pos; p = r_next(m, p, &l))
;
return p;
}
Contributors
Person | Tokens | Prop | Commits | CommitProp |
Al Viro | 54 | 76.06% | 1 | 20.00% |
Linus Torvalds (pre-git) | 10 | 14.08% | 2 | 40.00% |
Linus Torvalds | 4 | 5.63% | 1 | 20.00% |
Randy Dunlap | 3 | 4.23% | 1 | 20.00% |
Total | 71 | 100.00% | 5 | 100.00% |
static void r_stop(struct seq_file *m, void *v)
__releases(resource_lock)
{
read_unlock(&resource_lock);
}
Contributors
Person | Tokens | Prop | Commits | CommitProp |
Al Viro | 21 | 84.00% | 1 | 50.00% |
Linus Torvalds | 4 | 16.00% | 1 | 50.00% |
Total | 25 | 100.00% | 2 | 100.00% |
static int r_show(struct seq_file *m, void *v)
{
struct resource *root = m->private;
struct resource *r = v, *p;
unsigned long long start, end;
int width = root->end < 0x10000 ? 4 : 8;
int depth;
for (depth = 0, p = r; depth < MAX_IORES_LEVEL; depth++, p = p->parent)
if (p->parent == root)
break;
if (file_ns_capable(m->file, &init_user_ns, CAP_SYS_ADMIN)) {
start = r->start;
end = r->end;
} else {
start = end = 0;
}
seq_printf(m, "%*s%0*llx-%0*llx : %s\n",
depth * 2, "",
width, start,
width, end,
r->name ? r->name : "<BAD>");
return 0;
}
Contributors
Person | Tokens | Prop | Commits | CommitProp |
Al Viro | 72 | 45.00% | 1 | 11.11% |
Linus Torvalds | 44 | 27.50% | 1 | 11.11% |
Randy Dunlap | 23 | 14.38% | 1 | 11.11% |
Linus Torvalds (pre-git) | 20 | 12.50% | 5 | 55.56% |
Greg Kroah-Hartman | 1 | 0.62% | 1 | 11.11% |
Total | 160 | 100.00% | 9 | 100.00% |
static const struct seq_operations resource_op = {
.start = r_start,
.next = r_next,
.stop = r_stop,
.show = r_show,
};
static int ioports_open(struct inode *inode, struct file *file)
{
int res = seq_open(file, &resource_op);
if (!res) {
struct seq_file *m = file->private_data;
m->private = &ioport_resource;
}
return res;
}
Contributors
Person | Tokens | Prop | Commits | CommitProp |
Al Viro | 37 | 69.81% | 1 | 50.00% |
Randy Dunlap | 16 | 30.19% | 1 | 50.00% |
Total | 53 | 100.00% | 2 | 100.00% |
static int iomem_open(struct inode *inode, struct file *file)
{
int res = seq_open(file, &resource_op);
if (!res) {
struct seq_file *m = file->private_data;
m->private = &iomem_resource;
}
return res;
}
Contributors
Person | Tokens | Prop | Commits | CommitProp |
Al Viro | 32 | 60.38% | 1 | 33.33% |
Randy Dunlap | 19 | 35.85% | 1 | 33.33% |
Linus Torvalds (pre-git) | 2 | 3.77% | 1 | 33.33% |
Total | 53 | 100.00% | 3 | 100.00% |
static const struct file_operations proc_ioports_operations = {
.open = ioports_open,
.read = seq_read,
.llseek = seq_lseek,
.release = seq_release,
};
static const struct file_operations proc_iomem_operations = {
.open = iomem_open,
.read = seq_read,
.llseek = seq_lseek,
.release = seq_release,
};
static int __init ioresources_init(void)
{
proc_create("ioports", 0, NULL, &proc_ioports_operations);
proc_create("iomem", 0, NULL, &proc_iomem_operations);
return 0;
}
Contributors
Person | Tokens | Prop | Commits | CommitProp |
Randy Dunlap | 27 | 75.00% | 1 | 25.00% |
Denis V. Lunev | 6 | 16.67% | 1 | 25.00% |
Linus Torvalds (pre-git) | 3 | 8.33% | 2 | 50.00% |
Total | 36 | 100.00% | 4 | 100.00% |
__initcall(ioresources_init);
#endif /* CONFIG_PROC_FS */
static void free_resource(struct resource *res)
{
if (!res)
return;
if (!PageSlab(virt_to_head_page(res))) {
spin_lock(&bootmem_resource_lock);
res->sibling = bootmem_resource_free;
bootmem_resource_free = res;
spin_unlock(&bootmem_resource_lock);
} else {
kfree(res);
}
}
Contributors
Person | Tokens | Prop | Commits | CommitProp |
Yasuaki Ishimatsu | 60 | 100.00% | 1 | 100.00% |
Total | 60 | 100.00% | 1 | 100.00% |
static struct resource *alloc_resource(gfp_t flags)
{
struct resource *res = NULL;
spin_lock(&bootmem_resource_lock);
if (bootmem_resource_free) {
res = bootmem_resource_free;
bootmem_resource_free = res->sibling;
}
spin_unlock(&bootmem_resource_lock);
if (res)
memset(res, 0, sizeof(struct resource));
else
res = kzalloc(sizeof(struct resource), flags);
return res;
}
Contributors
Person | Tokens | Prop | Commits | CommitProp |
Yasuaki Ishimatsu | 80 | 100.00% | 1 | 100.00% |
Total | 80 | 100.00% | 1 | 100.00% |
/* Return the conflict entry if you can't request it */
static struct resource * __request_resource(struct resource *root, struct resource *new)
{
resource_size_t start = new->start;
resource_size_t end = new->end;
struct resource *tmp, **p;
if (end < start)
return root;
if (start < root->start)
return root;
if (end > root->end)
return root;
p = &root->child;
for (;;) {
tmp = *p;
if (!tmp || tmp->start > end) {
new->sibling = tmp;
*p = new;
new->parent = root;
return NULL;
}
p = &tmp->sibling;
if (tmp->end < start)
continue;
return tmp;
}
}
Contributors
Person | Tokens | Prop | Commits | CommitProp |
Linus Torvalds (pre-git) | 141 | 98.60% | 4 | 80.00% |
Greg Kroah-Hartman | 2 | 1.40% | 1 | 20.00% |
Total | 143 | 100.00% | 5 | 100.00% |
static int __release_resource(struct resource *old, bool release_child)
{
struct resource *tmp, **p, *chd;
p = &old->parent->child;
for (;;) {
tmp = *p;
if (!tmp)
break;
if (tmp == old) {
if (release_child || !(tmp->child)) {
*p = tmp->sibling;
} else {
for (chd = tmp->child;; chd = chd->sibling) {
chd->parent = tmp->parent;
if (!(chd->sibling))
break;
}
*p = tmp->child;
chd->sibling = tmp->sibling;
}
old->parent = NULL;
return 0;
}
p = &tmp->sibling;
}
return -EINVAL;
}
Contributors
Person | Tokens | Prop | Commits | CommitProp |
Linus Torvalds (pre-git) | 82 | 53.25% | 1 | 50.00% |
Toshi Kani | 72 | 46.75% | 1 | 50.00% |
Total | 154 | 100.00% | 2 | 100.00% |
static void __release_child_resources(struct resource *r)
{
struct resource *tmp, *p;
resource_size_t size;
p = r->child;
r->child = NULL;
while (p) {
tmp = p;
p = p->sibling;
tmp->parent = NULL;
tmp->sibling = NULL;
__release_child_resources(tmp);
printk(KERN_DEBUG "release child resource %pR\n", tmp);
/* need to restore size, and keep flags */
size = resource_size(tmp);
tmp->start = 0;
tmp->end = size - 1;
}
}
Contributors
Person | Tokens | Prop | Commits | CommitProp |
Yinghai Lu | 97 | 100.00% | 1 | 100.00% |
Total | 97 | 100.00% | 1 | 100.00% |
void release_child_resources(struct resource *r)
{
write_lock(&resource_lock);
__release_child_resources(r);
write_unlock(&resource_lock);
}
Contributors
Person | Tokens | Prop | Commits | CommitProp |
Yinghai Lu | 27 | 100.00% | 1 | 100.00% |
Total | 27 | 100.00% | 1 | 100.00% |
/**
* request_resource_conflict - request and reserve an I/O or memory resource
* @root: root resource descriptor
* @new: resource descriptor desired by caller
*
* Returns 0 for success, conflict resource on error.
*/
struct resource *request_resource_conflict(struct resource *root, struct resource *new)
{
struct resource *conflict;
write_lock(&resource_lock);
conflict = __request_resource(root, new);
write_unlock(&resource_lock);
return conflict;
}
Contributors
Person | Tokens | Prop | Commits | CommitProp |
Linus Torvalds (pre-git) | 40 | 86.96% | 1 | 50.00% |
Björn Helgaas | 6 | 13.04% | 1 | 50.00% |
Total | 46 | 100.00% | 2 | 100.00% |
/**
* request_resource - request and reserve an I/O or memory resource
* @root: root resource descriptor
* @new: resource descriptor desired by caller
*
* Returns 0 for success, negative error code on error.
*/
int request_resource(struct resource *root, struct resource *new)
{
struct resource *conflict;
conflict = request_resource_conflict(root, new);
return conflict ? -EBUSY : 0;
}
Contributors
Person | Tokens | Prop | Commits | CommitProp |
Björn Helgaas | 30 | 81.08% | 1 | 25.00% |
Linus Torvalds (pre-git) | 7 | 18.92% | 3 | 75.00% |
Total | 37 | 100.00% | 4 | 100.00% |
EXPORT_SYMBOL(request_resource);
/**
* release_resource - release a previously reserved resource
* @old: resource pointer
*/
int release_resource(struct resource *old)
{
int retval;
write_lock(&resource_lock);
retval = __release_resource(old, true);
write_unlock(&resource_lock);
return retval;
}
Contributors
Person | Tokens | Prop | Commits | CommitProp |
Linus Torvalds (pre-git) | 35 | 94.59% | 4 | 80.00% |
Toshi Kani | 2 | 5.41% | 1 | 20.00% |
Total | 37 | 100.00% | 5 | 100.00% |
EXPORT_SYMBOL(release_resource);
/*
* Finds the lowest iomem resource existing within [res->start.res->end).
* The caller must specify res->start, res->end, res->flags, and optionally
* desc. If found, returns 0, res is overwritten, if not found, returns -1.
* This function walks the whole tree and not just first level children until
* and unless first_level_children_only is true.
*/
static int find_next_iomem_res(struct resource *res, unsigned long desc,
bool first_level_children_only)
{
resource_size_t start, end;
struct resource *p;
bool sibling_only = false;
BUG_ON(!res);
start = res->start;
end = res->end;
BUG_ON(start >= end);
if (first_level_children_only)
sibling_only = true;
read_lock(&resource_lock);
for (p = iomem_resource.child; p; p = next_resource(p, sibling_only)) {
if ((p->flags & res->flags) != res->flags)
continue;
if ((desc != IORES_DESC_NONE) && (desc != p->desc))
continue;
if (p->start > end) {
p = NULL;
break;
}
if ((p->end >= start) && (p->start < end))
break;
}
read_unlock(&resource_lock);
if (!p)
return -1;
/* copy data */
if (res->start < p->start)
res->start = p->start;
if (res->end > p->end)
res->end = p->end;
res->flags = p->flags;
res->desc = p->desc;
return 0;
}
Contributors
Person | Tokens | Prop | Commits | CommitProp |
Kamezawa Hiroyuki | 163 | 70.26% | 5 | 50.00% |
Toshi Kani | 27 | 11.64% | 2 | 20.00% |
Vivek Goyal | 26 | 11.21% | 2 | 20.00% |
Tom Lendacky | 16 | 6.90% | 1 | 10.00% |
Total | 232 | 100.00% | 10 | 100.00% |
static int __walk_iomem_res_desc(struct resource *res, unsigned long desc,
bool first_level_children_only,
void *arg,
int (*func)(struct resource *, void *))
{
u64 orig_end = res->end;
int ret = -1;
while ((res->start < res->end) &&
!find_next_iomem_res(res, desc, first_level_children_only)) {
ret = (*func)(res, arg);
if (ret)
break;
res->start = res->end + 1;
res->end = orig_end;
}
return ret;
}
Contributors
Person | Tokens | Prop | Commits | CommitProp |
Toshi Kani | 49 | 44.95% | 1 | 25.00% |
Vivek Goyal | 38 | 34.86% | 1 | 25.00% |
Tom Lendacky | 22 | 20.18% | 2 | 50.00% |
Total | 109 | 100.00% | 4 | 100.00% |
/*
* Walks through iomem resources and calls func() with matching resource
* ranges. This walks through whole tree and not just first level children.
* All the memory ranges which overlap start,end and also match flags and
* desc are valid candidates.
*
* @desc: I/O resource descriptor. Use IORES_DESC_NONE to skip @desc check.
* @flags: I/O resource flags
* @start: start addr
* @end: end addr
*
* NOTE: For a new descriptor search, define a new IORES_DESC in
* <linux/ioport.h> and set it in 'desc' of a target resource entry.
*/
int walk_iomem_res_desc(unsigned long desc, unsigned long flags, u64 start,
u64 end, void *arg, int (*func)(struct resource *, void *))
{
struct resource res;
res.start = start;
res.end = end;
res.flags = flags;
return __walk_iomem_res_desc(&res, desc, false, arg, func);
}
Contributors
Person | Tokens | Prop | Commits | CommitProp |
Vivek Goyal | 50 | 67.57% | 1 | 25.00% |
Tom Lendacky | 23 | 31.08% | 2 | 50.00% |
Toshi Kani | 1 | 1.35% | 1 | 25.00% |
Total | 74 | 100.00% | 4 | 100.00% |
/*
* This function calls the @func callback against all memory ranges of type
* System RAM which are marked as IORESOURCE_SYSTEM_RAM and IORESOUCE_BUSY.
* Now, this function is only for System RAM, it deals with full ranges and
* not PFNs. If resources are not PFN-aligned, dealing with PFNs can truncate
* ranges.
*/
int walk_system_ram_res(u64 start, u64 end, void *arg,
int (*func)(struct resource *, void *))
{
struct resource res;
res.start = start;
res.end = end;
res.flags = IORESOURCE_SYSTEM_RAM | IORESOURCE_BUSY;
return __walk_iomem_res_desc(&res, IORES_DESC_NONE, true,
arg, func);
}
Contributors
Person | Tokens | Prop | Commits | CommitProp |
Tom Lendacky | 50 | 73.53% | 2 | 66.67% |
Vivek Goyal | 18 | 26.47% | 1 | 33.33% |
Total | 68 | 100.00% | 3 | 100.00% |
/*
* This function calls the @func callback against all memory ranges, which
* are ranges marked as IORESOURCE_MEM and IORESOUCE_BUSY.
*/
int walk_mem_res(u64 start, u64 end, void *arg,
int (*func)(struct resource *, void *))
{
struct resource res;
res.start = start;
res.end = end;
res.flags = IORESOURCE_MEM | IORESOURCE_BUSY;
return __walk_iomem_res_desc(&res, IORES_DESC_NONE, true,
arg, func);
}
Contributors
Person | Tokens | Prop | Commits | CommitProp |
Tom Lendacky | 68 | 100.00% | 1 | 100.00% |
Total | 68 | 100.00% | 1 | 100.00% |
#if !defined(CONFIG_ARCH_HAS_WALK_MEMORY)
/*
* This function calls the @func callback against all memory ranges of type
* System RAM which are marked as IORESOURCE_SYSTEM_RAM and IORESOUCE_BUSY.
* It is to be used only for System RAM.
*/
int walk_system_ram_range(unsigned long start_pfn, unsigned long nr_pages,
void *arg, int (*func)(unsigned long, unsigned long, void *))
{
struct resource res;
unsigned long pfn, end_pfn;
u64 orig_end;
int ret = -1;
res.start = (u64) start_pfn << PAGE_SHIFT;
res.end = ((u64)(start_pfn + nr_pages) << PAGE_SHIFT) - 1;
res.flags = IORESOURCE_SYSTEM_RAM | IORESOURCE_BUSY;
orig_end = res.end;
while ((res.start < res.end) &&
(find_next_iomem_res(&res, IORES_DESC_NONE, true) >= 0)) {
pfn = (res.start + PAGE_SIZE - 1) >> PAGE_SHIFT;
end_pfn = (res.end + 1) >> PAGE_SHIFT;
if (end_pfn > pfn)
ret = (*func)(pfn, end_pfn - pfn, arg);
if (ret)
break;
res.start = res.end + 1;
res.end = orig_end;
}
return ret;
}
Contributors
Person | Tokens | Prop | Commits | CommitProp |
Kamezawa Hiroyuki | 172 | 87.76% | 2 | 28.57% |
Fengguang Wu | 17 | 8.67% | 1 | 14.29% |
Toshi Kani | 3 | 1.53% | 2 | 28.57% |
Yasunori Goto | 2 | 1.02% | 1 | 14.29% |
Vivek Goyal | 2 | 1.02% | 1 | 14.29% |
Total | 196 | 100.00% | 7 | 100.00% |
#endif
static int __is_ram(unsigned long pfn, unsigned long nr_pages, void *arg)
{
return 1;
}
Contributors
Person | Tokens | Prop | Commits | CommitProp |
Fengguang Wu | 21 | 100.00% | 1 | 100.00% |
Total | 21 | 100.00% | 1 | 100.00% |
/*
* This generic page_is_ram() returns true if specified address is
* registered as System RAM in iomem_resource list.
*/
int __weak page_is_ram(unsigned long pfn)
{
return walk_system_ram_range(pfn, 1, NULL, __is_ram) == 1;
}
Contributors
Person | Tokens | Prop | Commits | CommitProp |
Fengguang Wu | 21 | 87.50% | 1 | 50.00% |
Andrew Morton | 3 | 12.50% | 1 | 50.00% |
Total | 24 | 100.00% | 2 | 100.00% |
EXPORT_SYMBOL_GPL(page_is_ram);
/**
* region_intersects() - determine intersection of region with known resources
* @start: region start address
* @size: size of region
* @flags: flags of resource (in iomem_resource)
* @desc: descriptor of resource (in iomem_resource) or IORES_DESC_NONE
*
* Check if the specified region partially overlaps or fully eclipses a
* resource identified by @flags and @desc (optional with IORES_DESC_NONE).
* Return REGION_DISJOINT if the region does not overlap @flags/@desc,
* return REGION_MIXED if the region overlaps @flags/@desc and another
* resource, and return REGION_INTERSECTS if the region overlaps @flags/@desc
* and no other defined resource. Note that REGION_INTERSECTS is also
* returned in the case when the specified region overlaps RAM and undefined
* memory holes.
*
* region_intersect() is used by memory remapping functions to ensure
* the user is not remapping RAM and is a vast speed up over walking
* through the resource table page by page.
*/
int region_intersects(resource_size_t start, size_t size, unsigned long flags,
unsigned long desc)
{
resource_size_t end = start + size - 1;
int type = 0; int other = 0;
struct resource *p;
read_lock(&resource_lock);
for (p = iomem_resource.child; p ; p = p->sibling) {
bool is_type = (((p->flags & flags) == flags) &&
((desc == IORES_DESC_NONE) ||
(desc == p->desc)));
if (start >= p->start && start <= p->end)
is_type ? type++ : other++;
if (end >= p->start && end <= p->end)
is_type ? type++ : other++;
if (p->start >= start && p->end <= end)
is_type ? type++ : other++;
}
read_unlock(&resource_lock);
if (other == 0)
return type ? REGION_INTERSECTS : REGION_DISJOINT;
if (type)
return REGION_MIXED;
return REGION_DISJOINT;
}
Contributors
Person | Tokens | Prop | Commits | CommitProp |
Dan J Williams | 87 | 44.62% | 1 | 20.00% |
Mike Travis | 76 | 38.97% | 1 | 20.00% |
Toshi Kani | 32 | 16.41% | 3 | 60.00% |
Total | 195 | 100.00% | 5 | 100.00% |
EXPORT_SYMBOL_GPL(region_intersects);
void __weak arch_remove_reservations(struct resource *avail)
{
}
Contributors
Person | Tokens | Prop | Commits | CommitProp |
Björn Helgaas | 10 | 100.00% | 1 | 100.00% |
Total | 10 | 100.00% | 1 | 100.00% |
static resource_size_t simple_align_resource(void *data,
const struct resource *avail,
resource_size_t size,
resource_size_t align)
{
return avail->start;
}
Contributors
Person | Tokens | Prop | Commits | CommitProp |
Björn Helgaas | 27 | 100.00% | 1 | 100.00% |
Total | 27 | 100.00% | 1 | 100.00% |
static void resource_clip(struct resource *res, resource_size_t min,
resource_size_t max)
{
if (res->start < min)
res->start = min;
if (res->end > max)
res->end = max;
}
Contributors
Person | Tokens | Prop | Commits | CommitProp |
Björn Helgaas | 45 | 100.00% | 1 | 100.00% |
Total | 45 | 100.00% | 1 | 100.00% |
/*
* Find empty slot in the resource tree with the given range and
* alignment constraints
*/
static int __find_resource(struct resource *root, struct resource *old,
struct resource *new,
resource_size_t size,
struct resource_constraint *constraint)
{
struct resource *this = root->child;
struct resource tmp = *new, avail, alloc;
tmp.start = root->start;
/*
* Skip past an allocated resource that starts at 0, since the assignment
* of this->start - 1 to tmp->end below would cause an underflow.
*/
if (this && this->start == root->start) {
tmp.start = (this == old) ? old->start : this->end + 1;
this = this->sibling;
}
for(;;) {
if (this)
tmp.end = (this == old) ? this->end : this->start - 1;
else
tmp.end = root->end;
if (tmp.end < tmp.start)
goto next;
resource_clip(&tmp, constraint->min, constraint->max);
arch_remove_reservations(&tmp);
/* Check for overflow after ALIGN() */
avail.start = ALIGN(tmp.start, constraint->align);
avail.end = tmp.end;
avail.flags = new->flags & ~IORESOURCE_UNSET;
if (avail.start >= tmp