Extending the OCB

In some cases, you may find the need to extend the OCB. This is relatively painless to do. The common uses for extending the OCB are to add extra flags you wish to maintain on a per-open basis. One such flag could be used with the io_unblock() handler to cache the value of the kernel's _NTO_MI_UNBLOCK_REQ flag. (See the Message Passing chapter, under "Using the _NTO_MI_UNBLOCK_REQ" for more details.)

To extend the OCB, you'll need to provide two functions; one to allocate (and initialize) the new OCB and one to free it. Then, you'll need to bind these two functions into the mount structure. (Yes, this does mean that you'll need a mount structure, if only for this one purpose.) Finally, you'll need to define your own OCB typedef, so that the prototypes for the code are all correct.

Let's look at the OCB typedef first, and then we'll see how to override the functions:

#define IOFUNC_OCB_T struct my_ocb
#include <sys/iofunc.h>

This tells the included file, <sys/iofunc.h>, that the manifest constant IOFUNC_OCB_T now points to your new and improved OCB structure.

Note: It's very important to keep in mind that the "normal" OCB must appear as the first entry in your extended OCB! This is because the POSIX helper library passes around a pointer to what it expects is a normal OCB—it doesn't know about your extended OCB, so therefore the first data element at the pointer location must be the normal OCB.

Here's our extended OCB:

typedef struct my_ocb
{
    iofunc_ocb_t    normal_ocb;
    int             my_extra_flags;
    ...
} my_ocb_t;

Finally, here's the code that illustrates how to override the allocation and deallocation functions in the mount structure:

// declare
iofunc_mount_t      mount;
iofunc_funcs_t      mount_funcs;

// set up the mount functions structure
// with our allocate/deallocate functions

// _IOFUNC_NFUNCS is from the .h file
mount_funcs.nfuncs = _IOFUNC_NFUNCS;

// your new OCB allocator
mount_funcs.ocb_calloc = my_ocb_calloc;

// your new OCB deallocator
mount_funcs.ocb_free = my_ocb_free;

// set up the mount structure
memset (&mount, 0, sizeof (mount));

Then all you have to do is bind the mount functions to the mount structure, and the mount structure to the attributes structure:

...

mount.funcs = &mount_funcs;
attr.mount = &mount;

The my_ocb_calloc() and my_ocb_free() functions are responsible for allocating and initializing an extended OCB and for freeing the OCB, respectively. They are prototyped as:

IOFUNC_OCB_T *
my_ocb_calloc (resmgr_context_t *ctp, IOFUNC_ATTR_T *attr);

void
my_ocb_free (IOFUNC_OCB_T *ocb);

This means that the my_ocb_calloc() function gets passed both the internal resource manager context and the attributes structure. The function is responsible for returning an initialized OCB. The my_ocb_free() function gets passed the OCB and is responsible for releasing the storage for it.

Note: It's important to realize that the OCB may be allocated by functions other than the normal io_open() handler—for example, the memory manager may allocate an OCB. The impact of this is that your OCB allocating function must be able to initialize the OCB with the attr argument.

There are two interesting uses for these two functions (that have nothing to do with extending the OCB):