/*
- * 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
*/
#include <linux/fs.h>
+#include <linux/ctype.h>
+#include <linux/quotaops.h>
#include "jfs_incore.h"
#include "jfs_superblock.h"
#include "jfs_inode.h"
*/
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 *);
*/
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;
}
insert_inode_hash(ip);
mark_inode_dirty(ip);
- d_instantiate(dentry, ip);
dip->i_ctime = dip->i_mtime = CURRENT_TIME;
if (rc) {
ip->i_nlink = 0;
iput(ip);
- }
+ } else
+ d_instantiate(dentry, ip);
out2:
free_UCSname(&dname);
*/
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;
}
insert_inode_hash(ip);
mark_inode_dirty(ip);
- d_instantiate(dentry, ip);
/* update parent directory inode */
dip->i_nlink++; /* for '..' from child directory */
if (rc) {
ip->i_nlink = 0;
iput(ip);
- }
+ } else
+ d_instantiate(dentry, ip);
out2:
free_UCSname(&dname);
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;
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;
pxdlock->flag = mlckFREEPXD;
PXDaddress(&pxdlock->pxd, xaddr);
PXDlength(&pxdlock->pxd, xlen);
- txFreeMap(ip, pxdlock, 0, COMMIT_WMAP);
+ txFreeMap(ip, pxdlock, NULL, COMMIT_WMAP);
}
/*
pxdlock->flag = mlckFREEPXD;
PXDaddress(&pxdlock->pxd, xaddr);
PXDlength(&pxdlock->pxd, xlen);
- txFreeMap(ip, pxdlock, 0, COMMIT_WMAP);
+ txFreeMap(ip, pxdlock, NULL, COMMIT_WMAP);
}
/*
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);
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;
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)
ip->i_mode |= 0777;
/*
- * write symbolic link target path name
+ * write symbolic link target path name
*/
xtInitRoot(tid, ip);
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);
if (rc) {
ip->i_nlink = 0;
iput(ip);
- }
+ } else
+ d_instantiate(dentry, ip);
out2:
free_UCSname(&dname);
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
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))
/* 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];
old_ip->i_ctime = CURRENT_TIME;
mark_inode_dirty(old_ip);
- new_dir->i_ctime = new_dir->i_mtime = CURRENT_TIME;
+ new_dir->i_ctime = new_dir->i_mtime = current_fs_time(new_dir->i_sb);
mark_inode_dirty(new_dir);
/* Build list of inodes modified by this transaction */
insert_inode_hash(ip);
mark_inode_dirty(ip);
- d_instantiate(dentry, ip);
dir->i_ctime = dir->i_mtime = CURRENT_TIME;
if (rc) {
ip->i_nlink = 0;
iput(ip);
- }
+ } else
+ d_instantiate(dentry, ip);
out1:
free_UCSname(&dname);
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)
.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,
+};