static void bclink_send_nack(struct tipc_node *n_ptr) { struct sk_buff *buf; struct tipc_msg *msg; if (!less(n_ptr->bclink.gap_after, n_ptr->bclink.gap_to)) return; buf = buf_acquire(INT_H_SIZE); if (buf) { msg = buf_msg(buf); msg_init(msg, BCAST_PROTOCOL, STATE_MSG, INT_H_SIZE, n_ptr->addr); msg_set_mc_netid(msg, tipc_net_id); msg_set_bcast_ack(msg, mod(n_ptr->bclink.last_in)); msg_set_bcgap_after(msg, n_ptr->bclink.gap_after); msg_set_bcgap_to(msg, n_ptr->bclink.gap_to); msg_set_bcast_tag(msg, tipc_own_tag); if (tipc_bearer_send(&bcbearer->bearer, buf, NULL)) { bcl->stats.sent_nacks++; buf_discard(buf); } else { tipc_bearer_schedule(bcl->b_ptr, bcl); bcl->proto_msg_queue = buf; bcl->stats.bearer_congs++; } /* * Ensure we doesn't send another NACK msg to the node * until 16 more deferred messages arrive from it * (i.e. helps prevent all nodes from NACK'ing at same time) */ n_ptr->bclink.nack_sync = tipc_own_tag; } }
/* * Synch an open file. */ int ffs_fsync(void *v) { struct vop_fsync_args *ap = v; struct vnode *vp = ap->a_vp; struct buf *bp, *nbp; int s, error, passes, skipmeta; if (vp->v_type == VBLK && vp->v_specmountpoint != NULL && (vp->v_specmountpoint->mnt_flag & MNT_SOFTDEP)) softdep_fsync_mountdev(vp, ap->a_waitfor); /* * Flush all dirty buffers associated with a vnode. */ passes = NIADDR + 1; skipmeta = 0; if (ap->a_waitfor == MNT_WAIT) skipmeta = 1; s = splbio(); loop: for (bp = LIST_FIRST(&vp->v_dirtyblkhd); bp; bp = LIST_NEXT(bp, b_vnbufs)) bp->b_flags &= ~B_SCANNED; for (bp = LIST_FIRST(&vp->v_dirtyblkhd); bp; bp = nbp) { nbp = LIST_NEXT(bp, b_vnbufs); /* * Reasons to skip this buffer: it has already been considered * on this pass, this pass is the first time through on a * synchronous flush request and the buffer being considered * is metadata, the buffer has dependencies that will cause * it to be redirtied and it has not already been deferred, * or it is already being written. */ if (bp->b_flags & (B_BUSY | B_SCANNED)) continue; if ((bp->b_flags & B_DELWRI) == 0) panic("ffs_fsync: not dirty"); if (skipmeta && bp->b_lblkno < 0) continue; if (ap->a_waitfor != MNT_WAIT && LIST_FIRST(&bp->b_dep) != NULL && (bp->b_flags & B_DEFERRED) == 0 && buf_countdeps(bp, 0, 1)) { bp->b_flags |= B_DEFERRED; continue; } bremfree(bp); buf_acquire(bp); bp->b_flags |= B_SCANNED; splx(s); /* * On our final pass through, do all I/O synchronously * so that we can find out if our flush is failing * because of write errors. */ if (passes > 0 || ap->a_waitfor != MNT_WAIT) (void) bawrite(bp); else if ((error = bwrite(bp)) != 0) return (error); s = splbio(); /* * Since we may have slept during the I/O, we need * to start from a known point. */ nbp = LIST_FIRST(&vp->v_dirtyblkhd); } if (skipmeta) { skipmeta = 0; goto loop; } if (ap->a_waitfor == MNT_WAIT) { vwaitforio(vp, 0, "ffs_fsync", 0); /* * Ensure that any filesystem metadata associated * with the vnode has been written. */ splx(s); if ((error = softdep_sync_metadata(ap)) != 0) return (error); s = splbio(); if (!LIST_EMPTY(&vp->v_dirtyblkhd)) { /* * Block devices associated with filesystems may * have new I/O requests posted for them even if * the vnode is locked, so no amount of trying will * get them clean. Thus we give block devices a * good effort, then just give up. For all other file * types, go around and try again until it is clean. */ if (passes > 0) { passes -= 1; goto loop; } #ifdef DIAGNOSTIC if (vp->v_type != VBLK) vprint("ffs_fsync: dirty", vp); #endif } } splx(s); return (UFS_UPDATE(VTOI(vp), ap->a_waitfor == MNT_WAIT)); }
/* * Buffer cleaning daemon. */ void buf_daemon(struct proc *p) { struct timeval starttime, timediff; struct buf *bp = NULL; int s, pushed = 0; cleanerproc = curproc; s = splbio(); for (;;) { if (bp == NULL || (pushed >= 16 && UNCLEAN_PAGES < hidirtypages && bcstats.kvaslots_avail > 2 * RESERVE_SLOTS)){ pushed = 0; /* * Wake up anyone who was waiting for buffers * to be released. */ if (needbuffer) { needbuffer = 0; wakeup(&needbuffer); } tsleep(&bd_req, PRIBIO - 7, "cleaner", 0); } getmicrouptime(&starttime); while ((bp = bufcache_getdirtybuf())) { struct timeval tv; if (UNCLEAN_PAGES < lodirtypages && bcstats.kvaslots_avail > 2 * RESERVE_SLOTS && pushed >= 16) break; bufcache_take(bp); buf_acquire(bp); splx(s); if (ISSET(bp->b_flags, B_INVAL)) { brelse(bp); s = splbio(); continue; } #ifdef DIAGNOSTIC if (!ISSET(bp->b_flags, B_DELWRI)) panic("Clean buffer on dirty queue"); #endif if (LIST_FIRST(&bp->b_dep) != NULL && !ISSET(bp->b_flags, B_DEFERRED) && buf_countdeps(bp, 0, 0)) { SET(bp->b_flags, B_DEFERRED); s = splbio(); bufcache_release(bp); buf_release(bp); continue; } bawrite(bp); pushed++; /* Never allow processing to run for more than 1 sec */ getmicrouptime(&tv); timersub(&tv, &starttime, &timediff); s = splbio(); if (timediff.tv_sec) break; } } }