📄 nfs_vnodeops.c
字号:
#ifndef lintstatic char *sccsid = "@(#)nfs_vnodeops.c 4.10 (ULTRIX) 4/25/91";#endif lint/************************************************************************ * * * Copyright (c) 1990 by * * Digital Equipment Corporation, Maynard, MA * * All rights reserved. * * * * This software is furnished under a license and may be used and * * copied only in accordance with the terms of such license and * * with the inclusion of the above copyright notice. This * * software or any other copies thereof may not be provided or * * otherwise made available to any other person. No title to and * * ownership of the software is hereby transferred. * * * * This software is derived from software received from the * * University of California, Berkeley, and from Bell * * Laboratories. Use, duplication, or disclosure is subject to * * restrictions under license agreements with University of * * California and with AT&T. * * * * The information in this software is subject to change without * * notice and should not be construed as a commitment by Digital * * Equipment Corporation. * * * * Digital assumes no responsibility for the use or reliability * * of its software on equipment which is not supplied by Digital. * * * ************************************************************************//* * Portions of this software have been licensed to * Digital Equipment Company, Maynard, MA. * Copyright (c) 1986 Sun Microsystems, Inc. ALL RIGHTS RESERVED. *//* * * Modification history: * * 25 Apr 91 -- chet * Add access check in nfs_lookup() after dnlc hit. * * 28 Feb 91 -- dws * Clean up client view of fhandle. * * 27 Feb 91 -- chet * Fix client side attribute problems when modify time goes backwards. * * 15 Feb 91 * Fixed nfs_fsync for case where file size > (0x7fffffff - (blksize-1)). * * 10 Feb 91 -- chet * Change nfs_attrcache() calls (again). * * 29 Jan 91 -- chet * Make kernel RPC calls interruptible. * * 28 Oct 90 -- chet * Change nfs_fsync() scheme to keep rnode dirty and gp locked * during complete operation. * * 8-Sep-90 -- Fred * Transfer complete file handle to lock handle structure in nfs_rlock (). * * 7 Jul 90 -- chet * Change nfs_write(), nfs_fsync() and nfs_attrcache() schemes; * remove count of outstanding write buffers. * * 20 Jun 90 -- cb * Fix the attribute cache. * * 9 Mar 90 -- chet * Change nfs_fsync() and nfs_attrcache() schemes to * use a count of outstanding write buffers. * * 23-Feb-90 -- sekhar * Merged Joe Martin's fix for 3.1 cld. When copying user PTEs, * check for page crossing and reevaluate vtopte. * * 15 Feb 90 -- prs * Added referencing the gnode in nfs_strategy() before scheduling a * wakeup to a sleeping async daemon. This way, a biod will hold * a ref to a gnode even if the invoking process closes the file. * * 7 Feb 90 -- chet * Change asynch daemon work list scheme. * * 6 Feb 90 -- chet * Change block I/O gnode referencing and nfs_fsync() gnode * locking schemes. * * 2 Feb 90 -- chet * Change asynchronous I/O gnode and buffer synchronization * * 1 Feb 90 -- prs * Fixed leaf node caching into dnlc. * * 13 Dec 89 -- chet * Add attribute cache timeout values. * * 10 Dec 89 -- chet * Remove dnlc purge call for non-directories in nfs_attrcache. * * 05 Oct 89 -- prs * Added locking of the [vg]node to nfs_close(). * * 25 Jul 89 -- chet * Changes for new bflush() and faster cache invalidations * * 6 Mar 89 -- chet * Put regular files into dnlc; make size of dnlc a function * of system size. * * 06 Feb 89 -- prs * Modified nfs_readdir() and nfs_close() to set u.u_error before * returning with an error value. These routines are called by * GFS directly, and assumed to set u.u_error before returning. * * 21 Nov 88 -- condylis * Added freeing of vnode credential to nfs_inactive. * * 07 Nov 88 -- dgg * Corrected calculation of pte from proc pointer in nfs_strategy. * [ dgg001 ] * * 28 Sep 88 -- chet * Put R_IN_FSYNC define where it belongs (vnode.h) * * 1 Sep 88 -- chet * Set u.u_error after a failed rfscall to readdir * * 5 Aug 88 -- condylis * Merge of 2.4 changes. Minimize number of calls to vtor and * check change in file size in nfs_attrcache. * * 18 Jul 88 -- condylis * Add SMP locking for bio daemon buffer list and async_daemon_count * variable. dnlc_lookup now bumps ref count of returned gnode; * removed VN_HOLD after call. Replaced unsafe modification of gnodes * with calls to SMP gnode primitives. * * 2 Mar 88 -- chet * Add RNOCACHE stuff for locked files to rwvp(). * * 4 Feb 88 -- chet for cb * add fifo mode fix in nfs_create() * * 26 Jan 88 -- chet * Put access check in nfs_getdirent(); lock gnode before doing * the access check to synchronize with any other process that has * it locked. * * 12 Jan 88 - Fred Glover * Add routine nfs_rlock for Sys-V file locking. * * 12-11-87 Robin L. and Larry C. and Ricky P. * Added new kmalloc memory allocation to system. * * 14 Jul 87 -- cb * added in rr's changes to remote execution. * * 14 Jul 87 -- chet * Changed binval() calls to binvalfree() calls in nfs_attrcache() * and nfs_close(). * * 16 Jun 87 -- cb * Added check to biod code to die gracefully on termination. * * 12 May 87 -- chet * Added commented check for opening special files. * * 11-May-87 -- logcher * Removed the mpurge which had wrong logic anyways. Does * not gain much if right logic was there. * * 02-Mar-87 -- logcher * Merged in diskless changes, removed an unused argument from * nfs_create, added support for mknod of non-regular files, * added code to support swapping to an NFS file. */#include "../h/param.h"#include "../h/mount.h"#include "../h/systm.h"#include "../h/user.h"#include "../h/gnode.h"#include "../h/file.h"#include "../h/uio.h"#include "../h/buf.h"#include "../h/kernel.h"#include "../h/cmap.h"#include "../h/proc.h"#include "../h/ipc.h"#include "../h/shm.h"#include "../h/vmmac.h"#include "../net/netinet/in.h"#include "../net/rpc/types.h"#include "../net/rpc/auth.h"#include "../net/rpc/clnt.h"#include "../net/rpc/xdr.h"#include "../nfs/nfs.h"#include "../nfs/nfs_clnt.h"#include "../nfs/vfs.h"#include "../nfs/vnode.h"#include "../h/fs_types.h"#include "../net/rpc/lockmgr.h"/* SMP lock for biod bfr list */struct lock_t lk_nfsbiod;/* MPC Counter to monitor wasted biod wakeups */int biod_has_work;int biod_has_no_work;struct vnode *makenfsnode();struct vnode *dnlc_lookup();char *newname();int nfs_dnlc = 1;#define check_stale_fh(errno, vp) if ((errno) == ESTALE) { dnlc_purge_vp(vp); }#define nfsattr_inval(vp) (vtor(vp)->r_nfsattrtime.tv_sec = 0)#define ISVDEV(t) ((t == VBLK) || (t == VCHR) || (t == VFIFO))/* * These are the vnode ops routines which implement the vnode interface to * the networked file system. These routines just take their parameters, * make them look networkish by putting the right info into interface structs, * and then calling the appropriate remote routine(s) to do the work. * * Note on directory name lookup cacheing: we desire that all operations * on a given client machine come out the same with or without the cache. * This is the same property we have with the disk buffer cache. In order * to guarantee this, we serialize all operations on a given directory, * by using lock and unlock around rfscalls to the server. This way, * we cannot get into races with ourself that would cause invalid information * in the cache. Other clients (or the server itself) can cause our * cached information to become invalid, the same as with data buffers. * Also, if we do detect a stale fhandle, we purge the directory cache * relative to that vnode. This way, the user won't get burned by the * cache repeatedly. */intnfs_open(vp, flag) register struct vnode *vp; int flag;{ register struct ucred *cred = u.u_cred; register int error; /* * refresh cached attributes */ nfsattr_inval(vp); error = nfs_getattr(vp, cred); if (!error) { vtor(vp)->r_flags |= ROPEN; } return (error);}intnfs_close(vp, flag) register struct vnode *vp; int flag;{ register struct ucred *cred = u.u_cred; register struct rnode *rp = vtor(vp); gfs_lock(vp); rp->r_flags &= ~ROPEN; /* * If this is a close of a file open for writing or an unlinked * open file or a file that has had an asynchronous write error, * flush synchronously. This allows us to invalidate the file's * buffers if there was a write error or the file was unlinked. */ if (flag & FWRITE || rp->r_unldvp != NULL || rp->r_error) { (void) nfs_fsync(vp); /* NB: nfs_getattr() will unlock vp */ } if (rp->r_unldvp != NULL || rp->r_error) { cacheinval((struct gnode *)vp); /* binvalfree((struct gnode *)vp); */ dnlc_purge_vp(vp); } gfs_unlock(vp); if (flag & FWRITE) { /* r_error is never cleared on a ref'd gnode */ u.u_error = rp->r_error; return; }}int nfs_read_incore = 0;int nfs_read_not_incore = 0;int nfs_bread1 = 0;int nfs_breada1 = 0;int nfs_bread2 = 0;int nfs_rfsread_count = 0;intrwvp(vp, uio, rw, ioflag) register struct vnode *vp; register struct uio *uio; enum uio_rw rw; int ioflag;{ register struct buf *bp; register struct rnode *rp = vtor(vp); register int n, on, size; daddr_t bn, mapped_bn, mapped_rabn; int eof = 0; int error = 0; if (uio->uio_resid == 0) { return (0); } if (uio->uio_offset < 0 || (uio->uio_offset + uio->uio_resid) < 0) { return (EINVAL); } if (rw == UIO_WRITE && vp->v_type == VREG && uio->uio_offset + uio->uio_resid > u.u_rlimit[RLIMIT_FSIZE].rlim_cur) { psignal(u.u_procp, SIGXFSZ); return (EFBIG); } size = vtoblksz(vp); size &= ~(DEV_BSIZE - 1); if (size <= 0) { panic("rwvp: zero size"); } do { bn = uio->uio_offset / size; on = uio->uio_offset % size; n = MIN((unsigned)(size - on), uio->uio_resid); nfs_bmap(vp, bn, &mapped_bn); /* Don't use cache for RNOCACHE reads */ if (rp->r_flags & RNOCACHE) { bp = geteblk(size); if (rw == UIO_READ) { error = nfsread(bp, vp, bp->b_un.b_addr+on, uio->uio_offset, n, u.u_cred, NFS_NOT_BLOCKIO); if (error) { brelse(bp); goto bad; } } } else if (rw == UIO_READ) { if (incore(vp->g_dev, mapped_bn, vp)) { /* * get attributes to check whether in * core data is stale */ ++nfs_read_incore; (void) nfs_getattr(vp, u.u_cred); } else ++nfs_read_not_incore; if (vp->g_lastr + 1 == bn) { nfs_bmap(vp, bn + 1, &mapped_rabn); ++nfs_breada1; bp = breada(vp->g_dev, mapped_bn, size, mapped_rabn, size, vp); } else { ++nfs_bread1; bp = bread(vp->g_dev, mapped_bn, size, vp); } } else { /* (rw == UIO_WRITE) */ struct gnode *gp = (struct gnode *) (vp); if (rp->r_error) { error = rp->r_error; goto bad; } if (gp->g_textp) xuntext(gp->g_textp); if (n == size) { bp = getblk(vp->g_dev, mapped_bn, size, vp); } else { ++nfs_bread2; bp = bread(vp->g_dev, mapped_bn, size, vp); } }/* CJXXX */ if (bp->b_flags & B_ERROR) { error = geterror(bp); brelse(bp); goto bad; } /* * The following code was moved down here when RNOCACHE * was put in so that both cached and non-cached reads * fall through. */ if (rw == UIO_READ) { int diff; vp->g_lastr = bn; diff = vp->g_size - uio->uio_offset; if (diff < n) { if (diff <= 0) { brelse(bp); return(0); } n = diff; eof = 1; } } u.u_error = uiomove(bp->b_un.b_addr+on, n, rw, uio); if (rw == UIO_READ) { if (rp->r_flags & RNOCACHE) bp->b_flags |= B_NOCACHE; brelse(bp); } else { /* (rw == UIO_WRITE) */ /* * g_size is the maximum number of bytes known * to be in the file. * Make sure it is at least as high as the last * byte we just wrote into the buffer. */ if (vp->g_size < uio->uio_offset) { vp->g_size = uio->uio_offset; } /* Don't cache any RNOCACHE writes */ if (rp->r_flags & RNOCACHE) { error = nfswrite(bp, vp, bp->b_un.b_addr+on, uio->uio_offset-n, n, u.u_cred, NFS_NOT_BLOCKIO); bp->b_flags |= B_NOCACHE; brelse(bp); } else { rp->r_flags |= RDIRTY; if (n + on == size) { bp->b_resid = 0; if ((ioflag & IO_SYNC) || vp->g_mp->m_flags & M_SYNC) bwrite(bp); else bawrite(bp); } else { /* * The bp->b_resid field is the number * of bytes in the buffer that are NOT * part of the file. We first compute * how many bytes beyond the end of * the file the last byte in the buffer * is (think about it). If the file * continues past the end of the block * then this value will be negative, * and we set it to zero since all the * bytes in the buffer are valid. The * result is used by nfswrite to decide * how many bytes to send to the * server. */ bp->b_resid = (size * (bn + 1)) - vp->g_size; if (bp->b_resid < 0) bp->b_resid = 0; if (ioflag & IO_SYNC || vp->g_mp->m_flags & M_SYNC) bwrite(bp); else { /* gid could have changed */ /* due to a cacheinval as */ /* part of bread() above; */ /* set gid so that buffer */ /* is not orphaned */ bp->b_gid = vp->g_id; bdwrite(bp); } } } } } while (u.u_error == 0 && uio->uio_resid > 0 && !eof); if (rw == UIO_WRITE && uio->uio_resid && u.u_error == 0) { printf("rwvp: short write. resid %d vp %x bn %d\n", uio->uio_resid, vp, bn);
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -