Skip to content

Commit

Permalink
Implementation of two new "files" command options. The "files -c"
Browse files Browse the repository at this point in the history
option is context-sensitive, similar to the the regular "files"
command when used without an argument, but replaces the FILE and
DENTRY columns with I_MAPPING and NRPAGES columns that reflect
each open file's inode.i_mapping address_space structure address,
and the address_space.nrpages count within it; this shows how
many of each open file's pages are currently in the system's
page cache.  The "files -p <inode>" option takes the address
of an inode, and dumps all of its pages that are currently in the
system's page cache, borrowing the "kmem -p" page structure output.
(yangoliver@gmail.com)
  • Loading branch information
Dave Anderson committed Jul 2, 2015
1 parent 7a2ff13 commit 3106fee
Show file tree
Hide file tree
Showing 6 changed files with 256 additions and 34 deletions.
14 changes: 10 additions & 4 deletions defs.h
Expand Up @@ -1940,6 +1940,7 @@ struct offset_table { /* stash of commonly-used offsets */
long task_struct_thread_reg31;
long pt_regs_regs;
long pt_regs_cp0_badvaddr;
long address_space_page_tree;
};

struct size_table { /* stash of commonly-used sizes */
Expand Down Expand Up @@ -2598,6 +2599,7 @@ struct load_module {
#define PRINT_SINGLE_VMA (0x80)
#define PRINT_RADIX_10 (0x100)
#define PRINT_RADIX_16 (0x200)
#define PRINT_NRPAGES (0x400)

#define MIN_PAGE_SIZE (4096)

Expand Down Expand Up @@ -4707,6 +4709,8 @@ void alter_stackbuf(struct bt_info *);
int vaddr_type(ulong, struct task_context *);
char *format_stack_entry(struct bt_info *bt, char *, ulong, ulong);
int in_user_stack(ulong, ulong);
int dump_inode_page(ulong);


/*
* filesys.c
Expand Down Expand Up @@ -4743,16 +4747,18 @@ int is_readable(char *);
#define RADIX_TREE_SEARCH (2)
#define RADIX_TREE_DUMP (3)
#define RADIX_TREE_GATHER (4)
#define RADIX_TREE_DUMP_CB (5)
struct radix_tree_pair {
ulong index;
void *value;
};
ulong do_radix_tree(ulong, int, struct radix_tree_pair *);
int file_dump(ulong, ulong, ulong, int, int);
#define DUMP_FULL_NAME 1
#define DUMP_INODE_ONLY 2
#define DUMP_DENTRY_ONLY 4
#define DUMP_EMPTY_FILE 8
#define DUMP_FULL_NAME 0x1
#define DUMP_INODE_ONLY 0x2
#define DUMP_DENTRY_ONLY 0x4
#define DUMP_EMPTY_FILE 0x8
#define DUMP_FILE_NRPAGES 0x10
#endif /* !GDB_COMMON */
int same_file(char *, char *);
#ifndef GDB_COMMON
Expand Down
197 changes: 173 additions & 24 deletions filesys.c
Expand Up @@ -49,7 +49,8 @@ static void *radix_tree_lookup(ulong, ulong, int);
static int match_file_string(char *, char *, char *);
static ulong get_root_vfsmount(char *);
static void check_live_arch_mismatch(void);

static long get_inode_nrpages(ulong);
static void dump_inode_page_cache_info(ulong);

#define DENTRY_CACHE (20)
#define INODE_CACHE (20)
Expand Down Expand Up @@ -2167,6 +2168,70 @@ dump_filesys_table(int verbose)
}
}

/*
* Get the page count for the specific mapping
*/
static long
get_inode_nrpages(ulong i_mapping)
{
char *address_space_buf;
ulong nrpages;

address_space_buf = GETBUF(SIZE(address_space));

readmem(i_mapping, KVADDR, address_space_buf,
SIZE(address_space), "address_space buffer",
FAULT_ON_ERROR);
nrpages = ULONG(address_space_buf + OFFSET(address_space_nrpages));

FREEBUF(address_space_buf);

return nrpages;
}

static void
dump_inode_page_cache_info(ulong inode)
{
char *inode_buf;
ulong i_mapping, nrpages, root_rnode, count;
struct radix_tree_pair rtp;
char header[BUFSIZE];
char buf1[BUFSIZE];
char buf2[BUFSIZE];

inode_buf = GETBUF(SIZE(inode));
readmem(inode, KVADDR, inode_buf, SIZE(inode), "inode buffer",
FAULT_ON_ERROR);

i_mapping = ULONG(inode_buf + OFFSET(inode_i_mapping));
nrpages = get_inode_nrpages(i_mapping);

sprintf(header, "%s NRPAGES\n",
mkstring(buf1, VADDR_PRLEN, CENTER|LJUST, "INODE"));
fprintf(fp, "%s", header);

fprintf(fp, "%s %s\n\n",
mkstring(buf1, VADDR_PRLEN,
CENTER|RJUST|LONG_HEX,
MKSTR(inode)),
mkstring(buf2, strlen("NRPAGES"),
RJUST|LONG_DEC,
MKSTR(nrpages)));

root_rnode = i_mapping + OFFSET(address_space_page_tree);
rtp.index = 0;
rtp.value = (void *)&dump_inode_page;

count = do_radix_tree(root_rnode, RADIX_TREE_DUMP_CB, &rtp);

if (count != nrpages)
error(INFO, "page_tree count: %ld nrpages: %ld\n",
count, nrpages);

FREEBUF(inode_buf);
return;
}

/*
* This command displays information about the open files of a context.
* For each open file descriptor the file descriptor number, a pointer
Expand All @@ -2187,11 +2252,12 @@ cmd_files(void)
int subsequent;
struct reference reference, *ref;
char *refarg;
int open_flags = 0;

ref = NULL;
refarg = NULL;

while ((c = getopt(argcnt, args, "d:R:")) != EOF) {
while ((c = getopt(argcnt, args, "d:R:p:c")) != EOF) {
switch(c)
{
case 'R':
Expand All @@ -2210,6 +2276,23 @@ cmd_files(void)
display_dentry_info(value);
return;

case 'p':
if (VALID_MEMBER(address_space_page_tree) &&
VALID_MEMBER(inode_i_mapping)) {
value = htol(optarg, FAULT_ON_ERROR, NULL);
dump_inode_page_cache_info(value);
} else
option_not_supported('p');
return;

case 'c':
if (VALID_MEMBER(address_space_page_tree) &&
VALID_MEMBER(inode_i_mapping))
open_flags |= PRINT_NRPAGES;
else
option_not_supported('c');
break;

default:
argerrs++;
break;
Expand All @@ -2222,7 +2305,9 @@ cmd_files(void)
if (!args[optind]) {
if (!ref)
print_task_header(fp, CURRENT_CONTEXT(), 0);
open_files_dump(CURRENT_TASK(), 0, ref);

open_files_dump(CURRENT_TASK(), open_flags, ref);

return;
}

Expand All @@ -2241,15 +2326,15 @@ cmd_files(void)
for (tc = pid_to_context(value); tc; tc = tc->tc_next) {
if (!ref)
print_task_header(fp, tc, subsequent);
open_files_dump(tc->task, 0, ref);
open_files_dump(tc->task, open_flags, ref);
fprintf(fp, "\n");
}
break;

case STR_TASK:
if (!ref)
print_task_header(fp, tc, subsequent);
open_files_dump(tc->task, 0, ref);
open_files_dump(tc->task, open_flags, ref);
break;

case STR_INVALID:
Expand Down Expand Up @@ -2321,6 +2406,7 @@ open_files_dump(ulong task, int flags, struct reference *ref)
char buf4[BUFSIZE];
char root_pwd[BUFSIZE];
int root_pwd_printed = 0;
int file_dump_flags = 0;

BZERO(root_pathname, BUFSIZE);
BZERO(pwd_pathname, BUFSIZE);
Expand All @@ -2329,15 +2415,27 @@ open_files_dump(ulong task, int flags, struct reference *ref)
fdtable_buf = GETBUF(SIZE(fdtable));
fill_task_struct(task);

sprintf(files_header, " FD%s%s%s%s%s%s%sTYPE%sPATH\n",
space(MINSPACE),
mkstring(buf1, VADDR_PRLEN, CENTER|LJUST, "FILE"),
space(MINSPACE),
mkstring(buf2, VADDR_PRLEN, CENTER|LJUST, "DENTRY"),
space(MINSPACE),
mkstring(buf3, VADDR_PRLEN, CENTER|LJUST, "INODE"),
space(MINSPACE),
space(MINSPACE));
if (flags & PRINT_NRPAGES) {
sprintf(files_header, " FD%s%s%s%s%sNRPAGES%sTYPE%sPATH\n",
space(MINSPACE),
mkstring(buf1, VADDR_PRLEN, CENTER|LJUST, "INODE"),
space(MINSPACE),
mkstring(buf2, MAX(VADDR_PRLEN, strlen("I_MAPPING")),
BITS32() ? (CENTER|RJUST) : (CENTER|LJUST), "I_MAPPING"),
space(MINSPACE),
space(MINSPACE),
space(MINSPACE));
} else {
sprintf(files_header, " FD%s%s%s%s%s%s%sTYPE%sPATH\n",
space(MINSPACE),
mkstring(buf1, VADDR_PRLEN, CENTER|LJUST, "FILE"),
space(MINSPACE),
mkstring(buf2, VADDR_PRLEN, CENTER|LJUST, "DENTRY"),
space(MINSPACE),
mkstring(buf3, VADDR_PRLEN, CENTER|LJUST, "INODE"),
space(MINSPACE),
space(MINSPACE));
}

tc = task_to_context(task);

Expand Down Expand Up @@ -2523,6 +2621,10 @@ open_files_dump(ulong task, int flags, struct reference *ref)
return;
}

file_dump_flags = DUMP_FULL_NAME | DUMP_EMPTY_FILE;
if (flags & PRINT_NRPAGES)
file_dump_flags |= DUMP_FILE_NRPAGES;

j = 0;
for (;;) {
unsigned long set;
Expand All @@ -2539,8 +2641,7 @@ open_files_dump(ulong task, int flags, struct reference *ref)

if (ref && file) {
open_tmpfile();
if (file_dump(file, 0, 0, i,
DUMP_FULL_NAME|DUMP_EMPTY_FILE)) {
if (file_dump(file, 0, 0, i, file_dump_flags)) {
BZERO(buf4, BUFSIZE);
rewind(pc->tmpfile);
ret = fgets(buf4, BUFSIZE,
Expand All @@ -2558,8 +2659,7 @@ open_files_dump(ulong task, int flags, struct reference *ref)
fprintf(fp, "%s", files_header);
header_printed = 1;
}
file_dump(file, 0, 0, i,
DUMP_FULL_NAME|DUMP_EMPTY_FILE);
file_dump(file, 0, 0, i, file_dump_flags);
}
}
i++;
Expand Down Expand Up @@ -2754,6 +2854,8 @@ file_dump(ulong file, ulong dentry, ulong inode, int fd, int flags)
char buf1[BUFSIZE];
char buf2[BUFSIZE];
char buf3[BUFSIZE];
ulong i_mapping = 0;
ulong nrpages = 0;

file_buf = NULL;

Expand Down Expand Up @@ -2863,6 +2965,28 @@ file_dump(ulong file, ulong dentry, ulong inode, int fd, int flags)
type,
space(MINSPACE),
pathname+1);
} else if (flags & DUMP_FILE_NRPAGES) {
i_mapping = ULONG(inode_buf + OFFSET(inode_i_mapping));
nrpages = get_inode_nrpages(i_mapping);

fprintf(fp, "%3d%s%s%s%s%s%s%s%s%s%s\n",
fd,
space(MINSPACE),
mkstring(buf1, VADDR_PRLEN,
CENTER|RJUST|LONG_HEX,
MKSTR(inode)),
space(MINSPACE),
mkstring(buf2, MAX(VADDR_PRLEN, strlen("I_MAPPING")),
CENTER|RJUST|LONG_HEX,
MKSTR(i_mapping)),
space(MINSPACE),
mkstring(buf3, strlen("NRPAGES"),
RJUST|LONG_DEC,
MKSTR(nrpages)),
space(MINSPACE),
type,
space(MINSPACE),
pathname);
} else {
fprintf(fp, "%3d%s%s%s%s%s%s%s%s%s%s\n",
fd,
Expand Down Expand Up @@ -3870,13 +3994,18 @@ ulong RADIX_TREE_MAP_MASK = UNINITIALIZED;
* limit the number of returned entries by putting the array size
* (max count) in the rtp->index field of the first structure
* in the passed-in array.
* RADIX_TREE_DUMP_CB - Similar with RADIX_TREE_DUMP, but for each
* radix tree entry, a user defined callback at rtp->value will
* be invoked.
*
* rtp: Unused by RADIX_TREE_COUNT and RADIX_TREE_DUMP.
* A pointer to a radix_tree_pair structure for RADIX_TREE_SEARCH.
* A pointer to an array of radix_tree_pair structures for
* RADIX_TREE_GATHER; the dimension (max count) of the array may
* be stored in the index field of the first structure to avoid
* any chance of an overrun.
* For RADIX_TREE_DUMP_CB, the rtp->value must be initialized as a
* callback function. The callback prototype must be: int (*)(ulong);
*/
ulong
do_radix_tree(ulong root, int flag, struct radix_tree_pair *rtp)
Expand All @@ -3889,6 +4018,7 @@ do_radix_tree(ulong root, int flag, struct radix_tree_pair *rtp)
struct radix_tree_pair *r;
ulong root_rnode;
void *ret;
int (*cb)(ulong) = NULL;

count = 0;

Expand Down Expand Up @@ -3932,14 +4062,13 @@ do_radix_tree(ulong root, int flag, struct radix_tree_pair *rtp)
"radix_tree_root", FAULT_ON_ERROR);
height = UINT(radix_tree_root_buf + OFFSET(radix_tree_root_height));

if (height > ilen) {
fprintf(fp, "radix_tree_root at %lx:\n", root);
if ((height < 0) || (height > ilen)) {
error(INFO, "height_to_maxindex[] index: %ld\n", ilen);
fprintf(fp, "invalid height in radix_tree_root at %lx:\n", root);
dump_struct("radix_tree_root", (ulong)root, RADIX(16));
error(FATAL,
"height %d is greater than height_to_maxindex[] index %ld\n",
height, ilen);
return 0;
}

maxindex = height_to_maxindex[height];
FREEBUF(height_to_maxindex);
FREEBUF(radix_tree_root_buf);
Expand Down Expand Up @@ -3993,6 +4122,26 @@ do_radix_tree(ulong root, int flag, struct radix_tree_pair *rtp)
}
break;

case RADIX_TREE_DUMP_CB:
if (rtp->value == NULL) {
error(FATAL, "do_radix_tree: need set callback function");
return -EINVAL;
}
cb = (int (*)(ulong))rtp->value;
for (index = count = 0; index <= maxindex; index++) {
if ((ret =
radix_tree_lookup(root_rnode, index, height))) {
/* Caller defined operation */
if (!cb((ulong)ret)) {
error(FATAL, "do_radix_tree: callback "
"operation failed: entry: %ld item: %lx\n",
count, (ulong)ret);
}
count++;
}
}
break;

default:
error(FATAL, "do_radix_tree: invalid flag: %lx\n", flag);
}
Expand Down

0 comments on commit 3106fee

Please sign in to comment.