In the jbd2 source code, any modification in the File System is mapped into a handle_t structure (per process) that later is used to map the buffer_head to the transaction_t which this handle is going to be part of.
As far as I could understand, when a modification to a given buffer_head is needed, then a call to do_get_write_access() is going to map this buffer_head to the transaction that the handle_t is being part of.
However, when this handle_t is used to map the buffer_head to the transaction_t, the reciprocal mapping is lost, that is, I cannot track back to which handle_t this buffer_head belonged.
The thing is that, during the jbd2_journal_commit_transaction() (commit phase 2b in commit function) I want to find a way to walk through these buffer_heads and be able to classify them if they are related to an inode, or to a metadata, or to a inode bitmap block, or an data bitmap block, for example. Furthermore, at this point in the source code, the buffer_heads seems to be opaque, where they are simply sent to the storage.
UPDATE 1:
What I have tried so far was this, in the jbd2_journal_commit_transaction() function, in the commit phase 2b.
struct journal_head *jh;
...
jh = commit_transaction->t_buffers;
if(jh->b_jlist == BJ_Metadata) {
struct buffer_head *bh_p = NULL;
bh_p = jh2bh(jh);
if(!bh_p) printk(KERN_DEBUG "Null ptr in bh_p\n");
else {
struct address_space *as_p = NULL;
if((as_p = bh_p->b_assoc_map) == NULL)
printk(KERN_DEBUG "Null ptr in as_p\n");
else {
struct inode *i_p = NULL;
if(i_p) printk(KERN_DEBUG "Inode is %lu\n", i_p->i_ino);
}
}
}
It is not working, it is giving NULL ptr in the as_p, that is, there is no b_assoc_map set for this buffer_head. But, I have no idea what is the b_assoc_map.
UPDATE 2:
I am trying to get the information from the handle_t structure at ext4_mark_iloc_dirty. handle_t->h_type has the information I need. However, when I try to compare this value, a NULL pointer is causing a kernel warning. I thought this structure is unique per process, but seems like it is having some race condition, I don't know clearly yet.
After looking through all the source code path related to this issue, I conclude that there is no way to do it without changing anything.
Basically, the
handle_tstructure has the information about the transaction. Later, when some modification is going to be done in a givenbuffer_head, thejbd2_journal_get_write_access(handle, bh)is called to get the write access to the specified buffer.Inside
jbd2_journal_get_write_accessthejournal_headstructure is created, and then it is going to point to thisbuffer_head, however, at this point there is no relation betweenhandle_t.Next step, after returning from
jbd2_journal_add_journal_head, a call todo_get_write_access(handle, bh)is made, and here thejournal_headis initialized with the information passed by thehandle_t.After this step, where the
handle_tis used to initialize thejournal_head, then thehandle_tis not necessary anymore.Up to here, everything is initialized, now we can move to the commit point.
In
jbd2_journal_commit_transaction, at commit phase 2b thebuffer_headsbelonging to the committing transaction are going to be iterated, and committed.Because the only information attached to the
buffer_headis thejournal_head, and thejournal_headdoes not contain the necessary information to distinguish what kind ofbuffer_headis it, then I conclude that it is not possible to reach what I want without modifying the source code.My solution was to add a new member to store the inode number in the
handle_t, and also injournal_headstructure. So, when thedo_get_write_access()call is made, I can filter the operation like this:So, I had to modify
handle_tto transport the inode number tojournal_head, and at commit time I can get the required information that I want.