public inbox for systemtap@sourceware.org
 help / color / mirror / Atom feed
* dereferencing filenames from a vfs_write probe
       [not found] <1205982759.13969.ezmlm@sourceware.org>
@ 2008-03-20  3:37 ` dave-systemtap
  2008-03-20  4:18   ` Eugene Teo
  2008-03-20  4:42   ` Ananth N Mavinakayanahalli
  0 siblings, 2 replies; 11+ messages in thread
From: dave-systemtap @ 2008-03-20  3:37 UTC (permalink / raw)
  To: systemtap

[-- Attachment #1: Type: text/plain, Size: 1802 bytes --]

Greetings list.

First, I'm not anywhere near being a kernel dev, so it's entirely likely
that I'm making dumb assumptions and/or am lacking some critical piece
of a priori knowledge here.  Apologies in advance.

So, I'm looking at some of the existing code on the wiki
and the internet at large which probes vfs_(read|write) for various
things.  For my purpose, it'd be handy to get a filename back from the
probe instead of (or in addition to) an inode number.  

for example:

probe kernel.function ("vfs_write"),
      kernel.function ("vfs_read")
{
  fname = $file->f_dentry-> <something>

   printf ("%s(%d,%d) %s\n",
     execname(), pid(), uid(), fname)
}


I'm aware I could use system() to derive the filename from an inode
number dereferenced from  $file->f_dentry->d_inode->i_ino, but that
feels a tad kludgy.

Poking around the kernel headers I see the dentry struct in
includes/linux/dcache.h has a struct of type qstr (quick string) called
'd_name'.  I see that the qstr struct has within it a pointer to a const
unsigned char called 'name'.  This seems tantalizingly close to what I'm
looking for but dereferencing it with the code above using
$file->f_dentry->d_name->name returns a type mismatch error. The
derefernced thingy called 'name' is appearently of type 'long', not a
pointer to a string.

So I'm beat,  is this long I'm getting back a memory address? If so how
do I '&' it in an stap script?  I spoke to Eugene on IRC briefly and he
mentioned a d_path struct that I don't see in this header, which makes
me wonder if I'm even looking at the correct headers.  I'll grep around
for it, but wanted to post this in the meantime in case I'm just making
some obvious newbie error.

Thanks in advance for your help. 

--dave josephsen

[-- Attachment #2: Type: application/pgp-signature, Size: 187 bytes --]

^ permalink raw reply	[flat|nested] 11+ messages in thread

* Re: dereferencing filenames from a vfs_write probe
  2008-03-20  3:37 ` dereferencing filenames from a vfs_write probe dave-systemtap
@ 2008-03-20  4:18   ` Eugene Teo
  2008-03-20 16:02     ` Stone, Joshua I
  2008-03-20 17:25     ` dave-systemtap
  2008-03-20  4:42   ` Ananth N Mavinakayanahalli
  1 sibling, 2 replies; 11+ messages in thread
From: Eugene Teo @ 2008-03-20  4:18 UTC (permalink / raw)
  To: systemtap

Hi Dave,

<quote sender="dave-systemtap@skeptech.org">
> So, I'm looking at some of the existing code on the wiki
> and the internet at large which probes vfs_(read|write) for various
> things.  For my purpose, it'd be handy to get a filename back from the
> probe instead of (or in addition to) an inode number.  
> 
> for example:
> 
> probe kernel.function ("vfs_write"),
>       kernel.function ("vfs_read")
> {
>   fname = $file->f_dentry-> <something>
> 
>    printf ("%s(%d,%d) %s\n",
>      execname(), pid(), uid(), fname)
> }

It would be useful if you also include the kernel version, as structures
may change in between versions.

linux-2.6:
 779 struct file {
[...]
 788         struct path             f_path;
 789 #define f_dentry        f_path.dentry
 790 #define f_vfsmnt        f_path.mnt

It is possible to get hold of the path name (including the filename)
using d_path().

I have not tested it, but I have a piece of code I used in a script
elsewhere that you can probably amend and reuse:

function get_d_path_info:string (task:long, fd:long) %{
	struct task_struct *p = (struct task_struct
*)((long)THIS->task);
	struct files_struct *files = kread(&p->files);
	char *page = (char *)__get_free_page(GFP_KERNEL);
	struct file *filp;
	struct dentry *dentry;
	struct vfsmount *vfsmnt;

	spin_lock(&files->file_lock);
	filp = fcheck_files(files, THIS->fd);
	dentry = kread(&filp->f_path.dentry);
	vfsmnt = kread(&filp->f_path.mnt);
	snprintf(THIS->__retvalue, MAXSTRINGLEN, "      %s",
			d_path(dentry, vfsmnt, page, PAGE_SIZE));
	free_page((unsigned long)page);
	spin_unlock(&files->file_lock);
	CATCH_DEREF_FAULT();
%}

Thanks,
Eugene

^ permalink raw reply	[flat|nested] 11+ messages in thread

* Re: dereferencing filenames from a vfs_write probe
  2008-03-20  3:37 ` dereferencing filenames from a vfs_write probe dave-systemtap
  2008-03-20  4:18   ` Eugene Teo
@ 2008-03-20  4:42   ` Ananth N Mavinakayanahalli
  2008-03-20 12:05     ` Eugene Teo
  1 sibling, 1 reply; 11+ messages in thread
From: Ananth N Mavinakayanahalli @ 2008-03-20  4:42 UTC (permalink / raw)
  To: systemtap

On Wed, Mar 19, 2008 at 10:37:34PM -0500, dave-systemtap@skeptech.org wrote:
 
> Poking around the kernel headers I see the dentry struct in
> includes/linux/dcache.h has a struct of type qstr (quick string) called
> 'd_name'.  I see that the qstr struct has within it a pointer to a const
> unsigned char called 'name'.  This seems tantalizingly close to what I'm
> looking for but dereferencing it with the code above using
> $file->f_dentry->d_name->name returns a type mismatch error. The
> derefernced thingy called 'name' is appearently of type 'long', not a
> pointer to a string.

Try kernel_string($file->f_dentry->d_name->name) instead.

Ananth

^ permalink raw reply	[flat|nested] 11+ messages in thread

* Re: dereferencing filenames from a vfs_write probe
  2008-03-20  4:42   ` Ananth N Mavinakayanahalli
@ 2008-03-20 12:05     ` Eugene Teo
  0 siblings, 0 replies; 11+ messages in thread
From: Eugene Teo @ 2008-03-20 12:05 UTC (permalink / raw)
  To: dave-systemtap; +Cc: systemtap, Ananth N Mavinakayanahalli

<quote sender="Ananth N Mavinakayanahalli">
> On Wed, Mar 19, 2008 at 10:37:34PM -0500, dave-systemtap@skeptech.org wrote:
>  
> > Poking around the kernel headers I see the dentry struct in
> > includes/linux/dcache.h has a struct of type qstr (quick string) called
> > 'd_name'.  I see that the qstr struct has within it a pointer to a const
> > unsigned char called 'name'.  This seems tantalizingly close to what I'm
> > looking for but dereferencing it with the code above using
> > $file->f_dentry->d_name->name returns a type mismatch error. The
> > derefernced thingy called 'name' is appearently of type 'long', not a
> > pointer to a string.
> 
> Try kernel_string($file->f_dentry->d_name->name) instead.

Thanks Ananth.

probe kernel.function("vfs_write"),
      kernel.function("vfs_read") {
        printf("%s(%d,%d) %s\n", execname(), pid(), uid(),
                        kernel_string($file->f_path->dentry->d_name->name))
}

Eugene

^ permalink raw reply	[flat|nested] 11+ messages in thread

* Re: dereferencing filenames from a vfs_write probe
  2008-03-20  4:18   ` Eugene Teo
@ 2008-03-20 16:02     ` Stone, Joshua I
  2008-03-20 17:25     ` dave-systemtap
  1 sibling, 0 replies; 11+ messages in thread
From: Stone, Joshua I @ 2008-03-20 16:02 UTC (permalink / raw)
  To: Eugene Teo; +Cc: systemtap

Eugene Teo wrote:
> I have not tested it, but I have a piece of code I used in a script
> elsewhere that you can probably amend and reuse:
> 
> function get_d_path_info:string (task:long, fd:long) %{
> 	struct task_struct *p = (struct task_struct *)((long)THIS->task);
> 	struct files_struct *files = kread(&p->files);
> 	char *page = (char *)__get_free_page(GFP_KERNEL);
> 	struct file *filp;
> 	struct dentry *dentry;
> 	struct vfsmount *vfsmnt;
> 
> 	spin_lock(&files->file_lock);
> 	filp = fcheck_files(files, THIS->fd);
> 	dentry = kread(&filp->f_path.dentry);
> 	vfsmnt = kread(&filp->f_path.mnt);
> 	snprintf(THIS->__retvalue, MAXSTRINGLEN, "      %s",
> 			d_path(dentry, vfsmnt, page, PAGE_SIZE));
> 	free_page((unsigned long)page);
> 	spin_unlock(&files->file_lock);
> 	CATCH_DEREF_FAULT();
> %}

You should careful - each kread() will jump to the CATCH_DEREF_FAULT()
block if there's an error.  You may end up leaving this function with
the page not freed or the lock still held!


Josh

^ permalink raw reply	[flat|nested] 11+ messages in thread

* Re: dereferencing filenames from a vfs_write probe
  2008-03-20  4:18   ` Eugene Teo
  2008-03-20 16:02     ` Stone, Joshua I
@ 2008-03-20 17:25     ` dave-systemtap
  2008-03-20 17:48       ` Frank Ch. Eigler
  2008-03-20 18:06       ` Jim Keniston
  1 sibling, 2 replies; 11+ messages in thread
From: dave-systemtap @ 2008-03-20 17:25 UTC (permalink / raw)
  To: systemtap

[-- Attachment #1: Type: text/plain, Size: 2799 bytes --]

On Thu, Mar 20, 2008 at 12:17:58PM +0800, Eugene Teo wrote:
> Hi Dave,
> 
> <quote sender="dave-systemtap@skeptech.org">
> > So, I'm looking at some of the existing code on the wiki
> > and the internet at large which probes vfs_(read|write) for various
> > things.  For my purpose, it'd be handy to get a filename back from the
> > probe instead of (or in addition to) an inode number.  
> > 
> > for example:
> > 
> > probe kernel.function ("vfs_write"),
> >       kernel.function ("vfs_read")
> > {
> >   fname = $file->f_dentry-> <something>
> > 
> >    printf ("%s(%d,%d) %s\n",
> >      execname(), pid(), uid(), fname)
> > }
> 
> It would be useful if you also include the kernel version, as structures
> may change in between versions.

This happens to be 2.6.16.19.  I'm curious, how often do systemtap
scripts need to change in practice because of data struture changes in
the kernel? 

> 
> linux-2.6:
>  779 struct file {
> [...]
>  788         struct path             f_path;
>  789 #define f_dentry        f_path.dentry
>  790 #define f_vfsmnt        f_path.mnt
> 
> It is possible to get hold of the path name (including the filename)
> using d_path().
> 
> I have not tested it, but I have a piece of code I used in a script
> elsewhere that you can probably amend and reuse:
> 
> function get_d_path_info:string (task:long, fd:long) %{
> 	struct task_struct *p = (struct task_struct
> *)((long)THIS->task);
> 	struct files_struct *files = kread(&p->files);
> 	char *page = (char *)__get_free_page(GFP_KERNEL);
> 	struct file *filp;
> 	struct dentry *dentry;
> 	struct vfsmount *vfsmnt;
> 
> 	spin_lock(&files->file_lock);
> 	filp = fcheck_files(files, THIS->fd);
> 	dentry = kread(&filp->f_path.dentry);
> 	vfsmnt = kread(&filp->f_path.mnt);
> 	snprintf(THIS->__retvalue, MAXSTRINGLEN, "      %s",
> 			d_path(dentry, vfsmnt, page, PAGE_SIZE));
> 	free_page((unsigned long)page);
> 	spin_unlock(&files->file_lock);
> 	CATCH_DEREF_FAULT();
> %}

Cool thanks. So based on that code I've chopped out the following function:

function get_path:string (dentry:dentry *,vsmnt:vsmount *) %{
  char *page = (char *)__get_free_page(GFP_KERNEL);
  sprintf("%s",d_path(dentry, vfsmnt, page, PAGE_SIZE));
  free_page((unsigned long)page);
%}

and am attempting to pass pointers to the requisite structs like so:
path=get_path($file->f_dentry, $file->f_vfsmnt)

This is, as you probably guessed, giving me a parse error: 

parse error: expected 'string' or 'long'
        
I guess this means I'm only allowed to pass strings or longs into
embedded C functions. I guess it's time to do some more rtfm'ing. 

parent=kernel_string($file->pathsearch) works perfectly btw. 

Thanks

--dave
 
> Thanks,
> Eugene


[-- Attachment #2: Type: application/pgp-signature, Size: 187 bytes --]

^ permalink raw reply	[flat|nested] 11+ messages in thread

* Re: dereferencing filenames from a vfs_write probe
  2008-03-20 17:25     ` dave-systemtap
@ 2008-03-20 17:48       ` Frank Ch. Eigler
  2008-03-20 18:06       ` Jim Keniston
  1 sibling, 0 replies; 11+ messages in thread
From: Frank Ch. Eigler @ 2008-03-20 17:48 UTC (permalink / raw)
  To: systemtap


dave-systemtap@skeptech.org writes:

> [...]  This happens to be 2.6.16.19.  I'm curious, how often do
> systemtap scripts need to change in practice because of data
> struture changes in the kernel?

It happens - it's one of the mixed blessings of a fast-churning
kernel.  Once the core of the system settles down, we will be able to
spend more time at pulling in such functions into the script tapset,
so that end-user scripts are better isolated from changes.

> Cool thanks. So based on that code I've chopped out the following function:
> function get_path:string (dentry:dentry *,vsmnt:vsmount *) %{
>   char *page = (char *)__get_free_page(GFP_KERNEL);
>   sprintf("%s",d_path(dentry, vfsmnt, page, PAGE_SIZE));
>   free_page((unsigned long)page);
> %}

Other than this code not compiling, it's not generally proper to make
potentially blocking calls like GFP_KERNEL allocations.  From the
context of your script it may be safe, but functions to be considered
for the general tapset must not make potentially blocking operations
such as a GFP_KERNEL allocation or a lock acquire.

> [...]
> I guess this means I'm only allowed to pass strings or longs into
> embedded C functions. I guess it's time to do some more rtfm'ing. 

(Pointers are cast to longs.)

- FChE

^ permalink raw reply	[flat|nested] 11+ messages in thread

* Re: dereferencing filenames from a vfs_write probe
  2008-03-20 17:25     ` dave-systemtap
  2008-03-20 17:48       ` Frank Ch. Eigler
@ 2008-03-20 18:06       ` Jim Keniston
  2008-03-20 21:04         ` dave
  1 sibling, 1 reply; 11+ messages in thread
From: Jim Keniston @ 2008-03-20 18:06 UTC (permalink / raw)
  To: dave-systemtap; +Cc: systemtap

On Thu, 2008-03-20 at 12:24 -0500, dave-systemtap@skeptech.org wrote:
...
> 
> This happens to be 2.6.16.19.  I'm curious, how often do systemtap
> scripts need to change in practice because of data struture changes in
> the kernel?

It's not uncommon, but the tapset maintainers try to shield tapset users
from this.  Grep for "kernel_v" and "LINUX_VERSION_CODE" in
src/tapset/*.stp to get an idea.

...
> Cool thanks. So based on that code I've chopped out the following function:
> 
> function get_path:string (dentry:dentry *,vsmnt:vsmount *) %{
>   char *page = (char *)__get_free_page(GFP_KERNEL);
>   sprintf("%s",d_path(dentry, vfsmnt, page, PAGE_SIZE));
>   free_page((unsigned long)page);
> %}

Keep in mind that a handler mustn't sleep, so you should use GFP_ATOMIC
rather than GFP_KERNEL.

And yeah, the dentry and vsmnt args should be declared long and cast to
the appropriate pointer types.

> 
> ... 
> 
> Thanks
> 
> --dave

Jim Keniston

^ permalink raw reply	[flat|nested] 11+ messages in thread

* Re: dereferencing filenames from a vfs_write probe
  2008-03-20 18:06       ` Jim Keniston
@ 2008-03-20 21:04         ` dave
  2008-03-21  0:19           ` Jim Keniston
  0 siblings, 1 reply; 11+ messages in thread
From: dave @ 2008-03-20 21:04 UTC (permalink / raw)
  To: systemtap

[-- Attachment #1: Type: text/plain, Size: 1824 bytes --]

On Thu, Mar 20, 2008 at 11:01:14AM -0700, Jim Keniston wrote:
> On Thu, 2008-03-20 at 12:24 -0500, dave-systemtap@skeptech.org wrote:
> ...
> > 
> > This happens to be 2.6.16.19.  I'm curious, how often do systemtap
> > scripts need to change in practice because of data struture changes in
> > the kernel?
> 
> It's not uncommon, but the tapset maintainers try to shield tapset users
> from this.  Grep for "kernel_v" and "LINUX_VERSION_CODE" in
> src/tapset/*.stp to get an idea.

Excellent thank you.
 
> ...
> > Cool thanks. So based on that code I've chopped out the following function:
> > 
> > function get_path:string (dentry:dentry *,vsmnt:vsmount *) %{
> >   char *page = (char *)__get_free_page(GFP_KERNEL);
> >   sprintf("%s",d_path(dentry, vfsmnt, page, PAGE_SIZE));
> >   free_page((unsigned long)page);
> > %}
> 
> Keep in mind that a handler mustn't sleep, so you should use GFP_ATOMIC
> rather than GFP_KERNEL.

Thanks. I'd be lying if I said I understood the distinction.  Can anyone
reccommend a book/site to help a sysadmin familiar with C get up to speed on
the kernel internals?
 
> And yeah, the dentry and vsmnt args should be declared long and cast to
> the appropriate pointer types.

So below is the resultant (fully operational) function.  Hopefully this
is resonably safe to use?  

function get_path:string (da:long, va:long) %{
  char *page = (char *)__get_free_page(GFP_ATOMIC);
  struct dentry *dentry = (struct dentry *)((long)THIS->da);
  struct vfsmount *vfsmnt = (struct vfsmount *)((long)THIS->va);
  snprintf(THIS->__retvalue, MAXSTRINGLEN, "%s", d_path(dentry, vfsmnt, page, PAGE_SIZE));
  free_page((unsigned long)page);
%}

Thanks again guys, you rock.

--dave


> > ... 
> > 
> > Thanks
> > 
> > --dave
> 
> Jim Keniston
> 

[-- Attachment #2: Type: application/pgp-signature, Size: 187 bytes --]

^ permalink raw reply	[flat|nested] 11+ messages in thread

* Re: dereferencing filenames from a vfs_write probe
  2008-03-20 21:04         ` dave
@ 2008-03-21  0:19           ` Jim Keniston
  2008-03-21  4:31             ` Ananth N Mavinakayanahalli
  0 siblings, 1 reply; 11+ messages in thread
From: Jim Keniston @ 2008-03-21  0:19 UTC (permalink / raw)
  To: dave; +Cc: systemtap

On Thu, 2008-03-20 at 16:04 -0500, dave@skeptech.org wrote:
...
> > 
> > Keep in mind that a handler mustn't sleep, so you should use GFP_ATOMIC
> > rather than GFP_KERNEL.
> 
> Thanks. I'd be lying if I said I understood the distinction.  Can anyone
> reccommend a book/site to help a sysadmin familiar with C get up to speed on
> the kernel internals?

Don't ask me about books.  I'm still using "Understanding the Linux
Kernel" by Boven & Cesati (published by O'Reilly).  The edition I have
on hand is old -- each chapter has a section called "Anticipating Linux
2.4" -- but much of the info is still relevant.

In the kernel source, cd Documentation, and fire away with ls, find, and
grep.  On the web, www.kroah.com/linux has some good stuff.
http://kernelnewbies.org is another possibility.

>  
> > And yeah, the dentry and vsmnt args should be declared long and cast to
> > the appropriate pointer types.
> 
> So below is the resultant (fully operational) function.  Hopefully this
> is resonably safe to use?  
> 
> function get_path:string (da:long, va:long) %{
>   char *page = (char *)__get_free_page(GFP_ATOMIC);
>   struct dentry *dentry = (struct dentry *)((long)THIS->da);
>   struct vfsmount *vfsmnt = (struct vfsmount *)((long)THIS->va);
>   snprintf(THIS->__retvalue, MAXSTRINGLEN, "%s", d_path(dentry, vfsmnt, page, PAGE_SIZE));
>   free_page((unsigned long)page);
> %}

That looks correct to me.

> 
> Thanks again guys, you rock.

This will be news to my children. :-)

> 
> --dave

Jim

^ permalink raw reply	[flat|nested] 11+ messages in thread

* Re: dereferencing filenames from a vfs_write probe
  2008-03-21  0:19           ` Jim Keniston
@ 2008-03-21  4:31             ` Ananth N Mavinakayanahalli
  0 siblings, 0 replies; 11+ messages in thread
From: Ananth N Mavinakayanahalli @ 2008-03-21  4:31 UTC (permalink / raw)
  To: Jim Keniston; +Cc: dave, systemtap

On Thu, Mar 20, 2008 at 05:14:30PM -0700, Jim Keniston wrote:
> On Thu, 2008-03-20 at 16:04 -0500, dave@skeptech.org wrote:
> ...
> > > 
> > > Keep in mind that a handler mustn't sleep, so you should use GFP_ATOMIC
> > > rather than GFP_KERNEL.
> > 
> > Thanks. I'd be lying if I said I understood the distinction.  Can anyone
> > reccommend a book/site to help a sysadmin familiar with C get up to speed on
> > the kernel internals?
> 
> Don't ask me about books.  I'm still using "Understanding the Linux
> Kernel" by Boven & Cesati (published by O'Reilly).  The edition I have
> on hand is old -- each chapter has a section called "Anticipating Linux
> 2.4" -- but much of the info is still relevant.
> 
> In the kernel source, cd Documentation, and fire away with ls, find, and
> grep.  On the web, www.kroah.com/linux has some good stuff.
> http://kernelnewbies.org is another possibility.

The latest edition of Linux Kernel Programming by Robert Love is a good
reference.

Also, Linux Device Drivers 3rd edition, available for free at
http://lwn.net/Kernel/LDD3/.

Ananth

^ permalink raw reply	[flat|nested] 11+ messages in thread

end of thread, other threads:[~2008-03-21  4:31 UTC | newest]

Thread overview: 11+ messages (download: mbox.gz / follow: Atom feed)
-- links below jump to the message on this page --
     [not found] <1205982759.13969.ezmlm@sourceware.org>
2008-03-20  3:37 ` dereferencing filenames from a vfs_write probe dave-systemtap
2008-03-20  4:18   ` Eugene Teo
2008-03-20 16:02     ` Stone, Joshua I
2008-03-20 17:25     ` dave-systemtap
2008-03-20 17:48       ` Frank Ch. Eigler
2008-03-20 18:06       ` Jim Keniston
2008-03-20 21:04         ` dave
2008-03-21  0:19           ` Jim Keniston
2008-03-21  4:31             ` Ananth N Mavinakayanahalli
2008-03-20  4:42   ` Ananth N Mavinakayanahalli
2008-03-20 12:05     ` Eugene Teo

This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox;
as well as URLs for read-only IMAP folder(s) and NNTP newsgroup(s).