From 5ebb62185663a83d6a2ebf5ba105460a4e1c0f1c Mon Sep 17 00:00:00 2001 From: shaver Date: Wed, 19 Mar 2003 18:32:17 +0000 Subject: [PATCH] Merge b_devel into b_recovery. --- lustre/extN/ext3-orphan_lock.diff | 79 ++++ lustre/extN/ext3-truncate_blocks.diff | 92 ++++ lustre/extN/extN-delete_thread.diff | 267 +++++++++++ lustre/extN/extN.patch-2.5.63 | 42 ++ lustre/kernel_patches/patches/lustre-2.5.63.patch | 547 ++++++++++++++++++++++ lustre/kernel_patches/pc/lustre-2.5.63.pc | 12 + lustre/kernel_patches/series/vanilla-2.5.63 | 2 + lustre/tests/mkdirdeep.c | 275 +++++++++++ 8 files changed, 1316 insertions(+) create mode 100644 lustre/extN/ext3-orphan_lock.diff create mode 100644 lustre/extN/ext3-truncate_blocks.diff create mode 100644 lustre/extN/extN-delete_thread.diff create mode 100644 lustre/extN/extN.patch-2.5.63 create mode 100644 lustre/kernel_patches/patches/lustre-2.5.63.patch create mode 100644 lustre/kernel_patches/pc/lustre-2.5.63.pc create mode 100644 lustre/kernel_patches/series/vanilla-2.5.63 create mode 100644 lustre/tests/mkdirdeep.c diff --git a/lustre/extN/ext3-orphan_lock.diff b/lustre/extN/ext3-orphan_lock.diff new file mode 100644 index 0000000..d1e5c8d --- /dev/null +++ b/lustre/extN/ext3-orphan_lock.diff @@ -0,0 +1,79 @@ +--- linux/fs/ext3/namei.c.orig Fri Mar 14 14:11:58 2003 ++++ linux/fs/ext3/namei.c Fri Mar 14 14:39:48 2003 +@@ -1406,8 +1409,8 @@ + struct super_block *sb = inode->i_sb; + struct ext3_iloc iloc; + int err = 0, rc; +- +- lock_super(sb); ++ ++ down(&EXT3_SB(sb)->s_orphan_lock); + if (!list_empty(&EXT3_I(inode)->i_orphan)) + goto out_unlock; + +@@ -1455,7 +1458,7 @@ + jbd_debug(4, "orphan inode %ld will point to %d\n", + inode->i_ino, NEXT_ORPHAN(inode)); + out_unlock: +- unlock_super(sb); ++ up(&EXT3_SB(sb)->s_orphan_lock); + ext3_std_error(inode->i_sb, err); + return err; + } +@@ -1468,20 +1471,19 @@ + { + struct list_head *prev; + struct ext3_inode_info *ei = EXT3_I(inode); +- struct ext3_sb_info *sbi; ++ struct ext3_sb_info *sbi = EXT3_SB(inode->i_sb); + unsigned long ino_next; + struct ext3_iloc iloc; + int err = 0; + +- lock_super(inode->i_sb); ++ down(&sbi->s_orphan_lock); + if (list_empty(&ei->i_orphan)) { +- unlock_super(inode->i_sb); ++ up(&sbi->s_orphan_lock); + return 0; + } + + ino_next = NEXT_ORPHAN(inode); + prev = ei->i_orphan.prev; +- sbi = EXT3_SB(inode->i_sb); + + jbd_debug(4, "remove inode %lu from orphan list\n", inode->i_ino); + +@@ -1525,10 +1527,10 @@ + if (err) + goto out_brelse; + +-out_err: ++out_err: + ext3_std_error(inode->i_sb, err); + out: +- unlock_super(inode->i_sb); ++ up(&sbi->s_orphan_lock); + return err; + + out_brelse: +--- linux/fs/ext3/super.c.orig Fri Mar 14 14:11:58 2003 ++++ linux/fs/ext3/super.c Fri Mar 14 14:36:00 2003 +@@ -1134,6 +1314,7 @@ + */ + sb->s_op = &ext3_sops; + INIT_LIST_HEAD(&sbi->s_orphan); /* unlinked but open files */ ++ sema_init(&sbi->s_orphan_lock, 1); + + sb->s_root = 0; + +--- linux/include/linux/ext3_fs_sb.h.orig Tue Feb 11 16:34:33 2003 ++++ linux/include/linux/ext3_fs_sb.h Fri Mar 14 14:30:11 2003 +@@ -67,6 +69,7 @@ + struct inode * s_journal_inode; + struct journal_s * s_journal; + struct list_head s_orphan; ++ struct semaphore s_orphan_lock; + unsigned long s_commit_interval; + struct block_device *journal_bdev; + #ifdef CONFIG_JBD_DEBUG diff --git a/lustre/extN/ext3-truncate_blocks.diff b/lustre/extN/ext3-truncate_blocks.diff new file mode 100644 index 0000000..ce3928d --- /dev/null +++ b/lustre/extN/ext3-truncate_blocks.diff @@ -0,0 +1,92 @@ +--- ./fs/ext3/inode.c.orig Wed Mar 12 02:44:06 2003 ++++ ./fs/ext3/inode.c Wed Mar 12 11:55:20 2003 +@@ -99,7 +99,35 @@ int ext3_forget(handle_t *handle, int is + return err; + } + +-/* ++/* ++ * Work out how many blocks we need to progress with the next chunk of a ++ * truncate transaction. ++ */ ++ ++static unsigned long blocks_for_truncate(struct inode *inode) ++{ ++ unsigned long needed; ++ ++ needed = inode->i_blocks >> (inode->i_sb->s_blocksize_bits - 9); ++ ++ /* Give ourselves just enough room to cope with inodes in which ++ * i_blocks is corrupt: we've seen disk corruptions in the past ++ * which resulted in random data in an inode which looked enough ++ * like a regular file for ext3 to try to delete it. Things ++ * will go a bit crazy if that happens, but at least we should ++ * try not to panic the whole kernel. */ ++ if (needed < 2) ++ needed = 2; ++ ++ /* But we need to bound the transaction so we don't overflow the ++ * journal. */ ++ if (needed > EXT3_MAX_TRANS_DATA) ++ needed = EXT3_MAX_TRANS_DATA; ++ ++ return EXT3_DATA_TRANS_BLOCKS + needed; ++} ++ ++/* + * Truncate transactions can be complex and absolutely huge. So we need to + * be able to restart the transaction at a conventient checkpoint to make + * sure we don't overflow the journal. +@@ -110,19 +138,14 @@ int ext3_forget(handle_t *handle, int is + * transaction in the top-level truncate loop. --sct + */ + +-static handle_t *start_transaction(struct inode *inode) ++static handle_t *start_transaction(struct inode *inode) + { +- long needed; + handle_t *result; +- +- needed = inode->i_blocks; +- if (needed > EXT3_MAX_TRANS_DATA) +- needed = EXT3_MAX_TRANS_DATA; +- +- result = ext3_journal_start(inode, EXT3_DATA_TRANS_BLOCKS + needed); ++ ++ result = ext3_journal_start(inode, blocks_for_truncate(inode)); + if (!IS_ERR(result)) + return result; +- ++ + ext3_std_error(inode->i_sb, PTR_ERR(result)); + return result; + } +@@ -135,14 +158,9 @@ static handle_t *start_transaction(struc + */ + static int try_to_extend_transaction(handle_t *handle, struct inode *inode) + { +- long needed; +- + if (handle->h_buffer_credits > EXT3_RESERVE_TRANS_BLOCKS) + return 0; +- needed = inode->i_blocks; +- if (needed > EXT3_MAX_TRANS_DATA) +- needed = EXT3_MAX_TRANS_DATA; +- if (!ext3_journal_extend(handle, EXT3_RESERVE_TRANS_BLOCKS + needed)) ++ if (!ext3_journal_extend(handle, blocks_for_truncate(inode))) + return 0; + return 1; + } +@@ -154,11 +172,8 @@ static int try_to_extend_transaction(han + */ + static int ext3_journal_test_restart(handle_t *handle, struct inode *inode) + { +- long needed = inode->i_blocks; +- if (needed > EXT3_MAX_TRANS_DATA) +- needed = EXT3_MAX_TRANS_DATA; + jbd_debug(2, "restarting handle %p\n", handle); +- return ext3_journal_restart(handle, EXT3_DATA_TRANS_BLOCKS + needed); ++ return ext3_journal_restart(handle, blocks_for_truncate(inode)); + } + + /* diff --git a/lustre/extN/extN-delete_thread.diff b/lustre/extN/extN-delete_thread.diff new file mode 100644 index 0000000..acb25e4 --- /dev/null +++ b/lustre/extN/extN-delete_thread.diff @@ -0,0 +1,267 @@ +--- linux/include/linux/extN_fs.h.orig Fri Mar 14 18:09:02 2003 ++++ linux/include/linux/extN_fs.h Fri Mar 14 18:10:20 2003 +@@ -190,6 +192,7 @@ + */ + #define EXTN_STATE_JDATA 0x00000001 /* journaled data exists */ + #define EXTN_STATE_NEW 0x00000002 /* inode is newly created */ ++#define EXTN_STATE_DELETE 0x00000010 /* deferred delete inode */ + + /* + * ioctl commands +--- linux/include/linux/extN_fs_sb.h.orig Tue Feb 11 16:34:33 2003 ++++ linux/include/linux/extN_fs_sb.h Mon Mar 10 14:42:07 2003 +@@ -29,6 +29,8 @@ + + #define EXTN_MAX_GROUP_LOADED 32 + ++#define EXTN_DELETE_THREAD ++ + /* + * third extended-fs super-block data in memory + */ +@@ -73,6 +75,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 EXTN_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_EXTN_FS_SB */ +--- linux/fs/extN/super.c.orig Wed Mar 12 14:05:30 2003 ++++ linux/fs/extN/super.c Thu Mar 13 19:05:26 2003 +@@ -396,6 +396,200 @@ + } + } + ++#ifdef EXTN_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 extN_delete_thread(void *data) ++{ ++ struct super_block *sb = data; ++ struct extN_sb_info *sbi = EXTN_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, "kdelextN-%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); ++ printk(KERN_INFO "EXTN-fs: delete thread on %s started\n", ++ kdevname(sb->s_dev)); ++ ++ /* main loop */ ++ for (;;) { ++ sleep_on(&sbi->s_delete_thread_queue); ++ printk(KERN_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)) { ++ memset(&sbi->s_delete_list, 0, ++ sizeof(sbi->s_delete_list)); ++ spin_unlock(&sbi->s_delete_lock); ++ printk(KERN_DEBUG "extN 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); ++ extN_debug("%s deleting inode %lu, %lu blocks\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) ++ printk(KERN_WARNING ++ "%lu blocks and %lu left 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 extN_start_delete_thread(struct super_block *sb) ++{ ++ struct extN_sb_info *sbi = EXTN_SB(sb); ++ int rc; ++ ++ spin_lock_init(&sbi->s_delete_lock); ++ memset(&sbi->s_delete_list, 0, sizeof(sbi->s_delete_list)); ++ init_waitqueue_head(&sbi->s_delete_thread_queue); ++ init_waitqueue_head(&sbi->s_delete_waiter_queue); ++ sbi->s_delete_blocks = 0; ++ sbi->s_delete_inodes = 0; ++ rc = kernel_thread(extN_delete_thread, sb, CLONE_VM | CLONE_FILES); ++ if (rc < 0) ++ printk(KERN_ERR "EXTN-fs: cannot start delete thread: rc %d\n", ++ rc); ++ else ++ wait_event(sbi->s_delete_waiter_queue, sbi->s_delete_list.next); ++} ++ ++static void extN_stop_delete_thread(struct extN_sb_info *sbi) ++{ ++ 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 ++ * duplicate the inode data 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 copy the whole thing. ++ * ++ * 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 ++ * truncate thread when we run out of space. ++ * ++ * One shouldn't consider this duplicate an "inode", as it isn't really ++ * visible to the VFS, but rather a data struct that holds truncate data. ++ * ++ * In 2.5 this can be done much more cleanly by just registering a "drop" ++ * method in the super_operations struct. ++ */ ++static void extN_delete_inode_thread(struct inode *old_inode) ++{ ++ struct extN_sb_info *sbi = EXTN_SB(old_inode->i_sb); ++ 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; ++ } ++ ++ /* We may want to delete the inode immediately and not defer it */ ++ if (IS_SYNC(old_inode) || blocks <= EXTN_NDIR_BLOCKS || ++ !sbi->s_delete_list.next) { ++ extN_delete_inode(old_inode); ++ return; ++ } ++ ++ if (EXTN_I(old_inode)->i_state & EXTN_STATE_DELETE) { ++ extN_debug("doing deferred inode %lu delete (%lu blocks)\n", ++ old_inode->i_ino, blocks); ++ extN_delete_inode(old_inode); ++ return; ++ } ++ ++ /* 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); ++ ++ EXTN_SB(old_inode->i_sb)->s_mount_state |= EXTN_ORPHAN_FS; ++ new_inode = iget(old_inode->i_sb, old_inode->i_ino); ++ EXTN_SB(old_inode->i_sb)->s_mount_state &= ~EXTN_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); ++ extN_debug(KERN_DEBUG "delete inode %lu directly (bad read)\n", ++ old_inode->i_ino); ++ extN_delete_inode(old_inode); ++ return; ++ } ++ J_ASSERT(new_inode != old_inode); ++ ++ list_del(&EXTN_I(old_inode)->i_orphan); ++ list_add(&EXTN_I(new_inode)->i_orphan, &sbi->s_orphan); ++ EXTN_I(new_inode)->i_state |= EXTN_STATE_DELETE; ++ up(&sbi->s_orphan_lock); ++ ++ clear_inode(old_inode); ++ ++ printk(KERN_DEBUG "delete inode %lu (%lu blocks) by thread\n", ++ new_inode->i_ino, blocks); ++ spin_lock(&sbi->s_delete_lock); ++ 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); ++ ++ wake_up(&sbi->s_delete_thread_queue); ++} ++#else ++#define extN_start_delete_thread(sbi) do {} while(0) ++#define extN_stop_delete_thread(sbi) do {} while(0) ++#endif /* EXTN_DELETE_THREAD */ ++ + void extN_put_super (struct super_block * sb) + { + struct extN_sb_info *sbi = EXTN_SB(sb); +@@ -403,6 +578,7 @@ + kdev_t j_dev = sbi->s_journal->j_dev; + int i; + ++ extN_stop_delete_thread(sbi); + extN_xattr_put_super(sb); + journal_destroy(sbi->s_journal); + if (!(sb->s_flags & MS_RDONLY)) { +@@ -451,7 +627,11 @@ + write_inode: extN_write_inode, /* BKL not held. Don't need */ + dirty_inode: extN_dirty_inode, /* BKL not held. We take it */ + put_inode: extN_put_inode, /* BKL not held. Don't need */ ++#ifdef EXTN_DELETE_THREAD ++ delete_inode: extN_delete_inode_thread,/* BKL not held. We take it */ ++#else + delete_inode: extN_delete_inode, /* BKL not held. We take it */ ++#endif + put_super: extN_put_super, /* BKL held */ + write_super: extN_write_super, /* BKL held */ + write_super_lockfs: extN_write_super_lockfs, /* BKL not held. Take it */ +@@ -1205,6 +1385,7 @@ + } + + extN_setup_super (sb, es, sb->s_flags & MS_RDONLY); ++ extN_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 diff --git a/lustre/extN/extN.patch-2.5.63 b/lustre/extN/extN.patch-2.5.63 new file mode 100644 index 0000000..e1bb363 --- /dev/null +++ b/lustre/extN/extN.patch-2.5.63 @@ -0,0 +1,42 @@ +--- fs/extN/xattr.c Wed Mar 5 23:09:55 2003 ++++ fs/extN/xattr.c Tue Mar 11 17:57:24 2003 +@@ -1181,3 +1181,7 @@ + ext3_xattr_unregister(EXT3_XATTR_INDEX_USER, + &ext3_xattr_user_handler); + } ++ ++EXPORT_SYMBOL(extN_xattr_get); ++EXPORT_SYMBOL(extN_xattr_set); ++ +--- fs/extN/inode.c Wed Mar 5 23:09:55 2003 ++++ fs/extN/inode.c Tue Mar 11 18:24:42 2003 +@@ -1019,7 +1019,7 @@ + *err = -EIO; + return NULL; + } +- ++EXPORT_SYMBOL(extN_bread); + static int walk_page_buffers( handle_t *handle, + struct buffer_head *head, + unsigned from, +--- fs/extN/super.c Wed Mar 5 23:09:55 2003 ++++ fs/extN/super.c Tue Mar 11 18:28:01 2003 +@@ -1703,6 +1703,7 @@ + unlock_kernel(); + return ret; + } ++EXPORT_SYMBOL(extN_force_commit); + + /* + * Ext3 always journals updates to the superblock itself, so we don't +--- fs/extN/xattr.h Tue Mar 11 21:37:48 2003 ++++ fs/extN/xattr.h Tue Mar 11 21:18:12 2003 +@@ -5,7 +5,7 @@ + + (C) 2001 Andreas Gruenbacher, + */ +- ++#include + #include + #include + diff --git a/lustre/kernel_patches/patches/lustre-2.5.63.patch b/lustre/kernel_patches/patches/lustre-2.5.63.patch new file mode 100644 index 0000000..c857ca4 --- /dev/null +++ b/lustre/kernel_patches/patches/lustre-2.5.63.patch @@ -0,0 +1,547 @@ + arch/um/kernel/mem.c | 18 +++++++++++- + fs/dcache.c | 12 ++++++-- + fs/namei.c | 71 +++++++++++++++++++++++++++++++++++-------------- + fs/namespace.c | 1 + fs/nfsd/vfs.c | 2 - + fs/sysfs/inode.c | 2 - + include/linux/dcache.h | 28 +++++++++++++++++++ + include/linux/fs.h | 20 +++++++++++++ + include/linux/namei.h | 3 +- + include/linux/slab.h | 1 + kernel/ksyms.c | 7 ++++ + mm/slab.c | 5 +++ + net/unix/af_unix.c | 2 - + 13 files changed, 143 insertions(+), 29 deletions(-) + +--- linux-2.5.63/arch/um/kernel/mem.c~lustre-2.5.63 Thu Mar 13 20:57:08 2003 ++++ linux-2.5.63-kedar/arch/um/kernel/mem.c Thu Mar 13 20:57:08 2003 +@@ -660,6 +660,22 @@ struct page *pte_mem_map(pte_t pte) + return(phys_mem_map(pte_val(pte))); + } + ++struct page *check_get_page(unsigned long kaddr) ++{ ++ struct page *page; ++ struct mem_region *mr; ++ unsigned long phys = __pa(kaddr); ++ unsigned int n = phys_region_index(phys); ++ ++ if(regions[n] == NULL) ++ return NULL; ++ ++ mr = regions[n]; ++ page = (struct page *) mr->mem_map; ++ return page + ((phys_addr(phys)) >> PAGE_SHIFT); ++} ++ ++ + struct mem_region *page_region(struct page *page, int *index_out) + { + int i; +@@ -747,7 +763,7 @@ extern unsigned long region_pa(void *vir + (addr <= region->start + region->len)) + return(mk_phys(addr - region->start, i)); + } +- panic("region_pa : no region for virtual address"); ++ //panic("region_pa : no region for virtual address"); + return(0); + } + +--- linux-2.5.63/fs/namei.c~lustre-2.5.63 Thu Mar 13 20:57:08 2003 ++++ linux-2.5.63-kedar/fs/namei.c Thu Mar 13 20:57:08 2003 +@@ -265,6 +265,9 @@ int deny_write_access(struct file * file + + void path_release(struct nameidata *nd) + { ++ if (nd->dentry && nd->dentry->d_op && ++ nd->dentry->d_op->d_intent_release) ++ nd->dentry->d_op->d_intent_release(nd->dentry, &nd->it); + dput(nd->dentry); + mntput(nd->mnt); + } +@@ -273,10 +276,18 @@ void path_release(struct nameidata *nd) + * Internal lookup() using the new generic dcache. + * SMP-safe + */ +-static struct dentry * cached_lookup(struct dentry * parent, struct qstr * name, int flags) ++static struct dentry * cached_lookup(struct dentry * parent, struct qstr * name, int flags, struct lookup_intent *it) + { + struct dentry * dentry = d_lookup(parent, name); + ++ if (dentry && dentry->d_op && dentry->d_op->d_revalidate2) { ++ if (!dentry->d_op->d_revalidate2(dentry, flags, it) && ++ !d_invalidate(dentry)) { ++ dput(dentry); ++ dentry = NULL; ++ } ++ return dentry; ++ } else + if (dentry && dentry->d_op && dentry->d_op->d_revalidate) { + if (!dentry->d_op->d_revalidate(dentry, flags) && !d_invalidate(dentry)) { + dput(dentry); +@@ -330,7 +341,7 @@ ok: + * make sure that nobody added the entry to the dcache in the meantime.. + * SMP-safe + */ +-static struct dentry * real_lookup(struct dentry * parent, struct qstr * name, int flags) ++static struct dentry * real_lookup(struct dentry * parent, struct qstr * name, int flags, struct lookup_intent *it) + { + struct dentry * result; + struct inode *dir = parent->d_inode; +@@ -348,7 +359,10 @@ static struct dentry * real_lookup(struc + struct dentry * dentry = d_alloc(parent, name); + result = ERR_PTR(-ENOMEM); + if (dentry) { +- result = dir->i_op->lookup(dir, dentry); ++ if (dir->i_op->lookup2) ++ result = dir->i_op->lookup2(dir, dentry, it); ++ else ++ result = dir->i_op->lookup(dir, dentry); + if (result) + dput(dentry); + else { +@@ -370,6 +384,12 @@ static struct dentry * real_lookup(struc + dput(result); + result = ERR_PTR(-ENOENT); + } ++ } else if (result->d_op && result->d_op->d_revalidate2) { ++ if (!result->d_op->d_revalidate2(result, flags, it) && ++ !d_invalidate(result)) { ++ dput(result); ++ result = ERR_PTR(-ENOENT); ++ } + } + return result; + } +@@ -531,7 +551,7 @@ done: + return 0; + + need_lookup: +- dentry = real_lookup(nd->dentry, name, LOOKUP_CONTINUE); ++ dentry = real_lookup(nd->dentry, name, LOOKUP_CONTINUE, &nd->it); + if (IS_ERR(dentry)) + goto fail; + goto done; +@@ -665,7 +685,7 @@ int link_path_walk(const char * name, st + nd->dentry = next.dentry; + } + err = -ENOTDIR; +- if (!inode->i_op->lookup) ++ if (!inode->i_op->lookup && !inode->i_op->lookup2) + break; + continue; + /* here ends the main loop */ +@@ -716,7 +736,8 @@ last_component: + break; + if (lookup_flags & LOOKUP_DIRECTORY) { + err = -ENOTDIR; +- if (!inode->i_op || !inode->i_op->lookup) ++ if (!inode->i_op || ++ (!inode->i_op->lookup && !inode->i_op->lookup2)) + break; + } + goto return_base; +@@ -857,7 +878,8 @@ int path_lookup(const char *name, unsign + * needs parent already locked. Doesn't follow mounts. + * SMP-safe. + */ +-struct dentry * lookup_hash(struct qstr *name, struct dentry * base) ++struct dentry * lookup_hash(struct qstr *name, struct dentry * base, ++ struct lookup_intent *it) + { + struct dentry * dentry; + struct inode *inode; +@@ -880,13 +902,16 @@ struct dentry * lookup_hash(struct qstr + goto out; + } + +- dentry = cached_lookup(base, name, 0); ++ dentry = cached_lookup(base, name, 0, it); + if (!dentry) { + struct dentry *new = d_alloc(base, name); + dentry = ERR_PTR(-ENOMEM); + if (!new) + goto out; +- dentry = inode->i_op->lookup(inode, new); ++ if (inode->i_op->lookup2) ++ dentry = inode->i_op->lookup2(inode, new, it); ++ else ++ dentry = inode->i_op->lookup(inode, new); + if (!dentry) { + dentry = new; + security_inode_post_lookup(inode, dentry); +@@ -898,7 +923,7 @@ out: + } + + /* SMP-safe */ +-struct dentry * lookup_one_len(const char * name, struct dentry * base, int len) ++struct dentry * lookup_one_len_it(const char * name, struct dentry * base, int len, struct lookup_intent *it) + { + unsigned long hash; + struct qstr this; +@@ -918,11 +943,16 @@ struct dentry * lookup_one_len(const cha + } + this.hash = end_name_hash(hash); + +- return lookup_hash(&this, base); ++ return lookup_hash(&this, base, it); + access: + return ERR_PTR(-EACCES); + } + ++struct dentry * lookup_one_len(const char * name, struct dentry * base, int len) ++{ ++ return lookup_one_len_it(name, base, len, NULL); ++} ++ + /* + * namei() + * +@@ -1239,7 +1269,7 @@ int open_namei(const char * pathname, in + + dir = nd->dentry; + down(&dir->d_inode->i_sem); +- dentry = lookup_hash(&nd->last, nd->dentry); ++ dentry = lookup_hash(&nd->last, nd->dentry, &nd->it); + + do_last: + error = PTR_ERR(dentry); +@@ -1342,7 +1372,7 @@ do_link: + } + dir = nd->dentry; + down(&dir->d_inode->i_sem); +- dentry = lookup_hash(&nd->last, nd->dentry); ++ dentry = lookup_hash(&nd->last, nd->dentry, &nd->it); + putname(nd->last.name); + goto do_last; + } +@@ -1356,7 +1386,7 @@ static struct dentry *lookup_create(stru + dentry = ERR_PTR(-EEXIST); + if (nd->last_type != LAST_NORM) + goto fail; +- dentry = lookup_hash(&nd->last, nd->dentry); ++ dentry = lookup_hash(&nd->last, nd->dentry, &nd->it); + if (IS_ERR(dentry)) + goto fail; + if (!is_dir && nd->last.name[nd->last.len] && !dentry->d_inode) +@@ -1588,7 +1618,7 @@ asmlinkage long sys_rmdir(const char * p + goto exit1; + } + down(&nd.dentry->d_inode->i_sem); +- dentry = lookup_hash(&nd.last, nd.dentry); ++ dentry = lookup_hash(&nd.last, nd.dentry, &nd.it); + error = PTR_ERR(dentry); + if (!IS_ERR(dentry)) { + error = vfs_rmdir(nd.dentry->d_inode, dentry); +@@ -1655,7 +1685,7 @@ asmlinkage long sys_unlink(const char * + if (nd.last_type != LAST_NORM) + goto exit1; + down(&nd.dentry->d_inode->i_sem); +- dentry = lookup_hash(&nd.last, nd.dentry); ++ dentry = lookup_hash(&nd.last, nd.dentry, &nd.it); + error = PTR_ERR(dentry); + if (!IS_ERR(dentry)) { + /* Why not before? Because we want correct error value */ +@@ -1934,7 +1964,8 @@ int vfs_rename_other(struct inode *old_d + } + + int vfs_rename(struct inode *old_dir, struct dentry *old_dentry, +- struct inode *new_dir, struct dentry *new_dentry) ++ struct inode *new_dir, struct dentry *new_dentry, ++ struct lookup_intent *it) + { + int error; + int is_dir = S_ISDIR(old_dentry->d_inode->i_mode); +@@ -2005,7 +2036,7 @@ static inline int do_rename(const char * + + trap = lock_rename(new_dir, old_dir); + +- old_dentry = lookup_hash(&oldnd.last, old_dir); ++ old_dentry = lookup_hash(&oldnd.last, old_dir, &oldnd.it); + error = PTR_ERR(old_dentry); + if (IS_ERR(old_dentry)) + goto exit3; +@@ -2025,7 +2056,7 @@ static inline int do_rename(const char * + error = -EINVAL; + if (old_dentry == trap) + goto exit4; +- new_dentry = lookup_hash(&newnd.last, new_dir); ++ new_dentry = lookup_hash(&newnd.last, new_dir, &newnd.it); + error = PTR_ERR(new_dentry); + if (IS_ERR(new_dentry)) + goto exit4; +@@ -2035,7 +2066,7 @@ static inline int do_rename(const char * + goto exit5; + + error = vfs_rename(old_dir->d_inode, old_dentry, +- new_dir->d_inode, new_dentry); ++ new_dir->d_inode, new_dentry, NULL); + exit5: + dput(new_dentry); + exit4: +--- linux-2.5.63/fs/nfsd/vfs.c~lustre-2.5.63 Thu Mar 13 20:57:08 2003 ++++ linux-2.5.63-kedar/fs/nfsd/vfs.c Thu Mar 13 20:57:08 2003 +@@ -1337,7 +1337,7 @@ nfsd_rename(struct svc_rqst *rqstp, stru + err = nfserr_perm; + } else + #endif +- err = vfs_rename(fdir, odentry, tdir, ndentry); ++ err = vfs_rename(fdir, odentry, tdir, ndentry, NULL); + if (!err && EX_ISSYNC(tfhp->fh_export)) { + nfsd_sync_dir(tdentry); + nfsd_sync_dir(fdentry); +--- linux-2.5.63/fs/sysfs/inode.c~lustre-2.5.63 Thu Mar 13 20:57:08 2003 ++++ linux-2.5.63-kedar/fs/sysfs/inode.c Thu Mar 13 20:57:08 2003 +@@ -540,7 +540,7 @@ static struct dentry * get_dentry(struct + qstr.name = name; + qstr.len = strlen(name); + qstr.hash = full_name_hash(name,qstr.len); +- return lookup_hash(&qstr,parent); ++ return lookup_hash(&qstr,parent,NULL); + } + + +--- linux-2.5.63/include/linux/dcache.h~lustre-2.5.63 Thu Mar 13 20:57:08 2003 ++++ linux-2.5.63-kedar/include/linux/dcache.h Thu Mar 13 20:57:08 2003 +@@ -12,6 +12,27 @@ + + struct vfsmount; + ++#define IT_OPEN (1) ++#define IT_CREAT (1<<1) ++#define IT_READDIR (1<<2) ++#define IT_GETATTR (1<<3) ++#define IT_LOOKUP (1<<4) ++#define IT_UNLINK (1<<5) ++ ++ ++struct lookup_intent { ++ int it_op; ++ int it_mode; ++ int it_flags; ++ int it_disposition; ++ int it_status; ++ struct iattr *it_iattr; ++ __u64 it_lock_handle[2]; ++ int it_lock_mode; ++ void *it_data; ++}; ++ ++ + /* + * linux/include/linux/dcache.h + * +@@ -34,6 +55,8 @@ struct qstr { + char name_str[0]; + }; + ++#include ++ + struct dentry_stat_t { + int nr_dentry; + int nr_unused; +@@ -87,6 +110,7 @@ struct dentry { + struct list_head d_subdirs; /* our children */ + struct list_head d_alias; /* inode alias list */ + int d_mounted; ++ struct lookup_intent *d_it; + struct qstr d_name; + struct qstr * d_qstr; /* quick str ptr used in lockless lookup and concurrent d_move */ + unsigned long d_time; /* used by d_revalidate */ +@@ -107,6 +131,8 @@ struct dentry_operations { + int (*d_delete)(struct dentry *); + void (*d_release)(struct dentry *); + void (*d_iput)(struct dentry *, struct inode *); ++ int (*d_revalidate2)(struct dentry *, int, struct lookup_intent *); ++ void (*d_intent_release)(struct dentry *, struct lookup_intent *); + }; + + /* the dentry parameter passed to d_hash and d_compare is the parent +@@ -147,6 +173,8 @@ d_iput: no no yes + + #define DCACHE_REFERENCED 0x0008 /* Recently used, don't discard. */ + #define DCACHE_UNHASHED 0x0010 ++#define DCACHE_LUSTRE_INVALID 0x0011 /* Lustre invalidated */ ++ + + extern spinlock_t dcache_lock; + extern rwlock_t dparent_lock; +--- linux-2.5.63/include/linux/fs.h~lustre-2.5.63 Thu Mar 13 20:57:08 2003 ++++ linux-2.5.63-kedar/include/linux/fs.h Thu Mar 13 20:57:08 2003 +@@ -234,6 +234,9 @@ typedef int (get_blocks_t)(struct inode + #define ATTR_ATTR_FLAG 1024 + #define ATTR_KILL_SUID 2048 + #define ATTR_KILL_SGID 4096 ++#define ATTR_RAW 8192 /* file system, not vfs will massage attrs */ ++#define ATTR_FROM_OPEN 16384 /* called from open path, ie O_TRUNC */ ++ + + /* + * This is the Inode Attributes structure, used for notify_change(). It +@@ -642,7 +645,7 @@ extern int vfs_symlink(struct inode *, s + extern int vfs_link(struct dentry *, struct inode *, struct dentry *); + extern int vfs_rmdir(struct inode *, struct dentry *); + extern int vfs_unlink(struct inode *, struct dentry *); +-extern int vfs_rename(struct inode *, struct dentry *, struct inode *, struct dentry *); ++extern int vfs_rename(struct inode *, struct dentry *, struct inode *, struct dentry *, struct lookup_intent *it); + + /* + * File types +@@ -728,19 +731,33 @@ struct file_operations { + struct inode_operations { + int (*create) (struct inode *,struct dentry *,int); + struct dentry * (*lookup) (struct inode *,struct dentry *); ++ struct dentry * (*lookup2) (struct inode *,struct dentry *, ++ struct lookup_intent *); + int (*link) (struct dentry *,struct inode *,struct dentry *); ++ int (*link2) (struct inode *,struct inode *, const char *, int); + int (*unlink) (struct inode *,struct dentry *); ++ int (*unlink2) (struct inode *, const char *, int); + int (*symlink) (struct inode *,struct dentry *,const char *); ++ int (*symlink2) (struct inode *, const char *, int, const char *); + int (*mkdir) (struct inode *,struct dentry *,int); ++ int (*mkdir2) (struct inode *, const char *, int,int); + int (*rmdir) (struct inode *,struct dentry *); ++ int (*rmdir2) (struct inode *, const char *, int); + int (*mknod) (struct inode *,struct dentry *,int,dev_t); ++ int (*mknod2) (struct inode *, const char *, int,int,int); + int (*rename) (struct inode *, struct dentry *, + struct inode *, struct dentry *); ++ int (*rename2) (struct inode *, struct inode *, ++ const char *oldname, int oldlen, ++ const char *newname, int newlen); + int (*readlink) (struct dentry *, char *,int); + int (*follow_link) (struct dentry *, struct nameidata *); ++ int (*follow_link2) (struct dentry *, struct nameidata *, ++ struct lookup_intent *it); + void (*truncate) (struct inode *); + int (*permission) (struct inode *, int); + int (*setattr) (struct dentry *, struct iattr *); ++ int (*setattr_raw) (struct inode *, struct iattr *); + int (*getattr) (struct vfsmount *mnt, struct dentry *, struct kstat *); + int (*setxattr) (struct dentry *, const char *,const void *,size_t,int); + ssize_t (*getxattr) (struct dentry *, const char *, void *, size_t,int); +@@ -953,6 +970,7 @@ extern int register_filesystem(struct fi + extern int unregister_filesystem(struct file_system_type *); + extern struct vfsmount *kern_mount(struct file_system_type *); + extern int may_umount(struct vfsmount *); ++struct vfsmount *do_kern_mount(const char *type, int flags, char *name, void *data); + extern long do_mount(char *, char *, char *, unsigned long, void *); + + extern int vfs_statfs(struct super_block *, struct statfs *); +--- linux-2.5.63/include/linux/namei.h~lustre-2.5.63 Thu Mar 13 20:57:08 2003 ++++ linux-2.5.63-kedar/include/linux/namei.h Thu Mar 13 20:57:08 2003 +@@ -11,6 +11,7 @@ struct nameidata { + struct qstr last; + unsigned int flags; + int last_type; ++ struct lookup_intent it; + }; + + /* +@@ -44,7 +45,7 @@ extern int FASTCALL(link_path_walk(const + extern void path_release(struct nameidata *); + + extern struct dentry * lookup_one_len(const char *, struct dentry *, int); +-extern struct dentry * lookup_hash(struct qstr *, struct dentry *); ++extern struct dentry * lookup_hash(struct qstr *, struct dentry *, struct lookup_intent *); + + extern int follow_down(struct vfsmount **, struct dentry **); + extern int follow_up(struct vfsmount **, struct dentry **); +--- linux-2.5.63/include/linux/slab.h~lustre-2.5.63 Thu Mar 13 20:57:08 2003 ++++ linux-2.5.63-kedar/include/linux/slab.h Thu Mar 13 20:57:08 2003 +@@ -55,6 +55,7 @@ extern int kmem_cache_destroy(kmem_cache + extern int kmem_cache_shrink(kmem_cache_t *); + extern void *kmem_cache_alloc(kmem_cache_t *, int); + extern void kmem_cache_free(kmem_cache_t *, void *); ++extern int kmem_cache_validate(kmem_cache_t *cachep, void *objp); + extern unsigned int kmem_cache_size(kmem_cache_t *); + + extern void *kmalloc(size_t, int); +--- linux-2.5.63/kernel/ksyms.c~lustre-2.5.63 Thu Mar 13 20:57:08 2003 ++++ linux-2.5.63-kedar/kernel/ksyms.c Thu Mar 13 20:57:08 2003 +@@ -377,6 +377,7 @@ EXPORT_SYMBOL(unregister_filesystem); + EXPORT_SYMBOL(kern_mount); + EXPORT_SYMBOL(__mntput); + EXPORT_SYMBOL(may_umount); ++EXPORT_SYMBOL(reparent_to_init); + + /* executable format registration */ + EXPORT_SYMBOL(register_binfmt); +@@ -407,6 +408,12 @@ EXPORT_SYMBOL(request_irq); + EXPORT_SYMBOL(free_irq); + EXPORT_SYMBOL(irq_stat); + ++/* lustre */ ++EXPORT_SYMBOL(do_kern_mount); ++EXPORT_SYMBOL(exit_files); ++EXPORT_SYMBOL(kmem_cache_validate); ++ ++ + /* waitqueue handling */ + EXPORT_SYMBOL(add_wait_queue); + EXPORT_SYMBOL(add_wait_queue_exclusive); +--- linux-2.5.63/mm/slab.c~lustre-2.5.63 Thu Mar 13 20:57:08 2003 ++++ linux-2.5.63-kedar/mm/slab.c Thu Mar 13 20:57:08 2003 +@@ -1792,6 +1792,11 @@ static inline void __cache_free (kmem_ca + } + } + ++int kmem_cache_validate(kmem_cache_t *cachep, void *objp) ++{ ++ return 1; ++} ++ + /** + * kmem_cache_alloc - Allocate an object + * @cachep: The cache to allocate from. +--- linux-2.5.63/net/unix/af_unix.c~lustre-2.5.63 Thu Mar 13 20:57:08 2003 ++++ linux-2.5.63-kedar/net/unix/af_unix.c Thu Mar 13 20:57:08 2003 +@@ -720,7 +720,7 @@ static int unix_bind(struct socket *sock + /* + * Do the final lookup. + */ +- dentry = lookup_hash(&nd.last, nd.dentry); ++ dentry = lookup_hash(&nd.last, nd.dentry, NULL); + err = PTR_ERR(dentry); + if (IS_ERR(dentry)) + goto out_mknod_unlock; +--- linux-2.5.63/fs/dcache.c~lustre-2.5.63 Thu Mar 13 20:57:08 2003 ++++ linux-2.5.63-kedar/fs/dcache.c Thu Mar 13 20:57:08 2003 +@@ -1111,15 +1111,21 @@ void d_delete(struct dentry * dentry) + * Adds a dentry to the hash according to its name. + */ + +-void d_rehash(struct dentry * entry) ++void __d_rehash(struct dentry * entry, int lock) + { + struct list_head *list = d_hash(entry->d_parent, entry->d_name.hash); +- spin_lock(&dcache_lock); ++ if (lock) spin_lock(&dcache_lock); + if (!list_empty(&entry->d_hash) && !d_unhashed(entry)) BUG(); + entry->d_vfs_flags &= ~DCACHE_UNHASHED; + entry->d_bucket = list; + list_add_rcu(&entry->d_hash, list); +- spin_unlock(&dcache_lock); ++ if (lock) spin_unlock(&dcache_lock); ++} ++EXPORT_SYMBOL(__d_rehash); ++ ++void d_rehash(struct dentry * entry) ++{ ++ __d_rehash(entry, 1); + } + + #define do_switch(x,y) do { \ +--- linux-2.5.63/fs/namespace.c~lustre-2.5.63 Thu Mar 13 20:58:54 2003 ++++ linux-2.5.63-kedar/fs/namespace.c Thu Mar 13 20:59:22 2003 +@@ -925,6 +925,7 @@ void set_fs_pwd(struct fs_struct *fs, st + mntput(old_pwdmnt); + } + } ++EXPORT_SYMBOL(set_fs_pwd); + + static void chroot_fs_refs(struct nameidata *old_nd, struct nameidata *new_nd) + { + +_ diff --git a/lustre/kernel_patches/pc/lustre-2.5.63.pc b/lustre/kernel_patches/pc/lustre-2.5.63.pc new file mode 100644 index 0000000..daeea17 --- /dev/null +++ b/lustre/kernel_patches/pc/lustre-2.5.63.pc @@ -0,0 +1,12 @@ +arch/um/kernel/mem.c +fs/namei.c +fs/nfsd/vfs.c +fs/sysfs/inode.c +include/linux/dcache.h +include/linux/fs.h +include/linux/namei.h +include/linux/slab.h +kernel/ksyms.c +mm/slab.c +net/unix/af_unix.c +fs/dcache.c diff --git a/lustre/kernel_patches/series/vanilla-2.5.63 b/lustre/kernel_patches/series/vanilla-2.5.63 new file mode 100644 index 0000000..b77c77b --- /dev/null +++ b/lustre/kernel_patches/series/vanilla-2.5.63 @@ -0,0 +1,2 @@ +lustre_version.patch +lustre-2.5.63.patch diff --git a/lustre/tests/mkdirdeep.c b/lustre/tests/mkdirdeep.c new file mode 100644 index 0000000..cfd1535 --- /dev/null +++ b/lustre/tests/mkdirdeep.c @@ -0,0 +1,275 @@ +/* -*- mode: c; c-basic-offset: 8; indent-tabs-mode: nil; -*- + * vim:expandtab:shiftwidth=8:tabstop=8: + * + * Compile with: + * cc -I../../portals/include -o mkdirdeep mkdirdeep.c + * -L../../portals/linux/utils -lptlctl + */ + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +static int opt_depth = 1; +static int opt_mknod = 0; +static int opt_verbose = 0; +static int opt_trace = 1; +static char* basepathname = 0; +static char mycwd[PATH_MAX]; +static char* pname = 0; +static char* outputfilename = 0; + +void usage() +{ + fprintf(stderr, "Usage: %s --depth --output " + "[--mknod] [--verbose] [--notrace] \n", pname); + exit(1); +} + +int do_mkdir(char* path) +{ + int rc = mkdir(path, 0755); + if (rc!=0) + fprintf(stderr, "mkdir(%s) failed: %s\n", + path, strerror(errno)); + if (opt_verbose) + printf("mkdir %s\n", path); + return rc; +} + + +int do_mknod(char* path) +{ + int rc = mknod(path, 0755, S_IFIFO); + if (rc!=0) + fprintf(stderr, "mkdir(%s) failed: %s\n", + path, strerror(errno)); + if (opt_verbose) + printf("mknod %s\n", path); + return rc; +} + +int do_chdir(char* path) +{ + int rc = chdir(path); + if (rc!=0) + fprintf(stderr, "chdir(%s) failed: %s\n", + path, strerror(errno)); + if (opt_verbose) + printf("chdir %s\n", path); + + return rc; +} + + +int do_stat(char* path) +{ + char mark_buf[PATH_MAX]; + struct stat mystat; + int rc = stat(path, &mystat); + if (rc!=0) + fprintf(stderr, "stat(%s) failed: %s\n", + path, strerror(errno)); + if (opt_verbose) + printf("stat %s = inode %lu\n", path, mystat.st_ino); + + if (opt_trace) { + snprintf(mark_buf, PATH_MAX, "stat %s = inode %lu", + path, mystat.st_ino); + ltrace_mark(0, mark_buf); + } + + return rc; +} + +int main(int argc, char** argv) +{ + int c, opt_index, i, mypid; + + static struct option long_options[] = { + {"depth", 1, 0, 0 }, + {"help", 0, 0, 0 }, + {"mknod", 0, 0, 0 }, + {"verbose", 0, 0, 0 }, + {"notrace", 0, 0, 0 }, + {"output", 1, 0, 0 }, + {0,0,0,0} + }; + + char full_pathname[PATH_MAX]; + char rel_pathname[PATH_MAX]; + char mark_buf[PATH_MAX]; + + pname = strdup(argv[0]); + + while (1) { + c = getopt_long(argc, argv, "d:mhv", long_options, &opt_index); + if (c == -1) + break; + if (c==0) { + if (!strcmp(long_options[opt_index].name, "notrace")) { + opt_trace = 0; + continue; + } + c = long_options[opt_index].name[0]; + } + switch (c) { + case 'd': + opt_depth = atoi(optarg); + if ((opt_depth == 0) || (opt_depth > 100)) + usage(); + break; + case 'm': + opt_mknod = 1; + break; + case 'v': + opt_verbose = 1; + break; + case 'o': + outputfilename = optarg; + break; + case 'h': + case '?': + case ':': + default: + usage(); + break; + } + } + + if (optind != (argc-1)) + usage(); + + if (outputfilename == NULL) + usage(); + + basepathname = argv[optind]; + mypid = getpid(); + + printf("%s(pid=%d) depth=%d mknod=%d, basepathname=%s, " + "trace=%d, outputfilename=%s\n", + pname, mypid, opt_depth, opt_mknod, basepathname, opt_trace, + outputfilename); + + if (!getcwd(&mycwd[0], sizeof(mycwd))) { + fprintf(stderr, "%s: unable to getcwd()\n", pname); + exit(1); + } + + if (opt_trace) { + ltrace_start(); + ltrace_clear(); + snprintf(mark_buf, PATH_MAX, + "Initialize - mkdir %s; chdir %s", + basepathname, basepathname); + ltrace_mark(2, mark_buf); + } + + if (do_mkdir(basepathname)!=0) + exit(1); + if (do_chdir(basepathname)!=0) + exit(1); + + /* Create directory tree with depth level of subdirectories */ + + if (opt_trace) { + snprintf(mark_buf, PATH_MAX, + "Create Directory Tree (depth %d)", opt_depth); + ltrace_mark(2, mark_buf); + } + + for (i=0; i