/* * NAME: jfs_lookup(dvp, vpp, pname, flag, vattrp, crp) * * FUNCTION: resolve <pname> in directory <dvp> to vnode <vpp> * with a reference acquired and attribute <vattrp>. * * PARAMETERS: dvp _ directory vnode * vpp - object vnode (out) * pname - object name * flag - * vattrp - object attribute (out) * crp - credential * * RETURN: errors from subroutines. */ jfs_lookup( struct vnode *dvp, struct vnode **vpp, UniChar *pname, /* NULL terminated */ int32 flag, struct vattr *vattrp, struct ucred *crp) { int32 rc = 0; struct vfs *vfsp = dvp->v_vfsp; inode_t *dip = VP2IP(dvp); /* parent directory inode */ ino_t ino; /* object i_number */ inode_t *ip; /* object inode */ component_t dname; /* object name */ ncookie_t ncookie; btstack_t btstack; NOISE(1,("jfs_lookup: dip:0x%08x name:%s\n", dip, pname)); *vpp = NULL; /* <dvp> must be a directory */ if ((dip->i_mode & IFMT) != IFDIR) return ENOTDIR; IREAD_LOCK(dip); if (dip->i_nlink == 0) { rc = ENOENT; goto out; } /* * resolve name to i_number via dnlc/directory lookup */ getInumber: /* * for "." or "..", lookup directory inode */ if (pname[0] == '.') { /* looking up ".." */ if (pname[1] == '.' && pname[2] == '\0') { ino = dip->i_parent; goto getInode; } /* looking up "." */ else if (pname[1] == '\0') { ip = dip; jfs_hold(dvp); *vpp = dvp; goto getAttribute; } } /* * search dnlc/directory */ dname.name = pname; dname.namlen = UniStrlen(pname); if ((ino = ncLookup(dip->i_ipimap, dip->i_number, &dname, &ncookie)) == 0) { /* * dnlc miss: search directory */ if (rc = dtSearch(dip, &dname, &ino, &btstack, JFS_LOOKUP)) goto out; /* insert name entry to dnlc */ ncEnter(dip->i_ipimap, dip->i_number, &dname, ino, &ncookie); } /* * resolve i_number to inode/vnode with a reference */ getInode: ICACHE_LOCK(); rc = iget(vfsp, ino, &ip, 0); ICACHE_UNLOCK(); if (rc) goto out; *vpp = IP2VP(ip); /* * get attribute */ getAttribute: if (vattrp != NULL) get_vattr(ip, vattrp); out: IREAD_UNLOCK(dip); NOISE(1,("jfs_lookup: rc:%d\n", rc)); return rc; }
/* * NAME: jfs_mknod(dvp, name, mode, dev, crp) * * FUNCTION: make a new object in directory <dvp> with mode = <mode>, * name = <pname>, and rdev = <dev>. * * PARAMETER: dvp - directory vnode * name - name of new object * mode - create mode (rwxrwxrwx). * dev - new device number if block/character-special file * crp - credential * * RETURN: Errors from subroutines * * note: JFS allows mknod() to create a special file. * XPG4.2: the only portable use of mknod() is to create a FIFO-special file * with mode = S_IFIFO and dev = 0. */ jfs_mknod( struct vnode *dvp, caddr_t name, mode_t mode, dev_t dev, struct ucred *crp) { int32 rc; int32 tid; inode_t *dip = VP2IP(dvp); inode_t *ip; ino_t ino; component_t dname; struct vfs *vfsp = dvp->v_vfsp; btstack_t btstack; inode_t *iplist[2]; /* JFS does NOT support mknod() of directory */ if ((mode & IFMT) == IFDIR) return EISDIR; if ((mode & IFMT) != IFIFO && (mode & IFMT) != IFSOCK) if (rc = privcheck_cr(DEV_CONFIG, crp)) return rc; IWRITE_LOCK(dip); txBegin(dip->i_ipmnt, &tid, 0); /* validate search+write permission on parent directory */ if (rc = iAccess(dip, IEXEC|IWRITE, crp)) goto out1; /* * scan parent directory for entry/freespace * (dtSearch() returns parent directory page pinned) */ dname.name = name; dname.namlen = strlen(name); if (rc = dtSearch(dip, &dname, &ino, &btstack, JFS_CREATE)) goto out1; /* * allocate in-memory+on-disk inode: * (iAlloc() returns new, locked inode) */ if (rc = iAlloc(vfsp, dip, mode, &ip, crp)) { /* release parent directory page */ BT_PUTSEARCH(&btstack); goto out1; } /* * create entry in parent directory * (dtInsert() releases parent directory page) */ ino = ip->i_number; if (rc = dtInsert(tid, dip, &dname, &ino, &btstack)) { /* discard the new inode */ ip->i_nlink = 0; goto out2; } /* * fo a block or character special file, the passed-in device number * needs to be set into the inode's device field and the gnode's * "real device" field. */ if ((ip->i_mode & IFMT) == IFBLK || (ip->i_mode & IFMT) == IFCHR) { ip->i_rdev = dev; IP2GP(ip)->gn_rdev = dev; } imark(ip, IACC|ICHG|IUPD|IFSYNC); /* update parent directory inode */ imark(dip, ICHG|IUPD|IFSYNC); /* * insert entry for the new file to dnlc */ ncEnter(dip->i_ipimap, dip->i_number, &dname, ino, NULL); iplist[0] = dip; iplist[1] = ip; rc = txCommit(tid, 2, &iplist[0], 0); out2: IWRITE_UNLOCK(ip); ICACHE_LOCK(); iput(ip, vfsp); ICACHE_UNLOCK(); out1: IWRITE_UNLOCK(dip); txEnd(tid); return rc; }
/* * NAME: dirlookup * * FUNCTION: Resolve <path> to vnode <vpp> * with a reference acquired. * The last component of the path is not looked up. * * PARAMETERS: vfsp - file system anchor * path - full path name * last - last component of path name (out) * vpp - where to put the new vnode (out) * crp - credential * * RETURN: errors from subroutines. */ int32 dirlookup( struct vfs * vfsp, pathlook_t * plp, struct ucred * crp) { int32 rc = 0; struct vnode * dvp; struct vnode * vp; UniChar * compn; UniChar * compp = NULL; uint32 complen; UniChar *component; struct dasd_usage *du = &plp->dlim; // F226941 inode_t *ip; // F226941 /* * F226941 - Only accumulate dasd info if limits enabled & operation * may affect dasd usage */ if (((vfsp->vfs_flag & VFS_DASDLIM) == 0) || (du->flag & DLIM_READONLY)) du = 0; component = (UniChar *)allocpool(unipool, 0); /* get the root vnode as the starting directory. */ vp = vfsp->vfs_mntd; jfs_hold(vp); /* Address the beginning of the path, skipping over <d>:. * Note that the path has been put into canonical form * by the IFSM; that is, it has no extraneous backslashes, * and . and .. references have been removed. */ compn = UniStrchr(plp->path, '\\'); /* for each component of the path up to the last: * parse the component name out of the path string, * pass it to jfs_lookup to get a vnode for it. */ for(;;) { // BEGIN F226941 if (du) { DLIM_add(du, VP2IP(vp), rc) if (rc) { jfs_rele(vp); break; } } // END F226941 /* find end of component; if last component * then UniStrchr will return NULL. */ compp = compn + 1; compn = UniStrchr(compp, '\\'); /* end loop when we reach the last component */ if (compn == NULL) break; /* copy the string to the component buffer. */ complen = compn - compp; UniStrncpy(component, compp, complen); component[complen] = '\0'; /* promote current vnode to directory vnode. */ dvp = vp; /* call lookup to get a vnode for the component. */ rc = jfs_lookup(dvp, &vp, component, 0, NULL, crp); /* release hold on the directory */ if (du == 0) // F226941 jfs_rele(dvp); if (rc != 0) { if (rc == ENOENT) rc = ENOTDIR; break; } } /* set the output pointers and return */ plp->pathlast = compp; plp->dvp = vp; freepool (unipool, (caddr_t *)component); return rc; }
/* * 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: jfs_rename * * FUNCTION: rename a file or directory * * PARAMETER: from_vp - pointer to source vnode * frompar_vp - pointer to source parent vnode * from_name - original name * to_vp - pointer to target vnode (if it exists) * topar_vp - pointer to target parent vnode * to_name - new name * crp - pointer to caller's credentials * * RETURN: errors from subroutines * * JFS supports sticky bit permission. * * normally, to rename an object, user needs execute and write * permission of the directory containing the object as well as * on the target directory. * EACCESS: if S_ISVTX (aka sticky) bit is set for a directory, * a file in the directory can be renamed only if * the user has write permission for the directory, and * either owns the file, owns the directory, or * is the superuser (or have appropriate privileges). * (e.g., /tmp in which any user can create a file but * should not be able to delete or rename files owned * by others) [XPG4.2] * * Basic algorithm is: * * 1) Check validity of parameters and then obtain locks on the source parent * directory, destination parent directory, source, and the destination * inode. This ensures neither the source or destination will be deleted out * from underneath us. It also ensures the source or destination won't be * modified before we finish. * 2) Link source to destination. If destination already exists, * delete it first. * 3) Unlink source reference to inode if still around. If a * directory was moved and the parent of the destination * is different from the source, patch the ".." entry in the * directory. * * The transaction log needs to have the changes journalled in such a * way that a crash meets the requirement that the destination always * exists (if it existed before). For directory objects it is critical * that the changes in i-numbers occur in such a way that loops and * orphans aren't created by a crash. */ int32 jfs_rename( struct vnode *from_vp, /* source vnode */ struct vnode *frompar_vp, /* source parent vnode */ UniChar *from_name, /* source name */ struct vnode *to_vp, /* destination vnode */ struct vnode *topar_vp, /* destination parent vnode */ UniChar *to_name, /* destination name */ struct dasd_usage *from_dlim, /* dasd usage structure for source F226941 */ struct dasd_usage *to_dlim, /* dasd usage structure for dest F226941 */ uint32 flags) /* INEWNAME if new pathname not 8.3 */ { inode_t *ipmnt; int32 tid = -1; /* Transaction ID */ int32 txCount = 0; /* Count of inodes in txList */ inode_t *txList[4]; /* List of modified inodes */ inode_t *from_ip = VP2IP (from_vp); /* Source inode */ inode_t *frompar_ip = VP2IP (frompar_vp); /* Source parent inode */ inode_t *to_ip = to_vp ? VP2IP (to_vp) : 0; /* Target inode (if it exists) */ inode_t *topar_ip = VP2IP (topar_vp); /* Target parent inode */ struct vfs *vfsf = frompar_vp->v_vfsp; struct vfs *vfst = topar_vp->v_vfsp; int32 doingdirectory = 0, /* Source inode is a directory */ newparent = 0; /* New i-number of parent */ int32 got_from = 0, got_to = 0; btstack_t btstack; /* Temporary stack for B-tree struct */ component_t dname; /* Directory name structure */ ino_t ino; /* I-number for directory searches */ int32 error = 0, rc; tlock_t *tlck; /* Transaction lock */ dtlock_t *dtlck; /* dtree line lock */ lv_t *lv; /* line lock vector */ // BEGIN F226941 #ifdef _JFS_OS2 int64 blocks_moving; /* Number of blocks being moved */ int64 orig_fromblocks; /* original dasd usage of from dir */ int64 orig_toblocks; /* original dasd usage of to dir */ uint32 start_here; /* index in limits array */ int32 i; inode_t *lock_arr[64]; /* Array of inodes to lock */ inode_t **lock_list; /* List of inodes to lock */ int32 num_locks; /* Number of inodes to lock */ int32 upper_limit; /* Upper limit to number of inodes * we need to lock */ #ifdef _JFS_FASTDASD int32 first_locked; /* index in lock_list array of first * inode still locked. D233382 */ #endif /* _JFS_FASTDASD */ #endif /* _JFS_OS2 */ // BEGIN F226941 assert( to_name != NULL && from_name != NULL); ipmnt = frompar_ip->i_ipmnt; RENAME_LOCK(ipmnt); /* * Make sure that we are not renaming the "." or ".." entries in * a directory. */ if (from_name[0] == '.' && (!from_name[1] || (from_name[1] == '.' && !from_name[2]))) { error = EINVAL; goto abortit; } /* * Now we want to verify the proper realationship between the inodes. * If everything checks out we need to obtain locks on the source parent * directory, destination parent directory, source, and destination * inodes. This allows us to proceed knowing that noone can delete * either the source or destination from underneath us. It also allows * us to know noone will be modifying the destination so we can delete * it safely. We need the lock on the source since we might need to * modify its .. entry. */ /* * In OS/2, the destination cannot exist unless it is the same as * the source. This is to allow DosMove to change the case of a * filename. */ if (to_ip && (from_ip != to_ip)) { error = EINVAL; goto abortit; } /* * Check for cross-device rename. */ if (frompar_ip->i_dev != topar_ip->i_dev) { error = EXDEV; goto abortit; } /* * Check if source is the destination parent. Can't do this * since this would orphan everything under the source. */ if (from_ip == topar_ip) { error = EINVAL; goto abortit; } /* * Now we know both the parents are okay. We will lock both the * parent inodes so we can guarantee the children will not be * deleted underneath us. We will also lock the source. * When locking the inodes we will use the protocol of locking * regular files first, then directories. When locking more than * one of each type, we do it in descending inode order. We also need * to make sure we don't attempt to lock one inode twice if the * two parents are the same. */ if ((from_ip->i_mode & IFMT) == IFDIR) doingdirectory = 1; // BEGIN F226941 if (from_dlim->num_limits) { /* We need to lock all directories from the root to each of * the from and to parent directories. The DASD usage lists * will contain at least one common entry (the root). We need * to compile a list of all unique inodes to lock. The upper * limit will be the sum of both num_limits fields. */ if (frompar_ip == topar_ip) upper_limit = from_dlim->num_limits + 1; else upper_limit = from_dlim->num_limits + to_dlim->num_limits; if (upper_limit > 64) lock_list = (inode_t **) xmalloc(upper_limit* sizeof(inode_t *), 0, kernel_heap); else lock_list = lock_arr; /* Put from parents dasd usage list into lock_list */ for (num_locks = 0; num_locks < from_dlim->num_limits; num_locks++) lock_list[num_locks] = from_dlim->pLimits[num_locks]; /* * We need to lock regular files before directories. If * we are moving a regular file, lock it now, otherwise add * it to the lock list. */ if (doingdirectory) lock_list[num_locks++] = from_ip; else IWRITE_LOCK(from_ip); if (frompar_ip != topar_ip) { /* Add unique members of to parent's dasd usage list */ for (i = 0; i < to_dlim->num_limits; i++) if (to_dlim->pLimits[i] != lock_list[i]) break; start_here = i; /* Needed by over_limit() */ while (i < to_dlim->num_limits) lock_list[num_locks++] = to_dlim->pLimits[i++]; } /* Lock them! */ sort_and_lock(0, num_locks, lock_list); /* * If this was a regular file, add the inode to the lock list * now, so we include it in the txCommit, and unlock it */ if (!doingdirectory) lock_list[num_locks++] = from_ip; from_dlim->flag |= DLIM_DIRS_LOCKED; frompar_ip->i_dasdlim = from_dlim; if (frompar_ip != topar_ip) // D230860 { to_dlim->flag |= DLIM_DIRS_LOCKED; topar_ip->i_dasdlim = to_dlim; } } else // END F226941 { if (doingdirectory) { if (frompar_ip == topar_ip) iwritelocklist(2, frompar_ip, from_ip); else iwritelocklist(3, frompar_ip, topar_ip, from_ip); } else { if (frompar_ip == topar_ip) { IWRITE_LOCK(from_ip); IWRITE_LOCK(frompar_ip); } else { IWRITE_LOCK(from_ip); iwritelocklist(2, frompar_ip, topar_ip); } } } /* * Now that we have the source parent locked we can lookup the * source inode to make sure it hasn't changed since we did our * initial verification. If it has we will need to release our * locks and repeat our verification with the new version. * Otherwise we know the source is valid and we can continue. */ dname.name = from_name; dname.namlen = UniStrlen (from_name); rc = dtSearch(frompar_ip, &dname, &ino, &btstack, JFS_LOOKUP); switch (rc) { case 0: /* * An entry was found, need to see if it is the * same inode as we had before. */ if (ino != from_ip->i_number) { rc = ENOENT; goto cleanup; } break; default: /* * Either the source cannot be found or * something went wrong in the search */ error = rc; goto cleanup; } /* * If changing case, no need to search for destination inode */ if (!to_ip) { /* * Now we can lookup the destination inode to make sure it * hasn't been created since we did our verifications. If it * has we abort. */ dname.name = to_name; dname.namlen = UniStrlen (to_name); if (dname.namlen > JFS_NAME_MAX-1) { error = ERROR_FILENAME_EXCED_RANGE; goto cleanup; } rc = dtSearch(topar_ip, &dname, &ino, &btstack, JFS_LOOKUP); switch (rc) { case 0: /* * We found an entry; fail with EEXIST */ rc = EEXIST; goto cleanup; case ENOENT: break; default: /* * Some error from dtSearch(). cleanup and * return */ error = rc; goto cleanup; } } /* * Now we need to validate parameters and check for proper inodes */ /* * Make sure the source inode has a positive link count */ if (from_ip->i_nlink <= 0) { error = EINVAL; goto cleanup; } if ((topar_ip->i_mode & IFMT) != IFDIR) { error = EINVAL; goto cleanup; } /* Check for the appropriate permissions on the source */ if (doingdirectory && (frompar_ip->i_number != topar_ip->i_number)) { /* * Account for ".." in new directory. When source and * destination have the same parent we don't fool with the link * count. */ if ((nlink_t)topar_ip->i_nlink >= LINK_MAX) { error = EMLINK; goto cleanup; } /* * If ".." must be changed (i.e. the directory gets a new * parent) then the source directory must not be in the * directory hierarchy above the target, as this would orphan * everything below the source directory. */ newparent = topar_ip->i_number; /* RENAME_LOCK(topar_ip->i_ipmnt); */ if (error = jfs_checkpath(from_ip, frompar_ip, topar_ip, vfst)) goto cleanup; } /* * Check for write-protected media */ if (isReadOnly(topar_ip)) { error = EROFS; goto cleanup; } // BEGIN F226941 /* * Check to see if there is room in the destination directory */ blocks_moving = doingdirectory ? DASDUSED(&from_ip->i_DASD) : from_ip->i_nblocks; if ((topar_ip != frompar_ip) && (topar_ip->i_dasdlim) && over_limit(topar_ip->i_dasdlim, blocks_moving, start_here)) { error = ERROR_DISK_FULL; goto cleanup; } orig_fromblocks = frompar_ip->i_nblocks; if (topar_ip != frompar_ip) orig_toblocks = topar_ip->i_nblocks; // END F226941 /* * Perform rename */ txBegin(topar_ip->i_ipmnt, &tid, 0); dname.name = to_name; dname.namlen = UniStrlen (to_name); if (to_ip != NULL) { /* * We change the case of the name in place. */ ino = to_ip->i_number; if (error = dtChangeCase(tid, frompar_ip, &dname, &ino, JFS_RENAME)) goto cleanup; imark(topar_ip, ICHG|IUPD|IFSYNC); } else { /* * We already know the destination does not exist, so link * source inode as destination. */ if (error = dtSearch(topar_ip, &dname, &ino, &btstack, JFS_CREATE)) { /* * Problem, can't find where to put this guy, or it * already exists!! */ goto cleanup; } ino = from_ip->i_number; if (error = dtInsert(tid, topar_ip, &dname, &ino, &btstack)) { /* * Failed adding source to destination parent */ goto cleanup; } imark(topar_ip, ICHG|IUPD|IFSYNC); /* Insert entry for the new file to name cache */ ncEnter(topar_ip->i_ipimap, topar_ip->i_number, &dname, from_ip->i_number, NULL); /* Remove source name from source parent and name cache */ dname.name = from_name; dname.namlen = UniStrlen (from_name); ino = from_ip->i_number; ncDelete(frompar_ip->i_ipimap, frompar_ip->i_number, &dname); if (error = dtDelete(tid, frompar_ip, &dname, &ino, JFS_REMOVE)) { /* * Another unexpected error -- the original file does not * appear to exist ... */ assert(0); } imark(frompar_ip, ICHG|IUPD|IFSYNC); /* * If this is a directory we need to update the ".." i-number * in the inode. Also, there is now one fewer ".." referencing * the source parent directory. Decrement the link count to * the source parent directory for this. */ if (doingdirectory && newparent) { /* linelock header of dtree root (containing idotdot) */ tlck = txLock(tid, from_ip, (jbuf_t *)&from_ip->i_bxflag, tlckDTREE|tlckBTROOT); dtlck = (dtlock_t *)&tlck->lock; ASSERT(dtlck->index == 0); lv = (lv_t *)&dtlck->lv[0]; lv->offset = 0; lv->length = 1; dtlck->index++; ((dtroot_t *) &from_ip->i_btroot)->header.idotdot = newparent; frompar_ip->i_nlink--; topar_ip->i_nlink++; /* RENAME_UNLOCK(topar_ip->i_ipmnt); */ } /* Set or reset INEWNAME flag as appropriate */ from_ip->i_mode = (from_ip->i_mode & ~INEWNAME) | (flags & INEWNAME); imark(from_ip, ICHG|IFSYNC); // D231252 txList[txCount++] = from_ip; // D231252 } // BEGIN F226941 /* * Modify dasd usage for source and destination directories. * Number of blocks for object being moved didn't change. */ if (frompar_ip == topar_ip) { DLIM_UPDATE(tid, frompar_ip, frompar_ip->i_nblocks - orig_fromblocks); } else { DLIM_UPDATE(tid, topar_ip, topar_ip->i_nblocks + blocks_moving - orig_toblocks); DLIM_UPDATE(tid, frompar_ip, frompar_ip->i_nblocks - (orig_fromblocks + blocks_moving)); } // BEGIN D233382 #ifdef _JFS_FASTDASD if (from_dlim->num_limits) { /* * Let's remove any ancestor directories at the beginning of * the lock list that aren't directly involved in the rename. * i_dasdlim will be non-zero for frompar_ip & topar_ip */ for(i = 0; i < num_locks; i++) { if (lock_list[i]->i_dasdlim) { first_locked = i; break; } IWRITE_UNLOCK(lock_list[i]); } ASSERT(i < num_locks); // We shouldn't have unlocked them all. } #endif /* _JFS_FASTDASD */ // END D233382 #ifndef _JFS_FASTDASD // D233382 if ((from_dlim->flag & DLIM_LOGGED) || (to_dlim->flag & DLIM_LOGGED)) { error = txCommit(tid, num_locks, lock_list, 0); from_dlim->flag &= ~DLIM_LOGGED; to_dlim->flag &= ~DLIM_LOGGED; } else #endif /* _JFS_FASTDASD */ // D233382 // END F226941 { if (frompar_ip != topar_ip) { /* * Different parent, so we need to add the other parent * to our transaction list */ txList[txCount++] = topar_ip; } /* Add source parent directory to transaction list */ txList[txCount++] = frompar_ip; assert(txCount <= 4); error = txCommit(tid, txCount, txList, 0); } cleanup: /* * Come to this label when all locks have been taken and ready to leave. * error should be set to return value. */ if (tid != -1) txEnd(tid); // BEGIN F226941 if (from_dlim->num_limits) { frompar_ip->i_dasdlim->flag &= ~DLIM_DIRS_LOCKED; frompar_ip->i_dasdlim = 0; if (frompar_ip != topar_ip) { topar_ip->i_dasdlim->flag &= ~DLIM_DIRS_LOCKED; topar_ip->i_dasdlim = 0; } #ifdef _JFS_FASTDASD for(i = first_locked; i < num_locks; i++) // D233382 #else for(i = 0; i < num_locks; i++) #endif IWRITE_UNLOCK(lock_list[i]); if (lock_list != lock_arr) xmfree((void *)lock_list, kernel_heap); } else // END F226941 { IWRITE_UNLOCK(from_ip); IWRITE_UNLOCK(frompar_ip); if (frompar_ip != topar_ip) { IWRITE_UNLOCK(topar_ip); } } abortit: /* * Come to this label when none of the locks have been taken and ready * to leave. error should be set to return value. */ if (to_ip && got_to) { ICACHE_LOCK(); iput(to_ip, vfst); ICACHE_UNLOCK(); } if (got_from) { ICACHE_LOCK(); iput(from_ip, vfsf); ICACHE_UNLOCK(); } RENAME_UNLOCK(ipmnt); return error; }
/* * NAME: pathlookup * * FUNCTION: resolve <path> to vnode <vpp> * with a reference acquired. * * PARAMETERS: vfsp - pointer to vfs * plp - path lookup structure * crp - credential * * RETURN: errors from subroutines. * -1 for a create when last component does not exist */ pathlookup( struct vfs * vfsp, pathlook_t * plp, struct ucred * crp) { int rc = 0; struct vnode * vp = NULL; /* map the volume handle to a vfs structure. */ if (vfsp == NULL) return ENOTDIR; /* probably should panic */ if (vfsp->vfs_flag & VFS_ACCEPT) return ENOTDIR; /* We're not really mounted */ /* Get the vnode for the last directory in the path. */ rc = dirlookup(vfsp, plp, crp); if (rc) return rc; /* special handling for last component of name. */ /* if the last component is null, then we are looking at * the root. */ if (*plp->pathlast == '\0') { /* add a hold to the directory vnode so that it * can be released twice by the caller. */ vp = plp->dvp; jfs_hold(vp); plp->statlast = PL_ISDIR; } else { /* if there is a wild card in the last component, then * set status accordingly. Otherwise, call lookup to see * if the name exists and get a vnode. */ /* This could be done more efficiently */ if (UniStrchr(plp->pathlast, '*') || UniStrchr(plp->pathlast, '?')) { plp->statlast = PL_WCARD; rc = 0; } else { rc = jfs_lookup(plp->dvp, &vp, plp->pathlast, 0, NULL, crp); /* set the status of the last component. */ switch (rc) { case(0): if ((VP2IP(vp)->i_mode & IFMT) == IFDIR) plp->statlast = PL_ISDIR; else plp->statlast = PL_EXIST; break; case(ENOENT): plp->statlast = PL_NOENT; rc = 0; break; default: /* general lookup failure; * release the vnodes and report an error */ if (plp->dlim.num_limits == 0) // F226941 jfs_rele(plp->dvp); break; } } } /* set the output pointers and return. */ plp->vp = vp; return rc; }
/* * NAME: readdir * * FUNCTION: read directory according to specifications * in directory search structure * * PARAMETER: * * RETURN: EINVAL - if not a directory * errors from subroutines * * note: * N.B. directory file offset encodes (directory page number, * entry index number), and shold NOT be interpreted/modified * by caller (lseek()) except that intial offset set to 0. * * no guarantees can be made that the exact offset * requested can be found if directory has been updated * by other threads between consecutive readdir()s. * transfer length of zero signals start offset beyond eof. * * unused space in the directory are not returned to the user, * i.e., more than requested size may have to be read * from directory to fill the user's buffer. */ readdir( struct vnode *dvp, /* inode of directory being read */ struct fsfd *fsfp, /* directory search information */ char *ubuf, /* user's data area */ uint32 ubytes, /* size of user's data area */ uint32 *matchcnt, /* count of entries returned */ uint32 level, /* level of output struct */ uint32 flags, /* offsets needed in output? */ EAOP *eaopp, /* pointer to EAOP */ struct ucred *crp) { int32 rc = 0; int32 ReturnCode = NO_ERROR; inode_t *dip; /* directory inode */ inode_t *ip; /* object inode */ uint32 matches; /* output matches found */ uint32 dtmatches; /* matches found per dtFind call */ uint32 position; /* offsets in output */ uint32 count; /* output buffer count */ int32 tbytes; /* byte count in dirent buffer */ struct dirent *dbuf; /* dirent buffer */ struct dirent *dbufp; /* dirent buffer */ uint32 ffhdsize; /* size of ffbuf header */ component_t lastmatch; /* pointer to last matching entry */ char *ffbuf; /* output buffer pointer */ char *nxbuf; /* output buffer pointer */ char *bufp; /* output buffer pointer */ MMPHPrereaddir(); /* MMPH Performance Hook */ /* set state from search structure */ dip = VP2IP(dvp); position = flags & FF_GETPOS; /* validate request */ if (ubytes == 0) { rc = EINVAL; goto readdir_Exit; } /* continuous read of empty directory ? */ if (fsfp->fsd_offset == -1) { rc = ERROR_NO_MORE_FILES; goto readdir_Exit; } dbuf = (struct dirent *)allocpool(dirent_pool, 0); // D228565 if (dbuf == 0) // D228565 { rc = ENOMEM; goto readdir_Exit; } /* set up variable to manipulate output buffer pointers * based on level. */ if (level == 1) ffhdsize = FFBUFHD; else if (level == 11) ffhdsize = FFBUFHD3L; else if (level < 11) ffhdsize = FFBUFHD2; else ffhdsize = FFBUFHD4L; if (position) ffhdsize += sizeof(uint32); ffbuf = ubuf; count = 0; matches = *matchcnt; *matchcnt = 0; while ((*matchcnt < matches) && (rc == 0)) { IREAD_LOCK(dip); /* directory became void when last link was removed */ if ((dip->i_nlink == 0) || ((dip->i_mode & IFMT) != IFDIR)) { IREAD_UNLOCK(dip); freepool(dirent_pool, (caddr_t *)dbuf); rc = ENOTDIR; goto readdir_Exit; } /* fill a directory buffer. * read on-disk structure (struct ldtentry_t) and * translate into readdir() structure (struct dirent). */ tbytes = 0; dtmatches = matches - *matchcnt; dbufp = dbuf; // D228565 rc = dtFind(dip, &fsfp->fsd_pattern, fsfp->fsd_lastmatch, &fsfp->fsd_offset, &dtmatches, PSIZE, &tbytes, dbufp); IREAD_UNLOCK(dip); if (rc) { freepool(dirent_pool, (caddr_t *)dbuf); goto readdir_Exit; } /* copy translate buffer to user FileFindBuf buffer */ while ((*matchcnt < matches) && (ReturnCode == NO_ERROR)) { uint32 namlen; /* translation buffer empty? */ if (tbytes == 0) break; /* get size of next name */ namlen = dbufp->d_namlen; /* user buffer full? * the +1 here is to allow for the null character * terminating the name string. */ if ((count + ffhdsize + namlen + 1) > ubytes) { rc = ERROR_BUFFER_OVERFLOW; break; } /* get the inode for the file */ ICACHE_LOCK(); rc = iget(dvp->v_vfsp, dbufp->d_ino, &ip, 0); ICACHE_UNLOCK(); if (rc) goto try_next; nxbuf = ffbuf; /* fill in file search info for files that have * the proper attributes; ignore others. */ rc = get_fileinfo(ip, &nxbuf, ubytes, dbufp->d_name, namlen, fsfp->fsd_havattr, level, eaopp, flags); if ((rc == ERROR_BUFFER_OVERFLOW) && (*matchcnt == 0) && ((level == FIL_QUERYEASFROMLIST) || (level == FIL_QUERYEASFROMLISTL))) { /* Can't fit EA in buffer, try without * getting EA */ if (level == FIL_QUERYEASFROMLIST) level = FIL_QUERYEASIZE; else level = FIL_QUERYEASIZEL; ReturnCode = ERROR_EAS_DIDNT_FIT; rc = get_fileinfo(ip, &nxbuf, ubytes, dbufp->d_name, namlen, fsfp->fsd_havattr, level, eaopp, flags); } /* release the inode */ jfs_rele(IP2VP(ip)); if (rc == 0) { /* set offset if requested */ if (position) { rc = KernCopyOut(ffbuf, &dbufp->d_offset, sizeof(int32)); if (rc) { /* This is very unlikely to * happen! */ ASSERT(0); break; } } /* update output buffer count */ count += nxbuf - ffbuf; /* move to next entry in output buffer */ ffbuf = nxbuf; /* update match count */ *matchcnt += 1; } else if (rc != -1) break; try_next: /* rc == -1 indicates no attribute match, * just keep going. */ rc = 0; /* save name for next call setup */ lastmatch.name = dbufp->d_name; lastmatch.namlen = namlen; /* update dirent buffer count */ tbytes -= dbufp->d_reclen; /* move to next entry in dirent buffer */ dbufp = (struct dirent *) ((caddr_t)dbufp + dbufp->d_reclen); } /* We don't want to continue if ReturnCode = ERROR_EAS_DIDNT_FIT */ if (rc == 0) rc = ReturnCode; /* set return code for end of directory with no matches */ if (fsfp->fsd_offset == -1) rc = ERROR_NO_MORE_FILES; else if ((rc == 0) || (rc == ERROR_EAS_DIDNT_FIT)) { /* save last matching name for next call */ UniStrncpy(fsfp->fsd_lastmatch,lastmatch.name, lastmatch.namlen); fsfp->fsd_lastmatch[lastmatch.namlen] = '\0'; } } /* claim success if we return any entries */ if (*matchcnt != 0) rc = ReturnCode; freepool(dirent_pool, (caddr_t *)dbuf); readdir_Exit: MMPHPostreaddir(); /* MMPH Performance Hook */ return rc; }
/* * NAME: jfs_readlink(vp, uiop, crp) * * FUNCTION: read a symbolic link <vp> into <uiop> * * PARAMETER: vp - pointer to the vnode that represents the * symlink we want to read * uiop - How much to read and where it goes * crp - credential * * RETURN: EINVAL - if not a symbolic link * errors from subroutines */ jfs_readlink( struct vnode *vp, /* symlink vnode */ struct uio *uiop, struct ucred *crp) { int32 rc = 0; inode_t *ip = VP2IP(vp); int32 cnt; jbuf_t *bp; NOISE(1,("jfs_readlink: ip:0x%08x\n", ip)); if (vp->v_vntype != VLNK) return EINVAL; IREAD_LOCK(ip); /* validate the buffer size vs target path name size * (AES requires ERANGE if the link name won't fit) */ if (ip->i_size > uiop->uio_resid) { rc = ERANGE; goto out; } /* * read the target path name */ if (ip->i_size <= IDATASIZE) { /* * fast symbolic link * * read target path name inline from on-disk inode */ cnt = MIN(ip->i_size, uiop->uio_iov->iov_len); rc = uiomove(ip->i_fastsymlink, cnt, UIO_READ, uiop); } else { /* * read target path name from a single extent * * target path name <= PATH_MAX < buffer page size * * even though the data of symlink object (target * path name) is treated as non-journaled user data, * it is read/written thru buffer cache for performance. */ if (rc = bmRead(ip, 0, ip->i_size, bmREAD_PAGE, &bp)) goto out; cnt = MIN(ip->i_size, uiop->uio_iov->iov_len); rc = uiomove(bp->b_bdata, cnt, UIO_READ, uiop); bmRelease(bp); } out: IREAD_UNLOCK(ip); NOISE(1,("jfs_readlink: rc:%d\n", rc)); return rc; }
/* * NAME: jfs_mkdir(dvp, name, mode, crp) * * FUNCTION: create a child directory in the parent directory <dvp> * with name = <name> and mode = <mode> * * PARAMETER: dvp - parent directory vnode * name - name of child directory * mode - create mode (rwxrwxrwx). * crp - credential * * RETURN: Errors from subroutines * * note: * EACCESS: user needs search+write permission on the parent directory */ jfs_mkdir( struct vnode *dvp, UniChar *name, mode_t mode, #ifdef _JFS_OS2 EAOP *pEABuf, #endif /* _JFS_OS2 */ struct ucred *crp) { int32 rc = 0, rc1 = 0; int32 tid; /* transaction id */ struct vfs *vfsp = dvp->v_vfsp; inode_t *dip = VP2IP(dvp); /* parent directory inode */ struct dasd_usage *du; // F226941 inode_t *ip = NULL; /* child directory inode */ ino_t ino; component_t dname; /* child directory name */ btstack_t btstack; inode_t *iplist[2]; int64 orig_nblocks; // F226941 #ifdef _JFS_LAZYCOMMIT tblock_t *tblk; // D230860 #endif #ifdef _JFS_OS2 FEALIST *pfealist = NULL; #endif /* _JFS_OS2 */ NOISE(1,("jfs_mkdir: dip:0x%08x name:%s\n", dip, name)); /* * the named file exists for "." or ".." */ if (name[0] == '.') { if ((name[1] == '.' && name[2] == '\0') || name[1] == '\0') return EEXIST; } #ifdef _JFS_OS2 /* validate the EAOP buffer, FEALIST size storage location and the * entire FEALIST storage area. Once all the storage has been * validated, the entire FEALIST is validated for format and the size is * computed and compared against the limit. */ if (pEABuf) { if (rc = jfs_ValidateUserFEAList(pEABuf, &pfealist, &pEABuf->oError)) { /* something failed -- bail out */ return rc; } } #endif /* _JFS_OS2 */ if (dip->i_nlink == 0) { rc = ENOENT; goto out1; } /* link count overflow on parent directory ? */ if (dip->i_nlink >= LINK_MAX) { rc = EMLINK; goto out1; } /* * search parent directory for entry/freespace * (dtSearch() returns parent directory page pinned) */ dname.name = name; dname.namlen = UniStrlen(name); if (dname.namlen > JFS_NAME_MAX-1) { rc = ERROR_FILENAME_EXCED_RANGE; goto out1; } // BEGIN D233382 #ifdef _JFS_LAZYCOMMIT if (isReadOnly(dip)) { rc = EROFS; 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. */ if (rc = iAlloc(vfsp, dip, IFDIR|mode|IDIRECTORY, &ip, crp)) goto out1; txBegin(dip->i_ipmnt, &tid, 0); if (rc = dtSearch(dip, &dname, &ino, &btstack, JFS_CREATE)) { ip->i_nlink = 0; ICACHE_LOCK(); iput(ip, vfsp); ICACHE_UNLOCK(); txEnd(tid); goto out1; } tblk = &TxBlock[tid]; // D230860 tblk->xflag |= COMMIT_CREATE; // D230860 tblk->ip = ip; // D230860 #else /* ! _JFS_LAZYCOMMIT */ // END D233382 if (rc = dtSearch(dip, &dname, &ino, &btstack, JFS_CREATE)) goto out1; if (isReadOnly(dip)) { rc = EROFS; /* release parent directory page */ BT_PUTSEARCH(&btstack); goto out1; } /* * allocate on-disk/in-memory inode for child directory: * (iAlloc() returns new, locked inode) */ if (rc = iAlloc(vfsp, dip, IFDIR|mode|IDIRECTORY, &ip, crp)) { /* release parent directory page */ BT_PUTSEARCH(&btstack); jEVENT(0,("jfs_mkdir: iAlloc error(%d)\n", rc)); goto out1; } txBegin(dip->i_ipmnt, &tid, 0); #endif /* _JFS_LAZYCOMMIT */ du = ip->i_dasdlim = dip->i_dasdlim; // F226941 orig_nblocks = dip->i_nblocks; // F226941 iplist[0] = dip; iplist[1] = ip; /* * initialize the child directory in-line in inode */ dtInitRoot(tid, ip, dip->i_number); /* * create entry in parent directory for child directory * (dtInsert() releases parent directory page) */ ino = ip->i_number; if (rc = dtInsert(tid, dip, &dname, &ino, &btstack)) { /* discard new directory inode */ ip->i_nlink = 0; if (rc == EIO) txAbort(tid, 1); /* Marks Filesystem dirty */ else txAbort(tid, 0); /* Filesystem full */ txEnd(tid); goto out3; } /* update child directory inode */ // BEGIN F226941 setDASDLIMIT(&ip->i_DASD, 0); setDASDUSED(&ip->i_DASD, 0); // END F226941 ip->i_nlink++; /* for '.' */ imark(ip, IACC|ICHG|IUPD|IFSYNC); /* update parent directory inode */ dip->i_nlink++; /* for '..' from child directory */ imark(dip, ICHG|IUPD|IFSYNC); /* * insert entry for the new file to dnlc */ ncEnter(dip->i_ipimap, dip->i_number, &dname, ino, NULL); #ifdef _JFS_OS2 if ((rc1 == 0) && pfealist) // F226941 rc1 = jfs_InitializeFEAList(ip, tid, pfealist); if ((rc1 == 0) && (dip->i_acl.flag) && (dip->i_acl.size)) rc1 = jfs_CopyACL(ip, dip, tid); #endif /* _JFS_OS2 */ // BEGIN FF226941 DLIM_UPDATE(tid, dip, dip->i_nblocks + ip->i_nblocks - orig_nblocks); setDASDUSED(&ip->i_DASD, ip->i_nblocks); // D233382 #ifndef _JFS_FASTDASD // D233382 /* * If the transaction modified the ancestors of the inode, the * parent will be in the dasd usage list. Otherwise, transaction * will only change new directory and parent. */ if (du && (du->flag & DLIM_LOGGED)) rc = dasd_commit(tid, ip, 0); else #endif /* _JFS_FASTDASD */ // D233382 // END FF226941 rc = txCommit(tid, 2, &iplist[0], 0); txEnd(tid); #ifdef _JFS_OS2 /* If we successfully added the directory, but failed adding the EA or * ACL, we must cleanup the created directory entry and return the * error. */ if (rc1) { // BEGIN D230860 if ((du) && (du->first_locked)) { /* * txCommit unlocked one or more inodes. * We need to unlock all the directories & * relock them. */ dip->i_dasdlim = 0; DLIM_WRITE_UNLOCK_DETACH(ip, du); DLIM_WRITE_LOCK_ATTACH(ip, du); dip->i_dasdlim = du; } // END D230860 jfs_xrmdir(dip, ip, name); rc = rc1; } #endif /* _JFS_OS2 */ out3: ip->i_dasdlim = 0; // F226941 IWRITE_UNLOCK(ip); ICACHE_LOCK(); iput(ip, vfsp); ICACHE_UNLOCK(); out1: #ifdef _JFS_OS2 /* * this buffer was allocated by * jfs_ValidateUserFEAList() at twice the * size of the given list to provide buffer * space for eliminating duplicate names */ if (pfealist) jfs_EABufFree((char *)pfealist, (pfealist->cbList << 1)); #endif /* _JFS_OS2 */ NOISE(1,("jfs_mkdir: rc:%d\n", rc)); return rc; }
/* * NAME: jfs_ftruncate(vp, flags, length, vinfo, crp) * * FUNCTION: truncate regular file <vp> to the specified size <length>. * * PARAMETER: vp _ file to be truncated. * flags - open flags * length - new length * vinfo - unused * crp - credential * * RETURN: * * note: EINVAL: JFS does NOT support ftruncate() on file types * other than regular filei: the effect of ftruncate()/truncate() * on file types other than regular file is unspecified. [XPG4.2]. * * LFS validation ?: the file must be open for writing. */ jfs_ftruncate( struct vnode *vp, /* file */ int32 flags, /* open flags */ offset_t length, /* new length */ caddr_t vinfo, /* Gfs specific inofo */ struct ucred *crp) /* credential structure */ { int64 orig_nblocks; // F226941 int32 rc = 0; int32 tid; inode_t *ip = VP2IP(vp); extern int iwritelockx(); extern int iwriteunlockx(); if ((ip->i_mode & IFMT) != IFREG) return EINVAL; IWRITE_LOCK(ip); /* * verify mandatory/enforcement-mode file section locking */ /* if (ENF_LOCK(ip->i_mode)) { struct eflock bf; bf.l_type = F_WRLCK; bf.l_whence = 0; bf.l_start = length; bf.l_len = 0; bf.l_pid = U.U_procp->p_pid; bf.l_sysid = 0; bf.l_vfs = MNT_XJFS; if ((rc = common_reclock(IP2GP(ip), ip->i_size, length, &bf, ((flags & (FNDELAY|FNONBLOCK)) ? INOFLCK : SLPFLCK|INOFLCK), 0, 0, iwritelockx, iwriteunlockx)) || bf.l_type != F_UNLCK) { rc = rc ? rc : EAGAIN; goto out; } } */ /* * truncate down */ if (length < ip->i_size) { // BEGIN D230860 /* * All inodes must be locked before beginning transaction */ if (ip->i_dasdlim && (ip->i_dasdlim->flag & DLIM_DIRS_LOCKED) == 0) dasd_write_lock(0, ip->i_dasdlim); // END D230860 txBegin(ip->i_ipmnt, &tid, 0); orig_nblocks = ip->i_nblocks; // F226941 if (rc = iTruncate(tid, ip, (int64)length)) { txEnd(tid); goto out; } ip->i_flag |= IFSYNC; DLIM_UPDATE(tid, ip , ip->i_nblocks - orig_nblocks); // F226941 rc = DLIM_TXCOMMIT(tid, ip, 0); // F226941 txEnd(tid); goto out; } /* * truncate up (extension) */ else if (length > ip->i_size) { #ifndef _JFS_OS2 /* check u_limit */ if (length > U.U_limit) { rc = EFBIG; goto out; } #endif /* _JFS_OS2 */ // BEGIN F226941 orig_nblocks = ip->i_nblocks; // D233382 #ifndef _JFS_FASTDASD // D233382 if (ip->i_dasdlim) { /* * All inodes must be locked before begining * transaction */ if ((ip->i_dasdlim->flag & DLIM_DIRS_LOCKED) == 0) // D230860 dasd_write_lock(0, ip->i_dasdlim); // D230860 txBegin(ip->i_ipmnt, &tid, 1); } else #endif /* _JFS_FASTDASD */ // D233382 { #ifdef _JFS_LAZYCOMMIT txBeginAnon(ip->i_ipmnt); // D233382 #endif tid = 0; } // END F226941 if (rc = iExtend(tid, ip, (int64)length)) { #ifndef _JFS_FASTDASD // D233382 if (tid) // F226941 txEnd(tid); // F226941 #endif // D233382 goto out; } ip->i_flag |= IFSYNC; // BEGIN F226941 DLIM_UPDATE(tid, ip, ip->i_nblocks - orig_nblocks); #ifndef _JFS_FASTDASD // D233382 if (tid) { rc = DLIM_TXCOMMIT(tid, ip, 0); txEnd(tid); } else #endif /* _JFS_FASTDASD */ // D233382 // END F226941 /* if available tlocks are scarce and inode has anonymous * tlocks, OR if we modified a metadata page that is on the * synclist, commit inode. */ if ((TlocksLow && ip->i_atlhead) || (ip->i_flag & ISYNCLIST)) { txBegin(ip->i_ipmnt, &tid, COMMIT_FORCE); rc = txCommit(tid, 1, &ip, 0); // F226941 txEnd(tid); } } /* * no change in size */ else /* (length == ip->i_size) */ /* mark the inode as changed and updated (ala BSD) */ imark(ip, ICHG|IUPD); out: DLIM_WRITE_UNLOCK(ip, ip->i_dasdlim); // F226941 return rc; }
/* * NAME: jfs_open(vp, flag, ext, vinfop, crp) * * FUNCTION: open a file <vp> with open flag <flag>. * * PARAMETER: vp - vnode to open * flag - open flags from the file pointer. * ext - external data for device driver. * vinfop - pointer to the vinfo field for the open file * crp - credential * * RETURN: ENOENT - non-positive link count * errors from subroutines * * note: silly story of open/type/mode flag ... * at user level, open flag (O_xxxx) is defined by fcntl.h, * file type and permission flags (S_xxxx defined by * sys/mode.h included in sys/stat.h); * in LFS, open flag is converted to file flag (Fxxxx defined * by fcntl.h) and to vnode type (Vxxxx defined by sys/vnode.h); * in PFS, file type and permission is defined by Ixxxx flag * (also defined by sys/mode.h) in addition to file flag and * vnode type; */ jfs_open( struct vnode *vp, /* object vnode */ int32 flag, /* open(2) flag */ uint32 oflag, /* file existence options */ EAOP *pcEABuf, struct ucred *crp) /* credential */ { int32 rc, rc1 = 0; inode_t *ip = VP2IP(vp); /* object inode */ int32 type; #ifdef _JFS_OS2 FEALIST *pfealist = NULL; inode_t *iplist[1]; #endif /* _JFS_OS2 */ jEVENT(0,("jfs_open(ip:0x%08x, flag:0x%08x)\n", ip, flag)); /* validate file type */ type = ip->i_mode & IFMT; if (! (type == IFREG || type == IFDIR)) { jEVENT(0,("jfs_open(ip:0x%08x, flag:0x%08x ERROR(EINVAL)\n", ip, flag)); return EINVAL; } #ifdef _JFS_OS2 /* validate the EAOP buffer, FEALIST size storage location and the * entire FEALIST storage area. Once all the storage has been * validated, the entire FEALIST is validated for format and the size is * computed and compared against the limit. */ if (pcEABuf && (oflag & OPEN_ACTION_REPLACE_IF_EXISTS)) { if (rc = jfs_ValidateUserFEAList(pcEABuf, &pfealist, &pcEABuf->oError)) { /* something failed -- bail out */ return rc; } } #endif /* _JFS_OS2 */ /* named file does not exist anymore ? */ if (ip->i_nlink == 0) { rc = ENOENT; goto out; } /* validate open access permission */ if (rc = iOpenAccess(ip, flag, crp)) goto out; #ifdef _JFS_OS2 rc = iOpen(ip, flag, oflag, pfealist, crp); #endif out: #ifdef _JFS_OS2 /* * this buffer was allocated by * jfs_ValidateUserFEAList() at twice the * size of the given list to provide buffer * space for eliminating duplicate names */ if (pfealist) jfs_EABufFree((char *)pfealist, (pfealist->cbList << 1)); #endif /* _JFS_OS2 */ /* If opening a file readonly, and we aren't explicitly told that * the access is random, perform readahead of first 32K */ if ((rc == 0) && ((flag & (OPEN_ACCESS_READWRITE | OPEN_ACCESS_WRITEONLY)) == OPEN_ACCESS_READONLY) && ((flag & OPEN_FLAGS_RANDOM) == 0)) { if (ip->i_size > 0) cmKickStart(ip); } jEVENT(0,("jfs_open(rc:%d)\n", rc)); return rc; }