- np->n_flag |= NMODIFIED;
- tsize = np->n_size;
-
- KERNEL_DEBUG((FSDBG_CODE(DBG_FSRW, 512)) | DBG_FUNC_START,
- (int)np->n_size, (int)vap->va_size, (int)np->n_vattr.va_size, np->n_flag, 0);
-
- if (vap->va_size == 0)
- error = nfs_vinvalbuf(vp, 0,
- ap->a_cred, ap->a_p, 1);
- else
- error = nfs_vinvalbuf(vp, V_SAVE,
- ap->a_cred, ap->a_p, 1);
-
- if (UBCISVALID(vp))
- ubc_setsize(vp, (off_t)vap->va_size); /* XXX check error */
-
- if (error) {
- printf("nfs_setattr: nfs_vinvalbuf %d\n", error);
-
-#if DIAGNOSTIC
- kprintf("nfs_setattr: nfs_vinvalbuf %d\n",
- error);
-#endif /* DIAGNOSTIC */
- if (UBCISVALID(vp))
- ubc_setsize(vp, (off_t)tsize); /* XXX check error */
-
- KERNEL_DEBUG((FSDBG_CODE(DBG_FSRW, 512)) | DBG_FUNC_END,
- (int)np->n_size, (int)vap->va_size, (int)np->n_vattr.va_size, -1, 0);
-
- return (error);
+ FSDBG_TOP(512, np->n_size, vap->va_size,
+ np->n_vattr.va_size, np->n_flag);
+ if (np->n_flag & NMODIFIED) {
+ if (vap->va_size == 0)
+ error = nfs_vinvalbuf(vp, 0,
+ ap->a_cred, ap->a_p, 1);
+ else
+ error = nfs_vinvalbuf(vp, V_SAVE,
+ ap->a_cred, ap->a_p, 1);
+ if (error) {
+ printf("nfs_setattr: nfs_vinvalbuf %d\n", error);
+ FSDBG_BOT(512, np->n_size, vap->va_size,
+ np->n_vattr.va_size, -1);
+ return (error);
+ }
+ } else if (np->n_size > vap->va_size) { /* shrinking? */
+ daddr_t obn, bn;
+ int biosize;
+ struct nfsbuf *bp;
+
+ biosize = vp->v_mount->mnt_stat.f_iosize;
+ obn = (np->n_size - 1) / biosize;
+ bn = vap->va_size / biosize;
+ for ( ; obn >= bn; obn--)
+ if (nfs_buf_incore(vp, obn)) {
+ bp = nfs_buf_get(vp, obn, biosize, 0, BLK_READ);
+ if (!bp)
+ continue;
+ if (obn == bn) {
+ int neweofoff, mustwrite;
+ mustwrite = 0;
+ neweofoff = vap->va_size - NBOFF(bp);
+ /* check for any dirty data before the new EOF */
+ if (bp->nb_dirtyend && bp->nb_dirtyoff < neweofoff) {
+ /* clip dirty range to EOF */
+ if (bp->nb_dirtyend > neweofoff)
+ bp->nb_dirtyend = neweofoff;
+ mustwrite++;
+ }
+ bp->nb_dirty &= (1 << round_page_32(neweofoff)/PAGE_SIZE) - 1;
+ if (bp->nb_dirty)
+ mustwrite++;
+ if (mustwrite) {
+ /* gotta write out dirty data before invalidating */
+ /* (NB_STABLE indicates that data writes should be FILESYNC) */
+ /* (NB_NOCACHE indicates buffer should be discarded) */
+ CLR(bp->nb_flags, (NB_DONE | NB_ERROR | NB_INVAL | NB_ASYNC | NB_READ));
+ SET(bp->nb_flags, NB_STABLE | NB_NOCACHE);
+ /*
+ * NFS has embedded ucred so crhold() risks zone corruption
+ */
+ if (bp->nb_wcred == NOCRED)
+ bp->nb_wcred = crdup(ap->a_cred);
+ error = nfs_buf_write(bp);
+ // Note: bp has been released
+ if (error) {
+ FSDBG(512, bp, 0xd00dee, 0xbad, error);
+ np->n_error = error;
+ np->n_flag |= NWRITEERR;
+ error = 0;
+ }
+ bp = NULL;
+ }
+ }
+ if (bp) {
+ FSDBG(512, bp, bp->nb_flags, 0, obn);
+ SET(bp->nb_flags, NB_INVAL);
+ nfs_buf_release(bp);
+ }
+ }