RMAN(9)

πŸ“¦
version 15.1 Β· 2 versions
, in freebsd 15.1

πŸŽ€ RMAN(9) πŸŽ€

okay bestie, buckle up β€” this is the resource management functions page from the Kernel Developer's Manual, and it's genuinely one of the most important little corners of the kernel. iykyk πŸ’…


✨ NAME ✨

rman, rman_activate_resource, rman_adjust_resource, rman_deactivate_resource, rman_fini, rman_init, rman_init_from_resource, rman_is_region_manager, rman_manage_region, rman_first_free_region, rman_last_free_region, rman_release_resource, rman_reserve_resource, rman_make_alignment_flags, rman_get_start, rman_get_end, rman_get_device, rman_get_size, rman_get_flags, rman_set_mapping, rman_get_mapping, rman_set_virtual, rman_get_virtual, rman_set_bustag, rman_get_bustag, rman_set_bushandle, rman_get_bushandle, rman_set_rid, rman_get_rid, rman_set_type, rman_get_type β€” resource management functions

like… that's the whole squad. the entire friend group. 🫢


🌸 SYNOPSIS 🌸

#include <sys/types.h>
#include <sys/rman.h>

int
rman_activate_resource(struct resource *r);

int
rman_adjust_resource(struct resource *r, rman_res_t start,
    rman_res_t end);

int
rman_deactivate_resource(struct resource *r);

int
rman_fini(struct rman *rm);

int
rman_init(struct rman *rm);

int
rman_init_from_resource(struct rman *rm, struct resource *r);

int
rman_is_region_manager(struct resource *r, struct rman *rm);

int
rman_manage_region(struct rman *rm, rman_res_t start, rman_res_t end);

int
rman_first_free_region(struct rman *rm, rman_res_t *start,
    rman_res_t *end);

int
rman_last_free_region(struct rman *rm, rman_res_t *start,
    rman_res_t *end);

int
rman_release_resource(struct resource *r);

struct resource *
rman_reserve_resource(struct rman *rm, rman_res_t start, rman_res_t end,
    rman_res_t count, u_int flags, device_t dev);

uint32_t
rman_make_alignment_flags(uint32_t size);

rman_res_t
rman_get_start(struct resource *r);

rman_res_t
rman_get_end(struct resource *r);

device_t
rman_get_device(struct resource *r);

rman_res_t
rman_get_size(struct resource *r);

u_int
rman_get_flags(struct resource *r);

void
rman_set_mapping(struct resource *r, struct resource_map *map);

void
rman_get_mapping(struct resource *r, struct resource_map *map);

void
rman_set_virtual(struct resource *r, void *v);

void *
rman_get_virtual(struct resource *r);

void
rman_set_bustag(struct resource *r, bus_space_tag_t t);

bus_space_tag_t
rman_get_bustag(struct resource *r);

void
rman_set_bushandle(struct resource *r, bus_space_handle_t h);

bus_space_handle_t
rman_get_bushandle(struct resource *r);

void
rman_set_rid(struct resource *r, int rid);

int
rman_get_rid(struct resource *r);

void
rman_set_type(struct resource *r, int type);

int
rman_get_type(struct resource *r);

πŸ’– DESCRIPTION πŸ’–

so the rman functions are this flexible resource management abstraction, right? they're used extensively by the bus management code β€” like, main character energy in the bus world. 🌈

it implements two big concepts: region and resource.

  • a region descriptor manages a region. that region could be memory, or some other form of bus space. πŸ’«
  • each region has a set of bounds, and within those bounds, allocated segments may reside.
  • each segment β€” which we call a resource β€” has several properties, and those live in a 16-bit flag register, like this:
#define RF_ALLOCATED    0x0001 /* resource has been reserved */
#define RF_ACTIVE       0x0002 /* resource allocation has been activated */
#define RF_SHAREABLE    0x0004 /* resource permits contemporaneous sharing */
#define RF_FIRSTSHARE   0x0020 /* first in sharing list */
#define RF_PREFETCHABLE 0x0040 /* resource is prefetchable */
#define RF_UNMAPPED     0x0100 /* don't map resource when activating */

and bestie, listen: bits 15:10 of the flag register are the ones representing the desired alignment of the resource within the region. don't forget those. πŸŽ€


πŸ¦‹ the setup + teardown girlies πŸ¦‹

  • rman_init(struct rman *rm) β€” initializes the region descriptor pointed to by the rm argument so it's ready for the resource management functions. okay but like, it has requirements: the fields rm_type and rm_descr of struct rman must be set before you call rman_init(). rm_type shall be set to RMAN_ARRAY. rm_descr shall be set to a string that describes the resource being managed. the rm_start and rm_end fields may be set to limit the range of acceptable resource addresses β€” and if you don't set them, rman_init() will initialize them to allow the entire range of resource addresses. it also initializes any mutexes associated with the structure. if it fails to initialize the mutex, it returns ENOMEM; otherwise it returns 0 and rm is initialized. slay. ✨
  • rman_fini(struct rman *rm) β€” frees any structures associated with the structure pointed to by rm. but here's the vibe check: if any of the resources within the managed region have the RF_ALLOCATED flag set, it returns EBUSY 😀. otherwise, any mutexes associated with the structure are released and destroyed, and the function returns 0.
  • rman_manage_region(struct rman *rm, rman_res_t start, rman_res_t end) β€” establishes the concept of a region that's under rman control. rm points to the region descriptor, and start and end specify the bounds of the region. if it succeeds, you get 0. if the region overlaps with an existing region, EBUSY. if any part of the region falls outside the valid address range for rm, EINVAL. and ENOMEM shows up when it failed to allocate memory for the region. πŸ’€
  • rman_init_from_resource(struct rman *rm, struct resource *r) β€” a lil wrapper routine that creates a resource manager backed by an existing resource. it initializes rm using rman_init() and then adds a region to rm corresponding to the address range allocated to r, via rman_manage_region(). cute, efficient, we love her. 🫢

πŸ’… the query + reserve girlies πŸ’…

  • rman_first_free_region(struct rman *rm, rman_res_t *start, rman_res_t *end) and rman_last_free_region(struct rman *rm, rman_res_t *start, rman_res_t *end) β€” you use these to query a resource manager for its first (or last) unallocated region. if rm contains no free region, they return ENOENT. otherwise *start and *end get set to the bounds of the free region and zero is returned. periodt. πŸ‘‘
  • rman_reserve_resource(struct rman *rm, rman_res_t start, rman_res_t end, rman_res_t count, u_int flags, device_t dev) β€” okay THIS is where the bulk of the rman logic lives, it's the whole main character. it attempts to reserve a contiguous range in the specified region rm for the use of the device dev. the caller can specify the start and end of an acceptable range, plus the required alignment, and the code will attempt to find a free segment that fits. πŸ’«
    • start is the lowest acceptable starting value of the resource.
    • end is the highest acceptable ending value of the resource.
    • therefore, start + count - 1 must be ≀ end for any allocation to happen. no exceptions bestie, that's just math.
    • the alignment requirement (if any) is specified in flags. often the RF_ALIGNMENT_LOG2 macro is used to specify alignment to a power-of-2 size, or rman_make_alignment_flags() can be used to compute the flags value at runtime.
    • a shared segment gets allocated if the RF_SHAREABLE flag is set; otherwise an exclusive segment is allocated.
    • and if that shared segment already exists, the caller has its device added to the list of consumers. sharing is caring πŸ’–
  • rman_make_alignment_flags(uint32_t size) β€” returns the flag mask corresponding to the desired alignment size. this should be used when calling rman_reserve_resource_bound(). πŸ”₯
  • rman_is_region_manager(struct resource *r, struct rman *rm) β€” returns true if the allocated resource r was allocated from rm. otherwise returns false. simple as. ⭐
  • rman_adjust_resource(struct resource *r, rman_res_t start, rman_res_t end) β€” used to adjust the reserved address range of an allocated resource so it reserves start through end. it can grow or shrink one or both ends of the resource range. lowkey powerful, highkey picky:
    • the current implementation does not support entirely relocating the resource, and will fail with EINVAL if the new resource range does not overlap the old resource range.
    • if either end of the resource range grows and the new range would conflict with another allocated resource, it fails with EBUSY.
    • it does not support adjusting the resource range for shared resources β€” those attempts fail with EINVAL.
    • upon success, the resource r will have a start address of start and an end address of end, and the function returns zero.
ngl bestie, this is important: none of the constraints of the original allocation request β€” things like alignment or boundary restrictions β€” are checked by rman_adjust_resource(). it is the caller's responsibility to enforce any such requirements. 😭 don't come for her when you didn't do your homework.
  • rman_release_resource(struct resource *r) β€” releases the reserved resource r. it may attempt to merge adjacent free resources. tidy ✨

🌈 activation era 🌈

  • rman_activate_resource(struct resource *r) β€” marks a resource as active by setting the RF_ACTIVE flag. but if this is a time shared resource, and the caller has not yet acquired the resource, the function returns EBUSY. πŸ™ˆ
  • rman_deactivate_resource(struct resource *r) β€” marks a resource r as inactive by clearing the RF_ACTIVE flag. and if other consumers are waiting for this range, it will wakeup their threads. so considerate πŸ’œ

πŸ“ getters, setters & the little details πŸ“

  • rman_get_start(), rman_get_end(), rman_get_size(), and rman_get_flags() β€” return the bounds, size, and flags of the previously reserved resource r. πŸŽ€
  • rman_set_bustag() β€” associates a bus_space_tag_t t with the resource r. rman_get_bustag() retrieves this tag once it's set. 🧚
  • rman_set_bushandle() β€” associates a bus_space_handle_t h with the resource r. rman_get_bushandle() retrieves this handle once it's set. ✨
  • rman_set_virtual() β€” used to associate a kernel virtual address with a resource r. rman_get_virtual() retrieves the KVA once it's set. 🌸
  • rman_set_mapping() β€” used to associate a resource mapping with a resource r. heads up though: the mapping must cover the entire resource. setting a mapping sets the associated bus_space(9) handle and tag for r as well as the kernel virtual address, if the mapping contains one. those individual values can be retrieved via rman_get_bushandle(), rman_get_bustag(), and rman_get_virtual(). πŸ’«
  • rman_get_mapping() β€” retrieves the associated resource mapping once it's set. πŸ¦‹
  • rman_set_rid() β€” associates a resource identifier with a resource r. rman_get_rid() retrieves this RID. 🌟
  • rman_set_type() β€” associates a resource type with a resource r. rman_get_type() retrieves this type. 🌺
  • rman_get_device() β€” returns a pointer to the device which reserved the resource r. literally her whole job, and she does it flawlessly. πŸ‘‘

πŸ”₯ SEE ALSO πŸ”₯

bus_activate_resource(9), bus_adjust_resource(9), bus_alloc_resource(9), bus_map_resource(9), bus_release_resource(9), bus_set_resource(9), bus_space(9), mutex(9)

go read them, they're the supporting cast and they ate πŸ’…


πŸ’œ AUTHORS πŸ’œ

This manual page was written by Bruce M Simpson <bms@spc.org>. king behavior honestly πŸ‘‘βœ¨


okay that's the whole page, you're officially educated, go forth and manage your resources bestie πŸ¦‹πŸ’–

Debian Β· March 13, 2024 Β· RMAN(9) β€” that's the vibe check, and it passed with flying colors πŸŒˆπŸ’…

πŸ“¦ where this page comes from
  • freebsd 15.1: base 15.1
  • πŸ’– girlified by deepseek-ai/DeepSeek-V4.1-Flash-1017 on : a language model's rewrite of the original, under its terms