irqreturn_t timer_interrupt (int irq, void *dev_id) { unsigned long next; next = get_linux_timer(); again: while ((signed long)(get_ccount() - next) > 0) { profile_tick(CPU_PROFILING); #ifndef CONFIG_SMP update_process_times(user_mode(get_irq_regs())); #endif write_seqlock(&xtime_lock); do_timer(1); /* Linux handler in kernel/timer.c */ /* Note that writing CCOMPARE clears the interrupt. */ next += CCOUNT_PER_JIFFY; set_linux_timer(next); write_sequnlock(&xtime_lock); } /* Allow platform to do something useful (Wdog). */ platform_heartbeat(); /* Make sure we didn't miss any tick... */ if ((signed long)(get_ccount() - next) > 0) goto again; return IRQ_HANDLED; }
/* * Must be called with interrupts disabled ! */ static void tick_do_update_jiffies64(ktime_t now) { unsigned long ticks = 0; ktime_t delta; /* * Do a quick check without holding xtime_lock: */ delta = ktime_sub(now, last_jiffies_update); if (delta.tv64 < tick_period.tv64) return; /* Reevalute with xtime_lock held */ write_seqlock(&xtime_lock); delta = ktime_sub(now, last_jiffies_update); if (delta.tv64 >= tick_period.tv64) { delta = ktime_sub(delta, tick_period); last_jiffies_update = ktime_add(last_jiffies_update, tick_period); /* Slow path for long timeouts */ if (unlikely(delta.tv64 >= tick_period.tv64)) { s64 incr = ktime_to_ns(tick_period); ticks = ktime_divns(delta, incr); last_jiffies_update = ktime_add_ns(last_jiffies_update, incr * ticks); } do_timer(++ticks); /* Keep the tick_next_period variable up to date */ tick_next_period = ktime_add(last_jiffies_update, tick_period); } write_sequnlock(&xtime_lock); }
static irqreturn_t tmu_timer_interrupt(int irq, void *dev_id, struct pt_regs *regs) { unsigned long timer_status; /* Clear UNF bit */ timer_status = ctrl_inw(TMU0_TCR); timer_status &= ~0x100; ctrl_outw(timer_status, TMU0_TCR); /* * Here we are in the timer irq handler. We just have irqs locally * disabled but we don't know if the timer_bh is running on the other * CPU. We need to avoid to SMP race with it. NOTE: we don' t need * the irq version of write_lock because as just said we have irq * locally disabled. -arca */ write_seqlock(&xtime_lock); handle_timer_tick(regs); write_sequnlock(&xtime_lock); return IRQ_HANDLED; }
static irqreturn_t ebsa110_timer_interrupt(int irq, void *dev_id, struct pt_regs *regs) { u32 count; write_seqlock(&xtime_lock); /* latch and read timer 1 */ __raw_writeb(0x40, PIT_CTRL); count = __raw_readb(PIT_T1); count |= __raw_readb(PIT_T1) << 8; count += COUNT; __raw_writeb(count & 0xff, PIT_T1); __raw_writeb(count >> 8, PIT_T1); timer_tick(regs); write_sequnlock(&xtime_lock); return IRQ_HANDLED; }
/* * IRQ handler for the timer */ static irqreturn_t imx_timer_interrupt(int irq, void *dev_id) { uint32_t tstat; /* clear the interrupt */ tstat = IMX_TSTAT(TIMER_BASE); IMX_TSTAT(TIMER_BASE) = 0; if (tstat & TSTAT_COMP) { do { write_seqlock(&xtime_lock); timer_tick(); write_sequnlock(&xtime_lock); IMX_TCMP(TIMER_BASE) += evt_diff; } while (unlikely((int32_t)(IMX_TCMP(TIMER_BASE) - IMX_TCN(TIMER_BASE)) < 0)); } return IRQ_HANDLED; }
irqreturn_t timer_interrupt(int irq, void *dummy) { /* last time the cmos clock got updated */ static long last_rtc_update; write_seqlock(&xtime_lock); do_timer(1); profile_tick(CPU_PROFILING); /* * If we have an externally synchronized Linux clock, then update * CMOS clock accordingly every ~11 minutes. Set_rtc_mmss() has to be * called as close as possible to 500 ms before the new second starts. */ if (ntp_synced() && xtime.tv_sec > last_rtc_update + 660 && (xtime.tv_nsec / NSEC_PER_USEC) >= 500000 - ((unsigned)TICK_SIZE) / 2 && (xtime.tv_nsec / NSEC_PER_USEC) <= 500000 + ((unsigned)TICK_SIZE) / 2) { if (set_rtc_mmss(xtime.tv_sec) == 0) last_rtc_update = xtime.tv_sec; else /* Do it again in 60s. */ last_rtc_update = xtime.tv_sec - 600; } write_sequnlock(&xtime_lock); #ifndef CONFIG_SMP update_process_times(user_mode(get_irq_regs())); #endif return IRQ_HANDLED; }
void *seqlock_write_test(void *arg) { int i; int j; int me = (long)arg; long long n_writes_local = 0LL; run_on(me); atomic_inc(&nthreadsrunning); while (ACCESS_ONCE(goflag) == GOFLAG_INIT) poll(NULL, 0, 1); while (ACCESS_ONCE(goflag) == GOFLAG_RUN) { for (i = COUNT_UPDATE_RUN; i > 0; i--) { write_seqlock(&test_seqlock); for (j = 0; j < n_elems; j++) testarray[j]++; write_sequnlock(&test_seqlock); barrier(); } n_writes_local += COUNT_UPDATE_RUN; } __get_thread_var(n_writes_pt) += n_writes_local; return NULL; }
int route_del(unsigned long addr) { struct route_entry *rep; struct route_entry **repp; write_seqlock(&sl); //\lnlbl{del:w_sqlock} repp = &route_list.re_next; for (;;) { rep = *repp; if (rep == NULL) break; if (rep->addr == addr) { *repp = rep->re_next; write_sequnlock(&sl); //\lnlbl{del:w_squnlock1} smp_mb(); rep->re_freed = 1; //\lnlbl{del:set_freed} free(rep); return 0; } repp = &rep->re_next; } write_sequnlock(&sl); //\lnlbl{del:w_squnlock2} return -ENOENT; }
/* * This is the same as the above, except we _also_ save the current * Time Stamp Counter value at the time of the timer interrupt, so that * we later on can estimate the time of day more exactly. */ irqreturn_t timer_interrupt(int irq, void *dev_id, struct pt_regs *regs) { /* * Here we are in the timer irq handler. We just have irqs locally * disabled but we don't know if the timer_bh is running on the other * CPU. We need to avoid to SMP race with it. NOTE: we don' t need * the irq version of write_lock because as just said we have irq * locally disabled. -arca */ write_seqlock(&xtime_lock); cur_timer->mark_offset(); do_timer_interrupt(irq, regs); write_sequnlock(&xtime_lock); #ifdef CONFIG_X86_LOCAL_APIC if (using_apic_timer) smp_send_timer_broadcast_ipi(regs); #endif return IRQ_HANDLED; }
/* * timer_interrupt() needs to keep up the real-time clock, * as well as call the "do_timer()" routine every clocktick */ irqreturn_t timer_interrupt(int irq, void *dummy) { /* last time the cmos clock got updated */ static long last_rtc_update = 0; /* Clear the interrupt condition */ outw(0, timer_membase + ALTERA_TIMER_STATUS_REG); nios2_timer_count += NIOS2_TIMER_PERIOD; write_seqlock(&xtime_lock); do_timer(1); profile_tick(CPU_PROFILING); /* * If we have an externally synchronized Linux clock, then update * CMOS clock accordingly every ~11 minutes. Set_rtc_mmss() has to be * called as close as possible to 500 ms before the new second starts. */ if (ntp_synced() && xtime.tv_sec > last_rtc_update + 660 && (xtime.tv_nsec / 1000) >= 500000 - ((unsigned)TICK_SIZE) / 2 && (xtime.tv_nsec / 1000) <= 500000 + ((unsigned)TICK_SIZE) / 2) { if (set_rtc_mmss(xtime.tv_sec) == 0) last_rtc_update = xtime.tv_sec; else last_rtc_update = xtime.tv_sec - 600; /* do it again in 60 s */ } write_sequnlock(&xtime_lock); #ifndef CONFIG_SMP update_process_times(user_mode(get_irq_regs())); #endif return (IRQ_HANDLED); }
static void mark_offset_hpet(void) { unsigned long long this_offset, last_offset; unsigned long offset; write_seqlock(&monotonic_lock); last_offset = ((unsigned long long)last_tsc_high<<32)|last_tsc_low; rdtsc(last_tsc_low, last_tsc_high); if (hpet_use_timer) offset = hpet_readl(HPET_T0_CMP) - hpet_tick; else offset = hpet_readl(HPET_COUNTER); if (unlikely(((offset - hpet_last) >= (2*hpet_tick)) && (hpet_last != 0))) { int lost_ticks = ((offset - hpet_last) / hpet_tick) - 1; jiffies_64 += lost_ticks; } hpet_last = offset; /* update the monotonic base value */ this_offset = ((unsigned long long)last_tsc_high<<32)|last_tsc_low; monotonic_base += cycles_2_ns(this_offset - last_offset); write_sequnlock(&monotonic_lock); }
/* * handle_timer_tick() needs to keep up the real-time clock, * as well as call the "do_timer()" routine every clocktick */ void handle_timer_tick(void) { if (current->pid) profile_tick(CPU_PROFILING); /* * Here we are in the timer irq handler. We just have irqs locally * disabled but we don't know if the timer_bh is running on the other * CPU. We need to avoid to SMP race with it. NOTE: we don' t need * the irq version of write_lock because as just said we have irq * locally disabled. -arca */ write_seqlock(&xtime_lock); do_timer(1); /* * If we have an externally synchronized Linux clock, then update * RTC clock accordingly every ~11 minutes. Set_rtc_mmss() has to be * called as close as possible to 500 ms before the new second starts. */ if (ntp_synced() && xtime.tv_sec > last_rtc_update + 660 && (xtime.tv_nsec / 1000) >= 500000 - ((unsigned) TICK_SIZE) / 2 && (xtime.tv_nsec / 1000) <= 500000 + ((unsigned) TICK_SIZE) / 2) { if (rtc_sh_set_time(xtime.tv_sec) == 0) last_rtc_update = xtime.tv_sec; else /* do it again in 60s */ last_rtc_update = xtime.tv_sec - 600; } write_sequnlock(&xtime_lock); #ifndef CONFIG_SMP update_process_times(user_mode(get_irq_regs())); #endif }
/* * Purge in-memory cell database. */ void afs_cell_purge(struct afs_net *net) { struct afs_cell *ws; _enter(""); write_seqlock(&net->cells_lock); ws = rcu_access_pointer(net->ws_cell); RCU_INIT_POINTER(net->ws_cell, NULL); write_sequnlock(&net->cells_lock); afs_put_cell(net, ws); _debug("del timer"); if (del_timer_sync(&net->cells_timer)) atomic_dec(&net->cells_outstanding); _debug("kick mgr"); afs_queue_cell_manager(net); _debug("wait"); wait_var_event(&net->cells_outstanding, !atomic_read(&net->cells_outstanding)); _leave(""); }
/* Validate changes from /proc interface. */ static int ipv4_local_port_range(struct ctl_table *table, int write, void __user *buffer, size_t *lenp, loff_t *ppos) { struct net *net = container_of(table->data, struct net, ipv4.ip_local_ports.range); int ret; int range[2]; struct ctl_table tmp = { .data = &range, .maxlen = sizeof(range), .mode = table->mode, .extra1 = &ip_local_port_range_min, .extra2 = &ip_local_port_range_max, }; inet_get_local_port_range(net, &range[0], &range[1]); ret = proc_dointvec_minmax(&tmp, write, buffer, lenp, ppos); if (write && ret == 0) { /* Ensure that the upper limit is not smaller than the lower, * and that the lower does not encroach upon the privileged * port limit. */ if ((range[1] < range[0]) || (range[0] < net->ipv4.sysctl_ip_prot_sock)) ret = -EINVAL; else set_local_port_range(net, range); } return ret; } /* Validate changes from /proc interface. */ static int ipv4_privileged_ports(struct ctl_table *table, int write, void __user *buffer, size_t *lenp, loff_t *ppos) { struct net *net = container_of(table->data, struct net, ipv4.sysctl_ip_prot_sock); int ret; int pports; int range[2]; struct ctl_table tmp = { .data = &pports, .maxlen = sizeof(pports), .mode = table->mode, .extra1 = &ip_privileged_port_min, .extra2 = &ip_privileged_port_max, }; pports = net->ipv4.sysctl_ip_prot_sock; ret = proc_dointvec_minmax(&tmp, write, buffer, lenp, ppos); if (write && ret == 0) { inet_get_local_port_range(net, &range[0], &range[1]); /* Ensure that the local port range doesn't overlap with the * privileged port range. */ if (range[0] < pports) ret = -EINVAL; else net->ipv4.sysctl_ip_prot_sock = pports; } return ret; } static void inet_get_ping_group_range_table(struct ctl_table *table, kgid_t *low, kgid_t *high) { kgid_t *data = table->data; struct net *net = container_of(table->data, struct net, ipv4.ping_group_range.range); unsigned int seq; do { seq = read_seqbegin(&net->ipv4.ping_group_range.lock); *low = data[0]; *high = data[1]; } while (read_seqretry(&net->ipv4.ping_group_range.lock, seq)); } /* Update system visible IP port range */ static void set_ping_group_range(struct ctl_table *table, kgid_t low, kgid_t high) { kgid_t *data = table->data; struct net *net = container_of(table->data, struct net, ipv4.ping_group_range.range); write_seqlock(&net->ipv4.ping_group_range.lock); data[0] = low; data[1] = high; write_sequnlock(&net->ipv4.ping_group_range.lock); }
/** * hfi1_error_qp - put a QP into the error state * @qp: the QP to put into the error state * @err: the receive completion error to signal if a RWQE is active * * Flushes both send and receive work queues. * Returns true if last WQE event should be generated. * The QP r_lock and s_lock should be held and interrupts disabled. * If we are already in error state, just return. */ int hfi1_error_qp(struct hfi1_qp *qp, enum ib_wc_status err) { struct hfi1_ibdev *dev = to_idev(qp->ibqp.device); struct ib_wc wc; int ret = 0; if (qp->state == IB_QPS_ERR || qp->state == IB_QPS_RESET) goto bail; qp->state = IB_QPS_ERR; if (qp->s_flags & (HFI1_S_TIMER | HFI1_S_WAIT_RNR)) { qp->s_flags &= ~(HFI1_S_TIMER | HFI1_S_WAIT_RNR); del_timer(&qp->s_timer); } if (qp->s_flags & HFI1_S_ANY_WAIT_SEND) qp->s_flags &= ~HFI1_S_ANY_WAIT_SEND; write_seqlock(&dev->iowait_lock); if (!list_empty(&qp->s_iowait.list) && !(qp->s_flags & HFI1_S_BUSY)) { qp->s_flags &= ~HFI1_S_ANY_WAIT_IO; list_del_init(&qp->s_iowait.list); if (atomic_dec_and_test(&qp->refcount)) wake_up(&qp->wait); } write_sequnlock(&dev->iowait_lock); if (!(qp->s_flags & HFI1_S_BUSY)) { qp->s_hdrwords = 0; if (qp->s_rdma_mr) { hfi1_put_mr(qp->s_rdma_mr); qp->s_rdma_mr = NULL; } flush_tx_list(qp); } /* Schedule the sending tasklet to drain the send work queue. */ if (qp->s_last != qp->s_head) hfi1_schedule_send(qp); clear_mr_refs(qp, 0); memset(&wc, 0, sizeof(wc)); wc.qp = &qp->ibqp; wc.opcode = IB_WC_RECV; if (test_and_clear_bit(HFI1_R_WRID_VALID, &qp->r_aflags)) { wc.wr_id = qp->r_wr_id; wc.status = err; hfi1_cq_enter(to_icq(qp->ibqp.recv_cq), &wc, 1); } wc.status = IB_WC_WR_FLUSH_ERR; if (qp->r_rq.wq) { struct hfi1_rwq *wq; u32 head; u32 tail; spin_lock(&qp->r_rq.lock); /* sanity check pointers before trusting them */ wq = qp->r_rq.wq; head = wq->head; if (head >= qp->r_rq.size) head = 0; tail = wq->tail; if (tail >= qp->r_rq.size) tail = 0; while (tail != head) { wc.wr_id = get_rwqe_ptr(&qp->r_rq, tail)->wr_id; if (++tail >= qp->r_rq.size) tail = 0; hfi1_cq_enter(to_icq(qp->ibqp.recv_cq), &wc, 1); } wq->tail = tail; spin_unlock(&qp->r_rq.lock); } else if (qp->ibqp.event_handler) ret = 1; bail: return ret; }
/* * Must not be called with IRQs off. This should only be used on the * slow path. * * Copy a foreign granted page to local memory. */ int gnttab_copy_grant_page(grant_ref_t ref, struct page **pagep) { struct gnttab_unmap_and_replace unmap; mmu_update_t mmu; struct page *page; struct page *new_page; void *new_addr; void *addr; paddr_t pfn; maddr_t mfn; maddr_t new_mfn; int err; page = *pagep; if (!get_page_unless_zero(page)) return -ENOENT; err = -ENOMEM; new_page = alloc_page(GFP_ATOMIC | __GFP_NOWARN); if (!new_page) goto out; new_addr = page_address(new_page); addr = page_address(page); memcpy(new_addr, addr, PAGE_SIZE); pfn = page_to_pfn(page); mfn = pfn_to_mfn(pfn); new_mfn = virt_to_mfn(new_addr); write_seqlock(&gnttab_dma_lock); /* Make seq visible before checking page_mapped. */ smp_mb(); /* Has the page been DMA-mapped? */ if (unlikely(page_mapped(page))) { write_sequnlock(&gnttab_dma_lock); put_page(new_page); err = -EBUSY; goto out; } if (!xen_feature(XENFEAT_auto_translated_physmap)) set_phys_to_machine(pfn, new_mfn); gnttab_set_replace_op(&unmap, (unsigned long)addr, (unsigned long)new_addr, ref); err = HYPERVISOR_grant_table_op(GNTTABOP_unmap_and_replace, &unmap, 1); BUG_ON(err); BUG_ON(unmap.status); write_sequnlock(&gnttab_dma_lock); if (!xen_feature(XENFEAT_auto_translated_physmap)) { set_phys_to_machine(page_to_pfn(new_page), INVALID_P2M_ENTRY); mmu.ptr = (new_mfn << PAGE_SHIFT) | MMU_MACHPHYS_UPDATE; mmu.val = pfn; err = HYPERVISOR_mmu_update(&mmu, 1, NULL, DOMID_SELF); BUG_ON(err); } new_page->mapping = page->mapping; new_page->index = page->index; set_bit(PG_foreign, &new_page->flags); *pagep = new_page; SetPageForeign(page, gnttab_page_free); page->mapping = NULL; out: put_page(page); return err; }
u64 ufs_new_fragments(struct inode *inode, void *p, u64 fragment, u64 goal, unsigned count, int *err, struct page *locked_page) { struct super_block * sb; struct ufs_sb_private_info * uspi; struct ufs_super_block_first * usb1; unsigned cgno, oldcount, newcount; u64 tmp, request, result; UFSD("ENTER, ino %lu, fragment %llu, goal %llu, count %u\n", inode->i_ino, (unsigned long long)fragment, (unsigned long long)goal, count); sb = inode->i_sb; uspi = UFS_SB(sb)->s_uspi; usb1 = ubh_get_usb_first(uspi); *err = -ENOSPC; mutex_lock(&UFS_SB(sb)->s_lock); tmp = ufs_data_ptr_to_cpu(sb, p); if (count + ufs_fragnum(fragment) > uspi->s_fpb) { ufs_warning(sb, "ufs_new_fragments", "internal warning" " fragment %llu, count %u", (unsigned long long)fragment, count); count = uspi->s_fpb - ufs_fragnum(fragment); } oldcount = ufs_fragnum (fragment); newcount = oldcount + count; /* * Somebody else has just allocated our fragments */ if (oldcount) { if (!tmp) { ufs_error(sb, "ufs_new_fragments", "internal error, " "fragment %llu, tmp %llu\n", (unsigned long long)fragment, (unsigned long long)tmp); mutex_unlock(&UFS_SB(sb)->s_lock); return INVBLOCK; } if (fragment < UFS_I(inode)->i_lastfrag) { UFSD("EXIT (ALREADY ALLOCATED)\n"); mutex_unlock(&UFS_SB(sb)->s_lock); return 0; } } else { if (tmp) { UFSD("EXIT (ALREADY ALLOCATED)\n"); mutex_unlock(&UFS_SB(sb)->s_lock); return 0; } } /* * There is not enough space for user on the device */ if (!capable(CAP_SYS_RESOURCE) && ufs_freespace(uspi, UFS_MINFREE) <= 0) { mutex_unlock(&UFS_SB(sb)->s_lock); UFSD("EXIT (FAILED)\n"); return 0; } if (goal >= uspi->s_size) goal = 0; if (goal == 0) cgno = ufs_inotocg (inode->i_ino); else cgno = ufs_dtog(uspi, goal); /* * allocate new fragment */ if (oldcount == 0) { result = ufs_alloc_fragments (inode, cgno, goal, count, err); if (result) { ufs_clear_frags(inode, result + oldcount, newcount - oldcount, locked_page != NULL); write_seqlock(&UFS_I(inode)->meta_lock); ufs_cpu_to_data_ptr(sb, p, result); write_sequnlock(&UFS_I(inode)->meta_lock); *err = 0; UFS_I(inode)->i_lastfrag = max(UFS_I(inode)->i_lastfrag, fragment + count); } mutex_unlock(&UFS_SB(sb)->s_lock); UFSD("EXIT, result %llu\n", (unsigned long long)result); return result; } /* * resize block */ result = ufs_add_fragments(inode, tmp, oldcount, newcount); if (result) { *err = 0; UFS_I(inode)->i_lastfrag = max(UFS_I(inode)->i_lastfrag, fragment + count); ufs_clear_frags(inode, result + oldcount, newcount - oldcount, locked_page != NULL); mutex_unlock(&UFS_SB(sb)->s_lock); UFSD("EXIT, result %llu\n", (unsigned long long)result); return result; } /* * allocate new block and move data */ switch (fs32_to_cpu(sb, usb1->fs_optim)) { case UFS_OPTSPACE: request = newcount; if (uspi->s_minfree < 5 || uspi->cs_total.cs_nffree > uspi->s_dsize * uspi->s_minfree / (2 * 100)) break; usb1->fs_optim = cpu_to_fs32(sb, UFS_OPTTIME); break; default: usb1->fs_optim = cpu_to_fs32(sb, UFS_OPTTIME); case UFS_OPTTIME: request = uspi->s_fpb; if (uspi->cs_total.cs_nffree < uspi->s_dsize * (uspi->s_minfree - 2) / 100) break; usb1->fs_optim = cpu_to_fs32(sb, UFS_OPTTIME); break; } result = ufs_alloc_fragments (inode, cgno, goal, request, err); if (result) { ufs_clear_frags(inode, result + oldcount, newcount - oldcount, locked_page != NULL); ufs_change_blocknr(inode, fragment - oldcount, oldcount, uspi->s_sbbase + tmp, uspi->s_sbbase + result, locked_page); write_seqlock(&UFS_I(inode)->meta_lock); ufs_cpu_to_data_ptr(sb, p, result); write_sequnlock(&UFS_I(inode)->meta_lock); *err = 0; UFS_I(inode)->i_lastfrag = max(UFS_I(inode)->i_lastfrag, fragment + count); mutex_unlock(&UFS_SB(sb)->s_lock); if (newcount < request) ufs_free_fragments (inode, result + newcount, request - newcount); ufs_free_fragments (inode, tmp, oldcount); UFSD("EXIT, result %llu\n", (unsigned long long)result); return result; } mutex_unlock(&UFS_SB(sb)->s_lock); UFSD("EXIT (FAILED)\n"); return 0; }
/* * afs_lookup_cell - Look up or create a cell record. * @net: The network namespace * @name: The name of the cell. * @namesz: The strlen of the cell name. * @vllist: A colon/comma separated list of numeric IP addresses or NULL. * @excl: T if an error should be given if the cell name already exists. * * Look up a cell record by name and query the DNS for VL server addresses if * needed. Note that that actual DNS query is punted off to the manager thread * so that this function can return immediately if interrupted whilst allowing * cell records to be shared even if not yet fully constructed. */ struct afs_cell *afs_lookup_cell(struct afs_net *net, const char *name, unsigned int namesz, const char *vllist, bool excl) { struct afs_cell *cell, *candidate, *cursor; struct rb_node *parent, **pp; enum afs_cell_state state; int ret, n; _enter("%s,%s", name, vllist); if (!excl) { rcu_read_lock(); cell = afs_lookup_cell_rcu(net, name, namesz); rcu_read_unlock(); if (!IS_ERR(cell)) goto wait_for_cell; } /* Assume we're probably going to create a cell and preallocate and * mostly set up a candidate record. We can then use this to stash the * name, the net namespace and VL server addresses. * * We also want to do this before we hold any locks as it may involve * upcalling to userspace to make DNS queries. */ candidate = afs_alloc_cell(net, name, namesz, vllist); if (IS_ERR(candidate)) { _leave(" = %ld", PTR_ERR(candidate)); return candidate; } /* Find the insertion point and check to see if someone else added a * cell whilst we were allocating. */ write_seqlock(&net->cells_lock); pp = &net->cells.rb_node; parent = NULL; while (*pp) { parent = *pp; cursor = rb_entry(parent, struct afs_cell, net_node); n = strncasecmp(cursor->name, name, min_t(size_t, cursor->name_len, namesz)); if (n == 0) n = cursor->name_len - namesz; if (n < 0) pp = &(*pp)->rb_left; else if (n > 0) pp = &(*pp)->rb_right; else goto cell_already_exists; } cell = candidate; candidate = NULL; rb_link_node_rcu(&cell->net_node, parent, pp); rb_insert_color(&cell->net_node, &net->cells); atomic_inc(&net->cells_outstanding); write_sequnlock(&net->cells_lock); queue_work(afs_wq, &cell->manager); wait_for_cell: _debug("wait_for_cell"); wait_var_event(&cell->state, ({ state = smp_load_acquire(&cell->state); /* vs error */ state == AFS_CELL_ACTIVE || state == AFS_CELL_FAILED; }));
static int fb_counter_event(struct notifier_block *self, unsigned long cmd, void *args) { int ret = NOTIFY_OK; unsigned int cpu; struct fblock *fb; struct fb_counter_priv __percpu *fb_priv; rcu_read_lock(); fb = rcu_dereference_raw(container_of(self, struct fblock_notifier, nb)->self); fb_priv = (struct fb_counter_priv __percpu *) rcu_dereference_raw(fb->private_data); rcu_read_unlock(); switch (cmd) { case FBLOCK_BIND_IDP: { int bound = 0; struct fblock_bind_msg *msg = args; get_online_cpus(); for_each_online_cpu(cpu) { struct fb_counter_priv *fb_priv_cpu; fb_priv_cpu = per_cpu_ptr(fb_priv, cpu); if (fb_priv_cpu->port[msg->dir] == IDP_UNKNOWN) { write_seqlock(&fb_priv_cpu->lock); fb_priv_cpu->port[msg->dir] = msg->idp; write_sequnlock(&fb_priv_cpu->lock); bound = 1; } else { ret = NOTIFY_BAD; break; } } put_online_cpus(); if (bound) printk(KERN_INFO "[%s::%s] port %s bound to IDP%u\n", fb->name, fb->factory->type, path_names[msg->dir], msg->idp); } break; case FBLOCK_UNBIND_IDP: { int unbound = 0; struct fblock_bind_msg *msg = args; get_online_cpus(); for_each_online_cpu(cpu) { struct fb_counter_priv *fb_priv_cpu; fb_priv_cpu = per_cpu_ptr(fb_priv, cpu); if (fb_priv_cpu->port[msg->dir] == msg->idp) { write_seqlock(&fb_priv_cpu->lock); fb_priv_cpu->port[msg->dir] = IDP_UNKNOWN; write_sequnlock(&fb_priv_cpu->lock); unbound = 1; } else { ret = NOTIFY_BAD; break; } } put_online_cpus(); if (unbound) printk(KERN_INFO "[%s::%s] port %s unbound\n", fb->name, fb->factory->type, path_names[msg->dir]); } break; case FBLOCK_SET_OPT: { struct fblock_opt_msg *msg = args; printk("Set option %s to %s!\n", msg->key, msg->val); } break; default: break; } return ret; }
/* * Manage a cell record, initialising and destroying it, maintaining its DNS * records. */ static void afs_manage_cell(struct work_struct *work) { struct afs_cell *cell = container_of(work, struct afs_cell, manager); struct afs_net *net = cell->net; bool deleted; int ret, usage; _enter("%s", cell->name); again: _debug("state %u", cell->state); switch (cell->state) { case AFS_CELL_INACTIVE: case AFS_CELL_FAILED: write_seqlock(&net->cells_lock); usage = 1; deleted = atomic_try_cmpxchg_relaxed(&cell->usage, &usage, 0); if (deleted) rb_erase(&cell->net_node, &net->cells); write_sequnlock(&net->cells_lock); if (deleted) goto final_destruction; if (cell->state == AFS_CELL_FAILED) goto done; cell->state = AFS_CELL_UNSET; goto again; case AFS_CELL_UNSET: cell->state = AFS_CELL_ACTIVATING; goto again; case AFS_CELL_ACTIVATING: ret = afs_activate_cell(net, cell); if (ret < 0) goto activation_failed; cell->state = AFS_CELL_ACTIVE; smp_wmb(); clear_bit(AFS_CELL_FL_NOT_READY, &cell->flags); wake_up_bit(&cell->flags, AFS_CELL_FL_NOT_READY); goto again; case AFS_CELL_ACTIVE: if (atomic_read(&cell->usage) > 1) { time64_t now = ktime_get_real_seconds(); if (cell->dns_expiry <= now && net->live) afs_update_cell(cell); goto done; } cell->state = AFS_CELL_DEACTIVATING; goto again; case AFS_CELL_DEACTIVATING: set_bit(AFS_CELL_FL_NOT_READY, &cell->flags); if (atomic_read(&cell->usage) > 1) goto reverse_deactivation; afs_deactivate_cell(net, cell); cell->state = AFS_CELL_INACTIVE; goto again; default: break; } _debug("bad state %u", cell->state); BUG(); /* Unhandled state */ activation_failed: cell->error = ret; afs_deactivate_cell(net, cell); cell->state = AFS_CELL_FAILED; smp_wmb(); if (test_and_clear_bit(AFS_CELL_FL_NOT_READY, &cell->flags)) wake_up_bit(&cell->flags, AFS_CELL_FL_NOT_READY); goto again; reverse_deactivation: cell->state = AFS_CELL_ACTIVE; smp_wmb(); clear_bit(AFS_CELL_FL_NOT_READY, &cell->flags); wake_up_bit(&cell->flags, AFS_CELL_FL_NOT_READY); _leave(" [deact->act]"); return; done: _leave(" [done %u]", cell->state); return; final_destruction: call_rcu(&cell->rcu, afs_cell_destroy); afs_dec_cells_outstanding(net); _leave(" [destruct %d]", atomic_read(&net->cells_outstanding)); }
/* * afs_lookup_cell - Look up or create a cell record. * @net: The network namespace * @name: The name of the cell. * @namesz: The strlen of the cell name. * @vllist: A colon/comma separated list of numeric IP addresses or NULL. * @excl: T if an error should be given if the cell name already exists. * * Look up a cell record by name and query the DNS for VL server addresses if * needed. Note that that actual DNS query is punted off to the manager thread * so that this function can return immediately if interrupted whilst allowing * cell records to be shared even if not yet fully constructed. */ struct afs_cell *afs_lookup_cell(struct afs_net *net, const char *name, unsigned int namesz, const char *vllist, bool excl) { struct afs_cell *cell, *candidate, *cursor; struct rb_node *parent, **pp; int ret, n; _enter("%s,%s", name, vllist); if (!excl) { rcu_read_lock(); cell = afs_lookup_cell_rcu(net, name, namesz); rcu_read_unlock(); if (!IS_ERR(cell)) goto wait_for_cell; } /* Assume we're probably going to create a cell and preallocate and * mostly set up a candidate record. We can then use this to stash the * name, the net namespace and VL server addresses. * * We also want to do this before we hold any locks as it may involve * upcalling to userspace to make DNS queries. */ candidate = afs_alloc_cell(net, name, namesz, vllist); if (IS_ERR(candidate)) { _leave(" = %ld", PTR_ERR(candidate)); return candidate; } /* Find the insertion point and check to see if someone else added a * cell whilst we were allocating. */ write_seqlock(&net->cells_lock); pp = &net->cells.rb_node; parent = NULL; while (*pp) { parent = *pp; cursor = rb_entry(parent, struct afs_cell, net_node); n = strncasecmp(cursor->name, name, min_t(size_t, cursor->name_len, namesz)); if (n == 0) n = cursor->name_len - namesz; if (n < 0) pp = &(*pp)->rb_left; else if (n > 0) pp = &(*pp)->rb_right; else goto cell_already_exists; } cell = candidate; candidate = NULL; rb_link_node_rcu(&cell->net_node, parent, pp); rb_insert_color(&cell->net_node, &net->cells); atomic_inc(&net->cells_outstanding); write_sequnlock(&net->cells_lock); queue_work(afs_wq, &cell->manager); wait_for_cell: _debug("wait_for_cell"); ret = wait_on_bit(&cell->flags, AFS_CELL_FL_NOT_READY, TASK_INTERRUPTIBLE); smp_rmb(); switch (READ_ONCE(cell->state)) { case AFS_CELL_FAILED: ret = cell->error; goto error; default: _debug("weird %u %d", cell->state, cell->error); goto error; case AFS_CELL_ACTIVE: break; } _leave(" = %p [cell]", cell); return cell; cell_already_exists: _debug("cell exists"); cell = cursor; if (excl) { ret = -EEXIST; } else { afs_get_cell(cursor); ret = 0; } write_sequnlock(&net->cells_lock); kfree(candidate); if (ret == 0) goto wait_for_cell; goto error_noput; error: afs_put_cell(net, cell); error_noput: _leave(" = %d [error]", ret); return ERR_PTR(ret); }
static unsigned long consider_steal_time(unsigned long new_itm) { unsigned long stolen, blocked; unsigned long delta_itm = 0, stolentick = 0; int cpu = smp_processor_id(); struct vcpu_runstate_info runstate; struct task_struct *p = current; get_runstate_snapshot(&runstate); /* * Check for vcpu migration effect * In this case, itc value is reversed. * This causes huge stolen value. * This function just checks and reject this effect. */ if (!time_after_eq(runstate.time[RUNSTATE_blocked], per_cpu(xen_blocked_time, cpu))) blocked = 0; if (!time_after_eq(runstate.time[RUNSTATE_runnable] + runstate.time[RUNSTATE_offline], per_cpu(xen_stolen_time, cpu))) stolen = 0; if (!time_after(delta_itm + new_itm, ia64_get_itc())) stolentick = ia64_get_itc() - new_itm; do_div(stolentick, NS_PER_TICK); stolentick++; do_div(stolen, NS_PER_TICK); if (stolen > stolentick) stolen = stolentick; stolentick -= stolen; do_div(blocked, NS_PER_TICK); if (blocked > stolentick) blocked = stolentick; if (stolen > 0 || blocked > 0) { account_steal_ticks(stolen); account_idle_ticks(blocked); run_local_timers(); rcu_check_callbacks(cpu, user_mode(get_irq_regs())); scheduler_tick(); run_posix_cpu_timers(p); delta_itm += local_cpu_data->itm_delta * (stolen + blocked); if (cpu == time_keeper_id) { write_seqlock(&xtime_lock); do_timer(stolen + blocked); local_cpu_data->itm_next = delta_itm + new_itm; write_sequnlock(&xtime_lock); } else { local_cpu_data->itm_next = delta_itm + new_itm; } per_cpu(xen_stolen_time, cpu) += NS_PER_TICK * stolen; per_cpu(xen_blocked_time, cpu) += NS_PER_TICK * blocked; } return delta_itm; }
static irqreturn_t timer_interrupt (int irq, void *dev_id) { unsigned long new_itm; if (unlikely(cpu_is_offline(smp_processor_id()))) { return IRQ_HANDLED; } platform_timer_interrupt(irq, dev_id); new_itm = local_cpu_data->itm_next; if (!time_after(ia64_get_itc(), new_itm)) printk(KERN_ERR "Oops: timer tick before it's due (itc=%lx,itm=%lx)\n", ia64_get_itc(), new_itm); profile_tick(CPU_PROFILING); if (paravirt_do_steal_accounting(&new_itm)) goto skip_process_time_accounting; while (1) { update_process_times(user_mode(get_irq_regs())); new_itm += local_cpu_data->itm_delta; if (smp_processor_id() == time_keeper_id) { /* * Here we are in the timer irq handler. We have irqs locally * disabled, but we don't know if the timer_bh is running on * another CPU. We need to avoid to SMP race by acquiring the * xtime_lock. */ write_seqlock(&xtime_lock); do_timer(1); local_cpu_data->itm_next = new_itm; write_sequnlock(&xtime_lock); } else local_cpu_data->itm_next = new_itm; if (time_after(new_itm, ia64_get_itc())) break; /* * Allow IPIs to interrupt the timer loop. */ local_irq_enable(); local_irq_disable(); } skip_process_time_accounting: do { /* * If we're too close to the next clock tick for * comfort, we increase the safety margin by * intentionally dropping the next tick(s). We do NOT * update itm.next because that would force us to call * do_timer() which in turn would let our clock run * too fast (with the potentially devastating effect * of losing monotony of time). */ while (!time_after(new_itm, ia64_get_itc() + local_cpu_data->itm_delta/2)) new_itm += local_cpu_data->itm_delta; ia64_set_itm(new_itm); /* double check, in case we got hit by a (slow) PMI: */ } while (time_after_eq(ia64_get_itc(), new_itm)); return IRQ_HANDLED; }
/* * timer_interrupt - gets called when the decrementer overflows, * with interrupts disabled. * We set it up to overflow again in 1/HZ seconds. */ void timer_interrupt(struct pt_regs * regs) { int next_dec; unsigned long cpu = smp_processor_id(); unsigned jiffy_stamp = last_jiffy_stamp(cpu); extern void do_IRQ(struct pt_regs *); if (atomic_read(&ppc_n_lost_interrupts) != 0) do_IRQ(regs); MARK(kernel_trap_entry, "%d struct pt_regs %p", regs->trap, regs); irq_enter(); while ((next_dec = tb_ticks_per_jiffy - tb_delta(&jiffy_stamp)) <= 0) { jiffy_stamp += tb_ticks_per_jiffy; profile_tick(CPU_PROFILING, regs); update_process_times(user_mode(regs)); if (smp_processor_id()) continue; /* We are in an interrupt, no need to save/restore flags */ write_seqlock(&xtime_lock); tb_last_stamp = jiffy_stamp; #ifdef CONFIG_LTT ltt_reset_timestamp(); #endif //CONFIG_LTT do_timer(regs); /* * update the rtc when needed, this should be performed on the * right fraction of a second. Half or full second ? * Full second works on mk48t59 clocks, others need testing. * Note that this update is basically only used through * the adjtimex system calls. Setting the HW clock in * any other way is a /dev/rtc and userland business. * This is still wrong by -0.5/+1.5 jiffies because of the * timer interrupt resolution and possible delay, but here we * hit a quantization limit which can only be solved by higher * resolution timers and decoupling time management from timer * interrupts. This is also wrong on the clocks * which require being written at the half second boundary. * We should have an rtc call that only sets the minutes and * seconds like on Intel to avoid problems with non UTC clocks. */ if ( ppc_md.set_rtc_time && ntp_synced() && xtime.tv_sec - last_rtc_update >= 659 && abs((xtime.tv_nsec / 1000) - (1000000-1000000/HZ)) < 500000/HZ && jiffies - wall_jiffies == 1) { if (ppc_md.set_rtc_time(xtime.tv_sec+1 + timezone_offset) == 0) last_rtc_update = xtime.tv_sec+1; else /* Try again one minute later */ last_rtc_update += 60; } write_sequnlock(&xtime_lock); } if ( !disarm_decr[smp_processor_id()] ) set_dec(next_dec); last_jiffy_stamp(cpu) = jiffy_stamp; if (ppc_md.heartbeat && !ppc_md.heartbeat_count--) ppc_md.heartbeat(); irq_exit(); trace_kernel_trap_exit(); MARK(kernel_trap_exit, MARK_NOARGS); }
/* try d_walk() in linux/fs/dcache.c */ int au_dcsub_pages(struct au_dcsub_pages *dpages, struct dentry *root, au_dpages_test test, void *arg) { int err; struct dentry *this_parent; struct list_head *next; struct super_block *sb = root->d_sb; err = 0; write_seqlock(&rename_lock); this_parent = root; spin_lock(&this_parent->d_lock); repeat: next = this_parent->d_subdirs.next; resume: if (this_parent->d_sb == sb && !IS_ROOT(this_parent) && au_di(this_parent) && d_count(this_parent) && (!test || test(this_parent, arg))) { err = au_dpages_append(dpages, this_parent, GFP_ATOMIC); if (unlikely(err)) goto out; } while (next != &this_parent->d_subdirs) { struct list_head *tmp = next; struct dentry *dentry = list_entry(tmp, struct dentry, d_u.d_child); next = tmp->next; spin_lock_nested(&dentry->d_lock, DENTRY_D_LOCK_NESTED); if (d_count(dentry)) { if (!list_empty(&dentry->d_subdirs)) { spin_unlock(&this_parent->d_lock); spin_release(&dentry->d_lock.dep_map, 1, _RET_IP_); this_parent = dentry; spin_acquire(&this_parent->d_lock.dep_map, 0, 1, _RET_IP_); goto repeat; } if (dentry->d_sb == sb && au_di(dentry) && (!test || test(dentry, arg))) err = au_dpages_append(dpages, dentry, GFP_ATOMIC); } spin_unlock(&dentry->d_lock); if (unlikely(err)) goto out; } if (this_parent != root) { struct dentry *tmp; struct dentry *child; tmp = this_parent->d_parent; rcu_read_lock(); spin_unlock(&this_parent->d_lock); child = this_parent; this_parent = tmp; spin_lock(&this_parent->d_lock); rcu_read_unlock(); next = child->d_u.d_child.next; goto resume; } out: spin_unlock(&this_parent->d_lock); write_sequnlock(&rename_lock); return err; }
static irqreturn_t timer_interrupt (int irq, void *dev_id, struct pt_regs *regs) { unsigned long new_itm; if (unlikely(cpu_is_offline(smp_processor_id()))) { return IRQ_HANDLED; } platform_timer_interrupt(irq, dev_id, regs); new_itm = local_cpu_data->itm_next; if (!time_after(ia64_get_itc(), new_itm)) printk(KERN_ERR "Oops: timer tick before it's due (itc=%lx,itm=%lx)\n", ia64_get_itc(), new_itm); profile_tick(CPU_PROFILING, regs); while (1) { #ifdef CONFIG_SMP /* * For UP, this is done in do_timer(). Weird, but * fixing that would require updates to all * platforms. */ update_process_times(user_mode(regs)); #endif new_itm += local_cpu_data->itm_delta; if (smp_processor_id() == TIME_KEEPER_ID) { /* * Here we are in the timer irq handler. We have irqs locally * disabled, but we don't know if the timer_bh is running on * another CPU. We need to avoid to SMP race by acquiring the * xtime_lock. */ write_seqlock(&xtime_lock); do_timer(regs); local_cpu_data->itm_next = new_itm; write_sequnlock(&xtime_lock); } else local_cpu_data->itm_next = new_itm; if (time_after(new_itm, ia64_get_itc())) break; } do { /* * If we're too close to the next clock tick for * comfort, we increase the safety margin by * intentionally dropping the next tick(s). We do NOT * update itm.next because that would force us to call * do_timer() which in turn would let our clock run * too fast (with the potentially devastating effect * of losing monotony of time). */ while (!time_after(new_itm, ia64_get_itc() + local_cpu_data->itm_delta/2)) new_itm += local_cpu_data->itm_delta; ia64_set_itm(new_itm); /* double check, in case we got hit by a (slow) PMI: */ } while (time_after_eq(ia64_get_itc(), new_itm)); return IRQ_HANDLED; }