vserver 1.9.3
[linux-2.6.git] / fs / jfs / namei.c
index abfe33f..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;
        }
@@ -135,7 +138,6 @@ static int jfs_create(struct inode *dip, struct dentry *dentry, int mode,
 
        insert_inode_hash(ip);
        mark_inode_dirty(ip);
-       d_instantiate(dentry, ip);
 
        dip->i_ctime = dip->i_mtime = CURRENT_TIME;
 
@@ -150,7 +152,8 @@ static int jfs_create(struct inode *dip, struct dentry *dentry, int mode,
        if (rc) {
                ip->i_nlink = 0;
                iput(ip);
-       }
+       } else
+               d_instantiate(dentry, ip);
 
       out2:
        free_UCSname(&dname);
@@ -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;
        }
@@ -265,7 +267,6 @@ static int jfs_mkdir(struct inode *dip, struct dentry *dentry, int mode)
 
        insert_inode_hash(ip);
        mark_inode_dirty(ip);
-       d_instantiate(dentry, ip);
 
        /* update parent directory inode */
        dip->i_nlink++;         /* for '..' from child directory */
@@ -281,7 +282,8 @@ static int jfs_mkdir(struct inode *dip, struct dentry *dentry, int mode)
        if (rc) {
                ip->i_nlink = 0;
                iput(ip);
-       }
+       } else
+               d_instantiate(dentry, ip);
 
       out2:
        free_UCSname(&dname);
@@ -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);
        }
 
        /*
@@ -806,12 +814,17 @@ static int jfs_link(struct dentry *old_dentry,
        ip->i_ctime = CURRENT_TIME;
        mark_inode_dirty(dir);
        atomic_inc(&ip->i_count);
-       d_instantiate(dentry, ip);
 
        iplist[0] = ip;
        iplist[1] = dir;
        rc = txCommit(tid, 2, &iplist[0], 0);
 
+       if (rc) {
+               ip->i_nlink--;
+               iput(ip);
+       } else
+               d_instantiate(dentry, ip);
+
       free_dname:
        free_UCSname(&dname);
 
@@ -856,7 +869,7 @@ static int jfs_symlink(struct inode *dip, struct dentry *dentry,
        unchar *i_fastsymlink;
        s64 xlen = 0;
        int bmask = 0, xsize;
-       s64 xaddr;
+       s64 extent = 0, xaddr;
        struct metapage *mp;
        struct super_block *sb;
        struct tblock *tblk;
@@ -890,29 +903,11 @@ static int jfs_symlink(struct inode *dip, struct dentry *dentry,
        down(&JFS_IP(dip)->commit_sem);
        down(&JFS_IP(ip)->commit_sem);
 
-       if ((rc = dtSearch(dip, &dname, &ino, &btstack, JFS_CREATE)))
-               goto out3;
-
        tblk = tid_to_tblock(tid);
        tblk->xflag |= COMMIT_CREATE;
        tblk->ino = ip->i_ino;
        tblk->u.ixpxd = JFS_IP(ip)->ixpxd;
 
-       /*
-        * create entry for symbolic link in parent directory
-        */
-
-       ino = ip->i_ino;
-
-
-
-       if ((rc = dtInsert(tid, dip, &dname, &ino, &btstack))) {
-               jfs_err("jfs_symlink: dtInsert returned %d", rc);
-               /* discard ne inode */
-               goto out3;
-
-       }
-
        /* fix symlink access permission
         * (dir_create() ANDs in the u.u_cmask, 
         * but symlinks really need to be 777 access)
@@ -920,7 +915,7 @@ static int jfs_symlink(struct inode *dip, struct dentry *dentry,
        ip->i_mode |= 0777;
 
        /*
-          *       write symbolic link target path name
+        * write symbolic link target path name
         */
        xtInitRoot(tid, ip);
 
@@ -964,62 +959,59 @@ static int jfs_symlink(struct inode *dip, struct dentry *dentry,
                xsize = (ssize + bmask) & ~bmask;
                xaddr = 0;
                xlen = xsize >> JFS_SBI(sb)->l2bsize;
-               if ((rc = xtInsert(tid, ip, 0, 0, xlen, &xaddr, 0)) == 0) {
-                       ip->i_size = ssize - 1;
-                       while (ssize) {
-                               int copy_size = min(ssize, PSIZE);
-
-                               mp = get_metapage(ip, xaddr, PSIZE, 1);
-
-                               if (mp == NULL) {
-                                       dtDelete(tid, dip, &dname, &ino,
-                                                JFS_REMOVE);
-                                       rc = -EIO;
-                                       goto out3;
-                               }
-                               memcpy(mp->data, name, copy_size);
-                               flush_metapage(mp);
-#if 0
-                               set_buffer_uptodate(bp);
-                               mark_buffer_dirty(bp, 1);
-                               if (IS_SYNC(dip))
-                                       sync_dirty_buffer(bp);
-                               brelse(bp);
-#endif                         /* 0 */
-                               ssize -= copy_size;
-                               xaddr += JFS_SBI(sb)->nbperpage;
-                       }
-                       ip->i_blocks = LBLK2PBLK(sb, xlen);
-               } else {
-                       dtDelete(tid, dip, &dname, &ino, JFS_REMOVE);
+               if ((rc = xtInsert(tid, ip, 0, 0, xlen, &xaddr, 0))) {
+                       txAbort(tid, 0);
                        rc = -ENOSPC;
                        goto out3;
                }
+               extent = xaddr;
+               ip->i_size = ssize - 1;
+               while (ssize) {
+                       /* This is kind of silly since PATH_MAX == 4K */
+                       int copy_size = min(ssize, PSIZE);
+
+                       mp = get_metapage(ip, xaddr, PSIZE, 1);
+
+                       if (mp == NULL) {
+                               xtTruncate(tid, ip, 0, COMMIT_PWMAP);
+                               rc = -EIO;
+                               txAbort(tid, 0);
+                               goto out3;
+                       }
+                       memcpy(mp->data, name, copy_size);
+                       flush_metapage(mp);
+                       ssize -= copy_size;
+                       name += copy_size;
+                       xaddr += JFS_SBI(sb)->nbperpage;
+               }
+       }
+
+       /*
+        * create entry for symbolic link in parent directory
+        */
+       rc = dtSearch(dip, &dname, &ino, &btstack, JFS_CREATE);
+       if (rc == 0) {
+               ino = ip->i_ino;
+               rc = dtInsert(tid, dip, &dname, &ino, &btstack);
+       }
+       if (rc) {
+               if (xlen)
+                       xtTruncate(tid, ip, 0, COMMIT_PWMAP);
+               txAbort(tid, 0);
+               /* discard new inode */
+               goto out3;
        }
 
        insert_inode_hash(ip);
        mark_inode_dirty(ip);
-       d_instantiate(dentry, ip);
 
        /*
         * commit update of parent directory and link object
-        *
-        * if extent allocation failed (ENOSPC),
-        * the parent inode is committed regardless to avoid
-        * backing out parent directory update (by dtInsert())
-        * and subsequent dtDelete() which is harmless wrt 
-        * integrity concern.  
-        * the symlink inode will be freed by iput() at exit
-        * as it has a zero link count (by dtDelete()) and 
-        * no permanant resources. 
         */
 
        iplist[0] = dip;
-       if (rc == 0) {
-               iplist[1] = ip;
-               rc = txCommit(tid, 2, &iplist[0], 0);
-       } else
-               rc = txCommit(tid, 1, &iplist[0], 0);
+       iplist[1] = ip;
+       rc = txCommit(tid, 2, &iplist[0], 0);
 
       out3:
        txEnd(tid);
@@ -1028,7 +1020,8 @@ static int jfs_symlink(struct inode *dip, struct dentry *dentry,
        if (rc) {
                ip->i_nlink = 0;
                iput(ip);
-       }
+       } else
+               d_instantiate(dentry, ip);
 
       out2:
        free_UCSname(&dname);
@@ -1119,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
@@ -1189,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))
@@ -1221,7 +1217,7 @@ static int jfs_rename(struct inode *old_dir, struct dentry *old_dentry,
                        /* Linelock header of dtree */
                        tlck = txLock(tid, old_ip,
                                    (struct metapage *) &JFS_IP(old_ip)->bxflag,
-                                     tlckDTREE | tlckBTROOT);
+                                     tlckDTREE | tlckBTROOT | tlckRELINK);
                        dtlck = (struct dt_lock *) & tlck->lock;
                        ASSERT(dtlck->index == 0);
                        lv = & dtlck->lv[0];
@@ -1368,7 +1364,6 @@ static int jfs_mknod(struct inode *dir, struct dentry *dentry,
 
        insert_inode_hash(ip);
        mark_inode_dirty(ip);
-       d_instantiate(dentry, ip);
 
        dir->i_ctime = dir->i_mtime = CURRENT_TIME;
 
@@ -1385,7 +1380,8 @@ static int jfs_mknod(struct inode *dir, struct dentry *dentry,
        if (rc) {
                ip->i_nlink = 0;
                iput(ip);
-       }
+       } else
+               d_instantiate(dentry, ip);
 
       out1:
        free_UCSname(&dname);
@@ -1439,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)
@@ -1493,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,
+};