vserver 1.9.3
[linux-2.6.git] / fs / jfs / namei.c
index 998410c..e089615 100644 (file)
@@ -1,5 +1,5 @@
 /*
- *   Copyright (C) International Business Machines Corp., 2000-2003
+ *   Copyright (C) International Business Machines Corp., 2000-2004
  *   Portions Copyright (C) Christoph Hellwig, 2001-2002
  *
  *   This program is free software;  you can redistribute it and/or modify
@@ -18,6 +18,8 @@
  */
 
 #include <linux/fs.h>
+#include <linux/ctype.h>
+#include <linux/quotaops.h>
 #include "jfs_incore.h"
 #include "jfs_superblock.h"
 #include "jfs_inode.h"
@@ -43,6 +45,7 @@ extern int jfs_init_acl(struct inode *, struct inode *);
  */
 struct inode_operations jfs_dir_inode_operations;
 struct file_operations jfs_dir_operations;
+struct dentry_operations jfs_ci_dentry_operations;
 
 static s64 commitZeroLink(tid_t, struct inode *);
 
@@ -121,10 +124,10 @@ static int jfs_create(struct inode *dip, struct dentry *dentry, int mode,
         */
        ino = ip->i_ino;
        if ((rc = dtInsert(tid, dip, &dname, &ino, &btstack))) {
-               jfs_err("jfs_create: dtInsert returned %d", rc);
-               if (rc == -EIO)
+               if (rc == -EIO) {
+                       jfs_err("jfs_create: dtInsert returned -EIO");
                        txAbort(tid, 1);        /* Marks Filesystem dirty */
-               else
+               else
                        txAbort(tid, 0);        /* Filesystem full */
                goto out3;
        }
@@ -248,11 +251,10 @@ static int jfs_mkdir(struct inode *dip, struct dentry *dentry, int mode)
         */
        ino = ip->i_ino;
        if ((rc = dtInsert(tid, dip, &dname, &ino, &btstack))) {
-               jfs_err("jfs_mkdir: dtInsert returned %d", rc);
-
-               if (rc == -EIO)
+               if (rc == -EIO) {
+                       jfs_err("jfs_mkdir: dtInsert returned -EIO");
                        txAbort(tid, 1);        /* Marks Filesystem dirty */
-               else
+               else
                        txAbort(tid, 0);        /* Filesystem full */
                goto out3;
        }
@@ -328,6 +330,9 @@ static int jfs_rmdir(struct inode *dip, struct dentry *dentry)
 
        jfs_info("jfs_rmdir: dip:0x%p name:%s", dip, dentry->d_name.name);
 
+       /* Init inode for quota operations. */
+       DQUOT_INIT(ip);
+
        /* directory must be empty to be removed */
        if (!dtEmpty(ip)) {
                rc = -ENOTEMPTY;
@@ -453,6 +458,9 @@ static int jfs_unlink(struct inode *dip, struct dentry *dentry)
 
        jfs_info("jfs_unlink: dip:0x%p name:%s", dip, dentry->d_name.name);
 
+       /* Init inode for quota operations. */
+       DQUOT_INIT(ip);
+
        if ((rc = get_UCSname(&dname, dentry)))
                goto out;
 
@@ -702,7 +710,7 @@ int freeZeroLink(struct inode *ip)
                pxdlock->flag = mlckFREEPXD;
                PXDaddress(&pxdlock->pxd, xaddr);
                PXDlength(&pxdlock->pxd, xlen);
-               txFreeMap(ip, pxdlock, 0, COMMIT_WMAP);
+               txFreeMap(ip, pxdlock, NULL, COMMIT_WMAP);
        }
 
        /*
@@ -722,7 +730,7 @@ int freeZeroLink(struct inode *ip)
                pxdlock->flag = mlckFREEPXD;
                PXDaddress(&pxdlock->pxd, xaddr);
                PXDlength(&pxdlock->pxd, xlen);
-               txFreeMap(ip, pxdlock, 0, COMMIT_WMAP);
+               txFreeMap(ip, pxdlock, NULL, COMMIT_WMAP);
        }
 
        /*
@@ -811,7 +819,10 @@ static int jfs_link(struct dentry *old_dentry,
        iplist[1] = dir;
        rc = txCommit(tid, 2, &iplist[0], 0);
 
-       if (!rc)
+       if (rc) {
+               ip->i_nlink--;
+               iput(ip);
+       } else
                d_instantiate(dentry, ip);
 
       free_dname:
@@ -962,7 +973,7 @@ static int jfs_symlink(struct inode *dip, struct dentry *dentry,
                        mp = get_metapage(ip, xaddr, PSIZE, 1);
 
                        if (mp == NULL) {
-                               dbFree(ip, extent, xlen);
+                               xtTruncate(tid, ip, 0, COMMIT_PWMAP);
                                rc = -EIO;
                                txAbort(tid, 0);
                                goto out3;
@@ -973,7 +984,6 @@ static int jfs_symlink(struct inode *dip, struct dentry *dentry,
                        name += copy_size;
                        xaddr += JFS_SBI(sb)->nbperpage;
                }
-               ip->i_blocks = LBLK2PBLK(sb, xlen);
        }
 
        /*
@@ -986,7 +996,7 @@ static int jfs_symlink(struct inode *dip, struct dentry *dentry,
        }
        if (rc) {
                if (xlen)
-                       dbFree(ip, extent, xlen);
+                       xtTruncate(tid, ip, 0, COMMIT_PWMAP);
                txAbort(tid, 0);
                /* discard new inode */
                goto out3;
@@ -1102,8 +1112,11 @@ static int jfs_rename(struct inode *old_dir, struct dentry *old_dentry,
                        rc = -EMLINK;
                        goto out3;
                }
-       } else if (new_ip)
+       } else if (new_ip) {
                IWRITE_LOCK(new_ip);
+               /* Init inode for quota operations. */
+               DQUOT_INIT(new_ip);
+       }
 
        /*
         * The real work starts here
@@ -1172,8 +1185,8 @@ static int jfs_rename(struct inode *old_dir, struct dentry *old_dentry,
                ino = old_ip->i_ino;
                rc = dtInsert(tid, new_dir, &new_dname, &ino, &btstack);
                if (rc) {
-                       jfs_err("jfs_rename: dtInsert failed w/rc = %d",
-                               rc);
+                       if (rc == -EIO)
+                               jfs_err("jfs_rename: dtInsert returned -EIO");
                        goto out4;
                }
                if (S_ISDIR(old_ip->i_mode))
@@ -1422,7 +1435,15 @@ static struct dentry *jfs_lookup(struct inode *dip, struct dentry *dentry, struc
                return ERR_PTR(-EACCES);
        }
 
-       return d_splice_alias(ip, dentry);
+       if (JFS_SBI(dip->i_sb)->mntflag & JFS_OS2)
+               dentry->d_op = &jfs_ci_dentry_operations;
+
+       dentry = d_splice_alias(ip, dentry);
+
+       if (dentry && (JFS_SBI(dip->i_sb)->mntflag & JFS_OS2))
+               dentry->d_op = &jfs_ci_dentry_operations;
+
+       return dentry;
 }
 
 struct dentry *jfs_get_parent(struct dentry *dentry)
@@ -1476,3 +1497,46 @@ struct file_operations jfs_dir_operations = {
        .readdir        = jfs_readdir,
        .fsync          = jfs_fsync,
 };
+
+static int jfs_ci_hash(struct dentry *dir, struct qstr *this)
+{
+       unsigned long hash;
+       int i;
+
+       hash = init_name_hash();
+       for (i=0; i < this->len; i++)
+               hash = partial_name_hash(tolower(this->name[i]), hash);
+       this->hash = end_name_hash(hash);
+
+       return 0;
+}
+
+static int jfs_ci_compare(struct dentry *dir, struct qstr *a, struct qstr *b)
+{
+       int i, result = 1;
+
+       if (a->len != b->len)
+               goto out;
+       for (i=0; i < a->len; i++) {
+               if (tolower(a->name[i]) != tolower(b->name[i]))
+                       goto out;
+       }
+       result = 0;
+
+       /*
+        * We want creates to preserve case.  A negative dentry, a, that
+        * has a different case than b may cause a new entry to be created
+        * with the wrong case.  Since we can't tell if a comes from a negative
+        * dentry, we blindly replace it with b.  This should be harmless if
+        * a is not a negative dentry.
+        */
+       memcpy((unsigned char *)a->name, b->name, a->len);
+out:
+       return result;
+}
+
+struct dentry_operations jfs_ci_dentry_operations =
+{
+       .d_hash = jfs_ci_hash,
+       .d_compare = jfs_ci_compare,
+};