コード例 #1
0
/*
 * 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;
}
コード例 #2
0
/*
 * 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;
}
コード例 #3
0
/*
 * 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;
}
コード例 #4
0
/*
 * 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;
}
コード例 #5
0
/*
 * 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;
}
コード例 #6
0
/*
 * 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;
}
コード例 #7
0
/*
 * 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;
}
コード例 #8
0
/*
 * 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;
}
コード例 #9
0
/*
 * 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;
}
コード例 #10
0
/*
 * 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;
}
コード例 #11
0
/*
 * 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;
}