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.
Related
can someone tell me what is the difference between coping one transaction(item) to the another like in examples bellow (add_method_port_1 and add_method_port_2):
add_method_port_1 (added_item: item_s) is {
var new_item: new_item_s;
gen new_item keeping {
it.my_trans_s == added_item.as_a(t_trans_s);
};
};
add_method_port_2 (added_item: item_s) is {
var new_item : new_item_s = deep_copy(added_item.as_a(t_trans_s));
};
Where new_item_s looks like:
struct new_item_s like item_s {
%my_trans_s: t_trans_s;
};
Thanks,
Andrija
Actually, the results of the two methods are different even if the assumption mentioned in Rodion's answer does hold.
With the first method, new_item points to the same my_trans_s object as the original added_item, because the constraint it.my_trans_s == added_item.as_a(t_trans_s) means pointer equality.
With the second method, new_item points to a copy of the original my_trans_s, because deep_copy copies everything recursively.
In this specific example, assuming that new_item_s has only one field my_trans_s, there is no difference in outcome.
In practice, the meaning and the goal of "gen keeping" and deep_copy is quite different:
gen keeping, even with '==' constraints, practically assignments, means random-constraint generating an item executing iGen logic engine; if this is a struct then pre_generate and post_generate methods are invoked, and all the fields not mentioned in 'keeping {}' block are also randomly generated according to existing constraints and their type properties. It is usually used to create a new item for which only some properties are known.
deep_copy creates an exact copy (up to some minor nuances) of the given struct, and if it has fields which are also structs - copy of all connected graph topology. There is no random generation, no special methods, no logical engine executed. Usually it used to capture the data at some point for later analysis.
In other words, if the assumption "new_item_s has only one field my_trans_s" is wrong, the result are going to be very much different.
I am currently doing a Customers program when a user can add/edit/search/list customers. I decided to use a binary tree as the backbone of this program. My idea was to then save each item in the tree to "customers.dat" right before the program closes, then on start up load everything from the file to the tree. So far so good, however after finally managing to save the binary search tree into a file, I have one bug.
Lets say I add 3 customers the first time. I then close the program, and when I reopen it I will find the same 3 customers in the tree. however, the next time I open the file, it gives me an error from one of my predefined errors, which occurs when a node is not able to identity whether to go left or right, maybe because its empty or uncomparable. here are some code snippets. I aslo tried using other fileopen techniques other than a+b, and I had no such error, but by the way I designed my program, I need the append method or else only one record will save.
Customers are stored in Cstmr in the header:
typedef struct customer
{
char Name[MAXNAME];
char Surname[MAXNAME];
char ID[MAXID];
char Address[MAXADDRESS];
} Cstmr;
else:
void CustomerTreeToFile(Tree*pt)
{
if (TreeIsEmpty(pt))
puts("Nothing to save!");
else
Traverse(pt,saveItem); //Traverses each node, and appliess the function
//saveItem to each node
}
void saveItem(Cstmr C)
{
save = C;
customers = fopen("customers.dat","ab+");
fwrite(&C,sizeof (Cstmr), 1, customers);
fclose(customers);
}
The problem is that you are always appending all the data to the same file ... so everything from the previous run is duplicated.
One solution would be to delete (unlink) the file before saving the data with your current approach.
However, as Freezerburn pointed out earlier, it's more economic to not open and close the file for each item. Just open the file once in overwrite mode (i.e. not append), then write all the data, then close the file. Should be much faster, too.
Another problem is that you save your data in binary format. Try to define an easy to read textual format. That would have made the problem obvious ...
I'm really scratching my head over how to correctly use the windows api to determine file permissions. I have seen so many posts on this, but I just can't seem to get it right. Specifically, I would like to examine whether a user has read or write permissions for a given file. These are my steps:
(1) Access fully qualified username of the calling client (inc. domain name) with GetUserNameEx; (returns 0 error; user name appears to print out correctly using a cout debug message).
(2) Access the user's SID using LookupAccountName. (I do this twice, the first time for setting the SID and domain buffer sizes -- Returns 122 error on first call and 0 error on second (to be expected)). I assume the SID buffer is correctly set.
(3) Build a trustee with the obtained sid:
TRUSTEE t;
PTRUSTEE tptr = &t;
BuildTrusteeWithSid(tptr,&sid[0]);
(4) Obtain the DACL:
// following are freed up later using LocalFree (maybe I should use delete?)
PACL ppDacl = new ACL;
PSECURITY_DESCRIPTOR ppSecurityDescriptor = new SECURITY_DESCRIPTOR;
std::vector<TCHAR> v(pathString.begin(), pathString.end());
GetNamedSecurityInfo(&v[0],
SE_FILE_OBJECT,
READ_CONTROL,
NULL,
NULL,
&ppDacl,
NULL,
&ppSecurityDescriptor);
A simple call
std::cout<<"ACE count: "<<ppDacl->AceCount<<std::endl;
then indicates that there are 58 ACEs leading me to assume that the DACL struct is being correctly instantiated (I am further assuming that there are 58 ACEs although I'm not sure how to manually verify this; I'm really not a windows person). However, printing GetLastError() after the GetNamedSecurityInfo call gives me a 122 (i.e. ERROR_INSUFFICIENT_BUFFER) so it appears something is going wrong at this step.
Note that initializing the PACL and PSECURITY_DESCRIPTOR as follows:
ACL dacl;
PACL ppDacl = &dacl;
SECURITY_DESCRIPTOR sd;
PSECURITY_DESCRIPTO = &sd;
rather than new-ing them doesn't seem to correctly fill the DACL (at least the call
std::cout<<"ACE count: "<<ppDacl->AceCount<<std::endl;
reports 0 rather than 58). I'm not sure why.
(5) Finally, I attempt to get the file's access mask given the created trustee and dacl:
ACCESS_MASK access;
GetEffectiveRightsFromAcl(ppDacl, tptr, &access);
Which indicates no access rights when I do:
((access & GENERIC_WRITE)==GENERIC_WRITE)
or
((access & GENERIC_READ)==GENERIC_READ)
I hope one of you can shed some light on this
Cheers,
Ben.
The call to GetNamedSecurityInfo() shall have DACL_SECURITY_INFORMATION set in the set of flags being passed as 3rd parameter. Only then the data being referenced by the value returned in the 6th parameter will be valid after the call returned.
Verbatim from GetNamedSecurityInfo()'s documentation on MSDN:
ppDacl [out, optional]
...
The returned pointer is valid only if you set the DACL_SECURITY_INFORMATION flag.
Also as a side note: There is no need to initialise ppDacl and ppSecurityDescriptor as this is done by GetNamedSecurityInfo(). If you dynamically allocate memory to those this causes a memory leak, as by the call to GetNamedSecurityInfo() you lose the references to what you allocated.
I am creating an application where I need to push some element in the sequence, I am using cvSeqPush, but I am not getting its second argument const void * element, I need to push a point of type cvPoint.
How is this done in C?
That method is called to push on the sequence whatever data you have, but in your case as I guess your sequence is configured to contain CvPoints's you will have to point to that kind of data to have a correct program.
CvPoint pnt = cvPoint(x,y);
cvSeqPush(srcSeq, (CvPoint *)&pnt);
Something like this should work for you, just point to some data the sequence needs.
If you need something more specific to your case you should post some code.
A couple things need to be added:
1. you will need to allocate memory to store your srcSeq
2. release memory when you're done using srcSeq
CvMemStorage* srcSeq_storage = cvCreateMemStorage(0);
CvSeq* srcSeq = cvCreateSeq(0, sizeof(CvSeq), sizeof(CvPoint), srcSeq_storage);
// now push your point element to srcSeq
cvSeqPush(srcSeq,&pnt);
// don't forget release memory
cvReleaseMemStorage(&srcSeq_storage);
INT GetTree (HWND hWnd, HTREEITEM hItem, HKEY *pRoot, TCHAR *pszKey,
INT nMax) {
TV_ITEM tvi;
TCHAR szName[256];
HTREEITEM hParent;
HWND hwndTV = GetDlgItem (hWnd, ID_TREEV);
memset (&tvi, 0, sizeof (tvi));
hParent = TreeView_GetParent (hwndTV, hItem);
if (hParent) {
// Get the parent of the parent of the...
GetTree (hWnd, hParent, pRoot, pszKey, nMax);
// Get the name of the item.
tvi.mask = TVIF_TEXT;
tvi.hItem = hItem;
tvi.pszText = szName;
tvi.cchTextMax = dim(szName);
TreeView_GetItem (hwndTV, &tvi); //send the TVM_GETITEM message?
lstrcat (pszKey, TEXT ("\\"));
lstrcat (pszKey, szName);
} else {
*pszKey = TEXT ('\0');
szName[0] = TEXT ('\0');
// Get the name of the item.
tvi.mask = TVIF_TEXT | TVIF_PARAM;
tvi.hItem = hItem;
tvi.pszText = szName;
tvi.cchTextMax = dim(szName);
if (TreeView_GetItem (hwndTV, &tvi))
//*pRoot = (HTREEITEM)tvi.lParam; //original
hItem = (HTREEITEM)tvi.lParam;
else {
INT rc = GetLastError();
}
}
return 0;
}
The block of code that begins with the comment "Get the name of the item" does not make sense to me. If you are getting the listview item why does the code set the parameters of the item being retrieved? If you already had the values there would be no need to retrieve them.
Secondly near the comment "original" is the original line of code which will compile with a warning under embedded visual c++ 4.0, but if you copy the exact same code into visual studio 2008 it will not compile. Since I did not write any of this code, and am trying to learn, is it possible the original author made a mistake on this line? The *pRoot should point to HKEY type yet he is casting to an HTREEITEM type which should never work since the data types don't match?
The block of code that begins with the comment "Get the name of the item" does not make sense to me. If you are getting the listview item why does the code set the parameters of the item being retrieved, because if you already had the values there would be no need to retrieve them.
After that comment, the first line is to specify to TreeView_GetItem (which, by the way, is actually a SendMessage in disguise) that we want to retrieve the text of the item and the associated lParam. The next line specifies the handle to the item about which we want information.
The following line specifies where the retrieved text must be saved, i.e. in the szName buffer, which has been allocated at the beginning of the function; the last line before the function call specifies the size of such buffer, so to avoid buffer overflows.
I suggest you to have a look at the documentation of TreeView_GetItem and of TVITEM to understand better what's going on.
Secondly near the comment "original" is the original line of code which will compile with a varning under embedded visual c++, but if you copy the exact same code into visual studio 2008 it will not compile. Since I did not write any of this code and am trying to learn is it possible the original author made a mistake on this line, since the *pRoot should point to and HKEY type yet he is casting to an HTREEITEM type which should never work since the data types don't match?
It's not clear what the code is trying to do there; at first glance I'd say that in the lParam associated to each item in the root node of the treeview is stored a handle to a registry key, and the procedure retrieves it in that way. Still, if it was like that, the (HTREEITEM) cast wouldn't make sense at all; probably it was a mistake, forgiven by the compiler because it treated all handles as plain void *; if my hypothesis is correct you should keep the original line, just replacing (HTREEITEM) with (HKEY).
Many times, API calls take in information in a structure, and also return information in the same structure. If you look at the documentation for TreeView_GetItem, it will clearly show how it operates.
As for the second question, are you compiling as C++? What is the error?
The LPTVITEM parameter to the TreeView_GetItem macro is used bi-directionally.
TreeView_GetItem does indeed send the TVM_GETITEM message to the treeview. What's going on here is that the caller fills in a little bit of the struct to say "here's what I have and what I want" and then the treeview will fill in the requested bits.
From the TreeView_GetItem documentation
When the TVM_GETITEM message is sent, the hItem member of the TVITEM or TVITEMEX structure identifies the item to retrieve information about, and the mask member specifies the attributes to retrieve.
For the second part, I think it looks like it was a mistake, based on the names of the variables etc., but you should probably check how the function is used in the rest of the code to make sure.
The first question is pretty simple: you're filling in a few of the items in the structure to tell what data you want, then calling TreeView_GetItem to actually retrieve the specified data. In this case, you're specifying TVIF_TEXT, which says you want the text for the particular item. You also give it a buffer where it's going to put the text (szName), and tell it how long that buffer is (so it won't write past the end of the buffer). When you call TreeView_GetIem, it copies the text for that item into your buffer.
As to your second question: it looks like all that code (both old and new) is somewhat problematic. The general intent seems to be to retrieve the path to the item that was originally passed in, but it seems to do that rather poorly. It starts by recursively walking up the tree to the root. Then it retrieves the text for the root item, but only into the local variable szName -- which it then ignores (does not copy into szKey). It does store the handle to the root item into hItem (this is where it originally wrote to pRoot).
Then, as it returns (walking back "down" the tree), it retrieves the text for each item, and appends those names to szKey (separated by '\'), to form (most of) the path to the item originally passed in. Unfortunately, as it does this, it ignores the nMax that was passed in, so it can (apparently) write past the end of the szKey buffer.