izac89
izac89

Reputation: 3930

Pointer calculation in Linux Kernel allocation implementation

From the guide Understanding The Linux Kernel, 3rd Edition , chapter 8.2.12. Allocating a Slab Object , there is the following piece of code:

void * kmem_cache_alloc(kmem_cache_t *cachep, int flags)
{  
    unsigned long save_flags;  
    void *objp;  
    struct array_cache *ac;  
    local_irq_save(save_flags);  
    ac = cache_p->array[smp_processor_id()];  
    if (ac->avail) 
    {  
       ac->touched = 1;
       objp = ((void**)(ac+1))[--ac->avail];  
    } else  
        objp = cache_alloc_refill(cachep, flags);  
    local_irq_restore(save_flags);  return objp; 
}

Now, look at the line ((void**)(ac+1))[--ac->avail], according to the guide:

Because the local cache array is stored right after the ac descriptor, ((void**)(ac+1))[--ac->avail] gets the address of that free object and decreases the value of ac->avail.

But, since ac is a pointer to type struct array_cache which contains the following fields (in this order)-

[type] unsigned int

[name] avail

[description] Number of pointers to available objects in the local cache. The field also acts as the index of the first free slot in the cache.

[type] unsigned int

[name] limit

[description] Size of the local cache that is, the maximum number of pointers in the local cache.

[type] unsigned int

[name] batch_count

[description] Chunk size for local cache refill or emptying.

[type] unsigned int

[name] touched

[description] Flag set to 1 if the local cache has been recently used.

so ac+1 will point to to the second byte of avail value (or 3rd byte in opposite Endian case) which makes no sense at all.

Am I getting this the wrong way?

Upvotes: 1

Views: 909

Answers (1)

unwind
unwind

Reputation: 399803

Yes, you're mistaken.

Pointer arithmetic is in terms of the type being pointed at, not bytes.

Consider this:

int a[2], *p = a;

++p;

This leaves p equal to &a[1], not ((char *) &a[0]) + 1. So that increment will increment the actual pointer value by sizeof *p, i.e. sizeof (int).

Remember that array indexing works through pointer arithmetic, so it has to be this way for that reason too.

It's quite common when implementing various data structures in C that you have a block of memory that starts with an instance of some struct, and then comes other data (often described by field in the struct). The first byte of that data is then at sp + 1, assuming sp is a pointer to the struct, just as the code you showed.

Upvotes: 3

Related Questions