Skip to content

Commit 23c570a

Browse files
Ram Paitorvalds
authored andcommitted
resource: ability to resize an allocated resource
Provides the ability to resize a resource that is already allocated. This functionality is put in place to support reallocation needs of pci resources. Signed-off-by: Ram Pai <[email protected]> Acked-by: Jesse Barnes <[email protected]> Signed-off-by: Linus Torvalds <[email protected]>
1 parent a51cb91 commit 23c570a

File tree

1 file changed

+98
-18
lines changed

1 file changed

+98
-18
lines changed

kernel/resource.c

Lines changed: 98 additions & 18 deletions
Original file line numberDiff line numberDiff line change
@@ -38,6 +38,14 @@ struct resource iomem_resource = {
3838
};
3939
EXPORT_SYMBOL(iomem_resource);
4040

41+
/* constraints to be met while allocating resources */
42+
struct resource_constraint {
43+
resource_size_t min, max, align;
44+
resource_size_t (*alignf)(void *, const struct resource *,
45+
resource_size_t, resource_size_t);
46+
void *alignf_data;
47+
};
48+
4149
static DEFINE_RWLOCK(resource_lock);
4250

4351
static void *r_next(struct seq_file *m, void *v, loff_t *pos)
@@ -384,16 +392,13 @@ static bool resource_contains(struct resource *res1, struct resource *res2)
384392
}
385393

386394
/*
387-
* Find empty slot in the resource tree given range and alignment.
395+
* Find empty slot in the resource tree with the given range and
396+
* alignment constraints
388397
*/
389-
static int find_resource(struct resource *root, struct resource *new,
390-
resource_size_t size, resource_size_t min,
391-
resource_size_t max, resource_size_t align,
392-
resource_size_t (*alignf)(void *,
393-
const struct resource *,
394-
resource_size_t,
395-
resource_size_t),
396-
void *alignf_data)
398+
static int __find_resource(struct resource *root, struct resource *old,
399+
struct resource *new,
400+
resource_size_t size,
401+
struct resource_constraint *constraint)
397402
{
398403
struct resource *this = root->child;
399404
struct resource tmp = *new, avail, alloc;
@@ -404,25 +409,26 @@ static int find_resource(struct resource *root, struct resource *new,
404409
* Skip past an allocated resource that starts at 0, since the assignment
405410
* of this->start - 1 to tmp->end below would cause an underflow.
406411
*/
407-
if (this && this->start == 0) {
408-
tmp.start = this->end + 1;
412+
if (this && this->start == root->start) {
413+
tmp.start = (this == old) ? old->start : this->end + 1;
409414
this = this->sibling;
410415
}
411416
for(;;) {
412417
if (this)
413-
tmp.end = this->start - 1;
418+
tmp.end = (this == old) ? this->end : this->start - 1;
414419
else
415420
tmp.end = root->end;
416421

417-
resource_clip(&tmp, min, max);
422+
resource_clip(&tmp, constraint->min, constraint->max);
418423
arch_remove_reservations(&tmp);
419424

420425
/* Check for overflow after ALIGN() */
421426
avail = *new;
422-
avail.start = ALIGN(tmp.start, align);
427+
avail.start = ALIGN(tmp.start, constraint->align);
423428
avail.end = tmp.end;
424429
if (avail.start >= tmp.start) {
425-
alloc.start = alignf(alignf_data, &avail, size, align);
430+
alloc.start = constraint->alignf(constraint->alignf_data, &avail,
431+
size, constraint->align);
426432
alloc.end = alloc.start + size - 1;
427433
if (resource_contains(&avail, &alloc)) {
428434
new->start = alloc.start;
@@ -432,14 +438,75 @@ static int find_resource(struct resource *root, struct resource *new,
432438
}
433439
if (!this)
434440
break;
435-
tmp.start = this->end + 1;
441+
if (this != old)
442+
tmp.start = this->end + 1;
436443
this = this->sibling;
437444
}
438445
return -EBUSY;
439446
}
440447

448+
/*
449+
* Find empty slot in the resource tree given range and alignment.
450+
*/
451+
static int find_resource(struct resource *root, struct resource *new,
452+
resource_size_t size,
453+
struct resource_constraint *constraint)
454+
{
455+
return __find_resource(root, NULL, new, size, constraint);
456+
}
457+
441458
/**
442-
* allocate_resource - allocate empty slot in the resource tree given range & alignment
459+
* reallocate_resource - allocate a slot in the resource tree given range & alignment.
460+
* The resource will be relocated if the new size cannot be reallocated in the
461+
* current location.
462+
*
463+
* @root: root resource descriptor
464+
* @old: resource descriptor desired by caller
465+
* @newsize: new size of the resource descriptor
466+
* @constraint: the size and alignment constraints to be met.
467+
*/
468+
int reallocate_resource(struct resource *root, struct resource *old,
469+
resource_size_t newsize,
470+
struct resource_constraint *constraint)
471+
{
472+
int err=0;
473+
struct resource new = *old;
474+
struct resource *conflict;
475+
476+
write_lock(&resource_lock);
477+
478+
if ((err = __find_resource(root, old, &new, newsize, constraint)))
479+
goto out;
480+
481+
if (resource_contains(&new, old)) {
482+
old->start = new.start;
483+
old->end = new.end;
484+
goto out;
485+
}
486+
487+
if (old->child) {
488+
err = -EBUSY;
489+
goto out;
490+
}
491+
492+
if (resource_contains(old, &new)) {
493+
old->start = new.start;
494+
old->end = new.end;
495+
} else {
496+
__release_resource(old);
497+
*old = new;
498+
conflict = __request_resource(root, old);
499+
BUG_ON(conflict);
500+
}
501+
out:
502+
write_unlock(&resource_lock);
503+
return err;
504+
}
505+
506+
507+
/**
508+
* allocate_resource - allocate empty slot in the resource tree given range & alignment.
509+
* The resource will be reallocated with a new size if it was already allocated
443510
* @root: root resource descriptor
444511
* @new: resource descriptor desired by caller
445512
* @size: requested resource region size
@@ -459,12 +526,25 @@ int allocate_resource(struct resource *root, struct resource *new,
459526
void *alignf_data)
460527
{
461528
int err;
529+
struct resource_constraint constraint;
462530

463531
if (!alignf)
464532
alignf = simple_align_resource;
465533

534+
constraint.min = min;
535+
constraint.max = max;
536+
constraint.align = align;
537+
constraint.alignf = alignf;
538+
constraint.alignf_data = alignf_data;
539+
540+
if ( new->parent ) {
541+
/* resource is already allocated, try reallocating with
542+
the new constraints */
543+
return reallocate_resource(root, new, size, &constraint);
544+
}
545+
466546
write_lock(&resource_lock);
467-
err = find_resource(root, new, size, min, max, align, alignf, alignf_data);
547+
err = find_resource(root, new, size, &constraint);
468548
if (err >= 0 && __request_resource(root, new))
469549
err = -EBUSY;
470550
write_unlock(&resource_lock);

0 commit comments

Comments
 (0)