162306a36Sopenharmony_ci// SPDX-License-Identifier: GPL-2.0-or-later 262306a36Sopenharmony_ci/* 362306a36Sopenharmony_ci * Copyright (C) International Business Machines Corp., 2000-2004 462306a36Sopenharmony_ci * Portions Copyright (C) Christoph Hellwig, 2001-2002 562306a36Sopenharmony_ci */ 662306a36Sopenharmony_ci 762306a36Sopenharmony_ci#include <linux/fs.h> 862306a36Sopenharmony_ci#include <linux/namei.h> 962306a36Sopenharmony_ci#include <linux/ctype.h> 1062306a36Sopenharmony_ci#include <linux/quotaops.h> 1162306a36Sopenharmony_ci#include <linux/exportfs.h> 1262306a36Sopenharmony_ci#include "jfs_incore.h" 1362306a36Sopenharmony_ci#include "jfs_superblock.h" 1462306a36Sopenharmony_ci#include "jfs_inode.h" 1562306a36Sopenharmony_ci#include "jfs_dinode.h" 1662306a36Sopenharmony_ci#include "jfs_dmap.h" 1762306a36Sopenharmony_ci#include "jfs_unicode.h" 1862306a36Sopenharmony_ci#include "jfs_metapage.h" 1962306a36Sopenharmony_ci#include "jfs_xattr.h" 2062306a36Sopenharmony_ci#include "jfs_acl.h" 2162306a36Sopenharmony_ci#include "jfs_debug.h" 2262306a36Sopenharmony_ci 2362306a36Sopenharmony_ci/* 2462306a36Sopenharmony_ci * forward references 2562306a36Sopenharmony_ci */ 2662306a36Sopenharmony_ciconst struct dentry_operations jfs_ci_dentry_operations; 2762306a36Sopenharmony_ci 2862306a36Sopenharmony_cistatic s64 commitZeroLink(tid_t, struct inode *); 2962306a36Sopenharmony_ci 3062306a36Sopenharmony_ci/* 3162306a36Sopenharmony_ci * NAME: free_ea_wmap(inode) 3262306a36Sopenharmony_ci * 3362306a36Sopenharmony_ci * FUNCTION: free uncommitted extended attributes from working map 3462306a36Sopenharmony_ci * 3562306a36Sopenharmony_ci */ 3662306a36Sopenharmony_cistatic inline void free_ea_wmap(struct inode *inode) 3762306a36Sopenharmony_ci{ 3862306a36Sopenharmony_ci dxd_t *ea = &JFS_IP(inode)->ea; 3962306a36Sopenharmony_ci 4062306a36Sopenharmony_ci if (ea->flag & DXD_EXTENT) { 4162306a36Sopenharmony_ci /* free EA pages from cache */ 4262306a36Sopenharmony_ci invalidate_dxd_metapages(inode, *ea); 4362306a36Sopenharmony_ci dbFree(inode, addressDXD(ea), lengthDXD(ea)); 4462306a36Sopenharmony_ci } 4562306a36Sopenharmony_ci ea->flag = 0; 4662306a36Sopenharmony_ci} 4762306a36Sopenharmony_ci 4862306a36Sopenharmony_ci/* 4962306a36Sopenharmony_ci * NAME: jfs_create(dip, dentry, mode) 5062306a36Sopenharmony_ci * 5162306a36Sopenharmony_ci * FUNCTION: create a regular file in the parent directory <dip> 5262306a36Sopenharmony_ci * with name = <from dentry> and mode = <mode> 5362306a36Sopenharmony_ci * 5462306a36Sopenharmony_ci * PARAMETER: dip - parent directory vnode 5562306a36Sopenharmony_ci * dentry - dentry of new file 5662306a36Sopenharmony_ci * mode - create mode (rwxrwxrwx). 5762306a36Sopenharmony_ci * nd- nd struct 5862306a36Sopenharmony_ci * 5962306a36Sopenharmony_ci * RETURN: Errors from subroutines 6062306a36Sopenharmony_ci * 6162306a36Sopenharmony_ci */ 6262306a36Sopenharmony_cistatic int jfs_create(struct mnt_idmap *idmap, struct inode *dip, 6362306a36Sopenharmony_ci struct dentry *dentry, umode_t mode, bool excl) 6462306a36Sopenharmony_ci{ 6562306a36Sopenharmony_ci int rc = 0; 6662306a36Sopenharmony_ci tid_t tid; /* transaction id */ 6762306a36Sopenharmony_ci struct inode *ip = NULL; /* child directory inode */ 6862306a36Sopenharmony_ci ino_t ino; 6962306a36Sopenharmony_ci struct component_name dname; /* child directory name */ 7062306a36Sopenharmony_ci struct btstack btstack; 7162306a36Sopenharmony_ci struct inode *iplist[2]; 7262306a36Sopenharmony_ci struct tblock *tblk; 7362306a36Sopenharmony_ci 7462306a36Sopenharmony_ci jfs_info("jfs_create: dip:0x%p name:%pd", dip, dentry); 7562306a36Sopenharmony_ci 7662306a36Sopenharmony_ci rc = dquot_initialize(dip); 7762306a36Sopenharmony_ci if (rc) 7862306a36Sopenharmony_ci goto out1; 7962306a36Sopenharmony_ci 8062306a36Sopenharmony_ci /* 8162306a36Sopenharmony_ci * search parent directory for entry/freespace 8262306a36Sopenharmony_ci * (dtSearch() returns parent directory page pinned) 8362306a36Sopenharmony_ci */ 8462306a36Sopenharmony_ci if ((rc = get_UCSname(&dname, dentry))) 8562306a36Sopenharmony_ci goto out1; 8662306a36Sopenharmony_ci 8762306a36Sopenharmony_ci /* 8862306a36Sopenharmony_ci * Either iAlloc() or txBegin() may block. Deadlock can occur if we 8962306a36Sopenharmony_ci * block there while holding dtree page, so we allocate the inode & 9062306a36Sopenharmony_ci * begin the transaction before we search the directory. 9162306a36Sopenharmony_ci */ 9262306a36Sopenharmony_ci ip = ialloc(dip, mode); 9362306a36Sopenharmony_ci if (IS_ERR(ip)) { 9462306a36Sopenharmony_ci rc = PTR_ERR(ip); 9562306a36Sopenharmony_ci goto out2; 9662306a36Sopenharmony_ci } 9762306a36Sopenharmony_ci 9862306a36Sopenharmony_ci tid = txBegin(dip->i_sb, 0); 9962306a36Sopenharmony_ci 10062306a36Sopenharmony_ci mutex_lock_nested(&JFS_IP(dip)->commit_mutex, COMMIT_MUTEX_PARENT); 10162306a36Sopenharmony_ci mutex_lock_nested(&JFS_IP(ip)->commit_mutex, COMMIT_MUTEX_CHILD); 10262306a36Sopenharmony_ci 10362306a36Sopenharmony_ci rc = jfs_init_acl(tid, ip, dip); 10462306a36Sopenharmony_ci if (rc) 10562306a36Sopenharmony_ci goto out3; 10662306a36Sopenharmony_ci 10762306a36Sopenharmony_ci rc = jfs_init_security(tid, ip, dip, &dentry->d_name); 10862306a36Sopenharmony_ci if (rc) { 10962306a36Sopenharmony_ci txAbort(tid, 0); 11062306a36Sopenharmony_ci goto out3; 11162306a36Sopenharmony_ci } 11262306a36Sopenharmony_ci 11362306a36Sopenharmony_ci if ((rc = dtSearch(dip, &dname, &ino, &btstack, JFS_CREATE))) { 11462306a36Sopenharmony_ci jfs_err("jfs_create: dtSearch returned %d", rc); 11562306a36Sopenharmony_ci txAbort(tid, 0); 11662306a36Sopenharmony_ci goto out3; 11762306a36Sopenharmony_ci } 11862306a36Sopenharmony_ci 11962306a36Sopenharmony_ci tblk = tid_to_tblock(tid); 12062306a36Sopenharmony_ci tblk->xflag |= COMMIT_CREATE; 12162306a36Sopenharmony_ci tblk->ino = ip->i_ino; 12262306a36Sopenharmony_ci tblk->u.ixpxd = JFS_IP(ip)->ixpxd; 12362306a36Sopenharmony_ci 12462306a36Sopenharmony_ci iplist[0] = dip; 12562306a36Sopenharmony_ci iplist[1] = ip; 12662306a36Sopenharmony_ci 12762306a36Sopenharmony_ci /* 12862306a36Sopenharmony_ci * initialize the child XAD tree root in-line in inode 12962306a36Sopenharmony_ci */ 13062306a36Sopenharmony_ci xtInitRoot(tid, ip); 13162306a36Sopenharmony_ci 13262306a36Sopenharmony_ci /* 13362306a36Sopenharmony_ci * create entry in parent directory for child directory 13462306a36Sopenharmony_ci * (dtInsert() releases parent directory page) 13562306a36Sopenharmony_ci */ 13662306a36Sopenharmony_ci ino = ip->i_ino; 13762306a36Sopenharmony_ci if ((rc = dtInsert(tid, dip, &dname, &ino, &btstack))) { 13862306a36Sopenharmony_ci if (rc == -EIO) { 13962306a36Sopenharmony_ci jfs_err("jfs_create: dtInsert returned -EIO"); 14062306a36Sopenharmony_ci txAbort(tid, 1); /* Marks Filesystem dirty */ 14162306a36Sopenharmony_ci } else 14262306a36Sopenharmony_ci txAbort(tid, 0); /* Filesystem full */ 14362306a36Sopenharmony_ci goto out3; 14462306a36Sopenharmony_ci } 14562306a36Sopenharmony_ci 14662306a36Sopenharmony_ci ip->i_op = &jfs_file_inode_operations; 14762306a36Sopenharmony_ci ip->i_fop = &jfs_file_operations; 14862306a36Sopenharmony_ci ip->i_mapping->a_ops = &jfs_aops; 14962306a36Sopenharmony_ci 15062306a36Sopenharmony_ci mark_inode_dirty(ip); 15162306a36Sopenharmony_ci 15262306a36Sopenharmony_ci dip->i_mtime = inode_set_ctime_current(dip); 15362306a36Sopenharmony_ci 15462306a36Sopenharmony_ci mark_inode_dirty(dip); 15562306a36Sopenharmony_ci 15662306a36Sopenharmony_ci rc = txCommit(tid, 2, &iplist[0], 0); 15762306a36Sopenharmony_ci 15862306a36Sopenharmony_ci out3: 15962306a36Sopenharmony_ci txEnd(tid); 16062306a36Sopenharmony_ci mutex_unlock(&JFS_IP(ip)->commit_mutex); 16162306a36Sopenharmony_ci mutex_unlock(&JFS_IP(dip)->commit_mutex); 16262306a36Sopenharmony_ci if (rc) { 16362306a36Sopenharmony_ci free_ea_wmap(ip); 16462306a36Sopenharmony_ci clear_nlink(ip); 16562306a36Sopenharmony_ci discard_new_inode(ip); 16662306a36Sopenharmony_ci } else { 16762306a36Sopenharmony_ci d_instantiate_new(dentry, ip); 16862306a36Sopenharmony_ci } 16962306a36Sopenharmony_ci 17062306a36Sopenharmony_ci out2: 17162306a36Sopenharmony_ci free_UCSname(&dname); 17262306a36Sopenharmony_ci 17362306a36Sopenharmony_ci out1: 17462306a36Sopenharmony_ci 17562306a36Sopenharmony_ci jfs_info("jfs_create: rc:%d", rc); 17662306a36Sopenharmony_ci return rc; 17762306a36Sopenharmony_ci} 17862306a36Sopenharmony_ci 17962306a36Sopenharmony_ci 18062306a36Sopenharmony_ci/* 18162306a36Sopenharmony_ci * NAME: jfs_mkdir(dip, dentry, mode) 18262306a36Sopenharmony_ci * 18362306a36Sopenharmony_ci * FUNCTION: create a child directory in the parent directory <dip> 18462306a36Sopenharmony_ci * with name = <from dentry> and mode = <mode> 18562306a36Sopenharmony_ci * 18662306a36Sopenharmony_ci * PARAMETER: dip - parent directory vnode 18762306a36Sopenharmony_ci * dentry - dentry of child directory 18862306a36Sopenharmony_ci * mode - create mode (rwxrwxrwx). 18962306a36Sopenharmony_ci * 19062306a36Sopenharmony_ci * RETURN: Errors from subroutines 19162306a36Sopenharmony_ci * 19262306a36Sopenharmony_ci * note: 19362306a36Sopenharmony_ci * EACCES: user needs search+write permission on the parent directory 19462306a36Sopenharmony_ci */ 19562306a36Sopenharmony_cistatic int jfs_mkdir(struct mnt_idmap *idmap, struct inode *dip, 19662306a36Sopenharmony_ci struct dentry *dentry, umode_t mode) 19762306a36Sopenharmony_ci{ 19862306a36Sopenharmony_ci int rc = 0; 19962306a36Sopenharmony_ci tid_t tid; /* transaction id */ 20062306a36Sopenharmony_ci struct inode *ip = NULL; /* child directory inode */ 20162306a36Sopenharmony_ci ino_t ino; 20262306a36Sopenharmony_ci struct component_name dname; /* child directory name */ 20362306a36Sopenharmony_ci struct btstack btstack; 20462306a36Sopenharmony_ci struct inode *iplist[2]; 20562306a36Sopenharmony_ci struct tblock *tblk; 20662306a36Sopenharmony_ci 20762306a36Sopenharmony_ci jfs_info("jfs_mkdir: dip:0x%p name:%pd", dip, dentry); 20862306a36Sopenharmony_ci 20962306a36Sopenharmony_ci rc = dquot_initialize(dip); 21062306a36Sopenharmony_ci if (rc) 21162306a36Sopenharmony_ci goto out1; 21262306a36Sopenharmony_ci 21362306a36Sopenharmony_ci /* 21462306a36Sopenharmony_ci * search parent directory for entry/freespace 21562306a36Sopenharmony_ci * (dtSearch() returns parent directory page pinned) 21662306a36Sopenharmony_ci */ 21762306a36Sopenharmony_ci if ((rc = get_UCSname(&dname, dentry))) 21862306a36Sopenharmony_ci goto out1; 21962306a36Sopenharmony_ci 22062306a36Sopenharmony_ci /* 22162306a36Sopenharmony_ci * Either iAlloc() or txBegin() may block. Deadlock can occur if we 22262306a36Sopenharmony_ci * block there while holding dtree page, so we allocate the inode & 22362306a36Sopenharmony_ci * begin the transaction before we search the directory. 22462306a36Sopenharmony_ci */ 22562306a36Sopenharmony_ci ip = ialloc(dip, S_IFDIR | mode); 22662306a36Sopenharmony_ci if (IS_ERR(ip)) { 22762306a36Sopenharmony_ci rc = PTR_ERR(ip); 22862306a36Sopenharmony_ci goto out2; 22962306a36Sopenharmony_ci } 23062306a36Sopenharmony_ci 23162306a36Sopenharmony_ci tid = txBegin(dip->i_sb, 0); 23262306a36Sopenharmony_ci 23362306a36Sopenharmony_ci mutex_lock_nested(&JFS_IP(dip)->commit_mutex, COMMIT_MUTEX_PARENT); 23462306a36Sopenharmony_ci mutex_lock_nested(&JFS_IP(ip)->commit_mutex, COMMIT_MUTEX_CHILD); 23562306a36Sopenharmony_ci 23662306a36Sopenharmony_ci rc = jfs_init_acl(tid, ip, dip); 23762306a36Sopenharmony_ci if (rc) 23862306a36Sopenharmony_ci goto out3; 23962306a36Sopenharmony_ci 24062306a36Sopenharmony_ci rc = jfs_init_security(tid, ip, dip, &dentry->d_name); 24162306a36Sopenharmony_ci if (rc) { 24262306a36Sopenharmony_ci txAbort(tid, 0); 24362306a36Sopenharmony_ci goto out3; 24462306a36Sopenharmony_ci } 24562306a36Sopenharmony_ci 24662306a36Sopenharmony_ci if ((rc = dtSearch(dip, &dname, &ino, &btstack, JFS_CREATE))) { 24762306a36Sopenharmony_ci jfs_err("jfs_mkdir: dtSearch returned %d", rc); 24862306a36Sopenharmony_ci txAbort(tid, 0); 24962306a36Sopenharmony_ci goto out3; 25062306a36Sopenharmony_ci } 25162306a36Sopenharmony_ci 25262306a36Sopenharmony_ci tblk = tid_to_tblock(tid); 25362306a36Sopenharmony_ci tblk->xflag |= COMMIT_CREATE; 25462306a36Sopenharmony_ci tblk->ino = ip->i_ino; 25562306a36Sopenharmony_ci tblk->u.ixpxd = JFS_IP(ip)->ixpxd; 25662306a36Sopenharmony_ci 25762306a36Sopenharmony_ci iplist[0] = dip; 25862306a36Sopenharmony_ci iplist[1] = ip; 25962306a36Sopenharmony_ci 26062306a36Sopenharmony_ci /* 26162306a36Sopenharmony_ci * initialize the child directory in-line in inode 26262306a36Sopenharmony_ci */ 26362306a36Sopenharmony_ci dtInitRoot(tid, ip, dip->i_ino); 26462306a36Sopenharmony_ci 26562306a36Sopenharmony_ci /* 26662306a36Sopenharmony_ci * create entry in parent directory for child directory 26762306a36Sopenharmony_ci * (dtInsert() releases parent directory page) 26862306a36Sopenharmony_ci */ 26962306a36Sopenharmony_ci ino = ip->i_ino; 27062306a36Sopenharmony_ci if ((rc = dtInsert(tid, dip, &dname, &ino, &btstack))) { 27162306a36Sopenharmony_ci if (rc == -EIO) { 27262306a36Sopenharmony_ci jfs_err("jfs_mkdir: dtInsert returned -EIO"); 27362306a36Sopenharmony_ci txAbort(tid, 1); /* Marks Filesystem dirty */ 27462306a36Sopenharmony_ci } else 27562306a36Sopenharmony_ci txAbort(tid, 0); /* Filesystem full */ 27662306a36Sopenharmony_ci goto out3; 27762306a36Sopenharmony_ci } 27862306a36Sopenharmony_ci 27962306a36Sopenharmony_ci set_nlink(ip, 2); /* for '.' */ 28062306a36Sopenharmony_ci ip->i_op = &jfs_dir_inode_operations; 28162306a36Sopenharmony_ci ip->i_fop = &jfs_dir_operations; 28262306a36Sopenharmony_ci 28362306a36Sopenharmony_ci mark_inode_dirty(ip); 28462306a36Sopenharmony_ci 28562306a36Sopenharmony_ci /* update parent directory inode */ 28662306a36Sopenharmony_ci inc_nlink(dip); /* for '..' from child directory */ 28762306a36Sopenharmony_ci dip->i_mtime = inode_set_ctime_current(dip); 28862306a36Sopenharmony_ci mark_inode_dirty(dip); 28962306a36Sopenharmony_ci 29062306a36Sopenharmony_ci rc = txCommit(tid, 2, &iplist[0], 0); 29162306a36Sopenharmony_ci 29262306a36Sopenharmony_ci out3: 29362306a36Sopenharmony_ci txEnd(tid); 29462306a36Sopenharmony_ci mutex_unlock(&JFS_IP(ip)->commit_mutex); 29562306a36Sopenharmony_ci mutex_unlock(&JFS_IP(dip)->commit_mutex); 29662306a36Sopenharmony_ci if (rc) { 29762306a36Sopenharmony_ci free_ea_wmap(ip); 29862306a36Sopenharmony_ci clear_nlink(ip); 29962306a36Sopenharmony_ci discard_new_inode(ip); 30062306a36Sopenharmony_ci } else { 30162306a36Sopenharmony_ci d_instantiate_new(dentry, ip); 30262306a36Sopenharmony_ci } 30362306a36Sopenharmony_ci 30462306a36Sopenharmony_ci out2: 30562306a36Sopenharmony_ci free_UCSname(&dname); 30662306a36Sopenharmony_ci 30762306a36Sopenharmony_ci 30862306a36Sopenharmony_ci out1: 30962306a36Sopenharmony_ci 31062306a36Sopenharmony_ci jfs_info("jfs_mkdir: rc:%d", rc); 31162306a36Sopenharmony_ci return rc; 31262306a36Sopenharmony_ci} 31362306a36Sopenharmony_ci 31462306a36Sopenharmony_ci/* 31562306a36Sopenharmony_ci * NAME: jfs_rmdir(dip, dentry) 31662306a36Sopenharmony_ci * 31762306a36Sopenharmony_ci * FUNCTION: remove a link to child directory 31862306a36Sopenharmony_ci * 31962306a36Sopenharmony_ci * PARAMETER: dip - parent inode 32062306a36Sopenharmony_ci * dentry - child directory dentry 32162306a36Sopenharmony_ci * 32262306a36Sopenharmony_ci * RETURN: -EINVAL - if name is . or .. 32362306a36Sopenharmony_ci * -EINVAL - if . or .. exist but are invalid. 32462306a36Sopenharmony_ci * errors from subroutines 32562306a36Sopenharmony_ci * 32662306a36Sopenharmony_ci * note: 32762306a36Sopenharmony_ci * if other threads have the directory open when the last link 32862306a36Sopenharmony_ci * is removed, the "." and ".." entries, if present, are removed before 32962306a36Sopenharmony_ci * rmdir() returns and no new entries may be created in the directory, 33062306a36Sopenharmony_ci * but the directory is not removed until the last reference to 33162306a36Sopenharmony_ci * the directory is released (cf.unlink() of regular file). 33262306a36Sopenharmony_ci */ 33362306a36Sopenharmony_cistatic int jfs_rmdir(struct inode *dip, struct dentry *dentry) 33462306a36Sopenharmony_ci{ 33562306a36Sopenharmony_ci int rc; 33662306a36Sopenharmony_ci tid_t tid; /* transaction id */ 33762306a36Sopenharmony_ci struct inode *ip = d_inode(dentry); 33862306a36Sopenharmony_ci ino_t ino; 33962306a36Sopenharmony_ci struct component_name dname; 34062306a36Sopenharmony_ci struct inode *iplist[2]; 34162306a36Sopenharmony_ci struct tblock *tblk; 34262306a36Sopenharmony_ci 34362306a36Sopenharmony_ci jfs_info("jfs_rmdir: dip:0x%p name:%pd", dip, dentry); 34462306a36Sopenharmony_ci 34562306a36Sopenharmony_ci /* Init inode for quota operations. */ 34662306a36Sopenharmony_ci rc = dquot_initialize(dip); 34762306a36Sopenharmony_ci if (rc) 34862306a36Sopenharmony_ci goto out; 34962306a36Sopenharmony_ci rc = dquot_initialize(ip); 35062306a36Sopenharmony_ci if (rc) 35162306a36Sopenharmony_ci goto out; 35262306a36Sopenharmony_ci 35362306a36Sopenharmony_ci /* directory must be empty to be removed */ 35462306a36Sopenharmony_ci if (!dtEmpty(ip)) { 35562306a36Sopenharmony_ci rc = -ENOTEMPTY; 35662306a36Sopenharmony_ci goto out; 35762306a36Sopenharmony_ci } 35862306a36Sopenharmony_ci 35962306a36Sopenharmony_ci if ((rc = get_UCSname(&dname, dentry))) { 36062306a36Sopenharmony_ci goto out; 36162306a36Sopenharmony_ci } 36262306a36Sopenharmony_ci 36362306a36Sopenharmony_ci tid = txBegin(dip->i_sb, 0); 36462306a36Sopenharmony_ci 36562306a36Sopenharmony_ci mutex_lock_nested(&JFS_IP(dip)->commit_mutex, COMMIT_MUTEX_PARENT); 36662306a36Sopenharmony_ci mutex_lock_nested(&JFS_IP(ip)->commit_mutex, COMMIT_MUTEX_CHILD); 36762306a36Sopenharmony_ci 36862306a36Sopenharmony_ci iplist[0] = dip; 36962306a36Sopenharmony_ci iplist[1] = ip; 37062306a36Sopenharmony_ci 37162306a36Sopenharmony_ci tblk = tid_to_tblock(tid); 37262306a36Sopenharmony_ci tblk->xflag |= COMMIT_DELETE; 37362306a36Sopenharmony_ci tblk->u.ip = ip; 37462306a36Sopenharmony_ci 37562306a36Sopenharmony_ci /* 37662306a36Sopenharmony_ci * delete the entry of target directory from parent directory 37762306a36Sopenharmony_ci */ 37862306a36Sopenharmony_ci ino = ip->i_ino; 37962306a36Sopenharmony_ci if ((rc = dtDelete(tid, dip, &dname, &ino, JFS_REMOVE))) { 38062306a36Sopenharmony_ci jfs_err("jfs_rmdir: dtDelete returned %d", rc); 38162306a36Sopenharmony_ci if (rc == -EIO) 38262306a36Sopenharmony_ci txAbort(tid, 1); 38362306a36Sopenharmony_ci txEnd(tid); 38462306a36Sopenharmony_ci mutex_unlock(&JFS_IP(ip)->commit_mutex); 38562306a36Sopenharmony_ci mutex_unlock(&JFS_IP(dip)->commit_mutex); 38662306a36Sopenharmony_ci 38762306a36Sopenharmony_ci goto out2; 38862306a36Sopenharmony_ci } 38962306a36Sopenharmony_ci 39062306a36Sopenharmony_ci /* update parent directory's link count corresponding 39162306a36Sopenharmony_ci * to ".." entry of the target directory deleted 39262306a36Sopenharmony_ci */ 39362306a36Sopenharmony_ci dip->i_mtime = inode_set_ctime_current(dip); 39462306a36Sopenharmony_ci inode_dec_link_count(dip); 39562306a36Sopenharmony_ci 39662306a36Sopenharmony_ci /* 39762306a36Sopenharmony_ci * OS/2 could have created EA and/or ACL 39862306a36Sopenharmony_ci */ 39962306a36Sopenharmony_ci /* free EA from both persistent and working map */ 40062306a36Sopenharmony_ci if (JFS_IP(ip)->ea.flag & DXD_EXTENT) { 40162306a36Sopenharmony_ci /* free EA pages */ 40262306a36Sopenharmony_ci txEA(tid, ip, &JFS_IP(ip)->ea, NULL); 40362306a36Sopenharmony_ci } 40462306a36Sopenharmony_ci JFS_IP(ip)->ea.flag = 0; 40562306a36Sopenharmony_ci 40662306a36Sopenharmony_ci /* free ACL from both persistent and working map */ 40762306a36Sopenharmony_ci if (JFS_IP(ip)->acl.flag & DXD_EXTENT) { 40862306a36Sopenharmony_ci /* free ACL pages */ 40962306a36Sopenharmony_ci txEA(tid, ip, &JFS_IP(ip)->acl, NULL); 41062306a36Sopenharmony_ci } 41162306a36Sopenharmony_ci JFS_IP(ip)->acl.flag = 0; 41262306a36Sopenharmony_ci 41362306a36Sopenharmony_ci /* mark the target directory as deleted */ 41462306a36Sopenharmony_ci clear_nlink(ip); 41562306a36Sopenharmony_ci mark_inode_dirty(ip); 41662306a36Sopenharmony_ci 41762306a36Sopenharmony_ci rc = txCommit(tid, 2, &iplist[0], 0); 41862306a36Sopenharmony_ci 41962306a36Sopenharmony_ci txEnd(tid); 42062306a36Sopenharmony_ci 42162306a36Sopenharmony_ci mutex_unlock(&JFS_IP(ip)->commit_mutex); 42262306a36Sopenharmony_ci mutex_unlock(&JFS_IP(dip)->commit_mutex); 42362306a36Sopenharmony_ci 42462306a36Sopenharmony_ci /* 42562306a36Sopenharmony_ci * Truncating the directory index table is not guaranteed. It 42662306a36Sopenharmony_ci * may need to be done iteratively 42762306a36Sopenharmony_ci */ 42862306a36Sopenharmony_ci if (test_cflag(COMMIT_Stale, dip)) { 42962306a36Sopenharmony_ci if (dip->i_size > 1) 43062306a36Sopenharmony_ci jfs_truncate_nolock(dip, 0); 43162306a36Sopenharmony_ci 43262306a36Sopenharmony_ci clear_cflag(COMMIT_Stale, dip); 43362306a36Sopenharmony_ci } 43462306a36Sopenharmony_ci 43562306a36Sopenharmony_ci out2: 43662306a36Sopenharmony_ci free_UCSname(&dname); 43762306a36Sopenharmony_ci 43862306a36Sopenharmony_ci out: 43962306a36Sopenharmony_ci jfs_info("jfs_rmdir: rc:%d", rc); 44062306a36Sopenharmony_ci return rc; 44162306a36Sopenharmony_ci} 44262306a36Sopenharmony_ci 44362306a36Sopenharmony_ci/* 44462306a36Sopenharmony_ci * NAME: jfs_unlink(dip, dentry) 44562306a36Sopenharmony_ci * 44662306a36Sopenharmony_ci * FUNCTION: remove a link to object <vp> named by <name> 44762306a36Sopenharmony_ci * from parent directory <dvp> 44862306a36Sopenharmony_ci * 44962306a36Sopenharmony_ci * PARAMETER: dip - inode of parent directory 45062306a36Sopenharmony_ci * dentry - dentry of object to be removed 45162306a36Sopenharmony_ci * 45262306a36Sopenharmony_ci * RETURN: errors from subroutines 45362306a36Sopenharmony_ci * 45462306a36Sopenharmony_ci * note: 45562306a36Sopenharmony_ci * temporary file: if one or more processes have the file open 45662306a36Sopenharmony_ci * when the last link is removed, the link will be removed before 45762306a36Sopenharmony_ci * unlink() returns, but the removal of the file contents will be 45862306a36Sopenharmony_ci * postponed until all references to the files are closed. 45962306a36Sopenharmony_ci * 46062306a36Sopenharmony_ci * JFS does NOT support unlink() on directories. 46162306a36Sopenharmony_ci * 46262306a36Sopenharmony_ci */ 46362306a36Sopenharmony_cistatic int jfs_unlink(struct inode *dip, struct dentry *dentry) 46462306a36Sopenharmony_ci{ 46562306a36Sopenharmony_ci int rc; 46662306a36Sopenharmony_ci tid_t tid; /* transaction id */ 46762306a36Sopenharmony_ci struct inode *ip = d_inode(dentry); 46862306a36Sopenharmony_ci ino_t ino; 46962306a36Sopenharmony_ci struct component_name dname; /* object name */ 47062306a36Sopenharmony_ci struct inode *iplist[2]; 47162306a36Sopenharmony_ci struct tblock *tblk; 47262306a36Sopenharmony_ci s64 new_size = 0; 47362306a36Sopenharmony_ci int commit_flag; 47462306a36Sopenharmony_ci 47562306a36Sopenharmony_ci jfs_info("jfs_unlink: dip:0x%p name:%pd", dip, dentry); 47662306a36Sopenharmony_ci 47762306a36Sopenharmony_ci /* Init inode for quota operations. */ 47862306a36Sopenharmony_ci rc = dquot_initialize(dip); 47962306a36Sopenharmony_ci if (rc) 48062306a36Sopenharmony_ci goto out; 48162306a36Sopenharmony_ci rc = dquot_initialize(ip); 48262306a36Sopenharmony_ci if (rc) 48362306a36Sopenharmony_ci goto out; 48462306a36Sopenharmony_ci 48562306a36Sopenharmony_ci if ((rc = get_UCSname(&dname, dentry))) 48662306a36Sopenharmony_ci goto out; 48762306a36Sopenharmony_ci 48862306a36Sopenharmony_ci IWRITE_LOCK(ip, RDWRLOCK_NORMAL); 48962306a36Sopenharmony_ci 49062306a36Sopenharmony_ci tid = txBegin(dip->i_sb, 0); 49162306a36Sopenharmony_ci 49262306a36Sopenharmony_ci mutex_lock_nested(&JFS_IP(dip)->commit_mutex, COMMIT_MUTEX_PARENT); 49362306a36Sopenharmony_ci mutex_lock_nested(&JFS_IP(ip)->commit_mutex, COMMIT_MUTEX_CHILD); 49462306a36Sopenharmony_ci 49562306a36Sopenharmony_ci iplist[0] = dip; 49662306a36Sopenharmony_ci iplist[1] = ip; 49762306a36Sopenharmony_ci 49862306a36Sopenharmony_ci /* 49962306a36Sopenharmony_ci * delete the entry of target file from parent directory 50062306a36Sopenharmony_ci */ 50162306a36Sopenharmony_ci ino = ip->i_ino; 50262306a36Sopenharmony_ci if ((rc = dtDelete(tid, dip, &dname, &ino, JFS_REMOVE))) { 50362306a36Sopenharmony_ci jfs_err("jfs_unlink: dtDelete returned %d", rc); 50462306a36Sopenharmony_ci if (rc == -EIO) 50562306a36Sopenharmony_ci txAbort(tid, 1); /* Marks FS Dirty */ 50662306a36Sopenharmony_ci txEnd(tid); 50762306a36Sopenharmony_ci mutex_unlock(&JFS_IP(ip)->commit_mutex); 50862306a36Sopenharmony_ci mutex_unlock(&JFS_IP(dip)->commit_mutex); 50962306a36Sopenharmony_ci IWRITE_UNLOCK(ip); 51062306a36Sopenharmony_ci goto out1; 51162306a36Sopenharmony_ci } 51262306a36Sopenharmony_ci 51362306a36Sopenharmony_ci ASSERT(ip->i_nlink); 51462306a36Sopenharmony_ci 51562306a36Sopenharmony_ci dip->i_mtime = inode_set_ctime_to_ts(dip, inode_set_ctime_current(ip)); 51662306a36Sopenharmony_ci mark_inode_dirty(dip); 51762306a36Sopenharmony_ci 51862306a36Sopenharmony_ci /* update target's inode */ 51962306a36Sopenharmony_ci inode_dec_link_count(ip); 52062306a36Sopenharmony_ci 52162306a36Sopenharmony_ci /* 52262306a36Sopenharmony_ci * commit zero link count object 52362306a36Sopenharmony_ci */ 52462306a36Sopenharmony_ci if (ip->i_nlink == 0) { 52562306a36Sopenharmony_ci assert(!test_cflag(COMMIT_Nolink, ip)); 52662306a36Sopenharmony_ci /* free block resources */ 52762306a36Sopenharmony_ci if ((new_size = commitZeroLink(tid, ip)) < 0) { 52862306a36Sopenharmony_ci txAbort(tid, 1); /* Marks FS Dirty */ 52962306a36Sopenharmony_ci txEnd(tid); 53062306a36Sopenharmony_ci mutex_unlock(&JFS_IP(ip)->commit_mutex); 53162306a36Sopenharmony_ci mutex_unlock(&JFS_IP(dip)->commit_mutex); 53262306a36Sopenharmony_ci IWRITE_UNLOCK(ip); 53362306a36Sopenharmony_ci rc = new_size; 53462306a36Sopenharmony_ci goto out1; 53562306a36Sopenharmony_ci } 53662306a36Sopenharmony_ci tblk = tid_to_tblock(tid); 53762306a36Sopenharmony_ci tblk->xflag |= COMMIT_DELETE; 53862306a36Sopenharmony_ci tblk->u.ip = ip; 53962306a36Sopenharmony_ci } 54062306a36Sopenharmony_ci 54162306a36Sopenharmony_ci /* 54262306a36Sopenharmony_ci * Incomplete truncate of file data can 54362306a36Sopenharmony_ci * result in timing problems unless we synchronously commit the 54462306a36Sopenharmony_ci * transaction. 54562306a36Sopenharmony_ci */ 54662306a36Sopenharmony_ci if (new_size) 54762306a36Sopenharmony_ci commit_flag = COMMIT_SYNC; 54862306a36Sopenharmony_ci else 54962306a36Sopenharmony_ci commit_flag = 0; 55062306a36Sopenharmony_ci 55162306a36Sopenharmony_ci /* 55262306a36Sopenharmony_ci * If xtTruncate was incomplete, commit synchronously to avoid 55362306a36Sopenharmony_ci * timing complications 55462306a36Sopenharmony_ci */ 55562306a36Sopenharmony_ci rc = txCommit(tid, 2, &iplist[0], commit_flag); 55662306a36Sopenharmony_ci 55762306a36Sopenharmony_ci txEnd(tid); 55862306a36Sopenharmony_ci 55962306a36Sopenharmony_ci mutex_unlock(&JFS_IP(ip)->commit_mutex); 56062306a36Sopenharmony_ci mutex_unlock(&JFS_IP(dip)->commit_mutex); 56162306a36Sopenharmony_ci 56262306a36Sopenharmony_ci while (new_size && (rc == 0)) { 56362306a36Sopenharmony_ci tid = txBegin(dip->i_sb, 0); 56462306a36Sopenharmony_ci mutex_lock(&JFS_IP(ip)->commit_mutex); 56562306a36Sopenharmony_ci new_size = xtTruncate_pmap(tid, ip, new_size); 56662306a36Sopenharmony_ci if (new_size < 0) { 56762306a36Sopenharmony_ci txAbort(tid, 1); /* Marks FS Dirty */ 56862306a36Sopenharmony_ci rc = new_size; 56962306a36Sopenharmony_ci } else 57062306a36Sopenharmony_ci rc = txCommit(tid, 2, &iplist[0], COMMIT_SYNC); 57162306a36Sopenharmony_ci txEnd(tid); 57262306a36Sopenharmony_ci mutex_unlock(&JFS_IP(ip)->commit_mutex); 57362306a36Sopenharmony_ci } 57462306a36Sopenharmony_ci 57562306a36Sopenharmony_ci if (ip->i_nlink == 0) 57662306a36Sopenharmony_ci set_cflag(COMMIT_Nolink, ip); 57762306a36Sopenharmony_ci 57862306a36Sopenharmony_ci IWRITE_UNLOCK(ip); 57962306a36Sopenharmony_ci 58062306a36Sopenharmony_ci /* 58162306a36Sopenharmony_ci * Truncating the directory index table is not guaranteed. It 58262306a36Sopenharmony_ci * may need to be done iteratively 58362306a36Sopenharmony_ci */ 58462306a36Sopenharmony_ci if (test_cflag(COMMIT_Stale, dip)) { 58562306a36Sopenharmony_ci if (dip->i_size > 1) 58662306a36Sopenharmony_ci jfs_truncate_nolock(dip, 0); 58762306a36Sopenharmony_ci 58862306a36Sopenharmony_ci clear_cflag(COMMIT_Stale, dip); 58962306a36Sopenharmony_ci } 59062306a36Sopenharmony_ci 59162306a36Sopenharmony_ci out1: 59262306a36Sopenharmony_ci free_UCSname(&dname); 59362306a36Sopenharmony_ci out: 59462306a36Sopenharmony_ci jfs_info("jfs_unlink: rc:%d", rc); 59562306a36Sopenharmony_ci return rc; 59662306a36Sopenharmony_ci} 59762306a36Sopenharmony_ci 59862306a36Sopenharmony_ci/* 59962306a36Sopenharmony_ci * NAME: commitZeroLink() 60062306a36Sopenharmony_ci * 60162306a36Sopenharmony_ci * FUNCTION: for non-directory, called by jfs_remove(), 60262306a36Sopenharmony_ci * truncate a regular file, directory or symbolic 60362306a36Sopenharmony_ci * link to zero length. return 0 if type is not 60462306a36Sopenharmony_ci * one of these. 60562306a36Sopenharmony_ci * 60662306a36Sopenharmony_ci * if the file is currently associated with a VM segment 60762306a36Sopenharmony_ci * only permanent disk and inode map resources are freed, 60862306a36Sopenharmony_ci * and neither the inode nor indirect blocks are modified 60962306a36Sopenharmony_ci * so that the resources can be later freed in the work 61062306a36Sopenharmony_ci * map by ctrunc1. 61162306a36Sopenharmony_ci * if there is no VM segment on entry, the resources are 61262306a36Sopenharmony_ci * freed in both work and permanent map. 61362306a36Sopenharmony_ci * (? for temporary file - memory object is cached even 61462306a36Sopenharmony_ci * after no reference: 61562306a36Sopenharmony_ci * reference count > 0 - ) 61662306a36Sopenharmony_ci * 61762306a36Sopenharmony_ci * PARAMETERS: cd - pointer to commit data structure. 61862306a36Sopenharmony_ci * current inode is the one to truncate. 61962306a36Sopenharmony_ci * 62062306a36Sopenharmony_ci * RETURN: Errors from subroutines 62162306a36Sopenharmony_ci */ 62262306a36Sopenharmony_cistatic s64 commitZeroLink(tid_t tid, struct inode *ip) 62362306a36Sopenharmony_ci{ 62462306a36Sopenharmony_ci int filetype; 62562306a36Sopenharmony_ci struct tblock *tblk; 62662306a36Sopenharmony_ci 62762306a36Sopenharmony_ci jfs_info("commitZeroLink: tid = %d, ip = 0x%p", tid, ip); 62862306a36Sopenharmony_ci 62962306a36Sopenharmony_ci filetype = ip->i_mode & S_IFMT; 63062306a36Sopenharmony_ci switch (filetype) { 63162306a36Sopenharmony_ci case S_IFREG: 63262306a36Sopenharmony_ci break; 63362306a36Sopenharmony_ci case S_IFLNK: 63462306a36Sopenharmony_ci /* fast symbolic link */ 63562306a36Sopenharmony_ci if (ip->i_size < IDATASIZE) { 63662306a36Sopenharmony_ci ip->i_size = 0; 63762306a36Sopenharmony_ci return 0; 63862306a36Sopenharmony_ci } 63962306a36Sopenharmony_ci break; 64062306a36Sopenharmony_ci default: 64162306a36Sopenharmony_ci assert(filetype != S_IFDIR); 64262306a36Sopenharmony_ci return 0; 64362306a36Sopenharmony_ci } 64462306a36Sopenharmony_ci 64562306a36Sopenharmony_ci set_cflag(COMMIT_Freewmap, ip); 64662306a36Sopenharmony_ci 64762306a36Sopenharmony_ci /* mark transaction of block map update type */ 64862306a36Sopenharmony_ci tblk = tid_to_tblock(tid); 64962306a36Sopenharmony_ci tblk->xflag |= COMMIT_PMAP; 65062306a36Sopenharmony_ci 65162306a36Sopenharmony_ci /* 65262306a36Sopenharmony_ci * free EA 65362306a36Sopenharmony_ci */ 65462306a36Sopenharmony_ci if (JFS_IP(ip)->ea.flag & DXD_EXTENT) 65562306a36Sopenharmony_ci /* acquire maplock on EA to be freed from block map */ 65662306a36Sopenharmony_ci txEA(tid, ip, &JFS_IP(ip)->ea, NULL); 65762306a36Sopenharmony_ci 65862306a36Sopenharmony_ci /* 65962306a36Sopenharmony_ci * free ACL 66062306a36Sopenharmony_ci */ 66162306a36Sopenharmony_ci if (JFS_IP(ip)->acl.flag & DXD_EXTENT) 66262306a36Sopenharmony_ci /* acquire maplock on EA to be freed from block map */ 66362306a36Sopenharmony_ci txEA(tid, ip, &JFS_IP(ip)->acl, NULL); 66462306a36Sopenharmony_ci 66562306a36Sopenharmony_ci /* 66662306a36Sopenharmony_ci * free xtree/data (truncate to zero length): 66762306a36Sopenharmony_ci * free xtree/data pages from cache if COMMIT_PWMAP, 66862306a36Sopenharmony_ci * free xtree/data blocks from persistent block map, and 66962306a36Sopenharmony_ci * free xtree/data blocks from working block map if COMMIT_PWMAP; 67062306a36Sopenharmony_ci */ 67162306a36Sopenharmony_ci if (ip->i_size) 67262306a36Sopenharmony_ci return xtTruncate_pmap(tid, ip, 0); 67362306a36Sopenharmony_ci 67462306a36Sopenharmony_ci return 0; 67562306a36Sopenharmony_ci} 67662306a36Sopenharmony_ci 67762306a36Sopenharmony_ci 67862306a36Sopenharmony_ci/* 67962306a36Sopenharmony_ci * NAME: jfs_free_zero_link() 68062306a36Sopenharmony_ci * 68162306a36Sopenharmony_ci * FUNCTION: for non-directory, called by iClose(), 68262306a36Sopenharmony_ci * free resources of a file from cache and WORKING map 68362306a36Sopenharmony_ci * for a file previously committed with zero link count 68462306a36Sopenharmony_ci * while associated with a pager object, 68562306a36Sopenharmony_ci * 68662306a36Sopenharmony_ci * PARAMETER: ip - pointer to inode of file. 68762306a36Sopenharmony_ci */ 68862306a36Sopenharmony_civoid jfs_free_zero_link(struct inode *ip) 68962306a36Sopenharmony_ci{ 69062306a36Sopenharmony_ci int type; 69162306a36Sopenharmony_ci 69262306a36Sopenharmony_ci jfs_info("jfs_free_zero_link: ip = 0x%p", ip); 69362306a36Sopenharmony_ci 69462306a36Sopenharmony_ci /* return if not reg or symbolic link or if size is 69562306a36Sopenharmony_ci * already ok. 69662306a36Sopenharmony_ci */ 69762306a36Sopenharmony_ci type = ip->i_mode & S_IFMT; 69862306a36Sopenharmony_ci 69962306a36Sopenharmony_ci switch (type) { 70062306a36Sopenharmony_ci case S_IFREG: 70162306a36Sopenharmony_ci break; 70262306a36Sopenharmony_ci case S_IFLNK: 70362306a36Sopenharmony_ci /* if its contained in inode nothing to do */ 70462306a36Sopenharmony_ci if (ip->i_size < IDATASIZE) 70562306a36Sopenharmony_ci return; 70662306a36Sopenharmony_ci break; 70762306a36Sopenharmony_ci default: 70862306a36Sopenharmony_ci return; 70962306a36Sopenharmony_ci } 71062306a36Sopenharmony_ci 71162306a36Sopenharmony_ci /* 71262306a36Sopenharmony_ci * free EA 71362306a36Sopenharmony_ci */ 71462306a36Sopenharmony_ci if (JFS_IP(ip)->ea.flag & DXD_EXTENT) { 71562306a36Sopenharmony_ci s64 xaddr = addressDXD(&JFS_IP(ip)->ea); 71662306a36Sopenharmony_ci int xlen = lengthDXD(&JFS_IP(ip)->ea); 71762306a36Sopenharmony_ci struct maplock maplock; /* maplock for COMMIT_WMAP */ 71862306a36Sopenharmony_ci struct pxd_lock *pxdlock; /* maplock for COMMIT_WMAP */ 71962306a36Sopenharmony_ci 72062306a36Sopenharmony_ci /* free EA pages from cache */ 72162306a36Sopenharmony_ci invalidate_dxd_metapages(ip, JFS_IP(ip)->ea); 72262306a36Sopenharmony_ci 72362306a36Sopenharmony_ci /* free EA extent from working block map */ 72462306a36Sopenharmony_ci maplock.index = 1; 72562306a36Sopenharmony_ci pxdlock = (struct pxd_lock *) & maplock; 72662306a36Sopenharmony_ci pxdlock->flag = mlckFREEPXD; 72762306a36Sopenharmony_ci PXDaddress(&pxdlock->pxd, xaddr); 72862306a36Sopenharmony_ci PXDlength(&pxdlock->pxd, xlen); 72962306a36Sopenharmony_ci txFreeMap(ip, pxdlock, NULL, COMMIT_WMAP); 73062306a36Sopenharmony_ci } 73162306a36Sopenharmony_ci 73262306a36Sopenharmony_ci /* 73362306a36Sopenharmony_ci * free ACL 73462306a36Sopenharmony_ci */ 73562306a36Sopenharmony_ci if (JFS_IP(ip)->acl.flag & DXD_EXTENT) { 73662306a36Sopenharmony_ci s64 xaddr = addressDXD(&JFS_IP(ip)->acl); 73762306a36Sopenharmony_ci int xlen = lengthDXD(&JFS_IP(ip)->acl); 73862306a36Sopenharmony_ci struct maplock maplock; /* maplock for COMMIT_WMAP */ 73962306a36Sopenharmony_ci struct pxd_lock *pxdlock; /* maplock for COMMIT_WMAP */ 74062306a36Sopenharmony_ci 74162306a36Sopenharmony_ci invalidate_dxd_metapages(ip, JFS_IP(ip)->acl); 74262306a36Sopenharmony_ci 74362306a36Sopenharmony_ci /* free ACL extent from working block map */ 74462306a36Sopenharmony_ci maplock.index = 1; 74562306a36Sopenharmony_ci pxdlock = (struct pxd_lock *) & maplock; 74662306a36Sopenharmony_ci pxdlock->flag = mlckFREEPXD; 74762306a36Sopenharmony_ci PXDaddress(&pxdlock->pxd, xaddr); 74862306a36Sopenharmony_ci PXDlength(&pxdlock->pxd, xlen); 74962306a36Sopenharmony_ci txFreeMap(ip, pxdlock, NULL, COMMIT_WMAP); 75062306a36Sopenharmony_ci } 75162306a36Sopenharmony_ci 75262306a36Sopenharmony_ci /* 75362306a36Sopenharmony_ci * free xtree/data (truncate to zero length): 75462306a36Sopenharmony_ci * free xtree/data pages from cache, and 75562306a36Sopenharmony_ci * free xtree/data blocks from working block map; 75662306a36Sopenharmony_ci */ 75762306a36Sopenharmony_ci if (ip->i_size) 75862306a36Sopenharmony_ci xtTruncate(0, ip, 0, COMMIT_WMAP); 75962306a36Sopenharmony_ci} 76062306a36Sopenharmony_ci 76162306a36Sopenharmony_ci/* 76262306a36Sopenharmony_ci * NAME: jfs_link(vp, dvp, name, crp) 76362306a36Sopenharmony_ci * 76462306a36Sopenharmony_ci * FUNCTION: create a link to <vp> by the name = <name> 76562306a36Sopenharmony_ci * in the parent directory <dvp> 76662306a36Sopenharmony_ci * 76762306a36Sopenharmony_ci * PARAMETER: vp - target object 76862306a36Sopenharmony_ci * dvp - parent directory of new link 76962306a36Sopenharmony_ci * name - name of new link to target object 77062306a36Sopenharmony_ci * crp - credential 77162306a36Sopenharmony_ci * 77262306a36Sopenharmony_ci * RETURN: Errors from subroutines 77362306a36Sopenharmony_ci * 77462306a36Sopenharmony_ci * note: 77562306a36Sopenharmony_ci * JFS does NOT support link() on directories (to prevent circular 77662306a36Sopenharmony_ci * path in the directory hierarchy); 77762306a36Sopenharmony_ci * EPERM: the target object is a directory, and either the caller 77862306a36Sopenharmony_ci * does not have appropriate privileges or the implementation prohibits 77962306a36Sopenharmony_ci * using link() on directories [XPG4.2]. 78062306a36Sopenharmony_ci * 78162306a36Sopenharmony_ci * JFS does NOT support links between file systems: 78262306a36Sopenharmony_ci * EXDEV: target object and new link are on different file systems and 78362306a36Sopenharmony_ci * implementation does not support links between file systems [XPG4.2]. 78462306a36Sopenharmony_ci */ 78562306a36Sopenharmony_cistatic int jfs_link(struct dentry *old_dentry, 78662306a36Sopenharmony_ci struct inode *dir, struct dentry *dentry) 78762306a36Sopenharmony_ci{ 78862306a36Sopenharmony_ci int rc; 78962306a36Sopenharmony_ci tid_t tid; 79062306a36Sopenharmony_ci struct inode *ip = d_inode(old_dentry); 79162306a36Sopenharmony_ci ino_t ino; 79262306a36Sopenharmony_ci struct component_name dname; 79362306a36Sopenharmony_ci struct btstack btstack; 79462306a36Sopenharmony_ci struct inode *iplist[2]; 79562306a36Sopenharmony_ci 79662306a36Sopenharmony_ci jfs_info("jfs_link: %pd %pd", old_dentry, dentry); 79762306a36Sopenharmony_ci 79862306a36Sopenharmony_ci rc = dquot_initialize(dir); 79962306a36Sopenharmony_ci if (rc) 80062306a36Sopenharmony_ci goto out; 80162306a36Sopenharmony_ci 80262306a36Sopenharmony_ci if (isReadOnly(ip)) { 80362306a36Sopenharmony_ci jfs_error(ip->i_sb, "read-only filesystem\n"); 80462306a36Sopenharmony_ci return -EROFS; 80562306a36Sopenharmony_ci } 80662306a36Sopenharmony_ci 80762306a36Sopenharmony_ci tid = txBegin(ip->i_sb, 0); 80862306a36Sopenharmony_ci 80962306a36Sopenharmony_ci mutex_lock_nested(&JFS_IP(dir)->commit_mutex, COMMIT_MUTEX_PARENT); 81062306a36Sopenharmony_ci mutex_lock_nested(&JFS_IP(ip)->commit_mutex, COMMIT_MUTEX_CHILD); 81162306a36Sopenharmony_ci 81262306a36Sopenharmony_ci /* 81362306a36Sopenharmony_ci * scan parent directory for entry/freespace 81462306a36Sopenharmony_ci */ 81562306a36Sopenharmony_ci if ((rc = get_UCSname(&dname, dentry))) 81662306a36Sopenharmony_ci goto out_tx; 81762306a36Sopenharmony_ci 81862306a36Sopenharmony_ci if ((rc = dtSearch(dir, &dname, &ino, &btstack, JFS_CREATE))) 81962306a36Sopenharmony_ci goto free_dname; 82062306a36Sopenharmony_ci 82162306a36Sopenharmony_ci /* 82262306a36Sopenharmony_ci * create entry for new link in parent directory 82362306a36Sopenharmony_ci */ 82462306a36Sopenharmony_ci ino = ip->i_ino; 82562306a36Sopenharmony_ci if ((rc = dtInsert(tid, dir, &dname, &ino, &btstack))) 82662306a36Sopenharmony_ci goto free_dname; 82762306a36Sopenharmony_ci 82862306a36Sopenharmony_ci /* update object inode */ 82962306a36Sopenharmony_ci inc_nlink(ip); /* for new link */ 83062306a36Sopenharmony_ci inode_set_ctime_current(ip); 83162306a36Sopenharmony_ci dir->i_mtime = inode_set_ctime_current(dir); 83262306a36Sopenharmony_ci mark_inode_dirty(dir); 83362306a36Sopenharmony_ci ihold(ip); 83462306a36Sopenharmony_ci 83562306a36Sopenharmony_ci iplist[0] = ip; 83662306a36Sopenharmony_ci iplist[1] = dir; 83762306a36Sopenharmony_ci rc = txCommit(tid, 2, &iplist[0], 0); 83862306a36Sopenharmony_ci 83962306a36Sopenharmony_ci if (rc) { 84062306a36Sopenharmony_ci drop_nlink(ip); /* never instantiated */ 84162306a36Sopenharmony_ci iput(ip); 84262306a36Sopenharmony_ci } else 84362306a36Sopenharmony_ci d_instantiate(dentry, ip); 84462306a36Sopenharmony_ci 84562306a36Sopenharmony_ci free_dname: 84662306a36Sopenharmony_ci free_UCSname(&dname); 84762306a36Sopenharmony_ci 84862306a36Sopenharmony_ci out_tx: 84962306a36Sopenharmony_ci txEnd(tid); 85062306a36Sopenharmony_ci 85162306a36Sopenharmony_ci mutex_unlock(&JFS_IP(ip)->commit_mutex); 85262306a36Sopenharmony_ci mutex_unlock(&JFS_IP(dir)->commit_mutex); 85362306a36Sopenharmony_ci 85462306a36Sopenharmony_ci out: 85562306a36Sopenharmony_ci jfs_info("jfs_link: rc:%d", rc); 85662306a36Sopenharmony_ci return rc; 85762306a36Sopenharmony_ci} 85862306a36Sopenharmony_ci 85962306a36Sopenharmony_ci/* 86062306a36Sopenharmony_ci * NAME: jfs_symlink(dip, dentry, name) 86162306a36Sopenharmony_ci * 86262306a36Sopenharmony_ci * FUNCTION: creates a symbolic link to <symlink> by name <name> 86362306a36Sopenharmony_ci * in directory <dip> 86462306a36Sopenharmony_ci * 86562306a36Sopenharmony_ci * PARAMETER: dip - parent directory vnode 86662306a36Sopenharmony_ci * dentry - dentry of symbolic link 86762306a36Sopenharmony_ci * name - the path name of the existing object 86862306a36Sopenharmony_ci * that will be the source of the link 86962306a36Sopenharmony_ci * 87062306a36Sopenharmony_ci * RETURN: errors from subroutines 87162306a36Sopenharmony_ci * 87262306a36Sopenharmony_ci * note: 87362306a36Sopenharmony_ci * ENAMETOOLONG: pathname resolution of a symbolic link produced 87462306a36Sopenharmony_ci * an intermediate result whose length exceeds PATH_MAX [XPG4.2] 87562306a36Sopenharmony_ci*/ 87662306a36Sopenharmony_ci 87762306a36Sopenharmony_cistatic int jfs_symlink(struct mnt_idmap *idmap, struct inode *dip, 87862306a36Sopenharmony_ci struct dentry *dentry, const char *name) 87962306a36Sopenharmony_ci{ 88062306a36Sopenharmony_ci int rc; 88162306a36Sopenharmony_ci tid_t tid; 88262306a36Sopenharmony_ci ino_t ino = 0; 88362306a36Sopenharmony_ci struct component_name dname; 88462306a36Sopenharmony_ci u32 ssize; /* source pathname size */ 88562306a36Sopenharmony_ci struct btstack btstack; 88662306a36Sopenharmony_ci struct inode *ip; 88762306a36Sopenharmony_ci s64 xlen = 0; 88862306a36Sopenharmony_ci int bmask = 0, xsize; 88962306a36Sopenharmony_ci s64 xaddr; 89062306a36Sopenharmony_ci struct metapage *mp; 89162306a36Sopenharmony_ci struct super_block *sb; 89262306a36Sopenharmony_ci struct tblock *tblk; 89362306a36Sopenharmony_ci 89462306a36Sopenharmony_ci struct inode *iplist[2]; 89562306a36Sopenharmony_ci 89662306a36Sopenharmony_ci jfs_info("jfs_symlink: dip:0x%p name:%s", dip, name); 89762306a36Sopenharmony_ci 89862306a36Sopenharmony_ci rc = dquot_initialize(dip); 89962306a36Sopenharmony_ci if (rc) 90062306a36Sopenharmony_ci goto out1; 90162306a36Sopenharmony_ci 90262306a36Sopenharmony_ci ssize = strlen(name) + 1; 90362306a36Sopenharmony_ci 90462306a36Sopenharmony_ci /* 90562306a36Sopenharmony_ci * search parent directory for entry/freespace 90662306a36Sopenharmony_ci * (dtSearch() returns parent directory page pinned) 90762306a36Sopenharmony_ci */ 90862306a36Sopenharmony_ci 90962306a36Sopenharmony_ci if ((rc = get_UCSname(&dname, dentry))) 91062306a36Sopenharmony_ci goto out1; 91162306a36Sopenharmony_ci 91262306a36Sopenharmony_ci /* 91362306a36Sopenharmony_ci * allocate on-disk/in-memory inode for symbolic link: 91462306a36Sopenharmony_ci * (iAlloc() returns new, locked inode) 91562306a36Sopenharmony_ci */ 91662306a36Sopenharmony_ci ip = ialloc(dip, S_IFLNK | 0777); 91762306a36Sopenharmony_ci if (IS_ERR(ip)) { 91862306a36Sopenharmony_ci rc = PTR_ERR(ip); 91962306a36Sopenharmony_ci goto out2; 92062306a36Sopenharmony_ci } 92162306a36Sopenharmony_ci 92262306a36Sopenharmony_ci tid = txBegin(dip->i_sb, 0); 92362306a36Sopenharmony_ci 92462306a36Sopenharmony_ci mutex_lock_nested(&JFS_IP(dip)->commit_mutex, COMMIT_MUTEX_PARENT); 92562306a36Sopenharmony_ci mutex_lock_nested(&JFS_IP(ip)->commit_mutex, COMMIT_MUTEX_CHILD); 92662306a36Sopenharmony_ci 92762306a36Sopenharmony_ci rc = jfs_init_security(tid, ip, dip, &dentry->d_name); 92862306a36Sopenharmony_ci if (rc) 92962306a36Sopenharmony_ci goto out3; 93062306a36Sopenharmony_ci 93162306a36Sopenharmony_ci tblk = tid_to_tblock(tid); 93262306a36Sopenharmony_ci tblk->xflag |= COMMIT_CREATE; 93362306a36Sopenharmony_ci tblk->ino = ip->i_ino; 93462306a36Sopenharmony_ci tblk->u.ixpxd = JFS_IP(ip)->ixpxd; 93562306a36Sopenharmony_ci 93662306a36Sopenharmony_ci /* fix symlink access permission 93762306a36Sopenharmony_ci * (dir_create() ANDs in the u.u_cmask, 93862306a36Sopenharmony_ci * but symlinks really need to be 777 access) 93962306a36Sopenharmony_ci */ 94062306a36Sopenharmony_ci ip->i_mode |= 0777; 94162306a36Sopenharmony_ci 94262306a36Sopenharmony_ci /* 94362306a36Sopenharmony_ci * write symbolic link target path name 94462306a36Sopenharmony_ci */ 94562306a36Sopenharmony_ci xtInitRoot(tid, ip); 94662306a36Sopenharmony_ci 94762306a36Sopenharmony_ci /* 94862306a36Sopenharmony_ci * write source path name inline in on-disk inode (fast symbolic link) 94962306a36Sopenharmony_ci */ 95062306a36Sopenharmony_ci 95162306a36Sopenharmony_ci if (ssize <= IDATASIZE) { 95262306a36Sopenharmony_ci ip->i_op = &jfs_fast_symlink_inode_operations; 95362306a36Sopenharmony_ci 95462306a36Sopenharmony_ci ip->i_link = JFS_IP(ip)->i_inline_all; 95562306a36Sopenharmony_ci memcpy(ip->i_link, name, ssize); 95662306a36Sopenharmony_ci ip->i_size = ssize - 1; 95762306a36Sopenharmony_ci 95862306a36Sopenharmony_ci /* 95962306a36Sopenharmony_ci * if symlink is > 128 bytes, we don't have the space to 96062306a36Sopenharmony_ci * store inline extended attributes 96162306a36Sopenharmony_ci */ 96262306a36Sopenharmony_ci if (ssize > sizeof (JFS_IP(ip)->i_inline)) 96362306a36Sopenharmony_ci JFS_IP(ip)->mode2 &= ~INLINEEA; 96462306a36Sopenharmony_ci 96562306a36Sopenharmony_ci jfs_info("jfs_symlink: fast symlink added ssize:%u name:%s ", 96662306a36Sopenharmony_ci ssize, name); 96762306a36Sopenharmony_ci } 96862306a36Sopenharmony_ci /* 96962306a36Sopenharmony_ci * write source path name in a single extent 97062306a36Sopenharmony_ci */ 97162306a36Sopenharmony_ci else { 97262306a36Sopenharmony_ci jfs_info("jfs_symlink: allocate extent ip:0x%p", ip); 97362306a36Sopenharmony_ci 97462306a36Sopenharmony_ci ip->i_op = &jfs_symlink_inode_operations; 97562306a36Sopenharmony_ci inode_nohighmem(ip); 97662306a36Sopenharmony_ci ip->i_mapping->a_ops = &jfs_aops; 97762306a36Sopenharmony_ci 97862306a36Sopenharmony_ci /* 97962306a36Sopenharmony_ci * even though the data of symlink object (source 98062306a36Sopenharmony_ci * path name) is treated as non-journaled user data, 98162306a36Sopenharmony_ci * it is read/written thru buffer cache for performance. 98262306a36Sopenharmony_ci */ 98362306a36Sopenharmony_ci sb = ip->i_sb; 98462306a36Sopenharmony_ci bmask = JFS_SBI(sb)->bsize - 1; 98562306a36Sopenharmony_ci xsize = (ssize + bmask) & ~bmask; 98662306a36Sopenharmony_ci xaddr = 0; 98762306a36Sopenharmony_ci xlen = xsize >> JFS_SBI(sb)->l2bsize; 98862306a36Sopenharmony_ci if ((rc = xtInsert(tid, ip, 0, 0, xlen, &xaddr, 0))) { 98962306a36Sopenharmony_ci txAbort(tid, 0); 99062306a36Sopenharmony_ci goto out3; 99162306a36Sopenharmony_ci } 99262306a36Sopenharmony_ci ip->i_size = ssize - 1; 99362306a36Sopenharmony_ci while (ssize) { 99462306a36Sopenharmony_ci /* This is kind of silly since PATH_MAX == 4K */ 99562306a36Sopenharmony_ci u32 copy_size = min_t(u32, ssize, PSIZE); 99662306a36Sopenharmony_ci 99762306a36Sopenharmony_ci mp = get_metapage(ip, xaddr, PSIZE, 1); 99862306a36Sopenharmony_ci 99962306a36Sopenharmony_ci if (mp == NULL) { 100062306a36Sopenharmony_ci xtTruncate(tid, ip, 0, COMMIT_PWMAP); 100162306a36Sopenharmony_ci rc = -EIO; 100262306a36Sopenharmony_ci txAbort(tid, 0); 100362306a36Sopenharmony_ci goto out3; 100462306a36Sopenharmony_ci } 100562306a36Sopenharmony_ci memcpy(mp->data, name, copy_size); 100662306a36Sopenharmony_ci flush_metapage(mp); 100762306a36Sopenharmony_ci ssize -= copy_size; 100862306a36Sopenharmony_ci name += copy_size; 100962306a36Sopenharmony_ci xaddr += JFS_SBI(sb)->nbperpage; 101062306a36Sopenharmony_ci } 101162306a36Sopenharmony_ci } 101262306a36Sopenharmony_ci 101362306a36Sopenharmony_ci /* 101462306a36Sopenharmony_ci * create entry for symbolic link in parent directory 101562306a36Sopenharmony_ci */ 101662306a36Sopenharmony_ci rc = dtSearch(dip, &dname, &ino, &btstack, JFS_CREATE); 101762306a36Sopenharmony_ci if (rc == 0) { 101862306a36Sopenharmony_ci ino = ip->i_ino; 101962306a36Sopenharmony_ci rc = dtInsert(tid, dip, &dname, &ino, &btstack); 102062306a36Sopenharmony_ci } 102162306a36Sopenharmony_ci if (rc) { 102262306a36Sopenharmony_ci if (xlen) 102362306a36Sopenharmony_ci xtTruncate(tid, ip, 0, COMMIT_PWMAP); 102462306a36Sopenharmony_ci txAbort(tid, 0); 102562306a36Sopenharmony_ci /* discard new inode */ 102662306a36Sopenharmony_ci goto out3; 102762306a36Sopenharmony_ci } 102862306a36Sopenharmony_ci 102962306a36Sopenharmony_ci mark_inode_dirty(ip); 103062306a36Sopenharmony_ci 103162306a36Sopenharmony_ci dip->i_mtime = inode_set_ctime_current(dip); 103262306a36Sopenharmony_ci mark_inode_dirty(dip); 103362306a36Sopenharmony_ci /* 103462306a36Sopenharmony_ci * commit update of parent directory and link object 103562306a36Sopenharmony_ci */ 103662306a36Sopenharmony_ci 103762306a36Sopenharmony_ci iplist[0] = dip; 103862306a36Sopenharmony_ci iplist[1] = ip; 103962306a36Sopenharmony_ci rc = txCommit(tid, 2, &iplist[0], 0); 104062306a36Sopenharmony_ci 104162306a36Sopenharmony_ci out3: 104262306a36Sopenharmony_ci txEnd(tid); 104362306a36Sopenharmony_ci mutex_unlock(&JFS_IP(ip)->commit_mutex); 104462306a36Sopenharmony_ci mutex_unlock(&JFS_IP(dip)->commit_mutex); 104562306a36Sopenharmony_ci if (rc) { 104662306a36Sopenharmony_ci free_ea_wmap(ip); 104762306a36Sopenharmony_ci clear_nlink(ip); 104862306a36Sopenharmony_ci discard_new_inode(ip); 104962306a36Sopenharmony_ci } else { 105062306a36Sopenharmony_ci d_instantiate_new(dentry, ip); 105162306a36Sopenharmony_ci } 105262306a36Sopenharmony_ci 105362306a36Sopenharmony_ci out2: 105462306a36Sopenharmony_ci free_UCSname(&dname); 105562306a36Sopenharmony_ci 105662306a36Sopenharmony_ci out1: 105762306a36Sopenharmony_ci jfs_info("jfs_symlink: rc:%d", rc); 105862306a36Sopenharmony_ci return rc; 105962306a36Sopenharmony_ci} 106062306a36Sopenharmony_ci 106162306a36Sopenharmony_ci 106262306a36Sopenharmony_ci/* 106362306a36Sopenharmony_ci * NAME: jfs_rename 106462306a36Sopenharmony_ci * 106562306a36Sopenharmony_ci * FUNCTION: rename a file or directory 106662306a36Sopenharmony_ci */ 106762306a36Sopenharmony_cistatic int jfs_rename(struct mnt_idmap *idmap, struct inode *old_dir, 106862306a36Sopenharmony_ci struct dentry *old_dentry, struct inode *new_dir, 106962306a36Sopenharmony_ci struct dentry *new_dentry, unsigned int flags) 107062306a36Sopenharmony_ci{ 107162306a36Sopenharmony_ci struct btstack btstack; 107262306a36Sopenharmony_ci ino_t ino; 107362306a36Sopenharmony_ci struct component_name new_dname; 107462306a36Sopenharmony_ci struct inode *new_ip; 107562306a36Sopenharmony_ci struct component_name old_dname; 107662306a36Sopenharmony_ci struct inode *old_ip; 107762306a36Sopenharmony_ci int rc; 107862306a36Sopenharmony_ci tid_t tid; 107962306a36Sopenharmony_ci struct tlock *tlck; 108062306a36Sopenharmony_ci struct dt_lock *dtlck; 108162306a36Sopenharmony_ci struct lv *lv; 108262306a36Sopenharmony_ci int ipcount; 108362306a36Sopenharmony_ci struct inode *iplist[4]; 108462306a36Sopenharmony_ci struct tblock *tblk; 108562306a36Sopenharmony_ci s64 new_size = 0; 108662306a36Sopenharmony_ci int commit_flag; 108762306a36Sopenharmony_ci 108862306a36Sopenharmony_ci if (flags & ~RENAME_NOREPLACE) 108962306a36Sopenharmony_ci return -EINVAL; 109062306a36Sopenharmony_ci 109162306a36Sopenharmony_ci jfs_info("jfs_rename: %pd %pd", old_dentry, new_dentry); 109262306a36Sopenharmony_ci 109362306a36Sopenharmony_ci rc = dquot_initialize(old_dir); 109462306a36Sopenharmony_ci if (rc) 109562306a36Sopenharmony_ci goto out1; 109662306a36Sopenharmony_ci rc = dquot_initialize(new_dir); 109762306a36Sopenharmony_ci if (rc) 109862306a36Sopenharmony_ci goto out1; 109962306a36Sopenharmony_ci 110062306a36Sopenharmony_ci old_ip = d_inode(old_dentry); 110162306a36Sopenharmony_ci new_ip = d_inode(new_dentry); 110262306a36Sopenharmony_ci 110362306a36Sopenharmony_ci if ((rc = get_UCSname(&old_dname, old_dentry))) 110462306a36Sopenharmony_ci goto out1; 110562306a36Sopenharmony_ci 110662306a36Sopenharmony_ci if ((rc = get_UCSname(&new_dname, new_dentry))) 110762306a36Sopenharmony_ci goto out2; 110862306a36Sopenharmony_ci 110962306a36Sopenharmony_ci /* 111062306a36Sopenharmony_ci * Make sure source inode number is what we think it is 111162306a36Sopenharmony_ci */ 111262306a36Sopenharmony_ci rc = dtSearch(old_dir, &old_dname, &ino, &btstack, JFS_LOOKUP); 111362306a36Sopenharmony_ci if (rc || (ino != old_ip->i_ino)) { 111462306a36Sopenharmony_ci rc = -ENOENT; 111562306a36Sopenharmony_ci goto out3; 111662306a36Sopenharmony_ci } 111762306a36Sopenharmony_ci 111862306a36Sopenharmony_ci /* 111962306a36Sopenharmony_ci * Make sure dest inode number (if any) is what we think it is 112062306a36Sopenharmony_ci */ 112162306a36Sopenharmony_ci rc = dtSearch(new_dir, &new_dname, &ino, &btstack, JFS_LOOKUP); 112262306a36Sopenharmony_ci if (!rc) { 112362306a36Sopenharmony_ci if ((!new_ip) || (ino != new_ip->i_ino)) { 112462306a36Sopenharmony_ci rc = -ESTALE; 112562306a36Sopenharmony_ci goto out3; 112662306a36Sopenharmony_ci } 112762306a36Sopenharmony_ci } else if (rc != -ENOENT) 112862306a36Sopenharmony_ci goto out3; 112962306a36Sopenharmony_ci else if (new_ip) { 113062306a36Sopenharmony_ci /* no entry exists, but one was expected */ 113162306a36Sopenharmony_ci rc = -ESTALE; 113262306a36Sopenharmony_ci goto out3; 113362306a36Sopenharmony_ci } 113462306a36Sopenharmony_ci 113562306a36Sopenharmony_ci if (S_ISDIR(old_ip->i_mode)) { 113662306a36Sopenharmony_ci if (new_ip) { 113762306a36Sopenharmony_ci if (!dtEmpty(new_ip)) { 113862306a36Sopenharmony_ci rc = -ENOTEMPTY; 113962306a36Sopenharmony_ci goto out3; 114062306a36Sopenharmony_ci } 114162306a36Sopenharmony_ci } 114262306a36Sopenharmony_ci } else if (new_ip) { 114362306a36Sopenharmony_ci IWRITE_LOCK(new_ip, RDWRLOCK_NORMAL); 114462306a36Sopenharmony_ci /* Init inode for quota operations. */ 114562306a36Sopenharmony_ci rc = dquot_initialize(new_ip); 114662306a36Sopenharmony_ci if (rc) 114762306a36Sopenharmony_ci goto out_unlock; 114862306a36Sopenharmony_ci } 114962306a36Sopenharmony_ci 115062306a36Sopenharmony_ci /* 115162306a36Sopenharmony_ci * The real work starts here 115262306a36Sopenharmony_ci */ 115362306a36Sopenharmony_ci tid = txBegin(new_dir->i_sb, 0); 115462306a36Sopenharmony_ci 115562306a36Sopenharmony_ci /* 115662306a36Sopenharmony_ci * How do we know the locking is safe from deadlocks? 115762306a36Sopenharmony_ci * The vfs does the hard part for us. Any time we are taking nested 115862306a36Sopenharmony_ci * commit_mutexes, the vfs already has i_mutex held on the parent. 115962306a36Sopenharmony_ci * Here, the vfs has already taken i_mutex on both old_dir and new_dir. 116062306a36Sopenharmony_ci */ 116162306a36Sopenharmony_ci mutex_lock_nested(&JFS_IP(new_dir)->commit_mutex, COMMIT_MUTEX_PARENT); 116262306a36Sopenharmony_ci mutex_lock_nested(&JFS_IP(old_ip)->commit_mutex, COMMIT_MUTEX_CHILD); 116362306a36Sopenharmony_ci if (old_dir != new_dir) 116462306a36Sopenharmony_ci mutex_lock_nested(&JFS_IP(old_dir)->commit_mutex, 116562306a36Sopenharmony_ci COMMIT_MUTEX_SECOND_PARENT); 116662306a36Sopenharmony_ci 116762306a36Sopenharmony_ci if (new_ip) { 116862306a36Sopenharmony_ci mutex_lock_nested(&JFS_IP(new_ip)->commit_mutex, 116962306a36Sopenharmony_ci COMMIT_MUTEX_VICTIM); 117062306a36Sopenharmony_ci /* 117162306a36Sopenharmony_ci * Change existing directory entry to new inode number 117262306a36Sopenharmony_ci */ 117362306a36Sopenharmony_ci ino = new_ip->i_ino; 117462306a36Sopenharmony_ci rc = dtModify(tid, new_dir, &new_dname, &ino, 117562306a36Sopenharmony_ci old_ip->i_ino, JFS_RENAME); 117662306a36Sopenharmony_ci if (rc) 117762306a36Sopenharmony_ci goto out_tx; 117862306a36Sopenharmony_ci drop_nlink(new_ip); 117962306a36Sopenharmony_ci if (S_ISDIR(new_ip->i_mode)) { 118062306a36Sopenharmony_ci drop_nlink(new_ip); 118162306a36Sopenharmony_ci if (new_ip->i_nlink) { 118262306a36Sopenharmony_ci mutex_unlock(&JFS_IP(new_ip)->commit_mutex); 118362306a36Sopenharmony_ci if (old_dir != new_dir) 118462306a36Sopenharmony_ci mutex_unlock(&JFS_IP(old_dir)->commit_mutex); 118562306a36Sopenharmony_ci mutex_unlock(&JFS_IP(old_ip)->commit_mutex); 118662306a36Sopenharmony_ci mutex_unlock(&JFS_IP(new_dir)->commit_mutex); 118762306a36Sopenharmony_ci if (!S_ISDIR(old_ip->i_mode) && new_ip) 118862306a36Sopenharmony_ci IWRITE_UNLOCK(new_ip); 118962306a36Sopenharmony_ci jfs_error(new_ip->i_sb, 119062306a36Sopenharmony_ci "new_ip->i_nlink != 0\n"); 119162306a36Sopenharmony_ci return -EIO; 119262306a36Sopenharmony_ci } 119362306a36Sopenharmony_ci tblk = tid_to_tblock(tid); 119462306a36Sopenharmony_ci tblk->xflag |= COMMIT_DELETE; 119562306a36Sopenharmony_ci tblk->u.ip = new_ip; 119662306a36Sopenharmony_ci } else if (new_ip->i_nlink == 0) { 119762306a36Sopenharmony_ci assert(!test_cflag(COMMIT_Nolink, new_ip)); 119862306a36Sopenharmony_ci /* free block resources */ 119962306a36Sopenharmony_ci if ((new_size = commitZeroLink(tid, new_ip)) < 0) { 120062306a36Sopenharmony_ci txAbort(tid, 1); /* Marks FS Dirty */ 120162306a36Sopenharmony_ci rc = new_size; 120262306a36Sopenharmony_ci goto out_tx; 120362306a36Sopenharmony_ci } 120462306a36Sopenharmony_ci tblk = tid_to_tblock(tid); 120562306a36Sopenharmony_ci tblk->xflag |= COMMIT_DELETE; 120662306a36Sopenharmony_ci tblk->u.ip = new_ip; 120762306a36Sopenharmony_ci } else { 120862306a36Sopenharmony_ci inode_set_ctime_current(new_ip); 120962306a36Sopenharmony_ci mark_inode_dirty(new_ip); 121062306a36Sopenharmony_ci } 121162306a36Sopenharmony_ci } else { 121262306a36Sopenharmony_ci /* 121362306a36Sopenharmony_ci * Add new directory entry 121462306a36Sopenharmony_ci */ 121562306a36Sopenharmony_ci rc = dtSearch(new_dir, &new_dname, &ino, &btstack, 121662306a36Sopenharmony_ci JFS_CREATE); 121762306a36Sopenharmony_ci if (rc) { 121862306a36Sopenharmony_ci jfs_err("jfs_rename didn't expect dtSearch to fail w/rc = %d", 121962306a36Sopenharmony_ci rc); 122062306a36Sopenharmony_ci goto out_tx; 122162306a36Sopenharmony_ci } 122262306a36Sopenharmony_ci 122362306a36Sopenharmony_ci ino = old_ip->i_ino; 122462306a36Sopenharmony_ci rc = dtInsert(tid, new_dir, &new_dname, &ino, &btstack); 122562306a36Sopenharmony_ci if (rc) { 122662306a36Sopenharmony_ci if (rc == -EIO) 122762306a36Sopenharmony_ci jfs_err("jfs_rename: dtInsert returned -EIO"); 122862306a36Sopenharmony_ci goto out_tx; 122962306a36Sopenharmony_ci } 123062306a36Sopenharmony_ci if (S_ISDIR(old_ip->i_mode)) 123162306a36Sopenharmony_ci inc_nlink(new_dir); 123262306a36Sopenharmony_ci } 123362306a36Sopenharmony_ci /* 123462306a36Sopenharmony_ci * Remove old directory entry 123562306a36Sopenharmony_ci */ 123662306a36Sopenharmony_ci 123762306a36Sopenharmony_ci ino = old_ip->i_ino; 123862306a36Sopenharmony_ci rc = dtDelete(tid, old_dir, &old_dname, &ino, JFS_REMOVE); 123962306a36Sopenharmony_ci if (rc) { 124062306a36Sopenharmony_ci jfs_err("jfs_rename did not expect dtDelete to return rc = %d", 124162306a36Sopenharmony_ci rc); 124262306a36Sopenharmony_ci txAbort(tid, 1); /* Marks Filesystem dirty */ 124362306a36Sopenharmony_ci goto out_tx; 124462306a36Sopenharmony_ci } 124562306a36Sopenharmony_ci if (S_ISDIR(old_ip->i_mode)) { 124662306a36Sopenharmony_ci drop_nlink(old_dir); 124762306a36Sopenharmony_ci if (old_dir != new_dir) { 124862306a36Sopenharmony_ci /* 124962306a36Sopenharmony_ci * Change inode number of parent for moved directory 125062306a36Sopenharmony_ci */ 125162306a36Sopenharmony_ci 125262306a36Sopenharmony_ci JFS_IP(old_ip)->i_dtroot.header.idotdot = 125362306a36Sopenharmony_ci cpu_to_le32(new_dir->i_ino); 125462306a36Sopenharmony_ci 125562306a36Sopenharmony_ci /* Linelock header of dtree */ 125662306a36Sopenharmony_ci tlck = txLock(tid, old_ip, 125762306a36Sopenharmony_ci (struct metapage *) &JFS_IP(old_ip)->bxflag, 125862306a36Sopenharmony_ci tlckDTREE | tlckBTROOT | tlckRELINK); 125962306a36Sopenharmony_ci dtlck = (struct dt_lock *) & tlck->lock; 126062306a36Sopenharmony_ci ASSERT(dtlck->index == 0); 126162306a36Sopenharmony_ci lv = & dtlck->lv[0]; 126262306a36Sopenharmony_ci lv->offset = 0; 126362306a36Sopenharmony_ci lv->length = 1; 126462306a36Sopenharmony_ci dtlck->index++; 126562306a36Sopenharmony_ci } 126662306a36Sopenharmony_ci } 126762306a36Sopenharmony_ci 126862306a36Sopenharmony_ci /* 126962306a36Sopenharmony_ci * Update ctime on changed/moved inodes & mark dirty 127062306a36Sopenharmony_ci */ 127162306a36Sopenharmony_ci inode_set_ctime_current(old_ip); 127262306a36Sopenharmony_ci mark_inode_dirty(old_ip); 127362306a36Sopenharmony_ci 127462306a36Sopenharmony_ci new_dir->i_mtime = inode_set_ctime_current(new_dir); 127562306a36Sopenharmony_ci mark_inode_dirty(new_dir); 127662306a36Sopenharmony_ci 127762306a36Sopenharmony_ci /* Build list of inodes modified by this transaction */ 127862306a36Sopenharmony_ci ipcount = 0; 127962306a36Sopenharmony_ci iplist[ipcount++] = old_ip; 128062306a36Sopenharmony_ci if (new_ip) 128162306a36Sopenharmony_ci iplist[ipcount++] = new_ip; 128262306a36Sopenharmony_ci iplist[ipcount++] = old_dir; 128362306a36Sopenharmony_ci 128462306a36Sopenharmony_ci if (old_dir != new_dir) { 128562306a36Sopenharmony_ci iplist[ipcount++] = new_dir; 128662306a36Sopenharmony_ci old_dir->i_mtime = inode_set_ctime_current(old_dir); 128762306a36Sopenharmony_ci mark_inode_dirty(old_dir); 128862306a36Sopenharmony_ci } 128962306a36Sopenharmony_ci 129062306a36Sopenharmony_ci /* 129162306a36Sopenharmony_ci * Incomplete truncate of file data can 129262306a36Sopenharmony_ci * result in timing problems unless we synchronously commit the 129362306a36Sopenharmony_ci * transaction. 129462306a36Sopenharmony_ci */ 129562306a36Sopenharmony_ci if (new_size) 129662306a36Sopenharmony_ci commit_flag = COMMIT_SYNC; 129762306a36Sopenharmony_ci else 129862306a36Sopenharmony_ci commit_flag = 0; 129962306a36Sopenharmony_ci 130062306a36Sopenharmony_ci rc = txCommit(tid, ipcount, iplist, commit_flag); 130162306a36Sopenharmony_ci 130262306a36Sopenharmony_ci out_tx: 130362306a36Sopenharmony_ci txEnd(tid); 130462306a36Sopenharmony_ci if (new_ip) 130562306a36Sopenharmony_ci mutex_unlock(&JFS_IP(new_ip)->commit_mutex); 130662306a36Sopenharmony_ci if (old_dir != new_dir) 130762306a36Sopenharmony_ci mutex_unlock(&JFS_IP(old_dir)->commit_mutex); 130862306a36Sopenharmony_ci mutex_unlock(&JFS_IP(old_ip)->commit_mutex); 130962306a36Sopenharmony_ci mutex_unlock(&JFS_IP(new_dir)->commit_mutex); 131062306a36Sopenharmony_ci 131162306a36Sopenharmony_ci while (new_size && (rc == 0)) { 131262306a36Sopenharmony_ci tid = txBegin(new_ip->i_sb, 0); 131362306a36Sopenharmony_ci mutex_lock(&JFS_IP(new_ip)->commit_mutex); 131462306a36Sopenharmony_ci new_size = xtTruncate_pmap(tid, new_ip, new_size); 131562306a36Sopenharmony_ci if (new_size < 0) { 131662306a36Sopenharmony_ci txAbort(tid, 1); 131762306a36Sopenharmony_ci rc = new_size; 131862306a36Sopenharmony_ci } else 131962306a36Sopenharmony_ci rc = txCommit(tid, 1, &new_ip, COMMIT_SYNC); 132062306a36Sopenharmony_ci txEnd(tid); 132162306a36Sopenharmony_ci mutex_unlock(&JFS_IP(new_ip)->commit_mutex); 132262306a36Sopenharmony_ci } 132362306a36Sopenharmony_ci if (new_ip && (new_ip->i_nlink == 0)) 132462306a36Sopenharmony_ci set_cflag(COMMIT_Nolink, new_ip); 132562306a36Sopenharmony_ci /* 132662306a36Sopenharmony_ci * Truncating the directory index table is not guaranteed. It 132762306a36Sopenharmony_ci * may need to be done iteratively 132862306a36Sopenharmony_ci */ 132962306a36Sopenharmony_ci if (test_cflag(COMMIT_Stale, old_dir)) { 133062306a36Sopenharmony_ci if (old_dir->i_size > 1) 133162306a36Sopenharmony_ci jfs_truncate_nolock(old_dir, 0); 133262306a36Sopenharmony_ci 133362306a36Sopenharmony_ci clear_cflag(COMMIT_Stale, old_dir); 133462306a36Sopenharmony_ci } 133562306a36Sopenharmony_ci out_unlock: 133662306a36Sopenharmony_ci if (new_ip && !S_ISDIR(new_ip->i_mode)) 133762306a36Sopenharmony_ci IWRITE_UNLOCK(new_ip); 133862306a36Sopenharmony_ci out3: 133962306a36Sopenharmony_ci free_UCSname(&new_dname); 134062306a36Sopenharmony_ci out2: 134162306a36Sopenharmony_ci free_UCSname(&old_dname); 134262306a36Sopenharmony_ci out1: 134362306a36Sopenharmony_ci jfs_info("jfs_rename: returning %d", rc); 134462306a36Sopenharmony_ci return rc; 134562306a36Sopenharmony_ci} 134662306a36Sopenharmony_ci 134762306a36Sopenharmony_ci 134862306a36Sopenharmony_ci/* 134962306a36Sopenharmony_ci * NAME: jfs_mknod 135062306a36Sopenharmony_ci * 135162306a36Sopenharmony_ci * FUNCTION: Create a special file (device) 135262306a36Sopenharmony_ci */ 135362306a36Sopenharmony_cistatic int jfs_mknod(struct mnt_idmap *idmap, struct inode *dir, 135462306a36Sopenharmony_ci struct dentry *dentry, umode_t mode, dev_t rdev) 135562306a36Sopenharmony_ci{ 135662306a36Sopenharmony_ci struct jfs_inode_info *jfs_ip; 135762306a36Sopenharmony_ci struct btstack btstack; 135862306a36Sopenharmony_ci struct component_name dname; 135962306a36Sopenharmony_ci ino_t ino; 136062306a36Sopenharmony_ci struct inode *ip; 136162306a36Sopenharmony_ci struct inode *iplist[2]; 136262306a36Sopenharmony_ci int rc; 136362306a36Sopenharmony_ci tid_t tid; 136462306a36Sopenharmony_ci struct tblock *tblk; 136562306a36Sopenharmony_ci 136662306a36Sopenharmony_ci jfs_info("jfs_mknod: %pd", dentry); 136762306a36Sopenharmony_ci 136862306a36Sopenharmony_ci rc = dquot_initialize(dir); 136962306a36Sopenharmony_ci if (rc) 137062306a36Sopenharmony_ci goto out; 137162306a36Sopenharmony_ci 137262306a36Sopenharmony_ci if ((rc = get_UCSname(&dname, dentry))) 137362306a36Sopenharmony_ci goto out; 137462306a36Sopenharmony_ci 137562306a36Sopenharmony_ci ip = ialloc(dir, mode); 137662306a36Sopenharmony_ci if (IS_ERR(ip)) { 137762306a36Sopenharmony_ci rc = PTR_ERR(ip); 137862306a36Sopenharmony_ci goto out1; 137962306a36Sopenharmony_ci } 138062306a36Sopenharmony_ci jfs_ip = JFS_IP(ip); 138162306a36Sopenharmony_ci 138262306a36Sopenharmony_ci tid = txBegin(dir->i_sb, 0); 138362306a36Sopenharmony_ci 138462306a36Sopenharmony_ci mutex_lock_nested(&JFS_IP(dir)->commit_mutex, COMMIT_MUTEX_PARENT); 138562306a36Sopenharmony_ci mutex_lock_nested(&JFS_IP(ip)->commit_mutex, COMMIT_MUTEX_CHILD); 138662306a36Sopenharmony_ci 138762306a36Sopenharmony_ci rc = jfs_init_acl(tid, ip, dir); 138862306a36Sopenharmony_ci if (rc) 138962306a36Sopenharmony_ci goto out3; 139062306a36Sopenharmony_ci 139162306a36Sopenharmony_ci rc = jfs_init_security(tid, ip, dir, &dentry->d_name); 139262306a36Sopenharmony_ci if (rc) { 139362306a36Sopenharmony_ci txAbort(tid, 0); 139462306a36Sopenharmony_ci goto out3; 139562306a36Sopenharmony_ci } 139662306a36Sopenharmony_ci 139762306a36Sopenharmony_ci if ((rc = dtSearch(dir, &dname, &ino, &btstack, JFS_CREATE))) { 139862306a36Sopenharmony_ci txAbort(tid, 0); 139962306a36Sopenharmony_ci goto out3; 140062306a36Sopenharmony_ci } 140162306a36Sopenharmony_ci 140262306a36Sopenharmony_ci tblk = tid_to_tblock(tid); 140362306a36Sopenharmony_ci tblk->xflag |= COMMIT_CREATE; 140462306a36Sopenharmony_ci tblk->ino = ip->i_ino; 140562306a36Sopenharmony_ci tblk->u.ixpxd = JFS_IP(ip)->ixpxd; 140662306a36Sopenharmony_ci 140762306a36Sopenharmony_ci ino = ip->i_ino; 140862306a36Sopenharmony_ci if ((rc = dtInsert(tid, dir, &dname, &ino, &btstack))) { 140962306a36Sopenharmony_ci txAbort(tid, 0); 141062306a36Sopenharmony_ci goto out3; 141162306a36Sopenharmony_ci } 141262306a36Sopenharmony_ci 141362306a36Sopenharmony_ci ip->i_op = &jfs_file_inode_operations; 141462306a36Sopenharmony_ci jfs_ip->dev = new_encode_dev(rdev); 141562306a36Sopenharmony_ci init_special_inode(ip, ip->i_mode, rdev); 141662306a36Sopenharmony_ci 141762306a36Sopenharmony_ci mark_inode_dirty(ip); 141862306a36Sopenharmony_ci 141962306a36Sopenharmony_ci dir->i_mtime = inode_set_ctime_current(dir); 142062306a36Sopenharmony_ci 142162306a36Sopenharmony_ci mark_inode_dirty(dir); 142262306a36Sopenharmony_ci 142362306a36Sopenharmony_ci iplist[0] = dir; 142462306a36Sopenharmony_ci iplist[1] = ip; 142562306a36Sopenharmony_ci rc = txCommit(tid, 2, iplist, 0); 142662306a36Sopenharmony_ci 142762306a36Sopenharmony_ci out3: 142862306a36Sopenharmony_ci txEnd(tid); 142962306a36Sopenharmony_ci mutex_unlock(&JFS_IP(ip)->commit_mutex); 143062306a36Sopenharmony_ci mutex_unlock(&JFS_IP(dir)->commit_mutex); 143162306a36Sopenharmony_ci if (rc) { 143262306a36Sopenharmony_ci free_ea_wmap(ip); 143362306a36Sopenharmony_ci clear_nlink(ip); 143462306a36Sopenharmony_ci discard_new_inode(ip); 143562306a36Sopenharmony_ci } else { 143662306a36Sopenharmony_ci d_instantiate_new(dentry, ip); 143762306a36Sopenharmony_ci } 143862306a36Sopenharmony_ci 143962306a36Sopenharmony_ci out1: 144062306a36Sopenharmony_ci free_UCSname(&dname); 144162306a36Sopenharmony_ci 144262306a36Sopenharmony_ci out: 144362306a36Sopenharmony_ci jfs_info("jfs_mknod: returning %d", rc); 144462306a36Sopenharmony_ci return rc; 144562306a36Sopenharmony_ci} 144662306a36Sopenharmony_ci 144762306a36Sopenharmony_cistatic struct dentry *jfs_lookup(struct inode *dip, struct dentry *dentry, unsigned int flags) 144862306a36Sopenharmony_ci{ 144962306a36Sopenharmony_ci struct btstack btstack; 145062306a36Sopenharmony_ci ino_t inum; 145162306a36Sopenharmony_ci struct inode *ip; 145262306a36Sopenharmony_ci struct component_name key; 145362306a36Sopenharmony_ci int rc; 145462306a36Sopenharmony_ci 145562306a36Sopenharmony_ci jfs_info("jfs_lookup: name = %pd", dentry); 145662306a36Sopenharmony_ci 145762306a36Sopenharmony_ci if ((rc = get_UCSname(&key, dentry))) 145862306a36Sopenharmony_ci return ERR_PTR(rc); 145962306a36Sopenharmony_ci rc = dtSearch(dip, &key, &inum, &btstack, JFS_LOOKUP); 146062306a36Sopenharmony_ci free_UCSname(&key); 146162306a36Sopenharmony_ci if (rc == -ENOENT) { 146262306a36Sopenharmony_ci ip = NULL; 146362306a36Sopenharmony_ci } else if (rc) { 146462306a36Sopenharmony_ci jfs_err("jfs_lookup: dtSearch returned %d", rc); 146562306a36Sopenharmony_ci ip = ERR_PTR(rc); 146662306a36Sopenharmony_ci } else { 146762306a36Sopenharmony_ci ip = jfs_iget(dip->i_sb, inum); 146862306a36Sopenharmony_ci if (IS_ERR(ip)) 146962306a36Sopenharmony_ci jfs_err("jfs_lookup: iget failed on inum %d", (uint)inum); 147062306a36Sopenharmony_ci } 147162306a36Sopenharmony_ci 147262306a36Sopenharmony_ci return d_splice_alias(ip, dentry); 147362306a36Sopenharmony_ci} 147462306a36Sopenharmony_ci 147562306a36Sopenharmony_cistatic struct inode *jfs_nfs_get_inode(struct super_block *sb, 147662306a36Sopenharmony_ci u64 ino, u32 generation) 147762306a36Sopenharmony_ci{ 147862306a36Sopenharmony_ci struct inode *inode; 147962306a36Sopenharmony_ci 148062306a36Sopenharmony_ci if (ino == 0) 148162306a36Sopenharmony_ci return ERR_PTR(-ESTALE); 148262306a36Sopenharmony_ci inode = jfs_iget(sb, ino); 148362306a36Sopenharmony_ci if (IS_ERR(inode)) 148462306a36Sopenharmony_ci return ERR_CAST(inode); 148562306a36Sopenharmony_ci 148662306a36Sopenharmony_ci if (generation && inode->i_generation != generation) { 148762306a36Sopenharmony_ci iput(inode); 148862306a36Sopenharmony_ci return ERR_PTR(-ESTALE); 148962306a36Sopenharmony_ci } 149062306a36Sopenharmony_ci 149162306a36Sopenharmony_ci return inode; 149262306a36Sopenharmony_ci} 149362306a36Sopenharmony_ci 149462306a36Sopenharmony_cistruct dentry *jfs_fh_to_dentry(struct super_block *sb, struct fid *fid, 149562306a36Sopenharmony_ci int fh_len, int fh_type) 149662306a36Sopenharmony_ci{ 149762306a36Sopenharmony_ci return generic_fh_to_dentry(sb, fid, fh_len, fh_type, 149862306a36Sopenharmony_ci jfs_nfs_get_inode); 149962306a36Sopenharmony_ci} 150062306a36Sopenharmony_ci 150162306a36Sopenharmony_cistruct dentry *jfs_fh_to_parent(struct super_block *sb, struct fid *fid, 150262306a36Sopenharmony_ci int fh_len, int fh_type) 150362306a36Sopenharmony_ci{ 150462306a36Sopenharmony_ci return generic_fh_to_parent(sb, fid, fh_len, fh_type, 150562306a36Sopenharmony_ci jfs_nfs_get_inode); 150662306a36Sopenharmony_ci} 150762306a36Sopenharmony_ci 150862306a36Sopenharmony_cistruct dentry *jfs_get_parent(struct dentry *dentry) 150962306a36Sopenharmony_ci{ 151062306a36Sopenharmony_ci unsigned long parent_ino; 151162306a36Sopenharmony_ci 151262306a36Sopenharmony_ci parent_ino = 151362306a36Sopenharmony_ci le32_to_cpu(JFS_IP(d_inode(dentry))->i_dtroot.header.idotdot); 151462306a36Sopenharmony_ci 151562306a36Sopenharmony_ci return d_obtain_alias(jfs_iget(dentry->d_sb, parent_ino)); 151662306a36Sopenharmony_ci} 151762306a36Sopenharmony_ci 151862306a36Sopenharmony_ciconst struct inode_operations jfs_dir_inode_operations = { 151962306a36Sopenharmony_ci .create = jfs_create, 152062306a36Sopenharmony_ci .lookup = jfs_lookup, 152162306a36Sopenharmony_ci .link = jfs_link, 152262306a36Sopenharmony_ci .unlink = jfs_unlink, 152362306a36Sopenharmony_ci .symlink = jfs_symlink, 152462306a36Sopenharmony_ci .mkdir = jfs_mkdir, 152562306a36Sopenharmony_ci .rmdir = jfs_rmdir, 152662306a36Sopenharmony_ci .mknod = jfs_mknod, 152762306a36Sopenharmony_ci .rename = jfs_rename, 152862306a36Sopenharmony_ci .listxattr = jfs_listxattr, 152962306a36Sopenharmony_ci .setattr = jfs_setattr, 153062306a36Sopenharmony_ci .fileattr_get = jfs_fileattr_get, 153162306a36Sopenharmony_ci .fileattr_set = jfs_fileattr_set, 153262306a36Sopenharmony_ci#ifdef CONFIG_JFS_POSIX_ACL 153362306a36Sopenharmony_ci .get_inode_acl = jfs_get_acl, 153462306a36Sopenharmony_ci .set_acl = jfs_set_acl, 153562306a36Sopenharmony_ci#endif 153662306a36Sopenharmony_ci}; 153762306a36Sopenharmony_ci 153862306a36Sopenharmony_ciWRAP_DIR_ITER(jfs_readdir) // FIXME! 153962306a36Sopenharmony_ciconst struct file_operations jfs_dir_operations = { 154062306a36Sopenharmony_ci .read = generic_read_dir, 154162306a36Sopenharmony_ci .iterate_shared = shared_jfs_readdir, 154262306a36Sopenharmony_ci .fsync = jfs_fsync, 154362306a36Sopenharmony_ci .unlocked_ioctl = jfs_ioctl, 154462306a36Sopenharmony_ci .compat_ioctl = compat_ptr_ioctl, 154562306a36Sopenharmony_ci .llseek = generic_file_llseek, 154662306a36Sopenharmony_ci}; 154762306a36Sopenharmony_ci 154862306a36Sopenharmony_cistatic int jfs_ci_hash(const struct dentry *dir, struct qstr *this) 154962306a36Sopenharmony_ci{ 155062306a36Sopenharmony_ci unsigned long hash; 155162306a36Sopenharmony_ci int i; 155262306a36Sopenharmony_ci 155362306a36Sopenharmony_ci hash = init_name_hash(dir); 155462306a36Sopenharmony_ci for (i=0; i < this->len; i++) 155562306a36Sopenharmony_ci hash = partial_name_hash(tolower(this->name[i]), hash); 155662306a36Sopenharmony_ci this->hash = end_name_hash(hash); 155762306a36Sopenharmony_ci 155862306a36Sopenharmony_ci return 0; 155962306a36Sopenharmony_ci} 156062306a36Sopenharmony_ci 156162306a36Sopenharmony_cistatic int jfs_ci_compare(const struct dentry *dentry, 156262306a36Sopenharmony_ci unsigned int len, const char *str, const struct qstr *name) 156362306a36Sopenharmony_ci{ 156462306a36Sopenharmony_ci int i, result = 1; 156562306a36Sopenharmony_ci 156662306a36Sopenharmony_ci if (len != name->len) 156762306a36Sopenharmony_ci goto out; 156862306a36Sopenharmony_ci for (i=0; i < len; i++) { 156962306a36Sopenharmony_ci if (tolower(str[i]) != tolower(name->name[i])) 157062306a36Sopenharmony_ci goto out; 157162306a36Sopenharmony_ci } 157262306a36Sopenharmony_ci result = 0; 157362306a36Sopenharmony_ciout: 157462306a36Sopenharmony_ci return result; 157562306a36Sopenharmony_ci} 157662306a36Sopenharmony_ci 157762306a36Sopenharmony_cistatic int jfs_ci_revalidate(struct dentry *dentry, unsigned int flags) 157862306a36Sopenharmony_ci{ 157962306a36Sopenharmony_ci /* 158062306a36Sopenharmony_ci * This is not negative dentry. Always valid. 158162306a36Sopenharmony_ci * 158262306a36Sopenharmony_ci * Note, rename() to existing directory entry will have ->d_inode, 158362306a36Sopenharmony_ci * and will use existing name which isn't specified name by user. 158462306a36Sopenharmony_ci * 158562306a36Sopenharmony_ci * We may be able to drop this positive dentry here. But dropping 158662306a36Sopenharmony_ci * positive dentry isn't good idea. So it's unsupported like 158762306a36Sopenharmony_ci * rename("filename", "FILENAME") for now. 158862306a36Sopenharmony_ci */ 158962306a36Sopenharmony_ci if (d_really_is_positive(dentry)) 159062306a36Sopenharmony_ci return 1; 159162306a36Sopenharmony_ci 159262306a36Sopenharmony_ci /* 159362306a36Sopenharmony_ci * This may be nfsd (or something), anyway, we can't see the 159462306a36Sopenharmony_ci * intent of this. So, since this can be for creation, drop it. 159562306a36Sopenharmony_ci */ 159662306a36Sopenharmony_ci if (!flags) 159762306a36Sopenharmony_ci return 0; 159862306a36Sopenharmony_ci 159962306a36Sopenharmony_ci /* 160062306a36Sopenharmony_ci * Drop the negative dentry, in order to make sure to use the 160162306a36Sopenharmony_ci * case sensitive name which is specified by user if this is 160262306a36Sopenharmony_ci * for creation. 160362306a36Sopenharmony_ci */ 160462306a36Sopenharmony_ci if (flags & (LOOKUP_CREATE | LOOKUP_RENAME_TARGET)) 160562306a36Sopenharmony_ci return 0; 160662306a36Sopenharmony_ci return 1; 160762306a36Sopenharmony_ci} 160862306a36Sopenharmony_ci 160962306a36Sopenharmony_ciconst struct dentry_operations jfs_ci_dentry_operations = 161062306a36Sopenharmony_ci{ 161162306a36Sopenharmony_ci .d_hash = jfs_ci_hash, 161262306a36Sopenharmony_ci .d_compare = jfs_ci_compare, 161362306a36Sopenharmony_ci .d_revalidate = jfs_ci_revalidate, 161462306a36Sopenharmony_ci}; 1615