示例#1
0
文件: osi_vm.c 项目: hwr/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.  If it is dropped and re-acquired,
 *   *slept should be set to warn the caller.
 *
 * Formerly, afs_xvcache was dropped and re-acquired for Solaris, but now it
 * is not dropped and re-acquired for any platform.  It may be that *slept is
 * therefore obsolescent.
 */
int
osi_VM_FlushVCache(struct vcache *avc, int *slept)
{
    if (avc->vrefCount != 0)
	return EBUSY;

    if (avc->opens)
	return EBUSY;

    /* if a lock is held, give up */
    if (CheckLock(&avc->lock))
	return EBUSY;

    AFS_GUNLOCK();
    pvn_vplist_dirty(AFSTOV(avc), 0, NULL, B_TRUNC | B_INVAL, CRED());
    AFS_GLOCK();

    /* Might as well make the obvious check */
    if (AFSTOV(avc)->v_pages)
	return EBUSY;		/* should be all gone still */

    rw_destroy(&avc->rwlock);
    if (avc->credp) {
	crfree(avc->credp);
	avc->credp = NULL;
    }


    return 0;
}
示例#2
0
文件: osi_vm.c 项目: hwr/openafs
/* Try to invalidate pages, for "fs flush" or "fs flushv"; or
 * try to free pages, when deleting a file.
 *
 * Locking:  the vcache entry's lock is held.  It may be dropped and
 * re-obtained.
 */
void
osi_VM_TryToSmush(struct vcache *avc, afs_ucred_t *acred, int sync)
{
    AFS_GUNLOCK();
    (void)pvn_vplist_dirty(AFSTOV(avc), (u_offset_t) 0, afs_putapage,
			   (sync ? B_INVAL : B_FREE), acred);
    AFS_GLOCK();
}
示例#3
0
文件: osi_vm.c 项目: hwr/openafs
/* Try to store pages to cache, in order to store a file back to the server.
 *
 * Locking:  the vcache entry's lock is held.  It will usually be dropped and
 * re-obtained.
 */
void
osi_VM_StoreAllSegments(struct vcache *avc)
{
    AFS_GUNLOCK();
    (void)pvn_vplist_dirty(AFSTOV(avc), (u_offset_t) 0, afs_putapage, 0,
			   CRED());
    AFS_GLOCK();
}
示例#4
0
文件: osi_vm.c 项目: hwr/openafs
/* Purge pages beyond end-of-file, when truncating a file.
 *
 * Locking:  no lock is held, not even the global lock.
 * Pageins are blocked (activeV is raised).
 */
void
osi_VM_Truncate(struct vcache *avc, int alen, afs_ucred_t *acred)
{
    /*
     * It's OK to specify afs_putapage here, even though we aren't holding
     * the vcache entry lock, because it isn't going to get called.
     */
    pvn_vplist_dirty(AFSTOV(avc), alen, afs_putapage, B_TRUNC | B_INVAL,
		     acred);
}
示例#5
0
/*
 * The disk has been changed!
 */
void
pc_diskchanged(struct pcfs *fsp)
{
	struct pcnode	*pcp, *npcp = NULL;
	struct pchead	*hp;
	struct vnode	*vp;
	extern vfs_t	EIO_vfs;
	struct vfs	*vfsp;

	/*
	 * Eliminate all pcnodes (dir & file) associated with this fs.
	 * If the node is internal, ie, no references outside of
	 * pcfs itself, then release the associated vnode structure.
	 * Invalidate the in core FAT.
	 * Invalidate cached data blocks and blocks waiting for I/O.
	 */
	PC_DPRINTF1(1, "pc_diskchanged fsp=0x%p\n", (void *)fsp);

	vfsp = PCFSTOVFS(fsp);

	for (hp = pcdhead; hp < &pcdhead[NPCHASH]; hp++) {
		for (pcp = hp->pch_forw;
		    pcp != (struct pcnode *)hp; pcp = npcp) {
			npcp = pcp -> pc_forw;
			vp = PCTOV(pcp);
			if ((vp->v_vfsp == vfsp) &&
			    !(pcp->pc_flags & PC_RELEHOLD)) {
				mutex_enter(&(vp)->v_lock);
				if (vp->v_count > 0) {
					mutex_exit(&(vp)->v_lock);
					continue;
				}
				mutex_exit(&(vp)->v_lock);
				VN_HOLD(vp);
				remque(pcp);
				vp->v_data = NULL;
				vp->v_vfsp = &EIO_vfs;
				vp->v_type = VBAD;
				VN_RELE(vp);
				if (!(pcp->pc_flags & PC_EXTERNAL)) {
					(void) pvn_vplist_dirty(vp,
					    (u_offset_t)0, pcfs_putapage,
					    B_INVAL | B_TRUNC,
					    (struct cred *)NULL);
					vn_free(vp);
				}
				kmem_free(pcp, sizeof (struct pcnode));
				fsp->pcfs_nrefs --;
				VFS_RELE(vfsp);
			}
		}
	}
	for (hp = pcfhead; fsp->pcfs_frefs && hp < &pcfhead[NPCHASH]; hp++) {
		for (pcp = hp->pch_forw; fsp->pcfs_frefs &&
		    pcp != (struct pcnode *)hp; pcp = npcp) {
			npcp = pcp -> pc_forw;
			vp = PCTOV(pcp);
			if ((vp->v_vfsp == vfsp) &&
			    !(pcp->pc_flags & PC_RELEHOLD)) {
				mutex_enter(&(vp)->v_lock);
				if (vp->v_count > 0) {
					mutex_exit(&(vp)->v_lock);
					continue;
				}
				mutex_exit(&(vp)->v_lock);
				VN_HOLD(vp);
				remque(pcp);
				vp->v_data = NULL;
				vp->v_vfsp = &EIO_vfs;
				vp->v_type = VBAD;
				VN_RELE(vp);
				if (!(pcp->pc_flags & PC_EXTERNAL)) {
					(void) pvn_vplist_dirty(vp,
					    (u_offset_t)0, pcfs_putapage,
					    B_INVAL | B_TRUNC,
					    (struct cred *)NULL);
					vn_free(vp);
				}
				kmem_free(pcp, sizeof (struct pcnode));
				fsp->pcfs_frefs--;
				fsp->pcfs_nrefs--;
				VFS_RELE(vfsp);
			}
		}
	}
#ifdef undef
	if (fsp->pcfs_frefs) {
		rw_exit(&pcnodes_lock);
		panic("pc_diskchanged: frefs");
	}
	if (fsp->pcfs_nrefs) {
		rw_exit(&pcnodes_lock);
		panic("pc_diskchanged: nrefs");
	}
#endif
	if (!(vfsp->vfs_flag & VFS_UNMOUNTED) &&
	    fsp->pcfs_fatp != (uchar_t *)0) {
		pc_invalfat(fsp);
	} else {
		binval(fsp->pcfs_xdev);
	}
}
示例#6
0
/*
 * Truncate a file to a length.
 * Node must be locked.
 */
int
pc_truncate(struct pcnode *pcp, uint_t length)
{
	struct pcfs *fsp;
	struct vnode *vp;
	int error = 0;

	PC_DPRINTF3(4, "pc_truncate pcp=0x%p, len=%u, size=%u\n",
	    (void *)pcp, length, pcp->pc_size);
	vp = PCTOV(pcp);
	if (pcp->pc_flags & PC_INVAL)
		return (EIO);
	fsp = VFSTOPCFS(vp->v_vfsp);
	/*
	 * directories are always truncated to zero and are not marked
	 */
	if (vp->v_type == VDIR) {
		error = pc_bfree(pcp, 0);
		return (error);
	}
	/*
	 * If length is the same as the current size
	 * just mark the pcnode and return.
	 */
	if (length > pcp->pc_size) {
		daddr_t bno;
		uint_t llcn = howmany((offset_t)length, fsp->pcfs_clsize);

		/*
		 * We are extending a file.
		 * Extend it with _one_ call to pc_balloc (no holes)
		 * since we don't need to use the block number(s).
		 */
		if ((daddr_t)howmany((offset_t)pcp->pc_size, fsp->pcfs_clsize) <
		    (daddr_t)llcn) {
			error = pc_balloc(pcp, (daddr_t)(llcn - 1), 1, &bno);
		}
		if (error) {
			pc_cluster32_t ncl = 0;
			PC_DPRINTF1(2, "pc_truncate: error=%d\n", error);
			/*
			 * probably ran out disk space;
			 * determine current file size
			 */
			if (pc_fileclsize(fsp, pcp->pc_scluster, &ncl)) {
				PC_DPRINTF1(2, "cluster chain corruption, "
				    "scluster=%d\n", pcp->pc_scluster);
				pcp->pc_flags |= PC_INVAL;
			}
			pcp->pc_size = fsp->pcfs_clsize * ncl;
		} else
			pcp->pc_size = length;

	} else if (length < pcp->pc_size) {
		/*
		 * We are shrinking a file.
		 * Free blocks after the block that length points to.
		 */
		if (pc_blkoff(fsp, length) == 0) {
			/*
			 * Truncation to a block (cluster size) boundary only
			 * requires us to invalidate everything after the new
			 * end of the file.
			 */
			(void) pvn_vplist_dirty(PCTOV(pcp), (u_offset_t)length,
			    pcfs_putapage, B_INVAL | B_TRUNC, CRED());
		} else {
			/*
			 * pvn_vpzero() cannot deal with more than MAXBSIZE
			 * chunks. Since the FAT clustersize can get larger
			 * than that, we'll zero from the new length to the
			 * end of the cluster for clustersizes smaller than
			 * MAXBSIZE - or the end of the MAXBSIZE block in
			 * case we've got a large clustersize.
			 */
			size_t nbytes =
			    roundup(length, MIN(fsp->pcfs_clsize, MAXBSIZE)) -
			    length;

			pvn_vpzero(PCTOV(pcp), (u_offset_t)length, nbytes);
			(void) pvn_vplist_dirty(PCTOV(pcp),
			    (u_offset_t)length + nbytes,
			    pcfs_putapage, B_INVAL | B_TRUNC, CRED());
		}
		error = pc_bfree(pcp, (pc_cluster32_t)
		    howmany((offset_t)length, fsp->pcfs_clsize));
		pcp->pc_size = length;
	}

	/*
	 * This is the only place in PCFS code where pc_mark_mod() is called
	 * without setting PC_MOD. May be a historical artifact ...
	 */
	pc_mark_mod(fsp, pcp);
	return (error);
}
示例#7
0
void
pc_rele(struct pcnode *pcp)
{
	struct pcfs *fsp;
	struct vnode *vp;
	int err;

	vp = PCTOV(pcp);
	PC_DPRINTF1(8, "pc_rele vp=0x%p\n", (void *)vp);

	fsp = VFSTOPCFS(vp->v_vfsp);
	ASSERT(fsp->pcfs_flags & PCFS_LOCKED);

	rw_enter(&pcnodes_lock, RW_WRITER);
	pcp->pc_flags |= PC_RELEHOLD;

retry:
	if (vp->v_type != VDIR && (pcp->pc_flags & PC_INVAL) == 0) {
		/*
		 * If the file was removed while active it may be safely
		 * truncated now.
		 */

		if (pcp->pc_entry.pcd_filename[0] == PCD_ERASED) {
			(void) pc_truncate(pcp, 0);
		} else if (pcp->pc_flags & PC_CHG) {
			(void) pc_nodeupdate(pcp);
		}
		err = syncpcp(pcp, B_INVAL);
		if (err) {
			(void) syncpcp(pcp, B_INVAL | B_FORCE);
		}
	}
	if (vn_has_cached_data(vp)) {
		/*
		 * pvn_vplist_dirty will abort all old pages
		 */
		(void) pvn_vplist_dirty(vp, (u_offset_t)0,
		    pcfs_putapage, B_INVAL, (struct cred *)NULL);
	}

	(void) pc_syncfat(fsp);
	mutex_enter(&vp->v_lock);
	if (vn_has_cached_data(vp)) {
		mutex_exit(&vp->v_lock);
		goto retry;
	}
	ASSERT(!vn_has_cached_data(vp));

	vp->v_count--;  /* release our hold from vn_rele */
	if (vp->v_count > 0) { /* Is this check still needed? */
		PC_DPRINTF1(3, "pc_rele: pcp=0x%p HELD AGAIN!\n", (void *)pcp);
		mutex_exit(&vp->v_lock);
		pcp->pc_flags &= ~PC_RELEHOLD;
		rw_exit(&pcnodes_lock);
		return;
	}

	remque(pcp);
	rw_exit(&pcnodes_lock);
	/*
	 * XXX - old code had a check for !(pcp->pc_flags & PC_INVAL)
	 * here. Seems superfluous/incorrect, but then earlier on PC_INVAL
	 * was never set anywhere in PCFS. Now it is, and we _have_ to drop
	 * the file reference here. Else, we'd screw up umount/modunload.
	 */
	if ((vp->v_type == VREG)) {
		fsp->pcfs_frefs--;
	}
	fsp->pcfs_nrefs--;
	VFS_RELE(vp->v_vfsp);

	if (fsp->pcfs_nrefs < 0) {
		panic("pc_rele: nrefs count");
	}
	if (fsp->pcfs_frefs < 0) {
		panic("pc_rele: frefs count");
	}

	mutex_exit(&vp->v_lock);
	vn_invalid(vp);
	vn_free(vp);
	kmem_free(pcp, sizeof (struct pcnode));
}
示例#8
0
/************************************************************************
 * iumfs_free_node()
 *
 *   指定された vnode および iumnode を解放する
 *
 *     1. iumnode に関連づいたリソースを解放
 *     2. iumnode 構造体を解放
 *     3. vnode 構造体を解放
 *
 *   これが呼ばれるのは、iumfs_inactive() もしくは iumfs_unmount() 経由の
 *   iumfs_free_all_node() だけ。つまり、v_count が 1(未参照状態)である
 *   事が確かな場合だけ。
 *
 * 引数:
 *
 *     vp: 解放する vnode 構造体のポインタ
 *     cr    : システムコールを呼び出したユーザのクレデンシャル
 *
 * 戻り値:
 *     無し
 *
 ************************************************************************/
void
iumfs_free_node(vnode_t *vp, struct cred *cr)
{
    iumnode_t *inp; // ファイルシステム型依存のノード情報(iumnode構造体)
    vnode_t *rootvp; // ファイルシステムのルートディレクトリの vnode。
    iumfs_t *iumfsp; // ファイルシステム型依存のプライベートデータ構造体
    vfs_t *vfsp; // ファイルシステム構造体
    int err;

    DEBUG_PRINT((CE_CONT, "iumfs_free_node is called\n"));

    iumfsp = VNODE2IUMFS(vp);
    vfsp = VNODE2VFS(vp);
    inp = VNODE2IUMNODE(vp);

    DEBUG_PRINT((CE_CONT, "iumfs_free_node: vnode=%p, vp->v_count=%d\n", vp, vp->v_count));

    /*
     * 最初にノードリンクリストから iumnode をはずす。誰かが利用中(EBUSY)だったらリターン。
     * 仮にノードリストに入っていなかったとしても、(ありえないはずだが) vnode のフリーは行う。
     */
    if((err = iumfs_remove_node_from_list(vfsp, vp)) != 0){
        if (err == ENOENT)
            cmn_err(CE_CONT, "iumfs_free_node: can't find vnode in the list. Free it anyway.\n");
        else
            return;
    }

    // debug 用
    rootvp = VNODE2ROOT(vp);
    if (rootvp != NULL && VN_CMP(rootvp, vp) != 0) {
        DEBUG_PRINT((CE_CONT, "iumfs_free_node: rootvnode is being freed\n"));
        mutex_enter(&(iumfsp->iumfs_lock));
        iumfsp->rootvnode = NULL;
        mutex_exit(&(iumfsp->iumfs_lock));
    }

    /*
     * もし iumnode にデータ(ディレクトリエントリ等)
     * を含んでいたらそれらも解放する。
     */
    if (inp->data != NULL) {
        kmem_free(inp->data, inp->dlen);
    }

    /*
     * この vnode に関連した page を無効にする
     */
    err = pvn_vplist_dirty(vp, 0, iumfs_putapage, B_INVAL, cr);
    DEBUG_PRINT((CE_CONT, "iumfs_free_node: pvn_vplist_dirty returned with (%d)\n", err));
    if (vn_has_cached_data(vp)) {
        cmn_err(CE_WARN, "iumfs_free_node: vnode still have cached\n");        
    } 

    // iumnode を解放
    mutex_destroy(&(inp)->i_dlock);
    rw_destroy(&(inp)->i_listlock);
    kmem_free(inp, sizeof (iumnode_t));

    // vnode を解放
#ifdef SOL10
    vn_free(vp);
#else
    mutex_destroy(&(vp)->v_lock);
    kmem_free(vp, sizeof (vnode_t));
#endif                
    DEBUG_PRINT((CE_CONT, "iumfs_free_node: return\n"));
    return;
}