/*
- * 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 <linux/vserver/xid.h>
#include "jfs_incore.h"
#include "jfs_superblock.h"
#include "jfs_inode.h"
#include "jfs_acl.h"
#include "jfs_debug.h"
-extern struct inode_operations jfs_file_inode_operations;
-extern struct inode_operations jfs_symlink_inode_operations;
-extern struct file_operations jfs_file_operations;
-extern struct address_space_operations jfs_aops;
-
-extern int jfs_fsync(struct file *, struct dentry *, int);
-extern void jfs_truncate_nolock(struct inode *, loff_t);
-extern int jfs_init_acl(struct inode *, struct inode *);
-
/*
* forward references
*/
-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 *);
+/*
+ * NAME: free_ea_wmap(inode)
+ *
+ * FUNCTION: free uncommitted extended attributes from working map
+ *
+ */
+static inline void free_ea_wmap(struct inode *inode)
+{
+ dxd_t *ea = &JFS_IP(inode)->ea;
+
+ if (ea->flag & DXD_EXTENT) {
+ /* free EA pages from cache */
+ invalidate_dxd_metapages(inode, *ea);
+ dbFree(inode, addressDXD(ea), lengthDXD(ea));
+ }
+ ea->flag = 0;
+}
+
/*
* NAME: jfs_create(dip, dentry, mode)
*
down(&JFS_IP(dip)->commit_sem);
down(&JFS_IP(ip)->commit_sem);
+ rc = jfs_init_acl(tid, ip, dip);
+ if (rc)
+ goto out3;
+
+ rc = jfs_init_security(tid, ip, dip);
+ if (rc) {
+ txAbort(tid, 0);
+ goto out3;
+ }
+
if ((rc = dtSearch(dip, &dname, &ino, &btstack, JFS_CREATE))) {
jfs_err("jfs_create: dtSearch returned %d", rc);
+ txAbort(tid, 0);
goto out3;
}
*/
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;
}
up(&JFS_IP(dip)->commit_sem);
up(&JFS_IP(ip)->commit_sem);
if (rc) {
+ free_ea_wmap(ip);
ip->i_nlink = 0;
iput(ip);
} else
out2:
free_UCSname(&dname);
-#ifdef CONFIG_JFS_POSIX_ACL
- if (rc == 0)
- jfs_init_acl(ip, dip);
-#endif
-
out1:
jfs_info("jfs_create: rc:%d", rc);
down(&JFS_IP(dip)->commit_sem);
down(&JFS_IP(ip)->commit_sem);
+ rc = jfs_init_acl(tid, ip, dip);
+ if (rc)
+ goto out3;
+
+ rc = jfs_init_security(tid, ip, dip);
+ if (rc) {
+ txAbort(tid, 0);
+ goto out3;
+ }
+
if ((rc = dtSearch(dip, &dname, &ino, &btstack, JFS_CREATE))) {
jfs_err("jfs_mkdir: dtSearch returned %d", rc);
+ txAbort(tid, 0);
goto out3;
}
*/
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;
}
ip->i_nlink = 2; /* for '.' */
ip->i_op = &jfs_dir_inode_operations;
ip->i_fop = &jfs_dir_operations;
- ip->i_mapping->a_ops = &jfs_aops;
- mapping_set_gfp_mask(ip->i_mapping, GFP_NOFS);
insert_inode_hash(ip);
mark_inode_dirty(ip);
up(&JFS_IP(dip)->commit_sem);
up(&JFS_IP(ip)->commit_sem);
if (rc) {
+ free_ea_wmap(ip);
ip->i_nlink = 0;
iput(ip);
} else
out2:
free_UCSname(&dname);
-#ifdef CONFIG_JFS_POSIX_ACL
- if (rc == 0)
- jfs_init_acl(ip, dip);
-#endif
out1:
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;
/*
- * NAME: freeZeroLink()
+ * NAME: jfs_free_zero_link()
*
* FUNCTION: for non-directory, called by iClose(),
* free resources of a file from cache and WORKING map
* while associated with a pager object,
*
* PARAMETER: ip - pointer to inode of file.
- *
- * RETURN: 0 -ok
*/
-int freeZeroLink(struct inode *ip)
+void jfs_free_zero_link(struct inode *ip)
{
- int rc = 0;
int type;
- jfs_info("freeZeroLink: ip = 0x%p", ip);
+ jfs_info("jfs_free_zero_link: ip = 0x%p", ip);
/* return if not reg or symbolic link or if size is
* already ok.
case S_IFLNK:
/* if its contained in inode nothing to do */
if (ip->i_size < IDATASIZE)
- return 0;
+ return;
break;
default:
- return 0;
+ return;
}
/*
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);
}
/*
* free xtree/data blocks from working block map;
*/
if (ip->i_size)
- rc = xtTruncate(0, ip, 0, COMMIT_WMAP);
-
- return rc;
+ xtTruncate(0, ip, 0, COMMIT_WMAP);
}
/*
/* update object inode */
ip->i_nlink++; /* for new link */
ip->i_ctime = CURRENT_TIME;
+ dir->i_ctime = dir->i_mtime = CURRENT_TIME;
mark_inode_dirty(dir);
atomic_inc(&ip->i_count);
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:
down(&JFS_IP(dip)->commit_sem);
down(&JFS_IP(ip)->commit_sem);
+ rc = jfs_init_security(tid, ip, dip);
+ if (rc)
+ goto out3;
+
tblk = tid_to_tblock(tid);
tblk->xflag |= COMMIT_CREATE;
tblk->ino = ip->i_ino;
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;
name += copy_size;
xaddr += JFS_SBI(sb)->nbperpage;
}
- ip->i_blocks = LBLK2PBLK(sb, xlen);
}
/*
}
if (rc) {
if (xlen)
- dbFree(ip, extent, xlen);
+ xtTruncate(tid, ip, 0, COMMIT_PWMAP);
txAbort(tid, 0);
/* discard new inode */
goto out3;
insert_inode_hash(ip);
mark_inode_dirty(ip);
+ dip->i_ctime = dip->i_mtime = CURRENT_TIME;
+ mark_inode_dirty(dip);
/*
* commit update of parent directory and link object
*/
up(&JFS_IP(dip)->commit_sem);
up(&JFS_IP(ip)->commit_sem);
if (rc) {
+ free_ea_wmap(ip);
ip->i_nlink = 0;
iput(ip);
} else
out2:
free_UCSname(&dname);
-#ifdef CONFIG_JFS_POSIX_ACL
- if (rc == 0)
- jfs_init_acl(ip, dip);
-#endif
-
out1:
jfs_info("jfs_symlink: rc:%d", rc);
return rc;
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))
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 */
down(&JFS_IP(dir)->commit_sem);
down(&JFS_IP(ip)->commit_sem);
- if ((rc = dtSearch(dir, &dname, &ino, &btstack, JFS_CREATE)))
+ rc = jfs_init_acl(tid, ip, dir);
+ if (rc)
goto out3;
+ rc = jfs_init_security(tid, ip, dir);
+ if (rc) {
+ txAbort(tid, 0);
+ goto out3;
+ }
+
+ if ((rc = dtSearch(dir, &dname, &ino, &btstack, JFS_CREATE))) {
+ txAbort(tid, 0);
+ goto out3;
+ }
+
tblk = tid_to_tblock(tid);
tblk->xflag |= COMMIT_CREATE;
tblk->ino = ip->i_ino;
tblk->u.ixpxd = JFS_IP(ip)->ixpxd;
ino = ip->i_ino;
- if ((rc = dtInsert(tid, dir, &dname, &ino, &btstack)))
+ if ((rc = dtInsert(tid, dir, &dname, &ino, &btstack))) {
+ txAbort(tid, 0);
goto out3;
+ }
ip->i_op = &jfs_file_inode_operations;
jfs_ip->dev = new_encode_dev(rdev);
up(&JFS_IP(ip)->commit_sem);
up(&JFS_IP(dir)->commit_sem);
if (rc) {
+ free_ea_wmap(ip);
ip->i_nlink = 0;
iput(ip);
} else
out1:
free_UCSname(&dname);
-#ifdef CONFIG_JFS_POSIX_ACL
- if (rc == 0)
- jfs_init_acl(ip, dir);
-#endif
-
out:
jfs_info("jfs_mknod: returning %d", rc);
return rc;
jfs_info("jfs_lookup: name = %s", name);
+ if (JFS_SBI(dip->i_sb)->mntflag & JFS_OS2)
+ dentry->d_op = &jfs_ci_dentry_operations;
if ((name[0] == '.') && (len == 1))
inum = dip->i_ino;
return ERR_PTR(-EACCES);
}
- return d_splice_alias(ip, dentry);
+ vx_propagate_xid(nd, ip);
+ 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,
+};