/* * Replace the key node from rbtree for new container * replace node from rbtree, return old node pointer */ struct container * container_replace(struct rb_root *root, const void *key, struct container *cont, int (*cmp)(const void *x, const void *y)) { struct container *find = container_search(root, key, cmp); if (!find) return 0; rb_replace_node(&(find->rb_node), &cont->rb_node, root); return find; }
/* n r r -> n l l */ static void rb_rotate_left(struct rb_tree *t, struct rb_node *n, struct rb_callbacks *cb) { struct rb_node *r = n->right; rb_replace_node(t, n, r); n->right = r->left; if (n->right) { n->right->parent = n; } r->left = n; r->left->parent = r; if (cb && cb->rotate) { cb->rotate(t, n, r); } }
static void rb_rotate_left(struct rb_root* root, struct rb_node* node) { struct rb_node* right = node->rb_right; rb_replace_node(root, node, right); node->rb_right = right->rb_left; if (right->rb_left != NULL) { right->rb_left->rb_parent = node; } right->rb_left = node; node->rb_parent = right; }
/* n l l -> n r r */ static void rb_rotate_right(struct rb_tree *t, struct rb_node *n, struct rb_callbacks *cb) { struct rb_node *l = n->left; struct rb_node *r = l->right; rb_replace_node(t, n, l); n->left = r; if (n->left) { n->left->parent = n; } l->right = n; l->right->parent = l; if (cb && cb->rotate) { cb->rotate(t, n, l); } }
static void rb_rotate_right(struct rb_root *root, struct rb_node* node) { struct rb_node* left = node->rb_left; rb_replace_node(root, node, left); node->rb_left = left->rb_right; if (left->rb_right != NULL) { left->rb_right->rb_parent = node; } left->rb_right = node; node->rb_parent = left; }
void rb_unlink(struct rb_tree *t, struct rb_node *n, struct rb_callbacks *cb) { CHECK(!rb_empty_node(n)); /* when deleting a node with two non-leaf children, we swap the node with its in-order predecessor (the maximum or rightmost element in the left subtree), and then delete the original node which now has only one non-leaf child */ if (n->left && n->right) { struct rb_node *pred = rb_max(n->left); rb_swap_node(t, n, pred); } /* a node with at most one non-leaf child can simply be replaced with its non-leaf child */ CHECK(!n->left || !n->right); struct rb_node *child = n->right ? n->right : n->left; if (rb_color(n) == RB_BLACK) { rb_unlink_1(t, n, cb); } rb_replace_node(t, n, child); /* force root to black */ if (t->root) { t->root->color = RB_BLACK; } /* fix up each node in the parent chain */ if (cb && cb->propagate) { cb->propagate(t, n->parent); } /* clear node state to support rb_empty_node */ memset(n, 0, sizeof(*n)); #if VERIFY_TREE rb_verify(t->root); #endif }
/* * This function is used when we read an inode. Data nodes arrive in * arbitrary order -- they may be older or newer than the nodes which * are already in the tree. Where overlaps occur, the older node can * be discarded as long as the newer passes the CRC check. We don't * bother to keep track of holes in this rbtree, and neither do we deal * with frags -- we can have multiple entries starting at the same * offset, and the one with the smallest length will come first in the * ordering. * * Returns 0 if the node was handled (including marking it obsolete) * < 0 an if error occurred */ static int jffs2_add_tn_to_tree(struct jffs2_sb_info *c, struct jffs2_readinode_info *rii, struct jffs2_tmp_dnode_info *tn) { uint32_t fn_end = tn->fn->ofs + tn->fn->size; struct jffs2_tmp_dnode_info *this, *ptn; dbg_readinode("insert fragment %#04x-%#04x, ver %u at %08x\n", tn->fn->ofs, fn_end, tn->version, ref_offset(tn->fn->raw)); /* If a node has zero dsize, we only have to keep if it if it might be the node with highest version -- i.e. the one which will end up as f->metadata. Note that such nodes won't be REF_UNCHECKED since there are no data to check anyway. */ if (!tn->fn->size) { if (rii->mdata_tn) { if (rii->mdata_tn->version < tn->version) { /* We had a candidate mdata node already */ dbg_readinode("kill old mdata with ver %d\n", rii->mdata_tn->version); jffs2_kill_tn(c, rii->mdata_tn); } else { dbg_readinode("kill new mdata with ver %d (older than existing %d\n", tn->version, rii->mdata_tn->version); jffs2_kill_tn(c, tn); return 0; } } rii->mdata_tn = tn; dbg_readinode("keep new mdata with ver %d\n", tn->version); return 0; } /* Find the earliest node which _may_ be relevant to this one */ this = jffs2_lookup_tn(&rii->tn_root, tn->fn->ofs); if (this) { /* If the node is coincident with another at a lower address, back up until the other node is found. It may be relevant */ while (this->overlapped) { ptn = tn_prev(this); if (!ptn) { /* * We killed a node which set the overlapped * flags during the scan. Fix it up. */ this->overlapped = 0; break; } this = ptn; } dbg_readinode("'this' found %#04x-%#04x (%s)\n", this->fn->ofs, this->fn->ofs + this->fn->size, this->fn ? "data" : "hole"); } while (this) { if (this->fn->ofs > fn_end) break; dbg_readinode("Ponder this ver %d, 0x%x-0x%x\n", this->version, this->fn->ofs, this->fn->size); if (this->version == tn->version) { /* Version number collision means REF_PRISTINE GC. Accept either of them as long as the CRC is correct. Check the one we have already... */ if (!check_tn_node(c, this)) { /* The one we already had was OK. Keep it and throw away the new one */ dbg_readinode("Like old node. Throw away new\n"); jffs2_kill_tn(c, tn); return 0; } else { /* Who cares if the new one is good; keep it for now anyway. */ dbg_readinode("Like new node. Throw away old\n"); rb_replace_node(&this->rb, &tn->rb, &rii->tn_root); jffs2_kill_tn(c, this); /* Same overlapping from in front and behind */ return 0; } } if (this->version < tn->version && this->fn->ofs >= tn->fn->ofs && this->fn->ofs + this->fn->size <= fn_end) { /* New node entirely overlaps 'this' */ if (check_tn_node(c, tn)) { dbg_readinode("new node bad CRC\n"); jffs2_kill_tn(c, tn); return 0; } /* ... and is good. Kill 'this' and any subsequent nodes which are also overlapped */ while (this && this->fn->ofs + this->fn->size <= fn_end) { struct jffs2_tmp_dnode_info *next = tn_next(this); if (this->version < tn->version) { tn_erase(this, &rii->tn_root); dbg_readinode("Kill overlapped ver %d, 0x%x-0x%x\n", this->version, this->fn->ofs, this->fn->ofs+this->fn->size); jffs2_kill_tn(c, this); } this = next; } dbg_readinode("Done killing overlapped nodes\n"); continue; } if (this->version > tn->version && this->fn->ofs <= tn->fn->ofs && this->fn->ofs+this->fn->size >= fn_end) { /* New node entirely overlapped by 'this' */ if (!check_tn_node(c, this)) { dbg_readinode("Good CRC on old node. Kill new\n"); jffs2_kill_tn(c, tn); return 0; } /* ... but 'this' was bad. Replace it... */ dbg_readinode("Bad CRC on old overlapping node. Kill it\n"); tn_erase(this, &rii->tn_root); jffs2_kill_tn(c, this); break; } this = tn_next(this); } /* We neither completely obsoleted nor were completely obsoleted by an earlier node. Insert into the tree */ { struct rb_node *parent; struct rb_node **link = &rii->tn_root.rb_node; struct jffs2_tmp_dnode_info *insert_point = NULL; while (*link) { parent = *link; insert_point = rb_entry(parent, struct jffs2_tmp_dnode_info, rb); if (tn->fn->ofs > insert_point->fn->ofs) link = &insert_point->rb.rb_right; else if (tn->fn->ofs < insert_point->fn->ofs || tn->fn->size < insert_point->fn->size) link = &insert_point->rb.rb_left; else link = &insert_point->rb.rb_right; } rb_link_node(&tn->rb, &insert_point->rb, link); rb_insert_color(&tn->rb, &rii->tn_root); } /* If there's anything behind that overlaps us, note it */ this = tn_prev(tn); if (this) { while (1) { if (this->fn->ofs + this->fn->size > tn->fn->ofs) { dbg_readinode("Node is overlapped by %p (v %d, 0x%x-0x%x)\n", this, this->version, this->fn->ofs, this->fn->ofs+this->fn->size); tn->overlapped = 1; break; } if (!this->overlapped) break; ptn = tn_prev(this); if (!ptn) { /* * We killed a node which set the overlapped * flags during the scan. Fix it up. */ this->overlapped = 0; break; } this = ptn; } } /* If the new node overlaps anything ahead, note it */ this = tn_next(tn); while (this && this->fn->ofs < fn_end) { this->overlapped = 1; dbg_readinode("Node ver %d, 0x%x-0x%x is overlapped\n", this->version, this->fn->ofs, this->fn->ofs+this->fn->size); this = tn_next(this); } return 0; }
static inline int reliable_ack___save (su_serv_t *psvr, const frames_t *frame, const void *outbuff, int outbytes) { /* Construct search key */ rb_key_cache_t key; memcpy(&key.destaddr, &frame->srcaddr, sizeof(SAUN)); key.destlen = frame->srclen; key.seq = frame->recvhdr.seq; key.sid = frame->recvhdr.sid; struct rb_node *cachenode; cache_t *cache; /* If is no reply content, only replace len value, don't replace node * If have a content, must allocating and replacing new node */ if (outbuff == 0 && outbytes == 0) { if ((cachenode = rb_search(&psvr->rbackcache, &key))) { cache = rb_entry(cachenode, cache_t, rbn); cache->frame.len = 0; #if defined SU_DEBUG_LIST || defined SU_DEBUG_RBTREE pthread_t tid = pthread_self(); char ipbuff[INET6_ADDRSTRLEN]; int port; su_get_ip_port_f(&cache->frame.srcaddr, ipbuff, sizeof(ipbuff), &port); log_msg("serv %x %x time %u key(%s:%d:%u:%u) " ColorRed "+ACK cache %p" ColorEnd , psvr, tid, cache->ts, ipbuff, port, cache->frame.recvhdr.sid, cache->frame.recvhdr.seq, cache); #endif return 0; } errno = ENOKEY; return -1; } cache_t * newack; newack = calloc(1, sizeof(cache_t) + outbytes); if (newack == 0) { errno = ENOBUFS; return -1; } /* Construct a new node */ memcpy(&newack->frame, frame, sizeof(frames_t)); memcpy(newack->frame.data, outbuff, outbytes); newack->frame.len = outbytes; /* Find and replace the hold node */ if ((cachenode = rb_search(&psvr->rbackcache, &key))) { rb_replace_node(cachenode, &newack->rbn, &psvr->rbackcache); cache = rb_entry(cachenode, cache_t, rbn); newack->ts = cache->ts; list_remove(&cache->frame.node); list_append(&psvr->lsackcache, &newack->frame.node); #if defined SU_DEBUG_LIST || defined SU_DEBUG_RBTREE pthread_t tid = pthread_self(); char ipbuff[INET6_ADDRSTRLEN]; int port; su_get_ip_port_f(&newack->frame.srcaddr, ipbuff, sizeof(ipbuff), &port); log_msg("serv %x %x time %u key(%s:%d:%u:%u) " ColorRed "+ACK cache %p Swap %p" ColorEnd , psvr, tid, newack->ts, ipbuff, port, frame->recvhdr.sid, frame->recvhdr.seq, cache, newack); #endif free(cache); return 0; } free(newack); errno = ENOKEY; return -1; }
/* Build a new IP datagram from all its fragments. */ static int ip_frag_reasm(struct ipq *qp, struct sk_buff *skb, struct sk_buff *prev_tail, struct net_device *dev) { struct net *net = container_of(qp->q.net, struct net, ipv4.frags); struct iphdr *iph; struct sk_buff *fp, *head = skb_rb_first(&qp->q.rb_fragments); struct sk_buff **nextp; /* To build frag_list. */ struct rb_node *rbn; int len; int ihlen; int err; u8 ecn; ipq_kill(qp); ecn = ip_frag_ecn_table[qp->ecn]; if (unlikely(ecn == 0xff)) { err = -EINVAL; goto out_fail; } /* Make the one we just received the head. */ if (head != skb) { fp = skb_clone(skb, GFP_ATOMIC); if (!fp) goto out_nomem; FRAG_CB(fp)->next_frag = FRAG_CB(skb)->next_frag; if (RB_EMPTY_NODE(&skb->rbnode)) FRAG_CB(prev_tail)->next_frag = fp; else rb_replace_node(&skb->rbnode, &fp->rbnode, &qp->q.rb_fragments); if (qp->q.fragments_tail == skb) qp->q.fragments_tail = fp; skb_morph(skb, head); FRAG_CB(skb)->next_frag = FRAG_CB(head)->next_frag; rb_replace_node(&head->rbnode, &skb->rbnode, &qp->q.rb_fragments); consume_skb(head); head = skb; } WARN_ON(head->ip_defrag_offset != 0); /* Allocate a new buffer for the datagram. */ ihlen = ip_hdrlen(head); len = ihlen + qp->q.len; err = -E2BIG; if (len > 65535) goto out_oversize; /* Head of list must not be cloned. */ if (skb_unclone(head, GFP_ATOMIC)) goto out_nomem; /* If the first fragment is fragmented itself, we split * it to two chunks: the first with data and paged part * and the second, holding only fragments. */ if (skb_has_frag_list(head)) { struct sk_buff *clone; int i, plen = 0; clone = alloc_skb(0, GFP_ATOMIC); if (!clone) goto out_nomem; skb_shinfo(clone)->frag_list = skb_shinfo(head)->frag_list; skb_frag_list_init(head); for (i = 0; i < skb_shinfo(head)->nr_frags; i++) plen += skb_frag_size(&skb_shinfo(head)->frags[i]); clone->len = clone->data_len = head->data_len - plen; head->truesize += clone->truesize; clone->csum = 0; clone->ip_summed = head->ip_summed; add_frag_mem_limit(qp->q.net, clone->truesize); skb_shinfo(head)->frag_list = clone; nextp = &clone->next; } else { nextp = &skb_shinfo(head)->frag_list; } skb_push(head, head->data - skb_network_header(head)); /* Traverse the tree in order, to build frag_list. */ fp = FRAG_CB(head)->next_frag; rbn = rb_next(&head->rbnode); rb_erase(&head->rbnode, &qp->q.rb_fragments); while (rbn || fp) { /* fp points to the next sk_buff in the current run; * rbn points to the next run. */ /* Go through the current run. */ while (fp) { *nextp = fp; nextp = &fp->next; fp->prev = NULL; memset(&fp->rbnode, 0, sizeof(fp->rbnode)); head->data_len += fp->len; head->len += fp->len; if (head->ip_summed != fp->ip_summed) head->ip_summed = CHECKSUM_NONE; else if (head->ip_summed == CHECKSUM_COMPLETE) head->csum = csum_add(head->csum, fp->csum); head->truesize += fp->truesize; fp = FRAG_CB(fp)->next_frag; } /* Move to the next run. */ if (rbn) { struct rb_node *rbnext = rb_next(rbn); fp = rb_to_skb(rbn); rb_erase(rbn, &qp->q.rb_fragments); rbn = rbnext; } } sub_frag_mem_limit(qp->q.net, head->truesize); *nextp = NULL; head->next = NULL; head->prev = NULL; head->dev = dev; head->tstamp = qp->q.stamp; IPCB(head)->frag_max_size = max(qp->max_df_size, qp->q.max_size); iph = ip_hdr(head); iph->tot_len = htons(len); iph->tos |= ecn; /* When we set IP_DF on a refragmented skb we must also force a * call to ip_fragment to avoid forwarding a DF-skb of size s while * original sender only sent fragments of size f (where f < s). * * We only set DF/IPSKB_FRAG_PMTU if such DF fragment was the largest * frag seen to avoid sending tiny DF-fragments in case skb was built * from one very small df-fragment and one large non-df frag. */ if (qp->max_df_size == qp->q.max_size) { IPCB(head)->flags |= IPSKB_FRAG_PMTU; iph->frag_off = htons(IP_DF); } else { iph->frag_off = 0; } ip_send_check(iph); __IP_INC_STATS(net, IPSTATS_MIB_REASMOKS); qp->q.fragments = NULL; qp->q.rb_fragments = RB_ROOT; qp->q.fragments_tail = NULL; qp->q.last_run_head = NULL; return 0; out_nomem: net_dbg_ratelimited("queue_glue: no memory for gluing queue %p\n", qp); err = -ENOMEM; goto out_fail; out_oversize: net_info_ratelimited("Oversized IP packet from %pI4\n", &qp->q.key.v4.saddr); out_fail: __IP_INC_STATS(net, IPSTATS_MIB_REASMFAILS); return err; }
/* * Oops, a fragment queue timed out. Kill it and send an ICMP reply. */ static void ip_expire(struct timer_list *t) { struct inet_frag_queue *frag = from_timer(frag, t, timer); const struct iphdr *iph; struct sk_buff *head = NULL; struct net *net; struct ipq *qp; int err; qp = container_of(frag, struct ipq, q); net = container_of(qp->q.net, struct net, ipv4.frags); rcu_read_lock(); spin_lock(&qp->q.lock); if (qp->q.flags & INET_FRAG_COMPLETE) goto out; ipq_kill(qp); __IP_INC_STATS(net, IPSTATS_MIB_REASMFAILS); __IP_INC_STATS(net, IPSTATS_MIB_REASMTIMEOUT); if (!(qp->q.flags & INET_FRAG_FIRST_IN)) goto out; /* sk_buff::dev and sk_buff::rbnode are unionized. So we * pull the head out of the tree in order to be able to * deal with head->dev. */ if (qp->q.fragments) { head = qp->q.fragments; qp->q.fragments = head->next; } else { head = skb_rb_first(&qp->q.rb_fragments); if (!head) goto out; if (FRAG_CB(head)->next_frag) rb_replace_node(&head->rbnode, &FRAG_CB(head)->next_frag->rbnode, &qp->q.rb_fragments); else rb_erase(&head->rbnode, &qp->q.rb_fragments); memset(&head->rbnode, 0, sizeof(head->rbnode)); barrier(); } if (head == qp->q.fragments_tail) qp->q.fragments_tail = NULL; sub_frag_mem_limit(qp->q.net, head->truesize); head->dev = dev_get_by_index_rcu(net, qp->iif); if (!head->dev) goto out; /* skb has no dst, perform route lookup again */ iph = ip_hdr(head); err = ip_route_input_noref(head, iph->daddr, iph->saddr, iph->tos, head->dev); if (err) goto out; /* Only an end host needs to send an ICMP * "Fragment Reassembly Timeout" message, per RFC792. */ if (frag_expire_skip_icmp(qp->q.key.v4.user) && (skb_rtable(head)->rt_type != RTN_LOCAL)) goto out; spin_unlock(&qp->q.lock); icmp_send(head, ICMP_TIME_EXCEEDED, ICMP_EXC_FRAGTIME, 0); goto out_rcu_unlock; out: spin_unlock(&qp->q.lock); out_rcu_unlock: rcu_read_unlock(); if (head) kfree_skb(head); ipq_put(qp); }
void rb_erase(struct rb_node *node, struct rb_root* root) { struct rb_node *t_node, *tp_node; struct rb_node *s_node, *c_node; int _switch = 1; if ((node->rb_left != NULL)&&(node->rb_right != NULL)) { for (t_node = node; t_node->rb_right != NULL; t_node = t_node->rb_right); tp_node = t_node->rb_parent; rb_replace_node (root, node, t_node); tp_node->rb_right = node; node->rb_parent = tp_node; tp_node = t_node->rb_left; t_node->rb_left = node->rb_left; t_node->rb_right = node->rb_right; node->rb_left = tp_node; node->rb_right = NULL; } c_node = (node->rb_right == NULL) ? node->rb_left: node->rb_right; t_node = node; if (node->color == BLACK) { node->color = c_node->color; while (_switch) { s_node = (node->rb_parent != NULL) ? \ ((node->rb_parent->rb_left == node) ? node->rb_parent->rb_right : node->rb_parent->rb_left) \ : NULL; switch(_switch) { case 1: if (node->rb_parent == NULL) { _switch = 0; break; } case 2: if (s_node->color == RED) { node->rb_parent->color = RED; s_node->color = BLACK; if (node == node->rb_parent->rb_left) rb_rotate_left(root, node->rb_parent); else rb_rotate_right(root, node->rb_parent); _switch = 0; break; } case 3: if ((node->rb_parent->color == BLACK) && \ (s_node->color == BLACK) && \ (s_node->rb_left->color == BLACK) && \ (s_node->rb_right->color == BLACK)) { s_node->color = RED; _switch = 1; node = node->rb_parent; break; } case 4: if ((node->rb_parent->color == RED) && \ (s_node->color == BLACK) && \ (s_node->rb_left->color == BLACK) && \ (s_node->rb_right->color == BLACK)) { s_node->color = RED; node->rb_parent->color = BLACK; _switch = 0; break; } case 5: if (s_node->color == BLACK) { if ((node == node->rb_parent->rb_left) && \ (s_node->rb_right->color == BLACK) && \ (s_node->rb_left->color == RED)) { s_node->color = RED; s_node->rb_left->color = BLACK; rb_rotate_right(root, s_node); } else if((node == node->rb_parent->rb_right) && \ (s_node->rb_left->color == BLACK) && \ (s_node->rb_right->color = RED)) { s_node->color = RED; s_node->rb_right->color = BLACK; rb_rotate_left(root, s_node); } _switch = 0; break; } case 6: s_node->color = node->rb_parent->color; node->rb_parent->color = BLACK; if (node == node->rb_parent->rb_left) { s_node->rb_right->color = BLACK; rb_rotate_left(root, node->rb_parent); } else { s_node->rb_left->color = BLACK; rb_rotate_right(root, node->rb_parent); } _switch = 0; break; default: _switch = 0; break; } } } rb_replace_node (root, t_node, c_node); }