/*
 * Copyright (C) 2000-2002 ASANO Masahiro
 */

#include <unistd.h>
#include "crash.h"

PRIVATE addr_t operations();
const commandtable_t command_operations =
	{"operations", operations, "-a|-b|-d|-f|-i|-s|-q|-v address", "print address_space, block_device, dentry, file, inode, super, dquot or vm operations"};

PRIVATE const char *address_space_op[] = {
	"ADDRESS SPACE OPERATIONS",
	"writepage", "readpage", "sync_page", "prepare_write", "commit_write",
	"bmap",
#if SUBLEVEL>=15
	"flushpage", "releaspage", "direct_IO",
#endif
	NULL
};

PRIVATE const char *block_device_op[] = {
	"BLOCK DEVICE OPERATIONS",
	"open", "release", "ioctl", "check_media_change", "revalidate",
	NULL
};

PRIVATE const char *file_op[] = {
	"FILE OPERATIONS",
	"owner",
	"llseek", "read", "write", "readdir", "poll", "ioctl", "mmap",
	"open", "flush", "release", "fsync", "fasync", "lock",
	"readv", "writev",
#if SUBLEVEL>=15
	"sendpage", "get_unmapped_area",
#endif
	NULL
};

PRIVATE const char *inode_op[] = {
	"INODE OPERATIONS",
	"create", "lookup", "link", "unlink", "symlink",
	"mkdir", "rmdir", "mknod", "rename", "readlink", "follow_link",
	"truncate", "permission", "revalidate", "setattr", "getattr",
	NULL
};

PRIVATE const char *super_op[] = {
	"SUPER OPERATIONS",
	"read_inode", "read_inode2", "dirty_inode", "write_inode", "put_inode",
	"delete_inode", "put_super", "write_super", "write_super_lockfs",
	"unlockfs", "statfs", "remount_fs", "clear_inode", "umount_begin",
#if SUBLEVEL>=15
	"fh_to_dentry", "dentry_to_fh",
#endif
	NULL
};

PRIVATE const char *dquot_op[] = {
	"DQUOT OPERATIONS",
	"initialize", "drop", "alloc_block", "alloc_inode", "free_block",
	"free_inode", "transfer",
	NULL
};

PRIVATE const char *dentry_op[] = {
	"DENTRY OPERATIONS",
	"revalidate", "hash", "compare", "delete", "release", "iput",
	NULL
};

PRIVATE const char *vm_op[] = {
	"VM OPERATIONS STRUCT",
	"open", "close", "nopage",
	NULL
};

const char head_operations[] = "%24s:   ADDRESS  SYMBOL\n";

void
print_operations(addr, op)
	addr_t addr;
	const char **op;
{
	addr_t buf[32];
	const char *p;
	int i;

	memread(addr, sizeof(buf), buf, "operations");
	mprintf(head_operations, op[0]);
	for (i = 1; op[i]; i++) {
		p = getsymstr(buf[i - 1]);
		mprintf("%24s:  " FPTR "  %s\n", op[i], buf[i - 1], p? p: "-");
	}
}

PRIVATE addr_t
operations()
{
	int i, c;
	const char **op = NULL;
	addr_t addr;

	while ((c = getopt(argcnt, args, "abdfiqsv")) != EOF) {
		switch (c) {
		case 'a':
			op = address_space_op;
			break;
		case 'b':
			op = block_device_op;
			break;
		case 'f':
			op = file_op;
			break;
		case 'i':
			op = inode_op;
			break;
		case 's':
			op = super_op;
			break;
		case 'q':
			op = dquot_op;
			break;
		case 'd':
			op = dentry_op;
			break;
		case 'v':
			op = vm_op;
			break;
		default:
			THROW(usage);
		}
	}
	if (op == NULL || optind == argcnt) {
		THROW(usage);
	}

	for (i = optind; i < argcnt; i++) {
		addr = getaddr(args[i]);
		print_operations(addr, op);
	}
	return 0;
}
