static struct dentry *jfs_lookup(struct inode *dip, struct dentry *dentry) { struct btstack btstack; ino_t inum; struct inode *ip; struct component_name key; const char *name = dentry->d_name.name; int len = dentry->d_name.len; int rc; jFYI(1, ("jfs_lookup: name = %s\n", name)); if ((name[0] == '.') && (len == 1)) inum = dip->i_ino; else if (strcmp(name, "..") == 0) inum = PARENT(dip); else { if ((rc = get_UCSname(&key, dentry, JFS_SBI(dip->i_sb)->nls_tab))) return ERR_PTR(-rc); rc = dtSearch(dip, &key, &inum, &btstack, JFS_LOOKUP); free_UCSname(&key); if (rc == ENOENT) { d_add(dentry, NULL); return ERR_PTR(0); } else if (rc) { jERROR(1, ("jfs_lookup: dtSearch returned %d\n", rc)); return ERR_PTR(-rc); } } ip = iget(dip->i_sb, inum); if (ip == NULL) { jERROR(1, ("jfs_lookup: iget failed on inum %d\n", (uint) inum)); return ERR_PTR(-EACCES); } d_add(dentry, ip); return ERR_PTR(0); }
tcstr Sys_Error::ReadCSV(IN size_t iRecord,IN EXCEL_CSV_STRING_VECTOR &out,IN OUT size_t& index,IN bool isCheck) { tcstr szKEY=0; tfname_t szHelp; szHelp[0]=0; if(isCheck && (out.size() != Get_STRUCT_COUNT()) ) { jERROR(_T("parse size error(%d!=Get_STRUCT_COUNT(%d) lineNum=%s"),out.size(),Get_STRUCT_COUNT(),index ); } Set_id(FromString(out[index++],m_id) ); Set_name(nExcelUtil_StringConverter(out[index++]).getT()); szKEY = Get_name(); Set_help(nExcelUtil_StringConverter(out[index++]).getT()); return szKEY; }
/* * NAME: pathlookup_pc * * FUNCTION: Lookup path, preserving case. * Lookup path, copying each component into output string * preserving its case. * * PARAMETERS: vfsp - pointer to VFS * path - full path name * path_pc - output - full path name w/preserved case * * RETURN: errors from subroutines. * * NOTES: We assume path is in canonical form: "X:\<path>" where there * are no extraneous backslashes and . and .. have been removed. * * dtFind is not very efficient for finding a directory entry * without wildcards, but infolevel 7 does not seem to actually * be used anywhere, so it must not be too important. */ int32 pathlookup_pc( struct vfs *vfsp, UniChar *path, /* input - Path */ UniChar *path_pc) /* output - path w/preserved case */ { int32 comp_len; uint32 count; UniChar *component; struct dirent *dbuf; inode_t *ip; int32 offset; UniChar *outptr = path_pc; component_t pattern; int rc; UniChar *slash; int32 tbytes; struct vnode *vp; if (vfsp == NULL) { jERROR(2,("pathlookup_pc: invalid VPB!\n")); return ENOTDIR; } /* Copy "X:\" to output string */ UniStrncpy(outptr, path, 3); outptr += 3; path += 3; if (*path == 0) { /* Trivial case "X:\" */ *outptr = 0; return NO_ERROR; } component = (UniChar *)allocpool(unipool, 0); if (component == 0) return ENOSPC; pattern.name = component; dbuf = (struct dirent *)allocpool(dirent_pool, 0); if (dbuf == 0) { freepool(unipool, (caddr_t *)component); return ENOSPC; } vp = vfsp->vfs_mntd; /* vnode of root directory */ jfs_hold(vp); while (path) { slash = UniStrchr(path, '\\'); if (slash) { comp_len = slash - path; slash++; } else comp_len = UniStrlen(path); UniStrncpy(component, path, comp_len); component[comp_len] = 0; UniStrupr(component); /* Convert to upper case */ pattern.namlen = comp_len; path = slash; offset = 0; count = 1; tbytes = 0; rc = dtFind(VP2IP(vp), &pattern, 0, &offset, &count, PSIZE, &tbytes, dbuf); jfs_rele(vp); if (rc || (count == 0)) { freepool(dirent_pool, (caddr_t *)dbuf); freepool(unipool, (caddr_t *)component); return ENOENT; } UniStrncpy(outptr, dbuf->d_name, dbuf->d_namlen); outptr += dbuf->d_namlen; if (path) { ICACHE_LOCK(); rc = iget(vfsp, dbuf->d_ino, &ip, 0); ICACHE_UNLOCK(); if (rc) { freepool(dirent_pool, (caddr_t *)dbuf); freepool(unipool, (caddr_t *)component); return rc; } vp = IP2VP(ip); *(outptr++) = '\\'; } else *outptr = 0; } freepool(dirent_pool, (caddr_t *)dbuf); freepool(unipool, (caddr_t *)component); return NO_ERROR; }
/* * NAME: ialloc() * * FUNCTION: Allocate a new inode * */ struct inode *ialloc(struct inode *parent, umode_t mode) { struct super_block *sb = parent->i_sb; struct inode *inode; struct jfs_inode_info *jfs_inode; int rc; inode = new_inode(sb); if (!inode) { jERROR(1, ("ialloc: new_inode returned NULL!\n")); return inode; } rc = alloc_jfs_inode(inode); if (rc) { make_bad_inode(inode); iput(inode); return NULL; } jfs_inode = JFS_IP(inode); rc = diAlloc(parent, S_ISDIR(mode), inode); if (rc) { jERROR(1, ("ialloc: diAlloc returned %d!\n", rc)); free_jfs_inode(inode); make_bad_inode(inode); iput(inode); return NULL; } inode->i_uid = current->fsuid; if (parent->i_mode & S_ISGID) { inode->i_gid = parent->i_gid; if (S_ISDIR(mode)) mode |= S_ISGID; } else inode->i_gid = current->fsgid; inode->i_mode = mode; if (S_ISDIR(mode)) jfs_inode->mode2 = IDIRECTORY | mode; else jfs_inode->mode2 = INLINEEA | ISPARSE | mode; inode->i_blksize = sb->s_blocksize; inode->i_blocks = 0; inode->i_mtime = inode->i_atime = inode->i_ctime = CURRENT_TIME; jfs_inode->otime = inode->i_ctime; inode->i_generation = JFS_SBI(sb)->gengen++; jfs_inode->cflag = 0; set_cflag(COMMIT_New, inode); /* Zero remaining fields */ memset(&jfs_inode->acl, 0, sizeof(dxd_t)); memset(&jfs_inode->ea, 0, sizeof(dxd_t)); jfs_inode->next_index = 0; jfs_inode->acltype = 0; jfs_inode->btorder = 0; jfs_inode->btindex = 0; jfs_inode->bxflag = 0; jfs_inode->blid = 0; jfs_inode->atlhead = 0; jfs_inode->atltail = 0; jfs_inode->xtlid = 0; jFYI(1, ("ialloc returns inode = 0x%p\n", inode)); return inode; }
int jfs_symlink(struct inode *dip, struct dentry *dentry, const char *name) { int rc; tid_t tid; ino_t ino = 0; struct component_name dname; int ssize; /* source pathname size */ struct btstack btstack; struct inode *ip = dentry->d_inode; unchar *i_fastsymlink; s64 xlen = 0; int bmask = 0, xsize; s64 xaddr; struct metapage *mp; struct super_block *sb; struct tblock *tblk; struct inode *iplist[2]; jFYI(1, ("jfs_symlink: dip:0x%p name:%s\n", dip, name)); ssize = strlen(name) + 1; /* * search parent directory for entry/freespace * (dtSearch() returns parent directory page pinned) */ if ((rc = get_UCSname(&dname, dentry, JFS_SBI(dip->i_sb)->nls_tab))) goto out1; /* * allocate on-disk/in-memory inode for symbolic link: * (iAlloc() returns new, locked inode) */ ip = ialloc(dip, S_IFLNK | 0777); if (ip == NULL) { rc = ENOSPC; goto out2; } tid = txBegin(dip->i_sb, 0); down(&JFS_IP(dip)->commit_sem); down(&JFS_IP(ip)->commit_sem); if ((rc = dtSearch(dip, &dname, &ino, &btstack, JFS_CREATE))) goto out3; tblk = tid_to_tblock(tid); tblk->xflag |= COMMIT_CREATE; tblk->ip = ip; /* * create entry for symbolic link in parent directory */ ino = ip->i_ino; if ((rc = dtInsert(tid, dip, &dname, &ino, &btstack))) { jERROR(1, ("jfs_symlink: dtInsert returned %d\n", rc)); /* discard ne inode */ goto out3; } /* fix symlink access permission * (dir_create() ANDs in the u.u_cmask, * but symlinks really need to be 777 access) */ ip->i_mode |= 0777; /* * write symbolic link target path name */ xtInitRoot(tid, ip); /* * write source path name inline in on-disk inode (fast symbolic link) */ if (ssize <= IDATASIZE) { ip->i_op = &jfs_symlink_inode_operations; i_fastsymlink = JFS_IP(ip)->i_inline; memcpy(i_fastsymlink, name, ssize); ip->i_size = ssize - 1; /* * if symlink is > 128 bytes, we don't have the space to * store inline extended attributes */ if (ssize > sizeof (JFS_IP(ip)->i_inline)) JFS_IP(ip)->mode2 &= ~INLINEEA; jFYI(1, ("jfs_symlink: fast symlink added ssize:%d name:%s \n", ssize, name)); } /* * write source path name in a single extent */ else { jFYI(1, ("jfs_symlink: allocate extent ip:0x%p\n", ip)); ip->i_op = &page_symlink_inode_operations; ip->i_mapping->a_ops = &jfs_aops; /* * 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. */ sb = ip->i_sb; bmask = JFS_SBI(sb)->bsize - 1; xsize = (ssize + bmask) & ~bmask; xaddr = 0; xlen = xsize >> JFS_SBI(sb)->l2bsize; if ((rc = xtInsert(tid, ip, 0, 0, xlen, &xaddr, 0)) == 0) { ip->i_size = ssize - 1; while (ssize) { int copy_size = min(ssize, PSIZE); mp = get_metapage(ip, xaddr, PSIZE, 1); if (mp == NULL) { dtDelete(tid, dip, &dname, &ino, JFS_REMOVE); rc = EIO; goto out3; } memcpy(mp->data, name, copy_size); flush_metapage(mp); #if 0 mark_buffer_uptodate(bp, 1); mark_buffer_dirty(bp, 1); if (IS_SYNC(dip)) { ll_rw_block(WRITE, 1, &bp); wait_on_buffer(bp); } brelse(bp); #endif /* 0 */ ssize -= copy_size; xaddr += JFS_SBI(sb)->nbperpage; } ip->i_blocks = LBLK2PBLK(sb, xlen); } else { dtDelete(tid, dip, &dname, &ino, JFS_REMOVE); rc = ENOSPC; goto out3; } } insert_inode_hash(ip); mark_inode_dirty(ip); d_instantiate(dentry, ip); /* * commit update of parent directory and link object * * if extent allocation failed (ENOSPC), * the parent inode is committed regardless to avoid * backing out parent directory update (by dtInsert()) * and subsequent dtDelete() which is harmless wrt * integrity concern. * the symlink inode will be freed by iput() at exit * as it has a zero link count (by dtDelete()) and * no permanant resources. */ iplist[0] = dip; if (rc == 0) { iplist[1] = ip; rc = txCommit(tid, 2, &iplist[0], 0); } else rc = txCommit(tid, 1, &iplist[0], 0); out3: txEnd(tid); up(&JFS_IP(dip)->commit_sem); up(&JFS_IP(ip)->commit_sem); if (rc) { ip->i_nlink = 0; iput(ip); } out2: free_UCSname(&dname); out1: jFYI(1, ("jfs_symlink: rc:%d\n", -rc)); return -rc; }
/* * NAME: jfs_create(dip, dentry, mode) * * FUNCTION: create a regular file in the parent directory <dip> * with name = <from dentry> and mode = <mode> * * PARAMETER: dip - parent directory vnode * dentry - dentry of new file * mode - create mode (rwxrwxrwx). * * RETURN: Errors from subroutines * */ int jfs_create(struct inode *dip, struct dentry *dentry, int mode) { int rc = 0; tid_t tid; /* transaction id */ struct inode *ip = NULL; /* child directory inode */ ino_t ino; struct component_name dname; /* child directory name */ struct btstack btstack; struct inode *iplist[2]; struct tblock *tblk; jFYI(1, ("jfs_create: dip:0x%p name:%s\n", dip, dentry->d_name.name)); /* * search parent directory for entry/freespace * (dtSearch() returns parent directory page pinned) */ if ((rc = get_UCSname(&dname, dentry, JFS_SBI(dip->i_sb)->nls_tab))) goto out1; /* * Either iAlloc() or txBegin() may block. Deadlock can occur if we * block there while holding dtree page, so we allocate the inode & * begin the transaction before we search the directory. */ ip = ialloc(dip, mode); if (ip == NULL) { rc = ENOSPC; goto out2; } tid = txBegin(dip->i_sb, 0); down(&JFS_IP(dip)->commit_sem); down(&JFS_IP(ip)->commit_sem); if ((rc = dtSearch(dip, &dname, &ino, &btstack, JFS_CREATE))) { jERROR(1, ("jfs_create: dtSearch returned %d\n", rc)); goto out3; } tblk = tid_to_tblock(tid); tblk->xflag |= COMMIT_CREATE; tblk->ip = ip; iplist[0] = dip; iplist[1] = ip; /* * initialize the child XAD tree root in-line in inode */ xtInitRoot(tid, ip); /* * create entry in parent directory for child directory * (dtInsert() releases parent directory page) */ ino = ip->i_ino; if ((rc = dtInsert(tid, dip, &dname, &ino, &btstack))) { jERROR(1, ("jfs_create: dtInsert returned %d\n", rc)); if (rc == EIO) txAbort(tid, 1); /* Marks Filesystem dirty */ else txAbort(tid, 0); /* Filesystem full */ goto out3; } ip->i_op = &jfs_file_inode_operations; ip->i_fop = &jfs_file_operations; ip->i_mapping->a_ops = &jfs_aops; insert_inode_hash(ip); mark_inode_dirty(ip); d_instantiate(dentry, ip); dip->i_ctime = dip->i_mtime = CURRENT_TIME; mark_inode_dirty(dip); rc = txCommit(tid, 2, &iplist[0], 0); out3: txEnd(tid); up(&JFS_IP(dip)->commit_sem); up(&JFS_IP(ip)->commit_sem); if (rc) { ip->i_nlink = 0; iput(ip); } out2: free_UCSname(&dname); out1: jFYI(1, ("jfs_create: rc:%d\n", -rc)); return -rc; }
/* * NAME: jfs_unlink(dip, dentry) * * FUNCTION: remove a link to object <vp> named by <name> * from parent directory <dvp> * * PARAMETER: dip - inode of parent directory * dentry - dentry of object to be removed * * RETURN: errors from subroutines * * note: * temporary file: if one or more processes have the file open * when the last link is removed, the link will be removed before * unlink() returns, but the removal of the file contents will be * postponed until all references to the files are closed. * * JFS does NOT support unlink() on directories. * */ int jfs_unlink(struct inode *dip, struct dentry *dentry) { int rc; tid_t tid; /* transaction id */ struct inode *ip = dentry->d_inode; ino_t ino; struct component_name dname; /* object name */ struct inode *iplist[2]; struct tblock *tblk; s64 new_size = 0; int commit_flag; jFYI(1, ("jfs_unlink: dip:0x%p name:%s\n", dip, dentry->d_name.name)); if ((rc = get_UCSname(&dname, dentry, JFS_SBI(dip->i_sb)->nls_tab))) goto out; IWRITE_LOCK(ip); tid = txBegin(dip->i_sb, 0); down(&JFS_IP(dip)->commit_sem); down(&JFS_IP(ip)->commit_sem); iplist[0] = dip; iplist[1] = ip; /* * delete the entry of target file from parent directory */ ino = ip->i_ino; if ((rc = dtDelete(tid, dip, &dname, &ino, JFS_REMOVE))) { jERROR(1, ("jfs_unlink: dtDelete returned %d\n", rc)); if (rc == EIO) txAbort(tid, 1); /* Marks FS Dirty */ txEnd(tid); up(&JFS_IP(dip)->commit_sem); up(&JFS_IP(ip)->commit_sem); IWRITE_UNLOCK(ip); goto out1; } ASSERT(ip->i_nlink); ip->i_ctime = dip->i_ctime = dip->i_mtime = CURRENT_TIME; mark_inode_dirty(dip); /* update target's inode */ ip->i_nlink--; mark_inode_dirty(ip); /* * commit zero link count object */ if (ip->i_nlink == 0) { assert(!test_cflag(COMMIT_Nolink, ip)); /* free block resources */ 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); IWRITE_UNLOCK(ip); rc = -new_size; /* We return -rc */ goto out1; } tblk = tid_to_tblock(tid); tblk->xflag |= COMMIT_DELETE; tblk->ip = ip; } /* * Incomplete truncate of file data can * result in timing problems unless we synchronously commit the * transaction. */ if (new_size) commit_flag = COMMIT_SYNC; else commit_flag = 0; /* * If xtTruncate was incomplete, commit synchronously to avoid * timing complications */ rc = txCommit(tid, 2, &iplist[0], commit_flag); txEnd(tid); up(&JFS_IP(dip)->commit_sem); up(&JFS_IP(ip)->commit_sem); while (new_size && (rc == 0)) { tid = txBegin(dip->i_sb, 0); down(&JFS_IP(ip)->commit_sem); new_size = xtTruncate_pmap(tid, ip, new_size); if (new_size < 0) { txAbort(tid, 1); /* Marks FS Dirty */ rc = -new_size; /* We return -rc */ } else rc = txCommit(tid, 2, &iplist[0], COMMIT_SYNC); txEnd(tid); up(&JFS_IP(ip)->commit_sem); } if (ip->i_nlink == 0) set_cflag(COMMIT_Nolink, ip); if (!test_cflag(COMMIT_Holdlock, ip)) IWRITE_UNLOCK(ip); /* * Truncating the directory index table is not guaranteed. It * may need to be done iteratively */ if (test_cflag(COMMIT_Stale, dip)) { if (dip->i_size > 1) jfs_truncate_nolock(dip, 0); clear_cflag(COMMIT_Stale, dip); } out1: free_UCSname(&dname); out: jFYI(1, ("jfs_unlink: rc:%d\n", -rc)); return -rc; }
/* * NAME: jfs_rmdir(dip, dentry) * * FUNCTION: remove a link to child directory * * PARAMETER: dip - parent inode * dentry - child directory dentry * * RETURN: EINVAL - if name is . or .. * EINVAL - if . or .. exist but are invalid. * 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 * the directory is released (cf.unlink() of regular file). */ int jfs_rmdir(struct inode *dip, struct dentry *dentry) { int rc; tid_t tid; /* transaction id */ struct inode *ip = dentry->d_inode; ino_t ino; struct component_name dname; struct inode *iplist[2]; struct tblock *tblk; jFYI(1, ("jfs_rmdir: dip:0x%p name:%s\n", dip, dentry->d_name.name)); /* directory must be empty to be removed */ if (!dtEmpty(ip)) { rc = ENOTEMPTY; goto out; } if ((rc = get_UCSname(&dname, dentry, JFS_SBI(dip->i_sb)->nls_tab))) { goto out; } tid = txBegin(dip->i_sb, 0); down(&JFS_IP(dip)->commit_sem); down(&JFS_IP(ip)->commit_sem); iplist[0] = dip; iplist[1] = ip; tblk = tid_to_tblock(tid); tblk->xflag |= COMMIT_DELETE; tblk->ip = ip; /* * delete the entry of target directory from parent directory */ ino = ip->i_ino; if ((rc = dtDelete(tid, dip, &dname, &ino, JFS_REMOVE))) { jERROR(1, ("jfs_rmdir: dtDelete returned %d\n", rc)); if (rc == EIO) txAbort(tid, 1); txEnd(tid); up(&JFS_IP(dip)->commit_sem); up(&JFS_IP(ip)->commit_sem); goto out2; } /* 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); /* * OS/2 could have created EA and/or ACL */ /* free EA from both persistent and working map */ if (JFS_IP(ip)->ea.flag & DXD_EXTENT) { /* free EA pages */ txEA(tid, ip, &JFS_IP(ip)->ea, NULL); } JFS_IP(ip)->ea.flag = 0; /* free ACL from both persistent and working map */ if (JFS_IP(ip)->acl.flag & DXD_EXTENT) { /* free ACL pages */ txEA(tid, ip, &JFS_IP(ip)->acl, NULL); } JFS_IP(ip)->acl.flag = 0; /* mark the target directory as deleted */ ip->i_nlink = 0; 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); /* * Truncating the directory index table is not guaranteed. It * may need to be done iteratively */ if (test_cflag(COMMIT_Stale, dip)) { if (dip->i_size > 1) jfs_truncate_nolock(dip, 0); clear_cflag(COMMIT_Stale, dip); } out2: free_UCSname(&dname); out: jFYI(1, ("jfs_rmdir: rc:%d\n", rc)); return -rc; }
/* * NAME: jfs_rename * * FUNCTION: rename a file or directory */ int jfs_rename(struct inode *old_dir, struct dentry *old_dentry, struct inode *new_dir, struct dentry *new_dentry) { struct btstack btstack; ino_t ino; struct component_name new_dname; struct inode *new_ip; struct component_name old_dname; struct inode *old_ip; int rc; tid_t tid; struct tlock *tlck; struct dt_lock *dtlck; struct lv *lv; int ipcount; struct inode *iplist[4]; struct tblock *tblk; s64 new_size = 0; int commit_flag; jFYI(1, ("jfs_rename: %s %s\n", old_dentry->d_name.name, new_dentry->d_name.name)); old_ip = old_dentry->d_inode; new_ip = new_dentry->d_inode; if ((rc = get_UCSname(&old_dname, old_dentry, JFS_SBI(old_dir->i_sb)->nls_tab))) goto out1; if ((rc = get_UCSname(&new_dname, new_dentry, JFS_SBI(old_dir->i_sb)->nls_tab))) goto out2; /* * Make sure source inode number is what we think it is */ rc = dtSearch(old_dir, &old_dname, &ino, &btstack, JFS_LOOKUP); if (rc || (ino != old_ip->i_ino)) { rc = ENOENT; goto out3; } /* * Make sure dest inode number (if any) is what we think it is */ rc = dtSearch(new_dir, &new_dname, &ino, &btstack, JFS_LOOKUP); if (rc == 0) { if ((new_ip == 0) || (ino != new_ip->i_ino)) { rc = ESTALE; goto out3; } } else if (rc != ENOENT) goto out3; else if (new_ip) { /* no entry exists, but one was expected */ rc = ESTALE; goto out3; } if (S_ISDIR(old_ip->i_mode)) { if (new_ip) { if (!dtEmpty(new_ip)) { rc = ENOTEMPTY; goto out3; } } else if ((new_dir != old_dir) && (new_dir->i_nlink == JFS_LINK_MAX)) { rc = EMLINK; goto out3; } } else if (new_ip) IWRITE_LOCK(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); if (old_dir != new_dir) down(&JFS_IP(old_dir)->commit_sem); if (new_ip) { down(&JFS_IP(new_ip)->commit_sem); /* * Change existing directory entry to new inode number */ ino = new_ip->i_ino; rc = dtModify(tid, new_dir, &new_dname, &ino, old_ip->i_ino, JFS_RENAME); if (rc) goto out4; new_ip->i_nlink--; if (S_ISDIR(new_ip->i_mode)) { new_ip->i_nlink--; assert(new_ip->i_nlink == 0); tblk = tid_to_tblock(tid); tblk->xflag |= COMMIT_DELETE; tblk->ip = new_ip; } else if (new_ip->i_nlink == 0) { assert(!test_cflag(COMMIT_Nolink, new_ip)); /* free block resources */ if ((new_size = commitZeroLink(tid, new_ip)) < 0) { txAbort(tid, 1); /* Marks FS Dirty */ rc = -new_size; /* We return -rc */ goto out4; } tblk = tid_to_tblock(tid); tblk->xflag |= COMMIT_DELETE; tblk->ip = new_ip; } else { new_ip->i_ctime = CURRENT_TIME; mark_inode_dirty(new_ip); } } else { /* * Add new directory entry */ rc = dtSearch(new_dir, &new_dname, &ino, &btstack, JFS_CREATE); if (rc) { jERROR(1, ("jfs_rename didn't expect dtSearch to fail w/rc = %d\n", rc)); goto out4; } ino = old_ip->i_ino; rc = dtInsert(tid, new_dir, &new_dname, &ino, &btstack); if (rc) { jERROR(1, ("jfs_rename: dtInsert failed w/rc = %d\n", rc)); goto out4; } if (S_ISDIR(old_ip->i_mode)) new_dir->i_nlink++; } /* * Remove old directory entry */ ino = old_ip->i_ino; rc = dtDelete(tid, old_dir, &old_dname, &ino, JFS_REMOVE); if (rc) { jERROR(1, ("jfs_rename did not expect dtDelete to return rc = %d\n", rc)); txAbort(tid, 1); /* Marks Filesystem dirty */ goto out4; } if (S_ISDIR(old_ip->i_mode)) { old_dir->i_nlink--; if (old_dir != new_dir) { /* * Change inode number of parent for moved directory */ JFS_IP(old_ip)->i_dtroot.header.idotdot = cpu_to_le32(new_dir->i_ino); /* Linelock header of dtree */ tlck = txLock(tid, old_ip, (struct metapage *) &JFS_IP(old_ip)->bxflag, tlckDTREE | tlckBTROOT); dtlck = (struct dt_lock *) & tlck->lock; ASSERT(dtlck->index == 0); lv = & dtlck->lv[0]; lv->offset = 0; lv->length = 1; dtlck->index++; } } /* * Update ctime on changed/moved inodes & mark dirty */ old_ip->i_ctime = CURRENT_TIME; mark_inode_dirty(old_ip); new_dir->i_ctime = CURRENT_TIME; mark_inode_dirty(new_dir); /* Build list of inodes modified by this transaction */ ipcount = 0; iplist[ipcount++] = old_ip; if (new_ip) iplist[ipcount++] = new_ip; iplist[ipcount++] = old_dir; if (old_dir != new_dir) { iplist[ipcount++] = new_dir; old_dir->i_ctime = CURRENT_TIME; mark_inode_dirty(old_dir); } /* * Incomplete truncate of file data can * result in timing problems unless we synchronously commit the * transaction. */ if (new_size) commit_flag = COMMIT_SYNC; else commit_flag = 0; rc = txCommit(tid, ipcount, iplist, commit_flag); /* * Don't unlock new_ip if COMMIT_HOLDLOCK is set */ if (new_ip && test_cflag(COMMIT_Holdlock, new_ip)) { up(&JFS_IP(new_ip)->commit_sem); new_ip = 0; } 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); while (new_size && (rc == 0)) { tid = txBegin(new_ip->i_sb, 0); down(&JFS_IP(new_ip)->commit_sem); new_size = xtTruncate_pmap(tid, new_ip, new_size); if (new_size < 0) { txAbort(tid, 1); rc = -new_size; /* We return -rc */ } else rc = txCommit(tid, 1, &new_ip, COMMIT_SYNC); txEnd(tid); up(&JFS_IP(new_ip)->commit_sem); } if (new_ip && (new_ip->i_nlink == 0)) set_cflag(COMMIT_Nolink, new_ip); out3: free_UCSname(&new_dname); out2: free_UCSname(&old_dname); out1: if (new_ip && !S_ISDIR(new_ip->i_mode)) IWRITE_UNLOCK(new_ip); /* * Truncating the directory index table is not guaranteed. It * may need to be done iteratively */ if (test_cflag(COMMIT_Stale, old_dir)) { if (old_dir->i_size > 1) jfs_truncate_nolock(old_dir, 0); clear_cflag(COMMIT_Stale, old_dir); } jFYI(1, ("jfs_rename: returning %d\n", rc)); return -rc; }