// imagine this is EXT3's SB method to alloc an inode, and return it to the VFS.
struct inode *ext3_alloc_inode(void)
{
  int vfs_inode_size = sizeof(struct inode);
  int ext3_inode_size = sizeof(struct ext3_inode);
  // allocate one buffer (a container) for BOTH structs
  void *buf = malloc(vfs_inode_size + ext3_inode_size);
  // assume malloc succeeded, no error checking
  // we will lay out in the buf the two structs
  // first we'll put the ext3_inode, then the VFS inode

  // to access the ext3_inode, we simply do this
  struct ext3_inode *private_ext3_inode = (struct ext3_inode *) buf;
  // meaning that buf[0] ... buf[ext3_inode_size - 1] are the bytes where a
  // struct ext3_inode lives

  // to access the VFS inode, we start inside buf, after the bytes we
  // reserved for ext3.
  struct inode *vfs_inode = (struct inode *) &buf[ext3_inode_size];
  // vfs_inode is guaranteed to have room for a full "struct inode" in the
  // rest of buf

  // return struct inode to VFS for caching in dcache
  return vfs_inode;
}

// late on, in some method, the ext3 code needs to get its OWN inode
// but the VFS only knows one point, to struct inode
int ext3_unlink(struct inode *inode, struct dentry *dentry, flags)
{
  // when this code needs to access the VFS inode, just refer to "inode"
  // when we need to access the ext3_inode, we "find" it before the VFS
  // inode
  struct ext3_inode *private_ext3_inode =
    (struct ext3_inode *) (inode - sizeof(struct ext3_inode));

  // this is called a "container" b/c it holes two structures in place
  // also called an out-of-band data structure, or OOB.

  // Note also, b/c the f/s allocates this "container", it has to be the one
  // to free it.  In C, you must free a buf with the same start addr you
  // were given back from malloc.  Don't free(inode), but free(ext3_inode);
}
