--- linux-2.4.20/fs/reiserfs/namei.c    Fri Nov 29 02:53:15 2002
+++ linux-2.4.20-t/fs/reiserfs/namei.c  Wed Jan 15 17:08:20 2003
@@ -488,27 +488,58 @@
    return 0;
}

+/* quota utility function, call if you've had to abort after calling
+** new_inode_init, and have not called reiserfs_new_inode yet.
+** This should only be called on inodes that do not hav stat data
+** inserted into the tree yet.
+*/
+static int drop_new_inode(struct inode *inode) {
+    make_bad_inode(inode) ;
+    iput(inode) ;
+    return 0 ;
+}
+
+/* utility function that does setup for reiserfs_new_inode.
+** DQUOT_ALLOC_INODE cannot be called inside a transaction, so we had
+** to pull some bits of reiserfs_new_inode out into this func.
+*/
+static int new_inode_init(struct inode *inode, struct inode *dir, int mode) {
+
+    /* the quota init calls have to know who to charge the quota to, so
+    ** we have to set uid and gid here
+    */
+    inode->i_uid = current->fsuid;
+    inode->i_mode = mode;
+
+    if (dir->i_mode & S_ISGID) {
+        inode->i_gid = dir->i_gid;
+        if (S_ISDIR(mode))
+            inode->i_mode |= S_ISGID;
+    } else
+        inode->i_gid = current->fsgid;

+    return 0 ;
+}
+
static int reiserfs_create (struct inode * dir, struct dentry *dentry, int mode)
{
    int retval;
    struct inode * inode;
-    int windex ;
    int jbegin_count = JOURNAL_PER_BALANCE_CNT * 2 ;
    struct reiserfs_transaction_handle th ;

-
    if (!(inode = new_inode(dir->i_sb))) {
       return -ENOMEM ;
    }
+    retval = new_inode_init(inode, dir, mode) ;
+    if (retval)
+       return retval ;
+
    journal_begin(&th, dir->i_sb, jbegin_count) ;
    th.t_caller = "create" ;
-    windex = push_journal_writer("reiserfs_create") ;
-    inode = reiserfs_new_inode (&th, dir, mode, 0, 0/*i_size*/, dentry, inode, &retval);
-    if (!inode) {
-       pop_journal_writer(windex) ;
-       journal_end(&th, dir->i_sb, jbegin_count) ;
-       return retval;
+    retval = reiserfs_new_inode (&th, dir, mode, 0, 0/*i_size*/, dentry, inode);
+    if (retval) {
+       goto out_failed ;
    }

    inode->i_op = &reiserfs_file_inode_operations;
@@ -520,20 +551,19 @@
    if (retval) {
       inode->i_nlink--;
       reiserfs_update_sd (&th, inode);
-       pop_journal_writer(windex) ;
-       // FIXME: should we put iput here and have stat data deleted
-       // in the same transactioin
       journal_end(&th, dir->i_sb, jbegin_count) ;
-       iput (inode);
-       return retval;
+       iput(inode) ;
+       goto out_failed ;
    }
    reiserfs_update_inode_transaction(inode) ;
    reiserfs_update_inode_transaction(dir) ;

    d_instantiate(dentry, inode);
-    pop_journal_writer(windex) ;
    journal_end(&th, dir->i_sb, jbegin_count) ;
    return 0;
+
+out_failed:
+    return retval ;
}


@@ -541,21 +571,21 @@
{
    int retval;
    struct inode * inode;
-    int windex ;
    struct reiserfs_transaction_handle th ;
    int jbegin_count = JOURNAL_PER_BALANCE_CNT * 3;

    if (!(inode = new_inode(dir->i_sb))) {
       return -ENOMEM ;
    }
+    retval = new_inode_init(inode, dir, mode) ;
+    if (retval)
+        return retval ;
+
    journal_begin(&th, dir->i_sb, jbegin_count) ;
-    windex = push_journal_writer("reiserfs_mknod") ;

-    inode = reiserfs_new_inode (&th, dir, mode, 0, 0/*i_size*/, dentry, inode, &retval);
-    if (!inode) {
-       pop_journal_writer(windex) ;
-       journal_end(&th, dir->i_sb, jbegin_count) ;
-       return retval;
+    retval = reiserfs_new_inode(&th, dir, mode, 0, 0/*i_size*/, dentry, inode);
+    if (retval) {
+       goto out_failed;
    }

    init_special_inode(inode, mode, rdev) ;
@@ -571,16 +601,17 @@
    if (retval) {
       inode->i_nlink--;
       reiserfs_update_sd (&th, inode);
-       pop_journal_writer(windex) ;
       journal_end(&th, dir->i_sb, jbegin_count) ;
-       iput (inode);
-       return retval;
+       iput(inode) ;
+        goto out_failed;
    }

    d_instantiate(dentry, inode);
-    pop_journal_writer(windex) ;
    journal_end(&th, dir->i_sb, jbegin_count) ;
    return 0;
+
+out_failed:
+    return retval ;
}


@@ -588,15 +619,18 @@
{
    int retval;
    struct inode * inode;
-    int windex ;
    struct reiserfs_transaction_handle th ;
    int jbegin_count = JOURNAL_PER_BALANCE_CNT * 3;

+    mode = S_IFDIR | mode;
    if (!(inode = new_inode(dir->i_sb))) {
       return -ENOMEM ;
    }
+    retval = new_inode_init(inode, dir, mode) ;
+    if (retval)
+       return retval ;
+
    journal_begin(&th, dir->i_sb, jbegin_count) ;
-    windex = push_journal_writer("reiserfs_mkdir") ;

    /* inc the link count now, so another writer doesn't overflow it while
    ** we sleep later on.
@@ -607,15 +641,13 @@
    /* set flag that new packing locality created and new blocks for the content     * of that directory are not displaced yet */
    dir->u.reiserfs_i.new_packing_locality = 1;
#endif
-    mode = S_IFDIR | mode;
-    inode = reiserfs_new_inode (&th, dir, mode, 0/*symlink*/,
-                               old_format_only (dir->i_sb) ? EMPTY_DIR_SIZE_V1 : EMPTY_DIR_SIZE,
-                               dentry, inode, &retval);
-    if (!inode) {
-       pop_journal_writer(windex) ;
+    retval = reiserfs_new_inode(&th, dir, mode, 0/*symlink*/,
+                               old_format_only (dir->i_sb) ?
+                               EMPTY_DIR_SIZE_V1 : EMPTY_DIR_SIZE,
+                               dentry, inode) ;
+    if (retval) {
       dir->i_nlink-- ;
-       journal_end(&th, dir->i_sb, jbegin_count) ;
-       return retval;
+       goto out_failed ;
    }
    reiserfs_update_inode_transaction(inode) ;
    reiserfs_update_inode_transaction(dir) ;
@@ -630,19 +662,20 @@
       inode->i_nlink = 0;
       DEC_DIR_INODE_NLINK(dir);
       reiserfs_update_sd (&th, inode);
-       pop_journal_writer(windex) ;
       journal_end(&th, dir->i_sb, jbegin_count) ;
-       iput (inode);
-       return retval;
+       iput(inode) ;
+       goto out_failed ;
    }

    // the above add_entry did not update dir's stat data
    reiserfs_update_sd (&th, dir);

    d_instantiate(dentry, inode);
-    pop_journal_writer(windex) ;
    journal_end(&th, dir->i_sb, jbegin_count) ;
    return 0;
+
+out_failed:
+    return retval ;
}

static inline int reiserfs_empty_dir(struct inode *inode) {
@@ -820,7 +853,7 @@
    struct inode * inode;
    char * name;
    int item_len;
-    int windex ;
+    int mode = S_IFLNK | S_IRWXUGO ;
    struct reiserfs_transaction_handle th ;
    int jbegin_count = JOURNAL_PER_BALANCE_CNT * 3;

@@ -828,31 +861,34 @@
    if (!(inode = new_inode(parent_dir->i_sb))) {
       return -ENOMEM ;
    }
+    retval = new_inode_init(inode, parent_dir, mode) ;
+    if (retval) {
+       return retval ;
+    }

    item_len = ROUND_UP (strlen (symname));
    if (item_len > MAX_DIRECT_ITEM_LEN (parent_dir->i_sb->s_blocksize)) {
-       iput(inode) ;
-       return -ENAMETOOLONG;
+       retval = -ENAMETOOLONG;
+       drop_new_inode(inode) ;
+       goto out_failed ;
    }

    name = reiserfs_kmalloc (item_len, GFP_NOFS, parent_dir->i_sb);
    if (!name) {
-       iput(inode) ;
-       return -ENOMEM;
+       retval = -ENOMEM;
+       drop_new_inode(inode) ;
+       goto out_failed ;
    }
    memcpy (name, symname, strlen (symname));
    padd_item (name, item_len, strlen (symname));

    journal_begin(&th, parent_dir->i_sb, jbegin_count) ;
-    windex = push_journal_writer("reiserfs_symlink") ;

-    inode = reiserfs_new_inode (&th, parent_dir, S_IFLNK | S_IRWXUGO, name, strlen (symname), dentry,
-                               inode, &retval);
+    retval = reiserfs_new_inode(&th, parent_dir, mode, name,
+                               strlen(symname), dentry, inode) ;
    reiserfs_kfree (name, item_len, parent_dir->i_sb);
-    if (inode == 0) { /* reiserfs_new_inode iputs for us */
-       pop_journal_writer(windex) ;
-       journal_end(&th, parent_dir->i_sb, jbegin_count) ;
-       return retval;
+    if (retval) {
+       goto out_failed ;
    }

    reiserfs_update_inode_transaction(inode) ;
@@ -870,16 +906,17 @@
    if (retval) {
       inode->i_nlink--;
       reiserfs_update_sd (&th, inode);
-       pop_journal_writer(windex) ;
       journal_end(&th, parent_dir->i_sb, jbegin_count) ;
-       iput (inode);
-       return retval;
+       iput(inode) ;
+       goto out_failed ;
    }

    d_instantiate(dentry, inode);
-    pop_journal_writer(windex) ;
    journal_end(&th, parent_dir->i_sb, jbegin_count) ;
    return 0;
+
+out_failed:
+    return retval ;
}


--- linux-2.4.20/fs/reiserfs/inode.c    Fri Nov 29 02:53:15 2002
+++ linux-2.4.20-t/fs/reiserfs/inode.c  Wed Jan 15 17:08:20 2003
@@ -1463,13 +1463,22 @@
/* inserts the stat data into the tree, and then calls
   reiserfs_new_directory (to insert ".", ".." item if new object is
   directory) or reiserfs_new_symlink (to insert symlink body if new
-   object is symlink) or nothing (if new object is regular file) */
-struct inode * reiserfs_new_inode (struct reiserfs_transaction_handle *th,
-                                  struct inode * dir, int mode,
-                                  const char * symname,
-                                  int i_size, /* 0 for regular, EMTRY_DIR_SIZE for dirs,
-                                                 strlen (symname) for symlinks)*/
-                                  struct dentry *dentry, struct inode *inode, int * err)
+   object is symlink) or nothing (if new object is regular file)
+
+   NOTE! uid and gid must already be set in the inode.  If we return
+   non-zero due to an error, we have to drop the quota previously allocated
+   for the fresh inode.  This can only be done outside a transaction, so
+   if we return non-zero, we also end the transaction.
+
+   */
+int reiserfs_new_inode (struct reiserfs_transaction_handle *th,
+                               struct inode * dir, int mode,
+                               const char * symname,
+                               /* 0 for regular, EMTRY_DIR_SIZE for dirs,
+                                  strlen (symname) for symlinks) */
+                               int i_size,
+                               struct dentry *dentry,
+                               struct inode *inode)
{
    struct super_block * sb;
    INITIALIZE_PATH (path_to_key);
@@ -1477,11 +1486,11 @@
    struct item_head ih;
    struct stat_data sd;
    int retval;
+    int err ;

    if (!dir || !dir->i_nlink) {
-       *err = -EPERM;
-       iput(inode) ;
-       return NULL;
+       err = -EPERM ;
+       goto out_bad_inode ;
    }

    sb = dir->i_sb;
@@ -1489,13 +1498,16 @@
           dir -> u.reiserfs_i.i_attrs & REISERFS_INHERIT_MASK;
    sd_attrs_to_i_attrs( inode -> u.reiserfs_i.i_attrs, inode );

+    /* symlink cannot be immutable or append only, right? */
+    if( S_ISLNK( inode -> i_mode ) )
+           inode -> i_flags &= ~ ( S_IMMUTABLE | S_APPEND );
+
    /* item head of new item */
    ih.ih_key.k_dir_id = INODE_PKEY (dir)->k_objectid;
    ih.ih_key.k_objectid = cpu_to_le32 (reiserfs_get_unused_objectid (th));
    if (!ih.ih_key.k_objectid) {
-       iput(inode) ;
-       *err = -ENOMEM;
-       return NULL;
+       err = -ENOMEM ;
+       goto out_bad_inode ;
    }
    if (old_format_only (sb))
      /* not a perfect generation count, as object ids can be reused, but this
@@ -1511,12 +1523,24 @@
#else
      inode->i_generation = ++event;
#endif
+    /* fill stat data */
+    inode->i_nlink = (S_ISDIR (mode) ? 2 : 1);
+
+    /* uid and gid must already be set by the caller for quota init */
+
+    inode->i_mtime = inode->i_atime = inode->i_ctime = CURRENT_TIME;
+    inode->i_size = i_size;
+    inode->i_blocks = (inode->i_size + 511) >> 9;
+    inode->u.reiserfs_i.i_first_direct_byte = S_ISLNK(mode) ? 1 :
+      U32_MAX/*NO_BYTES_IN_DIRECT_ITEM*/;
+
+    INIT_LIST_HEAD(&inode->u.reiserfs_i.i_prealloc_list) ;
+
    if (old_format_only (sb))
       make_le_item_head (&ih, 0, KEY_FORMAT_3_5, SD_OFFSET, TYPE_STAT_DATA, SD_V1_SIZE, MAX_US_INT);
    else
       make_le_item_head (&ih, 0, KEY_FORMAT_3_6, SD_OFFSET, TYPE_STAT_DATA, SD_SIZE, MAX_US_INT);

-
    /* key to search for correct place for new stat data */
    _make_cpu_key (&key, KEY_FORMAT_3_6, le32_to_cpu (ih.ih_key.k_dir_id),
                  le32_to_cpu (ih.ih_key.k_objectid), SD_OFFSET, TYPE_STAT_DATA, 3/*key length*/);
@@ -1524,47 +1548,21 @@
    /* find proper place for inserting of stat data */
    retval = search_item (sb, &key, &path_to_key);
    if (retval == IO_ERROR) {
-       iput (inode);
-       *err = -EIO;
-       return NULL;
+       err = -EIO;
+       goto out_bad_inode;
    }
    if (retval == ITEM_FOUND) {
       pathrelse (&path_to_key);
-       iput (inode);
-       *err = -EEXIST;
-       return NULL;
+       err = -EEXIST;
+       goto out_bad_inode;
    }

-    /* fill stat data */
-    inode->i_mode = mode;
-    inode->i_nlink = (S_ISDIR (mode) ? 2 : 1);
-    inode->i_uid = current->fsuid;
-    if (dir->i_mode & S_ISGID) {
-       inode->i_gid = dir->i_gid;
-       if (S_ISDIR(mode))
-           inode->i_mode |= S_ISGID;
-    } else
-       inode->i_gid = current->fsgid;
-
-    /* symlink cannot be immutable or append only, right? */
-    if( S_ISLNK( inode -> i_mode ) )
-           inode -> i_flags &= ~ ( S_IMMUTABLE | S_APPEND );
-
-    inode->i_mtime = inode->i_atime = inode->i_ctime = CURRENT_TIME;
-    inode->i_size = i_size;
-    inode->i_blocks = (inode->i_size + 511) >> 9;
-    inode->u.reiserfs_i.i_first_direct_byte = S_ISLNK(mode) ? 1 :
-      U32_MAX/*NO_BYTES_IN_DIRECT_ITEM*/;
-
-    INIT_LIST_HEAD(&inode->u.reiserfs_i.i_prealloc_list) ;
-
    if (old_format_only (sb)) {
       if (inode->i_uid & ~0xffff || inode->i_gid & ~0xffff) {
           pathrelse (&path_to_key);
           /* i_uid or i_gid is too big to be stored in stat data v3.5 */
-           iput (inode);
-           *err = -EINVAL;
-           return NULL;
+           err = -EINVAL;
+           goto out_bad_inode;
       }
       inode2sd_v1 (&sd, inode);
    } else
@@ -1595,10 +1593,9 @@
#endif
    retval = reiserfs_insert_item (th, &path_to_key, &key, &ih, (char *)(&sd));
    if (retval) {
-       iput (inode);
-       *err = retval;
       reiserfs_check_path(&path_to_key) ;
-       return NULL;
+       err = retval;
+       goto out_bad_inode;
    }

#ifdef DISPLACE_NEW_PACKING_LOCALITIES
@@ -1617,19 +1614,30 @@
       retval = reiserfs_new_symlink (th, &ih, &path_to_key, symname, i_size);
    }
    if (retval) {
-      inode->i_nlink = 0;
-       iput (inode);
-       *err = retval;
+       err = retval;
       reiserfs_check_path(&path_to_key) ;
-       return NULL;
+       journal_end(th, th->t_super, th->t_blocks_allocated) ;
+       goto out_inserted_sd;
    }

    insert_inode_hash (inode);
-    // we do not mark inode dirty: on disk content matches to the
-    // in-core one
+    reiserfs_update_sd(th, inode) ;
    reiserfs_check_path(&path_to_key) ;

-    return inode;
+    return 0;
+out_bad_inode:
+    /* Invalidate the object, nothing was inserted yet */
+    INODE_PKEY(inode)->k_objectid = 0;
+
+    /* dquot_drop must be done outside a transaction */
+    journal_end(th, th->t_super, th->t_blocks_allocated) ;
+    make_bad_inode(inode);
+
+out_inserted_sd:
+    inode->i_nlink = 0;
+    th->t_trans_id = 0 ; /* so the caller can't use this handle later */
+    iput(inode) ;
+    return err;
}

/*
--- linux-2.4.20/include/linux/reiserfs_fs.h    Tue Dec 10 13:47:47 2002
+++ linux-2.4.20-t/include/linux/reiserfs_fs.h  Wed Jan 15 15:51:06 2003
@@ -1748,11 +1748,12 @@
struct inode * reiserfs_iget (struct super_block * s,
                             const struct cpu_key * key);

-
-struct inode * reiserfs_new_inode (struct reiserfs_transaction_handle *th,
-                                  struct inode * dir, int mode,
-                                  const char * symname, int item_len,
-                                  struct dentry *dentry, struct inode *inode, int * err);
+int reiserfs_new_inode (struct reiserfs_transaction_handle *th,
+                               struct inode * dir, int mode,
+                               const char * symname,
+                               int i_size,
+                               struct dentry *dentry,
+                               struct inode *inode);
int reiserfs_sync_inode (struct reiserfs_transaction_handle *th, struct inode * inode);
void reiserfs_update_sd (struct reiserfs_transaction_handle *th, struct inode * inode);