#define IOC_PORTAL_CLEAR_DEBUG _IOWR('e', 32, long)
#define IOC_PORTAL_MARK_DEBUG _IOWR('e', 33, long)
#define IOC_PORTAL_PANIC _IOWR('e', 34, long)
-#define IOC_PORTAL_ADD_ROUTE _IOWR('e', 35, long)
-#define IOC_PORTAL_DEL_ROUTE _IOWR('e', 36, long)
-#define IOC_PORTAL_GET_ROUTE _IOWR('e', 37, long)
-#define IOC_PORTAL_NAL_CMD _IOWR('e', 38, long)
-#define IOC_PORTAL_GET_NID _IOWR('e', 39, long)
-#define IOC_PORTAL_FAIL_NID _IOWR('e', 40, long)
-#define IOC_PORTAL_SET_DAEMON _IOWR('e', 41, long)
-#define IOC_PORTAL_NOTIFY_ROUTER _IOWR('e', 42, long)
-#define IOC_PORTAL_LWT_CONTROL _IOWR('e', 43, long)
-#define IOC_PORTAL_LWT_SNAPSHOT _IOWR('e', 44, long)
-#define IOC_PORTAL_LWT_LOOKUP_STRING _IOWR('e', 45, long)
-#define IOC_PORTAL_MAX_NR 45
+#define IOC_PORTAL_NAL_CMD _IOWR('e', 35, long)
+#define IOC_PORTAL_GET_NID _IOWR('e', 36, long)
+#define IOC_PORTAL_FAIL_NID _IOWR('e', 37, long)
+#define IOC_PORTAL_SET_DAEMON _IOWR('e', 38, long)
+#define IOC_PORTAL_LWT_CONTROL _IOWR('e', 39, long)
+#define IOC_PORTAL_LWT_SNAPSHOT _IOWR('e', 40, long)
+#define IOC_PORTAL_LWT_LOOKUP_STRING _IOWR('e', 41, long)
+#define IOC_PORTAL_MAX_NR 41
enum {
QSWNAL = 1,
#define NAL_CMD_ADD_AUTOCONN 106
#define NAL_CMD_GET_AUTOCONN 107
#define NAL_CMD_GET_TXDESC 108
+#define NAL_CMD_ADD_ROUTE 109
+#define NAL_CMD_DEL_ROUTE 110
+#define NAL_CMD_GET_ROUTE 111
+#define NAL_CMD_NOTIFY_ROUTER 112
enum {
DEBUG_DAEMON_START = 1,
journal_info = current->journal_info;
current->journal_info = NULL;
sprintf(debug_file_name, "%s.%ld", debug_file_path, CURRENT_SECONDS);
- file = filp_open(debug_file_name, O_CREAT|O_TRUNC|O_RDWR, 0644);
+ file = filp_open(debug_file_name, O_CREAT|O_EXCL|O_RDWR, 0644);
if (!file || IS_ERR(file)) {
CERROR("cannot open %s for dumping: %ld\n", debug_file_name,
return str;
}
+#ifdef __KERNEL__
+#include <linux/lustre_version.h>
+#if (LUSTRE_KERNEL_VERSION >= 30)
+#warning "FIXME: remove workaround when l30 is widely used"
char stack_backtrace[LUSTRE_TRACE_SIZE];
spinlock_t stack_backtrace_lock = SPIN_LOCK_UNLOCKED;
#if defined(__arch_um__)
-# warning in arch_um
extern int is_kernel_text_address(unsigned long addr);
char *buf = stack_backtrace;
char *pbuf = buf;
unsigned long *stack = (unsigned long *)&buf;
-
+
size = sprintf(pbuf, " Call Trace: ");
pbuf += size;
while (((long) stack & (THREAD_SIZE-1)) != 0) {
break;
}
}
-
+
return buf;
}
#elif defined(CONFIG_X86)
-# warning in __i386__
extern int is_kernel_text_address(unsigned long addr);
extern int lookup_symbol(unsigned long address, char *buf, int buflen);
char *portals_debug_dumpstack(void)
{
- unsigned long esp = current->thread.esp;
+ unsigned long esp = current->thread.esp;
unsigned long *stack = (unsigned long *)&esp;
int size;
unsigned long addr;
char *buf = stack_backtrace;
char *pbuf = buf;
static char buffer[512];
-
- /* User space on another CPU? */
- if ((esp ^ (unsigned long)current) & (PAGE_MASK<<1)){
- memset(buf, 0x0, LUSTRE_TRACE_SIZE);
+ int rc = 0;
+
+ /* User space on another CPU? */
+ if ((esp ^ (unsigned long)current) & (PAGE_MASK<<1)){
+ buf[0] = '\0';
goto out;
}
-
+
size = sprintf(pbuf, " Call Trace: ");
pbuf += size;
while (((long) stack & (THREAD_SIZE-1)) != 0) {
addr = *stack++;
if (is_kernel_text_address(addr)) {
- lookup_symbol(addr, buffer, 512);
- if (buf + LUSTRE_TRACE_SIZE
+ rc = lookup_symbol(addr, buffer, 512);
+ if (rc == -ENOSYS) {
+ if (buf + LUSTRE_TRACE_SIZE <= pbuf + 12)
+ break;
+ size = sprintf(pbuf, "[<%08lx>] ", addr);
+ } else {
+ if (buf + LUSTRE_TRACE_SIZE
/* fix length + sizeof('\0') */
- <= pbuf + strlen(buffer) + 28 + 1)
- break;
- size = sprintf(pbuf, "([<%08lx>] %s (0x%x)) ",
- addr, buffer, stack-1);
+ <= pbuf + strlen(buffer) + 28 + 1)
+ break;
+ size = sprintf(pbuf, "([<%08lx>] %s (0x%x)) ",
+ addr, buffer, stack-1);
+ }
pbuf += size;
}
}
char *portals_debug_dumpstack(void)
{
char *buf = stack_backtrace;
- memset(buf, 0x0, LUSTRE_TRACE_SIZE);
+ buf[0] = '\0';
return buf;
}
#endif /* __arch_um__ */
+EXPORT_SYMBOL(stack_backtrace_lock);
+EXPORT_SYMBOL(portals_debug_dumpstack);
+#endif /* LUSTRE_KERNEL_VERSION < 30 */
+#endif /* __KERNEL__ */
EXPORT_SYMBOL(portals_debug_dumplog);
EXPORT_SYMBOL(portals_debug_msg);
EXPORT_SYMBOL(portals_run_upcall);
EXPORT_SYMBOL(portals_run_lbug_upcall);
EXPORT_SYMBOL(portals_nid2str);
-EXPORT_SYMBOL(portals_debug_dumpstack);
-EXPORT_SYMBOL(stack_backtrace_lock);
ENTRY;
switch(pcfg->pcfg_command) {
- case IOC_PORTAL_ADD_ROUTE:
+ case NAL_CMD_ADD_ROUTE:
CDEBUG(D_IOCTL, "Adding route: [%d] "LPU64" : "LPU64" - "LPU64"\n",
pcfg->pcfg_nal, pcfg->pcfg_nid,
pcfg->pcfg_nid2, pcfg->pcfg_nid3);
pcfg->pcfg_nid2, pcfg->pcfg_nid3);
break;
- case IOC_PORTAL_DEL_ROUTE:
+ case NAL_CMD_DEL_ROUTE:
CDEBUG (D_IOCTL, "Removing routes via [%d] "LPU64" : "LPU64" - "LPU64"\n",
pcfg->pcfg_nal, pcfg->pcfg_nid,
pcfg->pcfg_nid2, pcfg->pcfg_nid3);
pcfg->pcfg_nid2, pcfg->pcfg_nid3);
break;
- case IOC_PORTAL_NOTIFY_ROUTER: {
+ case NAL_CMD_NOTIFY_ROUTER: {
CDEBUG (D_IOCTL, "Notifying peer [%d] "LPU64" %s @ %ld\n",
pcfg->pcfg_nal, pcfg->pcfg_nid,
pcfg->pcfg_flags ? "Enabling" : "Disabling",
break;
}
- case IOC_PORTAL_GET_ROUTE:
+ case NAL_CMD_GET_ROUTE:
CDEBUG (D_IOCTL, "Getting route [%d]\n", pcfg->pcfg_count);
err = kportal_get_route(pcfg->pcfg_count, &pcfg->pcfg_nal,
&pcfg->pcfg_nid,
ENTRY;
+ if (current->fsuid != 0)
+ RETURN(err = -EACCES);
+
if ( _IOC_TYPE(cmd) != IOC_PORTAL_TYPE ||
_IOC_NR(cmd) < IOC_PORTAL_MIN_NR ||
_IOC_NR(cmd) > IOC_PORTAL_MAX_NR ) {
}
#ifndef __CYGWIN__
-# warning FIXME: cleanup fstat issue here
# ifndef SYS_fstat64
# define __SYS_fstat__ SYS_fstat
# else
-# define __SYS_fstat__ SYS_fstat64
-#endif
+# define __SYS_fstat__ SYS_fstat64
+# endif
rc = syscall(__SYS_fstat__, fd, &statbuf);
#else
rc = fstat(fd, &statbuf);
#ifndef __CYGWIN__
fd = syscall(SYS_open, dump_file, O_RDONLY);
-#warning FIXME: cleanup fstat issue here
#ifndef SYS_fstat64
# define __SYS_fstat__ SYS_fstat
#else
#define _PARSER_H_
#define HISTORY 100 /* Don't let history grow unbounded */
-#define MAXARGS 100
+#define MAXARGS 512
#define CMD_COMPLETE 0
#define CMD_INCOMPLETE 1
return (-1);
}
- PCFG_INIT(pcfg, IOC_PORTAL_ADD_ROUTE);
+ PCFG_INIT(pcfg, NAL_CMD_ADD_ROUTE);
pcfg.pcfg_nid = gateway_nid;
pcfg.pcfg_nal = g_nal;
pcfg.pcfg_nid2 = MIN (nid1, nid2);
}
}
- PCFG_INIT(pcfg, IOC_PORTAL_DEL_ROUTE);
+ PCFG_INIT(pcfg, NAL_CMD_DEL_ROUTE);
pcfg.pcfg_nal = g_nal;
pcfg.pcfg_nid = nid;
pcfg.pcfg_nid2 = nid1;
return (-1);
}
- PCFG_INIT(pcfg, IOC_PORTAL_NOTIFY_ROUTER);
+ PCFG_INIT(pcfg, NAL_CMD_NOTIFY_ROUTER);
pcfg.pcfg_nal = g_nal;
pcfg.pcfg_nid = nid;
pcfg.pcfg_flags = enable;
for (index = 0;;index++)
{
- PCFG_INIT(pcfg, IOC_PORTAL_GET_ROUTE);
+ PCFG_INIT(pcfg, NAL_CMD_GET_ROUTE);
pcfg.pcfg_count = index;
rc = pcfg_ioctl(&pcfg);
--- /dev/null
+ fs/ext3/file.c | 4
+ fs/ext3/inode.c | 116 ++++++++++++++++++++++
+ fs/ext3/super.c | 230 +++++++++++++++++++++++++++++++++++++++++++++
+ include/linux/ext3_fs.h | 5
+ include/linux/ext3_fs_sb.h | 10 +
+ 5 files changed, 365 insertions(+)
+
+Index: linux-2.4.21-suse/fs/ext3/super.c
+===================================================================
+--- linux-2.4.21-suse.orig/fs/ext3/super.c 2003-10-30 02:03:04.000000000 +0300
++++ linux-2.4.21-suse/fs/ext3/super.c 2003-10-30 02:05:38.000000000 +0300
+@@ -400,6 +400,220 @@
+ }
+ }
+
++#ifdef EXT3_DELETE_THREAD
++/*
++ * Delete inodes in a loop until there are no more to be deleted.
++ * Normally, we run in the background doing the deletes and sleeping again,
++ * and clients just add new inodes to be deleted onto the end of the list.
++ * If someone is concerned about free space (e.g. block allocation or similar)
++ * then they can sleep on s_delete_waiter_queue and be woken up when space
++ * has been freed.
++ */
++int ext3_delete_thread(void *data)
++{
++ struct super_block *sb = data;
++ struct ext3_sb_info *sbi = EXT3_SB(sb);
++ struct task_struct *tsk = current;
++
++ /* Almost like daemonize, but not quite */
++ exit_mm(current);
++ tsk->session = 1;
++ tsk->pgrp = 1;
++ tsk->tty = NULL;
++ exit_files(current);
++ reparent_to_init();
++
++ sprintf(tsk->comm, "kdelext3-%s", kdevname(sb->s_dev));
++ sigfillset(&tsk->blocked);
++
++ /*tsk->flags |= PF_KERNTHREAD;*/
++
++ INIT_LIST_HEAD(&sbi->s_delete_list);
++ wake_up(&sbi->s_delete_waiter_queue);
++ ext3_debug("delete thread on %s started\n", kdevname(sb->s_dev));
++
++ /* main loop */
++ for (;;) {
++ wait_event_interruptible(sbi->s_delete_thread_queue,
++ !list_empty(&sbi->s_delete_list) ||
++ !test_opt(sb, ASYNCDEL));
++ ext3_debug("%s woken up: %lu inodes, %lu blocks\n",
++ tsk->comm,sbi->s_delete_inodes,sbi->s_delete_blocks);
++
++ spin_lock(&sbi->s_delete_lock);
++ if (list_empty(&sbi->s_delete_list)) {
++ clear_opt(sbi->s_mount_opt, ASYNCDEL);
++ memset(&sbi->s_delete_list, 0,
++ sizeof(sbi->s_delete_list));
++ spin_unlock(&sbi->s_delete_lock);
++ ext3_debug("delete thread on %s exiting\n",
++ kdevname(sb->s_dev));
++ wake_up(&sbi->s_delete_waiter_queue);
++ break;
++ }
++
++ while (!list_empty(&sbi->s_delete_list)) {
++ struct inode *inode=list_entry(sbi->s_delete_list.next,
++ struct inode, i_dentry);
++ unsigned long blocks = inode->i_blocks >>
++ (inode->i_blkbits - 9);
++
++ list_del_init(&inode->i_dentry);
++ spin_unlock(&sbi->s_delete_lock);
++ ext3_debug("%s delete ino %lu blk %lu\n",
++ tsk->comm, inode->i_ino, blocks);
++
++ iput(inode);
++
++ spin_lock(&sbi->s_delete_lock);
++ sbi->s_delete_blocks -= blocks;
++ sbi->s_delete_inodes--;
++ }
++ if (sbi->s_delete_blocks != 0 || sbi->s_delete_inodes != 0) {
++ ext3_warning(sb, __FUNCTION__,
++ "%lu blocks, %lu inodes on list?\n",
++ sbi->s_delete_blocks,sbi->s_delete_inodes);
++ sbi->s_delete_blocks = 0;
++ sbi->s_delete_inodes = 0;
++ }
++ spin_unlock(&sbi->s_delete_lock);
++ wake_up(&sbi->s_delete_waiter_queue);
++ }
++
++ return 0;
++}
++
++static void ext3_start_delete_thread(struct super_block *sb)
++{
++ struct ext3_sb_info *sbi = EXT3_SB(sb);
++ int rc;
++
++ spin_lock_init(&sbi->s_delete_lock);
++ init_waitqueue_head(&sbi->s_delete_thread_queue);
++ init_waitqueue_head(&sbi->s_delete_waiter_queue);
++
++ if (!test_opt(sb, ASYNCDEL))
++ return;
++
++ rc = kernel_thread(ext3_delete_thread, sb, CLONE_VM | CLONE_FILES);
++ if (rc < 0)
++ printk(KERN_ERR "EXT3-fs: cannot start delete thread: rc %d\n",
++ rc);
++ else
++ wait_event(sbi->s_delete_waiter_queue, sbi->s_delete_list.next);
++}
++
++static void ext3_stop_delete_thread(struct ext3_sb_info *sbi)
++{
++ if (sbi->s_delete_list.next == 0) /* thread never started */
++ return;
++
++ clear_opt(sbi->s_mount_opt, ASYNCDEL);
++ wake_up(&sbi->s_delete_thread_queue);
++ wait_event(sbi->s_delete_waiter_queue, list_empty(&sbi->s_delete_list));
++}
++
++/* Instead of playing games with the inode flags, destruction, etc we just
++ * create a new inode locally and put it on a list for the truncate thread.
++ * We need large parts of the inode struct in order to complete the
++ * truncate and unlink, so we may as well just have a real inode to do it.
++ *
++ * If we have any problem deferring the delete, just delete it right away.
++ * If we defer it, we also mark how many blocks it would free, so that we
++ * can keep the statfs data correct, and we know if we should sleep on the
++ * delete thread when we run out of space.
++ */
++static void ext3_delete_inode_thread(struct inode *old_inode)
++{
++ struct ext3_sb_info *sbi = EXT3_SB(old_inode->i_sb);
++ struct ext3_inode_info *nei, *oei = EXT3_I(old_inode);
++ struct inode *new_inode;
++ unsigned long blocks = old_inode->i_blocks >> (old_inode->i_blkbits-9);
++
++ if (is_bad_inode(old_inode)) {
++ clear_inode(old_inode);
++ return;
++ }
++
++ if (!test_opt(old_inode->i_sb, ASYNCDEL) || !sbi->s_delete_list.next)
++ goto out_delete;
++
++ /* We may want to delete the inode immediately and not defer it */
++ if (IS_SYNC(old_inode) || blocks <= EXT3_NDIR_BLOCKS)
++ goto out_delete;
++
++ /* We can't use the delete thread as-is during real orphan recovery,
++ * as we add to the orphan list here, causing ext3_orphan_cleanup()
++ * to loop endlessly. It would be nice to do so, but needs work.
++ */
++ if (oei->i_state & EXT3_STATE_DELETE ||
++ sbi->s_mount_state & EXT3_ORPHAN_FS) {
++ ext3_debug("doing deferred inode %lu delete (%lu blocks)\n",
++ old_inode->i_ino, blocks);
++ goto out_delete;
++ }
++
++ /* We can iget this inode again here, because our caller has unhashed
++ * old_inode, so new_inode will be in a different inode struct.
++ *
++ * We need to ensure that the i_orphan pointers in the other inodes
++ * point at the new inode copy instead of the old one so the orphan
++ * list doesn't get corrupted when the old orphan inode is freed.
++ */
++ down(&sbi->s_orphan_lock);
++
++ sbi->s_mount_state |= EXT3_ORPHAN_FS;
++ new_inode = iget(old_inode->i_sb, old_inode->i_ino);
++ sbi->s_mount_state &= ~EXT3_ORPHAN_FS;
++ if (is_bad_inode(new_inode)) {
++ printk(KERN_WARNING "read bad inode %lu\n", old_inode->i_ino);
++ iput(new_inode);
++ new_inode = NULL;
++ }
++ if (!new_inode) {
++ up(&sbi->s_orphan_lock);
++ ext3_debug("delete inode %lu directly (bad read)\n",
++ old_inode->i_ino);
++ goto out_delete;
++ }
++ J_ASSERT(new_inode != old_inode);
++
++ J_ASSERT(!list_empty(&oei->i_orphan));
++
++ nei = EXT3_I(new_inode);
++ /* Ugh. We need to insert new_inode into the same spot on the list
++ * as old_inode was, to ensure the in-memory orphan list is still
++ * in the same order as the on-disk orphan list (badness otherwise).
++ */
++ nei->i_orphan = oei->i_orphan;
++ nei->i_orphan.next->prev = &nei->i_orphan;
++ nei->i_orphan.prev->next = &nei->i_orphan;
++ nei->i_state |= EXT3_STATE_DELETE;
++ up(&sbi->s_orphan_lock);
++
++ clear_inode(old_inode);
++
++ spin_lock(&sbi->s_delete_lock);
++ J_ASSERT(list_empty(&new_inode->i_dentry));
++ list_add_tail(&new_inode->i_dentry, &sbi->s_delete_list);
++ sbi->s_delete_blocks += blocks;
++ sbi->s_delete_inodes++;
++ spin_unlock(&sbi->s_delete_lock);
++
++ ext3_debug("delete inode %lu (%lu blocks) by thread\n",
++ new_inode->i_ino, blocks);
++
++ wake_up(&sbi->s_delete_thread_queue);
++ return;
++
++out_delete:
++ ext3_delete_inode(old_inode);
++}
++#else
++#define ext3_start_delete_thread(sbi) do {} while(0)
++#define ext3_stop_delete_thread(sbi) do {} while(0)
++#endif /* EXT3_DELETE_THREAD */
++
+ void ext3_put_super (struct super_block * sb)
+ {
+ struct ext3_sb_info *sbi = EXT3_SB(sb);
+@@ -407,6 +621,7 @@
+ kdev_t j_dev = sbi->s_journal->j_dev;
+ int i;
+
++ ext3_stop_delete_thread(sbi);
+ ext3_xattr_put_super(sb);
+ journal_destroy(sbi->s_journal);
+ if (!(sb->s_flags & MS_RDONLY)) {
+@@ -455,7 +670,11 @@
+ write_inode: ext3_write_inode, /* BKL not held. Don't need */
+ dirty_inode: ext3_dirty_inode, /* BKL not held. We take it */
+ put_inode: ext3_put_inode, /* BKL not held. Don't need */
++#ifdef EXT3_DELETE_THREAD
++ delete_inode: ext3_delete_inode_thread,/* BKL not held. We take it */
++#else
+ delete_inode: ext3_delete_inode, /* BKL not held. We take it */
++#endif
+ put_super: ext3_put_super, /* BKL held */
+ write_super: ext3_write_super, /* BKL held */
+ sync_fs: ext3_sync_fs,
+@@ -524,6 +743,13 @@
+ clear_opt (*mount_options, XATTR_USER);
+ else
+ #endif
++#ifdef EXT3_DELETE_THREAD
++ if (!strcmp(this_char, "asyncdel"))
++ set_opt(*mount_options, ASYNCDEL);
++ else if (!strcmp(this_char, "noasyncdel"))
++ clear_opt(*mount_options, ASYNCDEL);
++ else
++#endif
+ if (!strcmp (this_char, "bsddf"))
+ clear_opt (*mount_options, MINIX_DF);
+ else if (!strcmp (this_char, "nouid32")) {
+@@ -1223,6 +1449,7 @@
+ }
+
+ ext3_setup_super (sb, es, sb->s_flags & MS_RDONLY);
++ ext3_start_delete_thread(sb);
+ /*
+ * akpm: core read_super() calls in here with the superblock locked.
+ * That deadlocks, because orphan cleanup needs to lock the superblock
+@@ -1678,6 +1905,9 @@
+ if (!parse_options(data, &tmp, sbi, &tmp, 1))
+ return -EINVAL;
+
++ if (!test_opt(sb, ASYNCDEL) || (*flags & MS_RDONLY))
++ ext3_stop_delete_thread(sbi);
++
+ if (sbi->s_mount_opt & EXT3_MOUNT_ABORT)
+ ext3_abort(sb, __FUNCTION__, "Abort forced by user");
+
+Index: linux-2.4.21-suse/fs/ext3/inode.c
+===================================================================
+--- linux-2.4.21-suse.orig/fs/ext3/inode.c 2003-10-30 02:03:57.000000000 +0300
++++ linux-2.4.21-suse/fs/ext3/inode.c 2003-10-30 02:05:38.000000000 +0300
+@@ -2552,6 +2552,118 @@
+ return err;
+ }
+
++#ifdef EXT3_DELETE_THREAD
++/* Move blocks from to-be-truncated inode over to a new inode, and delete
++ * that one from the delete thread instead. This avoids a lot of latency
++ * when truncating large files.
++ *
++ * If we have any problem deferring the truncate, just truncate it right away.
++ * If we defer it, we also mark how many blocks it would free, so that we
++ * can keep the statfs data correct, and we know if we should sleep on the
++ * delete thread when we run out of space.
++ */
++void ext3_truncate_thread(struct inode *old_inode)
++{
++ struct ext3_sb_info *sbi = EXT3_SB(old_inode->i_sb);
++ struct ext3_inode_info *nei, *oei = EXT3_I(old_inode);
++ struct inode *new_inode;
++ handle_t *handle;
++ unsigned long blocks = old_inode->i_blocks >> (old_inode->i_blkbits-9);
++
++ if (!test_opt(old_inode->i_sb, ASYNCDEL) || !sbi->s_delete_list.next)
++ goto out_truncate;
++
++ /* XXX This is a temporary limitation for code simplicity.
++ * We could truncate to arbitrary sizes at some later time.
++ */
++ if (old_inode->i_size != 0)
++ goto out_truncate;
++
++ /* We may want to truncate the inode immediately and not defer it */
++ if (IS_SYNC(old_inode) || blocks <= EXT3_NDIR_BLOCKS ||
++ old_inode->i_size > oei->i_disksize)
++ goto out_truncate;
++
++ /* We can't use the delete thread as-is during real orphan recovery,
++ * as we add to the orphan list here, causing ext3_orphan_cleanup()
++ * to loop endlessly. It would be nice to do so, but needs work.
++ */
++ if (oei->i_state & EXT3_STATE_DELETE ||
++ sbi->s_mount_state & EXT3_ORPHAN_FS) {
++ ext3_debug("doing deferred inode %lu delete (%lu blocks)\n",
++ old_inode->i_ino, blocks);
++ goto out_truncate;
++ }
++
++ ext3_discard_prealloc(old_inode);
++
++ /* old_inode = 1
++ * new_inode = sb + GDT + ibitmap
++ * orphan list = 1 inode/superblock for add, 2 inodes for del
++ * quota files = 2 * EXT3_SINGLEDATA_TRANS_BLOCKS
++ */
++ handle = ext3_journal_start(old_inode, 7);
++ if (IS_ERR(handle))
++ goto out_truncate;
++
++ new_inode = ext3_new_inode(handle, old_inode, old_inode->i_mode);
++ if (IS_ERR(new_inode)) {
++ ext3_debug("truncate inode %lu directly (no new inodes)\n",
++ old_inode->i_ino);
++ goto out_journal;
++ }
++
++ nei = EXT3_I(new_inode);
++
++ down_write(&oei->truncate_sem);
++ new_inode->i_size = old_inode->i_size;
++ new_inode->i_blocks = old_inode->i_blocks;
++ new_inode->i_uid = old_inode->i_uid;
++ new_inode->i_gid = old_inode->i_gid;
++ new_inode->i_nlink = 0;
++
++ /* FIXME when we do arbitrary truncates */
++ old_inode->i_blocks = oei->i_file_acl ? old_inode->i_blksize / 512 : 0;
++ old_inode->i_mtime = old_inode->i_ctime = CURRENT_TIME;
++
++ memcpy(nei->i_data, oei->i_data, sizeof(nei->i_data));
++ memset(oei->i_data, 0, sizeof(oei->i_data));
++
++ nei->i_disksize = oei->i_disksize;
++ nei->i_state |= EXT3_STATE_DELETE;
++ up_write(&oei->truncate_sem);
++
++ if (ext3_orphan_add(handle, new_inode) < 0)
++ goto out_journal;
++
++ if (ext3_orphan_del(handle, old_inode) < 0) {
++ ext3_orphan_del(handle, new_inode);
++ iput(new_inode);
++ goto out_journal;
++ }
++
++ ext3_journal_stop(handle, old_inode);
++
++ spin_lock(&sbi->s_delete_lock);
++ J_ASSERT(list_empty(&new_inode->i_dentry));
++ list_add_tail(&new_inode->i_dentry, &sbi->s_delete_list);
++ sbi->s_delete_blocks += blocks;
++ sbi->s_delete_inodes++;
++ spin_unlock(&sbi->s_delete_lock);
++
++ ext3_debug("delete inode %lu (%lu blocks) by thread\n",
++ new_inode->i_ino, blocks);
++
++ wake_up(&sbi->s_delete_thread_queue);
++ return;
++
++out_journal:
++ ext3_journal_stop(handle, old_inode);
++out_truncate:
++ ext3_truncate(old_inode);
++}
++#endif /* EXT3_DELETE_THREAD */
++
+ /*
+ * On success, We end up with an outstanding reference count against
+ * iloc->bh. This _must_ be cleaned up later.
+Index: linux-2.4.21-suse/fs/ext3/file.c
+===================================================================
+--- linux-2.4.21-suse.orig/fs/ext3/file.c 2003-10-30 01:40:33.000000000 +0300
++++ linux-2.4.21-suse/fs/ext3/file.c 2003-10-30 02:05:38.000000000 +0300
+@@ -125,7 +125,11 @@
+ };
+
+ struct inode_operations ext3_file_inode_operations = {
++#ifdef EXT3_DELETE_THREAD
++ truncate: ext3_truncate_thread, /* BKL held */
++#else
+ truncate: ext3_truncate, /* BKL held */
++#endif
+ setattr: ext3_setattr, /* BKL held */
+ setxattr: ext3_setxattr, /* BKL held */
+ getxattr: ext3_getxattr, /* BKL held */
+Index: linux-2.4.21-suse/include/linux/ext3_fs.h
+===================================================================
+--- linux-2.4.21-suse.orig/include/linux/ext3_fs.h 2003-10-30 02:03:57.000000000 +0300
++++ linux-2.4.21-suse/include/linux/ext3_fs.h 2003-10-30 02:06:05.000000000 +0300
+@@ -193,6 +193,7 @@
+ */
+ #define EXT3_STATE_JDATA 0x00000001 /* journaled data exists */
+ #define EXT3_STATE_NEW 0x00000002 /* inode is newly created */
++#define EXT3_STATE_DELETE 0x00000010 /* deferred delete inode */
+
+ /*
+ * ioctl commands
+@@ -320,6 +321,7 @@
+ #define EXT3_MOUNT_UPDATE_JOURNAL 0x1000 /* Update the journal format */
+ #define EXT3_MOUNT_NO_UID32 0x2000 /* Disable 32-bit UIDs */
+ #define EXT3_MOUNT_XATTR_USER 0x4000 /* Extended user attributes */
++#define EXT3_MOUNT_ASYNCDEL 0x20000 /* Delayed deletion */
+
+ /* Compatibility, for having both ext2_fs.h and ext3_fs.h included at once */
+ #ifndef _LINUX_EXT2_FS_H
+@@ -697,6 +699,9 @@
+ extern void ext3_dirty_inode(struct inode *);
+ extern int ext3_change_inode_journal_flag(struct inode *, int);
+ extern void ext3_truncate (struct inode *);
++#ifdef EXT3_DELETE_THREAD
++extern void ext3_truncate_thread(struct inode *inode);
++#endif
+ extern void ext3_set_inode_flags(struct inode *);
+
+ /* ioctl.c */
+Index: linux-2.4.21-suse/include/linux/ext3_fs_sb.h
+===================================================================
+--- linux-2.4.21-suse.orig/include/linux/ext3_fs_sb.h 2003-10-30 02:03:04.000000000 +0300
++++ linux-2.4.21-suse/include/linux/ext3_fs_sb.h 2003-10-30 02:05:38.000000000 +0300
+@@ -29,6 +29,8 @@
+
+ #define EXT3_MAX_GROUP_LOADED 8
+
++#define EXT3_DELETE_THREAD
++
+ /*
+ * third extended-fs super-block data in memory
+ */
+@@ -76,6 +78,14 @@
+ struct timer_list turn_ro_timer; /* For turning read-only (crash simulation) */
+ wait_queue_head_t ro_wait_queue; /* For people waiting for the fs to go read-only */
+ #endif
++#ifdef EXT3_DELETE_THREAD
++ spinlock_t s_delete_lock;
++ struct list_head s_delete_list;
++ unsigned long s_delete_blocks;
++ unsigned long s_delete_inodes;
++ wait_queue_head_t s_delete_thread_queue;
++ wait_queue_head_t s_delete_waiter_queue;
++#endif
+ };
+
+ #endif /* _LINUX_EXT3_FS_SB */
-Index: linux-2.4.20/arch/um/kernel/Makefile
+Index: linux-2.4.20-uml/arch/um/kernel/Makefile
===================================================================
---- linux-2.4.20.orig/arch/um/kernel/Makefile 2003-11-07 15:54:41.000000000 +0800
-+++ linux-2.4.20/arch/um/kernel/Makefile 2003-11-07 15:57:08.000000000 +0800
+--- linux-2.4.20-uml.orig/arch/um/kernel/Makefile 2003-11-10 13:42:48.000000000 +0800
++++ linux-2.4.20-uml/arch/um/kernel/Makefile 2003-11-10 13:43:06.000000000 +0800
@@ -37,7 +37,8 @@
export-objs-$(CONFIG_GPROF) += gprof_syms.o
export-objs-$(CONFIG_GCOV) += gmon_syms.o
CFLAGS_user_syms.o = -D__AUTOCONF_INCLUDED__ $(DMODULES-y) $(DMODVERSIONS-y) \
-I/usr/include -I../include
-Index: linux-2.4.20/arch/um/kernel/sysrq.c
+Index: linux-2.4.20-uml/arch/um/kernel/sysrq.c
===================================================================
---- linux-2.4.20.orig/arch/um/kernel/sysrq.c 2003-11-07 15:54:41.000000000 +0800
-+++ linux-2.4.20/arch/um/kernel/sysrq.c 2003-11-07 16:02:48.000000000 +0800
+--- linux-2.4.20-uml.orig/arch/um/kernel/sysrq.c 2003-11-10 13:42:49.000000000 +0800
++++ linux-2.4.20-uml/arch/um/kernel/sysrq.c 2003-11-10 13:43:06.000000000 +0800
@@ -86,6 +86,37 @@
show_trace((unsigned long *)esp);
}
/*
* Overrides for Emacs so that we follow Linus's tabbing style.
* Emacs will notice this stuff at the end of the file and automatically
+Index: linux-2.4.20-uml/arch/i386/kernel/Makefile
+===================================================================
+--- linux-2.4.20-uml.orig/arch/i386/kernel/Makefile 2002-11-29 07:53:09.000000000 +0800
++++ linux-2.4.20-uml/arch/i386/kernel/Makefile 2003-11-10 14:39:28.000000000 +0800
+@@ -14,7 +14,8 @@
+
+ O_TARGET := kernel.o
+
+-export-objs := mca.o mtrr.o msr.o cpuid.o microcode.o i386_ksyms.o time.o
++export-objs := mca.o mtrr.o msr.o cpuid.o microcode.o i386_ksyms.o time.o \
++ traps.o
+
+ obj-y := process.o semaphore.o signal.o entry.o traps.o irq.o vm86.o \
+ ptrace.o i8259.o ioport.o ldt.o setup.o time.o sys_i386.o \
+Index: linux-2.4.20-uml/arch/i386/kernel/traps.c
+===================================================================
+--- linux-2.4.20-uml.orig/arch/i386/kernel/traps.c 2002-11-29 07:53:09.000000000 +0800
++++ linux-2.4.20-uml/arch/i386/kernel/traps.c 2003-11-10 14:53:53.000000000 +0800
+@@ -1004,3 +1004,41 @@
+ cobalt_init();
+ #endif
+ }
++
++#ifdef CONFIG_MODULES
++extern struct module *module_list;
++extern struct module kernel_module;
++#endif
++
++int is_kernel_text_address(unsigned long addr)
++{
++ int retval = 0;
++#ifdef CONFIG_MODULES
++ struct module *mod;
++#endif
++ if (addr >= (unsigned long) &_stext &&
++ addr <= (unsigned long) &_etext);
++ return 1;
++
++#ifdef CONFIG_MODULES
++ for (mod = module_list; mod != &kernel_module; mod = mod->next) {
++ /* mod_bound tests for addr being inside the vmalloc'ed
++ * module area. Of course it'd be better to test only
++ * for the .text subset... */
++ if (mod_bound(addr, 0, mod)) {
++ retval = 1;
++ break;
++ }
++ }
++#endif
++
++ return retval;
++}
++
++int lookup_symbol(unsigned long address, char *buf, int buflen)
++{
++ return -ENOSYS;
++}
++
++EXPORT_SYMBOL_GPL(is_kernel_text_address);
++EXPORT_SYMBOL_GPL(lookup_symbol);
#define IOC_PORTAL_CLEAR_DEBUG _IOWR('e', 32, long)
#define IOC_PORTAL_MARK_DEBUG _IOWR('e', 33, long)
#define IOC_PORTAL_PANIC _IOWR('e', 34, long)
-#define IOC_PORTAL_ADD_ROUTE _IOWR('e', 35, long)
-#define IOC_PORTAL_DEL_ROUTE _IOWR('e', 36, long)
-#define IOC_PORTAL_GET_ROUTE _IOWR('e', 37, long)
-#define IOC_PORTAL_NAL_CMD _IOWR('e', 38, long)
-#define IOC_PORTAL_GET_NID _IOWR('e', 39, long)
-#define IOC_PORTAL_FAIL_NID _IOWR('e', 40, long)
-#define IOC_PORTAL_SET_DAEMON _IOWR('e', 41, long)
-#define IOC_PORTAL_NOTIFY_ROUTER _IOWR('e', 42, long)
-#define IOC_PORTAL_LWT_CONTROL _IOWR('e', 43, long)
-#define IOC_PORTAL_LWT_SNAPSHOT _IOWR('e', 44, long)
-#define IOC_PORTAL_LWT_LOOKUP_STRING _IOWR('e', 45, long)
-#define IOC_PORTAL_MAX_NR 45
+#define IOC_PORTAL_NAL_CMD _IOWR('e', 35, long)
+#define IOC_PORTAL_GET_NID _IOWR('e', 36, long)
+#define IOC_PORTAL_FAIL_NID _IOWR('e', 37, long)
+#define IOC_PORTAL_SET_DAEMON _IOWR('e', 38, long)
+#define IOC_PORTAL_LWT_CONTROL _IOWR('e', 39, long)
+#define IOC_PORTAL_LWT_SNAPSHOT _IOWR('e', 40, long)
+#define IOC_PORTAL_LWT_LOOKUP_STRING _IOWR('e', 41, long)
+#define IOC_PORTAL_MAX_NR 41
enum {
QSWNAL = 1,
#define NAL_CMD_ADD_AUTOCONN 106
#define NAL_CMD_GET_AUTOCONN 107
#define NAL_CMD_GET_TXDESC 108
+#define NAL_CMD_ADD_ROUTE 109
+#define NAL_CMD_DEL_ROUTE 110
+#define NAL_CMD_GET_ROUTE 111
+#define NAL_CMD_NOTIFY_ROUTER 112
enum {
DEBUG_DAEMON_START = 1,
journal_info = current->journal_info;
current->journal_info = NULL;
sprintf(debug_file_name, "%s.%ld", debug_file_path, CURRENT_SECONDS);
- file = filp_open(debug_file_name, O_CREAT|O_TRUNC|O_RDWR, 0644);
+ file = filp_open(debug_file_name, O_CREAT|O_EXCL|O_RDWR, 0644);
if (!file || IS_ERR(file)) {
CERROR("cannot open %s for dumping: %ld\n", debug_file_name,
return str;
}
+#ifdef __KERNEL__
+#include <linux/lustre_version.h>
+#if (LUSTRE_KERNEL_VERSION >= 30)
+#warning "FIXME: remove workaround when l30 is widely used"
char stack_backtrace[LUSTRE_TRACE_SIZE];
spinlock_t stack_backtrace_lock = SPIN_LOCK_UNLOCKED;
#if defined(__arch_um__)
-# warning in arch_um
extern int is_kernel_text_address(unsigned long addr);
char *buf = stack_backtrace;
char *pbuf = buf;
unsigned long *stack = (unsigned long *)&buf;
-
+
size = sprintf(pbuf, " Call Trace: ");
pbuf += size;
while (((long) stack & (THREAD_SIZE-1)) != 0) {
break;
}
}
-
+
return buf;
}
#elif defined(CONFIG_X86)
-# warning in __i386__
extern int is_kernel_text_address(unsigned long addr);
extern int lookup_symbol(unsigned long address, char *buf, int buflen);
char *portals_debug_dumpstack(void)
{
- unsigned long esp = current->thread.esp;
+ unsigned long esp = current->thread.esp;
unsigned long *stack = (unsigned long *)&esp;
int size;
unsigned long addr;
char *buf = stack_backtrace;
char *pbuf = buf;
static char buffer[512];
-
- /* User space on another CPU? */
- if ((esp ^ (unsigned long)current) & (PAGE_MASK<<1)){
- memset(buf, 0x0, LUSTRE_TRACE_SIZE);
+ int rc = 0;
+
+ /* User space on another CPU? */
+ if ((esp ^ (unsigned long)current) & (PAGE_MASK<<1)){
+ buf[0] = '\0';
goto out;
}
-
+
size = sprintf(pbuf, " Call Trace: ");
pbuf += size;
while (((long) stack & (THREAD_SIZE-1)) != 0) {
addr = *stack++;
if (is_kernel_text_address(addr)) {
- lookup_symbol(addr, buffer, 512);
- if (buf + LUSTRE_TRACE_SIZE
+ rc = lookup_symbol(addr, buffer, 512);
+ if (rc == -ENOSYS) {
+ if (buf + LUSTRE_TRACE_SIZE <= pbuf + 12)
+ break;
+ size = sprintf(pbuf, "[<%08lx>] ", addr);
+ } else {
+ if (buf + LUSTRE_TRACE_SIZE
/* fix length + sizeof('\0') */
- <= pbuf + strlen(buffer) + 28 + 1)
- break;
- size = sprintf(pbuf, "([<%08lx>] %s (0x%x)) ",
- addr, buffer, stack-1);
+ <= pbuf + strlen(buffer) + 28 + 1)
+ break;
+ size = sprintf(pbuf, "([<%08lx>] %s (0x%x)) ",
+ addr, buffer, stack-1);
+ }
pbuf += size;
}
}
char *portals_debug_dumpstack(void)
{
char *buf = stack_backtrace;
- memset(buf, 0x0, LUSTRE_TRACE_SIZE);
+ buf[0] = '\0';
return buf;
}
#endif /* __arch_um__ */
+EXPORT_SYMBOL(stack_backtrace_lock);
+EXPORT_SYMBOL(portals_debug_dumpstack);
+#endif /* LUSTRE_KERNEL_VERSION < 30 */
+#endif /* __KERNEL__ */
EXPORT_SYMBOL(portals_debug_dumplog);
EXPORT_SYMBOL(portals_debug_msg);
EXPORT_SYMBOL(portals_run_upcall);
EXPORT_SYMBOL(portals_run_lbug_upcall);
EXPORT_SYMBOL(portals_nid2str);
-EXPORT_SYMBOL(portals_debug_dumpstack);
-EXPORT_SYMBOL(stack_backtrace_lock);
ENTRY;
switch(pcfg->pcfg_command) {
- case IOC_PORTAL_ADD_ROUTE:
+ case NAL_CMD_ADD_ROUTE:
CDEBUG(D_IOCTL, "Adding route: [%d] "LPU64" : "LPU64" - "LPU64"\n",
pcfg->pcfg_nal, pcfg->pcfg_nid,
pcfg->pcfg_nid2, pcfg->pcfg_nid3);
pcfg->pcfg_nid2, pcfg->pcfg_nid3);
break;
- case IOC_PORTAL_DEL_ROUTE:
+ case NAL_CMD_DEL_ROUTE:
CDEBUG (D_IOCTL, "Removing routes via [%d] "LPU64" : "LPU64" - "LPU64"\n",
pcfg->pcfg_nal, pcfg->pcfg_nid,
pcfg->pcfg_nid2, pcfg->pcfg_nid3);
pcfg->pcfg_nid2, pcfg->pcfg_nid3);
break;
- case IOC_PORTAL_NOTIFY_ROUTER: {
+ case NAL_CMD_NOTIFY_ROUTER: {
CDEBUG (D_IOCTL, "Notifying peer [%d] "LPU64" %s @ %ld\n",
pcfg->pcfg_nal, pcfg->pcfg_nid,
pcfg->pcfg_flags ? "Enabling" : "Disabling",
break;
}
- case IOC_PORTAL_GET_ROUTE:
+ case NAL_CMD_GET_ROUTE:
CDEBUG (D_IOCTL, "Getting route [%d]\n", pcfg->pcfg_count);
err = kportal_get_route(pcfg->pcfg_count, &pcfg->pcfg_nal,
&pcfg->pcfg_nid,
ENTRY;
+ if (current->fsuid != 0)
+ RETURN(err = -EACCES);
+
if ( _IOC_TYPE(cmd) != IOC_PORTAL_TYPE ||
_IOC_NR(cmd) < IOC_PORTAL_MIN_NR ||
_IOC_NR(cmd) > IOC_PORTAL_MAX_NR ) {
}
#ifndef __CYGWIN__
-# warning FIXME: cleanup fstat issue here
# ifndef SYS_fstat64
# define __SYS_fstat__ SYS_fstat
# else
-# define __SYS_fstat__ SYS_fstat64
-#endif
+# define __SYS_fstat__ SYS_fstat64
+# endif
rc = syscall(__SYS_fstat__, fd, &statbuf);
#else
rc = fstat(fd, &statbuf);
#ifndef __CYGWIN__
fd = syscall(SYS_open, dump_file, O_RDONLY);
-#warning FIXME: cleanup fstat issue here
#ifndef SYS_fstat64
# define __SYS_fstat__ SYS_fstat
#else
#define _PARSER_H_
#define HISTORY 100 /* Don't let history grow unbounded */
-#define MAXARGS 100
+#define MAXARGS 512
#define CMD_COMPLETE 0
#define CMD_INCOMPLETE 1
return (-1);
}
- PCFG_INIT(pcfg, IOC_PORTAL_ADD_ROUTE);
+ PCFG_INIT(pcfg, NAL_CMD_ADD_ROUTE);
pcfg.pcfg_nid = gateway_nid;
pcfg.pcfg_nal = g_nal;
pcfg.pcfg_nid2 = MIN (nid1, nid2);
}
}
- PCFG_INIT(pcfg, IOC_PORTAL_DEL_ROUTE);
+ PCFG_INIT(pcfg, NAL_CMD_DEL_ROUTE);
pcfg.pcfg_nal = g_nal;
pcfg.pcfg_nid = nid;
pcfg.pcfg_nid2 = nid1;
return (-1);
}
- PCFG_INIT(pcfg, IOC_PORTAL_NOTIFY_ROUTER);
+ PCFG_INIT(pcfg, NAL_CMD_NOTIFY_ROUTER);
pcfg.pcfg_nal = g_nal;
pcfg.pcfg_nid = nid;
pcfg.pcfg_flags = enable;
for (index = 0;;index++)
{
- PCFG_INIT(pcfg, IOC_PORTAL_GET_ROUTE);
+ PCFG_INIT(pcfg, NAL_CMD_GET_ROUTE);
pcfg.pcfg_count = index;
rc = pcfg_ioctl(&pcfg);