⭐ 欢迎来到虫虫下载站! | 📦 资源下载 📁 资源专辑 ℹ️ 关于我们
⭐ 虫虫下载站

📄 nfs_vnodeops.c

📁 <B>Digital的Unix操作系统VAX 4.2源码</B>
💻 C
📖 第 1 页 / 共 4 页
字号:
	}	if (error == 0)				/* XXX */		error = u.u_error;		/* XXX */bad:	return (error);}/* * Write to a remote file. * Writes to remote server in largest size chunks that the server can * handle.  Write is synchronous from the client's point of view. */intnfswrite(bp, vp, base, offset, count, cred, blockio)	struct buf *bp;	struct vnode *vp;	caddr_t base;	int offset;	int count;	struct ucred *cred;	int blockio;	/* Block I/O?:			 *   1 (NFS_BLOCKIO) if called by do_bio(),			 *   0 (NFS_NOT_BLOCKIO) if called directly by rwvp(),			 *     i.e. NFS locked files.			 */{	register struct rnode *rp = vtor(vp);	int error;	struct nfswriteargs wa;	struct nfsattrstat *ns;	int tsize;	int async = 0;	/*	 * Check for write-behind (asynchronous) errors, and	 * throw this request away if there has been one.	 */	error = rp->r_error; /* N.B.: gnode may not be locked here */	if (error) {		bp->b_error = error;		bp->b_flags |= B_ERROR;		if (blockio)	/* If doing block I/O, free the buffer */			iodone(bp);		return(error);	}			kmem_alloc(ns, struct nfsattrstat *, (u_int)sizeof(*ns), KM_NFS);	do {		tsize = min(vtomi(vp)->mi_stsize, count);		wa.wa_data = base;		wa.wa_fhandle = *vtofh(vp);		wa.wa_begoff = offset;		wa.wa_totcount = tsize;		wa.wa_count = tsize;		wa.wa_offset = offset;		error = rfscall(vtomi(vp), RFS_WRITE, xdr_writeargs,				(caddr_t)&wa, xdr_attrstat, (caddr_t)ns, cred);		if (!error) {			error = geterrno(ns->ns_status);			check_stale_fh(error, vp);		}		count -= tsize;		base += tsize;		offset += tsize;	} while (!error && count);	if (bp->b_flags & B_ASYNC)		async = 1;	if (error) {		bp->b_error = error;		bp->b_flags |= B_ERROR;			}	/*	 * N.B. It's easy to forget (or not understand in the first place)	 * that an async write is handled by a	 * biod only if there is one available; if there isn't, then	 * the calling process gets blocked. This can be the process	 * actually doing writes, the update daemon, or some completely 	 * random victim that stumbled into a DELWRI buffer.	 * Synchronous writes can be the writing (or nfs_fsync()'ing) process	 * or a random buffer cache victim.	 * Thus, the gnode may or may not be held locked by the calling	 * process. This can cause deadlock problems between	 * buffers and gnodes.	 * 	 * The general gnode/buffer rule to avoid deadlocks is:	 * 	`Don't hold a buffer busy while attempting to lock a gnode.'	 *	 * This is why we free the buffer before calling nfs_attrcache().	 * If the write fails and it was asynchronous all future writes will	 * get an error. We must do the rp->r_error assignment before	 * releasing the buffer for proper nfs_fsync() synchronization, but	 * can't get the gnode lock since we could deadlock. 	 *	 * Although it would be desirable to never throw attributes away,	 * there is a (hopefully rare) deadlock case where we are	 * writing for the random victim which may have anything locked.	 * In this case, we must throw attributes away.	 * 	 * Since trying to account for all write buffers leads to deadlocks,	 * we rely on the RDIRTY flag used by nfs_fsync() when reconciling	 * file attributes in nfs_attrcache().	 * When we release buffers here, that frees nfs_fsync() to complete	 * and reset RDIRTY before async write processes (which would	 * block on vp) have run through nfs_attrcache().	 * So as to not create a race with nfs_attrcache() which could	 * result in confused file attributes, we never call	 * it on behalf of async writes.	 */	if (error && async)		rp->r_error = error;	/*	 * Free the buffer and rely on nfs_attrcache() to worry about	 * races with other processes that provide fresher attributes	 * than ours.	 */	if (blockio)	/* If doing block I/O, free the buffer */		iodone(bp);	/* Never cache async or error attributes */	if (!async && !error)		nfs_attrcache(vp, &ns->ns_attr, NOFLUSH);	kmem_free(ns, KM_NFS);	switch (error) {	      case 0:	      case EDQUOT:		break;	      case ENOSPC:		printf("NFS write error, server %s, remote file system full\n",		   vtomi(vp)->mi_hostname);		break;	      default:		printf("NFS write error %d on host %s fh ", error, vtomi(vp)->mi_hostname);		printfhandle((caddr_t)vtofh(vp));		printf("\n");		break;	}	return (error);}/* * Print a file handle */printfhandle(fh)	caddr_t fh;{	int i;	int fhint[NFS_FHSIZE / sizeof (int)];	bcopy(fh, (caddr_t)fhint, sizeof (fhint));	for (i = 0; i < (sizeof (fhint) / sizeof (int)); i++) {		printf("%x ", fhint[i]);	}}/* * Read from a remote file. * Reads data in largest chunks our interface can handle */intnfsread(bp, vp, base, offset, count, cred, blockio)	struct buf *bp;	struct vnode *vp;	caddr_t base;	int offset;	int count;	struct ucred *cred;	int blockio;	/* Block I/O?:			 *   1 (NFS_BLOCKIO) if called by do_bio(),			 *   0 (NFS_NOT_BLOCKIO) if called by rwvp(),			 *     i.e. NFS locked files.			 */{	int error;	struct nfsreadargs ra;	struct nfsrdresult rr;	register int tsize;	do {		tsize = min(vtomi(vp)->mi_tsize, count);		rr.rr_data = base;		ra.ra_fhandle = *vtofh(vp);		ra.ra_offset = offset;		ra.ra_totcount = tsize;		ra.ra_count = tsize;		++nfs_rfsread_count;		error = rfscall(vtomi(vp), RFS_READ, xdr_readargs,				(caddr_t)&ra, xdr_rdresult,				(caddr_t)&rr, cred);		if (!error) {			error = geterrno(rr.rr_status);			check_stale_fh(error, vp);		}		if (!error) {			count -= rr.rr_count;			base += rr.rr_count;			offset += rr.rr_count;		}	} while (!error && count && rr.rr_count == tsize);	if (error) {		bp->b_error = error;		bp->b_flags |= B_ERROR;	} else if (count) {		bzero(bp->b_un.b_addr + bp->b_bcount - count,		      (u_int)count);	}	/*	 * The gnode may or may not be held locked by the calling	 * process. This can cause lock ordering problems	 * between buffers and gnodes. We free the buffer in all cases	 * and rely on nfs_attrcache() to worry about races with	 * other processes that provide fresher attributes than ours.	 */	if (blockio)	/* If doing block I/O, free the buffer */		iodone(bp);	if (!error) {		nfs_attrcache(vp, &rr.rr_attr, SFLUSH);	}		return (error);}int binval_debug = 0;/* returns true if attributes are strictly newer, not equal */#define ATTR_NEW(vp, na) (((na)->na_mtime.tv_sec > (vp)->g_mtime.tv_sec) ||   \		          ((na)->na_mtime.tv_sec == (vp)->g_mtime.tv_sec &&   \		 	   (na)->na_mtime.tv_usec > (vp)->g_mtime.tv_usec) || \			  ((na)->na_ctime.tv_sec > (vp)->g_ctime.tv_sec) ||   \			  ((na)->na_ctime.tv_sec == (vp)->g_ctime.tv_sec &&   \		 	   (na)->na_ctime.tv_usec > (vp)->g_ctime.tv_usec))/* returns true if modify time is strictly older and change time is equal */#define ATTR_OLD(vp, na) ((((na)->na_mtime.tv_sec < (vp)->g_mtime.tv_sec) ||  \		           ((na)->na_mtime.tv_sec == (vp)->g_mtime.tv_sec &&  \		 	    (na)->na_mtime.tv_usec < (vp)->g_mtime.tv_usec))&&\			  ((na)->na_ctime.tv_sec == (vp)->g_ctime.tv_sec  && \			   (na)->na_ctime.tv_usec == (vp)->g_ctime.tv_usec))/* returns true if attributes are strictly equal */#define ATTR_SAME(vp, na) ((na)->na_mtime.tv_sec == (vp)->g_mtime.tv_sec   && \		           (na)->na_mtime.tv_usec == (vp)->g_mtime.tv_usec && \			   (na)->na_ctime.tv_sec == (vp)->g_ctime.tv_sec   && \		           (na)->na_ctime.tv_usec == (vp)->g_ctime.tv_usec)intnfs_attrcache(vp, na, fflag)	register struct vnode *vp;	register struct nfsfattr *na;	enum staleflush fflag;{	register struct rnode *rp = vtor(vp);	int oldsize;	int need_lock;	char *s;	if (binval_debug) {		if (glocked((struct gnode *)vp) == LK_TRUE)			s = "locked";		else			s = "!locked";		mprintf("attr: 0x%x %s %s %s\n ntime %d %d nsize %d\n  time %d %d size %d\n",			vp, (vp->v_type == VREG)?"file":"!file",			(fflag)?"flush":"!flush",			s,			na->na_mtime.tv_sec, na->na_mtime.tv_usec,			na->na_size, 			vp->g_mtime.tv_sec, vp->g_mtime.tv_usec,			vp->g_size);	}  	/*	 * Lock the gnode if it's not already locked	 * (asynchronous I/O is one way for vp to be unlocked,	 * see nfswrite() comments for others).	 */	if (glocked(vp) != LK_TRUE) {		need_lock = 1;		gfs_lock((struct gnode *)vp);		/*		 * If we lose a race to update attributes,		 * throw these away.		 */		if (ATTR_OLD(vp, na)) /* strictly old, not equal */		       goto done;	}	else { /* we have the gnode locked already */		need_lock = 0;	}	if (binval_debug) {		mprintf("cache: 0x%x %s %s %s\n ntime %d %d nsize %d\n  time %d %d size %d\n",			vp, (vp->v_type == VREG)?"file":"!file",			(fflag)?"flush":"!flush",			s,			na->na_mtime.tv_sec, na->na_mtime.tv_usec,			na->na_size, 			vp->g_mtime.tv_sec, vp->g_mtime.tv_usec,			vp->g_size);	}        /*	 * Check the new modify time against the old modify time	 * to see if cached data is stale	 */	if (na->na_mtime.tv_sec != vp->g_mtime.tv_sec ||	    na->na_mtime.tv_usec != vp->g_mtime.tv_usec) {		/*		 * The file has changed on the server.		 *		 * If this was unexpected (SFLUSH), and we are not actively		 * modifying the file ourselves,		 * then flush delayed write blocks associated with this vnode		 * from the buffer cache and invalidate cached blocks		 * on the free list.		 *		 * If this is a text file, stop running copies.		 *		 * If this is a directory, purge the name lookup cache.		 */		if (fflag == SFLUSH && !(rp->r_flags & RDIRTY)) {			if (binval_debug) {				mprintf("do binvalfree\n");			}  			binvalfree((struct gnode *)vp);		}		/* if it is a text, clean out running procs and vm */		if (vp->v_flag & VTEXT) {			xinval((struct gnode *)vp);			cacheinval((struct gnode *)vp);			/* binval((dev_t)NODEV, (struct gnode *)vp); */		}		if (vp->v_type == VDIR)					dnlc_purge_vp(vp);	}	/*	 * Copy the new attributes into the gnode and timestamp them.	 *	 * Any writes caused by binvalfree() call above will be async,	 * so those returned attributes will be discarded.	 * If this thread didn't have the gnode locked coming in,	 * when we got it above, we would have discarded old attributes.	 * The only way (famous last words) we can now have old attributes	 * is if we lost a race getting the gnode again after going to the	 * wire in nfs_getattr().	 *	 * There is some weirdness with the gnode size here.  We must	 * keep the old size if the file has unaccounted writes and	 * the old size is greater than the new size, since these writes	 * may make the file grow.	 *	 */	if (!(ATTR_OLD(vp, na))) {		oldsize = vp->g_size;		nattr_to_gattr(vp, na);		if (oldsize > vp->g_size) { /* our size > server size */		 	/* Keep our size if there are writes outstanding. */			if (rp->r_flags & RDIRTY) {				vp->g_size = oldsize;			}		}	}	/* 	 * If no attributes caching, ignore time-to-life of attributes.	 */	if (!(vtomi(vp)->mi_noac)) {		nfs_ttlattr(vp, na);	} done:	if (need_lock)		gfs_unlock((struct gnode *)vp);}	intnfs_ttlattr(vp, na)	register struct vnode *vp;	register struct nfsfattr *na;{	register int delta;	register struct rnode *rp = vtor(vp);	/* ***It is assumed that vp is locked by caller*** */	rp->r_nfsattrtime = *(timepick);	/*	 * Delta is the number of seconds that we will cache	 * attributes of the file.  It is based on the number of seconds	 * since the last change (i.e. files that changed recently	 * are likely to change soon), but there is a minimum and	 * a maximum for regular files and for directories.	 */	delta = (timepick->tv_sec - na->na_mtime.tv_sec) >> 4;	if (vp->v_type == VDIR) {		if (delta < vtomi(vp)->mi_acdirmin) {			delta = vtomi(vp)->mi_acdirmin;		} else if (delta > vtomi(vp)->mi_acdirmax) {			delta = vtomi(vp)->mi_acdirmax;		}	} else {		if (delta < vtomi(vp)->mi_acregmin) {			delta = vtomi(vp)->mi_acregmin;		} else if (delta > vtomi(vp)->mi_acregmax) {			delta = vtomi(vp)->mi_acregmax;		}	}	rp->r_nfsattrtime.tv_sec += delta;}intnfs_getattr(vp, cred)	struct vnode *vp;	struct ucred *cred;{	register struct rnode *rp = vtor(vp);	int error;	struct nfsattrstat *ns;	int locked = 0;	if (!vtomi(vp)->mi_noac) { /* i.e. maybe use cached attributes */		if ((timepick->tv_sec < rp->r_nfsattrtime.tv_sec) ||		    ((timepick->tv_sec == rp->r_nfsattrtime.tv_sec) && 		    (timepick->tv_usec < rp->r_nfsattrtime.tv_usec))) {				/*				 * Use cached attributes.				 */				return (0);		}	}	if (rp->r_flags & RDIRTY) {		nfs_fsync(vp); /* nfs_fsync() goes directly to the wire */	}	kmem_alloc(ns, struct nfsattrstat *, (u_int)sizeof(*ns), KM_NFS);	/* don't hold gnode locked while going over the wire */	if (glocked((struct gnode *)vp) == LK_TRUE) {		locked = 1;		gfs_unlock((struct gnode *)vp);	}	error = rfscall(vtomi(vp), RFS_GETATTR, xdr_fhandle,			(caddr_t)vtofh(vp), xdr_attrstat, (caddr_t)ns, cred);	/* lock gnode again if it was locked coming in */	if (locked)		gfs_lock((struct gnode *)vp);	if (!error) {		error = geterrno(ns->ns_status);		if (!error) {			nfs_attrcache(vp, &ns->ns_attr, SFLUSH);		}		else {			check_stale_fh(error, vp);		}	}	kmem_free(ns, KM_NFS);	return (error);}intnfs_setattr(vp, vap, cred)	register struct vnode *vp;	register struct vattr *vap;	struct ucred *cred;{	register struct rnode *rp = vtor(vp);	int error;	struct nfssaargs args;	struct nfsattrstat *ns;	kmem_alloc(ns, struct nfsattrstat *, (u_int)sizeof(*ns), KM_NFS);	if ((vap->va_nlink != -1) || (vap->va_blocksize != -1) ||	    (vap->va_rdev != -1) || (vap->va_blocks != -1) ||	    (vap->va_ctime.tv_sec != -1) || (vap->va_ctime.tv_usec != -1)) {		error = EINVAL;	} else {		if (rp->r_flags & RDIRTY) {			nfs_fsync(vp); /* NB: nfs_getattr() will unlock vp */		}		if (vap->va_size != (u_long) -1) {

⌨️ 快捷键说明

复制代码 Ctrl + C
搜索代码 Ctrl + F
全屏模式 F11
切换主题 Ctrl + Shift + D
显示快捷键 ?
增大字号 Ctrl + =
减小字号 Ctrl + -