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_t
structure has the information about the transaction. Later, when some modification is going to be done in a given buffer_head
, the jbd2_journal_get_write_access(handle, bh)
is called to get the write access to the specified buffer.
Inside jbd2_journal_get_write_access
the journal_head
structure is created, and then it is going to point to this buffer_head
, however, at this point there is no relation between handle_t
.
Next step, after returning from jbd2_journal_add_journal_head
, a call to do_get_write_access(handle, bh)
is made, and here the journal_head
is initialized with the information passed by the handle_t
.
After this step, where the handle_t
is used to initialize the journal_head
, then the handle_t
is 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 the buffer_heads
belonging to the committing transaction are going to be iterated, and committed.
Because the only information attached to the buffer_head
is the journal_head
, and the journal_head
does not contain the necessary information to distinguish what kind of buffer_head
is 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 in journal_head
structure. So, when the do_get_write_access()
call is made, I can filter the operation like this:
if(handle->h_ino)
jh->b_ino = handle->h_ino;
So, I had to modify handle_t
to transport the inode number to journal_head
, and at commit time I can get the required information that I want.