コード例 #1
0
int
dm_set_region(
	dm_sessid_t	sid,
	void		*hanp,
	size_t		hlen,
	dm_token_t	token,
	u_int		nelem,
	dm_region_t	*regbufp,
	dm_boolean_t	*exactflagp)
{
	dm_fsys_vector_t *fsys_vector;
	dm_tokdata_t	*tdp;
	int		error;

	error = dm_app_get_tdp(sid, hanp, hlen, token, DM_TDT_REG,
		DM_RIGHT_EXCL, &tdp);
	if (error != 0)
		return(error);

	VN_BHV_READ_LOCK(VN_BHV_HEAD(tdp->td_vp));
	fsys_vector = dm_fsys_vector(tdp->td_vp);
	error = fsys_vector->set_region(tdp->td_vp, tdp->td_right,
		nelem, regbufp, exactflagp);
	VN_BHV_READ_UNLOCK(VN_BHV_HEAD(tdp->td_vp));

	dm_app_put_tdp(tdp);
	return(error);
}
コード例 #2
0
int
dm_get_config_events(
	void		*hanp,
	size_t		hlen,
	u_int		nelem,
	dm_eventset_t	*eventsetp,
	u_int		*nelemp)
{
	dm_fsys_vector_t *fsys_vector;
	dm_tokdata_t	*tdp;
	int		error;

	/* Convert the handle into a vnode. */

	if ((error = dm_get_config_tdp(hanp, hlen, &tdp)) != 0)
		return(error);

	/* Now call the filesystem-specific routine to determine the
	   events supported by that filesystem.
	*/

	VN_BHV_READ_LOCK(VN_BHV_HEAD(tdp->td_vp));
	fsys_vector = dm_fsys_vector(tdp->td_vp);
	error = fsys_vector->get_config_events(tdp->td_vp, tdp->td_right,
		nelem, eventsetp, nelemp);
	VN_BHV_READ_UNLOCK(VN_BHV_HEAD(tdp->td_vp));

	dm_app_put_tdp(tdp);
	return(error);
}
コード例 #3
0
int
dm_get_config(
	void		*hanp,
	size_t		hlen,
	dm_config_t	flagname,
	dm_size_t	*retvalp)
{
	dm_fsys_vector_t *fsys_vector;
	dm_tokdata_t	*tdp;
	dm_size_t	retval;
	int		system = 1;
	int		error;

	/* Trap and process configuration parameters which are system-wide. */

	switch (flagname) {
	case DM_CONFIG_LEGACY:
	case DM_CONFIG_PENDING:
	case DM_CONFIG_OBJ_REF:
		retval = DM_TRUE;
		break;
	case DM_CONFIG_MAX_MESSAGE_DATA:
		retval = DM_MAX_MSG_DATA;
		break;
	default:
		system = 0;
		break;
	}
	if (system) {
		if (copy_to_user(retvalp, &retval, sizeof(retval)))
			return(EFAULT);
		return(0);
	}

	/* Must be filesystem-specific.	 Convert the handle into a vnode. */

	if ((error = dm_get_config_tdp(hanp, hlen, &tdp)) != 0)
		return(error);

	/* Now call the filesystem-specific routine to determine the
	   value of the configuration option for that filesystem.
	*/

	VN_BHV_READ_LOCK(VN_BHV_HEAD(tdp->td_vp));
	fsys_vector = dm_fsys_vector(tdp->td_vp);
	error = fsys_vector->get_config(tdp->td_vp, tdp->td_right,
		flagname, retvalp);
	VN_BHV_READ_UNLOCK(VN_BHV_HEAD(tdp->td_vp));

	dm_app_put_tdp(tdp);
	return(error);
}
コード例 #4
0
ファイル: xfs_vnode.c プロジェクト: OpenHMR/Open-HMR600
struct vnode *
vn_initialize(
	struct inode	*inode)
{
	struct vnode	*vp = LINVFS_GET_VP(inode);

	XFS_STATS_INC(vn_active);
	XFS_STATS_INC(vn_alloc);

	vp->v_flag = VMODIFIED;
	spinlock_init(&vp->v_lock, "v_lock");

	spin_lock(&vnumber_lock);
	if (!++vn_generation)	/* v_number shouldn't be zero */
		vn_generation++;
	vp->v_number = vn_generation;
	spin_unlock(&vnumber_lock);

	ASSERT(VN_CACHED(vp) == 0);

	/* Initialize the first behavior and the behavior chain head. */
	vn_bhv_head_init(VN_BHV_HEAD(vp), "vnode");

#ifdef	XFS_VNODE_TRACE
	vp->v_trace = ktrace_alloc(VNODE_TRACE_SIZE, KM_SLEEP);
#endif	/* XFS_VNODE_TRACE */

	vn_trace_exit(vp, "vn_initialize", (inst_t *)__return_address);
	return vp;
}
コード例 #5
0
ファイル: xfs_super.c プロジェクト: xricson/knoppix
void
xfs_initialize_vnode(
	bhv_desc_t		*bdp,
	vnode_t			*vp,
	bhv_desc_t		*inode_bhv,
	int			unlock)
{
	xfs_inode_t		*ip = XFS_BHVTOI(inode_bhv);
	struct inode		*inode = LINVFS_GET_IP(vp);

	if (!inode_bhv->bd_vobj) {
		vp->v_vfsp = bhvtovfs(bdp);
		bhv_desc_init(inode_bhv, ip, vp, &xfs_vnodeops);
		bhv_insert(VN_BHV_HEAD(vp), inode_bhv);
	}

	vp->v_type = IFTOVT(ip->i_d.di_mode);

	/* Have we been called during the new inode create process,
	 * in which case we are too early to fill in the Linux inode.
	 */
	if (vp->v_type == VNON)
		return;

	xfs_revalidate_inode(XFS_BHVTOM(bdp), vp, ip);

	/* For new inodes we need to set the ops vectors,
	 * and unlock the inode.
	 */
	if (unlock && (inode->i_state & I_NEW)) {
		xfs_set_inodeops(inode);
		unlock_new_inode(inode);
	}
}
/*
 * Get a XFS inode from a given vnode.
 */
xfs_inode_t *
xfs_vtoi(
	struct vnode	*vp)
{
	bhv_desc_t      *bdp;

	bdp = bhv_lookup_range(VN_BHV_HEAD(vp),
			VNODE_POSITION_XFS, VNODE_POSITION_XFS);
	if (unlikely(bdp == NULL))
		return NULL;
	return XFS_BHVTOI(bdp);
}
コード例 #7
0
static int
xfs_vn_allocate(xfs_mount_t *mp, xfs_inode_t *ip, struct xfs_vnode **vpp)
{
	struct vnode *vp;
	struct xfs_vnode *vdata;
	int error;

	/* Use zone allocator here? */
	vdata = kmem_zalloc(sizeof(*vdata), KM_SLEEP);

	error = getnewvnode("xfs", XVFSTOMNT(XFS_MTOVFS(mp)),
			    &xfs_vnops, &vp);
	if (error) {
		kmem_free(vdata, sizeof(*vdata));
		return (error);
	}

	vp->v_vnlock->lk_flags |= LK_CANRECURSE;
	vn_lock(vp, LK_EXCLUSIVE | LK_RETRY, curthread);
	error = insmntque(vp, XVFSTOMNT(XFS_MTOVFS(mp)));
	if (error != 0) {
		kmem_free(vdata, sizeof(*vdata));
		return (error);
	}

	vp->v_data = (void *)vdata;
	vdata->v_number= 0;
	vdata->v_inode = ip;
	vdata->v_vfsp  = XFS_MTOVFS(mp);
	vdata->v_vnode = vp;

 	vn_bhv_head_init(VN_BHV_HEAD(vdata), "vnode");


#ifdef  CONFIG_XFS_VNODE_TRACING
        vp->v_trace = ktrace_alloc(VNODE_TRACE_SIZE, KM_SLEEP);
#endif  /* CONFIG_XFS_VNODE_TRACING */

        vn_trace_exit(vp, "vn_initialize", (inst_t *)__return_address);

	if (error == 0)
		*vpp = vdata;

	return (error);
}
コード例 #8
0
ファイル: xfs_utils.c プロジェクト: Antonio-Zhou/Linux-2.6.11
/*
 * xfs_get_dir_entry is used to get a reference to an inode given
 * its parent directory inode and the name of the file.	 It does
 * not lock the child inode, and it unlocks the directory before
 * returning.  The directory's generation number is returned for
 * use by a later call to xfs_lock_dir_and_entry.
 */
int
xfs_get_dir_entry(
	vname_t		*dentry,
	xfs_inode_t	**ipp)
{
	vnode_t		*vp;
	bhv_desc_t	*bdp;

	vp = VNAME_TO_VNODE(dentry);
	bdp = vn_bhv_lookup_unlocked(VN_BHV_HEAD(vp), &xfs_vnodeops);
	if (!bdp) {
		*ipp = NULL;
		return XFS_ERROR(ENOENT);
	}
	VN_HOLD(vp);
	*ipp = XFS_BHVTOI(bdp);
	return 0;
}
コード例 #9
0
ファイル: xfs_ioctl.c プロジェクト: BackupTheBerlios/arp2-svn
STATIC int
xfs_fssetdm_by_handle(
	xfs_mount_t		*mp,
	void			__user *arg,
	struct file		*parfilp,
	struct inode		*parinode)
{
	int			error;
	struct fsdmidata	fsd;
	xfs_fsop_setdm_handlereq_t dmhreq;
	struct inode		*inode;
	bhv_desc_t		*bdp;
	vnode_t			*vp;

	if (!capable(CAP_MKNOD))
		return -XFS_ERROR(EPERM);
	if (copy_from_user(&dmhreq, arg, sizeof(xfs_fsop_setdm_handlereq_t)))
		return -XFS_ERROR(EFAULT);

	error = xfs_vget_fsop_handlereq(mp, parinode, &dmhreq.hreq, &vp, &inode);
	if (error)
		return -error;

	if (IS_IMMUTABLE(inode) || IS_APPEND(inode)) {
		VN_RELE(vp);
		return -XFS_ERROR(EPERM);
	}

	if (copy_from_user(&fsd, dmhreq.data, sizeof(fsd))) {
		VN_RELE(vp);
		return -XFS_ERROR(EFAULT);
	}

	bdp = bhv_base_unlocked(VN_BHV_HEAD(vp));
	error = xfs_set_dmattrs(bdp, fsd.fsd_dmevmask, fsd.fsd_dmstate, NULL);

	VN_RELE(vp);
	if (error)
		return -error;
	return 0;
}
コード例 #10
0
ファイル: xfs_aops.c プロジェクト: iPodLinux/linux-2.6.7-ipod
void
xfs_page_trace(
	int		tag,
	struct inode	*inode,
	struct page	*page,
	int		mask)
{
	xfs_inode_t	*ip;
	bhv_desc_t	*bdp;
	vnode_t		*vp = LINVFS_GET_VP(inode);
	loff_t		isize = i_size_read(inode);
	loff_t		offset = page->index << PAGE_CACHE_SHIFT;
	int		delalloc = -1, unmapped = -1, unwritten = -1;

	if (page_has_buffers(page))
		xfs_count_page_state(page, &delalloc, &unmapped, &unwritten);

	bdp = vn_bhv_lookup(VN_BHV_HEAD(vp), &xfs_vnodeops);
	ip = XFS_BHVTOI(bdp);
	if (!ip->i_rwtrace)
		return;

	ktrace_enter(ip->i_rwtrace,
		(void *)((unsigned long)tag),
		(void *)ip,
		(void *)inode,
		(void *)page,
		(void *)((unsigned long)mask),
		(void *)((unsigned long)((ip->i_d.di_size >> 32) & 0xffffffff)),
		(void *)((unsigned long)(ip->i_d.di_size & 0xffffffff)),
		(void *)((unsigned long)((isize >> 32) & 0xffffffff)),
		(void *)((unsigned long)(isize & 0xffffffff)),
		(void *)((unsigned long)((offset >> 32) & 0xffffffff)),
		(void *)((unsigned long)(offset & 0xffffffff)),
		(void *)((unsigned long)delalloc),
		(void *)((unsigned long)unmapped),
		(void *)((unsigned long)unwritten),
		(void *)NULL,
		(void *)NULL);
}
コード例 #11
0
ファイル: xfs_ioctl.c プロジェクト: JBTech/ralink_rt5350
/*
 * xfs_find_handle maps from userspace xfs_fsop_handlereq structure to
 * a file or fs handle.
 *
 * XFS_IOC_PATH_TO_FSHANDLE
 *    returns fs handle for a mount point or path within that mount point
 * XFS_IOC_FD_TO_HANDLE
 *    returns full handle for a FD opened in user space
 * XFS_IOC_PATH_TO_HANDLE
 *    returns full handle for a path
 */
STATIC int
xfs_find_handle(
	unsigned int		cmd,
	unsigned long		arg)
{
	int			hsize;
	xfs_handle_t		handle;
	xfs_fsop_handlereq_t	hreq;
	struct inode		*inode;
	struct vnode		*vp;

	if (copy_from_user(&hreq, (xfs_fsop_handlereq_t *)arg, sizeof(hreq)))
		return -XFS_ERROR(EFAULT);

	memset((char *)&handle, 0, sizeof(handle));

	switch (cmd) {
	case XFS_IOC_PATH_TO_FSHANDLE:
	case XFS_IOC_PATH_TO_HANDLE: {
		struct nameidata	nd;
		int			error;

		error = user_path_walk_link(hreq.path, &nd);
		if (error)
			return error;

		ASSERT(nd.dentry);
		ASSERT(nd.dentry->d_inode);
		inode = igrab(nd.dentry->d_inode);
		path_release(&nd);
		break;
	}

	case XFS_IOC_FD_TO_HANDLE: {
		struct file	*file;

		file = fget(hreq.fd);
		if (!file)
		    return -EBADF;

		ASSERT(file->f_dentry);
		ASSERT(file->f_dentry->d_inode);
		inode = igrab(file->f_dentry->d_inode);
		fput(file);
		break;
	}

	default:
		ASSERT(0);
		return -XFS_ERROR(EINVAL);
	}

	if (inode->i_sb->s_magic != XFS_SB_MAGIC) {
		/* we're not in XFS anymore, Toto */
		iput(inode);
		return -XFS_ERROR(EINVAL);
	}

	/* we need the vnode */
	vp = LINVFS_GET_VP(inode);
	if (vp->v_type != VREG && vp->v_type != VDIR && vp->v_type != VLNK) {
		iput(inode);
		return -XFS_ERROR(EBADF);
	}

	/* now we can grab the fsid */
	memcpy(&handle.ha_fsid, vp->v_vfsp->vfs_altfsid, sizeof(xfs_fsid_t));
	hsize = sizeof(xfs_fsid_t);

	if (cmd != XFS_IOC_PATH_TO_FSHANDLE) {
		xfs_inode_t	*ip;
		bhv_desc_t	*bhv;
		int		lock_mode;

		/* need to get access to the xfs_inode to read the generation */
		bhv = vn_bhv_lookup_unlocked(VN_BHV_HEAD(vp), &xfs_vnodeops);
		ASSERT(bhv);
		ip = XFS_BHVTOI(bhv);
		ASSERT(ip);
		lock_mode = xfs_ilock_map_shared(ip);

		/* fill in fid section of handle from inode */
		handle.ha_fid.xfs_fid_len = sizeof(xfs_fid_t) -
					    sizeof(handle.ha_fid.xfs_fid_len);
		handle.ha_fid.xfs_fid_pad = 0;
		handle.ha_fid.xfs_fid_gen = ip->i_d.di_gen;
		handle.ha_fid.xfs_fid_ino = ip->i_ino;

		xfs_iunlock_map_shared(ip, lock_mode);

		hsize = XFS_HSIZE(handle);
	}

	/* now copy our handle into the user buffer & write out the size */
	if (copy_to_user((xfs_handle_t *)hreq.ohandle, &handle, hsize) ||
	    copy_to_user(hreq.ohandlen, &hsize, sizeof(__s32))) {
		iput(inode);
		return -XFS_ERROR(EFAULT);
	}

	iput(inode);
	return 0;
}
コード例 #12
0
ファイル: osi_vm.c プロジェクト: bagdxk/openafs
/* Try to discard pages, in order to recycle a vcache entry.
 *
 * We also make some sanity checks:  ref count, open count, held locks.
 *
 * We also do some non-VM-related chores, such as releasing the cred pointer
 * (for AIX and Solaris) and releasing the gnode (for AIX).
 *
 * Locking:  afs_xvcache lock is held. It must not be dropped.
 */
int
osi_VM_FlushVCache(struct vcache *avc)
{
    int s, code;
    vnode_t *vp = &avc->v;

    if (avc->vrefCount != 0)
	return EBUSY;

    if (avc->opens != 0)
	return EBUSY;

    /*
     * Just in case someone is still referring to the vnode we give up
     * trying to get rid of this guy.
     */
    if (CheckLock(&avc->lock) || LockWaiters(&avc->lock))
	return EBUSY;

    s = VN_LOCK(vp);

    /*
     * we just need to avoid the race
     * in vn_rele between the ref count going to 0 and VOP_INACTIVE
     * finishing up.
     * Note that although we checked vcount above, we didn't have the lock
     */
    if (vp->v_count > 0 || (vp->v_flag & VINACT)) {
	VN_UNLOCK(vp, s);
	return EBUSY;
    }
    VN_UNLOCK(vp, s);

    /*
     * Since we store on last close and on VOP_INACTIVE
     * there should be NO dirty pages
     * Note that we hold the xvcache lock the entire time.
     */
    AFS_GUNLOCK();
    PTOSSVP(vp, (off_t) 0, (off_t) MAXLONG);
    AFS_GLOCK();

    /* afs_chkpgoob will drop and re-acquire the global lock. */
    afs_chkpgoob(vp, 0);
    osi_Assert(!VN_GET_PGCNT(vp));
    osi_Assert(!AFS_VN_MAPPED(vp));
    osi_Assert(!AFS_VN_DIRTY(&avc->v));

#if defined(AFS_SGI65_ENV)
    if (vp->v_filocks)
	cleanlocks(vp, IGN_PID, 0);
    mutex_destroy(&vp->v_filocksem);
#else /* AFS_SGI65_ENV */
    if (vp->v_filocksem) {
	if (vp->v_filocks)
#ifdef AFS_SGI64_ENV
	    cleanlocks(vp, &curprocp->p_flid);
#else
	    cleanlocks(vp, IGN_PID, 0);
#endif
	osi_Assert(vp->v_filocks == NULL);
	mutex_destroy(vp->v_filocksem);
	kmem_free(vp->v_filocksem, sizeof *vp->v_filocksem);
	vp->v_filocksem = NULL;
    }
#endif /* AFS_SGI65_ENV */

    if (avc->vrefCount)
	osi_Panic("flushVcache: vm race");
#ifdef AFS_SGI64_ENV
    AFS_GUNLOCK();
    vnode_pcache_reclaim(vp);	/* this can sleep */
    vnode_pcache_free(vp);
    if (vp->v_op != &Afs_vnodeops) {
	VOP_RECLAIM(vp, FSYNC_WAIT, code);
    }
    AFS_GLOCK();
#ifdef AFS_SGI65_ENV
#ifdef VNODE_TRACING
    ktrace_free(vp->v_trace);
#endif /* VNODE_TRACING */
    vn_bhv_remove(VN_BHV_HEAD(vp), &(avc->vc_bhv_desc));
    vn_bhv_head_destroy(&(vp->v_bh));
    destroy_bitlock(&vp->v_pcacheflag);
    mutex_destroy(&vp->v_buf_lock);
#else
    bhv_remove(VN_BHV_HEAD(vp), &(avc->vc_bhv_desc));
    bhv_head_destroy(&(vp->v_bh));
#endif
    vp->v_flag = 0;		/* debug */
#if defined(DEBUG) && defined(VNODE_INIT_BITLOCK)
    destroy_bitlock(&vp->v_flag);
#endif
#ifdef INTR_KTHREADS
    AFS_VN_DESTROY_BUF_LOCK(vp);
#endif
#endif /* AFS_SGI64_ENV */

    return 0;
}
コード例 #13
0
ファイル: xfs_dfrag.c プロジェクト: OpenHMR/Open-HMR600
/*
 * Syssgi interface for swapext
 */
int
xfs_swapext(
	xfs_swapext_t	__user *sxp)
{
	xfs_swapext_t	sx;
	xfs_inode_t     *ip=NULL, *tip=NULL, *ips[2];
	xfs_trans_t     *tp;
	xfs_mount_t     *mp;
	xfs_bstat_t	*sbp;
	struct file	*fp = NULL, *tfp = NULL;
	vnode_t		*vp, *tvp;
	bhv_desc_t      *bdp, *tbdp;
	vn_bhv_head_t   *bhp, *tbhp;
	uint		lock_flags=0;
	int		ilf_fields, tilf_fields;
	int		error = 0;
	xfs_ifork_t	tempif, *ifp, *tifp;
	__uint64_t	tmp;
	int		aforkblks = 0;
	int		taforkblks = 0;
	int		locked = 0;

	if (copy_from_user(&sx, sxp, sizeof(sx)))
		return XFS_ERROR(EFAULT);

	/* Pull information for the target fd */
	if (((fp = fget((int)sx.sx_fdtarget)) == NULL) ||
	    ((vp = LINVFS_GET_VP(fp->f_dentry->d_inode)) == NULL))  {
		error = XFS_ERROR(EINVAL);
		goto error0;
	}

	bhp = VN_BHV_HEAD(vp);
	bdp = vn_bhv_lookup(bhp, &xfs_vnodeops);
	if (bdp == NULL) {
		error = XFS_ERROR(EBADF);
		goto error0;
	} else {
		ip = XFS_BHVTOI(bdp);
	}

	if (((tfp = fget((int)sx.sx_fdtmp)) == NULL) ||
	    ((tvp = LINVFS_GET_VP(tfp->f_dentry->d_inode)) == NULL)) {
		error = XFS_ERROR(EINVAL);
		goto error0;
	}

	tbhp = VN_BHV_HEAD(tvp);
	tbdp = vn_bhv_lookup(tbhp, &xfs_vnodeops);
	if (tbdp == NULL) {
		error = XFS_ERROR(EBADF);
		goto error0;
	} else {
		tip = XFS_BHVTOI(tbdp);
	}

	if (ip->i_mount != tip->i_mount) {
		error =  XFS_ERROR(EINVAL);
		goto error0;
	}

	if (ip->i_ino == tip->i_ino) {
		error =  XFS_ERROR(EINVAL);
		goto error0;
	}

	mp = ip->i_mount;

	sbp = &sx.sx_stat;

	if (XFS_FORCED_SHUTDOWN(mp)) {
		error =  XFS_ERROR(EIO);
		goto error0;
	}

	locked = 1;

	/* Lock in i_ino order */
	if (ip->i_ino < tip->i_ino) {
		ips[0] = ip;
		ips[1] = tip;
	} else {
		ips[0] = tip;
		ips[1] = ip;
	}
	lock_flags = XFS_ILOCK_EXCL | XFS_IOLOCK_EXCL;
	xfs_lock_inodes(ips, 2, 0, lock_flags);

	/* Check permissions */
	error = xfs_iaccess(ip, S_IWUSR, NULL);
	if (error)
		goto error0;

	error = xfs_iaccess(tip, S_IWUSR, NULL);
	if (error)
		goto error0;

	/* Verify that both files have the same format */
	if ((ip->i_d.di_mode & S_IFMT) != (tip->i_d.di_mode & S_IFMT)) {
		error = XFS_ERROR(EINVAL);
		goto error0;
	}

	/* Verify both files are either real-time or non-realtime */
	if ((ip->i_d.di_flags & XFS_DIFLAG_REALTIME) !=
	    (tip->i_d.di_flags & XFS_DIFLAG_REALTIME)) {
		error = XFS_ERROR(EINVAL);
		goto error0;
	}

	/* Should never get a local format */
	if (ip->i_d.di_format == XFS_DINODE_FMT_LOCAL ||
	    tip->i_d.di_format == XFS_DINODE_FMT_LOCAL) {
		error = XFS_ERROR(EINVAL);
		goto error0;
	}

	if (VN_CACHED(tvp) != 0)
		xfs_inval_cached_pages(XFS_ITOV(tip), &(tip->i_iocore),
						(xfs_off_t)0, 0, 0);

	/* Verify O_DIRECT for ftmp */
	if (VN_CACHED(tvp) != 0) {
		error = XFS_ERROR(EINVAL);
		goto error0;
	}

	/* Verify all data are being swapped */
	if (sx.sx_offset != 0 ||
	    sx.sx_length != ip->i_d.di_size ||
	    sx.sx_length != tip->i_d.di_size) {
		error = XFS_ERROR(EFAULT);
		goto error0;
	}

	/*
	 * If the target has extended attributes, the tmp file
	 * must also in order to ensure the correct data fork
	 * format.
	 */
	if ( XFS_IFORK_Q(ip) != XFS_IFORK_Q(tip) ) {
		error = XFS_ERROR(EINVAL);
		goto error0;
	}

	/*
	 * Compare the current change & modify times with that
	 * passed in.  If they differ, we abort this swap.
	 * This is the mechanism used to ensure the calling
	 * process that the file was not changed out from
	 * under it.
	 */
	if ((sbp->bs_ctime.tv_sec != ip->i_d.di_ctime.t_sec) ||
	    (sbp->bs_ctime.tv_nsec != ip->i_d.di_ctime.t_nsec) ||
	    (sbp->bs_mtime.tv_sec != ip->i_d.di_mtime.t_sec) ||
	    (sbp->bs_mtime.tv_nsec != ip->i_d.di_mtime.t_nsec)) {
		error = XFS_ERROR(EBUSY);
		goto error0;
	}

	/* We need to fail if the file is memory mapped.  Once we have tossed
	 * all existing pages, the page fault will have no option
	 * but to go to the filesystem for pages. By making the page fault call
	 * VOP_READ (or write in the case of autogrow) they block on the iolock
	 * until we have switched the extents.
	 */
	if (VN_MAPPED(vp)) {
		error = XFS_ERROR(EBUSY);
		goto error0;
	}

	xfs_iunlock(ip, XFS_ILOCK_EXCL);
	xfs_iunlock(tip, XFS_ILOCK_EXCL);

	/*
	 * There is a race condition here since we gave up the
	 * ilock.  However, the data fork will not change since
	 * we have the iolock (locked for truncation too) so we
	 * are safe.  We don't really care if non-io related
	 * fields change.
	 */

	VOP_TOSS_PAGES(vp, 0, -1, FI_REMAPF);

	tp = xfs_trans_alloc(mp, XFS_TRANS_SWAPEXT);
	if ((error = xfs_trans_reserve(tp, 0,
				     XFS_ICHANGE_LOG_RES(mp), 0,
				     0, 0))) {
		xfs_iunlock(ip,  XFS_IOLOCK_EXCL);
		xfs_iunlock(tip, XFS_IOLOCK_EXCL);
		xfs_trans_cancel(tp, 0);
		return error;
	}
	xfs_lock_inodes(ips, 2, 0, XFS_ILOCK_EXCL);

	/*
	 * Count the number of extended attribute blocks
	 */
	if ( ((XFS_IFORK_Q(ip) != 0) && (ip->i_d.di_anextents > 0)) &&
	     (ip->i_d.di_aformat != XFS_DINODE_FMT_LOCAL)) {
		error = xfs_bmap_count_blocks(tp, ip, XFS_ATTR_FORK, &aforkblks);
		if (error) {
			xfs_iunlock(ip,  lock_flags);
			xfs_iunlock(tip, lock_flags);
			xfs_trans_cancel(tp, 0);
			return error;
		}
	}
	if ( ((XFS_IFORK_Q(tip) != 0) && (tip->i_d.di_anextents > 0)) &&
	     (tip->i_d.di_aformat != XFS_DINODE_FMT_LOCAL)) {
		error = xfs_bmap_count_blocks(tp, tip, XFS_ATTR_FORK,
			&taforkblks);
		if (error) {
			xfs_iunlock(ip,  lock_flags);
			xfs_iunlock(tip, lock_flags);
			xfs_trans_cancel(tp, 0);
			return error;
		}
	}

	/*
	 * Swap the data forks of the inodes
	 */
	ifp = &ip->i_df;
	tifp = &tip->i_df;
	tempif = *ifp;	/* struct copy */
	*ifp = *tifp;	/* struct copy */
	*tifp = tempif;	/* struct copy */

	/*
	 * Fix the on-disk inode values
	 */
	tmp = (__uint64_t)ip->i_d.di_nblocks;
	ip->i_d.di_nblocks = tip->i_d.di_nblocks - taforkblks + aforkblks;
	tip->i_d.di_nblocks = tmp + taforkblks - aforkblks;

	tmp = (__uint64_t) ip->i_d.di_nextents;
	ip->i_d.di_nextents = tip->i_d.di_nextents;
	tip->i_d.di_nextents = tmp;

	tmp = (__uint64_t) ip->i_d.di_format;
	ip->i_d.di_format = tip->i_d.di_format;
	tip->i_d.di_format = tmp;

	ilf_fields = XFS_ILOG_CORE;

	switch(ip->i_d.di_format) {
	case XFS_DINODE_FMT_EXTENTS:
		/* If the extents fit in the inode, fix the
		 * pointer.  Otherwise it's already NULL or
		 * pointing to the extent.
		 */
		if (ip->i_d.di_nextents <= XFS_INLINE_EXTS) {
			ifp->if_u1.if_extents =
				ifp->if_u2.if_inline_ext;
		}
		ilf_fields |= XFS_ILOG_DEXT;
		break;
	case XFS_DINODE_FMT_BTREE:
		ilf_fields |= XFS_ILOG_DBROOT;
		break;
	}

	tilf_fields = XFS_ILOG_CORE;

	switch(tip->i_d.di_format) {
	case XFS_DINODE_FMT_EXTENTS:
		/* If the extents fit in the inode, fix the
		 * pointer.  Otherwise it's already NULL or
		 * pointing to the extent.
		 */
		if (tip->i_d.di_nextents <= XFS_INLINE_EXTS) {
			tifp->if_u1.if_extents =
				tifp->if_u2.if_inline_ext;
		}
		tilf_fields |= XFS_ILOG_DEXT;
		break;
	case XFS_DINODE_FMT_BTREE:
		tilf_fields |= XFS_ILOG_DBROOT;
		break;
	}

	/*
	 * Increment vnode ref counts since xfs_trans_commit &
	 * xfs_trans_cancel will both unlock the inodes and
	 * decrement the associated ref counts.
	 */
	VN_HOLD(vp);
	VN_HOLD(tvp);

	xfs_trans_ijoin(tp, ip, lock_flags);
	xfs_trans_ijoin(tp, tip, lock_flags);

	xfs_trans_log_inode(tp, ip,  ilf_fields);
	xfs_trans_log_inode(tp, tip, tilf_fields);

	/*
	 * If this is a synchronous mount, make sure that the
	 * transaction goes to disk before returning to the user.
	 */
	if (mp->m_flags & XFS_MOUNT_WSYNC) {
		xfs_trans_set_sync(tp);
	}

	error = xfs_trans_commit(tp, XFS_TRANS_SWAPEXT, NULL);

	fput(fp);
	fput(tfp);

	return error;

 error0:
	if (locked) {
		xfs_iunlock(ip,  lock_flags);
		xfs_iunlock(tip, lock_flags);
	}

	if (fp != NULL) fput(fp);
	if (tfp != NULL) fput(tfp);

	return error;
}
コード例 #14
0
ファイル: xfs_rename.c プロジェクト: kzlin129/tt-gpl
/*
 * xfs_rename
 */
int
xfs_rename(
	bhv_desc_t	*src_dir_bdp,
	vname_t		*src_vname,
	vnode_t		*target_dir_vp,
	vname_t		*target_vname,
	cred_t		*credp)
{
	xfs_trans_t	*tp;
	xfs_inode_t	*src_dp, *target_dp, *src_ip, *target_ip;
	xfs_mount_t	*mp;
	int		new_parent;		/* moving to a new dir */
	int		src_is_directory;	/* src_name is a directory */
	int		error;
	xfs_bmap_free_t free_list;
	xfs_fsblock_t   first_block;
	int		cancel_flags;
	int		committed;
	xfs_inode_t	*inodes[4];
	int		target_ip_dropped = 0;	/* dropped target_ip link? */
	vnode_t		*src_dir_vp;
	bhv_desc_t	*target_dir_bdp;
	int		spaceres;
	int		target_link_zero = 0;
	int		num_inodes;
	char		*src_name = VNAME(src_vname);
	char		*target_name = VNAME(target_vname);
	int		src_namelen = VNAMELEN(src_vname);
	int		target_namelen = VNAMELEN(target_vname);

	src_dir_vp = BHV_TO_VNODE(src_dir_bdp);
	vn_trace_entry(src_dir_vp, "xfs_rename", (inst_t *)__return_address);
	vn_trace_entry(target_dir_vp, "xfs_rename", (inst_t *)__return_address);

	/*
	 * Find the XFS behavior descriptor for the target directory
	 * vnode since it was not handed to us.
	 */
	target_dir_bdp = vn_bhv_lookup_unlocked(VN_BHV_HEAD(target_dir_vp),
						&xfs_vnodeops);
	if (target_dir_bdp == NULL) {
		return XFS_ERROR(EXDEV);
	}

	src_dp = XFS_BHVTOI(src_dir_bdp);
	target_dp = XFS_BHVTOI(target_dir_bdp);
	mp = src_dp->i_mount;

	if (DM_EVENT_ENABLED(src_dir_vp->v_vfsp, src_dp, DM_EVENT_RENAME) ||
	    DM_EVENT_ENABLED(target_dir_vp->v_vfsp,
				target_dp, DM_EVENT_RENAME)) {
		error = XFS_SEND_NAMESP(mp, DM_EVENT_RENAME,
					src_dir_vp, DM_RIGHT_NULL,
					target_dir_vp, DM_RIGHT_NULL,
					src_name, target_name,
					0, 0, 0);
		if (error) {
			return error;
		}
	}
	/* Return through std_return after this point. */

	/*
	 * Lock all the participating inodes. Depending upon whether
	 * the target_name exists in the target directory, and
	 * whether the target directory is the same as the source
	 * directory, we can lock from 2 to 4 inodes.
	 * xfs_lock_for_rename() will return ENOENT if src_name
	 * does not exist in the source directory.
	 */
	tp = NULL;
	error = xfs_lock_for_rename(src_dp, target_dp, src_vname,
			target_vname, &src_ip, &target_ip, inodes,
			&num_inodes);

	if (error) {
		/*
		 * We have nothing locked, no inode references, and
		 * no transaction, so just get out.
		 */
		goto std_return;
	}

	ASSERT(src_ip != NULL);

	if ((src_ip->i_d.di_mode & S_IFMT) == S_IFDIR) {
		/*
		 * Check for link count overflow on target_dp
		 */
		if (target_ip == NULL && (src_dp != target_dp) &&
		    target_dp->i_d.di_nlink >= XFS_MAXLINK) {
			error = XFS_ERROR(EMLINK);
			xfs_rename_unlock4(inodes, XFS_ILOCK_SHARED);
			goto rele_return;
		}
	}

	new_parent = (src_dp != target_dp);
	src_is_directory = ((src_ip->i_d.di_mode & S_IFMT) == S_IFDIR);

	/*
	 * Drop the locks on our inodes so that we can start the transaction.
	 */
	xfs_rename_unlock4(inodes, XFS_ILOCK_SHARED);

	XFS_BMAP_INIT(&free_list, &first_block);
	tp = xfs_trans_alloc(mp, XFS_TRANS_RENAME);
	cancel_flags = XFS_TRANS_RELEASE_LOG_RES;
	spaceres = XFS_RENAME_SPACE_RES(mp, target_namelen);
	error = xfs_trans_reserve(tp, spaceres, XFS_RENAME_LOG_RES(mp), 0,
			XFS_TRANS_PERM_LOG_RES, XFS_RENAME_LOG_COUNT);
	if (error == ENOSPC) {
		spaceres = 0;
		error = xfs_trans_reserve(tp, 0, XFS_RENAME_LOG_RES(mp), 0,
				XFS_TRANS_PERM_LOG_RES, XFS_RENAME_LOG_COUNT);
	}
	if (error) {
		xfs_trans_cancel(tp, 0);
		goto rele_return;
	}

	/*
	 * Attach the dquots to the inodes
	 */
	if ((error = XFS_QM_DQVOPRENAME(mp, inodes))) {
		xfs_trans_cancel(tp, cancel_flags);
		goto rele_return;
	}

	/*
	 * Reacquire the inode locks we dropped above.
	 */
	xfs_lock_inodes(inodes, num_inodes, 0, XFS_ILOCK_EXCL);

	/*
	 * Join all the inodes to the transaction. From this point on,
	 * we can rely on either trans_commit or trans_cancel to unlock
	 * them.  Note that we need to add a vnode reference to the
	 * directories since trans_commit & trans_cancel will decrement
	 * them when they unlock the inodes.  Also, we need to be careful
	 * not to add an inode to the transaction more than once.
	 */
	VN_HOLD(src_dir_vp);
	xfs_trans_ijoin(tp, src_dp, XFS_ILOCK_EXCL);
	if (new_parent) {
		VN_HOLD(target_dir_vp);
		xfs_trans_ijoin(tp, target_dp, XFS_ILOCK_EXCL);
	}
	if ((src_ip != src_dp) && (src_ip != target_dp)) {
		xfs_trans_ijoin(tp, src_ip, XFS_ILOCK_EXCL);
	}
	if ((target_ip != NULL) &&
	    (target_ip != src_ip) &&
	    (target_ip != src_dp) &&
	    (target_ip != target_dp)) {
		xfs_trans_ijoin(tp, target_ip, XFS_ILOCK_EXCL);
	}

	/*
	 * Set up the target.
	 */
	if (target_ip == NULL) {
		/*
		 * If there's no space reservation, check the entry will
		 * fit before actually inserting it.
		 */
		if (spaceres == 0 &&
		    (error = XFS_DIR_CANENTER(mp, tp, target_dp, target_name,
				target_namelen))) {
			goto error_return;
		}
		/*
		 * If target does not exist and the rename crosses
		 * directories, adjust the target directory link count
		 * to account for the ".." reference from the new entry.
		 */
		error = XFS_DIR_CREATENAME(mp, tp, target_dp, target_name,
					   target_namelen, src_ip->i_ino,
					   &first_block, &free_list, spaceres);
		if (error == ENOSPC) {
			goto error_return;
		}
		if (error) {
			goto abort_return;
		}
		xfs_ichgtime(target_dp, XFS_ICHGTIME_MOD | XFS_ICHGTIME_CHG);

		if (new_parent && src_is_directory) {
			error = xfs_bumplink(tp, target_dp);
			if (error) {
				goto abort_return;
			}
		}
	} else { /* target_ip != NULL */

		/*
		 * If target exists and it's a directory, check that both
		 * target and source are directories and that target can be
		 * destroyed, or that neither is a directory.
		 */
		if ((target_ip->i_d.di_mode & S_IFMT) == S_IFDIR) {
			/*
			 * Make sure target dir is empty.
			 */
			if (!(XFS_DIR_ISEMPTY(target_ip->i_mount, target_ip)) ||
			    (target_ip->i_d.di_nlink > 2)) {
				error = XFS_ERROR(EEXIST);
				goto error_return;
			}
		}

		/*
		 * Link the source inode under the target name.
		 * If the source inode is a directory and we are moving
		 * it across directories, its ".." entry will be
		 * inconsistent until we replace that down below.
		 *
		 * In case there is already an entry with the same
		 * name at the destination directory, remove it first.
		 */
		error = XFS_DIR_REPLACE(mp, tp, target_dp, target_name,
			target_namelen, src_ip->i_ino, &first_block,
			&free_list, spaceres);
		if (error) {
			goto abort_return;
		}
		xfs_ichgtime(target_dp, XFS_ICHGTIME_MOD | XFS_ICHGTIME_CHG);

		/*
		 * Decrement the link count on the target since the target
		 * dir no longer points to it.
		 */
		error = xfs_droplink(tp, target_ip);
		if (error) {
			goto abort_return;
		}
		target_ip_dropped = 1;

		if (src_is_directory) {
			/*
			 * Drop the link from the old "." entry.
			 */
			error = xfs_droplink(tp, target_ip);
			if (error) {
				goto abort_return;
			}
		}

		/* Do this test while we still hold the locks */
		target_link_zero = (target_ip)->i_d.di_nlink==0;

	} /* target_ip != NULL */

	/*
	 * Remove the source.
	 */
	if (new_parent && src_is_directory) {

		/*
		 * Rewrite the ".." entry to point to the new
		 * directory.
		 */
		error = XFS_DIR_REPLACE(mp, tp, src_ip, "..", 2,
					target_dp->i_ino, &first_block,
					&free_list, spaceres);
		ASSERT(error != EEXIST);
		if (error) {
			goto abort_return;
		}
		xfs_ichgtime(src_ip, XFS_ICHGTIME_MOD | XFS_ICHGTIME_CHG);

	} else {
		/*
		 * We always want to hit the ctime on the source inode.
		 * We do it in the if clause above for the 'new_parent &&
		 * src_is_directory' case, and here we get all the other
		 * cases.  This isn't strictly required by the standards
		 * since the source inode isn't really being changed,
		 * but old unix file systems did it and some incremental
		 * backup programs won't work without it.
		 */
		xfs_ichgtime(src_ip, XFS_ICHGTIME_CHG);
	}

	/*
	 * Adjust the link count on src_dp.  This is necessary when
	 * renaming a directory, either within one parent when
	 * the target existed, or across two parent directories.
	 */
	if (src_is_directory && (new_parent || target_ip != NULL)) {

		/*
		 * Decrement link count on src_directory since the
		 * entry that's moved no longer points to it.
		 */
		error = xfs_droplink(tp, src_dp);
		if (error) {
			goto abort_return;
		}
	}

	error = XFS_DIR_REMOVENAME(mp, tp, src_dp, src_name, src_namelen,
			src_ip->i_ino, &first_block, &free_list, spaceres);
	if (error) {
		goto abort_return;
	}
	xfs_ichgtime(src_dp, XFS_ICHGTIME_MOD | XFS_ICHGTIME_CHG);

	/*
	 * Update the generation counts on all the directory inodes
	 * that we're modifying.
	 */
	src_dp->i_gen++;
	xfs_trans_log_inode(tp, src_dp, XFS_ILOG_CORE);

	if (new_parent) {
		target_dp->i_gen++;
		xfs_trans_log_inode(tp, target_dp, XFS_ILOG_CORE);
	}

	/*
	 * If there was a target inode, take an extra reference on
	 * it here so that it doesn't go to xfs_inactive() from
	 * within the commit.
	 */
	if (target_ip != NULL) {
		IHOLD(target_ip);
	}

	/*
	 * If this is a synchronous mount, make sure that the
	 * rename transaction goes to disk before returning to
	 * the user.
	 */
	if (mp->m_flags & (XFS_MOUNT_WSYNC|XFS_MOUNT_DIRSYNC)) {
		xfs_trans_set_sync(tp);
	}

	/*
	 * Take refs. for vop_link_removed calls below.  No need to worry
	 * about directory refs. because the caller holds them.
	 *
	 * Do holds before the xfs_bmap_finish since it might rele them down
	 * to zero.
	 */

	if (target_ip_dropped)
		IHOLD(target_ip);
	IHOLD(src_ip);

	error = xfs_bmap_finish(&tp, &free_list, first_block, &committed);
	if (error) {
		xfs_bmap_cancel(&free_list);
		xfs_trans_cancel(tp, (XFS_TRANS_RELEASE_LOG_RES |
				 XFS_TRANS_ABORT));
		if (target_ip != NULL) {
			IRELE(target_ip);
		}
		if (target_ip_dropped) {
			IRELE(target_ip);
		}
		IRELE(src_ip);
		goto std_return;
	}

	/*
	 * trans_commit will unlock src_ip, target_ip & decrement
	 * the vnode references.
	 */
	error = xfs_trans_commit(tp, XFS_TRANS_RELEASE_LOG_RES, NULL);
	if (target_ip != NULL) {
		xfs_refcache_purge_ip(target_ip);
		IRELE(target_ip);
	}
	/*
	 * Let interposed file systems know about removed links.
	 */
	if (target_ip_dropped) {
		VOP_LINK_REMOVED(XFS_ITOV(target_ip), target_dir_vp,
					target_link_zero);
		IRELE(target_ip);
	}

	FSC_NOTIFY_NAME_CHANGED(XFS_ITOV(src_ip));

	IRELE(src_ip);

	/* Fall through to std_return with error = 0 or errno from
	 * xfs_trans_commit	 */
std_return:
	if (DM_EVENT_ENABLED(src_dir_vp->v_vfsp, src_dp, DM_EVENT_POSTRENAME) ||
	    DM_EVENT_ENABLED(target_dir_vp->v_vfsp,
				target_dp, DM_EVENT_POSTRENAME)) {
		(void) XFS_SEND_NAMESP (mp, DM_EVENT_POSTRENAME,
					src_dir_vp, DM_RIGHT_NULL,
					target_dir_vp, DM_RIGHT_NULL,
					src_name, target_name,
					0, error, 0);
	}
	return error;

 abort_return:
	cancel_flags |= XFS_TRANS_ABORT;
	/* FALLTHROUGH */
 error_return:
	xfs_bmap_cancel(&free_list);
	xfs_trans_cancel(tp, cancel_flags);
	goto std_return;

 rele_return:
	IRELE(src_ip);
	if (target_ip != NULL) {
		IRELE(target_ip);
	}
	goto std_return;
}