X-Git-Url: http://git.onelab.eu/?a=blobdiff_plain;f=fs%2Fjfs%2Fnamei.c;h=fa91e489d817aa87cac19c88a686ad7afc499d3a;hb=97bf2856c6014879bd04983a3e9dfcdac1e7fe85;hp=998410cccaa03e6d07a8fb32fc89fa4218207ac4;hpb=9213980e6a70d8473e0ffd4b39ab5b6caaba9ff5;p=linux-2.6.git diff --git a/fs/jfs/namei.c b/fs/jfs/namei.c index 998410ccc..fa91e489d 100644 --- a/fs/jfs/namei.c +++ b/fs/jfs/namei.c @@ -1,23 +1,26 @@ /* - * 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 * it under the terms of the GNU General Public License as published by - * the Free Software Foundation; either version 2 of the License, or + * the Free Software Foundation; either version 2 of the License, or * (at your option) any later version. - * + * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See * the GNU General Public License for more details. * * You should have received a copy of the GNU General Public License - * along with this program; if not, write to the Free Software + * along with this program; if not, write to the Free Software * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA */ #include +#include +#include +#include #include "jfs_incore.h" #include "jfs_superblock.h" #include "jfs_inode.h" @@ -29,30 +32,38 @@ #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) * * FUNCTION: create a regular file in the parent directory * with name = and mode = * - * PARAMETER: dip - parent directory vnode + * PARAMETER: dip - parent directory vnode * dentry - dentry of new file * mode - create mode (rwxrwxrwx). * nd- nd struct @@ -87,18 +98,29 @@ static int jfs_create(struct inode *dip, struct dentry *dentry, int mode, * begin the transaction before we search the directory. */ ip = ialloc(dip, mode); - if (ip == NULL) { - rc = -ENOSPC; + if (IS_ERR(ip)) { + rc = PTR_ERR(ip); goto out2; } tid = txBegin(dip->i_sb, 0); - down(&JFS_IP(dip)->commit_sem); - down(&JFS_IP(ip)->commit_sem); + mutex_lock(&JFS_IP(dip)->commit_mutex); + mutex_lock(&JFS_IP(ip)->commit_mutex); + + 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; } @@ -121,10 +143,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; } @@ -144,9 +166,10 @@ static int jfs_create(struct inode *dip, struct dentry *dentry, int mode, out3: txEnd(tid); - up(&JFS_IP(dip)->commit_sem); - up(&JFS_IP(ip)->commit_sem); + mutex_unlock(&JFS_IP(ip)->commit_mutex); + mutex_unlock(&JFS_IP(dip)->commit_mutex); if (rc) { + free_ea_wmap(ip); ip->i_nlink = 0; iput(ip); } else @@ -155,11 +178,6 @@ static int jfs_create(struct inode *dip, struct dentry *dentry, int mode, 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); @@ -173,7 +191,7 @@ static int jfs_create(struct inode *dip, struct dentry *dentry, int mode, * FUNCTION: create a child directory in the parent directory * with name = and mode = * - * PARAMETER: dip - parent directory vnode + * PARAMETER: dip - parent directory vnode * dentry - dentry of child directory * mode - create mode (rwxrwxrwx). * @@ -214,18 +232,29 @@ static int jfs_mkdir(struct inode *dip, struct dentry *dentry, int mode) * begin the transaction before we search the directory. */ ip = ialloc(dip, S_IFDIR | mode); - if (ip == NULL) { - rc = -ENOSPC; + if (IS_ERR(ip)) { + rc = PTR_ERR(ip); goto out2; } tid = txBegin(dip->i_sb, 0); - down(&JFS_IP(dip)->commit_sem); - down(&JFS_IP(ip)->commit_sem); + mutex_lock(&JFS_IP(dip)->commit_mutex); + mutex_lock(&JFS_IP(ip)->commit_mutex); + + 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; } @@ -248,11 +277,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; } @@ -260,14 +288,12 @@ static int jfs_mkdir(struct inode *dip, struct dentry *dentry, int mode) 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); /* update parent directory inode */ - dip->i_nlink++; /* for '..' from child directory */ + inc_nlink(dip); /* for '..' from child directory */ dip->i_ctime = dip->i_mtime = CURRENT_TIME; mark_inode_dirty(dip); @@ -275,9 +301,10 @@ static int jfs_mkdir(struct inode *dip, struct dentry *dentry, int mode) out3: txEnd(tid); - up(&JFS_IP(dip)->commit_sem); - up(&JFS_IP(ip)->commit_sem); + mutex_unlock(&JFS_IP(ip)->commit_mutex); + mutex_unlock(&JFS_IP(dip)->commit_mutex); if (rc) { + free_ea_wmap(ip); ip->i_nlink = 0; iput(ip); } else @@ -286,10 +313,6 @@ static int jfs_mkdir(struct inode *dip, struct dentry *dentry, int mode) out2: free_UCSname(&dname); -#ifdef CONFIG_JFS_POSIX_ACL - if (rc == 0) - jfs_init_acl(ip, dip); -#endif out1: @@ -302,7 +325,7 @@ static int jfs_mkdir(struct inode *dip, struct dentry *dentry, int mode) * * FUNCTION: remove a link to child directory * - * PARAMETER: dip - parent inode + * PARAMETER: dip - parent inode * dentry - child directory dentry * * RETURN: -EINVAL - if name is . or .. @@ -310,10 +333,10 @@ static int jfs_mkdir(struct inode *dip, struct dentry *dentry, int mode) * errors from subroutines * * note: - * if other threads have the directory open when the last link - * is removed, the "." and ".." entries, if present, are removed before - * rmdir() returns and no new entries may be created in the directory, - * but the directory is not removed until the last reference to + * if other threads have the directory open when the last link + * is removed, the "." and ".." entries, if present, are removed before + * rmdir() returns and no new entries may be created in the directory, + * but the directory is not removed until the last reference to * the directory is released (cf.unlink() of regular file). */ static int jfs_rmdir(struct inode *dip, struct dentry *dentry) @@ -328,6 +351,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; @@ -340,8 +366,8 @@ static int jfs_rmdir(struct inode *dip, struct dentry *dentry) tid = txBegin(dip->i_sb, 0); - down(&JFS_IP(dip)->commit_sem); - down(&JFS_IP(ip)->commit_sem); + mutex_lock(&JFS_IP(dip)->commit_mutex); + mutex_lock(&JFS_IP(ip)->commit_mutex); iplist[0] = dip; iplist[1] = ip; @@ -359,8 +385,8 @@ static int jfs_rmdir(struct inode *dip, struct dentry *dentry) if (rc == -EIO) txAbort(tid, 1); txEnd(tid); - up(&JFS_IP(dip)->commit_sem); - up(&JFS_IP(ip)->commit_sem); + mutex_unlock(&JFS_IP(ip)->commit_mutex); + mutex_unlock(&JFS_IP(dip)->commit_mutex); goto out2; } @@ -368,9 +394,8 @@ static int jfs_rmdir(struct inode *dip, struct dentry *dentry) /* update parent directory's link count corresponding * to ".." entry of the target directory deleted */ - dip->i_nlink--; dip->i_ctime = dip->i_mtime = CURRENT_TIME; - mark_inode_dirty(dip); + inode_dec_link_count(dip); /* * OS/2 could have created EA and/or ACL @@ -390,15 +415,15 @@ static int jfs_rmdir(struct inode *dip, struct dentry *dentry) JFS_IP(ip)->acl.flag = 0; /* mark the target directory as deleted */ - ip->i_nlink = 0; + clear_nlink(ip); mark_inode_dirty(ip); rc = txCommit(tid, 2, &iplist[0], 0); txEnd(tid); - up(&JFS_IP(dip)->commit_sem); - up(&JFS_IP(ip)->commit_sem); + mutex_unlock(&JFS_IP(ip)->commit_mutex); + mutex_unlock(&JFS_IP(dip)->commit_mutex); /* * Truncating the directory index table is not guaranteed. It @@ -422,11 +447,11 @@ static int jfs_rmdir(struct inode *dip, struct dentry *dentry) /* * NAME: jfs_unlink(dip, dentry) * - * FUNCTION: remove a link to object named by + * FUNCTION: remove a link to object named by * from parent directory * - * PARAMETER: dip - inode of parent directory - * dentry - dentry of object to be removed + * PARAMETER: dip - inode of parent directory + * dentry - dentry of object to be removed * * RETURN: errors from subroutines * @@ -453,6 +478,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; @@ -460,8 +488,8 @@ static int jfs_unlink(struct inode *dip, struct dentry *dentry) tid = txBegin(dip->i_sb, 0); - down(&JFS_IP(dip)->commit_sem); - down(&JFS_IP(ip)->commit_sem); + mutex_lock(&JFS_IP(dip)->commit_mutex); + mutex_lock(&JFS_IP(ip)->commit_mutex); iplist[0] = dip; iplist[1] = ip; @@ -475,8 +503,8 @@ static int jfs_unlink(struct inode *dip, struct dentry *dentry) if (rc == -EIO) txAbort(tid, 1); /* Marks FS Dirty */ txEnd(tid); - up(&JFS_IP(dip)->commit_sem); - up(&JFS_IP(ip)->commit_sem); + mutex_unlock(&JFS_IP(ip)->commit_mutex); + mutex_unlock(&JFS_IP(dip)->commit_mutex); IWRITE_UNLOCK(ip); goto out1; } @@ -487,8 +515,7 @@ static int jfs_unlink(struct inode *dip, struct dentry *dentry) mark_inode_dirty(dip); /* update target's inode */ - ip->i_nlink--; - mark_inode_dirty(ip); + inode_dec_link_count(ip); /* * commit zero link count object @@ -499,8 +526,8 @@ static int jfs_unlink(struct inode *dip, struct dentry *dentry) if ((new_size = commitZeroLink(tid, ip)) < 0) { txAbort(tid, 1); /* Marks FS Dirty */ txEnd(tid); - up(&JFS_IP(dip)->commit_sem); - up(&JFS_IP(ip)->commit_sem); + mutex_unlock(&JFS_IP(ip)->commit_mutex); + mutex_unlock(&JFS_IP(dip)->commit_mutex); IWRITE_UNLOCK(ip); rc = new_size; goto out1; @@ -528,13 +555,12 @@ static int jfs_unlink(struct inode *dip, struct dentry *dentry) txEnd(tid); - up(&JFS_IP(dip)->commit_sem); - up(&JFS_IP(ip)->commit_sem); - + mutex_unlock(&JFS_IP(ip)->commit_mutex); + mutex_unlock(&JFS_IP(dip)->commit_mutex); while (new_size && (rc == 0)) { tid = txBegin(dip->i_sb, 0); - down(&JFS_IP(ip)->commit_sem); + mutex_lock(&JFS_IP(ip)->commit_mutex); new_size = xtTruncate_pmap(tid, ip, new_size); if (new_size < 0) { txAbort(tid, 1); /* Marks FS Dirty */ @@ -542,7 +568,7 @@ static int jfs_unlink(struct inode *dip, struct dentry *dentry) } else rc = txCommit(tid, 2, &iplist[0], COMMIT_SYNC); txEnd(tid); - up(&JFS_IP(ip)->commit_sem); + mutex_unlock(&JFS_IP(ip)->commit_mutex); } if (ip->i_nlink == 0) @@ -573,7 +599,7 @@ static int jfs_unlink(struct inode *dip, struct dentry *dentry) * * FUNCTION: for non-directory, called by jfs_remove(), * truncate a regular file, directory or symbolic - * link to zero length. return 0 if type is not + * link to zero length. return 0 if type is not * one of these. * * if the file is currently associated with a VM segment @@ -583,7 +609,7 @@ static int jfs_unlink(struct inode *dip, struct dentry *dentry) * map by ctrunc1. * if there is no VM segment on entry, the resources are * freed in both work and permanent map. - * (? for temporary file - memory object is cached even + * (? for temporary file - memory object is cached even * after no reference: * reference count > 0 - ) * @@ -637,7 +663,7 @@ static s64 commitZeroLink(tid_t tid, struct inode *ip) /* * free xtree/data (truncate to zero length): - * free xtree/data pages from cache if COMMIT_PWMAP, + * free xtree/data pages from cache if COMMIT_PWMAP, * free xtree/data blocks from persistent block map, and * free xtree/data blocks from working block map if COMMIT_PWMAP; */ @@ -649,23 +675,20 @@ static s64 commitZeroLink(tid_t tid, struct inode *ip) /* - * NAME: freeZeroLink() + * NAME: jfs_free_zero_link() * * FUNCTION: for non-directory, called by iClose(), - * free resources of a file from cache and WORKING map + * free resources of a file from cache and WORKING map * for a file previously committed with zero link count * 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. @@ -678,10 +701,10 @@ int freeZeroLink(struct inode *ip) case S_IFLNK: /* if its contained in inode nothing to do */ if (ip->i_size < IDATASIZE) - return 0; + return; break; default: - return 0; + return; } /* @@ -702,7 +725,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 +745,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); } /* @@ -731,9 +754,7 @@ int freeZeroLink(struct inode *ip) * 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); } /* @@ -742,7 +763,7 @@ int freeZeroLink(struct inode *ip) * FUNCTION: create a link to by the name = * in the parent directory * - * PARAMETER: vp - target object + * PARAMETER: vp - target object * dvp - parent directory of new link * name - name of new link to target object * crp - credential @@ -782,8 +803,8 @@ static int jfs_link(struct dentry *old_dentry, tid = txBegin(ip->i_sb, 0); - down(&JFS_IP(dir)->commit_sem); - down(&JFS_IP(ip)->commit_sem); + mutex_lock(&JFS_IP(dir)->commit_mutex); + mutex_lock(&JFS_IP(ip)->commit_mutex); /* * scan parent directory for entry/freespace @@ -802,8 +823,9 @@ static int jfs_link(struct dentry *old_dentry, goto free_dname; /* update object inode */ - ip->i_nlink++; /* for new link */ + inc_nlink(ip); /* 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); @@ -811,7 +833,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--; /* never instantiated */ + iput(ip); + } else d_instantiate(dentry, ip); free_dname: @@ -820,8 +845,8 @@ static int jfs_link(struct dentry *old_dentry, out: txEnd(tid); - up(&JFS_IP(dir)->commit_sem); - up(&JFS_IP(ip)->commit_sem); + mutex_unlock(&JFS_IP(ip)->commit_mutex); + mutex_unlock(&JFS_IP(dir)->commit_mutex); jfs_info("jfs_link: rc:%d", rc); return rc; @@ -834,8 +859,8 @@ static int jfs_link(struct dentry *old_dentry, * in directory * * PARAMETER: dip - parent directory vnode - * dentry - dentry of symbolic link - * name - the path name of the existing object + * dentry - dentry of symbolic link + * name - the path name of the existing object * that will be the source of the link * * RETURN: errors from subroutines @@ -882,15 +907,19 @@ static int jfs_symlink(struct inode *dip, struct dentry *dentry, * (iAlloc() returns new, locked inode) */ ip = ialloc(dip, S_IFLNK | 0777); - if (ip == NULL) { - rc = -ENOSPC; + if (IS_ERR(ip)) { + rc = PTR_ERR(ip); goto out2; } tid = txBegin(dip->i_sb, 0); - down(&JFS_IP(dip)->commit_sem); - down(&JFS_IP(ip)->commit_sem); + mutex_lock(&JFS_IP(dip)->commit_mutex); + mutex_lock(&JFS_IP(ip)->commit_mutex); + + rc = jfs_init_security(tid, ip, dip); + if (rc) + goto out3; tblk = tid_to_tblock(tid); tblk->xflag |= COMMIT_CREATE; @@ -898,7 +927,7 @@ static int jfs_symlink(struct inode *dip, struct dentry *dentry, tblk->u.ixpxd = JFS_IP(ip)->ixpxd; /* fix symlink access permission - * (dir_create() ANDs in the u.u_cmask, + * (dir_create() ANDs in the u.u_cmask, * but symlinks really need to be 777 access) */ ip->i_mode |= 0777; @@ -939,7 +968,7 @@ static int jfs_symlink(struct inode *dip, struct dentry *dentry, ip->i_mapping->a_ops = &jfs_aops; /* - * even though the data of symlink object (source + * even though the data of symlink object (source * path name) is treated as non-journaled user data, * it is read/written thru buffer cache for performance. */ @@ -950,7 +979,6 @@ static int jfs_symlink(struct inode *dip, struct dentry *dentry, xlen = xsize >> JFS_SBI(sb)->l2bsize; if ((rc = xtInsert(tid, ip, 0, 0, xlen, &xaddr, 0))) { txAbort(tid, 0); - rc = -ENOSPC; goto out3; } extent = xaddr; @@ -962,7 +990,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 +1001,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 +1013,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; @@ -995,6 +1022,8 @@ static int jfs_symlink(struct inode *dip, struct dentry *dentry, 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 */ @@ -1005,9 +1034,10 @@ static int jfs_symlink(struct inode *dip, struct dentry *dentry, out3: txEnd(tid); - up(&JFS_IP(dip)->commit_sem); - up(&JFS_IP(ip)->commit_sem); + mutex_unlock(&JFS_IP(ip)->commit_mutex); + mutex_unlock(&JFS_IP(dip)->commit_mutex); if (rc) { + free_ea_wmap(ip); ip->i_nlink = 0; iput(ip); } else @@ -1016,11 +1046,6 @@ static int jfs_symlink(struct inode *dip, struct dentry *dentry, 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; @@ -1102,21 +1127,24 @@ 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 */ tid = txBegin(new_dir->i_sb, 0); - down(&JFS_IP(new_dir)->commit_sem); - down(&JFS_IP(old_ip)->commit_sem); + mutex_lock(&JFS_IP(new_dir)->commit_mutex); + mutex_lock(&JFS_IP(old_ip)->commit_mutex); if (old_dir != new_dir) - down(&JFS_IP(old_dir)->commit_sem); + mutex_lock(&JFS_IP(old_dir)->commit_mutex); if (new_ip) { - down(&JFS_IP(new_ip)->commit_sem); + mutex_lock(&JFS_IP(new_ip)->commit_mutex); /* * Change existing directory entry to new inode number */ @@ -1125,14 +1153,15 @@ static int jfs_rename(struct inode *old_dir, struct dentry *old_dentry, old_ip->i_ino, JFS_RENAME); if (rc) goto out4; - new_ip->i_nlink--; + drop_nlink(new_ip); if (S_ISDIR(new_ip->i_mode)) { - new_ip->i_nlink--; + drop_nlink(new_ip); if (new_ip->i_nlink) { - up(&JFS_IP(new_dir)->commit_sem); - up(&JFS_IP(old_ip)->commit_sem); + mutex_unlock(&JFS_IP(new_ip)->commit_mutex); if (old_dir != new_dir) - up(&JFS_IP(old_dir)->commit_sem); + mutex_unlock(&JFS_IP(old_dir)->commit_mutex); + mutex_unlock(&JFS_IP(old_ip)->commit_mutex); + mutex_unlock(&JFS_IP(new_dir)->commit_mutex); if (!S_ISDIR(old_ip->i_mode) && new_ip) IWRITE_UNLOCK(new_ip); jfs_error(new_ip->i_sb, @@ -1147,7 +1176,7 @@ static int jfs_rename(struct inode *old_dir, struct dentry *old_dentry, /* free block resources */ if ((new_size = commitZeroLink(tid, new_ip)) < 0) { txAbort(tid, 1); /* Marks FS Dirty */ - rc = new_size; + rc = new_size; goto out4; } tblk = tid_to_tblock(tid); @@ -1172,12 +1201,12 @@ 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)) - new_dir->i_nlink++; + inc_nlink(new_dir); } /* * Remove old directory entry @@ -1192,7 +1221,7 @@ static int jfs_rename(struct inode *old_dir, struct dentry *old_dentry, goto out4; } if (S_ISDIR(old_ip->i_mode)) { - old_dir->i_nlink--; + drop_nlink(old_dir); if (old_dir != new_dir) { /* * Change inode number of parent for moved directory @@ -1220,7 +1249,7 @@ static int jfs_rename(struct inode *old_dir, struct dentry *old_dentry, 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 */ @@ -1250,25 +1279,24 @@ static int jfs_rename(struct inode *old_dir, struct dentry *old_dentry, out4: txEnd(tid); - - up(&JFS_IP(new_dir)->commit_sem); - up(&JFS_IP(old_ip)->commit_sem); - if (old_dir != new_dir) - up(&JFS_IP(old_dir)->commit_sem); if (new_ip) - up(&JFS_IP(new_ip)->commit_sem); + mutex_unlock(&JFS_IP(new_ip)->commit_mutex); + if (old_dir != new_dir) + mutex_unlock(&JFS_IP(old_dir)->commit_mutex); + mutex_unlock(&JFS_IP(old_ip)->commit_mutex); + mutex_unlock(&JFS_IP(new_dir)->commit_mutex); while (new_size && (rc == 0)) { tid = txBegin(new_ip->i_sb, 0); - down(&JFS_IP(new_ip)->commit_sem); + mutex_lock(&JFS_IP(new_ip)->commit_mutex); new_size = xtTruncate_pmap(tid, new_ip, new_size); if (new_size < 0) { txAbort(tid, 1); - rc = new_size; + rc = new_size; } else rc = txCommit(tid, 1, &new_ip, COMMIT_SYNC); txEnd(tid); - up(&JFS_IP(new_ip)->commit_sem); + mutex_unlock(&JFS_IP(new_ip)->commit_mutex); } if (new_ip && (new_ip->i_nlink == 0)) set_cflag(COMMIT_Nolink, new_ip); @@ -1322,28 +1350,42 @@ static int jfs_mknod(struct inode *dir, struct dentry *dentry, goto out; ip = ialloc(dir, mode); - if (ip == NULL) { - rc = -ENOSPC; + if (IS_ERR(ip)) { + rc = PTR_ERR(ip); goto out1; } jfs_ip = JFS_IP(ip); tid = txBegin(dir->i_sb, 0); - down(&JFS_IP(dir)->commit_sem); - down(&JFS_IP(ip)->commit_sem); + mutex_lock(&JFS_IP(dir)->commit_mutex); + mutex_lock(&JFS_IP(ip)->commit_mutex); - 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); @@ -1362,9 +1404,10 @@ static int jfs_mknod(struct inode *dir, struct dentry *dentry, out3: txEnd(tid); - up(&JFS_IP(ip)->commit_sem); - up(&JFS_IP(dir)->commit_sem); + mutex_unlock(&JFS_IP(ip)->commit_mutex); + mutex_unlock(&JFS_IP(dir)->commit_mutex); if (rc) { + free_ea_wmap(ip); ip->i_nlink = 0; iput(ip); } else @@ -1373,11 +1416,6 @@ static int jfs_mknod(struct inode *dir, struct dentry *dentry, 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; @@ -1395,6 +1433,8 @@ static struct dentry *jfs_lookup(struct inode *dip, struct dentry *dentry, struc 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; @@ -1422,7 +1462,13 @@ static struct dentry *jfs_lookup(struct inode *dip, struct dentry *dentry, struc return ERR_PTR(-EACCES); } - return d_splice_alias(ip, dentry); + dx_propagate_tag(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) @@ -1469,10 +1515,55 @@ struct inode_operations jfs_dir_inode_operations = { .setattr = jfs_setattr, .permission = jfs_permission, #endif + .sync_flags = jfs_sync_flags, }; -struct file_operations jfs_dir_operations = { +const struct file_operations jfs_dir_operations = { .read = generic_read_dir, .readdir = jfs_readdir, .fsync = jfs_fsync, + .ioctl = jfs_ioctl, +}; + +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, };