--- smbfs_vnops.c.DIST Sun Apr 21 21:18:58 2002 +++ smbfs_vnops.c Fri Dec 27 19:45:35 2002 @@ -340,6 +340,113 @@ return 0; } +/*XXX code stloen from NFS */ +static struct buf * smb_getcacheblk(struct vnode *vp, daddr_t bn, + int size, struct proc * p); +int smb_meta_setsize(struct vnode *vp, struct ucred *cred, + struct proc *p, u_quad_t nsize); + +/* + * Get an smb [was nfs] cache block. + * + * Allocate a new one if the block isn't currently in the cache + * and return the block marked busy. If the calling process is + * interrupted by a signal for an interruptible mount point, return + * NULL. + * + * The caller must carefully deal with the possible B_INVAL state of + * the buffer. nfs_doio() clears B_INVAL (and nfs_asyncio() clears it + * indirectly), so synchronous reads can be issued without worrying about + * the B_INVAL state. We have to be a little more careful when dealing + * with writes (see comments in nfs_write()) when extending a file past + * its EOF. + */ + +static struct buf * +smb_getcacheblk(vp, bn, size, p) + struct vnode *vp; + daddr_t bn; + int size; + struct proc *p; +{ + register struct buf *bp; + struct mount *mp; + struct smbmount *nmp; + + mp = vp->v_mount; +#if 0 + nmp = VTOSMB(mp); +#else + nmp = NULL; +#endif + +#if 0 + if (nmp && nmp->nm_flag & NFSMNT_INT) { + bp = getblk(vp, bn, size, PCATCH, 0); + while (bp == (struct buf *)0) { + if (nfs_sigintr(nmp, (struct nfsreq *)0, p)) + return ((struct buf *)0); + bp = getblk(vp, bn, size, 0, 2 * hz); + } + } else +#endif + { + bp = getblk(vp, bn, size, 0, 0); + } + + if (vp->v_type == VREG) { + int biosize; + + biosize = mp->mnt_stat.f_iosize; + bp->b_blkno = bn * (biosize / DEV_BSIZE); + } + return (bp); +} + +/* + * Used to aid in handling ftruncate() operations on the NFS client side. + * Truncation creates a number of special problems for NFS. We have to + * throw away VM pages and buffer cache buffers that are beyond EOF, and + * we have to properly handle VM pages or (potentially dirty) buffers + * that straddle the truncation point. + */ + +int +smb_meta_setsize(struct vnode *vp, struct ucred *cred, struct proc *p, u_quad_t nsize) +{ + struct smbnode *np = VTOSMB(vp); + u_quad_t tsize = np->n_size; + int biosize = vp->v_mount->mnt_stat.f_iosize; + int error = 0; + + np->n_size = nsize; + + if (np->n_size < tsize) { + struct buf *bp; + daddr_t lbn; + int bufsize; + + /* + * vtruncbuf() doesn't get the buffer overlapping the + * truncation point. We may have a B_DELWRI and/or B_CACHE + * buffer that now needs to be truncated. + */ + error = vtruncbuf(vp, cred, p, nsize, biosize); + lbn = nsize / biosize; + bufsize = nsize & (biosize - 1); + bp = smb_getcacheblk(vp, lbn, bufsize, p); + if (bp->b_dirtyoff > bp->b_bcount) + bp->b_dirtyoff = bp->b_bcount; + if (bp->b_dirtyend > bp->b_bcount) + bp->b_dirtyend = bp->b_bcount; + bp->b_flags |= B_RELBUF; /* don't leave garbage around */ + brelse(bp); + } else { + vnode_pager_setsize(vp, nsize); + } + return(error); +} + static int smbfs_setattr(ap) struct vop_setattr_args /* { @@ -383,7 +490,10 @@ if (isreadonly) return EROFS; doclose = 0; + vnode_pager_setsize(vp, (u_long)vap->va_size); + smb_meta_setsize(vp, ap->a_cred, ap->a_p, vap->va_size); + tsize = np->n_size; np->n_size = vap->va_size; if (np->n_opencount == 0) {