Chinaunix

标题: Kernel Bug-Vulnerability-Comment library [打印本页]

作者: sisi8408    时间: 2007-08-18 13:49
标题: Kernel Bug-Vulnerability-Comment library
这里搜集/整理/讨论 linux 八哥/漏洞,和解决方案

[ 本帖最后由 sisi8408 于 2008-7-27 14:20 编辑 ]
作者: sisi8408    时间: 2007-08-18 13:52

  1. linux-2.6.17.x/drivers/net/ppp_generic.c

  2. static void cardmap_set(struct cardmap **pmap, unsigned int nr, void *ptr)
  3. {
  4.         struct cardmap *p;
  5.         int i;

  6.         p = *pmap;
  7.         if (p == NULL || (nr >> p->shift) >= CARDMAP_WIDTH) {
  8.                 do {
  9.                         /* need a new top level */
  10.                         struct cardmap *np = kmalloc(sizeof(*np), GFP_KERNEL);
  11.                         /*
  12.                          * ¥6
  13.                          * if (np == NULL)
  14.                          *        what_to_do???
  15.                          */
  16.                         memset(np, 0, sizeof(*np));
  17.                         np->ptr[0] = p;
  18.                         if (p != NULL) {
  19.                                 np->shift = p->shift + CARDMAP_ORDER;
  20.                                 p->parent = np;
  21.                         } else
  22.                                 np->shift = 0;
  23.                         p = np;
  24.                         /*
  25.                          * ¥3
  26.                          * if (p->shift == 0)
  27.                          *      ask_linuz_stop_while_loop???
  28.                          */
  29.                 } while ((nr >> p->shift) >= CARDMAP_WIDTH);
  30.                 *pmap = p;
  31.         }
  32.         while (p->shift > 0) {
  33.                 i = (nr >> p->shift) & CARDMAP_MASK;
  34.                 if (p->ptr[i] == NULL) {
  35.                         struct cardmap *np = kmalloc(sizeof(*np), GFP_KERNEL);
  36.                         memset(np, 0, sizeof(*np));
  37.                         np->shift = p->shift - CARDMAP_ORDER;
  38.                         np->parent = p;
  39.                         p->ptr[i] = np;
  40.                 }
  41.                 if (ptr == NULL)
  42.                         clear_bit(i, &p->inuse);
  43.                 p = p->ptr[i];
  44.         }
  45.         i = nr & CARDMAP_MASK;
  46.         p->ptr[i] = ptr;
  47.         if (ptr != NULL)
  48.                 set_bit(i, &p->inuse);
  49.         else
  50.                 clear_bit(i, &p->inuse);
  51. }
复制代码

[ 本帖最后由 sisi8408 于 2007-8-18 14:20 编辑 ]
作者: sisi8408    时间: 2007-08-18 13:56

  1. linux-2.6.22.1/kernel/time/timer_list.c

  2. static void print_active_timers(struct seq_file *m,
  3.         struct hrtimer_clock_base *base, u64 now)
  4. {
  5.         struct hrtimer *timer, tmp;
  6.         unsigned long next = 0, i;
  7.         struct rb_node *curr;
  8.         unsigned long flags;

  9. next_one:
  10.         i = 0;
  11.         spin_lock_irqsave(&base->cpu_base->lock, flags);

  12.         curr = base->first;
  13.         /*
  14.          * Crude but we have to do this O(N*N) thing, because
  15.          * we have to unlock the base when printing:
  16.          */
  17.         while (curr && i < next) {
  18.                 curr = rb_next(curr);
  19.                 i++;
  20.         }

  21.         if (curr) {
  22.                 timer = rb_entry(curr, struct hrtimer, node);
  23.                 tmp = *timer;
  24.                 spin_unlock_irqrestore(&base->cpu_base->lock, flags);
  25.                 /*
  26.                  * yeah Ingo Molnar, ifuleu,
  27.                  * but print shows not timer but tmp,
  28.                  * how can i see %p timer??
  29.                  */
  30.                 print_timer(m, &tmp, i, now);
  31.                 next++;
  32.                 goto next_one;
  33.         }
  34.         spin_unlock_irqrestore(&base->cpu_base->lock, flags);
  35. }
复制代码

[ 本帖最后由 sisi8408 于 2007-8-18 13:58 编辑 ]
作者: sisi8408    时间: 2007-08-18 14:04

  1. /*
  2. * linux-2.6.22.1/net/ipv4/ip_fragment.c
  3. *
  4. * Oops, a fragment queue timed out.
  5. * Kill it and send an ICMP reply.
  6. *
  7. * sisi 2007-8-13 02:27pm
  8. */
  9. static void ip_expire(unsigned long arg)
  10. {
  11.         struct ipq *qp = (struct ipq *) arg;

  12.         spin_lock(&qp->lock);

  13.         if (qp->last_in & COMPLETE)
  14.                 goto out;

  15.         ipq_kill(qp);

  16.         IP_INC_STATS_BH(IPSTATS_MIB_REASMTIMEOUT);
  17.         IP_INC_STATS_BH(IPSTATS_MIB_REASMFAILS);

  18.         if ((qp->last_in&FIRST_IN) && qp->fragments != NULL) {
  19.                 struct sk_buff *head = qp->fragments;
  20.                 /*
  21.                  * Send an ICMP "Fragment Reassembly Timeout" message.
  22.                  *
  23.                  * 由这里引发
  24.                  */
  25.                 if ((head->dev = dev_get_by_index(qp->iif)) != NULL) {
  26.                         icmp_send(head, ICMP_TIME_EXCEEDED, ICMP_EXC_FRAGTIME, 0);
  27.                         dev_put(head->dev);
  28.                 }
  29.         }
  30. out:
  31.         spin_unlock(&qp->lock);
  32.         ipq_put(qp, NULL);
  33. }

  34. void icmp_send(struct sk_buff *skb_in, int type, int code, __be32 info)
  35. {
  36.         struct iphdr *iph;
  37.         int room;
  38.         struct icmp_bxm icmp_param;
  39.         struct rtable *rt = (struct rtable *)skb_in->dst;
  40.         struct ipcm_cookie ipc;
  41.         __be32 saddr;
  42.         u8  tos;

  43.         if (!rt) {
  44.                 /* 在这里兑现,
  45.                  *
  46.                  * defarg, if issued by netfilter,
  47.                  * at PRE_ROUTING in normal cases,
  48.                  * 谁给skb_in->dst赋值?
  49.                  *
  50.                  * 本应发送Fragment Reassembly Timeout message,
  51.                  * 确没有发。
  52.                  */
  53.                 goto out;
  54.         }
  55. }
复制代码


  1. shot bug by daemeon

  2. --- linux-2.6.22/net/ipv4/icmp.c        2007-07-09 07:32:17.000000000 +0800
  3. +++ new/net/ipv4/icmp.c        2007-08-13 17:36:21.000000000 +0800
  4. @@ -440,9 +440,6 @@ void icmp_send(struct sk_buff *skb_in, i
  5.         __be32 saddr;
  6.         u8  tos;

  7. -        if (!rt)
  8. -                goto out;
  9. -
  10.         /*
  11.          *        Find the original header. It is expected to be valid, of course.
  12.          *        Check this, icmp_send is called from the most obscure devices
  13. @@ -461,16 +458,24 @@ void icmp_send(struct sk_buff *skb_in, i
  14.                 goto out;

  15.         /*
  16. -         *        Now check at the protocol level
  17. +         *        Only reply to fragment 0. We byte re-order the constant
  18. +         *        mask for efficiency.
  19.          */
  20. -        if (rt->rt_flags & (RTCF_BROADCAST | RTCF_MULTICAST))
  21. +        if (iph->frag_off & htons(IP_OFFSET))
  22.                 goto out;

  23. +        if (!rt) {
  24. +                if (ip_route_input(skb_in, iph->daddr, iph->saddr,
  25. +                                        iph->tos, skb_in->dev) != 0)
  26. +                        goto out;
  27. +
  28. +                rt = (struct rtable *)skb_in->dst;
  29. +        }
  30. +
  31.         /*
  32. -         *        Only reply to fragment 0. We byte re-order the constant
  33. -         *        mask for efficiency.
  34. +         *        Now check at the protocol level
  35.          */
  36. -        if (iph->frag_off & htons(IP_OFFSET))
  37. +        if (rt->rt_flags & (RTCF_BROADCAST | RTCF_MULTICAST))
  38.                 goto out;

  39.         /*
复制代码


daemeon won ¥4。
版权问题,请daemeon大哥确认。


  1. refined by rtable

  2. +        if (!rt) {
  3. +                struct net_device __ndev;
  4. +
  5. +                if (skb_in->input_dev)
  6. +                    __ndev = skb_in->input_dev;
  7. +                else
  8. +                   __ndev = get_dev_by_index(skb_in->iif);
  9. +                if (!__ndev)
  10. +                   goto out;
  11. +
  12. +                if (ip_route_input(skb_in, iph->daddr, iph->saddr,
  13. +                                             iph->tos, __ndev) != 0)
  14. +                        goto out;
  15. +
  16. +                rt = (struct rtable *)skb_in->dst;
  17. +        }
复制代码

[ 本帖最后由 sisi8408 于 2007-8-18 14:37 编辑 ]
作者: sisi8408    时间: 2007-08-18 14:06

  1. /*
  2. * linux-2.6.22.1/net/xfrm/xfrm_state.c
  3. * sisi 2007-8-14 10:44am
  4. */
  5. int km_report (u8 proto, struct xfrm_selector *sel, xfrm_address_t *addr)
  6. {
  7.         int err = -EINVAL;
  8.         int ret;
  9.         struct xfrm_mgr *km;

  10.         read_lock(&xfrm_km_lock);
  11.         list_for_each_entry(km, &xfrm_km_list, list) {
  12.                 if (km->report) {
  13.                         ret = km->report(proto, sel, addr);
  14.                         if (!ret)
  15.                                 err = ret;
  16.                 }
  17.         }
  18.         read_unlock(&xfrm_km_lock);
  19.         /*
  20.          * err report bug
  21.          */
  22.         return err;
  23. }
复制代码

作者: sisi8408    时间: 2007-08-18 14:10

  1. linux-2.6.20.7 漏洞

  2. static int wanpipe_rcv(struct sk_buff *skb, struct net_device *dev,
  3.                        struct sock *sk)
  4. {
  5.         struct wan_sockaddr_ll * sll = (struct wan_sockaddr_ll *)skb->cb;
  6.         wanpipe_common_t * chan = dev->priv;
  7.         /*
  8.          * When we registered the protocol,
  9.          * we saved the socket in the data field for just this event.
  10.          */
  11.         skb->dev = dev;

  12.         sll->sll_family = AF_WANPIPE;
  13.         sll->sll_hatype = dev->type;
  14.         sll->sll_protocol = skb->protocol;
  15.         sll->sll_pkttype = skb->pkt_type;
  16.         sll->sll_ifindex = dev->ifindex;
  17.       
  18.         sll->sll_halen = 0;
  19.         if (dev->hard_header_parse)
  20.                 sll->sll_halen = dev->hard_header_parse(skb, sll->sll_addr);

  21.         /*
  22.          * WAN_PACKET_DATA : Data which should be passed up the receive queue.
  23.          * WAN_PACKET_ASYC : Asynchronous data like place call, which should
  24.          *                   be passed up the listening sock.
  25.          * WAN_PACKET_ERR  : Asynchronous data like clear call or restart
  26.          *                   which should go into an error queue.
  27.          */
  28.         switch (skb->pkt_type) {
  29.                 case WAN_PACKET_DATA:
  30.                         if (sock_queue_rcv_skb(sk, skb) < 0) {
  31.                                 return -ENOMEM;
  32.                         }
  33.                         break;
  34.                
  35.                 case WAN_PACKET_CMD:
  36.                         sk->sk_state = chan->state;
  37.                         /* Bug fix: update Mar6.
  38.                          * Do not set the sock lcn number here, since
  39.                           * cmd is not guaranteed to be executed on the
  40.                          * board, thus Lcn could be wrong
  41.                          */
  42.                         sk->sk_data_ready(sk, skb->len);
  43.                         kfree_skb(skb);
  44.                         break;
  45.                
  46.                 case WAN_PACKET_ERR:
  47.                         sk->sk_state = chan->state;
  48.                         if (sock_queue_err_skb(sk,skb)<0){
  49.                                 return -ENOMEM;
  50.                         }
  51.                         break;
  52.                
  53.                 default:
  54.                         //at this case 就在这儿,呵呵
  55.                         printk(KERN_INFO "wansock: BH Illegal Packet Type Dropping\n");
  56.                         kfree_skb(skb);
  57.                         break;
  58.         }
  59.         return 0;
  60. }
复制代码

作者: daemeon    时间: 2007-08-18 14:53
标题: 回复 #1 sisi8408 的帖子
>>请daemeon大哥确认
狂汗

print_active_timers不会是指Andrew的注释里的说问题吧?
作者: sisi8408    时间: 2007-08-18 14:58
标题: 回复 #7 daemeon 的帖子
请细说Andrew的注释里的问题,

这里请注意spin lock 的用法,¥1 就为这个。

化¥1 理解I Molnar的苦心,if(timer_pending(t))让俺受苦。
¥5 for WAN 还等你出手,呵呵。

[ 本帖最后由 sisi8408 于 2007-8-18 15:13 编辑 ]
作者: daemeon    时间: 2007-08-18 16:06
标题: 回复 #8 sisi8408 的帖子
spin_lock用法没有问题.
作者: sisi8408    时间: 2007-08-18 16:22
标题: 回复 #9 daemeon 的帖子
的确没问题,他干吗用个tmp,还要memcpy?
俺查看timer的地址,对吗?

[ 本帖最后由 sisi8408 于 2007-8-18 16:33 编辑 ]
作者: daemeon    时间: 2007-08-18 16:50
after release lock, how to guarantee timer not  freed in other place.
作者: sisi8408    时间: 2007-08-18 17:00
标题: 回复 #11 daemeon 的帖子
you won ¥1, congratulation.

but how can i get timer, say through /dev/mem after lunch?

[ 本帖最后由 sisi8408 于 2007-8-19 09:49 编辑 ]
作者: sisi8408    时间: 2007-08-19 10:12

  1. /*
  2. * linux-2.6.20.7/kernel/time/clocksource.c
  3. */
  4. static ssize_t sysfs_show_available_clocksources(struct sys_device *dev, char *buf)
  5. {
  6.         struct list_head *tmp;
  7.         char *curr = buf;

  8.         spin_lock_irq(&clocksource_lock);
  9.         list_for_each(tmp, &clocksource_list) {
  10.                 struct clocksource *src;

  11.                 src = list_entry(tmp, struct clocksource, list);
  12.                 /*
  13.                  * no check of buf overflow
  14.                  */
  15.                 curr += sprintf(curr, "%s ", src->name);
  16.         }
  17.         spin_unlock_irq(&clocksource_lock);
  18.         curr += sprintf(curr, "\n");
  19.         return curr - buf;
  20. }
复制代码

作者: sisi8408    时间: 2007-08-19 10:18

  1. /*
  2. * linux-2.6.20.7/kernel/time/clocksource.c
  3. */
  4. static int __init init_clocksource_sysfs(void)
  5. {
  6.         int error = sysdev_class_register(&clocksource_sysclass);

  7.         if (!error)
  8.                 error = sysdev_register(&device_clocksource);
  9.         if (!error)
  10.                 error = sysdev_create_file(
  11.                                 &device_clocksource,
  12.                                 &attr_current_clocksource);
  13.         /*
  14.          * lack of xxx_unregister to clean trash
  15.          */
  16.         if (!error)
  17.                 error = sysdev_create_file(
  18.                                 &device_clocksource,
  19.                                 &attr_available_clocksource);
  20.         return error;
  21. }
复制代码

作者: Solaris12    时间: 2007-08-19 11:32
原帖由 sisi8408 于 2007-8-18 13:49 发表
这里搜集/整理/讨论 linux 八哥/漏洞,和解决方案

贴八哥/漏洞,一次性获得¥1,最多¥2。


贴解决方案,一次性获得¥1,最多¥9。


1,如果要求任何版权,sisi8408只承诺 版权归地球人,与GPLvx无关 ...



不明白你们为什么要这样做,不如直接提交bug给Linux社区,这样即贡献了社区,如果你自己理解有误,自己又学习东西了。我并不反对大家交流,希望交流以后,能提交bug给社区,甚至是提交patch给社区。



到今天为之我提交了过不少bug给Solaris,其中大多数是驱动/tcp-ip/内核相关的。一开始提交bug只是简单描述下问题,或者重现步骤,但后来有些bug就可以给出一些自己的分析,甚至指出那里可能有问题。

提交bug能学到很多东西,尤其是从修bug的人那里。

所以说,大家不要放弃通过提交bug和那些内核开发者的交流机会。

[ 本帖最后由 Solaris12 于 2007-8-19 11:37 编辑 ]
作者: sisi8408    时间: 2007-08-19 11:59
标题: 回复 #15 Solaris12 的帖子
1,敬仰 提交了不少bug给Solaris。
     如果能在CU分享,俺看就是美事。

2,提交和搜集不矛盾,也不冲突。
     表达自己的想法,在LKML、bugzila、CU,可能没有本质区别,都是社区吗。

3,¥表示致敬和鼓励干涩的眼睛,是俺的心意,俺很乐意。

[ 本帖最后由 sisi8408 于 2007-8-23 10:27 编辑 ]
作者: sisi8408    时间: 2007-08-19 14:31

  1. /*
  2. * linux-2.6.20.7/net/ipv4/netfilter/ip_conntrack_core.c
  3. */
  4. int __init ip_conntrack_init(void)
  5. {
  6.         unsigned int i;
  7.         int ret;

  8.         /* Idea from tcp.c: use 1/16384 of memory.  On i386: 32MB
  9.          * machine has 256 buckets.  >= 1GB machines have 8192 buckets. */
  10.         if (!ip_conntrack_htable_size) {
  11.                 ip_conntrack_htable_size
  12.                         = (((num_physpages << PAGE_SHIFT) / 16384)
  13.                            / sizeof(struct list_head));
  14.                 if (num_physpages > (1024 * 1024 * 1024 / PAGE_SIZE))
  15.                         ip_conntrack_htable_size = 8192;
  16.                 if (ip_conntrack_htable_size < 16)
  17.                         ip_conntrack_htable_size = 16;
  18.         }
  19.         ip_conntrack_max = 8 * ip_conntrack_htable_size;

  20.         printk("ip_conntrack version %s (%u buckets, %d max)"
  21.                " - %Zd bytes per conntrack\n", IP_CONNTRACK_VERSION,
  22.                ip_conntrack_htable_size, ip_conntrack_max,
  23.                sizeof(struct ip_conntrack));

  24.         ret = nf_register_sockopt(&so_getorigdst);
  25.         if (ret != 0) {
  26.                 printk(KERN_ERR "Unable to register netfilter socket option\n");
  27.                 return ret;
  28.         }

  29.         ip_conntrack_hash = alloc_hashtable(ip_conntrack_htable_size,
  30.                                             &ip_conntrack_vmalloc);
  31.         if (!ip_conntrack_hash) {
  32.                 printk(KERN_ERR "Unable to create ip_conntrack_hash\n");
  33.                 goto err_unreg_sockopt;
  34.         }

  35.         ip_conntrack_cachep = kmem_cache_create("ip_conntrack",
  36.                                                 sizeof(struct ip_conntrack), 0,
  37.                                                 0, NULL, NULL);
  38.         if (!ip_conntrack_cachep) {
  39.                 printk(KERN_ERR "Unable to create ip_conntrack slab cache\n");
  40.                 goto err_free_hash;
  41.         }

  42.         ip_conntrack_expect_cachep = kmem_cache_create("ip_conntrack_expect",
  43.                                         sizeof(struct ip_conntrack_expect),
  44.                                         0, 0, NULL, NULL);
  45.         if (!ip_conntrack_expect_cachep) {
  46.                 printk(KERN_ERR "Unable to create ip_expect slab cache\n");
  47.                 goto err_free_conntrack_slab;
  48.         }

  49.         /* Don't NEED lock here, but good form anyway. */
  50.         write_lock_bh(&ip_conntrack_lock);
  51.         for (i = 0; i < MAX_IP_CT_PROTO; i++)
  52.                 /*
  53.                  * potential base upon which issue
  54.                  * iph->protocol += 32 attack
  55.                  */
  56.                 ip_ct_protos[i] = &ip_conntrack_generic_protocol;
  57.        
  58.         /* Sew in builtin protocols. */
  59.         ip_ct_protos[IPPROTO_TCP] = &ip_conntrack_protocol_tcp;
  60.         ip_ct_protos[IPPROTO_UDP] = &ip_conntrack_protocol_udp;
  61.         ip_ct_protos[IPPROTO_ICMP] = &ip_conntrack_protocol_icmp;
  62.         write_unlock_bh(&ip_conntrack_lock);

  63.         /* For use by ipt_REJECT */
  64.         ip_ct_attach = ip_conntrack_attach;

  65.         /* Set up fake conntrack:
  66.             - to never be deleted, not in any hashes */
  67.         atomic_set(&ip_conntrack_untracked.ct_general.use, 1);
  68.         /*  - and look it like as a confirmed connection */
  69.         set_bit(IPS_CONFIRMED_BIT, &ip_conntrack_untracked.status);

  70.         return ret;

  71. err_free_conntrack_slab:
  72.         kmem_cache_destroy(ip_conntrack_cachep);
  73. err_free_hash:
  74.         free_conntrack_hash(ip_conntrack_hash, ip_conntrack_vmalloc,
  75.                             ip_conntrack_htable_size);
  76. err_unreg_sockopt:
  77.         nf_unregister_sockopt(&so_getorigdst);

  78.         return -ENOMEM;
  79. }
复制代码

[ 本帖最后由 sisi8408 于 2007-8-19 14:33 编辑 ]
作者: sisi8408    时间: 2007-08-19 14:46

  1. /*
  2. * linux-2.6.20.7/net/ipv4/netfilter/ip_conntrack_core.c
  3. *
  4. * On success, returns conntrack ptr, sets skb->nfct and ctinfo
  5. */
  6. static inline struct ip_conntrack *
  7. resolve_normal_ct(struct sk_buff *skb,
  8.                   struct ip_conntrack_protocol *proto,
  9.                   int *set_reply,
  10.                   unsigned int hooknum,
  11.                   enum ip_conntrack_info *ctinfo)
  12. {
  13.         struct ip_conntrack_tuple tuple;
  14.         struct ip_conntrack_tuple_hash *h;
  15.         struct ip_conntrack *ct;

  16.         IP_NF_ASSERT((skb->nh.iph->frag_off & htons(IP_OFFSET)) == 0);

  17.         if (!ip_ct_get_tuple(skb->nh.iph, skb, skb->nh.iph->ihl*4,
  18.                                 &tuple,proto))
  19.                 return NULL;

  20.         /* look for tuple match */
  21.         h = ip_conntrack_find_get(&tuple, NULL);
  22.         if (!h) {
  23.                 /*
  24.                  * potential base upon which issue
  25.                  * pure tcp ack attack
  26.                  */
  27.                 h = init_conntrack(&tuple, proto, skb);
  28.                 if (!h)
  29.                         return NULL;
  30.                 if (IS_ERR(h))
  31.                         return (void *)h;
  32.         }
  33.         ct = tuplehash_to_ctrack(h);

  34.         /* It exists; we have (non-exclusive) reference. */
  35.         if (DIRECTION(h) == IP_CT_DIR_REPLY) {
  36.                 *ctinfo = IP_CT_ESTABLISHED + IP_CT_IS_REPLY;
  37.                 /* Please set reply bit if this packet OK */
  38.                 *set_reply = 1;
  39.         } else {
  40.                 /* Once we've had two way comms, always ESTABLISHED. */
  41.                 if (test_bit(IPS_SEEN_REPLY_BIT, &ct->status)) {
  42.                         DEBUGP("ip_conntrack_in: normal packet for %p\n",
  43.                                ct);
  44.                         *ctinfo = IP_CT_ESTABLISHED;
  45.                 } else if (test_bit(IPS_EXPECTED_BIT, &ct->status)) {
  46.                         DEBUGP("ip_conntrack_in: related packet for %p\n",
  47.                                ct);
  48.                         *ctinfo = IP_CT_RELATED;
  49.                 } else {
  50.                         DEBUGP("ip_conntrack_in: new packet for %p\n",
  51.                                ct);
  52.                         *ctinfo = IP_CT_NEW;
  53.                 }
  54.                 *set_reply = 0;
  55.         }
  56.         skb->nfct = &ct->ct_general;
  57.         skb->nfctinfo = *ctinfo;
  58.         return ct;
  59. }
复制代码

作者: sisi8408    时间: 2007-08-19 14:58

  1. /*
  2. * linux-2.6.20.7/net/ipv4/netfilter/ip_conntrack_proto_tcp.c
  3. */
  4. static int tcp_in_window(struct ip_ct_tcp *state,
  5.                          enum ip_conntrack_dir dir,
  6.                          unsigned int index,
  7.                          const struct sk_buff *skb,
  8.                          struct iphdr *iph,
  9.                          struct tcphdr *tcph)
  10. {
  11.         struct ip_ct_tcp_state *sender = &state->seen[dir];
  12.         struct ip_ct_tcp_state *receiver = &state->seen[!dir];
  13.         __u32 seq, ack, sack, end, win, swin;
  14.         int res;
  15.        
  16.         /*
  17.          * Get the required data from the packet.
  18.          */
  19.         seq = ntohl(tcph->seq);
  20.         ack = sack = ntohl(tcph->ack_seq);
  21.         win = ntohs(tcph->window);
  22.         end = segment_seq_plus_len(seq, skb->len, iph, tcph);
  23.        
  24.         if (receiver->flags & IP_CT_TCP_FLAG_SACK_PERM)
  25.                 tcp_sack(skb, iph, tcph, &sack);
  26.                
  27.         DEBUGP("tcp_in_window: START\n");
  28.         DEBUGP("tcp_in_window: src=%u.%u.%u.%u:%hu dst=%u.%u.%u.%u:%hu "
  29.                "seq=%u ack=%u sack=%u win=%u end=%u\n",
  30.                 NIPQUAD(iph->saddr), ntohs(tcph->source),
  31.                 NIPQUAD(iph->daddr), ntohs(tcph->dest),
  32.                 seq, ack, sack, win, end);
  33.         DEBUGP("tcp_in_window: sender end=%u maxend=%u maxwin=%u scale=%i "
  34.                "receiver end=%u maxend=%u maxwin=%u scale=%i\n",
  35.                 sender->td_end, sender->td_maxend, sender->td_maxwin,
  36.                 sender->td_scale,
  37.                 receiver->td_end, receiver->td_maxend, receiver->td_maxwin,
  38.                 receiver->td_scale);
  39.                
  40.         if (sender->td_end == 0) {
  41.                 /*
  42.                  * Initialize sender data.
  43.                  */
  44.                 if (tcph->syn && tcph->ack) {
  45.                         /*
  46.                          * Outgoing SYN-ACK in reply to a SYN.
  47.                          */
  48.                         sender->td_end =
  49.                         sender->td_maxend = end;
  50.                         sender->td_maxwin = (win == 0 ? 1 : win);

  51.                         tcp_options(skb, iph, tcph, sender);
  52.                         /*
  53.                          * RFC 1323:
  54.                          * Both sides must send the Window Scale option
  55.                          * to enable window scaling in either direction.
  56.                          */
  57.                         if (!(sender->flags & IP_CT_TCP_FLAG_WINDOW_SCALE
  58.                               && receiver->flags & IP_CT_TCP_FLAG_WINDOW_SCALE))
  59.                                 sender->td_scale =
  60.                                 receiver->td_scale = 0;
  61.                 } else {
  62.                         /*
  63.                          * We are in the middle of a connection,
  64.                          * its history is lost for us.
  65.                          * Let's try to use the data from the packet.
  66.                           */
  67.                          /*
  68.                           * why not drop/reject pure tcp ack????
  69.                           */
  70.                         sender->td_end = end;
  71.                         sender->td_maxwin = (win == 0 ? 1 : win);
  72.                         sender->td_maxend = end + sender->td_maxwin;
  73.                 }
  74.         } else if (((state->state == TCP_CONNTRACK_SYN_SENT
  75.                      && dir == IP_CT_DIR_ORIGINAL)
  76.                     || (state->state == TCP_CONNTRACK_SYN_RECV
  77.                         && dir == IP_CT_DIR_REPLY))
  78.                     && after(end, sender->td_end)) {
  79.                 /*
  80.                  * RFC 793: "if a TCP is reinitialized ... then it need
  81.                  * not wait at all; it must only be sure to use sequence
  82.                  * numbers larger than those recently used."
  83.                  */
  84.                 sender->td_end =
  85.                 sender->td_maxend = end;
  86.                 sender->td_maxwin = (win == 0 ? 1 : win);

  87.                 tcp_options(skb, iph, tcph, sender);
  88.         }
  89.        
  90.         if (!(tcph->ack)) {
  91.                 /*
  92.                  * If there is no ACK, just pretend it was set and OK.
  93.                  */
  94.                 ack = sack = receiver->td_end;
  95.         } else if (((tcp_flag_word(tcph) & (TCP_FLAG_ACK|TCP_FLAG_RST)) ==
  96.                     (TCP_FLAG_ACK|TCP_FLAG_RST))
  97.                    && (ack == 0)) {
  98.                 /*
  99.                  * Broken TCP stacks, that set ACK in RST packets as well
  100.                  * with zero ack value.
  101.                  */
  102.                 ack = sack = receiver->td_end;
  103.         }

  104.         if (seq == end
  105.             && (!tcph->rst
  106.                 || (seq == 0 && state->state == TCP_CONNTRACK_SYN_SENT)))
  107.                 /*
  108.                  * Packets contains no data: we assume it is valid
  109.                  * and check the ack value only.
  110.                  * However RST segments are always validated by their
  111.                  * SEQ number, except when seq == 0 (reset sent answering
  112.                  * SYN.
  113.                  */
  114.                 seq = end = sender->td_end;
  115.                
  116.         DEBUGP("tcp_in_window: src=%u.%u.%u.%u:%hu dst=%u.%u.%u.%u:%hu "
  117.                "seq=%u ack=%u sack =%u win=%u end=%u\n",
  118.                 NIPQUAD(iph->saddr), ntohs(tcph->source),
  119.                 NIPQUAD(iph->daddr), ntohs(tcph->dest),
  120.                 seq, ack, sack, win, end);
  121.         DEBUGP("tcp_in_window: sender end=%u maxend=%u maxwin=%u scale=%i "
  122.                "receiver end=%u maxend=%u maxwin=%u scale=%i\n",
  123.                 sender->td_end, sender->td_maxend, sender->td_maxwin,
  124.                 sender->td_scale,
  125.                 receiver->td_end, receiver->td_maxend, receiver->td_maxwin,
  126.                 receiver->td_scale);
  127.        
  128.         DEBUGP("tcp_in_window: I=%i II=%i III=%i IV=%i\n",
  129.                 before(seq, sender->td_maxend + 1),
  130.                     after(end, sender->td_end - receiver->td_maxwin - 1),
  131.                     before(sack, receiver->td_end + 1),
  132.                     after(ack, receiver->td_end - MAXACKWINDOW(sender)));
  133.        
  134.         if (sender->loose || receiver->loose ||
  135.             (before(seq, sender->td_maxend + 1) &&
  136.              after(end, sender->td_end - receiver->td_maxwin - 1) &&
  137.              before(sack, receiver->td_end + 1) &&
  138.              after(ack, receiver->td_end - MAXACKWINDOW(sender)))) {
  139.                     /*
  140.                  * Take into account window scaling (RFC 1323).
  141.                  */
  142.                 if (!tcph->syn)
  143.                         win <<= sender->td_scale;
  144.                
  145.                 /*
  146.                  * Update sender data.
  147.                  */
  148.                 swin = win + (sack - ack);
  149.                 if (sender->td_maxwin < swin)
  150.                         sender->td_maxwin = swin;
  151.                 if (after(end, sender->td_end))
  152.                         sender->td_end = end;
  153.                 /*
  154.                  * Update receiver data.
  155.                  */
  156.                 if (after(end, sender->td_maxend))
  157.                         receiver->td_maxwin += end - sender->td_maxend;
  158.                 if (after(sack + win, receiver->td_maxend - 1)) {
  159.                         receiver->td_maxend = sack + win;
  160.                         if (win == 0)
  161.                                 receiver->td_maxend++;
  162.                 }

  163.                 /*
  164.                  * Check retransmissions.
  165.                  */
  166.                 if (index == TCP_ACK_SET) {
  167.                         if (state->last_dir == dir
  168.                             && state->last_seq == seq
  169.                             && state->last_ack == ack
  170.                             && state->last_end == end
  171.                             && state->last_win == win)
  172.                                 state->retrans++;
  173.                         else {
  174.                                 state->last_dir = dir;
  175.                                 state->last_seq = seq;
  176.                                 state->last_ack = ack;
  177.                                 state->last_end = end;
  178.                                 state->last_win = win;
  179.                                 state->retrans = 0;
  180.                         }
  181.                 }
  182.                 /*
  183.                  * Close the window of disabled window tracking :-)
  184.                  */
  185.                 if (sender->loose)
  186.                         sender->loose--;
  187.                
  188.                 res = 1;
  189.         } else {
  190.                 if (LOG_INVALID(IPPROTO_TCP))
  191.                         nf_log_packet(PF_INET, 0, skb, NULL, NULL, NULL,
  192.                         "ip_ct_tcp: %s ",
  193.                         before(seq, sender->td_maxend + 1) ?
  194.                         after(end, sender->td_end - receiver->td_maxwin - 1) ?
  195.                         before(sack, receiver->td_end + 1) ?
  196.                         after(ack, receiver->td_end - MAXACKWINDOW(sender)) ? "BUG"
  197.                         : "ACK is under the lower bound (possible overly delayed ACK)"
  198.                         : "ACK is over the upper bound (ACKed data not seen yet)"
  199.                         : "SEQ is under the lower bound (already ACKed data retransmitted)"
  200.                         : "SEQ is over the upper bound (over the window of the receiver)");

  201.                 res = ip_ct_tcp_be_liberal;
  202.           }
  203.   
  204.         DEBUGP("tcp_in_window: res=%i sender end=%u maxend=%u maxwin=%u "
  205.                "receiver end=%u maxend=%u maxwin=%u\n",
  206.                 res, sender->td_end, sender->td_maxend, sender->td_maxwin,
  207.                 receiver->td_end, receiver->td_maxend, receiver->td_maxwin);

  208.         return res;
  209. }
复制代码

作者: mingyanguo    时间: 2007-08-19 15:34
原帖由 sisi8408 于 2007-8-19 11:59 发表
1,敬仰 提交了不少bug给Solaris。
     如果能在CU分享,俺看就是美事。
     还是那句话,您能来发贴,俺就欢迎、知足。呵呵,满意的笑容。

2,提交和搜集不矛盾,也不冲突。 区别只在于GPL。
     想贴 ...

如果对licence有异议,可以考虑换个kernel,这样做,给人的感觉不是太好。
作者: sisi8408    时间: 2007-08-19 19:03

  1. /* linux-2.6.20.7/kernel/hrtimer.c
  2. *
  3. * Switch the timer base to the current CPU when possible
  4. */
  5. static inline struct hrtimer_base *
  6. switch_hrtimer_base(struct hrtimer *timer, struct hrtimer_base *base)
  7. {
  8.         struct hrtimer_base *new_base;

  9.         new_base = &__get_cpu_var(hrtimer_bases)[base->index];

  10.         if (base != new_base) {
  11.                 /*
  12.                  * We are trying to schedule the timer on the local CPU.
  13.                  *
  14.                  * However we can't change timer's base while it is running,
  15.                  * so we keep it on the same CPU.
  16.                  *
  17.                  * No hassle vs. reprogramming
  18.                  * the event source in the high resolution case.
  19.                  *
  20.                  * The softirq code will take care of this,
  21.                  * when the timer function has completed.
  22.                  *
  23.                  * There is no conflict, as we hold the lock until
  24.                  * the timer is enqueued.
  25.                  */
  26.                 if (unlikely(base->curr_timer == timer))
  27.                         return base;

  28.                 /* See the comment in lock_timer_base() */
  29.                 timer->base = NULL;
  30.                 spin_unlock(&base->lock);
  31.                 /*
  32.                  * When the timer's base is locked,
  33.                  * and the timer removed from list,
  34.                  * it is possible to set timer->base = NULL and
  35.                  * drop the lock: the timer remains locked.
  36.                  * =================================
  37.                  * ¥3
  38.                  * but during get new_base->lock,
  39.                  * how about base->curr_timer == timer ???
  40.                  * any warrant ??? what consequence ???
  41.                  */
  42.                 spin_lock(&new_base->lock);
  43.                 timer->base = new_base;
  44.         }
  45.         return new_base;
  46. }
复制代码

[ 本帖最后由 sisi8408 于 2007-8-20 20:38 编辑 ]
作者: sisi8408    时间: 2007-08-19 20:31

  1. /*
  2. * linux-2.6.20.7/kernel/hrtimer.c
  3. *
  4. * Expire the per base hrtimer-queue:
  5. */
  6. static inline void run_hrtimer_queue(struct hrtimer_base *base)
  7. {
  8.         struct rb_node *node;

  9.         if (!base->first)
  10.                 return;

  11.         if (base->get_softirq_time)
  12.                 base->softirq_time = base->get_softirq_time();

  13.         spin_lock_irq(&base->lock);

  14.         while ((node = base->first)) {
  15.                 struct hrtimer *timer;
  16.                 int (*fn)(struct hrtimer *);
  17.                 int restart;

  18.                 timer = rb_entry(node, struct hrtimer, node);
  19.                 if (base->softirq_time.tv64 <= timer->expires.tv64)
  20.                         break;

  21.                 fn = timer->function;
  22.                 set_curr_timer(base, timer);
  23.                 __remove_hrtimer(timer, base);
  24.                 spin_unlock_irq(&base->lock);

  25.                 restart = fn(timer);

  26.                 spin_lock_irq(&base->lock);

  27.                 if (restart != HRTIMER_NORESTART) {
  28.                         BUG_ON(hrtimer_active(timer));
  29.                         /*
  30.                          * ¥2
  31.                          * no check to assure
  32.                          * 1, fair play among timers
  33.                          * 2, cpu potentially suck by one timer
  34.                          */
  35.                         enqueue_hrtimer(timer, base);
  36.                 }
  37.         }
  38.         set_curr_timer(base, NULL);
  39.         spin_unlock_irq(&base->lock);
  40. }
复制代码

作者: sisi8408    时间: 2007-08-20 20:22

  1. /*
  2. * linux-2.6.20.7/net/ipv4/netfilter/ip_conntrack_core.c
  3. * ¥8
  4. * this is not bug/vulnerability in any definition
  5. * but the so-called SBL, single/super big lock,
  6. * as the result of # grep ip_conntrack_lock linux-2.6.20.7/net/ipv4/netfilter/*.c
  7. * show its heavy impact upon performance of netfilter,
  8. * if ip conntrack in running system.
  9. *
  10. * though rcu plays not nice game without lock,
  11. * netfilter shouldnt be only protected by SBL.
  12. */
  13. DEFINE_RWLOCK(ip_conntrack_lock);
复制代码

[ 本帖最后由 sisi8408 于 2007-8-20 23:21 编辑 ]
作者: sisi8408    时间: 2007-08-20 20:29
标题: 回复 #20 mingyanguo 的帖子
大哥,您一路辛苦,八哥有茶水相待。
您心情好,就贴个方案。
作者: sisi8408    时间: 2007-08-20 21:16

  1. static int e1000_clean(struct net_device *poll_dev, int *budget)
  2. {
  3.         struct e1000_adapter *adapter;
  4.         int work_to_do = min(*budget, poll_dev->quota);
  5.         int tx_cleaned = 0, work_done = 0;

  6.         /* Must NOT use netdev_priv macro here. */
  7.         adapter = poll_dev->priv;

  8.         /* Keep link state information with original netdev */
  9.         if (!netif_carrier_ok(poll_dev))
  10.                 goto quit_polling;

  11.         /* e1000_clean is called per-cpu.  This lock protects
  12.          * tx_ring[0] from being cleaned by multiple cpus
  13.          * simultaneously.  A failure obtaining the lock means
  14.          * tx_ring[0] is currently being cleaned anyway.
  15.          *
  16.          * ¥8 logic bug
  17.          *
  18.          * linux-2.6.20.7/drivers/net/e1000/e1000_main.c
  19.          *
  20.          * not-well-known pseudo TX-hang occurs
  21.          * in some cases when RX is busy enough.
  22.          *
  23.          */
  24.         if (spin_trylock(&adapter->tx_queue_lock)) {
  25.                 tx_cleaned = e1000_clean_tx_irq(adapter,
  26.                                                 &adapter->tx_ring[0]);
  27.                 spin_unlock(&adapter->tx_queue_lock);
  28.         }

  29.         adapter->clean_rx(adapter, &adapter->rx_ring[0],
  30.                           &work_done, work_to_do);

  31.         *budget -= work_done;
  32.         poll_dev->quota -= work_done;

  33.         /* If no Tx and not enough Rx work done, exit the polling mode */
  34.         if ((!tx_cleaned && (work_done == 0)) ||
  35.            !netif_running(poll_dev)) {
  36. quit_polling:
  37.                 if (likely(adapter->itr_setting & 3))
  38.                         e1000_set_itr(adapter);
  39.                 netif_rx_complete(poll_dev);
  40.                 e1000_irq_enable(adapter);
  41.                 return 0;
  42.         }

  43.         return 1;
  44. }
复制代码

[ 本帖最后由 sisi8408 于 2007-8-20 23:24 编辑 ]
作者: sisi8408    时间: 2007-08-21 11:29
it is hot&hard to deal with SBL,
but another version of, maybe slower, fragment treatment can be made with rcu,
of cough, possibly followed with bug&vulnerability,
to rx frag either legal or illegal.


  1. --- linux-2.6.22.1/net/ipv4/ip_fragment.c        2007-07-11 02:56:30.000000000 +0800
  2. +++ /usr/src/chg/ip_fragment3.c        2007-08-21 11:27:03.000000000 +0800
  3. @@ -25,6 +25,7 @@
  4. #include <linux/compiler.h>
  5. #include <linux/module.h>
  6. #include <linux/types.h>
  7. +#include <linux/rcupdate.h>
  8. #include <linux/mm.h>
  9. #include <linux/jiffies.h>
  10. #include <linux/skbuff.h>
  11. @@ -111,8 +112,8 @@ int ip_frag_nqueues = 0;

  12. static __inline__ void __ipq_unlink(struct ipq *qp)
  13. {
  14. -        hlist_del(&qp->list);
  15. -        list_del(&qp->lru_list);
  16. +        hlist_del_rcu(&qp->list);
  17. +        list_del_rcu(&qp->lru_list);
  18.         ip_frag_nqueues--;
  19. }

  20. @@ -149,10 +150,10 @@ static void ipfrag_secret_rebuild(unsign
  21.                                                       q->daddr, q->protocol);

  22.                         if (hval != i) {
  23. -                                hlist_del(&q->list);
  24. +                                hlist_del_rcu(&q->list);

  25.                                 /* Relink to new hash chain. */
  26. -                                hlist_add_head(&q->list, &ipq_hash[hval]);
  27. +                                hlist_add_head_rcu(&q->list, &ipq_hash[hval]);
  28.                         }
  29.                 }
  30.         }
  31. @@ -252,16 +253,16 @@ static void ip_evictor(void)
  32.                 return;

  33.         while (work > 0) {
  34. -                read_lock(&ipfrag_lock);
  35. +                rcu_read_lock();
  36.                 if (list_empty(&ipq_lru_list)) {
  37. -                        read_unlock(&ipfrag_lock);
  38. +                        rcu_read_unlock();
  39.                         return;
  40.                 }
  41. -                tmp = ipq_lru_list.next;
  42. -                qp = list_entry(tmp, struct ipq, lru_list);
  43. +                tmp = rcu_dereference(ipq_lru_list.next);
  44. +                qp  = list_entry(tmp, struct ipq, lru_list);
  45.                 atomic_inc(&qp->refcnt);
  46. -                read_unlock(&ipfrag_lock);
  47. -
  48. +                rcu_read_unlock();
  49. +               
  50.                 spin_lock(&qp->lock);
  51.                 if (!(qp->last_in&COMPLETE))
  52.                         ipq_kill(qp);
  53. @@ -320,7 +321,7 @@ static struct ipq *ip_frag_intern(struct
  54.          * such entry could be created on other cpu, while we
  55.          * promoted read lock to write lock.
  56.          */
  57. -        hlist_for_each_entry(qp, n, &ipq_hash[hash], list) {
  58. +        hlist_for_each_entry_rcu(qp, n, &ipq_hash[hash], list) {
  59.                 if (qp->id == qp_in->id                &&
  60.                     qp->saddr == qp_in->saddr        &&
  61.                     qp->daddr == qp_in->daddr        &&
  62. @@ -340,9 +341,9 @@ static struct ipq *ip_frag_intern(struct
  63.                 atomic_inc(&qp->refcnt);

  64.         atomic_inc(&qp->refcnt);
  65. -        hlist_add_head(&qp->list, &ipq_hash[hash]);
  66. +        hlist_add_head_rcu(&qp->list, &ipq_hash[hash]);
  67.         INIT_LIST_HEAD(&qp->lru_list);
  68. -        list_add_tail(&qp->lru_list, &ipq_lru_list);
  69. +        list_add_tail_rcu(&qp->lru_list, &ipq_lru_list);
  70.         ip_frag_nqueues++;
  71.         write_unlock(&ipfrag_lock);
  72.         return qp;
  73. @@ -395,20 +396,20 @@ static inline struct ipq *ip_find(struct
  74.         struct ipq *qp;
  75.         struct hlist_node *n;

  76. -        read_lock(&ipfrag_lock);
  77. +        rcu_read_lock();
  78.         hash = ipqhashfn(id, saddr, daddr, protocol);
  79. -        hlist_for_each_entry(qp, n, &ipq_hash[hash], list) {
  80. +        hlist_for_each_entry_rcu(qp, n, &ipq_hash[hash], list) {
  81.                 if (qp->id == id                &&
  82.                     qp->saddr == saddr        &&
  83.                     qp->daddr == daddr        &&
  84.                     qp->protocol == protocol &&
  85.                     qp->user == user) {
  86.                         atomic_inc(&qp->refcnt);
  87. -                        read_unlock(&ipfrag_lock);
  88. +                        rcu_read_unlock();
  89.                         return qp;
  90.                 }
  91.         }
  92. -        read_unlock(&ipfrag_lock);
  93. +        rcu_read_lock();

  94.         return ip_frag_create(iph, user);
  95. }
  96. @@ -599,7 +600,8 @@ static void ip_frag_queue(struct ipq *qp
  97.                 qp->last_in |= FIRST_IN;

  98.         write_lock(&ipfrag_lock);
  99. -        list_move_tail(&qp->lru_list, &ipq_lru_list);
  100. +        list_del_rcu(&qp->lru_list);
  101. +        list_add_tail_rcu(&qp->lru_list, &ipq_lru_list);
  102.         write_unlock(&ipfrag_lock);

  103.         return;
复制代码

[ 本帖最后由 sisi8408 于 2007-8-22 10:48 编辑 ]
作者: sisi8408    时间: 2007-08-23 10:39

  1. struct ip_conntrack
  2. {
  3.         /* Usage count in here is 1 for hash table/destruct timer, 1 per skb,
  4.            plus 1 for any connection(s) we are `master' for */
  5.         struct nf_conntrack ct_general;

  6.         /* Have we seen traffic both ways yet? (bitset) */
  7.         unsigned long status;

  8.         /* Timer function; drops refcnt when it goes off. */
  9.         /*
  10.          * linux-2.6.20.7/include/linux/netfilter_ipv4/ip_conntrack.h
  11.          * ¥8
  12.          * potential vulnerability in design
  13.          *
  14.          * if as boasted, FW warrant 1M connections,
  15.          * how many cpus required to response timer?
  16.          */
  17.         struct timer_list timeout;

  18. #ifdef CONFIG_IP_NF_CT_ACCT
  19.         /* Accounting Information (same cache line as other written members) */
  20.         struct ip_conntrack_counter counters[IP_CT_DIR_MAX];
  21. #endif
  22.         /* If we were expected by an expectation, this will be it */
  23.         struct ip_conntrack *master;

  24.         /* Current number of expected connections */
  25.         unsigned int expecting;

  26.         /* Unique ID that identifies this conntrack*/
  27.         unsigned int id;

  28.         /* Helper, if any. */
  29.         struct ip_conntrack_helper *helper;

  30.         /* Storage reserved for other modules: */
  31.         union ip_conntrack_proto proto;

  32.         union ip_conntrack_help help;

  33. #ifdef CONFIG_IP_NF_NAT_NEEDED
  34.         struct {
  35.                 struct ip_nat_info info;
  36.                 union ip_conntrack_nat_help help;
  37. #if defined(CONFIG_IP_NF_TARGET_MASQUERADE) || \
  38.         defined(CONFIG_IP_NF_TARGET_MASQUERADE_MODULE)
  39.                 int masq_index;
  40. #endif
  41.         } nat;
  42. #endif /* CONFIG_IP_NF_NAT_NEEDED */

  43. #if defined(CONFIG_IP_NF_CONNTRACK_MARK)
  44.         u_int32_t mark;
  45. #endif

  46. #ifdef CONFIG_IP_NF_CONNTRACK_SECMARK
  47.         u_int32_t secmark;
  48. #endif

  49.         /* Traversed often, so hopefully in different cacheline to top */
  50.         /* These are my tuples; original and reply */
  51.         struct ip_conntrack_tuple_hash tuplehash[IP_CT_DIR_MAX];
  52. };
复制代码

作者: sisi8408    时间: 2007-08-23 11:37

  1. void shrink_dcache_sb(struct super_block * sb)
  2. {
  3.         struct list_head *tmp, *next;
  4.         struct dentry *dentry;

  5.         /*
  6.          * Pass one ... move the dentries for the specified
  7.          * superblock to the most recent end of the unused list.
  8.          */
  9.         spin_lock(&dcache_lock);
  10.         list_for_each_safe(tmp, next, &dentry_unused) {
  11.                 dentry = list_entry(tmp, struct dentry, d_lru);
  12.                 if (dentry->d_sb != sb)
  13.                         continue;
  14.                 list_move(tmp, &dentry_unused);
  15.         }

  16.         /*
  17.          * Pass two ... free the dentries for this superblock.
  18.          */
  19. repeat:
  20.         list_for_each_safe(tmp, next, &dentry_unused) {
  21.                 dentry = list_entry(tmp, struct dentry, d_lru);
  22.                 if (dentry->d_sb != sb)
  23.                         continue;
  24.                 dentry_stat.nr_unused--;
  25.                 list_del_init(tmp);
  26.                 spin_lock(&dentry->d_lock);
  27.                 if (atomic_read(&dentry->d_count)) {
  28.                         /*
  29.                          * linux-2.6.20.7/fs/dcache.c
  30.                          *
  31.                          * ¥3
  32.                          * how can i get dentry on lru later?
  33.                          * where u go on earth?
  34.                          */
  35.                         spin_unlock(&dentry->d_lock);
  36.                         continue;
  37.                 }
  38.                 prune_one_dentry(dentry);
  39.                 cond_resched_lock(&dcache_lock);
  40.                 goto repeat;
  41.         }
  42.         spin_unlock(&dcache_lock);
  43. }
复制代码

[ 本帖最后由 sisi8408 于 2007-8-23 11:40 编辑 ]
作者: 思一克    时间: 2007-08-23 20:45
你说的这里有什么问题? 能否详细说一下?

原帖由 sisi8408 于 2007-8-23 11:37 发表 [url=http://linux.chinaunix.net/bbs/redirect.php?goto=findpost&&

void shrink_dcache_sb(struct super_block * sb)
{
        struct list_head *tmp, *next;
        struct dentry *dentry;

        /*
         * Pass one ... move the dentries for the specified
         * superblock to the most recent end of the unused list.
         */
        spin_lock(&dcache_lock);
        list_for_each_safe(tmp, next, &dentry_unused) {
                dentry = list_entry(tmp, struct dentry, d_lru);
                if (dentry->d_sb != sb)
                        continue;
                list_move(tmp, &dentry_unused);
        }

        /*
         * Pass two ... free the dentries for this superblock.
         */
repeat:
        list_for_each_safe(tmp, next, &dentry_unused) {
                dentry = list_entry(tmp, struct dentry, d_lru);
                if (dentry->d_sb != sb)
                        continue;
                dentry_stat.nr_unused--;
                list_del_init(tmp);
                spin_lock(&dentry->d_lock);
                if (atomic_read(&dentry->d_count)) {
                        /*
                         * linux-2.6.20.7/fs/dcache.c
                         *
                         * ¥3
                         * how can i get dentry on lru later?
                         * where u go on earth?
                         */
                        spin_unlock(&dentry->d_lock);
                        continue;
                }
                prune_one_dentry(dentry);
                cond_resched_lock(&dcache_lock);
                goto repeat;
        }
        spin_unlock(&dcache_lock);
}

作者: sisi8408    时间: 2007-08-24 09:39

  1. int ocfs2_node_map_is_only(struct ocfs2_super *osb,
  2.                            struct ocfs2_node_map *target,
  3.                            int bit)
  4. {
  5.         struct ocfs2_node_map temp;
  6.         int ret;

  7.         spin_lock(&osb->node_map_lock);
  8.         __ocfs2_node_map_dup(&temp, target);
  9.         /*
  10.          * linux-2.6.20.7/fs/ocfs2/heartbeat.c
  11.          *
  12.          * ¥1
  13.          *
  14.          * abuse of spin_lock
  15.          */
  16.         __ocfs2_node_map_clear_bit(&temp, bit);
  17.         ret = __ocfs2_node_map_is_empty(&temp);
  18.         spin_unlock(&osb->node_map_lock);

  19.         return ret;
  20. }
复制代码

作者: sisi8408    时间: 2007-08-24 09:41

  1. int ocfs2_node_map_iterate(struct ocfs2_super *osb,
  2.                            struct ocfs2_node_map *map,
  3.                            int idx)
  4. {
  5.         int i = idx;

  6.         idx = O2NM_INVALID_NODE_NUM;
  7.         spin_lock(&osb->node_map_lock);
  8.         if ((i != O2NM_INVALID_NODE_NUM) &&
  9.             (i >= 0) &&
  10.             (i < map->num_nodes)) {
  11.             /*
  12.          * linux-2.6.20.7/fs/ocfs2/heartbeat.c
  13.          *
  14.          * ¥1
  15.          *
  16.          * oversight bitops of arch version by linux
  17.              */
  18.                 while (i < map->num_nodes) {
  19.                         if (test_bit(i, map->map)) {
  20.                                 idx = i;
  21.                                 break;
  22.                         }
  23.                         i++;
  24.                 }
  25.         }
  26.         spin_unlock(&osb->node_map_lock);
  27.         return idx;
  28. }
复制代码

作者: sisi8408    时间: 2007-08-24 09:45

  1. int vfs_rmdir(struct inode *dir, struct dentry *dentry)
  2. {
  3.         int error = may_delete(dir, dentry, 1);

  4.         if (error)
  5.                 return error;

  6.         if (!dir->i_op || !dir->i_op->rmdir)
  7.                 return -EPERM;

  8.         DQUOT_INIT(dir);

  9.         mutex_lock(&dentry->d_inode->i_mutex);
  10.         dentry_unhash(dentry);
  11.         if (d_mountpoint(dentry))
  12.                 error = -EBUSY;
  13.         else {
  14.                 error = security_inode_rmdir(dir, dentry);
  15.                 if (!error) {
  16.                         error = dir->i_op->rmdir(dir, dentry);
  17.                         if (!error)
  18.                                 dentry->d_inode->i_flags |= S_DEAD;
  19.                 }
  20.         }
  21.         mutex_unlock(&dentry->d_inode->i_mutex);
  22.         if (!error) {

  23. /*
  24. * linux-2.6.20.7/fs/namei.c
  25. *
  26. * potentially trigger-1
  27. */
  28.                 d_delete(dentry);
  29.         }
  30.         dput(dentry);

  31.         return error;
  32. }
复制代码

  1. void d_delete(struct dentry * dentry)
  2. {
  3.         int isdir = 0;
  4.         /*
  5.          * Are we the only user?
  6.          */
  7.         spin_lock(&dcache_lock);
  8.         spin_lock(&dentry->d_lock);
  9.         isdir = S_ISDIR(dentry->d_inode->i_mode);
  10.        
  11.         if (atomic_read(&dentry->d_count) == 1) {
  12.                 dentry_iput(dentry);
  13.                 fsnotify_nameremove(dentry, isdir);

  14.                 /* remove this and other inotify debug checks after 2.6.18 */
  15.                 dentry->d_flags &= ~DCACHE_INOTIFY_PARENT_WATCHED;

  16. /*
  17. * linux-2.6.20.7/fs/dcache.c
  18. *
  19. * potentially trigger-2
  20. */
  21.                 return;
  22.         }

  23.         if (!d_unhashed(dentry))
  24.                 __d_drop(dentry);

  25.         spin_unlock(&dentry->d_lock);
  26.         spin_unlock(&dcache_lock);

  27.         fsnotify_nameremove(dentry, isdir);
  28. }
复制代码

  1. void dput(struct dentry *dentry)
  2. {
  3.         if (!dentry)
  4.                 return;

  5. repeat:
  6.         if (atomic_read(&dentry->d_count) == 1)
  7.                 might_sleep();
  8.        
  9.         if (!atomic_dec_and_lock(&dentry->d_count, &dcache_lock))
  10.                 return;

  11. /*
  12. * linux-2.6.20.7/fs/dcache.c
  13. *
  14. * ¥6
  15. * potentially race @ here
  16. */
  17.         spin_lock(&dentry->d_lock);
  18.        
  19.         if (atomic_read(&dentry->d_count)) {
  20.                 spin_unlock(&dentry->d_lock);
  21.                 spin_unlock(&dcache_lock);
  22.                 return;
  23.         }

  24.         /*
  25.          * AV: ->d_delete() is _NOT_ allowed to block now.
  26.          */
  27.         if (dentry->d_op && dentry->d_op->d_delete) {
  28.                 if (dentry->d_op->d_delete(dentry))
  29.                         goto unhash_it;
  30.         }

  31.         /* Unreachable? Get rid of it */
  32.         if (d_unhashed(dentry))
  33.                 goto kill_it;
  34.        
  35.         if (list_empty(&dentry->d_lru)) {
  36.                   dentry->d_flags |= DCACHE_REFERENCED;
  37.                   list_add(&dentry->d_lru, &dentry_unused);
  38.                   dentry_stat.nr_unused++;
  39.           }
  40.         spin_unlock(&dentry->d_lock);
  41.         spin_unlock(&dcache_lock);
  42.         return;

  43. unhash_it:
  44.         __d_drop(dentry);

  45. kill_it: {
  46.                 struct dentry *parent;

  47.                 /* If dentry was on d_lru list,
  48.                  * delete it from there
  49.                  */
  50.                   if (!list_empty(&dentry->d_lru)) {
  51.                           list_del(&dentry->d_lru);
  52.                           dentry_stat.nr_unused--;
  53.                   }
  54.                   list_del(&dentry->d_u.d_child);
  55.                 dentry_stat.nr_dentry--;        /* For d_free, below */
  56.                
  57.                 /* drops the locks,
  58.                  * at that point nobody can reach this dentry
  59.                  */
  60.                 dentry_iput(dentry);
  61.                
  62.                 parent = dentry->d_parent;
  63.                 d_free(dentry);
  64.                
  65.                 if (dentry == parent)
  66.                         return;
  67.                 dentry = parent;
  68.                 goto repeat;
  69.         }
  70. }
复制代码

作者: 思一克    时间: 2007-08-24 10:45
你说的问题(BUG)怎么存在了?请详细解释好吗。


  1. void dput(struct dentry *dentry)
  2. {
  3.         if (!dentry)
  4.                 return;

  5. repeat:
  6.         if (atomic_read(&dentry->d_count) == 1)
  7.                 might_sleep();
  8.       
  9.         if (!atomic_dec_and_lock(&dentry->d_count, &dcache_lock))
  10.                 return;

  11. /*
  12. * linux-2.6.20.7/fs/dcache.c
  13. *
  14. * ¥6
  15. * potentially race @ here
  16. */
  17.         spin_lock(&dentry->d_lock);
  18.       
  19.         if (atomic_read(&dentry->d_count)) {
  20.                 spin_unlock(&dentry->d_lock);
  21.                 spin_unlock(&dcache_lock);
  22.                 return;
  23.         }

  24.         /*
  25.          * AV: ->d_delete() is _NOT_ allowed to block now.
  26.          */
  27.         if (dentry->d_op && dentry->d_op->d_delete) {
  28.                 if (dentry->d_op->d_delete(dentry))
  29.                         goto unhash_it;
  30.         }

  31.         /* Unreachable? Get rid of it */
  32.         if (d_unhashed(dentry))
  33.                 goto kill_it;
  34.       
  35.         if (list_empty(&dentry->d_lru)) {
  36.                   dentry->d_flags |= DCACHE_REFERENCED;
  37.                   list_add(&dentry->d_lru, &dentry_unused);
  38.                   dentry_stat.nr_unused++;
  39.           }
  40.         spin_unlock(&dentry->d_lock);
  41.         spin_unlock(&dcache_lock);
  42.         return;

  43. unhash_it:
  44.         __d_drop(dentry);

  45. kill_it: {
  46.                 struct dentry *parent;

  47.                 /* If dentry was on d_lru list,
  48.                  * delete it from there
  49.                  */
  50.                   if (!list_empty(&dentry->d_lru)) {
  51.                           list_del(&dentry->d_lru);
  52.                           dentry_stat.nr_unused--;
  53.                   }
  54.                   list_del(&dentry->d_u.d_child);
  55.                 dentry_stat.nr_dentry--;        /* For d_free, below */
  56.                
  57.                 /* drops the locks,
  58.                  * at that point nobody can reach this dentry
  59.                  */
  60.                 dentry_iput(dentry);
  61.                
  62.                 parent = dentry->d_parent;
  63.                 d_free(dentry);
  64.                
  65.                 if (dentry == parent)
  66.                         return;
  67.                 dentry = parent;
  68.                 goto repeat;
  69.         }
  70. }
复制代码

作者: sisi8408    时间: 2007-08-24 11:22
标题: 回复 #33 思一克 的帖子

  1.         if (!error) {
  2.                 d_delete(dentry);
  3. /*
  4. *  d_delete return potentially without releasing dcache_lock & dentry->d_lock
  5. */
  6.         }
  7. /*
  8. * however dput at least try to get dentry->d_lock
  9. */
  10.         dput(dentry);


  11. /*
  12. * yeah, these codes used everyday after bootstrap,
  13. * why not heard bloat???
  14. */
复制代码

作者: 思一克    时间: 2007-08-24 11:46
你怎么知道d_delete return potentially without releasing dcache_lock & dentry->d_lock?

我看的是2。6。13版本。和你的应该差不多。

原帖由 sisi8408 于 2007-8-24 11:22 发表

        if (!error) {
                d_delete(dentry);
/*
*  d_delete return potentially without releasing dcache_lock & dentry->d_lock
*/
        }
/*
* however dput at least try to ...

作者: 思一克    时间: 2007-08-24 11:57
我觉得你提出的BUG中的大多数都是不存在的。尤其是在各版本都稳定了的代码中。


原帖由 思一克 于 2007-8-24 11:46 发表
你怎么知道d_delete return potentially without releasing dcache_lock & dentry->d_lock?

我看的是2。6。13版本。和你的应该差不多。


作者: sisi8408    时间: 2007-08-24 12:56
天太热,BUG可能躲荫了。
喝杯清茶,回头再看,随手写来,表达个想法,不必当真,呵呵。
作者: 思一克    时间: 2007-08-24 13:00
没有当真。

d_delete中的dentry_iput()会spin_unlock ( ... d_lock)的。

还有,我说的是在版本稳定的代码中不大可能有你说的BUG。但是在驱动中,htimer中你你说的可能是有的。我的6.2.13中没有你贴出的那部分代码,所以没有法看。driver中的我又不懂。

原帖由 sisi8408 于 2007-8-24 12:56 发表
天太热,BUG可能躲荫了。
喝杯清茶,回头再看,随手写来,表达个想法,不必当真,呵呵。

作者: sisi8408    时间: 2007-08-24 13:11
如果skipjack用的版本疮上了,这里提个醒,不算太罗唆。

哪个版本稳定呐?不好说,看的人多一点,可能稍好吧。

BUG,俺叫他八哥,一种好听的鸟,养着乐的。
作者: 思一克    时间: 2007-08-24 13:22
现在都到2。6。2X了,那么2.6.1X的就是稳定的。
还有,许多内河代码(函数)在版本升级后并没有变化。这部分也是稳定的。要找出其中的BUG是很难的。否则系统就不会运行的那样稳定可靠了。

驱动中BUG应该多些。

原帖由 sisi8408 于 2007-8-24 13:11 发表
如果skipjack用的版本疮上了,这里提个醒,不算太罗唆。

哪个版本稳定呐?不好说,看的人多一点,可能稍好吧。

BUG,俺叫他八哥,一种好听的鸟,养着乐的。

作者: sisi8408    时间: 2007-08-24 13:26
确如思一克大侠所言,得以解惑,鲜花和致敬奉上,还有¥6。


  1. /*
  2. * linux-2.6.20.7/fs/dcache.c
  3. */
  4. static void dentry_iput(struct dentry * dentry)
  5. {
  6.         struct inode * inode = dentry->d_inode;
  7.        
  8.         if (inode) {
  9.                 dentry->d_inode = NULL;
  10.                 list_del_init(&dentry->d_alias);
  11.                 spin_unlock(&dentry->d_lock);
  12.                 spin_unlock(&dcache_lock);

  13.                 if (!inode->i_nlink)
  14.                         fsnotify_inoderemove(inode);
  15.                
  16.                 if (dentry->d_op && dentry->d_op->d_iput)
  17.                         dentry->d_op->d_iput(dentry, inode);
  18.                 else
  19.                         iput(inode);
  20.         } else {
  21.                 spin_unlock(&dentry->d_lock);
  22.                 spin_unlock(&dcache_lock);
  23.         }
  24. }
复制代码

[ 本帖最后由 sisi8408 于 2007-8-27 16:22 编辑 ]
作者: daemeon    时间: 2007-08-25 07:04
偶也来贴一个

2.6.22

int tcp_set_allowed_congestion_control(char *val)
{
    struct tcp_congestion_ops *ca;
    char *clone, *name;
    int ret = 0;

    clone = kstrdup(val, GFP_USER);
    if (!clone)
        return -ENOMEM;

    spin_lock(&tcp_cong_list_lock);
    /* pass 1 check for bad entries */
    while ((name = strsep(&clone, " ")) && *name) {
        ca = tcp_ca_find(name);
        if (!ca) {
            ret = -ENOENT;
            goto out;
        }
    }

    /* pass 2 clear old values */
    list_for_each_entry_rcu(ca, &tcp_cong_list, list)
        ca->flags &= ~TCP_CONG_NON_RESTRICTED;

    /* pass 3 mark as allowed */
    while ((name = strsep(&val, " ")) && *name) {
        ca = tcp_ca_find(name);
        WARN_ON(!ca);
        if (ca)
            ca->flags |= TCP_CONG_NON_RESTRICTED;
    }
out:
    spin_unlock(&tcp_cong_list_lock);

    return ret;
}


[ 本帖最后由 daemeon 于 2007-8-25 16:21 编辑 ]
作者: sisi8408    时间: 2007-08-25 13:50
标题: 回复 #42 daemeon 的帖子
鲜花奉上,还有¥1。

另外,劳烦daemeon大哥注明kernel版本,方便大家查询比对。

clone not released?

[ 本帖最后由 sisi8408 于 2007-8-25 14:07 编辑 ]
作者: sisi8408    时间: 2007-08-25 19:58
标题: 回复 #42 daemeon 的帖子

  1. int tcp_set_allowed_congestion_control(char *val)
  2. {
  3.      .............

  4. out:
  5.     spin_unlock(&tcp_cong_list_lock);
  6.     if (clone)
  7.             kfree(clone);
  8.     return ret;
  9. }

  10. /*
  11. * based upon linux/2.6.20.7/mm/utils.c
  12. */
  13. char * kstrdup(const char *s, gfp_t gfp)
  14. {
  15.         size_t len;
  16.         char *buf;

  17.         if (!s)
  18.                 return NULL;

  19.         len = strlen(s) + 1;
  20.         buf = kmalloc_track_caller(len, gfp);
  21.         if (buf)
  22.                 memcpy(buf, s, len);
  23.         return buf;
  24. }
复制代码

作者: daemeon    时间: 2007-08-25 20:48
标题: 回复 #44 sisi8408 的帖子
the variable 'clone' is modified by strsep. we need another variable to save original value.
作者: sisi8408    时间: 2007-08-26 08:42
try again


  1. int tcp_set_allowed_congestion_control(char *val)
  2. {
  3.     struct tcp_congestion_ops *ca;
  4.     char *clone, *name;
  5. +    char *org;
  6.     int ret = 0;

  7.     clone = kstrdup(val, GFP_USER);
  8.     if (!clone)
  9.         return -ENOMEM;
  10. +  org = clone;
  11.     spin_lock(&tcp_cong_list_lock);
  12.     /* pass 1 check for bad entries */
  13.     while ((name = strsep(&clone, " ")) && *name) {
  14.         ca = tcp_ca_find(name);
  15.         if (!ca) {
  16.             ret = -ENOENT;
  17.             goto out;
  18.         }
  19.     }

  20.     /* pass 2 clear old values */
  21.     list_for_each_entry_rcu(ca, &tcp_cong_list, list)
  22.         ca->flags &= ~TCP_CONG_NON_RESTRICTED;

  23.     /* pass 3 mark as allowed */
  24.     while ((name = strsep(&val, " ")) && *name) {
  25.         ca = tcp_ca_find(name);
  26.         WARN_ON(!ca);
  27.         if (ca)
  28.             ca->flags |= TCP_CONG_NON_RESTRICTED;
  29.     }
  30. out:
  31.     spin_unlock(&tcp_cong_list_lock);
  32. +  if (org)  kfree(org);
  33.     return ret;
  34. }
复制代码

作者: sisi8408    时间: 2007-08-27 15:29

  1. static ssize_t dlmfs_file_read(struct file *filp,
  2.                                char __user *buf, size_t count,
  3.                                loff_t *ppos)
  4. {
  5.         int bytes_left;
  6.         ssize_t readlen;
  7.         char *lvb_buf;
  8.         struct inode *inode = filp->f_path.dentry->d_inode;

  9.         mlog(0, "inode %lu, count = %zu, *ppos = %llu\n",
  10.                 inode->i_ino, count, *ppos);

  11.         if (*ppos >= i_size_read(inode))
  12.                 return 0;

  13.         if (!count)
  14.                 return 0;

  15.         if (!access_ok(VERIFY_WRITE, buf, count))
  16.                 return -EFAULT;

  17.         /* don't read past the lvb */
  18.         if ((count + *ppos) > i_size_read(inode))
  19.                 readlen = i_size_read(inode) - *ppos;
  20.         else
  21. /*
  22. * linux-2.6.22.5/fs/ocfs2/dlm/dlmfs.c
  23. * ¥2
  24. * what relation between count and ppos?
  25. * readlen determined right?
  26. * say, i_size_read(inode) = 8M bytes, count = 4096 bytes.
  27. */
  28.                 readlen = count - *ppos;

  29.         lvb_buf = kmalloc(readlen, GFP_NOFS);
  30.         if (!lvb_buf)
  31.                 return -ENOMEM;

  32.         user_dlm_read_lvb(inode, lvb_buf, readlen);
  33.         bytes_left = __copy_to_user(buf, lvb_buf, readlen);
  34.         readlen -= bytes_left;

  35.         kfree(lvb_buf);

  36.         *ppos = *ppos + readlen;

  37.         mlog(0, "read %zd bytes\n", readlen);

  38.         return readlen;
  39. }
复制代码

作者: sisi8408    时间: 2007-08-27 16:20

  1. static ssize_t dlmfs_file_write(struct file *filp,
  2.                                 const char __user *buf, size_t count,
  3.                                 loff_t *ppos)
  4. {
  5.         int bytes_left;
  6.         ssize_t writelen;
  7.         char *lvb_buf;
  8.         struct inode *inode = filp->f_path.dentry->d_inode;

  9.         mlog(0, "inode %lu, count = %zu, *ppos = %llu\n",
  10.                 inode->i_ino, count, *ppos);

  11.         if (*ppos >= i_size_read(inode))
  12.                 return -ENOSPC;

  13.         if (!count)
  14.                 return 0;

  15.         if (!access_ok(VERIFY_READ, buf, count))
  16.                 return -EFAULT;

  17.         /* don't write past the lvb */
  18.         if ((count + *ppos) > i_size_read(inode))
  19.                 writelen = i_size_read(inode) - *ppos;
  20.         else
  21. /*
  22. * linux-2.6.22.5/fs/ocfs2/dlm/dlmfs.c

  23. #!/bin/sh
  24. if [ $# != 2 ]
  25. then
  26.         echo disasfun objectfile functionname
  27.         exit 1
  28. fi
  29. OBJFILE=$1
  30. FUNNAME=$2
  31. ADDRSZ=`objdump -t $OBJFILE | gawk -- "{
  32.         if (\\\$3 == \\"F\\" && \\\$6 == \\"$FUNNAME\\") {
  33.                 printf(\\"%s %s\\", \\\$1, \\\$5)
  34.         }
  35. }"`
  36. ADDR=`echo $ADDRSZ | gawk "{ printf(\\"%s\\",\\\$1)}"`
  37. SIZE=`echo $ADDRSZ | gawk "{ printf(\\"%s\\",\\\$2)}"`
  38. if [ -z "$ADDR" -o -z "$SIZE" ]
  39. then
  40.         echo Cannot find address or size of function $FUNNAME
  41.         exit 2
  42. fi
  43. objdump -S $OBJFILE --start-address=0x$ADDR --stop-address=$((0x$ADDR + 0x$SIZE))

  44. * writelen determined right?
  45. */
  46.                 writelen = count - *ppos;

  47.         lvb_buf = kmalloc(writelen, GFP_NOFS);
  48.         if (!lvb_buf)
  49.                 return -ENOMEM;

  50.         bytes_left = copy_from_user(lvb_buf, buf, writelen);
  51.         writelen -= bytes_left;
  52.         if (writelen)
  53.                 user_dlm_write_lvb(inode, lvb_buf, writelen);

  54.         kfree(lvb_buf);

  55.         *ppos = *ppos + writelen;
  56.         mlog(0, "wrote %zd bytes\n", writelen);
  57.         return writelen;
  58. }
复制代码

[ 本帖最后由 sisi8408 于 2008-3-1 10:19 编辑 ]
作者: sisi8408    时间: 2007-08-28 15:15

  1. static int ocfs2_write_data_page(struct inode *inode, handle_t *handle,
  2.                                  u64 *p_blkno, struct page *page,
  3.                                  struct ocfs2_write_ctxt *wc, int new)
  4. {
  5.         int ret, copied = 0;
  6.         unsigned int from = 0, to = 0;
  7.         unsigned int cluster_start, cluster_end;
  8.         unsigned int zero_from = 0, zero_to = 0;

  9.         ocfs2_figure_cluster_boundaries(OCFS2_SB(inode->i_sb), wc->w_cpos,
  10.                                         &cluster_start, &cluster_end);

  11.         if ((wc->w_pos >> PAGE_CACHE_SHIFT) == page->index
  12.             && !wc->w_finished_copy) {
  13.                 wc->w_this_page = page;
  14.                 wc->w_this_page_new = new;
  15.                
  16.                 ret = wc->w_write_data_page(inode, wc, p_blkno, &from, &to);

  17.                 if (ret < 0) {
  18.                         mlog_errno(ret);
  19.                         goto out;
  20.                 }
  21.                 copied = ret;

  22.                 zero_from = from;
  23.                 zero_to = to;

  24.                 if (new) {
  25.                         from = cluster_start;
  26.                         to = cluster_end;
  27.                 }
  28.         } else {
  29.                 /*
  30.                  * If we haven't allocated the new page yet, we
  31.                  * shouldn't be writing it out without copying user
  32.                  * data. This is likely a math error from the caller.
  33.                  */
  34.                 BUG_ON(!new);

  35.                 from = cluster_start;
  36.                 to = cluster_end;

  37.                 ret = ocfs2_map_page_blocks(page, p_blkno, inode,
  38.                                             cluster_start, cluster_end, 1);
  39.                 if (ret) {
  40.                         mlog_errno(ret);
  41.                         goto out;
  42.                 }
  43.         }

  44.         /*
  45.          * Parts of newly allocated pages need to be zero'd.
  46.          *
  47.          * Above, we have also rewritten 'to' and 'from' - as far as
  48.          * the rest of the function is concerned, the entire cluster
  49.          * range inside of a page needs to be written.
  50.          *
  51.          * We can skip this if the page is uptodate - it's already
  52.          * been zero'd from being read in as a hole.
  53.          */
  54.         if (new && !PageUptodate(page))
  55.                 ocfs2_clear_page_regions(page, OCFS2_SB(inode->i_sb),
  56.                                          wc->w_cpos, zero_from, zero_to);
  57.         flush_dcache_page(page);

  58.         if (ocfs2_should_order_data(inode)) {
  59.                 ret = walk_page_buffers(handle,
  60.                                         page_buffers(page),
  61.                                         from, to, NULL,
  62.                                         ocfs2_journal_dirty_data);
  63.                 if (ret < 0)
  64. /*
  65. * linux-2.6.22.5/fs/ocfs2/aops.c
  66. *
  67. * how to & necessary to include this case on return?
  68. * how to re-check in mlog?
  69. */
  70.                         mlog_errno(ret);
  71.         }

  72.         /*
  73.          * We don't use generic_commit_write() because we need to
  74.          * handle our own i_size update.
  75.          */
  76.         ret = block_commit_write(page, from, to);
  77.         if (ret)
  78.                 mlog_errno(ret);
  79. out:
  80.         return copied ? copied : ret;
  81. }
复制代码

作者: sisi8408    时间: 2007-08-30 13:33

  1. static int ocfs2_try_to_merge_extent_map(struct ocfs2_extent_map_item *emi,
  2.                                          struct ocfs2_extent_map_item *ins)
  3. {
  4.         /*
  5.          * Handle contiguousness
  6.          */
  7.         if (ins->ei_phys == (emi->ei_phys + emi->ei_clusters) &&
  8.             ins->ei_cpos == (emi->ei_cpos + emi->ei_clusters) &&
  9.             ins->ei_flags == emi->ei_flags) {
  10.                 emi->ei_clusters += ins->ei_clusters;
  11.                 return 1;
  12.         } else if ((ins->ei_phys + ins->ei_clusters) == emi->ei_phys &&
  13. /*
  14. * linux-2.6.22.5/fs/ocfs2/extent_map.c
  15. * why not
  16. * (ins->ei_cpos + ins->ei_clusters) == emi->ei_cpos
  17. * and more symmetric??
  18. */
  19.                    (ins->ei_cpos + ins->ei_clusters) == emi->ei_phys &&
  20.                    ins->ei_flags == emi->ei_flags) {
  21.                 emi->ei_phys = ins->ei_phys;
  22.                 emi->ei_cpos = ins->ei_cpos;
  23.                 emi->ei_clusters += ins->ei_clusters;
  24.                 return 1;
  25.         }

  26.         /*
  27.          * Overlapping extents - this shouldn't happen unless we've
  28.          * split an extent to change it's flags. That is exceedingly
  29.          * rare, so there's no sense in trying to optimize it yet.
  30.          */
  31.         if (ocfs2_ei_is_contained(emi, ins) ||
  32.             ocfs2_ei_is_contained(ins, emi)) {
  33. /*
  34. * more care needed in em-cache, even a small/simple one.
  35. */
  36.                 ocfs2_copy_emi_fields(emi, ins);
  37.                 return 1;
  38.         }

  39.         /* No merge was possible. */
  40.         return 0;
  41. }
复制代码

[ 本帖最后由 sisi8408 于 2007-8-30 13:51 编辑 ]
作者: sisi8408    时间: 2007-12-01 18:30

  1. /* linux-2.6.22.5/arch/i386/kernel/io_apic.c */
  2. static void __init setup_IO_APIC_irqs (void)
  3. {
  4.                 entry.trigger  = irq_trigger(idx);
  5.                 entry.polarity = irq_polarity(idx);
  6.                 /*2007-12-1 18:29
  7.                 if (entry.trigger) {
  8.                         entry.mask = 1;
  9.                 }
  10.                 */
  11.                 if (irq_trigger(idx)) {
  12.                         entry.trigger = 1;
  13.                         entry.mask = 1;
  14.                 }
  15.                 irq = pin_2_irq(idx, apic, pin);
  16. }
复制代码

this function maybe modified in a few ways in practical usage
作者: 宁愿冷酷到底    时间: 2007-12-03 15:14
申请一个指针,直接指向Y1调用出,最简单的是构造一个API变量,那么直接和系统底层NTLL函数调用,这样省去了中间件,硬件的吞吐量也会很大,整体性能也会上来,

最近没时间写代码,后面有时间补充上来

大家不要拍砖 ^_^
作者: 宁愿冷酷到底    时间: 2007-12-03 15:15
此段指向代码最好用汇编写  。。。。。。。。

具体写法 。。。。。。正在构思中  晚上发上来。。。。
作者: sisi8408    时间: 2007-12-08 07:54

  1. void set_pending_irq(unsigned int irq, cpumask_t mask)
  2. {
  3.         struct irq_desc *desc = irq_desc + irq;
  4.         unsigned long flags;

  5.         spin_lock_irqsave(&desc->lock, flags);
  6.         desc->status |= IRQ_MOVE_PENDING;
  7.         /* 2007-12-8 7:50
  8.          * linux-2.6.22.5/kernel/irq/migration.c
  9.          * desc->pending_mask = mask;
  10.          */
  11.         irq_desc[irq].pending_mask = mask;
  12.         spin_unlock_irqrestore(&desc->lock, flags);
  13. }

复制代码

作者: sisi8408    时间: 2007-12-08 11:09

  1. Touching APIC represented by GNU linux-2.6.22+
复制代码

  1. #ifndef _LINUX_IRQ_H
  2. #define _LINUX_IRQ_H
  3. /*
  4. * Please do not include this file in generic code.
  5. *
  6. * There is currently no requirement for any architecture
  7. * to implement anything held within this file.
  8. *
  9. * Thanks. --rmk
  10. *
  11. ××××××××××××××××××××××××××××××××××××
  12. * IRQ的处理,Ingo Molnar是大今天的赢家,
  13. * 2.6.21+ 迎来Ingo Molnar的时代,还有Andi Kleen in X86-64.
  14. *
  15. * 这种统一的设计方法,俺八哥百学不会,汗汗汗,
  16. × 类似的经典
  17. *        VFS,
  18. *        Block,       老鸟 Jens Axboe, Andrea Arcangeli
  19. *        Socket,     新秀 Arnaldo Carvalho de Melo
  20. ×        Netfilter,  新秀 Yasuyuki Kozakai的时代
  21. ××××××××××××××××××××××××××××××××××××
  22. ×
  23. × 2007/9--11月,八哥出京躲债,在APIC上吃了亏,今天想把这一课补上。
  24. * IRQ,软件的基本定义从<linux/irq.h>发源,
  25. × 硬件已经是XAPIC的时代,八哥想介绍几个关系,
  26. *        1, vector[IRQ]
  27. *        2, LAPIC[IRQ]/IOPIC[IRQ]
  28. *        3, cpu-balance[IRQ]
  29. *        4, request[IRQ]
  30. *
  31. * 代码来自linux-2.6.22.5 from kernel.org
  32. */

  33. request[IRQ]
  34. ============

  35. 先看熟悉的,菜鸟八哥这里仅限于PCI,
  36. request[IRQ]是IRQ subsystem给device driver提供的接口,

  37. static int e1000_request_irq (struct e1000_adapter *adapter)
  38. {
  39.         struct net_device *netdev = adapter->netdev;
  40.         void (*handler) = &e1000_intr;
  41.         int irq_flags = IRQF_SHARED;
  42.         int err;

  43.         if (adapter->hw.mac_type >= e1000_82571) {
  44.                 adapter->have_msi = !pci_enable_msi(adapter->pdev);
  45.                 if (adapter->have_msi) {
  46.                         handler = &e1000_intr_msi;
  47.                         irq_flags = 0;
  48.                 }
  49.         }

  50.         err = request_irq(adapter->pdev->irq, handler,
  51.                           irq_flags, netdev->name, netdev);
  52.         if (err) {
  53.                 if (adapter->have_msi)
  54.                         pci_disable_msi(adapter->pdev);
  55.                 DPRINTK(PROBE, ERR,
  56.                         "Unable to allocate interrupt Error: %d\n", err);
  57.         }
  58.         return err;
  59. }

  60. 设备/芯片的属性/能力不同,表现在request[IRQ]的操作上,

  61. 1,msi与non-msi两种模式
  62. [homework]
  63.         if (adapter->hw.mac_type >= e1000_82571) {
  64.                 adapter->have_msi = !pci_enable_msi(adapter->pdev);
  65.                 if (adapter->have_msi) {
  66.                         handler = &e1000_intr_msi;
  67.                         irq_flags = 0;
  68.                 }
  69.         } else
  70.                 irq_flags = 0;
  71. 又如何?
  72. [/homework]

  73. [homework]
  74. falgs 的定义在 <linux/interrupt.h>
  75. 请比较
  76.         flags |= IRQF_DISABLED ;
  77.         request_irq();

  78.         flags ~= IRQF_DISABLED ;
  79.         request_irq();
  80.        
  81. 的do_IRQ的上下文的区别,扯远啦。
  82. [/homework]

  83. 2,handler统吃两种模式,够牛吧,
  84.    非兮,应该是硬件支持。

  85. int pci_enable_msi (struct pci_dev *dev)
  86. {
  87.         int status;

  88.         status = pci_msi_check_device(dev, 1, PCI_CAP_ID_MSI);
  89.         if (status)
  90.                 return status;

  91.         WARN_ON(!!dev->msi_enabled);

  92.         /* Check whether driver already requested for MSI-X irqs */
  93.         ///
  94.         /// nnd, MSI还没整明白,MSI-X又冒出来了,
  95.         /// 三天不学习,赶不上刘少奇
  96.         ///
  97.         if (dev->msix_enabled) {
  98.                 printk(KERN_INFO "PCI: %s: Can't enable MSI.  "
  99.                         "Device already has MSI-X enabled\n",
  100.                         pci_name(dev));
  101.                 return -EINVAL;
  102.         }
  103.         status = msi_capability_init(dev);
  104.         return status;
  105. }

  106. static int pci_msi_check_device (struct pci_dev* dev, int nvec, int type)
  107. {
  108.         struct pci_bus *bus;
  109.         int ret;

  110.         /* MSI must be globally enabled and supported by the device */
  111.         ///
  112.         ///其一,CONFIG_MSI
  113.         ///
  114.         if (!pci_msi_enable || !dev || dev->no_msi)
  115.                 return -EINVAL;

  116.         /*
  117.          * You can't ask to have 0 or less MSIs configured.
  118.          *  a) it's stupid ..
  119.          *  b) the list manipulation code assumes nvec >= 1.
  120.          */
  121.         if (nvec < 1)
  122.                 return -ERANGE;

  123.         /* Any bridge which does NOT route MSI transactions from it's
  124.          * secondary bus to it's primary bus must set NO_MSI flag on
  125.          * the secondary pci_bus.
  126.          * We expect only arch-specific PCI host bus controller driver
  127.          * or quirks for specific PCI bridges to be setting NO_MSI.
  128.          */
  129.         ///
  130.         ///其二,要求芯片组上下贯通,丝毫不含糊
  131.         ///
  132.         for (bus = dev->bus; bus; bus = bus->parent)
  133.                 if (bus->bus_flags & PCI_BUS_FLAGS_NO_MSI)
  134.                         return -EINVAL;

  135.         ///
  136.         ///其三,查询其他要求
  137.         ///
  138.         ret = arch_msi_check_device(dev, nvec, type);
  139.         if (ret)
  140.                 return ret;
  141.         ///
  142.         ///其四,设备要有能力
  143.         ///
  144.         if (!pci_find_capability(dev, type))
  145.                 return -EINVAL;

  146.         return 0;
  147. }

  148. 3,pdev->irq 哪来的?

  149. static void __init pdev_fixup_irq (struct pci_dev *dev,
  150.                 u8 (*swizzle)(struct pci_dev *, u8 *),
  151.                 int (*map_irq)(struct pci_dev *, u8, u8))
  152. {
  153.         u8 pin, slot;
  154.         int irq = 0;
  155.         /*
  156.         If this device is not on the primary bus,
  157.         we need to figure out which interrupt pin it will come in on.
  158.        
  159.         We know which slot it will come in on 'cos that slot is where the bridge is.

  160.         Each time the interrupt line passes through a PCI-PCI bridge we must
  161.         apply the swizzle function.
  162.         */
  163.         pci_read_config_byte(dev, PCI_INTERRUPT_PIN, &pin);
  164.         /* Cope with illegal */
  165.         if (pin > 4)
  166.                 pin = 1;

  167.         if (pin != 0) {
  168.                 /* Follow the chain of bridges, swizzling as we go.  */
  169.                 slot = (*swizzle)(dev, &pin);
  170.                 irq  = (*map_irq)(dev, slot, pin);
  171.                
  172.                 if (irq == -1)
  173.                         irq = 0;
  174.         }
  175.         ///
  176.         ///其二,原来如此
  177.         /// pci dev 在PCI空间是 bus:slot.fun
  178.         /// 在APCI空间是 bus:slot.pin,这是后话
  179. /***
  180. static void pci_read_irq (struct pci_dev *dev)
  181. {
  182.         unsigned char irq;

  183.         pci_read_config_byte(dev, PCI_INTERRUPT_PIN, &irq);
  184.         dev->pin = irq;

  185.         if (irq)
  186.                 pci_read_config_byte(dev, PCI_INTERRUPT_LINE, &irq);

  187.         ///
  188.         ///其三,PCI_INTERRUPT_PIN 与PCI_INTERRUPT_LINE的统一
  189.         ///
  190.         dev->irq = irq;
  191. }
  192. ***/
  193.         dev->irq = irq;

  194.         pr_debug("PCI: fixup irq: (%s) got irq%d\n",
  195.                 dev->dev.kobj.name, dev->irq);

  196.         /* Always tell the device, so the driver knows what is
  197.            the real IRQ to use; the device does not use it.
  198.         */
  199.         pcibios_update_irq(dev, irq);
  200. }

  201. void __init pci_fixup_irqs (u8 (*swizzle)(struct pci_dev *, u8 *),
  202.                                 int (*map_irq)(struct pci_dev *, u8, u8))
  203. {
  204.         struct pci_dev *dev = NULL;
  205.         ///
  206.         ///其一,都在这了,呵呵
  207.         ///
  208.         while ((dev = pci_get_device(PCI_ANY_ID, PCI_ANY_ID, dev)) != NULL) {
  209.                 pdev_fixup_irq(dev, swizzle, map_irq);
  210.         }
  211. }
  212. [homework]
  213. MSI的IRQ如何不同,有的驱动在这儿就没有留心。
  214. [/homework]
复制代码


参加Linux爱好者技术聚会,去喽。。。

[ 本帖最后由 sisi8408 于 2007-12-8 11:16 编辑 ]
作者: sisi8408    时间: 2007-12-09 10:31

  1. vector[IRQ]
  2. ===========

  3. Understanding 有一章介绍Vector和IDT(Interrupt Description Table),
  4. 八哥看的是第二版,其基本定义在

  5. #ifndef _ASM_HW_IRQ_H
  6. #define _ASM_HW_IRQ_H
  7. /*
  8. * linux/include/asm/hw_irq.h
  9. *
  10. * (C) 1992, 1993 Linus Torvalds, (C) 1997 Ingo Molnar
  11. *
  12. * moved some of the old arch/i386/kernel/irq.h to here. VY
  13. *
  14. * IRQ/IPI changes taken from work by Thomas Radke
  15. * <[email]tomsoft@informatik.tu-chemnitz.de[/email]>
  16. *
  17. * hacked by Andi Kleen for x86-64
  18. */
  19. 相对i386,x86-64的情况简单些,

  20. #define NMI_VECTOR                0x02
  21. /*
  22. * IDT vectors usable for external interrupt sources start
  23. * at 0x20:
  24. ×
  25. × 0x00--0x1f被处理器占用,in kernel/traps.c

  26. void __init trap_init(void)
  27. {
  28.         set_intr_gate(0,&divide_error);
  29.         set_intr_gate_ist(1,&debug,DEBUG_STACK);
  30.         set_intr_gate_ist(2,&nmi,NMI_STACK);
  31.         set_system_gate_ist(3,&int3,DEBUG_STACK); /* int3 can be called from all */
  32.         set_system_gate(4,&overflow);        /* int4 can be called from all */
  33.         set_intr_gate(5,&bounds);
  34.         set_intr_gate(6,&invalid_op);
  35.         set_intr_gate(7,&device_not_available);
  36.         set_intr_gate_ist(8,&double_fault, DOUBLEFAULT_STACK);
  37.         set_intr_gate(9,&coprocessor_segment_overrun);
  38.         set_intr_gate(10,&invalid_TSS);
  39.         set_intr_gate(11,&segment_not_present);
  40.         set_intr_gate_ist(12,&stack_segment,STACKFAULT_STACK);
  41.         set_intr_gate(13,&general_protection);
  42.         set_intr_gate(14,&page_fault);
  43.         set_intr_gate(15,&spurious_interrupt_bug);
  44.         set_intr_gate(16,&coprocessor_error);
  45.         set_intr_gate(17,&alignment_check);
  46. #ifdef CONFIG_X86_MCE
  47.         set_intr_gate_ist(18,&machine_check, MCE_STACK);
  48. #endif
  49.         set_intr_gate(19,&simd_coprocessor_error);

  50. #ifdef CONFIG_IA32_EMULATION
  51.         set_system_gate(IA32_SYSCALL_VECTOR, ia32_syscall);
  52. #endif
  53.       
  54.         /*
  55.          * Should be a barrier for any external CPU state.
  56.          */
  57.         cpu_init();
  58. }
  59. ×××××××××××××
  60. */
  61. #define FIRST_EXTERNAL_VECTOR        0x20

  62. #define IA32_SYSCALL_VECTOR        0x80



  63. /* Reserve the lowest usable priority level 0x20 - 0x2f for triggering
  64. * cleanup after irq migration.
  65. */
  66. #define IRQ_MOVE_CLEANUP_VECTOR        FIRST_EXTERNAL_VECTOR
  67. /*
  68. * Vectors 0x30-0x3f are used for ISA interrupts.
  69. *
  70. * 所谓的16个legacy IRQ被映射到vector[0x30--0x3f]
  71. */
  72. #define IRQ0_VECTOR                FIRST_EXTERNAL_VECTOR + 0x10 ///0x20 + 0x10 = 0x30
  73. #define IRQ1_VECTOR                IRQ0_VECTOR + 1
  74. #define IRQ2_VECTOR                IRQ0_VECTOR + 2
  75. #define IRQ3_VECTOR                IRQ0_VECTOR + 3
  76. #define IRQ4_VECTOR                IRQ0_VECTOR + 4
  77. #define IRQ5_VECTOR                IRQ0_VECTOR + 5
  78. #define IRQ6_VECTOR                IRQ0_VECTOR + 6
  79. #define IRQ7_VECTOR                IRQ0_VECTOR + 7
  80. #define IRQ8_VECTOR                IRQ0_VECTOR + 8
  81. #define IRQ9_VECTOR                IRQ0_VECTOR + 9
  82. #define IRQ10_VECTOR                IRQ0_VECTOR + 10
  83. #define IRQ11_VECTOR                IRQ0_VECTOR + 11
  84. #define IRQ12_VECTOR                IRQ0_VECTOR + 12
  85. #define IRQ13_VECTOR                IRQ0_VECTOR + 13
  86. #define IRQ14_VECTOR                IRQ0_VECTOR + 14
  87. #define IRQ15_VECTOR                IRQ0_VECTOR + 15

  88. /*
  89. * Special IRQ vectors used by the SMP architecture, 0xf0-0xff
  90. *
  91. *  some of the following vectors are 'rare', they are merged
  92. *  into a single vector (CALL_FUNCTION_VECTOR) to save vector space.
  93. *
  94. *  TLB, reschedule and local APIC vectors are performance-critical.
  95. */
  96. #define SPURIOUS_APIC_VECTOR        0xff
  97. #define ERROR_APIC_VECTOR        0xfe
  98. #define RESCHEDULE_VECTOR        0xfd
  99. #define CALL_FUNCTION_VECTOR        0xfc
  100. /*
  101.   0xfb free - please don't re-add KDB here because it's useless
  102.   (hint - think what a NMI bit does to a vector)
  103. */
  104. #define THERMAL_APIC_VECTOR        0xfa
  105. #define THRESHOLD_APIC_VECTOR   0xf9
  106. /*
  107.   0xf8 free
  108. */
  109. #define INVALIDATE_TLB_VECTOR_END        0xf7
  110. #define INVALIDATE_TLB_VECTOR_START        0xf0        /* 0xf0--0xf7 used for TLB flush */

  111. #define NUM_INVALIDATE_TLB_VECTORS        8        /* 0xf0--0xf7 */

  112. /*
  113. * Local APIC timer IRQ vector is on a different priority level,
  114. * to work around the 'lost local interrupt if more than 2 IRQ
  115. * sources per level' errata.
  116. */
  117. #define LOCAL_TIMER_VECTOR        0xef

  118. /*
  119. * First APIC vector available to drivers: (vectors 0x30-0xee)
  120. * we start at 0x41 to spread out vectors evenly between priority
  121. * levels. (0x80 is the syscall vector)
  122. *
  123. * 有了vector和IRQ的映射关系,还要主意 priority levels.
  124. */
  125. #define FIRST_DEVICE_VECTOR        (IRQ15_VECTOR + 2)
  126. #define FIRST_SYSTEM_VECTOR        0xef   /* duplicated in irq.h */

  127. #ifndef __ASSEMBLY__
  128. typedef int vector_irq_t[NR_VECTORS];
  129. DECLARE_PER_CPU(vector_irq_t, vector_irq);
  130. /*
  131. * 映射关系的具体实现,int[NR_CPUS][NR_VECTORS];
  132. */
  133. extern void __setup_vector_irq(int cpu);
  134. /*
  135. * 映射关系的操作方法
  136. */
  137. extern spinlock_t vector_lock;

  138. /*
  139. * Various low-level irq details needed by
  140. *        irq.c,
  141. *        process.c,
  142. *        time.c,
  143. *        io_apic.c and
  144. *        smp.c
  145. *
  146. * 如此多,如此诱惑的金矿,镐在哪?
  147. *
  148. * Interrupt entry/exit code at both C and assembly level
  149. */

  150. extern void disable_8259A_irq(unsigned int irq);
  151. extern void enable_8259A_irq(unsigned int irq);
  152. /*
  153. * 8259A的系列操作
  154. */
  155. extern int i8259A_irq_pending(unsigned int irq);
  156. extern void make_8259A_irq(unsigned int irq);
  157. extern void init_8259A(int aeoi);

  158. extern void send_IPI(int dest, int vector);
  159. /*
  160. * IPI, inter-processor interrupt 操作
  161. *
  162. [homework]
  163. 搜出所有的IPI操作,under arch/x86_64,
  164. 仔细揣摩,玩法多多。
  165. [/homework]
  166. */
  167. extern void send_IPI_self(int vector);

  168. extern void init_VISWS_APIC_irqs(void);

  169. extern void setup_IO_APIC(void);
  170. extern void disable_IO_APIC(void);
  171. /*
  172. * IO_APIC的系列操作,后文慢慢说
  173. */
  174. extern void print_IO_APIC(void);
  175. extern int IO_APIC_get_PCI_irq_vector(int bus, int slot, int fn);
  176. extern void setup_ioapic_dest(void);

  177. extern unsigned long io_apic_irqs;

  178. extern atomic_t irq_err_count;
  179. extern atomic_t irq_mis_count;
  180. /*
  181. io_apic_irqs 是 bitmap??
  182. */
  183. #define IO_APIC_IRQ(x) (((x) >= 16) || ((1<<(x)) & io_apic_irqs))

  184. #define __STR(x) #x
  185. #define STR(x) __STR(x)

  186. #include <asm/ptrace.h>

  187. #define IRQ_NAME2(nr) nr##_interrupt(void)
  188. #define IRQ_NAME(nr) IRQ_NAME2(IRQ##nr)

  189. /*
  190. * SMP has a few special interrupts for IPI messages
  191. *
  192. * 请说明 #define BUILD_IRQ(nr)
  193. */
  194. #define BUILD_IRQ(nr) \
  195. asmlinkage void IRQ_NAME(nr);        \
  196. __asm__("\n.p2align\n"                \
  197.         "IRQ" #nr "_interrupt:\n\t" \
  198.         "push $~(" #nr ") ; " \
  199.         "jmp common_interrupt");


  200. #define platform_legacy_irq(irq)        ((irq) < 16)

  201. #endif
  202. #endif /* _ASM_HW_IRQ_H */

  203. ///
  204. ///中断发生时,vector 的操作在 arch/kernel/head.S
  205. ///vector[IRQ]如何填充??
  206. ///
复制代码

作者: sisi8408    时间: 2007-12-09 17:25

  1. APIC[IRQ]
  2. =========

  3. #ifndef __ASM_APICDEF_H
  4. #define __ASM_APICDEF_H
  5. /*
  6. * Constants for various Intel APICs. (local APIC, IOAPIC, etc.)
  7. *
  8. * Alan Cox <[email]Alan.Cox@linux.org[/email]>, 1995.
  9. * Ingo Molnar <[email]mingo@redhat.com[/email]>, 1999, 2000
  10. */
  11. #define MAX_IO_APICS        128
  12. #define MAX_LOCAL_APIC        256
  13. ///
  14. /// APIC = Local APIC + IO APIC
  15. /// 相比 IO APIC,LAPIC要简单些,
  16. /// 软件描述为 struct local_apic。
  17. ///
  18. /// 多处理器环境,cpu = smp_processor_id();
  19. /// boot_cpu = 0; 这是逻辑编号;还有phy_cpu_id[cpu]编号。
  20. ///
  21. /// 在APIC空间,phy_lapic_id[nr], 0 <= nr <  MAX_LOCAL_APIC,
  22. /// cpu还有与nr的映射关系,cpu = lapic_cpu[nr]。
  23. ///
  24. /// 八哥从来不看Manul, either Intel or AMD,
  25. /// 实话是看不懂,只在代码里面体会。
  26. /// 这里摘录Understanding-II,
  27. /// 1,CPU包含一部分called LAPIC
  28. /// 2,LAPIC包含:
  29. ///                 一堆寄存器        /* in struct local_apic */
  30. ///                 一个内部时钟
  31. ///                 LINT0/1
  32. ///
  33. /// 3, IOAPIC包含:
  34. ///                 N条IRQ线
  35. ///                 N项IRT,interrupt routing/redirection table
  36. ///    IRT可以被独立编程,指明
  37. ///                    中断向量
  38. ///                    优先级
  39. ///                    目标处理器        /* represented by lapic */
  40. ///                    选择处理器的方式
  41. ///
  42. /// 4, 中断的分发方式
  43. ///        4.1  静态分发
  44. ///             查IRT中设定的LAPIC,可以是一个CPU,多个CPU, 全部CPU。
  45. ///
  46. ///        4.2  动态分发
  47. ///             4.2.1  根据正在运行的进程的优先级,发送给低优先级。
  48. ///                    因为LAPIC有可编程TPR,task priority register.
  49. ///             4.2.2  优先级不能决定时,由arbitration决定。
  50. ///
  51. /// 5,通过写LAPIC的ICR,interrupt command register,
  52. ///    产生IPI,inter-processor interrupt             
  53. ///
  54. /// APIC的着眼点是P,在代码中领会,
  55. /// LAPIC的中断分发,IOAPIC的IRT。
  56. ///

  57. /*
  58. * All x86-64 systems are xAPIC compatible.
  59. * In the following, "apicid" is a physical APIC ID.
  60. */
  61. #define XAPIC_DEST_CPUS_SHIFT        4
  62. #define XAPIC_DEST_CPUS_MASK        ((1u << XAPIC_DEST_CPUS_SHIFT) - 1)
  63. #define XAPIC_DEST_CLUSTER_MASK        (XAPIC_DEST_CPUS_MASK << XAPIC_DEST_CPUS_SHIFT)

  64. #define APIC_CLUSTER(apicid)        ((apicid) & XAPIC_DEST_CLUSTER_MASK)
  65. #define APIC_CLUSTERID(apicid)        (APIC_CLUSTER(apicid) >> XAPIC_DEST_CPUS_SHIFT)
  66. /*
  67. * cluster:         high 4 bits
  68. * cpu:                low  4 bits
  69. */
  70. #define APIC_CPUID(apicid)        ((apicid) & XAPIC_DEST_CPUS_MASK)
  71. #define NUM_APIC_CLUSTERS        ((BAD_APICID + 1) >> XAPIC_DEST_CPUS_SHIFT)

  72. /*
  73. * Basic functions accessing LAPIC
  74. *
  75. * 类似 pci_read_config_dword
  76. */
  77. static __inline void apic_write(unsigned long reg, unsigned int v)
  78. {
  79.         *((volatile unsigned int *)(APIC_BASE+reg)) = v;
  80. }

  81. static __inline unsigned int apic_read(unsigned long reg)
  82. {
  83.         return *((volatile unsigned int *)(APIC_BASE+reg));
  84. }
  85. /*
  86. * Basic functions 的具体应用
  87. */
  88. static inline void ack_APIC_irq(void)
  89. {
  90.         /*
  91.          * ack_APIC_irq() actually gets compiled as a single instruction:
  92.          * - a single rmw on Pentium/82489DX
  93.          * - a single write on P6+ cores (CONFIG_X86_GOOD_APIC)
  94.          * ... yummie.
  95.          */

  96.         /* Docs say use 0 for future compatibility */
  97.         apic_write(APIC_EOI, 0);
  98. }
  99. /*
  100.   有了basic,就可以摆弄寄存器了,
  101.   八哥坚持认为,摆弄寄存器是三流代码,照着manul添就是了,
  102.   不如CFQ in block, CBQ in QoS自由和浪漫,
  103.   不过,摆弄好了,也是功夫。
  104. */
  105. extern int get_maxlvt (void);
  106. extern void clear_local_APIC (void);
  107. extern void connect_bsp_APIC (void);
  108. extern void disconnect_bsp_APIC (int virt_wire_setup);
  109. extern void disable_local_APIC (void);
  110. extern int verify_local_APIC (void);
  111. extern void cache_APIC_registers (void);
  112. extern void sync_Arb_IDs (void);
  113. extern void init_bsp_APIC (void);
  114. extern void setup_local_APIC (void);
  115. extern void init_apic_mappings (void);
  116. extern void smp_local_timer_interrupt (void);
  117. extern void setup_boot_APIC_clock (void);
  118. extern void setup_secondary_APIC_clock (void);
  119. extern int APIC_init_uniprocessor (void);
  120. extern void disable_APIC_timer(void);
  121. extern void enable_APIC_timer(void);
  122. extern void setup_apic_routing(void);

  123. extern void setup_APIC_extened_lvt(unsigned char lvt_off, unsigned char vector,
  124.                                    unsigned char msg_type, unsigned char mask);

  125. #define K8_APIC_EXT_LVT_BASE    0x500
  126. #define K8_APIC_EXT_INT_MSG_FIX 0x0
  127. #define K8_APIC_EXT_INT_MSG_SMI 0x2
  128. #define K8_APIC_EXT_INT_MSG_NMI 0x4
  129. #define K8_APIC_EXT_INT_MSG_EXT 0x7
  130. #define K8_APIC_EXT_LVT_ENTRY_THRESHOLD    0

  131. void smp_send_timer_broadcast_ipi(void);
  132. void switch_APIC_timer_to_ipi(void *cpumask);
  133. void switch_ipi_to_APIC_timer(void *cpumask);

  134. #define ARCH_APICTIMER_STOPS_ON_C3        1

  135. extern unsigned boot_cpu_id;
  136. extern int local_apic_timer_c2_ok;
复制代码

作者: sisi8408    时间: 2007-12-14 23:17

  1. /*  ===== in x86_64/kernel/apic.c ====== */

  2. static __init int setup_disableapic(char *str)
  3. {
  4.         disable_apic = 1;
  5.         /*
  6.          * P not only in APIC, but also
  7.          */
  8.         clear_bit(X86_FEATURE_APIC, boot_cpu_data.x86_capability);
  9.         return 0;
  10. }
  11. early_param("disableapic", setup_disableapic);

  12. /*
  13. * This initializes the IO-APIC and APIC hardware if this is
  14. * a UP kernel.
  15. */
  16. int __init APIC_init_uniprocessor(void)
  17. {
  18.         if (disable_apic) {
  19.                 printk(KERN_INFO "Apic disabled\n");
  20.                 return -1;
  21.         }
  22.         if (!cpu_has_apic) {
  23.                 disable_apic = 1;
  24.                 printk(KERN_INFO "Apic disabled by BIOS\n");
  25.                 return -1;
  26.         }
  27.         verify_local_APIC();

  28.         phys_cpu_present_map = physid_mask_of_physid(boot_cpu_id);
  29.         /*
  30.          * 1, what cpu is in APIC space
  31.          */
  32.         apic_write(APIC_ID, SET_APIC_ID(boot_cpu_id));
  33.         /*
  34.          * 2, LAPIC first
  35.          */
  36.         setup_local_APIC();

  37.         if (smp_found_config
  38.             && !skip_ioapic_setup
  39.             && nr_ioapics) {
  40.         /*
  41.          * 3, then IO APIC if at least smp_found_config
  42.          *    why??
  43.          *        maybe IRT unecessary
  44.          */
  45.                 setup_IO_APIC();
  46.         } else
  47.                 nr_ioapics = 0;

  48.         /*
  49.          * 4, and LAPIC clock
  50.          */
  51.         setup_boot_APIC_clock();
  52.         /*
  53.          * 5, finally NMI
  54.          */
  55.         check_nmi_watchdog();
  56.         return 0;
  57. }

  58. asmlinkage void smp_error_interrupt(void)
  59. {
  60.         unsigned int v, v1;

  61.         exit_idle();
  62.         irq_enter();
  63.         /*
  64.           First tickle the hardware,
  65.           only then report what went on.
  66.           -- REW
  67.         */
  68.         v = apic_read(APIC_ESR);
  69.         apic_write(APIC_ESR, 0);
  70.         v1 = apic_read(APIC_ESR);
  71.         ack_APIC_irq();
  72.         /*
  73.          * and the order is important, why not???
  74.         v = apic_read(APIC_ESR);
  75.         apic_write(APIC_ESR, 0);
  76.         ack_APIC_irq();
  77.         v1 = apic_read(APIC_ESR);
  78.          */
  79.         atomic_inc(&irq_err_count);

  80.         /* Here is what the APIC error bits mean:
  81.            0: Send CS error
  82.            1: Receive CS error
  83.            2: Send accept error
  84.            3: Receive accept error
  85.            4: Reserved
  86.            5: Send illegal vector
  87.            6: Received illegal vector
  88.            7: Illegal register address
  89.         */
  90.         printk (KERN_DEBUG "APIC error on CPU%d: %02x(%02x)\n",
  91.                 smp_processor_id(), v , v1);
  92.         irq_exit();
  93. }

  94. asmlinkage void smp_spurious_interrupt (void)
  95. {
  96.         unsigned int v;

  97.         exit_idle();
  98.         irq_enter();
  99.         /*
  100.          * Check if this really is a spurious interrupt and ACK it.
  101.          * if it is a vectored one.  Just in case...
  102.          * Spurious interrupts should not be ACKed.
  103.          */
  104.         v = apic_read(APIC_ISR + ((SPURIOUS_APIC_VECTOR & ~0x1f) >> 1));
  105.         if (v & (1 << (SPURIOUS_APIC_VECTOR & 0x1f)))
  106.                 ack_APIC_irq();

  107. /* ack should be ASAP,
  108. * and tell user innomarl occured,
  109. *
  110. * 八哥遇见e100-82559中断无人处理的情况,on Intel-5110,
  111. * 系统将其关闭。
  112. */
  113. {
  114.         static unsigned long last_warning;
  115.         static unsigned long skipped;

  116.         /* see sw-dev-man vol 3, chapter 7.4.13.5 */
  117. ///        if (time_before(last_warning+30*HZ, jiffies)) {
  118.         if (time_before(jiffies, last_warning +30*HZ)) {
  119.                 printk(KERN_INFO
  120.                 "spurious APIC interrupt on CPU#%d, %ld skipped.\n",
  121.                 smp_processor_id(), skipped);
  122.                 last_warning = jiffies;
  123.                 skipped = 0;
  124.         } else {
  125.                 skipped++;
  126.         }
  127. }
  128.         irq_exit();
  129. }

  130. /*
  131. * LAPIC包含一个内部时钟 and operation
  132. */
  133. void enable_APIC_timer (void)
  134. {
  135.         /*
  136.          * 多数情况的应用是logic cpu number
  137.          */
  138.         int cpu = smp_processor_id();

  139.         if (using_apic_timer &&
  140.             !cpu_isset(cpu, timer_interrupt_broadcast_ipi_mask)) {
  141.                 unsigned long v;

  142.                 v = apic_read(APIC_LVTT);
  143.                 apic_write(APIC_LVTT, v & ~APIC_LVT_MASKED);
  144.         }
  145. }
  146. /*
  147. * goto read manul by AMD
  148. */
  149. void setup_APIC_extened_lvt(unsigned char lvt_off, unsigned char vector,
  150.                             unsigned char msg_type, unsigned char mask)
  151. {
  152.         unsigned long reg = (lvt_off << 4) + K8_APIC_EXT_LVT_BASE;
  153.         unsigned int  v   = (mask << 16) | (msg_type << 8) | vector;
  154.         apic_write(reg, v);
  155. }

  156. void smp_send_timer_broadcast_ipi(void)
  157. {
  158.         int cpu = smp_processor_id();
  159.         cpumask_t mask;

  160.         cpus_and(mask, cpu_online_map,
  161.                  timer_interrupt_broadcast_ipi_mask);

  162.         if (cpu_isset(cpu, mask)) {
  163.                 cpu_clear(cpu, mask);
  164.                 add_pda(apic_timer_irqs, 1);
  165.                 smp_local_timer_interrupt();
  166.         }
  167.         /*
  168.          * 请 cpus in mask do IRQ represented by LOCAL_TIMER_VECTOR,
  169.          * cpu 不懂IRQ,but vector
  170.          *
  171.          * 这样的应用方式大有意思。
  172.          */
  173.         if (!cpus_empty(mask))
  174.                 send_IPI_mask(mask, LOCAL_TIMER_VECTOR);
  175. }
  176. /*
  177. * 编程APIC,启用timer
  178. */
  179. void enable_APIC_timer (void)
  180. {
  181.         int cpu = smp_processor_id();

  182.         if (using_apic_timer &&
  183.             !cpu_isset(cpu, timer_interrupt_broadcast_ipi_mask)) {
  184.                 unsigned long v;

  185.                 v = apic_read(APIC_LVTT);
  186.                 apic_write(APIC_LVTT, v & ~APIC_LVT_MASKED);
  187.         }
  188. }

  189. static int __init calibrate_APIC_clock(void)
  190. {
  191.         unsigned apic, apic_start;
  192.         unsigned long tsc, tsc_start;
  193.         int result;
  194.         /*
  195.          * Put whatever arbitrary (but long enough) timeout
  196.          * value into the APIC clock, we just want to get the
  197.          * counter running for calibration.
  198.          */
  199.         __setup_APIC_LVTT(4000000000);

  200.         apic_start = apic_read(APIC_TMCCT);
  201.        
  202. #ifdef CONFIG_X86_PM_TIMER
  203.         if (apic_calibrate_pmtmr && pmtmr_ioport) {
  204.                 pmtimer_wait(5000);  /* 5ms wait */
  205.                 apic = apic_read(APIC_TMCCT);
  206.                 result = (apic_start - apic) * 1000L / 5;
  207.         } else
  208. #endif
  209.         {
  210.         /*
  211.          * tsc, timestamp counter,
  212.          * 这个准一些,亚纳秒级的精度。
  213.          */
  214.                 rdtscll(tsc_start);

  215.                 do {
  216.                         apic = apic_read(APIC_TMCCT);
  217.                         rdtscll(tsc);
  218.                 } while ((tsc - tsc_start) < TICK_COUNT &&
  219.                         (apic_start - apic) < TICK_COUNT);

  220.                 /* 得到微秒级的结果 */
  221.                 result = (apic_start - apic) * 1000L * tsc_khz /
  222.                                         (tsc - tsc_start);
  223.         }
  224.         printk("result %d\n", result);

  225.         printk(KERN_INFO "Detected %d.%03d MHz APIC timer.\n",
  226.                 result / 1000 / 1000, result / 1000 % 1000);

  227.         return result * APIC_DIVISOR / HZ;
  228. }
  229. /*
  230. * This function sets up the local APIC timer,
  231. * with a timeout of 'clocks' APIC bus clock.
  232. */
  233. static void __setup_APIC_LVTT(unsigned int clocks)
  234. {
  235.         unsigned int lvtt_value, tmp_value;
  236.         int cpu = smp_processor_id();

  237.         lvtt_value = APIC_LVT_TIMER_PERIODIC | LOCAL_TIMER_VECTOR;

  238.         if (cpu_isset(cpu, timer_interrupt_broadcast_ipi_mask))
  239.                 lvtt_value |= APIC_LVT_MASKED;
  240.         apic_write(APIC_LVTT, lvtt_value);

  241.         /*
  242.          * Divide PICLK by 16
  243.          * 32, 64...1024 未必不可,不过没试过。
  244.          * 看看如何影响 Ingo Molnar的HPET
  245.          */
  246.         tmp_value = apic_read(APIC_TDCR);
  247.         apic_write(APIC_TDCR,
  248.           (tmp_value & ~(APIC_TDR_DIV_1 | APIC_TDR_DIV_TMBASE))
  249.           | APIC_TDR_DIV_16);

  250.         apic_write(APIC_TMICT, clocks/APIC_DIVISOR);
  251. }

  252. void __init init_apic_mappings(void)
  253. {
  254.         unsigned long apic_phys;
  255.         /*
  256.          * If no local APIC can be found then set up a fake all
  257.          * zeroes page to simulate the local APIC and another
  258.          * one for the IO-APIC.
  259.          */
  260.         if (!smp_found_config && detect_init_APIC()) {
  261.                 apic_phys = (unsigned long) alloc_bootmem_pages(PAGE_SIZE);
  262.                 apic_phys = __pa(apic_phys);
  263.         } else /*
  264.                 * 当然是硬件的,
  265.                 * smp_found_config的由来,下回再说。
  266.                 */
  267.                 apic_phys = mp_lapic_addr;

  268.         set_fixmap_nocache(FIX_APIC_BASE, apic_phys);
  269.         apic_mapped = 1;
  270.         apic_printk(APIC_VERBOSE,"mapped APIC to %16lx (%16lx)\n",
  271.                         APIC_BASE, apic_phys);

  272.         /* Put local APIC into the resource map. */
  273.         lapic_resource.start = apic_phys;
  274.         lapic_resource.end = lapic_resource.start + PAGE_SIZE - 1;
  275.         insert_resource(&iomem_resource, &lapic_resource);

  276.         /*
  277.          * Fetch the APIC ID of the BSP in case we have a
  278.          * default configuration (or the MP table is broken).
  279.          *
  280.          * 对应smp_processor_id
  281.          */
  282.         boot_cpu_id = GET_APIC_ID(apic_read(APIC_ID));

  283.         {
  284.                 unsigned long ioapic_phys, idx = FIX_IO_APIC_BASE_0;
  285.                 int i;
  286.                 struct resource *ioapic_res;

  287.                 ioapic_res = ioapic_setup_resources();
  288.                 for (i = 0; i < nr_ioapics; i++) {
  289.                         if (smp_found_config) {
  290.                                 ioapic_phys = mp_ioapics[i].mpc_apicaddr;
  291.                         } else {
  292.                                 ioapic_phys = (unsigned long) alloc_bootmem_pages(PAGE_SIZE);
  293.                                 ioapic_phys = __pa(ioapic_phys);
  294.                         }
  295.                         set_fixmap_nocache(idx, ioapic_phys);
  296.                         apic_printk(APIC_VERBOSE,
  297.                                 "mapped IOAPIC to %016lx (%016lx)\n",
  298.                                 __fix_to_virt(idx), ioapic_phys);
  299.                         idx++;

  300.                         if (ioapic_res != NULL) {
  301.                                 ioapic_res->start = ioapic_phys;
  302.                                 ioapic_res->end = ioapic_phys + (4 * 1024) - 1;
  303.                                 ioapic_res++;
  304.                         }
  305.                 }
  306.         }
  307. }

  308. static int lapic_suspend(struct sys_device *dev, pm_message_t state);
  309. /*
  310. * 变化真快,LAPIC也睡觉,
  311. * 还是请球王alb讲讲ACPI
  312. */
  313. static int lapic_resume(struct sys_device *dev)

  314. void __cpuinit setup_local_APIC (void)
  315. {
  316.         unsigned int value, maxlvt;
  317.         int i, j;

  318.         value = apic_read(APIC_LVR);

  319.         BUILD_BUG_ON((SPURIOUS_APIC_VECTOR & 0x0f) != 0x0f);

  320.         /*
  321.          * Double-check whether this APIC is really registered.
  322.          * This is meaningless in clustered apic mode, so we skip it.
  323.          */
  324.         if (!apic_id_registered())
  325.                 BUG();

  326.         /*
  327.          * Intel recommends to set DFR, LDR and TPR before enabling
  328.          * an APIC.  See e.g. "AP-388 82489DX User's Manual" (Intel
  329.          * document number 292116).  So here it goes...
  330.          */
  331.         init_apic_ldr();

  332.         /*
  333.          * Set Task Priority to 'accept all'.
  334.          * We never change this later on.
  335.          *
  336.          * 其一,linux 处理LAPIC与IOAPIC的关系如此简单,
  337.          * 这是主要关系
  338.          */
  339.         value = apic_read(APIC_TASKPRI);
  340.         value &= ~APIC_TPRI_MASK;
  341.         apic_write(APIC_TASKPRI, value);

  342.         /*
  343.          * After a crash, we no longer service the interrupts and a pending
  344.          * interrupt from previous kernel might still have ISR bit set.
  345.          *
  346.          * Most probably by now CPU has serviced that pending interrupt and
  347.          * it might not have done the ack_APIC_irq() because it thought,
  348.          * interrupt came from i8259 as ExtInt. LAPIC did not get EOI so it
  349.          * does not clear the ISR bit and cpu thinks it has already serivced
  350.          * the interrupt. Hence a vector might get locked. It was noticed
  351.          * for timer irq (vector 0x31). Issue an extra EOI to clear ISR.
  352.          */
  353.         for (i = APIC_ISR_NR - 1; i >= 0; i--) {
  354.                 value = apic_read(APIC_ISR + i*0x10);
  355.                 for (j = 31; j >= 0; j--) {
  356.                         if (value & (1<<j))
  357.                                 ack_APIC_irq();
  358.                 }
  359.         }

  360.         /*
  361.          * Now that we are all set up, enable the APIC
  362.          */
  363.         value = apic_read(APIC_SPIV);
  364.         value &= ~APIC_VECTOR_MASK;
  365.         /*
  366.          * Enable APIC
  367.          */
  368.         value |= APIC_SPIV_APIC_ENABLED;

  369.         /* We always use processor focus */
  370.         /*
  371.          * Set spurious IRQ vector
  372.          */
  373.         value |= SPURIOUS_APIC_VECTOR;
  374.         apic_write(APIC_SPIV, value);

  375.         /*
  376.          * Set up LVT0, LVT1:
  377.          *
  378.          * set up through-local-APIC on the BP's LINT0. This is not
  379.          * strictly necessary in pure symmetric-IO mode, but sometimes
  380.          * we delegate interrupts to the 8259A.
  381.          */
  382.         /*
  383.          * TODO: set up through-local-APIC from through-I/O-APIC? --macro
  384.          */
  385.         value = apic_read(APIC_LVT0) & APIC_LVT_MASKED;
  386.         if (!smp_processor_id() && !value) {
  387.                 value = APIC_DM_EXTINT;
  388.                 apic_printk(APIC_VERBOSE, "enabled ExtINT on CPU#%d\n", smp_processor_id());
  389.         } else {
  390.                 value = APIC_DM_EXTINT | APIC_LVT_MASKED;
  391.                 apic_printk(APIC_VERBOSE, "masked ExtINT on CPU#%d\n", smp_processor_id());
  392.         }
  393.         apic_write(APIC_LVT0, value);

  394.         /*
  395.          * only the BP should see the LINT1 NMI signal, obviously.
  396.          */
  397.         if (!smp_processor_id())
  398.                 value = APIC_DM_NMI;
  399.         else
  400.                 value = APIC_DM_NMI | APIC_LVT_MASKED;
  401.         apic_write(APIC_LVT1, value);

  402.         {
  403.                 unsigned oldvalue;
  404.                
  405.                 maxlvt = get_maxlvt();
  406.                 oldvalue = apic_read(APIC_ESR);
  407.                 value = ERROR_APIC_VECTOR;      // enables sending errors
  408.                 apic_write(APIC_LVTERR, value);
  409.                 /*
  410.                  * spec says clear errors after enabling vector.
  411.                  */
  412.                 if (maxlvt > 3)
  413.                         apic_write(APIC_ESR, 0);
  414.                 value = apic_read(APIC_ESR);
  415.                 if (value != oldvalue)
  416.                         apic_printk(APIC_VERBOSE,
  417.                         "ESR value after enabling vector: %08x, after %08x\n",
  418.                         oldvalue, value);
  419.         }
  420.         nmi_watchdog_default();
  421.         setup_apic_nmi_watchdog(NULL);
  422.         apic_pm_activate();
  423. }

  424. void __init init_bsp_APIC(void)
  425. {
  426.         unsigned int value;

  427.         /*
  428.          * Don't do the setup now if we have a SMP BIOS as the
  429.          * through-I/O-APIC virtual wire mode might be active.
  430.          */
  431.         if (smp_found_config || !cpu_has_apic)
  432.                 return;

  433.         value = apic_read(APIC_LVR);

  434.         /*
  435.          * Do not trust the local APIC being empty at bootup.
  436.          */
  437.         clear_local_APIC();

  438.         /*
  439.          * Enable APIC.
  440.          */
  441.         value = apic_read(APIC_SPIV);
  442.         value &= ~APIC_VECTOR_MASK;
  443.         value |= APIC_SPIV_APIC_ENABLED;
  444.         /*
  445.          * 其二,BSP不用FOCUS
  446.          */
  447.         value |= APIC_SPIV_FOCUS_DISABLED;
  448.         value |= SPURIOUS_APIC_VECTOR;
  449.         apic_write(APIC_SPIV, value);

  450.         /*
  451.          * Set up the virtual wire mode.
  452.          */
  453.         apic_write(APIC_LVT0, APIC_DM_EXTINT);
  454.         value = APIC_DM_NMI;
  455.         apic_write(APIC_LVT1, value);
  456. }

  457. void __init sync_Arb_IDs(void)
  458. {
  459.         /* Unsupported on P4 - see Intel Dev. Manual Vol. 3, Ch. 8.6.1 */
  460.         unsigned int ver = GET_APIC_VERSION(apic_read(APIC_LVR));
  461.        
  462.         /* P4 or higher
  463.          * Intel 关于SMP的1.4版本
  464.          */
  465.         if (ver >= 0x14)
  466.                 return;
  467.         /*
  468.          * Wait for idle.
  469.          */
  470.         apic_wait_icr_idle();

  471.         apic_printk(APIC_DEBUG, "Synchronizing Arb IDs.\n");
  472.         /*
  473.          * 其三,仲裁机制的使用
  474.          */
  475.         apic_write(APIC_ICR, APIC_DEST_ALLINC |
  476.                                 APIC_INT_LEVELTRIG
  477.                                 | APIC_DM_INIT);
  478. }

复制代码

作者: sisi8408    时间: 2007-12-15 09:09

  1. static int modern_apic(void)
  2. {
  3.         /* AMD systems use old APIC versions, so check the CPU */
  4.         if (boot_cpu_data.x86_vendor == X86_VENDOR_AMD &&
  5.             boot_cpu_data.x86 >= 0xf)
  6.                 return 1;

  7.         /*
  8.          * linux is able to combine specifications by
  9.          * both Intel and AMD
  10.          */
  11.         return lapic_get_version() >= 0x14;
  12. }

  13. int get_physical_broadcast(void)
  14. {
  15.         /*
  16.          * v1.1 specifies 16 LAPIC
  17.          * v1.4 specifies 2566 LAPIC
  18.          */
  19.         return modern_apic() ? 0xff : 0xf;
  20. }

  21. /* ===== end of LAPIC =====
  22.   summary:
  23.   1, two versions 1.1 and 1.4
  24.   2, the key of LAPIC is P from software point
  25.   3, programing lapic timer
  26.   4, programing lapic LINT0/1
  27.   5, programing lapic IRQ DM, delivery model
复制代码

[ 本帖最后由 sisi8408 于 2007-12-15 10:27 编辑 ]
作者: sisi8408    时间: 2007-12-15 10:26

  1. IOAPIC[IRQ]
  2. ===========

  3. IOAPIC比LAPIC麻烦些,有几种版本,
  4. 1,PIC,2个8259A
  5. 2,MPS,multi pentium standar
  6. 3,MADT,multi APIC description table
  7. 现在流行MADT,由BIOS提供。

  8. part—1,basic def and operation

  9. int nr_ioapic_registers[MAX_IO_APICS];
  10. /*
  11. * Rough estimation of how many shared IRQs there are, can
  12. * be changed anytime.
  13. */
  14. #define MAX_PLUS_SHARED_IRQS        NR_IRQS
  15. #define PIN_MAP_SIZE (MAX_PLUS_SHARED_IRQS + NR_IRQS)
  16. /*
  17. * This is performance-critical, we want to do it O(1)
  18. *
  19. * the indexing order of this array favors 1:1 mappings
  20. * between pins and IRQs.
  21. */
  22. static struct irq_pin_list
  23. {
  24.         int apic,
  25.              pin,
  26.              next;
  27. } irq_2_pin[PIN_MAP_SIZE];

  28. struct io_apic
  29. {
  30.         unsigned int index;        /* reg indx */
  31.         unsigned int unused[3];
  32.         unsigned int data;        /* reg value */
  33. };

  34. /*
  35.   in asm/io_apic.h

  36.   the chip is structured by linux as
  37.         IO_APIC_reg_0x + struct IO_APIC_route_entry
  38.   and that is all ;)
  39. */
  40. union entry_union
  41. {
  42.         /*
  43.          * or simply just a 64-bit number :/
  44.          *
  45.          * and currently engineers to play chip
  46.          * are strongly demanded, specially in CNY,
  47.          * not by linux??
  48.          */
  49.         struct { u32 w1, w2; } ;
  50.         struct IO_APIC_route_entry entry;
  51. };

  52. static struct io_apic __iomem * __attribute_const__  io_apic_base (int idx)
  53. {
  54.         return (void __iomem *) __fix_to_virt(FIX_IO_APIC_BASE_0 + idx)
  55.                 + (mp_ioapics[idx].mpc_apicaddr & ~PAGE_MASK);
  56.         /*
  57.          * mp_ioapics[],暂且认为是来自MADT
  58.          */
  59. }
  60. static inline unsigned int io_apic_read (unsigned int apic, unsigned int reg)
  61. {
  62.         struct io_apic __iomem *io_apic = io_apic_base(apic);

  63.         writel(reg, &io_apic->index);
  64.         return readl(&io_apic->data);
  65. }
  66. static inline void io_apic_write(unsigned int apic,
  67.                                 unsigned int reg, unsigned int value)
  68. {
  69.         struct io_apic __iomem *io_apic = io_apic_base(apic);
  70.         writel(reg, &io_apic->index);
  71.         writel(value, &io_apic->data);
  72. }
复制代码

作者: sisi8408    时间: 2007-12-15 11:19

  1. part-2,IRT entry programming

  2. static struct IO_APIC_route_entry  ioapic_read_entry(int apic, int pin);
  3. /*
  4. * basic IRTE read/write, indexed by pin,
  5. * but how is mapped to irq, then to vector??
  6. */
  7. static void ioapic_write_entry (int apic, int pin,
  8.                 struct IO_APIC_route_entry e);

  9. /* shutup IRQ mapped by pin */
  10. static void ioapic_mask_entry (int apic, int pin);

  11. /*
  12. * IRQ<-->pin mapping table is irq_2_pin[]
  13. *
  14. * but where irq come from??
  15. */
  16. static void add_pin_to_irq (unsigned int irq, int apic, int pin)
  17. {
  18.         static int first_free_entry = NR_IRQS;
  19.         struct irq_pin_list *entry = irq_2_pin + irq;

  20.         while (entry->next)
  21.                 entry = irq_2_pin + entry->next;

  22.         if (entry->pin != -1) {
  23.                 /*
  24.                  * in case IRQ is shared
  25.                  */
  26.                 entry->next = first_free_entry;
  27.                 entry = irq_2_pin + entry->next;
  28.                
  29.                 if (++first_free_entry >= PIN_MAP_SIZE)
  30.                         panic("io_apic.c: whoops");
  31.         }
  32.         entry->apic = apic;
  33.         entry->pin  = pin;
  34. }

  35. /*
  36. * Reroute an IRQ to a different pin
  37. *
  38. * or, cfg pin to use IRQ
  39. */
  40. static void __init replace_pin_at_irq(unsigned int irq,
  41.                                       int oldapic, int oldpin,
  42.                                       int newapic, int newpin);
  43. /*
  44. * core programing method,
  45. * first read, then write.
  46. */
  47. static void __modify_IO_APIC_irq (unsigned int irq,
  48.                                   unsigned long enable,
  49.                                   unsigned long disable)

  50. static void clear_IO_APIC_pin (unsigned int apic, unsigned int pin)
  51. {
  52. /*
  53. * in chip of ioapic, pin is represented by route entry
  54. */
  55.         struct IO_APIC_route_entry entry;
  56.        
  57.         /* Check delivery_mode to be sure we're not clearing an SMI pin */
  58.         entry = ioapic_read_entry(apic, pin);
  59.         if (entry.delivery_mode == dest_SMI)
  60.                 return;
  61.         /*
  62.          * Disable it in the IO-APIC irq-routing table:
  63.          */
  64.         ioapic_mask_entry(apic, pin);
  65. }
复制代码

作者: sisi8408    时间: 2007-12-15 11:20

  1. part-3 irq affinity/balance

  2. 非常高兴,关于balance在CU已经看见 思一克 漂亮的工作,
  3. 这里八哥就不费心了。

复制代码

[ 本帖最后由 sisi8408 于 2007-12-15 11:29 编辑 ]
作者: sisi8408    时间: 2007-12-15 13:48

  1. part-4 麻烦来了,MADT/MPS

  2. /*
  3. * Find the IRQ entry number of a certain pin
  4. */
  5. static int find_irq_entry (int apic, int pin, int type)
  6. {
  7.         int i;
  8.         /*
  9.          * bonding of irq and pin is pre-defined?!
  10.          */
  11.         for (i = 0; i < mp_irq_entries; i++) {
  12.                 if (mp_irqs[i].mpc_irqtype == type &&
  13.                     (mp_irqs[i].mpc_dstapic == mp_ioapics[apic].mpc_apicid ||
  14.                      mp_irqs[i].mpc_dstapic == MP_APIC_ALL) &&
  15.                     mp_irqs[i].mpc_dstirq == pin)
  16.                         return i;
  17.         }
  18.         return -1;
  19. }
  20. /*
  21. * seems it is impossible to make IRQ unshared, if
  22. * two pci devices cfged shared in mp_irqs[]??
  23. * and it is appreciated in practical usage where
  24. * unshared IRQ preferred.
  25. */
  26. static int __init find_pci_irq_pin (int irq, int type)
  27. {
  28.         int i;

  29.         for (i = 0; i < mp_irq_entries; i++) {
  30.                 int lbus;
  31.                
  32.                 lbus = mp_irqs[i].mpc_srcbus;

  33.                 if (mp_bus_id_to_type[lbus]  == MP_BUS_PCI
  34.                  && mp_irqs[i].mpc_irqtype   == type
  35.                  && mp_irqs[i].mpc_srcbusirq == irq)        /* defined in this way */
  36.                         return mp_irqs[i].mpc_dstirq;        /* and its pin */
  37.         }
  38.         return -1;
  39. }

  40. /*
  41. * Find a specific PCI IRQ entry
  42. *
  43. *********************************************
  44. * Not an __init, possibly needed by modules *  
  45. *********************************************
  46. *
  47. * linux从不决人后路,如果Solaris敢放马开放,
  48. * linux充分吸收后,就没有吸引用户的必要了,请鳖揭开面纱。
  49. */

  50. int IO_APIC_get_PCI_irq_vector (int bus, int slot, int pin)
  51. {
  52.         int apic, i, best_guess = -1;

  53.         apic_printk(APIC_DEBUG, "querying PCI -> IRQ mapping bus%d, "
  54.                 "slot%d, pin%d\n", bus, slot, pin);
  55.        
  56.         if (mp_bus_id_to_pci_bus[bus] == -1) {
  57.                 printk(KERN_WARNING
  58.                         "PCI BIOS passed nonexistent PCI bus%d!\n", bus);
  59.                 return -1;
  60.         }

  61.         for (i = 0; i < mp_irq_entries; i++) {
  62.                 int lbus = mp_irqs[i].mpc_srcbus;

  63.                 for (apic = 0; apic < nr_ioapics; apic++) {
  64.                         /*
  65.                          * determine IRQ controler
  66.                          */
  67.                         if (mp_irqs[i].mpc_dstapic == mp_ioapics[apic].mpc_apicid
  68.                          || mp_irqs[i].mpc_dstapic == MP_APIC_ALL)
  69.                                 break;
  70.                 }

  71.                 if (mp_bus_id_to_type[lbus] == MP_BUS_PCI
  72.                  && !mp_irqs[i].mpc_irqtype /* need confirm */
  73.                  && bus == lbus                /* both bus and slot match */
  74.                  && slot == (mp_irqs[i].mpc_srcbusirq >> 2) & 0x1f) {
  75.                         int irq;
  76.                        
  77.                         irq = pin_2_irq(i, apic, mp_irqs[i].mpc_dstirq);
  78.                         if (!(apic || IO_APIC_IRQ(irq)))
  79.                                 continue;
  80.                         /*
  81.                          * and pin match
  82.                          */
  83.                         if (pin == (mp_irqs[i].mpc_srcbusirq & 3))
  84.                                 return irq;

  85.                         /*
  86.                          * Use the first all-but-pin matching entry as a
  87.                          * best-guess fuzzy result for broken mptables.
  88.                          */
  89.                         if (best_guess < 0)
  90.                                 best_guess = irq;
  91.                 }
  92.         }
  93.         return best_guess;
  94. }
  95. /*
  96. * irq of pci_bus:slot.dev is determined in IOAPIC space
  97. * 1, to which controler connected and pin?
  98. * 2, irq = controler_nr * nr_irte + pin
  99. * limited currently by
  100. *        256 vector per cpu
  101. *        128 controler
  102. *         24 irte per controler
  103. *
  104. * irt<-->LAPIC mapping can also be programmed,
  105. * goto see set_ioapic_affinity_irq(irq, TARGET_CPUS) and
  106. * balanced_irq_init()
  107. *
  108. * the major purpose of MADT maybe tell OS controler and pin,
  109. * irq can be re-cfged.
  110. * no problem, ok.
  111. */
  112. static int pin_2_irq (int idx, int apic, int pin)
  113. {
  114.         int irq, i;
  115.         int bus = mp_irqs[idx].mpc_srcbus;
  116.         /*
  117.          * Debugging check, we are in big trouble if this message pops up!
  118.          */
  119.         if (mp_irqs[idx].mpc_dstirq != pin)
  120.                 printk(KERN_ERR "broken BIOS or MPTABLE parser in pin_2_irq, ayiee!!\n");

  121.         switch (mp_bus_id_to_type[bus])
  122.         {
  123.                 case MP_BUS_ISA: /* ISA pin */
  124.                 case MP_BUS_EISA:
  125.                 case MP_BUS_MCA:
  126.                 {
  127.                         irq = mp_irqs[idx].mpc_srcbusirq;
  128.                         break;
  129.                 }
  130.                 case MP_BUS_PCI: /* PCI pin */
  131.                 {
  132.                         /*
  133.                          * PCI IRQs are mapped in order
  134.                          */
  135.                         i = irq = 0;
  136.                         while (i < apic)
  137.                                 irq += nr_ioapic_registers[i++];
  138.                         irq += pin;
  139.                         /*
  140.                          * For MPS mode, so far only needed by ES7000 platform
  141.                          */
  142.                         if (ioapic_renumber_irq)
  143.                                 irq = ioapic_renumber_irq(apic, irq);
  144.                         break;
  145.                 }
  146.                 default:
  147.                 {
  148.                         printk(KERN_ERR "unknown bus type %d in pin_2_irq\n",bus);
  149.                         irq = 0;
  150.                         break;
  151.                 }
  152.         }
  153.         /*
  154.          * PCI IRQ command line redirection.
  155.          * Yes, limits are hardcoded.
  156.          */
  157.         if (pin >= 16 && pin <= 23) {
  158.                 if (pirq_entries[pin -16] != -1) {
  159.                         if (!pirq_entries[pin -16]) {
  160.                                 apic_printk(APIC_VERBOSE, KERN_DEBUG
  161.                                         "disabling PIRQ%d\n", pin -16);
  162.                         } else {
  163.                                 irq = pirq_entries[pin -16];
  164.                                 apic_printk(APIC_VERBOSE, KERN_DEBUG
  165.                                         "using PIRQ%d -> IRQ %d\n", pin -16, irq);
  166.                         }
  167.                 }
  168.         }
  169.         return irq;
  170. }

复制代码

作者: sisi8408    时间: 2007-12-15 13:49

  1. part-5 IRQ attr: trigger/polarity

  2. /*
  3. * 不仅变化快,还很复杂,
  4. *  trigger: edge/level
  5. *  polarity: high/low
  6. */

  7. /*
  8. * check irq is level or edge
  9. */
  10. static inline int IO_APIC_irq_trigger (int irq)
  11. {
  12.         int apic, idx, pin;

  13.         for (apic = 0; apic < nr_ioapics; apic++) {
  14.                 for (pin = 0; pin < nr_ioapic_registers[apic]; pin++) {
  15.                         idx = find_irq_entry(apic, pin, mp_INT);
  16.                         if (idx != -1
  17.                          && irq == pin_2_irq(idx, apic, pin))
  18.                                 return irq_trigger(idx);
  19.                 }
  20.         }
  21.         /*
  22.          * nonexistent IRQs are edge default
  23.          */
  24.         return 0;
  25. }
复制代码

作者: sisi8408    时间: 2007-12-15 13:51

  1. part-6 vector[IRQ]

  2. /*
  3. * irq_vectors is indexed by the sum of all RTEs in all I/O APICs
  4. */
  5. static u8 irq_vector[NR_IRQ_VECTORS] __read_mostly = { FIRST_DEVICE_VECTOR , 0 };

  6. static int __assign_irq_vector (int irq)
  7. {
  8.         static int current_vector = FIRST_DEVICE_VECTOR;
  9.         static int current_offset = 0;
  10.         int vector, offset, i;

  11.         BUG_ON((unsigned)irq >= NR_IRQ_VECTORS);

  12.         if (irq_vector[irq] > 0)        /* shared irq */
  13.                 return irq_vector[irq];

  14.         vector = current_vector;
  15.         offset = current_offset;
  16. next:
  17.         vector += 8;
  18.         if (vector >= FIRST_SYSTEM_VECTOR) {
  19.                 offset = (offset + 1) % 8;
  20.                 /*
  21.                  * the vector of pci-irq has to
  22.                  * be larger than FIRST_DEVICE_VECTOR,
  23.                  * imposed by Intel
  24.                  */
  25.                 vector = FIRST_DEVICE_VECTOR + offset;
  26.         }
  27.         if (vector == current_vector)
  28.                 return -ENOSPC;

  29.         if (vector == SYSCALL_VECTOR)
  30.                 goto next;

  31.         for (i = 0; i < NR_IRQ_VECTORS; i++)
  32.                 if (irq_vector[i] == vector)
  33.                         goto next;

  34.         current_vector = vector;
  35.         current_offset = offset;

  36.         irq_vector[irq] = vector;
  37.         return vector;
  38. }

  39. static struct irq_chip        ioapic_chip;

  40. #define IOAPIC_AUTO        -1
  41. #define IOAPIC_EDGE         0
  42. #define IOAPIC_LEVEL         1

  43. static void ioapic_register_intr (int irq, int vector, unsigned long trigger)
  44. {
  45.         if ((trigger == IOAPIC_AUTO && IO_APIC_irq_trigger(irq))
  46.           || trigger == IOAPIC_LEVEL)
  47.                 set_irq_chip_and_handler_name(irq, &ioapic_chip,
  48.                                  handle_fasteoi_irq, "fasteoi");
  49.         else
  50.                 set_irq_chip_and_handler_name(irq, &ioapic_chip,
  51.                                  handle_edge_irq, "edge");

  52.         set_intr_gate(vector, interrupt[irq]);
  53. }
  54. /* and put all together through
  55. * __ioapic_write_entry(apic, pin, entry);
  56. */
  57. static void __init setup_IO_APIC_irqs (void);

  58. /*
  59. * finally setup
  60. * struct irq_chip msi_chip, lapic_chip and ioapic_chip
  61. * for use by struct irq_desc,
  62. * the nut of linux abstract core of IRQ subsystem
  63. */
  64. [homework]
  65. 1, howto make pci-dev irqs unshared??
  66. 2, is IT from independent thought??
  67. [/homework]

复制代码

作者: sisi8408    时间: 2007-12-16 10:25

  1. #ifdef CONFIG_SMP
  2. /*
  3. * linux-2.6.22.5/arch/i386/kernel/io_apic.c
  4. * 2007-12-16 10:18
  5. * ¥1
  6. */
  7. static void set_msi_irq_affinity (unsigned int irq, cpumask_t mask)
  8. {
  9.         struct msi_msg msg;
  10.         unsigned int dest;
  11.         cpumask_t tmp;
  12.         int vector;

  13.         cpus_and(tmp, mask, cpu_online_map);
  14.         if (cpus_empty(tmp))
  15.                 tmp = TARGET_CPUS;
  16.         /*
  17.          * though tmp checked, but not used anymore.
  18.          * the following `mask' should be tmp
  19.          *
  20.          * mask = tmp;
  21.          */
  22.         vector = assign_irq_vector(irq);
  23.         if (vector < 0)
  24.                 return;

  25.         dest = cpu_mask_to_apicid(mask);

  26.         read_msi_msg(irq, &msg);

  27.         msg.data &= ~MSI_DATA_VECTOR_MASK;
  28.         msg.data |= MSI_DATA_VECTOR(vector);

  29.         msg.address_lo &= ~MSI_ADDR_DEST_ID_MASK;
  30.         msg.address_lo |= MSI_ADDR_DEST_ID(dest);

  31.         write_msi_msg(irq, &msg);
  32.         irq_desc[irq].affinity = mask;
  33. }
  34. #endif
复制代码

作者: sisi8408    时间: 2007-12-16 19:27

  1. /* linux-2.6.22.5/arch/x86_64/kernel/mpparse.c
  2. * 2007-12-16 19:20
  3. * ¥1
  4. */
  5. static void __init MP_ioapic_info (struct mpc_config_ioapic *m)
  6. {
  7.         if (!(m->mpc_flags & MPC_APIC_USABLE))
  8.                 return;

  9.         printk("I/O APIC #%d at 0x%X.\n",
  10.                 m->mpc_apicid, m->mpc_apicaddr);

  11.         if (bad_ioapic(m->mpc_apicaddr))
  12.                 return;
  13. /*
  14.         printk("I/O APIC #%d at 0x%X",
  15.                 m->mpc_apicid, m->mpc_apicaddr);

  16.         if (bad_ioapic(m->mpc_apicaddr)) {
  17.                 printk(" bad\n");
  18.                 return;
  19.         } else
  20.                 printk("\n");
  21. */
  22.         mp_ioapics[nr_ioapics] = *m;
  23.         nr_ioapics++;
  24. }

复制代码

作者: sisi8408    时间: 2007-12-19 21:02

  1. /* linux-2.6.22.5/include/linux/skbuff.h
  2. * 2007-12-19 20:52
  3. * ¥1
  4. */
  5. static inline int pskb_may_pull(struct sk_buff *skb, unsigned int len)
  6. {
  7.         if (likely(len <= skb_headlen(skb))) {
  8.                 /*
  9.                  * howto sure skb->data += len not overflow ?
  10.                  */
  11.                 return 1;
  12.         }
  13.         if (unlikely(len > skb->len))
  14.                 return 0;
  15.         return __pskb_pull_tail(skb, len-skb_headlen(skb)) != NULL;
  16. }
复制代码

作者: sisi8408    时间: 2007-12-22 09:26

  1. /*
  2.   linux-2.6.22.5/kernel/workqueue.c
  3.   2007-12-22 9:19
  4. */
  5. struct workqueue_struct *__create_workqueue(const char *name,
  6.                                             int singlethread, int freezeable)
  7. {
  8.         struct workqueue_struct *wq;
  9.         struct cpu_workqueue_struct *cwq;
  10.         int err = 0, cpu;

  11.         wq = kzalloc(sizeof(*wq), GFP_KERNEL);
  12.         if (!wq)
  13.                 return NULL;

  14.         wq->cpu_wq = alloc_percpu(struct cpu_workqueue_struct);
  15.         if (!wq->cpu_wq) {
  16.                 kfree(wq);
  17.                 return NULL;
  18.         }

  19.         wq->name = name;
  20.         wq->singlethread = singlethread;
  21.         wq->freezeable = freezeable;
  22.         INIT_LIST_HEAD(&wq->list);

  23.         if (singlethread) {
  24.                 cwq = init_cpu_workqueue(wq, singlethread_cpu);
  25.                 err = create_workqueue_thread(cwq, singlethread_cpu);
  26.                 start_workqueue_thread(cwq, -1);
  27.         } else {
  28.                 mutex_lock(&workqueue_mutex);
  29.                 list_add(&wq->list, &workqueues);

  30.                 for_each_possible_cpu(cpu) {
  31.                         cwq = init_cpu_workqueue(wq, cpu);
  32.                         /*
  33.                         if (!cpu_online(cpu))
  34.                                 continue;
  35.                         if (err)
  36.                                 break;
  37.                         */
  38.                         if (err || !cpu_online(cpu))
  39.                                 continue;
  40.                         err = create_workqueue_thread(cwq, cpu);
  41.                         start_workqueue_thread(cwq, cpu);
  42.                 }
  43.                 mutex_unlock(&workqueue_mutex);
  44.         }

  45.         if (err) {
  46.                 destroy_workqueue(wq);
  47.                 wq = NULL;
  48.         }
  49.         return wq;
  50. }
复制代码

作者: sisi8408    时间: 2007-12-22 12:55

  1. /*
  2.   linux-2.6.22.5/net/netfilter/nf_conntrack_proto_tcp.c
  3.   2007-12-22 10:38
  4.   ¥6
  5.   howto crash netfilter with TCP SYN packet, possible?
  6. */
  7. static int tcp_error(struct sk_buff *skb,
  8.                      unsigned int dataoff,
  9.                      enum ip_conntrack_info *ctinfo,
  10.                      int pf,
  11.                      unsigned int hooknum)
  12. {
  13.         struct tcphdr _tcph, *th;
  14.         unsigned int tcplen = skb->len - dataoff;
  15.         u_int8_t tcpflags;

  16.         /* Smaller that minimal TCP header? */
  17.         th = skb_header_pointer(skb, dataoff, sizeof(_tcph), &_tcph);
  18.         if (th == NULL) {
  19.                 if (LOG_INVALID(IPPROTO_TCP))
  20.                         nf_log_packet(pf, 0, skb, NULL, NULL, NULL,
  21.                                 "nf_ct_tcp: short packet ");
  22.                 return -NF_ACCEPT;
  23.         }

  24.         /* Not whole TCP header or malformed packet */
  25.         if (th->doff*4 < sizeof(struct tcphdr)
  26.             || tcplen < th->doff*4) {
  27. [color=Red]                /*
  28.                  * 其一 隐患;/
  29.                  * TCP头长大于60字节是合法的 8-(:
  30.                  */
  31. [/color]                if (LOG_INVALID(IPPROTO_TCP))
  32.                         nf_log_packet(pf, 0, skb, NULL, NULL, NULL,
  33.                                 "nf_ct_tcp: truncated/malformed packet ");
  34.                 return -NF_ACCEPT;
  35.         }

  36.         /* Checksum invalid? Ignore.
  37.          * We skip checking packets on the outgoing path
  38.          * because the checksum is assumed to be correct.
  39.          */
  40.         /* FIXME: Source route IP option packets --RR */
  41.         if (nf_conntrack_checksum &&
  42.             ((pf == PF_INET && hooknum == NF_IP_PRE_ROUTING) ||
  43.              (pf == PF_INET6 && hooknum == NF_IP6_PRE_ROUTING)) &&
  44.             nf_checksum(skb, hooknum, dataoff, IPPROTO_TCP, pf)) {
  45.                 if (LOG_INVALID(IPPROTO_TCP))
  46.                         nf_log_packet(pf, 0, skb, NULL, NULL, NULL,
  47.                                   "nf_ct_tcp: bad TCP checksum ");
  48.                 return -NF_ACCEPT;
  49.         }

  50.         /* Check TCP flags. */
  51.         tcpflags = (((u_int8_t *)th)[13] & ~(TH_ECE|TH_CWR|TH_PUSH));
  52.         if (!tcp_valid_flags[tcpflags]) {
  53.                 if (LOG_INVALID(IPPROTO_TCP))
  54.                         nf_log_packet(pf, 0, skb, NULL, NULL, NULL,
  55.                                   "nf_ct_tcp: invalid TCP flag combination ");
  56.                 return -NF_ACCEPT;
  57.         }
  58.         return NF_ACCEPT;
  59. }

  60. static void tcp_options(const struct sk_buff *skb,
  61.                         unsigned int dataoff,
  62.                         struct tcphdr *tcph,
  63.                         struct ip_ct_tcp_state *state)
  64. {
  65.         unsigned char buff[(15 * 4) - sizeof(struct tcphdr)];
  66.         unsigned char *ptr;
  67.         int length = (tcph->doff*4) - sizeof(struct tcphdr);
  68.         /*
  69.          * length可以大于40;/
  70.          * but sizeof(buff) = 40
  71.          */
  72.         if (!length)
  73.                 return;

  74.         ptr = skb_header_pointer(skb, dataoff + sizeof(struct tcphdr),
  75.                                  length, buff);
  76. [color=Red]        /*
  77.          * 其二 buff可能overflow
  78.          */
  79. [/color]        BUG_ON(ptr == NULL);

  80.         state->td_scale = state->flags = 0;

  81.         while (length > 0) {
  82.                 int opcode = *ptr++;
  83.                 int opsize;

  84.                 switch (opcode) {
  85.                 case TCPOPT_EOL:
  86.                         return;
  87.                
  88.                 case TCPOPT_NOP:        /* Ref: RFC 793 section 3.1 */
  89.                         length--;
  90.                         continue;
  91.                
  92.                 default:
  93.                         opsize = *ptr++;
  94.                        
  95.                         if (opsize < 2) /* "silly options" */
  96.                                 return;
  97.                        
  98.                         if (opsize > length)
  99.                                 break;        /* don't parse partial options */

  100.                         if (opcode == TCPOPT_SACK_PERM
  101.                             && opsize == TCPOLEN_SACK_PERM) {
  102.                                 state->flags |= IP_CT_TCP_FLAG_SACK_PERM;
  103.                         }
  104.                         else if (opcode == TCPOPT_WINDOW
  105.                                  && opsize == TCPOLEN_WINDOW) {
  106.                                 state->td_scale = *(u_int8_t *)ptr;

  107.                                 if (state->td_scale > 14) {
  108.                                         /* See RFC1323 */
  109.                                         state->td_scale = 14;
  110.                                 }
  111.                                 state->flags |= IP_CT_TCP_FLAG_WINDOW_SCALE;
  112.                         }
  113.                         ptr += opsize - 2;
  114.                         length -= opsize;
  115.                 }
  116.         }
  117. }

  118. static inline void * skb_header_pointer (const struct sk_buff *skb,
  119.                                          int offset, int len, void *buffer)
  120. { /* in <linux/skbuff.h> */
  121.        
  122.         int hlen = skb_headlen(skb);

  123.         if (hlen - offset >= len)
  124.                 return skb->data + offset;
  125. [color=Red]        /*
  126.          * 其三  如果是大SYN包,使得skb_copy_bits被调用了,
  127.          * if (len > 40 bytes)
  128.          *        buffer overflow;
  129.          *
  130.          * 但是,netfilter看到的包都是整合过的,
  131.          * 这样的机会几乎没有,要看ipfrag reasm的结果
  132.          */
  133. [/color]        if (skb_copy_bits(skb, offset, buffer, len) < 0)
  134.                 return NULL;

  135.         return buffer;
  136. }
  137. int skb_copy_bits(const struct sk_buff *skb, int offset, void *to, int len)
  138. {
  139.         int i, copy;
  140.         int start = skb_headlen(skb);

  141.         if (offset > (int)skb->len - len)
  142.                 goto fault;

  143.         /* Copy header. */
  144.         if ((copy = start - offset) > 0) {
  145.                 if (copy > len)
  146.                         copy = len;
  147.                 /*
  148.                   这里没有check len,
  149.                   而是默认len <= sizeof(to)
  150.                 */
  151.                 skb_copy_from_linear_data_offset(skb, offset, to, copy);
  152.                 if ((len -= copy) == 0)
  153.                         return 0;
  154.                 offset += copy;
  155.                 to     += copy;
  156.         }
  157.         ...
  158. }
  159. void * memcpy(void *dest, const void *src, size_t count)
  160. {
  161. /*
  162.    C版的memcpy in lib/string.c

  163.    memcpy没有检测overflow的义务;/
  164. */
  165.         char *tmp = dest;
  166.         const char *s = src;

  167.         while (count--)
  168.                 *tmp++ = *s++;
  169.         return dest;
  170. }

  171. static struct sk_buff * ip_frag_reasm (struct ipq *qp, struct net_device *dev)
  172. { /* net/ipv4/ip_fragment.c */
  173.        
  174.         struct iphdr *iph;
  175.         struct sk_buff *fp, *head = qp->fragments;
  176.         int len;
  177.         int ihlen;

  178.         ipq_kill(qp);

  179.         BUG_TRAP(head != NULL);
  180.         BUG_TRAP(FRAG_CB(head)->offset == 0);

  181.         /* Allocate a new buffer for the datagram. */
  182.         ihlen = ip_hdrlen(head);
  183.         len = ihlen + qp->len;

  184.         if (len > 65535)
  185.                 goto out_oversize;

  186.         /* Head of list must not be cloned. */
  187.         if (skb_cloned(head) && pskb_expand_head(head, 0, 0, GFP_ATOMIC))
  188.                 goto out_nomem;

  189.         /* If the first fragment is fragmented itself, we split
  190.          * it to two chunks: the first with data and paged part
  191.          * and the second, holding only fragments. */
  192.         if (skb_shinfo(head)->frag_list) {
  193.                 struct sk_buff *clone;
  194.                 int i, plen = 0;

  195.                 if ((clone = alloc_skb(0, GFP_ATOMIC)) == NULL)
  196.                         goto out_nomem;
  197.                 clone->next = head->next;
  198.                 head->next = clone;
  199.                 skb_shinfo(clone)->frag_list = skb_shinfo(head)->frag_list;
  200.                 skb_shinfo(head)->frag_list = NULL;
  201.                 for (i=0; i<skb_shinfo(head)->nr_frags; i++)
  202.                         plen += skb_shinfo(head)->frags[i].size;
  203.                 clone->len = clone->data_len = head->data_len - plen;
  204.                 head->data_len -= clone->len;
  205.                 head->len -= clone->len;
  206.                 clone->csum = 0;
  207.                 clone->ip_summed = head->ip_summed;
  208.                 atomic_add(clone->truesize, &ip_frag_mem);
  209.         }

  210.         skb_shinfo(head)->frag_list = head->next;
  211. [color=Red]        /*
  212.          * 其四  linux skb精巧的设计,可以方便地处理大包 &)
  213.          *
  214.          * 在这里没有实施linearize,性能可佳。
  215.          */
  216. [/color]        skb_push(head, head->data - skb_network_header(head));
  217.         atomic_sub(head->truesize, &ip_frag_mem);

  218.         for (fp = head->next; fp; fp = fp->next) {
  219.                 head->data_len += fp->len;
  220. [color=Red]                /*
  221.                  * 由于没有linearize操作,
  222.                  * 虽然总包长要求len < 65535 byte,
  223.                  * 首包长确可以是
  224.                  * 82byte = 20byte<IP> + 60byte<TCP> + 2byte<trash>
  225.                  *
  226.                  * 所以 tcp->doff*4 = 88byte,
  227.                  * 将迫使skb_header_pointer调用skb_copy_bits,
  228.                  * 结果导致40byte的buff overflow
  229.                  */
  230. [/color]                head->len += fp->len;
  231.                
  232.                 if (head->ip_summed != fp->ip_summed)
  233.                         head->ip_summed = CHECKSUM_NONE;
  234.                 else if (head->ip_summed == CHECKSUM_COMPLETE)
  235.                         head->csum = csum_add(head->csum, fp->csum);
  236.                
  237.                 head->truesize += fp->truesize;
  238.                 atomic_sub(fp->truesize, &ip_frag_mem);
  239.         }

  240.         head->next = NULL;
  241.         head->dev = dev;
  242.         head->tstamp = qp->stamp;

  243.         iph = ip_hdr(head);
  244.         iph->frag_off = 0;
  245.         iph->tot_len = htons(len);
  246.         IP_INC_STATS_BH(IPSTATS_MIB_REASMOKS);
  247.         qp->fragments = NULL;
  248.         return head;

  249. out_nomem:
  250.         LIMIT_NETDEBUG(KERN_ERR "IP: queue_glue: no memory for gluing "
  251.                               "queue %p\n", qp);
  252.         goto out_fail;
  253. out_oversize:
  254.         if (net_ratelimit())
  255.                 printk(KERN_INFO
  256.                         "Oversized IP packet from %d.%d.%d.%d.\n",
  257.                         NIPQUAD(qp->saddr));
  258. out_fail:
  259.         IP_INC_STATS_BH(IPSTATS_MIB_REASMFAILS);
  260.         return NULL;
  261. }
复制代码

[ 本帖最后由 sisi8408 于 2007-12-22 14:42 编辑 ]
作者: platinum    时间: 2007-12-22 13:27
两个问题
1、sisi8408 大哥做过实验吗?
2、根据对 sisi8408 大哥的了解,含有中文注释并带有 color=red 的贴子更像是从哪里转过来的,文章来源是哪里呢?
作者: sisi8408    时间: 2007-12-22 14:33
标题: 回复 #71 platinum 的帖子
1、sisi8408 大哥做过实验吗?
//实验的没有,道理上说得通,就应该关注了

2、根据对 sisi8408 大哥的了解,含有中文注释并带有 color=red 的贴子更像是从哪里转过来的,
文章来源是哪里呢?
//没了解好,俺抄谁呐?给大家提个兴而已。
作者: sisi8408    时间: 2007-12-22 14:55

  1. struct tcphdr {
  2.         __be16        source;
  3.         __be16        dest;
  4.         __be32        seq;
  5.         __be32        ack_seq;
  6. #if defined(__LITTLE_ENDIAN_BITFIELD)
  7.         __u16        res1:4,
  8.                 doff:4,        /* 正解 doff *4 <= 60, 逗你玩 */
  9.                 fin:1,
  10.                 syn:1,
  11.                 rst:1,
  12.                 psh:1,
  13.                 ack:1,
  14.                 urg:1,
  15.                 ece:1,
  16.                 cwr:1;
  17. #elif defined(__BIG_ENDIAN_BITFIELD)
  18.         __u16        doff:4,
  19.                 res1:4,
  20.                 cwr:1,
  21.                 ece:1,
  22.                 urg:1,
  23.                 ack:1,
  24.                 psh:1,
  25.                 rst:1,
  26.                 syn:1,
  27.                 fin:1;
  28. #else
  29. #error        "Adjust your <asm/byteorder.h> defines"
  30. #endif       
  31.         __be16        window;
  32.         __sum16        check;
  33.         __be16        urg_ptr;
  34. };

复制代码

作者: sisi8408    时间: 2007-12-22 20:52

  1. /* 2007-12-22 20:47 */
  2. static void tcp_options(const struct sk_buff *skb,
  3.                         unsigned int dataoff,
  4.                         struct tcphdr *tcph,
  5.                         struct ip_ct_tcp_state *state)
  6. {
  7.         unsigned char buff[(15 * 4) - sizeof(struct tcphdr)];
  8.         unsigned char *ptr;
  9.         int length = (tcph->doff*4) - sizeof(struct tcphdr);
  10.         /*
  11.          * sizeof(buff) = 40
  12.          * length 只能 <= 40 ;)
  13.          */
  14.         if (!length)
  15.                 return;

  16.         ptr = skb_header_pointer(skb, dataoff + sizeof(struct tcphdr),
  17.                                  length, buff);
  18.        
  19.         /*108byte(20byte<IP>  +
  20.          *          20byte<TCP>  +
  21.          *          40byte<TCP opt> +
  22.          *          28byte<trash>)SYN 包拆成两个碎片:
  23.          * 第一个包:20byte<IP> + 20byte<TCP> + 24byte<TCP opt>
  24.          *           and tcp->doff = 0xf
  25.          * 第二个包:20byte<IP> + 16byte<TCP opt> + 28byte<trash>
  26.          *
  27.          * 这样会迫使 ptr = buff ;/
  28.          * =========================
  29.          * 40byte<TCP opt>这样填充,使得:
  30.          * buff[0 ... 38] = TCPOPT_NOP ;
  31.          * buff[39] = 非 TCPOPT_NOP and TCPOPT_EOL
  32.          */
  33.         BUG_ON(ptr == NULL);

  34.         state->td_scale = state->flags = 0;

  35.         while (length > 0) {
  36.                 /*
  37.                  * when length = 1, ptr = &buff[39], and
  38.                  * while-loop progress...
  39.                  */
  40.                 int opcode = *ptr++;
  41.                 /*
  42.                  * after opcode is read,
  43.                  * ptr = &buff[40]
  44.                  * still ok,
  45.                  */
  46.                 int opsize;

  47.                 switch (opcode) {
  48.                 case TCPOPT_EOL:
  49.                         return;
  50.                 case TCPOPT_NOP:        /* Ref: RFC 793 section 3.1 */
  51.                         length--;
  52.                         continue;
  53.                 default:
  54.                         /*
  55.                          * but when opsize is reading,
  56.                          * buff overflow :?/
  57.                          */
  58.                         opsize = *ptr++;
  59.                        
  60.                         if (opsize < 2) /* "silly options" */
  61.                                 return;
  62.                        
  63.                         if (opsize > length)
  64.                                 break;        /* don't parse partial options */

  65.                         if (opcode == TCPOPT_SACK_PERM
  66.                             && opsize == TCPOLEN_SACK_PERM) {
  67.                                 state->flags |= IP_CT_TCP_FLAG_SACK_PERM;
  68.                         }
  69.                         else if (opcode == TCPOPT_WINDOW
  70.                                  && opsize == TCPOLEN_WINDOW) {
  71.                                 state->td_scale = *(u_int8_t *)ptr;

  72.                                 if (state->td_scale > 14) {
  73.                                         /* See RFC1323 */
  74.                                         state->td_scale = 14;
  75.                                 }
  76.                                 state->flags |= IP_CT_TCP_FLAG_WINDOW_SCALE;
  77.                         }
  78.                         ptr += opsize - 2;
  79.                         length -= opsize;
  80.                 }
  81.         }
  82. }
复制代码

[ 本帖最后由 sisi8408 于 2007-12-22 20:59 编辑 ]
作者: platinum    时间: 2007-12-25 01:10
我也来凑个热闹,这也是一个 BUG 吗?(能力有限,让大家笑话了)

/usr/src/linux/net/ipv4/netfilter/ip_conntrack_proto_tcp.c

  1. /* Print out the private part of the conntrack. */
  2. static int tcp_print_conntrack(struct seq_file *s,
  3.                                const struct ip_conntrack *conntrack)
  4. {
  5.         enum tcp_conntrack state;
  6.         read_lock_bh(&tcp_lock);

  7.         /* 这里 state 可能取到很多值 */
  8.         state = conntrack->proto.tcp.state;
  9.         read_unlock_bh(&tcp_lock);

  10.         /* 这里显示具体的 state */
  11.         return seq_printf(s, "%s ", tcp_conntrack_names[state]);
  12. }
复制代码

  1. static const char *tcp_conntrack_names[] = {
  2.         "NONE",
  3.         "SYN_SENT",
  4.         "SYN_RECV",
  5.         "ESTABLISHED",
  6.         "FIN_WAIT",
  7.         "CLOSE_WAIT",
  8.         "LAST_ACK",
  9.         "TIME_WAIT",
  10.         "CLOSE",
  11.         "LISTEN"
  12. };
复制代码

  1. /* This is exposed to userspace (ctnetlink) */
  2. enum tcp_conntrack {
  3.         TCP_CONNTRACK_NONE,
  4.         TCP_CONNTRACK_SYN_SENT,
  5.         TCP_CONNTRACK_SYN_RECV,
  6.         TCP_CONNTRACK_ESTABLISHED,
  7.         TCP_CONNTRACK_FIN_WAIT,
  8.         TCP_CONNTRACK_CLOSE_WAIT,
  9.         TCP_CONNTRACK_LAST_ACK,
  10.         TCP_CONNTRACK_TIME_WAIT,
  11.         TCP_CONNTRACK_CLOSE,
  12.         TCP_CONNTRACK_LISTEN,
  13.         TCP_CONNTRACK_MAX,          /* 这个没有出现在 tcp_conntrack_names 中 */
  14.         TCP_CONNTRACK_IGNORE     /* 同上 */
  15. };
复制代码

  1. struct ip_ct_tcp
  2. {
  3.         struct ip_ct_tcp_state seen[2]; /* connection parameters per direction */
  4.         u_int8_t        state;          /* state of the connection (enum tcp_conntrack) */
  5.                                                 /* 这里取的可是 enum tcp_conntrack 的值啊? */
  6.         /* For detecting stale connections */
  7.         u_int8_t        last_dir;       /* Direction of the last packet (enum ip_conntrack_dir) */
  8.         u_int8_t        retrans;        /* Number of retransmitted packets */
  9.         u_int8_t        last_index;     /* Index of the last packet */
  10.         u_int32_t       last_seq;       /* Last sequence number seen in dir */
  11.         u_int32_t       last_ack;       /* Last sequence number seen in opposite dir */
  12.         u_int32_t       last_end;       /* Last seq + len */
  13.         u_int16_t       last_win;       /* Last window advertisement seen in dir */
  14. };
复制代码

state = conntrack->proto.tcp.state; 可能取到 TCP_CONNTRACK_MAX 或 TCP_CONNTRACK_IGNORE 吗?
return seq_printf(s, "%s ", tcp_conntrack_names[state]); 会不会溢出?

[ 本帖最后由 platinum 于 2007-12-25 13:28 编辑 ]
作者: sisi8408    时间: 2007-12-29 22:15

  1. #include <net/snmp.h>
  2. #include <net/ip.h>
  3. #include <net/protocol.h>
  4. #include <net/route.h>
  5. #include <net/xfrm.h>
  6. #include <linux/skbuff.h>
  7. #include <net/sock.h>
  8. #include <net/arp.h>
  9. #include <net/icmp.h>
  10. /* why so much men? linux-2.6.22.5/net/ipv4/ip_output.c
  11. #include <net/checksum.h> */
  12. #include <net/inetpeer.h>
  13. #include <net/checksum.h>
  14. #include <linux/igmp.h>

复制代码

作者: sisi8408    时间: 2008-01-11 23:00

  1. Hi, Jozsef

  2. Though functions in nf_conntrack_proto_tcp.c never see fragmented packets,
  3. the implementation of the function, ip_frag_reasm() in linux/net/ipv4/ip_fragment.c,
  4. does not make sure that the skb seen in nf_conntrack_proto_tcp.c is linearized,
  5. at least in the case of linux-2.6.22.5 from kernel.org.

  6. Therefore buff overflow is still a problem, if not a vulnerability,
  7. in the function of tcp_options(),
  8. as shown in the following code,

  9. static struct sk_buff *ip_frag_reasm(struct ipq *qp, struct net_device *dev)
  10. {
  11. [...]
  12.     /*
  13.      * head is not linearized,
  14.      * 2008-1-11 22:48 by sisi
  15.      */
  16.     skb_shinfo(head)->frag_list = head->next;

  17.     skb_push(head, head->data - skb_network_header(head));
  18.     atomic_sub(head->truesize, &ip_frag_mem);

  19.     for (fp=head->next; fp; fp = fp->next) {
  20.         head->data_len += fp->len;
  21.         head->len += fp->len;
  22.         if (head->ip_summed != fp->ip_summed)
  23.             head->ip_summed = CHECKSUM_NONE;
  24.         else if (head->ip_summed == CHECKSUM_COMPLETE)
  25.             head->csum = csum_add(head->csum, fp->csum);
  26.         head->truesize += fp->truesize;
  27.         atomic_sub(fp->truesize, &ip_frag_mem);
  28.     }

  29.     head->next = NULL;
  30.     head->dev = dev;
  31.     head->tstamp = qp->stamp;

  32.     iph = ip_hdr(head);
  33.     iph->frag_off = 0;
  34.     iph->tot_len = htons(len);
  35.     IP_INC_STATS_BH(IPSTATS_MIB_REASMOKS);
  36.     qp->fragments = NULL;
  37.     return head;
  38. [...]
  39. }


  40. Best regards,
  41. Jing



  42. 2008/1/4, Jozsef Kadlecsik <[email]kadlec@blackhole.kfki.hu[/email]>:

  43.     Hi,

  44.     On Mon, 24 Dec 2007, jing zhang wrote:

  45.     > buffer overflow is discovered in parsing TCP options,
  46.     > in both tcp_sack() and tcp_options() functions,
  47.     > implemented in nf_conntrack_proto_tcp.c of linux-2.6.22/23.x
  48.     >
  49.     > I think it is possible to crash a netfilter-based firewall box with simply
  50.     > constructed TCP SYN packet.
  51.     [...]
  52.     > /*
  53.     >   If 108-byte TCP SYN packet is received in
  54.     >   the manner of two frags:
  55.     >   farg-I,  20-byte-IP + 20-byte-TCP + 24-byte-TCP_OPT
  56.     >             and tcp->doff assigned to 0xf
  57.     >
  58.     >   farg-II,  20-byte-IP + 16-byte-TCP_OPT + 28-byte-TRASH
  59.     >
  60.     >   then the `ptr' is forcedly assigned to `buff',
  61.     >   and sizeof(buff) is 40-byte.
  62.     > */
  63.     [...]

  64.     Please note, defragmenting happens before conntrack is called. In other
  65.     words these functions never see fragmented packets. Therefore I think
  66.     there is no such problem in nf_conntrack_proto_tcp.c.

  67.     Best regards,
  68.     Jozsef
  69.     -
  70.     E-mail  : [email]kadlec@blackhole.kfki.hu[/email], [email]kadlec@sunserv.kfki.hu[/email]
  71.     PGP key : [url]http://www.kfki.hu/~kadlec/pgp_public_key.txt[/url]
  72.     Address : KFKI Research Institute for Particle and Nuclear Physics
  73.               H-1525 Budapest 114, POB. 49, Hungary
复制代码


though attended, not understood enough yet.

[ 本帖最后由 sisi8408 于 2008-1-13 15:44 编辑 ]
作者: sisi8408    时间: 2008-01-13 15:45

  1. static int ksoftirqd(void * __bind_cpu)
  2. {
  3.         set_current_state(TASK_INTERRUPTIBLE);
  4.         /*
  5.          * linux-2.6.23.12
  6.          * set_user_nice(current, 1);
  7.          */
  8. [...]
  9. }
复制代码

作者: platinum    时间: 2008-01-13 19:11
sisi8408 大哥帮我看看 75 楼的问题,究竟是怎么一回事呢?
作者: sisi8408    时间: 2008-01-14 20:26
to platinum

  1. $
  2. $ mkdir /home/platin
  3. $ vim /home/platin/show_buflow.c

  4. #include <linux/module.h>
  5. #include <linux/kernel.h>

  6. #define SHOW_BUF_MAX 3
  7. static char *buff[] = {
  8.         [0 ... SHOW_BUF_MAX -2] = "aaa",
  9.         [SHOW_BUF_MAX -1] = "and what?",
  10. };

  11. static int __init show_buflow_start(void)
  12. {
  13.         int j;
  14.         for (j = 0; j < SHOW_BUF_MAX; j++)
  15.                 printk("%s\n", buff[j]);
  16.         printk("%s\n", buff[j+3]);
  17.         return 0;
  18. }
  19. static void __exit show_buflow_finish(void) {}
  20. module_init(show_buflow_start);
  21. module_exit(show_buflow_finish);

  22. $ echo obj-m=show_buflow.o >>  /home/platin/Makefile
  23. $ make -C /usr/src/linux-2.6.23.12 M=/home/platin modules
  24. $ insmod  /home/platin/show_buflow.ko
  25. $
复制代码

作者: platinum    时间: 2008-01-15 11:54

  1. localhost test # insmod show_buflow.ko
  2. 段错误
  3. localhost test # lsmod
  4. Module                  Size  Used by
  5. show_buflow             5248  1
  6. pcnet32                31236  0
  7. localhost test # rmmod show_buflow
  8. ERROR: Module show_buflow is in use
  9. localhost test #
复制代码

  1. Jan 15 11:42:15 localhost show_buflow: module license 'unspecified' taints kernel.
  2. Jan 15 11:42:15 localhost aaa
  3. Jan 15 11:42:15 localhost aaa
  4. Jan 15 11:42:15 localhost and what?
  5. Jan 15 11:42:15 localhost BUG: unable to handle kernel paging request at virtual address 74616877
  6. Jan 15 11:42:15 localhost printing eip:
  7. Jan 15 11:42:15 localhost c01e6737
  8. Jan 15 11:42:15 localhost *pde = 00000000
  9. Jan 15 11:42:15 localhost Oops: 0000 [#1]
  10. Jan 15 11:42:15 localhost PREEMPT SMP
  11. Jan 15 11:42:15 localhost Modules linked in: show_buflow(P) pcnet32
  12. Jan 15 11:42:15 localhost CPU:    0
  13. Jan 15 11:42:15 localhost EIP:    0060:[<c01e6737>]    Tainted: P       VLI
  14. Jan 15 11:42:15 localhost EFLAGS: 00010097   (2.6.21-gentoo-r4 #56)
  15. Jan 15 11:42:15 localhost EIP is at vsnprintf+0x2af/0x48c
  16. Jan 15 11:42:15 localhost eax: 74616877   ebx: ffffffff   ecx: 74616877   edx: fffffffe
  17. Jan 15 11:42:15 localhost esi: c04d26c0   edi: c4b63eb0   ebp: ffffffff   esp: c4b63dc4
  18. Jan 15 11:42:15 localhost ds: 007b   es: 007b   fs: 00d8  gs: 0033  ss: 0068
  19. Jan 15 11:42:15 localhost Process insmod (pid: 6658, ti=c4b62000 task=cfeb1580 task.ti=c4b62000)
  20. Jan 15 11:42:15 localhost Stack: 00000000 cfeb7070 cfeb7070 1b41a784 00000109 0000f6d7 00000400 c04d26c0
  21. Jan 15 11:42:15 localhost 0051e0c0 c4b63e0c c04d2ac0 ffffffff 00000000 d0855051 00000400 cf402c00
  22. Jan 15 11:42:15 localhost cf402d98 d0855280 c01e69fd c4b63eb0 00000003 c011e412 c4b63eb0 cf51e0c0
  23. Jan 15 11:42:15 localhost Call Trace:
  24. Jan 15 11:42:15 localhost [<c01e69fd>] vscnprintf+0x14/0x1f
  25. Jan 15 11:42:15 localhost [<c011e412>] vprintk+0xbd/0x2fc
  26. Jan 15 11:42:15 localhost [<c01195f0>] try_to_wake_up+0x393/0x39d
  27. Jan 15 11:42:15 localhost [<c033b0a8>] preempt_schedule+0x46/0x58
  28. Jan 15 11:42:15 localhost [<c01195f0>] try_to_wake_up+0x393/0x39d
  29. Jan 15 11:42:15 localhost [<c033b05a>] wait_for_completion+0x93/0x9b
  30. Jan 15 11:42:15 localhost [<c033c911>] _spin_unlock_irq+0xe/0x22
  31. Jan 15 11:42:15 localhost [<c011e66c>] printk+0x1b/0x1f
  32. Jan 15 11:42:15 localhost [<d0855038>] init_module+0x38/0x40 [show_buflow]
  33. Jan 15 11:42:15 localhost [<c01395e5>] sys_init_module+0x15ac/0x16e3
  34. Jan 15 11:42:15 localhost [<c033c767>] _spin_lock+0xd/0x5a
  35. Jan 15 11:42:15 localhost [<c011e651>] printk+0x0/0x1f
  36. Jan 15 11:42:15 localhost [<c0159fa7>] __fput+0x112/0x13c
  37. Jan 15 11:42:15 localhost [<c016ac25>] mntput_no_expire+0x11/0x5c
  38. Jan 15 11:42:15 localhost [<c0104e20>] sysenter_past_esp+0x5d/0x81
  39. Jan 15 11:42:15 localhost =======================
  40. Jan 15 11:42:15 localhost Code: 74 24 28 73 03 c6 06 20 46 4d 85 ed 7f f1 e9 b9 00 00 00 8b 0f 81 f9 ff 0f 00 00 b8 2e 51 3d c0 0f 46 c8 8b 54 24 2c 89 c8 eb 06 <80> 38 00 74 07 40 4a 83 fa ff 75 f4 29 c8 89 c3 89 e8 f6 44 24
  41. Jan 15 11:42:15 localhost EIP: [<c01e6737>] vsnprintf+0x2af/0x48c SS:ESP 0068:c4b63dc4
  42. Jan 15 11:42:15 localhost note: insmod[6658] exited with preempt_count 2
  43. Jan 15 11:42:15 localhost BUG: scheduling while atomic: insmod/0x10000002/6658
  44. Jan 15 11:42:15 localhost [<c033a806>] __sched_text_start+0x56/0x7c3
  45. Jan 15 11:42:15 localhost [<c02e70f0>] net_rx_action+0x13c/0x181
  46. Jan 15 11:42:15 localhost [<c0119a38>] __cond_resched+0x12/0x2c
  47. Jan 15 11:42:15 localhost [<c033b575>] cond_resched+0x26/0x31
  48. Jan 15 11:42:15 localhost [<c0148961>] unmap_vmas+0x415/0x514
  49. Jan 15 11:42:15 localhost [<c014b307>] exit_mmap+0x7c/0x108
  50. Jan 15 11:42:15 localhost [<c011bcd0>] mmput+0x1d/0x78
  51. Jan 15 11:42:15 localhost [<c0120623>] do_exit+0x1ae/0x6ad
  52. Jan 15 11:42:15 localhost [<c010638b>] die+0x208/0x22d
  53. Jan 15 11:42:15 localhost [<c033e362>] do_page_fault+0x442/0x510
  54. Jan 15 11:42:15 localhost [<c033df20>] do_page_fault+0x0/0x510
  55. Jan 15 11:42:15 localhost [<c033cacc>] error_code+0x7c/0x84
  56. Jan 15 11:42:15 localhost [<c01e6737>] vsnprintf+0x2af/0x48c
  57. Jan 15 11:42:15 localhost [<c01e69fd>] vscnprintf+0x14/0x1f
  58. Jan 15 11:42:15 localhost [<c011e412>] vprintk+0xbd/0x2fc
  59. Jan 15 11:42:15 localhost [<c01195f0>] try_to_wake_up+0x393/0x39d
  60. Jan 15 11:42:15 localhost [<c033b0a8>] preempt_schedule+0x46/0x58
  61. Jan 15 11:42:15 localhost [<c01195f0>] try_to_wake_up+0x393/0x39d
  62. Jan 15 11:42:15 localhost [<c033b05a>] wait_for_completion+0x93/0x9b
  63. Jan 15 11:42:15 localhost [<c033c911>] _spin_unlock_irq+0xe/0x22
  64. Jan 15 11:42:15 localhost [<c011e66c>] printk+0x1b/0x1f
  65. Jan 15 11:42:15 localhost [<d0855038>] init_module+0x38/0x40 [show_buflow]
  66. Jan 15 11:42:15 localhost [<c01395e5>] sys_init_module+0x15ac/0x16e3
  67. Jan 15 11:42:15 localhost [<c033c767>] _spin_lock+0xd/0x5a
  68. Jan 15 11:42:15 localhost [<c011e651>] printk+0x0/0x1f
  69. Jan 15 11:42:15 localhost [<c0159fa7>] __fput+0x112/0x13c
  70. Jan 15 11:42:15 localhost [<c016ac25>] mntput_no_expire+0x11/0x5c
  71. Jan 15 11:42:15 localhost [<c0104e20>] sysenter_past_esp+0x5d/0x81
  72. Jan 15 11:42:15 localhost =======================
复制代码

这样是会溢出的啊
问题是 TCP_CONNTRACK_MAX 和 TCP_CONNTRACK_IGNORE 会不会被取到呢?我不是太了解

[ 本帖最后由 platinum 于 2008-1-15 12:03 编辑 ]
作者: platinum    时间: 2008-01-15 15:52
知道了,那两种状态根本就不会进入 conntrack->proto.tcp.state,所以不会出现溢出状况
作者: sisi8408    时间: 2008-01-15 20:06
大脚王,赞一个

tcp_conntrack_names[] overflow 与
tcp_options overflow 不一样,

tcp_options overflow in stack, but
tcp_conntrack_names[] overflow in heap,

module 没法卸载

[ 本帖最后由 sisi8408 于 2008-1-15 20:14 编辑 ]
作者: platinum    时间: 2008-01-15 22:39
前两天还在研究 heap 和 stack 之间的关系,今天 sisi8408 大哥这么一说,我更明白了,谢谢你 ^_^
作者: sisi8408    时间: 2008-01-18 21:18

  1. static void add_file(struct super_block *sb, char *name,
  2.         int (*func) (struct seq_file *, struct super_block *))
  3. {
  4.         struct proc_dir_entry *de;

  5.         de = create_proc_entry(name, 0, REISERFS_SB(sb)->procdir);
  6.         if (de) {
  7.                 /*
  8.                  * linux-2.6.23.12/fs/reiserfs
  9.                  * 2008-1-18 21:09
  10.                  * nice play show what is free indeed
  11.                  */
  12.                 de->data = func;
  13.                 de->proc_fops = &r_file_operations;
  14.         }
  15. }

复制代码

作者: sisi8408    时间: 2008-01-18 22:31

  1.                 // make sure, that the node contents look like a node of
  2.                 // certain level
  3.                 if (!is_tree_node(p_s_bh, expected_level)) {
  4.                         reiserfs_warning(p_s_sb, "vs-5150: search_by_key: "
  5.                                          "invalid format found in block %ld. Fsck?",
  6.                                          p_s_bh->b_blocknr);
  7.                         pathrelse(p_s_search_path);
  8.                         /* linux-2.6.23.12
  9.                          * it is not HW err
  10.                          */
  11.                         return IO_ERROR;
  12.                 }

复制代码

作者: sisi8408    时间: 2008-01-19 10:30

  1. struct in_core_key
  2. {
  3.         __u32 k_dir_id;
  4.         __u32 k_objectid;
  5.         __u64 k_offset;
  6.         __u8  k_type;        /* shit and big tail eagle?! */
  7. }; /* shouldbe? __attribute__ ((__packed__)); */
  8. /*linux-2.6.23.12*/
  9. struct cpu_key
  10. {
  11.         struct in_core_key on_disk_key;
  12.         int version;
  13.         int key_length;                /* 3 in all cases but direct2indirect and
  14.                                    indirect2direct conversion */
  15. };

复制代码

作者: sisi8408    时间: 2008-01-30 22:02
potential NULL pointer bug in reiserfs-3.6


  1. static int balance_leaf(struct tree_balance *tb,
  2.                         struct item_head *ih,        /* item header of inserted item (this is on little endian) */
  3.                         const char *body,        /* body  of inserted item or bytes to paste */
  4.                         int flag,        /* i - insert, d - delete, c - cut, p - paste
  5.                                            (see comment to do_balance) */
  6.                         struct item_head *insert_key,        /* in our processing of one level we sometimes determine what
  7.                                                            must be inserted into the next higher level.  This insertion
  8.                                                            consists of a key or two keys and their corresponding
  9.                                                            pointers */
  10.                         struct buffer_head **insert_ptr        /* inserted node-ptrs for the next level */
  11.     )
  12. {
  13.         struct buffer_head *tbS0 = PATH_PLAST_BUFFER(tb->tb_path);
  14.         int item_pos = PATH_LAST_POSITION(tb->tb_path);        /*  index into the array of item headers in S[0]
  15.                                                            of the affected item */
  16.         struct buffer_info bi;
  17.         struct buffer_head *S_new[2];        /* new nodes allocated to hold what could not fit into S */
  18.         int snum[2];                /* number of items that will be placed
  19.                                    into S_new (includes partially shifted
  20.                                    items) */
  21.         int sbytes[2];                /* if an item is partially shifted into S_new then
  22.                                    if it is a directory item
  23.                                    it is the number of entries from the item that are shifted into S_new
  24.                                    else
  25.                                    it is the number of bytes from the item that are shifted into S_new
  26.                                  */
  27.         int n, i;
  28.         int ret_val;
  29.         int pos_in_item;
  30.         int zeros_num;

  31.         PROC_INFO_INC(tb->tb_sb, balance_at[0]);

  32.         /* Make balance in case insert_size[0] < 0 */
  33.         if (tb->insert_size[0] < 0)
  34.                 return balance_leaf_when_delete(tb, flag);

  35.         zeros_num = 0;
  36.         if (flag == M_INSERT && body == 0)
  37.                 /*
  38.                  * 2008-1-30 21:46
  39.                  * linux-2.6.23.12
  40.                  * @@@@@@@@@@@@@@@@@@@@@@@@@@@@
  41.                  * potential ih NULL pointer  @
  42.                  * @@@@@@@@@@@@@@@@@@@@@@@@@@@@
  43.                  */
  44.                 zeros_num = ih_item_len(ih);

  45.         pos_in_item = tb->tb_path->pos_in_item;
  46.         /* for indirect item pos_in_item is measured in unformatted node
  47.            pointers. Recalculate to bytes */
  48.         if (flag != M_INSERT
  49.             && is_indirect_le_ih(B_N_PITEM_HEAD(tbS0, item_pos)))
  50.                 pos_in_item *= UNFM_P_SIZE;
  51. [...]
  52. }

  53. int reiserfs_paste_into_item(struct reiserfs_transaction_handle *th,
  54.                              struct treepath *p_s_search_path,        /* Path to the pasted item */
  55.                              const struct cpu_key *p_s_key,        /* Key to search for the needed item */
  56.                              struct inode *inode,        /* Inode that item belongs to */
  57.                              const char *p_c_body,        /* Pointer to the bytes to paste */
  58.                              int n_pasted_size) /* Size of pasted bytes */
  59. {
  60. [...]
  61.         /* Perform balancing after all resources are collected by fix_nodes, and
  62.          * accessing them will not risk triggering schedule.
  63.          */
  64.         if (retval == CARRY_ON) {
  65.                 /*
  66.                  * source-01
  67.                  */
  68.                 do_balance(&s_paste_balance, NULL, /*ih*/ p_c_body, M_PASTE);
  69.                 return 0;
  70.         }
  71.         retval = (retval == NO_DISK_SPACE) ? -ENOSPC : -EIO;
  72. [...]
  73. }

  74. void do_balance(struct tree_balance *tb,        /* tree_balance structure */
  75.                 struct item_head *ih,        /* item header of inserted item */
  76.                 const char *body,        /* body  of inserted item or bytes to paste */
  77.                 int flag)
  78.                                 /* i - insert, d - delete
  79.                                    c - cut, p - paste

  80.                                    Cut means delete part of an item
  81.                                    (includes removing an entry from a directory).

  82.                                    Delete means delete whole item.

  83.                                    Insert means add a new item into the tree.

  84.                                    Paste means to append to the end of an
  85.                                          existing file or to insert a directory entry.
  86.                                 */
  87. {
  88. [...]
  89.         do_balance_starts(tb);
  90.         /* balance leaf returns 0 except
  91.          * if combining L R and S into one node.
  92.          *
  93.          * see balance_internal() for explanation of this line of code.
  94.          */
  95.         child_pos = PATH_H_B_ITEM_ORDER(tb->tb_path, 0) +
  96.                 /*
  97.                  * source-02
  98.                  */
  99.                 balance_leaf(tb, ih, body, flag, insert_key, insert_ptr);
  100. [...]
  101. }

复制代码

作者: daemeon    时间: 2008-02-03 00:40
标题: 回复 #88 sisi8408 的帖子
It's not a bug since the marked codes are executed only when flag == M_INSERT.
作者: zx_wing    时间: 2008-02-03 17:03
很有意思的帖子,以前还从没看过。
至今为止我只在e100的驱动中发现过一个中断处理的bug。老大让把patch发出去,结果俺到现在还没发。
很想看一下这个帖子,可惜大部分代码都不熟悉,光看片段代码很难知道是不是BUG,必须结合相关子系统上下文一起看。
像大家学习了,关注中
作者: sisi8408    时间: 2008-02-09 12:58

  1. static void internal_copy_pointers_items(struct buffer_info *dest_bi,
  2.                                          struct buffer_head *src,
  3.                                          int last_first, int cpy_num)
  4. {
  5.         /* ATTENTION! Number of node pointers in DEST is equal to number of items in DEST,
  6.          * as delimiting key have already inserted to buffer dest.
  7.          */
  8.         struct buffer_head *dest = dest_bi->bi_bh;
  9.         int nr_dest, nr_src;
  10.         int dest_order, src_order;
  11.         struct block_head *blkh;
  12.         struct reiserfs_key *key;
  13.         struct disk_child *dc;

  14.         nr_src = B_NR_ITEMS(src);

  15.         RFALSE(dest == NULL || src == NULL,
  16.                "src (%p) or dest (%p) buffer is 0", src, dest);
  17.         /*
  18.         2008-2-9 12:54
  19.         linux-2.6.23.12
  20.        
  21.         RFALSE(dest == NULL || src == NULL,
  22.                "src (%p) or dest (%p) buffer is 0", src, dest);
  23.         nr_src = B_NR_ITEMS(src);
  24.         */
  25. [...]
  26. }

复制代码

作者: sisi8408    时间: 2008-02-12 17:27

  1. simple ops in Stree

  2. Unlike ext2, reiserfs is a modner FS and has attrs:
  3. 1, logging
  4. 2, extent inode attr
  5. 3, acl, posix or not
  6. 4, Stree, derived from Btree

  7. Like Btree, Stree consists of nodes and manages nodes,
  8. which only contains meta info. there are two kinds of nodes
  9. in Stree: interal and leaf, and for simplicity the internal
  10. is called node here, following the Btree def.

  11. By def in Stree, node, mapped to phyiscal block(block on disk) by BLKH,
  12. is just a array of KEY+DC(block pointer or disk child), though the format
  13. of the array is funny, and Mr HR, i guess, favorates block ops in crazy manner,
  14. which can be understood since the block_sz can be changed acoording to ur taste.

  15. Unlike node, leaf is used to store four types of items,
  16. 1, sd, stat data, or inode, the hot element of FS
  17. 2, de, dir entry, also hot
  18. 3, direct
  19. 4, indirect
  20. compared withext2, nothing is new but the way to manage them.

  21. Lets see a rather simple example on linux cmdline

  22. # echo a >> /mnt_HS/Stree/simple
  23. # echo $?
  24. 0

  25. /*
  26. * As in the whitepaper by Mr. HR, it is not simple to show Stree chart though
  27. * charmimg like Nina Reiser, here i do what i can.
  28. */

  29. and the corresponding image in Stree is

  30.         | BLKH[h+2] | P0 | ... | P[h+2] | ... | free space |

  31. where BLKH[h+2] represents the block of block_sz bytes pointed to by root node,
  32. i gas, and P[h+2] to dir `Stree',

  33.         | BLKH[h+1] | P0 | ... | PL[h+1] | P[h+1] | PR[h+1] | ... | free space |

  34. where P[h+1] to regular file `simple' or S in HR's dictionary,
  35. simlarly PL[h+1] to L, and PR[h+1] to R, finally and obviuosly h = 0,
  36. in this simple case.

  37.         | BLKH[h] | IH-0 | IH-1 | free space | I-1 | I-0 |

  38. where IH for Item Header, and IH-0 is of type `sd',
  39. I-0 is the socalled inode of `simple',
  40. IH-1, i gas, is of type `direct', and its body I-1 is just `a'.

  41. After another operation on `simple'

  42. # echo b >> /mnt_HS/Stree/simple

  43. i gas, the only chg in Stree is IH-1 and its body from `a' to `ab',
  44. lets check what HR did in v-3.6 of linux-2.6.23.12,

  45. /* first, ==========================
  46.    ip means Inserting or Pasting
  47. */
  48. static int ip_check_balance(struct tree_balance *tb, int h)
  49. {
  50. [...]
  51.         if (can_node_be_removed(vn->vn_mode, lfree, sfree, rfree, tb, h)
  52.             == NO_BALANCING_NEEDED)
  53.                 /* new item fits into node S[h] without any shifting */
  54.                 return NO_BALANCING_NEEDED;
  55. [...]
  56. }

  57. /* second, ==========================
  58. */
  59. static inline int can_node_be_removed(int mode, int lfree, int sfree, int rfree,
  60.                                       struct tree_balance *tb, int h)
  61. {
  62.         struct buffer_head *Sh = PATH_H_PBUFFER(tb->tb_path, h);
  63.         int levbytes = tb->insert_size[h];

  64.         struct item_head *ih;
  65.         struct reiserfs_key *r_key = NULL;

  66.         ih = B_N_PITEM_HEAD(Sh, 0);

  67.         if (tb->CFR[h])
  68.                 r_key = B_N_PDELIM_KEY(tb->CFR[h], tb->rkey[h]);
  69.         /*
  70.          * nicer to understand as:
  71.          * lfree + rfree < MAX_CHILD_SIZE(Sh) - sfree + levbytes
  72.          */
  73.         if (lfree + rfree + sfree < MAX_CHILD_SIZE(Sh) + levbytes
  74.             /* shifting may merge items which might save space */
  75.             - ((!h && op_is_left_mergeable(&ih->ih_key, Sh->b_size)) ? IH_SIZE : 0)
  76.             - ((!h && r_key && op_is_left_mergeable(r_key, Sh->b_size)) ? IH_SIZE : 0)
  77.             + (h ? KEY_SIZE : 0))
  78.         { /* node can not be removed */
  79.                 if (sfree >= levbytes) {
  80.                         /* new item fits into node S[h] without any shifting */
  81.                         if (!h)
  82.                                 tb->s0num = B_NR_ITEMS(Sh) + ((mode == M_INSERT) ? 1 : 0);
  83.                        
  84.                         set_parameters(tb, h, 0, 0, 1, NULL, -1, -1);
  85.                         return NO_BALANCING_NEEDED;
  86.                 }
  87.         }
  88.         PROC_INFO_INC(tb->tb_sb, can_node_be_removed[h]);
  89.         return !NO_BALANCING_NEEDED;
  90. }

  91. Oh Jesus, HR favorates shift much more, and i gas once more,
  92. meta data and balance are concerned by HR much more than file data?

  93. As u see, the code for the two ops, fix_node and do_balance, upon Stree is
  94. hard and harder to read, and i dream dig it no more harder
  95. in v-3.7 in the original track, and U r welcome to my dream.

复制代码

[ 本帖最后由 sisi8408 于 2008-2-12 17:29 编辑 ]
作者: sisi8408    时间: 2008-02-13 20:15

  1. static void create_virtual_node(struct tree_balance *tb, int h)
  2. {
  3.         struct item_head *ih;
  4.         struct virtual_node *vn = tb->tb_vn;
  5.         int new_num;
  6.         struct buffer_head *Sh = PATH_H_PBUFFER(tb->tb_path, h);

  7.         if (!h) {
  8.                 create_virtual_leaf(tb, h);
  9.                 return;
  10.         }
  11.         /* size of v node */
  12.         vn->vn_size = MAX_CHILD_SIZE(Sh) - B_FREE_SPACE(Sh)
  13.                         + tb->insert_size[h];
  14.         vn->vn_nr_item = (vn->vn_size - DC_SIZE) / (DC_SIZE + KEY_SIZE);
  15. }

  16. static void create_virtual_leaf(struct tree_balance *tb, int h)
  17. {
  18.         struct item_head *ih;
  19.         struct virtual_node *vn = tb->tb_vn;
  20.         int new_num;
  21.         struct buffer_head *Sh = PATH_H_PBUFFER(tb->tb_path, h);
  22.        
  23.         vn->vn_size = MAX_CHILD_SIZE(Sh) - B_FREE_SPACE(Sh) + tb->insert_size[h];
  24.        
  25.         /* number of items in v node  */
  26.         vn->vn_nr_item = B_NR_ITEMS(Sh) +
  27.                          ((vn->vn_mode == M_INSERT) ? 1 : 0) -
  28.                              ((vn->vn_mode == M_DELETE) ? 1 : 0);

  29.         /* first v item */
  30.         vn->vn_vi = (struct virtual_item *)(tb->tb_vn + 1);
  31.        
  32.         memset(vn->vn_vi, 0, vn->vn_nr_item * sizeof(struct virtual_item));
  33.        
  34.         vn->vn_free_ptr += vn->vn_nr_item * sizeof(struct virtual_item);
  35.         /*
  36.          * first item in S[h]
  37.          */
  38.         ih = B_N_PITEM_HEAD(Sh, 0);
  39.         /*
  40.          * define the mergeability for 0-th item,
  41.          * if it is not being deleted
  42.          */
  43.         if (op_is_left_mergeable(&ih->ih_key, Sh->b_size)
  44.             && (vn->vn_mode != M_DELETE || vn->vn_affected_item_num))
  45.                 vn->vn_vi[0].vi_type |= VI_TYPE_LEFT_MERGEABLE;

  46.         /*
  47.          * go through all items those remain in the virtual node,
  48.          * except for the new (inserted) one
  49.          */
  50.         for (new_num = 0; new_num < vn->vn_nr_item; new_num++) {
  51.                 int j;
  52.                 struct virtual_item *vi = vn->vn_vi + new_num;
  53.                 int is_affected = new_num == vn->vn_affected_item_num;

  54.                 if (is_affected && vn->vn_mode == M_INSERT)
  55.                         continue;

  56.                 /* get item number in source node */
  57.                 j = old_item_num(new_num, vn->vn_affected_item_num, vn->vn_mode);
  58.                 /*
  59.                  * vi->vi_item_len += ih_item_len(ih + j) + IH_SIZE;
  60.                  *
  61.                  * and its still amazing why IH_SIZE counted even if !is_affected.
  62.                                  *
  63.                                  * Jesus, its used, at least, by check_left/right

  64.         for (i = 0; i < vn->vn_nr_item;
  65.              i++, ih_size = IH_SIZE, d_size = 0, vi++) {
  66.                 d_size += vi->vi_item_len;

  67.         for (i = vn->vn_nr_item - 1; i >= 0;
  68.              i--, d_size = 0, ih_size = IH_SIZE, vi--) {
  69.                 d_size += vi->vi_item_len;
  70.                                  *
  71.                                  */
  72.                 vi->vi_item_len = ih_item_len(ih + j) + IH_SIZE;
  73.                 vi->vi_ih   = ih + j;
  74.                 vi->vi_item = B_I_PITEM(Sh, ih + j);
  75.                 vi->vi_uarea = vn->vn_free_ptr;
  76.                 /*
  77.                  * FIXME: there is no check, that item operation did not
  78.                  * consume too much memory
  79.                  */
  80.                 vn->vn_free_ptr +=
  81.                         op_create_vi(vn, vi, is_affected, tb->insert_size[0]);

  82.                 if (tb->vn_buf + tb->vn_buf_size < vn->vn_free_ptr)
  83.                         reiserfs_panic(tb->tb_sb,
  84.                                        "vs-8030: create_virtual_node: "
  85.                                        "virtual node space consumed");
  86.                
  87.                 if (!is_affected) /* this item is not being changed */
  88.                         continue;

  89.                 if (vn->vn_mode == M_PASTE || vn->vn_mode == M_CUT) {
  90.                         /*vn->vn_vi[new_num].vi_item_len += tb->insert_size[0]; */
  91.                         vi->vi_item_len += tb->insert_size[0];
  92.                         vi->vi_new_data = vn->vn_data;
  93.                 }
  94.         }

  95.         /* virtual inserted item is not defined yet */
  96.         if (vn->vn_mode == M_INSERT) {
  97.                 struct virtual_item *vi = vn->vn_vi + vn->vn_affected_item_num;

  98.                 RFALSE(vn->vn_ins_ih == 0,
  99.                        "vs-8040: item header of inserted item is not specified");

  100.                 vi->vi_item_len = tb->insert_size[0];
  101.                 vi->vi_ih = vn->vn_ins_ih;
  102.                 vi->vi_item = vn->vn_data;
  103.                 vi->vi_uarea = vn->vn_free_ptr;

  104.                 op_create_vi(vn, vi, 0 /*not pasted or cut */ ,
  105.                              tb->insert_size[0]);
  106.         }

  107.         /* set right merge flag we take right delimiting key and
  108.          * check whether it is a mergeable item
  109.          */
  110.         if (tb->CFR[0]) {
  111.                 struct reiserfs_key *key;

  112.                 key = B_N_PDELIM_KEY(tb->CFR[0], tb->rkey[0]);

  113.                 if (op_is_left_mergeable(key, Sh->b_size) &&
  114.                     (vn->vn_mode != M_DELETE ||
  115.                      vn->vn_affected_item_num != B_NR_ITEMS(Sh) - 1))
  116.                         vn->vn_vi[vn->vn_nr_item - 1].vi_type |= VI_TYPE_RIGHT_MERGEABLE;

  117. #ifdef CONFIG_REISERFS_CHECK
  118.                 if (op_is_left_mergeable(key, Sh->b_size) &&
  119.                     !(vn->vn_mode != M_DELETE
  120.                       || vn->vn_affected_item_num != B_NR_ITEMS(Sh) - 1)) {
  121.                         /* we delete last item and
  122.                          * it could be merged with right neighbor's first item
  123.                          */
  124.                         if (!
  125.                             (B_NR_ITEMS(Sh) == 1
  126.                              && is_direntry_le_ih(B_N_PITEM_HEAD(Sh, 0))
  127.                              && I_ENTRY_COUNT(B_N_PITEM_HEAD(Sh, 0)) == 1)) {
  128.                                 /* node contains more than 1 item, or item is not directory item, or this item contains more than 1 entry */
  129.                                 print_block(Sh, 0, -1, -1);
  130.                                 reiserfs_panic(tb->tb_sb,
  131.                                                "vs-8045: create_virtual_node: rdkey %k, affected item==%d (mode==%c) Must be %c",
  132.                                                key, vn->vn_affected_item_num,
  133.                                                vn->vn_mode, M_DELETE);
  134.                         }
  135.                 }
  136. #endif
  137.         }
  138. }
复制代码

[ 本帖最后由 sisi8408 于 2008-2-13 20:45 编辑 ]
作者: daemeon    时间: 2008-02-15 03:44
linux-2.6.24/fs/dcache.c

static void switch_names(struct dentry *dentry, struct dentry *target)
{
        if (dname_external(target)) {
                if (dname_external(dentry)) {
                        /*
                         * Both external: swap the pointers
                         */
                        do_switch(target->d_name.name, dentry->d_name.name);
                } else {
                        /*
                         * dentry:internal, target:external.  Steal target's
                         * storage and make target internal.
                         */
                        memcpy(target->d_iname, dentry->d_name.name,
                                        dentry->d_name.len + 1);
                        dentry->d_name.name = target->d_name.name;
                        target->d_name.name = target->d_iname;
                }
        } else {
                if (dname_external(dentry)) {
                        /*
                         * dentry:external, target:internal.  Give dentry's
                         * storage to target and make dentry internal
                         */
                        memcpy(dentry->d_iname, target->d_name.name,
                                        target->d_name.len + 1);
                        target->d_name.name = dentry->d_name.name;
                        dentry->d_name.name = dentry->d_iname;
                } else {
                        /*
                         * Both are internal.  Just copy target to dentry
                         */
                        memcpy(dentry->d_iname, target->d_name.name,
                                        target->d_name.len + 1);

                }
        }
}

作者: sisi8408    时间: 2008-02-16 14:54
标题: 回复 #94 daemeon 的帖子
itis only u, at least uptonow, play cool game like this,
and it sounds cooler if u show ur nice comment.
作者: sisi8408    时间: 2008-02-16 14:56

  1. static void balance_leaf_do_split(struct tree_balance *tb,
  2.                                    struct item_head *ih,
  3.                                    const char *body,
  4.                                    int flag,
  5.                                    struct item_head *insert_key,
  6.                                    struct buffer_head **insert_ptr)
  7. {
  8.         struct buffer_head *tbS0 = PATH_PLAST_BUFFER(tb->tb_path);
  9.         /* index of the affected item */
  10.         int item_pos = PATH_LAST_POSITION(tb->tb_path);

  11.         struct buffer_info bi;

  12.         int n, i, ret_val;
  13.         int pos_in_item;
  14.         int zeros_num;

  15.         struct buffer_head *S_new[2];
  16.         int snum[2];
  17.         int sbytes[2];
  18.        
  19.         if (!tb->blknum[0])
  20.                 return;

  21.         if (!(flag == M_INSERT || flag == M_PASTE) {
  22.                 reiserfs_panic(tb->tb_sb,
  23.                         "PAP-12245: balance_leaf: blknum > 2: unexpectable mode: %s(%d)",
  24.                         (flag == M_DELETE) ? "DELETE" :
  25.                         ((flag == M_CUT) ? "CUT" : "UNKNOWN"), flag);
  26.                 return;
  27.         }
  28.        
  29.         RFALSE(tb->blknum[0] < 1 || tb->blknum[0] > 3,
  30.                 "PAP-12180: blknum can not be %d. It must be in range [1,3]",
  31.                 tb->blknum[0]);

  32.         /* Fill new nodes that appear in place of S[0] */
  33.         snum[0] = tb->s1num;
  34.         snum[1] = tb->s2num;
  35.         sbytes[0] = tb->s1bytes;
  36.         sbytes[1] = tb->s2bytes;

  37.         for (i = tb->blknum[0] - 2; i >= 0; i--) {
  38.                 RFALSE(!snum[i], "PAP-12200: snum[%d] == %d. Must be > 0", i, snum[i]);
  39.                 /* here we shift from S to S_new nodes */
  40.                 S_new[i] = get_FEB(tb);
  41.                 /* initialized block type and tree level */
  42.                 set_blkh_level(B_BLK_HEAD(S_new[i]), DISK_LEAF_NODE_LEVEL);

  43.                 n = B_NR_ITEMS(tbS0);
  44.                
  45.                 if (flag == M_INSERT) {
  46.                         if (!(n - snum[i] < item_pos)) {
  47.                                 /* new item or it part don't falls into S_new[i] */
  48.                                 leaf_move_items(LEAF_FROM_S_TO_SNEW, tb,
  49.                                                 snum[i], sbytes[i], S_new[i]);
  50.                                 goto next;
  51.                         }
  52.                         goto long_tail_insert;
  53.                 } else {
  54.                         if (!(n - snum[i] <= item_pos)) {
  55.                                 /* pasted item doesn't fall into S_new[i] */
  56.                                 leaf_move_items(LEAF_FROM_S_TO_SNEW, tb,
  57.                                                 snum[i], sbytes[i], S_new[i]);
  58.                                 goto next;
  59.                         }
  60.                         goto long_tail_paste;
  61.                 }

  62.         long_tail_insert:
  63.                 if (item_pos == n - snum[i] + 1 && sbytes[i] != -1) {
  64.                         /* part of new item falls into S_new[i] */
  65.                         int old_key_comp, old_len, r_zeros_number;
  66.                         const char *r_body;
  67.                         int version;
  68.                        
  69.                         /* Move snum[i]-1 items from S[0] to S_new[i] */
  70.                         leaf_move_items(LEAF_FROM_S_TO_SNEW, tb,
  71.                                         snum[i] -1, -1, S_new[i]);
  72.                         /* Remember key component and item length */
  73.                         version = ih_version(ih);
  74.                         old_key_comp = le_ih_k_offset(ih);
  75.                         old_len = ih_item_len(ih);
  76.                        
  77.                         /*Calculate key component and item length to insert into S_new[i] */
  78.                         set_le_ih_k_offset(ih,
  79.                             le_ih_k_offset(ih) +
  80.                                ((old_len - sbytes[i]) << (is_indirect_le_ih(ih) ?
  81.                                                                  tb->tb_sb->s_blocksize_bits - UNFM_P_SHIFT : 0)));
  82.                         put_ih_item_len(ih, sbytes[i]);
  83.                         /* Insert part of the item into S_new[i] before 0-th item */
  84.                         bi.tb = tb;
  85.                         bi.bi_bh = S_new[i];
  86.                         bi.bi_parent = NULL;
  87.                         bi.bi_position = 0;
  88.                        
  89.                         if ((old_len - sbytes[i]) > zeros_num) {
  90.                                 r_zeros_number = 0;
  91.                                 r_body = body + (old_len - sbytes[i]) - zeros_num;
  92.                         } else {
  93.                                 r_body = body;
  94.                                 r_zeros_number = zeros_num - (old_len - sbytes[i]);
  95.                                 zeros_num -= r_zeros_number;
  96.                         }
  97.                         leaf_insert_into_buf(&bi, 0, ih, r_body, r_zeros_number);
  98.                        
  99.                         /* Calculate key component and item length to insert into S[i] */
  100.                         set_le_ih_k_offset(ih, old_key_comp);
  101.                         put_ih_item_len(ih, old_len - sbytes[i]);
  102.                         tb->insert_size[0] -= sbytes[i];
  103.                
  104.                 } else { /* whole new item falls into S_new[i] */
  105.                         /* Shift snum[0] - 1 items to S_new[i] (sbytes[i] of split item) */
  106.                         leaf_move_items(LEAF_FROM_S_TO_SNEW, tb,
  107.                                         snum[i] -1, sbytes[i], S_new[i]);
  108.                         /* Insert new item into S_new[i] */
  109.                         bi.tb = tb;
  110.                         bi.bi_bh = S_new[i];
  111.                         bi.bi_parent = NULL;
  112.                         bi.bi_position = 0;
  113.                        
  114.                         leaf_insert_into_buf(&bi, item_pos - n + snum[i] - 1,
  115.                                                 ih, body, zeros_num);
  116.                         zeros_num = tb->insert_size[0] = 0;
  117.                 }
  118.                 goto next;
  119.        
  120.         long_tail_paste:
  121.                 if (item_pos == n - snum[i] && sbytes[i] != -1) {
  122.                         /* we must shift part of the appended item */
  123.                         struct item_head *aux_ih;
  124.                        
  125.                         RFALSE(ih, "PAP-12210: ih must be 0");
  126.                        
  127.                         aux_ih = B_N_PITEM_HEAD(tbS0, item_pos);
  128.                         if (is_direntry_le_ih(aux_ih)) {
  129.                                 /* we append to directory item */
  130.                                 int entry_count = ih_entry_count(aux_ih);
  131.                                
  132.                                 if (entry_count - sbytes[i] < pos_in_item
  133.                                     && pos_in_item <= entry_count) {
  134.                                         /* new directory entry falls into S_new[i] */
  135.                                         RFALSE(!tb->insert_size[0],
  136.                                                "PAP-12215: insert_size is already 0");
  137.                                         RFALSE(sbytes[i] - 1 >= entry_count,
  138.                                                "PAP-12220: there are no so much entries (%d), only %d",
  139.                                                sbytes[i] - 1, entry_count);
  140.                                        
  141.                                         /* Shift snum[i]-1 items in whole. Shift sbytes[i] directory entries from directory item number snum[i] */
  142.                                         leaf_move_items(LEAF_FROM_S_TO_SNEW, tb, snum[i],
  143.                                                              sbytes[i] - 1, S_new[i]);
  144.                                         /* Paste given directory entry to directory item */
  145.                                         bi.tb = tb;
  146.                                         bi.bi_bh = S_new[i];
  147.                                         bi.bi_parent = NULL;
  148.                                         bi.bi_position = 0;
  149.                                        
  150.                                         leaf_paste_in_buffer(&bi, 0,
  151.                                                 pos_in_item - entry_count + sbytes[i] - 1,
  152.                                                 tb->insert_size[0], body, zeros_num);
  153.                                        
  154.                                         /* paste new directory entry */
  155.                                         leaf_paste_entries(bi.bi_bh, 0,
  156.                                                 pos_in_item - entry_count + sbytes[i] - 1,
  157.                                                 1,
  158.                                                 (struct reiserfs_de_head *) body,
  159.                                                 body + DEH_SIZE, tb->insert_size[0]);
  160.                                        
  161.                                         tb->insert_size[0] = 0;
  162.                                         pos_in_item++;
  163.                                 } else {
  164.                                         /* new directory entry doesn't fall into S_new[i] */
  165.                                         leaf_move_items(LEAF_FROM_S_TO_SNEW, tb,
  166.                                                 snum[i], sbytes[i], S_new[i]);
  167.                                 }
  168.                         } else { /* regular object */
  169.                                 int n_shift, n_rem, r_zeros_number;
  170.                                 const char *r_body;
  171.                                
  172.                                 RFALSE(pos_in_item != ih_item_len(B_N_PITEM_HEAD(tbS0, item_pos))
  173.                                        || tb->insert_size[0] <= 0,
  174.                                        "PAP-12225: item too short or insert_size <= 0");
  175.                                 /* Calculate number of bytes which must be
  176.                                  * shifted from appended item */
  177.                                 n_shift = sbytes[i] - tb->insert_size[0];
  178.                                 if (n_shift < 0)
  179.                                         n_shift = 0;
  180.                                
  181.                                 leaf_move_items(LEAF_FROM_S_TO_SNEW, tb,
  182.                                                 snum[i], n_shift, S_new[i]);
  183.                                
  184.                                 /* Calculate number of bytes which must remain
  185.                                  * in body after append to S_new[i] */
  186.                                 n_rem = tb->insert_size[0] - sbytes[i];
  187.                                 if (n_rem < 0)
  188.                                         n_rem = 0;
  189.                                 /* Append part of body into S_new[0] */
  190.                                 bi.tb = tb;
  191.                                 bi.bi_bh = S_new[i];
  192.                                 bi.bi_parent = NULL;
  193.                                 bi.bi_position = 0;
  194.                                
  195.                                 if (n_rem > zeros_num) {
  196.                                         r_zeros_number = 0;
  197.                                         r_body = body + n_rem - zeros_num;
  198.                                 } else {
  199.                                         r_body = body;
  200.                                         r_zeros_number = zeros_num - n_rem;
  201.                                         zeros_num -= r_zeros_number;
  202.                                 }
  203.                                 leaf_paste_in_buffer(&bi, 0, n_shift,
  204.                                                      tb->insert_size[0] - n_rem,
  205.                                                      r_body, r_zeros_number);
  206.                                 {
  207.                                         /* 2008-2-16 14:19
  208.                                          * itis not easy to format,
  209.                                          * needless to say to debug HR.
  210.                                          */
  211.                                         struct item_head *tmp;
  212.                                        
  213.                                         tmp = B_N_PITEM_HEAD(S_new[i], 0);
  214.                                         if (is_indirect_le_ih(tmp)) {
  215.                                                 set_ih_free_space(tmp, 0);
  216.                                                
  217.                                                 set_le_ih_k_offset(tmp,
  218.                                                     le_ih_k_offset(tmp) +
  219.                                                         (n_rem << (tb->tb_sb->s_blocksize_bits - UNFM_P_SHIFT)));
  220.                                         } else {
  221.                                                 set_le_ih_k_offset(tmp,
  222.                                                     le_ih_k_offset(tmp) + n_rem);
  223.                                         }
  224.                                 }
  225.                                 tb->insert_size[0] = n_rem;
  226.                                 if (!n_rem)
  227.                                         pos_in_item++;
  228.                         }
  229.                 } else { /* item falls wholly into S_new[i] */
  230.                         int ret_val;
  231.                         struct item_head *pasted;
  232. #ifdef CONFIG_REISERFS_CHECK
  233.                         struct item_head *ih = B_N_PITEM_HEAD(tbS0, item_pos);
  234.                        
  235.                         if (!is_direntry_le_ih(ih) &&
  236.                             (pos_in_item != ih_item_len(ih)
  237.                              || tb->insert_size[0] <= 0))
  238.                                 reiserfs_panic(tb->tb_sb,
  239.                                                "PAP-12235: balance_leaf: pos_in_item must be equal to ih_item_len");
  240. #endif        /* CONFIG_REISERFS_CHECK */
  241.                         ret_val = leaf_move_items(LEAF_FROM_S_TO_SNEW, tb,
  242.                                                  snum[i], sbytes[i], S_new[i]);
  243.                         RFALSE(ret_val,
  244.                                "PAP-12240: unexpected value returned by leaf_move_items (%d)",
  245.                                ret_val);
  246.                         /* paste into item */
  247.                         bi.tb = tb;
  248.                         bi.bi_bh = S_new[i];
  249.                         bi.bi_parent = NULL;
  250.                         bi.bi_position = 0;
  251.                        
  252.                         leaf_paste_in_buffer(&bi, item_pos - n + snum[i],
  253.                                              pos_in_item,
  254.                                              tb->insert_size[0],
  255.                                              body, zeros_num);
  256.                        
  257.                         pasted = B_N_PITEM_HEAD(S_new[i], item_pos - n + snum[i]);
  258.                         if (is_direntry_le_ih(pasted))
  259.                                 leaf_paste_entries(bi.bi_bh,
  260.                                                    item_pos - n + snum[i],
  261.                                                    pos_in_item, 1,
  262.                                                    (struct reiserfs_de_head *)body,
  263.                                                    body + DEH_SIZE,
  264.                                                    tb->insert_size[0]);
  265.                         /* if we paste to indirect item update ih_free_space */
  266.                         if (is_indirect_le_ih(pasted))
  267.                                 set_ih_free_space(pasted, 0);
  268.                         zeros_num = tb->insert_size[0] = 0;
  269.                 }
  270.                 goto next;
  271.        
  272.         next:
  273.                 memcpy(insert_key + i, B_N_PKEY(S_new[i], 0), KEY_SIZE);
  274.                 insert_ptr[i] = S_new[i];

  275.                 RFALSE(!buffer_journaled(S_new[i])
  276.                        || buffer_journal_dirty(S_new[i])
  277.                        || buffer_dirty(S_new[i]),
  278.                        "PAP-12247: S_new[%d] : (%b)", i, S_new[i]);
  279.         } /* for loop */
  280. }
复制代码

作者: sisi8408    时间: 2008-02-16 14:57

  1. static void balance_leaf_shift_right(struct tree_balance *tb,
  2.                                    struct item_head *ih,
  3.                                    const char *body,
  4.                                    int flag,
  5.                                    struct item_head *insert_key,
  6.                                    struct buffer_head **insert_ptr)
  7. {
  8.         struct buffer_head *tbS0 = PATH_PLAST_BUFFER(tb->tb_path);
  9.         /* index of the affected item */
  10.         int item_pos = PATH_LAST_POSITION(tb->tb_path);
  11.        
  12.         struct buffer_info bi;

  13.         int n, ret_val;
  14.         int pos_in_item;
  15.         int zeros_num;
  16.        
  17.         if (!(tb->rnum[0] > 0)) /* right shift not needed */
  18.                 return;
  19.        
  20.         zeros_num = 0;
  21.         if (flag == M_INSERT && body == 0)
  22.                 zeros_num = ih_item_len(ih);

  23.         pos_in_item = tb->tb_path->pos_in_item;
  24.         /* for indirect item pos_in_item is measured in unformatted node
  25.          * pointers. Recalculate to bytes
  26.          */
  27.         if (flag != M_INSERT &&
  28.             is_indirect_le_ih(B_N_PITEM_HEAD(tbS0, item_pos)))
  29.                 pos_in_item *= UNFM_P_SIZE;

  30.         n = B_NR_ITEMS(tbS0);
  31.        
  32.         if (flag == M_INSERT) {
  33.                 if (!(n - tb->rnum[0] < item_pos)) {
  34.                         /* new item or part of it doesn't fall into R[0] */
  35.                         leaf_shift_right(tb, tb->rnum[0], tb->rbytes);
  36.                         return;
  37.                 }
  38.                 if (!(item_pos == n - tb->rnum[0] + 1 && tb->rbytes != -1)) {
  39.                         /* whole new item falls into R[0] */

  40.                         /* Shift rnum[0]-1 items to R[0] */
  41.                         ret_val = leaf_shift_right(tb, tb->rnum[0] -1, tb->rbytes);
  42.                        
  43.                         /* Insert new item into R[0] */
  44.                         bi.tb = tb;
  45.                         bi.bi_bh = tb->R[0];
  46.                         bi.bi_parent = tb->FR[0];
  47.                         bi.bi_position = get_right_neighbor_position(tb, 0);
  48.                        
  49.                         leaf_insert_into_buf(&bi, item_pos - n + tb->rnum[0] - 1,
  50.                                              ih, body, zeros_num);
  51.                         if (item_pos - n + tb->rnum[0] - 1 == 0) {
  52.                                 replace_key(tb, tb->CFR[0], tb->rkey[0],
  53.                                             tb->R[0], 0);
  54.                         }
  55.                         zeros_num = tb->insert_size[0] = 0;
  56.                 } else {
  57.                         loff_t old_key_comp, old_len, r_zeros_number;
  58.                         const char *r_body;
  59.                         int version;
  60.                         loff_t offset;
  61.                        
  62.                         leaf_shift_right(tb, tb->rnum[0] -1, -1);
  63.                        
  64.                         version = ih_version(ih);
  65.                         /* Remember key component and item length */
  66.                         old_key_comp = le_ih_k_offset(ih);
  67.                         old_len = ih_item_len(ih);
  68.                        
  69.                         /* Calculate key component and item length to insert into R[0] */
  70.                         offset = le_ih_k_offset(ih) +
  71.                                  ((old_len - tb->rbytes) << (is_indirect_le_ih(ih) ?
  72.                                   tb->tb_sb-> s_blocksize_bits - UNFM_P_SHIFT : 0));
  73.                         set_le_ih_k_offset(ih, offset);
  74.                         put_ih_item_len(ih, tb->rbytes);
  75.                        
  76.                         /* Insert part of the item into R[0] */
  77.                         bi.tb = tb;
  78.                         bi.bi_bh = tb->R[0];
  79.                         bi.bi_parent = tb->FR[0];
  80.                         bi.bi_position = get_right_neighbor_position(tb, 0);
  81.                        
  82.                         if ((old_len - tb->rbytes) > zeros_num) {
  83.                                 r_zeros_number = 0;
  84.                                 r_body = body + (old_len - tb->rbytes) - zeros_num;
  85.                         } else {
  86.                                 r_body = body;
  87.                                 r_zeros_number = zeros_num - (old_len - tb->rbytes);
  88.                                 zeros_num -= r_zeros_number;
  89.                         }
  90.                         leaf_insert_into_buf(&bi, 0, ih, r_body, r_zeros_number);
  91.                        
  92.                         /* Replace right delimiting key by first key in R[0] */
  93.                         replace_key(tb, tb->CFR[0], tb->rkey[0], tb->R[0], 0);
  94.                        
  95.                         /* Calculate key component and item length to insert into S[0] */
  96.                         set_le_ih_k_offset(ih, old_key_comp);
  97.                         put_ih_item_len(ih, old_len - tb->rbytes);
  98.                        
  99.                         tb->insert_size[0] -= tb->rbytes;
  100.                 }
  101.         }
  102.         else if (flag == M_PASTE) {
  103.                 if (!(n - tb->rnum[0] <= item_pos)) {
  104.                         /* new item doesn't fall into R[0] */
  105.                         leaf_shift_right(tb, tb->rnum[0], tb->rbytes);
  106.                 }
  107.                 else if (!(item_pos == n - tb->rnum[0] && tb->rbytes != -1)) {
  108.                         /* pasted item in whole falls into R[0] */
  109.                         struct item_head *pasted;
  110.                        
  111.                         ret_val = leaf_shift_right(tb, tb->rnum[0], tb->rbytes);
  112.                        
  113.                         /* append item in R[0] */
  114.                         /* if (pos_in_item >= 0) */ {
  115.                                 bi.tb = tb;
  116.                                 bi.bi_bh = tb->R[0];
  117.                                 bi.bi_parent = tb->FR[0];
  118.                                 bi.bi_position = get_right_neighbor_position(tb, 0);
  119.                                
  120.                                 leaf_paste_in_buffer(&bi, item_pos - n + tb->rnum[0],
  121.                                                      pos_in_item, tb->insert_size[0],
  122.                                                      body, zeros_num);
  123.                         }
  124.                         /* paste new entry, if item is directory item */
  125.                         pasted = B_N_PITEM_HEAD(tb->R[0], item_pos - n + tb->rnum[0]);
  126.                        
  127.                         if (is_direntry_le_ih(pasted) && pos_in_item >= 0) {
  128.                                 leaf_paste_entries(bi.bi_bh, item_pos - n + tb->rnum[0],
  129.                                                    pos_in_item, 1,
  130.                                                    (struct reiserfs_de_head *)body,
  131.                                                    body + DEH_SIZE,
  132.                                                    tb->insert_size[0]);
  133.                                 if (!pos_in_item) {
  134.                                         RFALSE(item_pos - n + tb->rnum[0],
  135.                                                "PAP-12165: directory item must be first item of node when pasting is in 0th position");
  136.                                         /* update delimiting keys */
  137.                                         replace_key(tb, tb->CFR[0], tb->rkey[0],
  138.                                                     tb->R[0], 0);
  139.                                 }
  140.                         }

  141.                         if (is_indirect_le_ih(pasted))
  142.                                 set_ih_free_space(pasted, 0);
  143.                        
  144.                         zeros_num = tb->insert_size[0] = 0;
  145.                 }
  146.                 else if (is_direntry_le_ih(B_N_PITEM_HEAD(tbS0, item_pos))) {
  147.                         /* we append to directory item */
  148.                         int entry_count;

  149.                         RFALSE(zeros_num,
  150.                                "PAP-12145: invalid parameter in case of a directory");
  151.                        
  152.                         entry_count = I_ENTRY_COUNT(B_N_PITEM_HEAD(tbS0, item_pos));
  153.                         if (entry_count - tb->rbytes < pos_in_item) {
  154.                                 /* new directory entry falls into R[0] */
  155.                                 int paste_entry_position;
  156.                                
  157.                                 RFALSE(tb->rbytes - 1 >= entry_count ||
  158.                                         !tb->insert_size[0],
  159.                                        "PAP-12150: no enough of entries to shift to R[0]: rbytes=%d, entry_count=%d",
  160.                                        tb->rbytes, entry_count);
  161.                                
  162.                                 /* Shift rnum[0] items in whole.
  163.                                  * Shift rbytes-1 directory entries from directory item number rnum[0] */
  164.                                 leaf_shift_right(tb, tb->rnum[0], tb->rbytes -1);
  165.                                
  166.                                 /* Paste given directory entry to directory item */
  167.                                 paste_entry_position = pos_in_item - entry_count +
  168.                                                         tb->rbytes - 1;
  169.                                 bi.tb = tb;
  170.                                 bi.bi_bh = tb->R[0];
  171.                                 bi.bi_parent = tb->FR[0];
  172.                                 bi.bi_position = get_right_neighbor_position(tb, 0);
  173.                                
  174.                                 leaf_paste_in_buffer(&bi, 0, paste_entry_position,
  175.                                                      tb->insert_size[0],
  176.                                                      body, zeros_num);
  177.                                 /* paste entry */
  178.                                 leaf_paste_entries(bi.bi_bh, 0,
  179.                                                    paste_entry_position, 1,
  180.                                                    (struct reiserfs_de_head *) body,
  181.                                                    body + DEH_SIZE,
  182.                                                    tb->insert_size[0]);
  183.                                 if (paste_entry_position == 0) {
  184.                                         /* change delimiting keys */
  185.                                         replace_key(tb, tb->CFR[0], tb->rkey[0],
  186.                                                     tb->R[0], 0);
  187.                                 }
  188.                                
  189.                                 tb->insert_size[0] = 0;
  190.                                 pos_in_item++;
  191.                        
  192.                         } else { /* new directory entry doesn't fall into R[0] */
  193.                                 leaf_shift_right(tb, tb->rnum[0], tb->rbytes);
  194.                         }
  195.                
  196.                 } else { /* regular object */
  197.                         int n_shift, n_rem, r_zeros_number;
  198.                         const char *r_body;
  199.                        
  200.                         /* Calculate number of bytes which must be
  201.                          * shifted from appended item */
  202.                         n_shift = tb->rbytes - tb->insert_size[0];
  203.                         if (n_shift < 0)
  204.                                 n_shift = 0;
  205.                        
  206.                         RFALSE(pos_in_item != ih_item_len(B_N_PITEM_HEAD(tbS0, item_pos)),
  207.                                "PAP-12155: invalid position to paste. ih_item_len=%d, pos_in_item=%d",
  208.                                pos_in_item, ih_item_len(B_N_PITEM_HEAD(tbS0, item_pos)));
  209.                        
  210.                         leaf_shift_right(tb, tb->rnum[0], n_shift);
  211.                        
  212.                         /* Calculate number of bytes which must remain in body
  213.                          * after appending to R[0] */
  214.                         n_rem = tb->insert_size[0] - tb->rbytes;
  215.                         if (n_rem < 0)
  216.                                 n_rem = 0;
  217.                        
  218.                         {
  219.                                 int version;
  220.                                 unsigned long temp_rem = n_rem;
  221.                                
  222.                                 version = ih_version(B_N_PITEM_HEAD(tb->R[0], 0));
  223.                                 if (is_indirect_le_key(version, B_N_PKEY(tb->R[0], 0)))
  224.                                         temp_rem = n_rem << (tb->tb_sb->s_blocksize_bits - UNFM_P_SHIFT);
  225.                                
  226.                                 set_le_key_k_offset(version, B_N_PKEY(tb->R[0], 0),
  227.                                     le_key_k_offset(version, B_N_PKEY(tb->R[0], 0)) + temp_rem);
  228.                                
  229.                                 set_le_key_k_offset(version, B_N_PDELIM_KEY(tb->CFR[0], tb->rkey[0]),
  230.                                     le_key_k_offset(version, B_N_PDELIM_KEY(tb->CFR[0], tb->rkey[0])) + temp_rem);
  231.                         }
  232.                         /*
  233.                          k_offset (B_N_PKEY(tb->R[0],0)) += n_rem;
  234.                            k_offset (B_N_PDELIM_KEY(tb->CFR[0],tb->rkey[0])) += n_rem;
  235.                           */
  236.                         do_balance_mark_internal_dirty(tb, tb->CFR[0], 0);

  237.                         /* Append part of body into R[0] */
  238.                         bi.tb = tb;
  239.                         bi.bi_bh = tb->R[0];
  240.                         bi.bi_parent = tb->FR[0];
  241.                         bi.bi_position = get_right_neighbor_position(tb, 0);
  242.                        
  243.                         if (n_rem > zeros_num) {
  244.                                 r_zeros_number = 0;
  245.                                 r_body = body + n_rem - zeros_num;
  246.                         } else {
  247.                                 r_body = body;
  248.                                 r_zeros_number = zeros_num - n_rem;
  249.                                 zeros_num -= r_zeros_number;
  250.                         }
  251.                        
  252.                         leaf_paste_in_buffer(&bi, 0, n_shift,
  253.                                              tb->insert_size[0] - n_rem,
  254.                                              r_body, r_zeros_number);
  255.                        
  256.                         if (is_indirect_le_ih(B_N_PITEM_HEAD(tb->R[0], 0))) {
  257.                 #if 0
  258.                                 RFALSE(n_rem, "PAP-12160: paste more than one unformatted node pointer");
  259.                 #endif
  260.                                 set_ih_free_space(B_N_PITEM_HEAD(tb->R[0], 0), 0);
  261.                         }
  262.                        
  263.                         tb->insert_size[0] = n_rem;
  264.                         if (!n_rem)
  265.                                 pos_in_item++;
  266.                 }
  267.         }
  268.         else {
  269.                 reiserfs_panic(tb->tb_sb,
  270.                        "PAP-12175: balance_leaf: rnum > 0: unexpectable mode: %s(%d)",
  271.                        (flag == M_DELETE) ? "DELETE" :
  272.                        ((flag == M_CUT) ? "CUT" : "UNKNOWN"), flag);
  273.         }
  274. }
复制代码

作者: sisi8408    时间: 2008-02-16 14:58

  1. /*
  2. * @ih,           item header of inserted item, this is on little endian
  3. * @body,  body of inserted item or bytes to paste
  4. * @flag,  i - insert, d - delete, c - cut, p - paste, see comment to do_balance
  5. * @insert_key,         in our processing of one level,
  6. *                 we sometimes determine what must be inserted into the next higher level.
  7. *                 This insertion consists of a key or two keys and
  8. *                 their corresponding pointers.
  9. * @insert_ptr,         inserted node-ptrs for the next level
  10. */
  11. static void balance_leaf_shift_left(struct tree_balance *tb,
  12.                                    struct item_head *ih,
  13.                                    const char *body,
  14.                                    int flag,
  15.                                    struct item_head *insert_key,
  16.                                    struct buffer_head **insert_ptr)
  17. {
  18.         struct buffer_head *tbS0 = PATH_PLAST_BUFFER(tb->tb_path);
  19.         /*  index of the affected item */
  20.         int item_pos = PATH_LAST_POSITION(tb->tb_path);
  21.        
  22.         struct buffer_info bi;

  23.         int ret_val;
  24.         int pos_in_item;
  25.         int zeros_num;
  26.        
  27.         if (!(tb->lnum[0] > 0)) /* left shift not needed */
  28.                 return;
  29.        
  30.         zeros_num = 0;
  31.         if (flag == M_INSERT && body == 0)
  32.                 zeros_num = ih_item_len(ih);

  33.         pos_in_item = tb->tb_path->pos_in_item;
  34.         /* for indirect item pos_in_item is measured in unformatted node
  35.          * pointers. Recalculate to bytes
  36.          */
  37.         if (flag != M_INSERT &&
  38.             is_indirect_le_ih(B_N_PITEM_HEAD(tbS0, item_pos)))
  39.                 pos_in_item *= UNFM_P_SIZE;
  40.         /*
  41.          * lets compare the affted item with lnum[h] computed in fix_node.
  42.          *
  43.          * left shift, defed by Hans, as to
  44.          * move lnum[h] items starting at I-0 in S to L
  45.          */
  46.         if (!(item_pos < tb->lnum[0])) {
  47.                 /* new item doesn't fall into L[0] */
  48.                 leaf_shift_left(tb, tb->lnum[0], tb->lbytes);
  49.                 return;
  50.         }

  51.         n = B_NR_ITEMS(tb->L[0]);

  52.         if (flag == M_INSERT) {
  53.                 if (item_pos == tb->lnum[0] -1 && tb->lbytes != -1) {
  54.                         /* part of new item falls into L[0] */
  55.                         int new_item_len;
  56.                         int version;
  57.                        
  58.                         /* shift lnum[0]-1 items entirely */
  59.                         ret_val = leaf_shift_left(tb, tb->lnum[0] -1, -1);
  60.                        
  61.                         /* Calculate item length to insert to S[0] */
  62.                         new_item_len = ih_item_len(ih) - tb->lbytes;
  63.                        
  64.                         /* Calculate and check item length to insert to L[0] */
  65.                         put_ih_item_len(ih, tb->lbytes /*ih_item_len(ih) - new_item_len*/);
  66.                         RFALSE(tb->lbytes <= 0,
  67.                                 "PAP-12080: there is nothing to insert into L[0]: ih_item_len=%d",
  68.                                 ih_item_len(ih));

  69.                         /* Insert new item into L[0] */
  70.                         bi.tb = tb;
  71.                         bi.bi_bh = tb->L[0];
  72.                         bi.bi_parent = tb->FL[0];
  73.                         bi.bi_position = get_left_neighbor_position(tb, 0);
  74.                        
  75.                         leaf_insert_into_buf(&bi, n + item_pos - ret_val,
  76.                                                 ih, body,
  77.                                                 zeros_num > ih_item_len(ih) ?
  78.                                                 ih_item_len(ih) : zeros_num);
  79.                        
  80.                         version = ih_version(ih);
  81.                         /* Calculate key component,
  82.                          * item length and body to insert into S[0]
  83.                          */
  84.                         set_le_ih_k_offset(ih,
  85.                             le_ih_k_offset(ih) +
  86.                             (tb->lbytes << (is_indirect_le_ih(ih) ?
  87.                                 tb->tb_sb->s_blocksize_bits - UNFM_P_SHIFT : 0)));

  88.                         put_ih_item_len(ih, new_item_len);
  89.                        
  90.                         if (tb->lbytes > zeros_num) {
  91.                                 body += (tb->lbytes - zeros_num);
  92.                                 zeros_num = 0;
  93.                         } else
  94.                                 zeros_num -= tb->lbytes;

  95.                         RFALSE(ih_item_len(ih) <= 0,
  96.                                "PAP-12085: there is nothing to insert into S[0]: ih_item_len=%d",
  97.                                ih_item_len(ih));
  98.                 } else {
  99.                         /* new item in whole falls into L[0] */
  100.                        
  101.                         /* Shift lnum[0]-1 items to L[0] */
  102.                         ret_val = leaf_shift_left(tb, tb->lnum[0] -1, tb->lbytes);
  103.                        
  104.                         /* Insert new item into L[0] */
  105.                         bi.tb = tb;
  106.                         bi.bi_bh = tb->L[0];
  107.                         bi.bi_parent = tb->FL[0];
  108.                         bi.bi_position = get_left_neighbor_position(tb, 0);
  109.                        
  110.                         leaf_insert_into_buf(&bi, n + item_pos - ret_val,
  111.                                                 ih, body, zeros_num);
  112.                         tb->insert_size[0] = 0;
  113.                         zeros_num = 0;
  114.                 }
  115.         }
  116.         else if (flag == M_PASTE) {
  117.                 if (!(item_pos == tb->lnum[0] -1 && tb->lbytes != -1)) {
  118.                         /* appended item will be in L[0] in whole */
  119.                         struct item_head *pasted;

  120.                         if (!item_pos &&
  121.                             op_is_left_mergeable(B_N_PKEY(tbS0, 0), tbS0->b_size)) {
  122.                                     /* if we paste into first item of S[0], and
  123.                                      * it is left mergable,
  124.                                      * then increment pos_in_item by the size of
  125.                                      * the last item in L[0]
  126.                                      */
  127.                                 pasted = B_N_PITEM_HEAD(tb->L[0], n -1);
  128.                                
  129.                                 if (is_direntry_le_ih(pasted))
  130.                                         pos_in_item += ih_entry_count(pasted);
  131.                                 else
  132.                                         pos_in_item += ih_item_len(pasted);
  133.                         }
  134.                         /* Shift lnum[0] in whole */
  135.                         ret_val = leaf_shift_left(tb, tb->lnum[0], tb->lbytes);
  136.                        
  137.                         /* Append to body of item in L[0] */
  138.                         bi.tb = tb;
  139.                         bi.bi_bh = tb->L[0];
  140.                         bi.bi_parent = tb->FL[0];
  141.                         bi.bi_position = get_left_neighbor_position(tb, 0);
  142.                        
  143.                         leaf_paste_in_buffer(&bi, n + item_pos - ret_val,
  144.                                         pos_in_item, tb->insert_size[0],
  145.                                         body, zeros_num);
  146.                        
  147.                         /* if appended item is directory, paste entry */
  148.                         pasted = B_N_PITEM_HEAD(tb->L[0], n + item_pos - ret_val);
  149.                         if (is_direntry_le_ih(pasted))
  150.                                 leaf_paste_entries(bi.bi_bh, n + item_pos - ret_val,
  151.                                                 pos_in_item, 1,
  152.                                                 (struct reiserfs_de_head *)body,
  153.                                                 body + DEH_SIZE,
  154.                                                 tb->insert_size[0]);
  155.                         /* if appended item is indirect item,
  156.                          * put unformatted node into un list
  157.                          */
  158.                         if (is_indirect_le_ih(pasted))
  159.                                 set_ih_free_space(pasted, 0);
  160.                        
  161.                         tb->insert_size[0] = 0;
  162.                         zeros_num = 0;
  163.                         return;
  164.                 }
  165.                 /* we must shift the part of the appended item */
  166.                 if (is_direntry_le_ih(B_N_PITEM_HEAD(tbS0, item_pos))) {
  167.                         /* case of directory item */
  168.                         RFALSE(zeros_num,
  169.                                "PAP-12090: invalid parameter in case of a directory");
  170.                        
  171.                         if (tb->lbytes > pos_in_item) {
  172.                                 /* new directory entry falls into L[0] */
  173.                                 struct item_head *pasted;
  174.                                 int l_pos_in_item = pos_in_item;
  175.                                
  176.                                 /* Shift lnum[0] items in whole.
  177.                                  * Shift lbytes - 1 entries from given directory item
  178.                                  */
  179.                                 ret_val = leaf_shift_left(tb, tb->lnum[0], tb->lbytes -1);
  180.                                 if (ret_val && !item_pos) {
  181.                                         pasted = B_N_PITEM_HEAD(tb->L[0], B_NR_ITEMS(tb->L[0]) -1);
  182.                                         l_pos_in_item += I_ENTRY_COUNT(pasted) - (tb->lbytes -1);
  183.                                 }
  184.                                 /* Append given directory entry to directory item */
  185.                                 bi.tb = tb;
  186.                                 bi.bi_bh = tb->L[0];
  187.                                 bi.bi_parent = tb->FL[0];
  188.                                 bi.bi_position = get_left_neighbor_position(tb, 0);
  189.                                
  190.                                 leaf_paste_in_buffer(&bi, n + item_pos - ret_val,
  191.                                                         l_pos_in_item,
  192.                                                         tb->insert_size[0],
  193.                                                         body, zeros_num);
  194.                                
  195.                                 /* previous string prepared space for pasting new entry,
  196.                                  * following string pastes this entry */
  197.                                 /* when we have merge directory item,
  198.                                  * pos_in_item has been changed too */
  199.                                 /* paste new directory entry. 1 is entry number */
  200.                                 leaf_paste_entries(bi.bi_bh, n + item_pos - ret_val,
  201.                                                    l_pos_in_item, 1,
  202.                                                    (struct reiserfs_de_head *) body,
  203.                                                    body + DEH_SIZE,
  204.                                                    tb->insert_size[0]);
  205.                                 tb->insert_size[0] = 0;
  206.                         } else {
  207.                                 /* new directory item doesn't fall into L[0] */
  208.                                 /* Shift lnum[0]-1 items in whole.
  209.                                  * Shift lbytes directory entries from directory item number lnum[0] */
  210.                                 leaf_shift_left(tb, tb->lnum[0], tb->lbytes);
  211.                         }
  212.                        
  213.                         /* Calculate new position to append in item body */
  214.                         pos_in_item -= tb->lbytes;
  215.                
  216.                 } else { /* regular object */
  217.                         RFALSE(tb->lbytes <= 0,
  218.                                "PAP-12095: there is nothing to shift to L[0]. lbytes=%d",
  219.                                tb->lbytes);
  220.                        
  221.                         RFALSE(pos_in_item != ih_item_len(B_N_PITEM_HEAD(tbS0, item_pos)),
  222.                                "PAP-12100: incorrect position to paste: item_len=%d, pos_in_item=%d",
  223.                                ih_item_len(B_N_PITEM_HEAD(tbS0, item_pos)), pos_in_item);
  224.                        
  225.                         if (tb->lbytes >= pos_in_item) {
  226.                                 /* appended item will be in L[0] in whole */
  227.                                 /* this bytes number must be appended to
  228.                                  * the last item of L[h] */
  229.                                 int l_n = tb->lbytes - pos_in_item;
  230.                                
  231.                                 /* Calculate new insert_size[0] */
  232.                                 tb->insert_size[0] -= l_n;

  233.                                 RFALSE(tb->insert_size[0] <= 0,
  234.                                       "PAP-12105: there is nothing to paste into L[0]. insert_size=%d",
  235.                                        tb->insert_size[0]);
  236.                                
  237.                                 ret_val = leaf_shift_left(tb, tb->lnum[0],
  238.                                                ih_item_len(B_N_PITEM_HEAD(tbS0, item_pos)));
  239.                                 /* Append to body of item in L[0] */
  240.                                 bi.tb = tb;
  241.                                 bi.bi_bh = tb->L[0];
  242.                                 bi.bi_parent = tb->FL[0];
  243.                                 bi.bi_position = get_left_neighbor_position(tb, 0);
  244.                                
  245.                                 leaf_paste_in_buffer(&bi, n + item_pos - ret_val,
  246.                                             ih_item_len(B_N_PITEM_HEAD(tb->L[0], n + item_pos - ret_val)),
  247.                                             l_n, body, zeros_num > l_n ? l_n : zeros_num);
  248.                                
  249.                                 /* 0-th item in S0 can be only of DIRECT type when l_n != 0 */
  250.                                 {
  251.                                         int version;
  252.                                         int temp_l = l_n;
  253.                                        
  254.                                         RFALSE(ih_item_len(B_N_PITEM_HEAD(tbS0, 0)),
  255.                                                 "PAP-12106: item length must be 0");
  256.                                         RFALSE(comp_short_le_keys(B_N_PKEY(tbS0, 0),
  257.                                                                   B_N_PKEY(tb->L[0], n + item_pos - ret_val)),
  258.                                                 "PAP-12107: items must be of the same file");
  259.                                        
  260.                                         if (is_indirect_le_ih(B_N_PITEM_HEAD(tb->L[0], n + item_pos - ret_val)))
  261.                                                 temp_l = l_n << (tb->tb_sb->s_blocksize_bits - UNFM_P_SHIFT);
  262.                                        
  263.                                         /* update key of first item in S0 */
  264.                                         version = ih_version(B_N_PITEM_HEAD(tbS0, 0));
  265.                                         set_le_key_k_offset(version, B_N_PKEY(tbS0, 0),
  266.                                             le_key_k_offset(version, B_N_PKEY(tbS0, 0)) + temp_l);
  267.                                         /* update left delimiting key */
  268.                                         set_le_key_k_offset(version,
  269.                                             B_N_PDELIM_KEY(tb->CFL[0], tb->lkey[0]),
  270.                                             le_key_k_offset(version,
  271.                                               B_N_PDELIM_KEY(tb->CFL[0], tb->lkey[0])) + temp_l);
  272.                                 }
  273.                                 /* Calculate new body, position in item and insert_size[0] */
  274.                                 if (l_n > zeros_num) {
  275.                                         body += (l_n - zeros_num);
  276.                                         zeros_num = 0;
  277.                                 } else
  278.                                         zeros_num -= l_n;
  279.                                 pos_in_item = 0;
  280.                                
  281.                                 RFALSE(comp_short_le_keys(B_N_PKEY(tbS0, 0),
  282.                                                           B_N_PKEY(tb->L[0], B_NR_ITEMS(tb->L[0]) - 1))
  283.                                         || !op_is_left_mergeable(B_N_PKEY(tbS0, 0), tbS0->b_size)
  284.                                         || !op_is_left_mergeable(B_N_PDELIM_KEY(tb->CFL[0], tb->lkey[0]), tbS0->b_size),
  285.                                         "PAP-12120: item must be merge-able with left neighboring item");
  286.                        
  287.                         } else { /* only part of the appended item will be in L[0] */
  288.                                 /* Calculate position in item for append in S[0] */
  289.                                 pos_in_item -= tb->lbytes;

  290.                                 RFALSE(pos_in_item <= 0,
  291.                                        "PAP-12125: no place for paste. pos_in_item=%d",
  292.                                        pos_in_item);
  293.                                
  294.                                 /* Shift lnum[0] items in whole.
  295.                                  * Shift lbytes byte from item number lnum[0] */
  296.                                 leaf_shift_left(tb, tb->lnum[0], tb->lbytes);
  297.                         }
  298.                 }
  299.         } else {
  300.                 reiserfs_panic(tb->tb_sb,
  301.                        "PAP-12130: balance_leaf: lnum > 0: unexpectable mode: %s(%d)",
  302.                        (flag == M_DELETE) ? "DELETE" :
  303.                        ((flag == M_CUT) ? "CUT" : "UNKNOWN"), flag);
  304.         }
  305. }
复制代码

作者: daemeon    时间: 2008-02-17 03:22
linux-2.6.24/fs/dcache.c

int
block_page_mkwrite(struct vm_area_struct *vma, struct page *page,
                   get_block_t get_block)
{
        struct inode *inode = vma->vm_file->f_path.dentry->d_inode;
        unsigned long end;
        loff_t size;
        int ret = -EINVAL;

        lock_page(page);
        size = i_size_read(inode);
        if ((page->mapping != inode->i_mapping) ||
            (page_offset(page) > size)) {
                /* page got truncated out from underneath us */
                goto out_unlock;
        }

        /* page is wholly or partially inside EOF */
        if (((page->index + 1) << PAGE_CACHE_SHIFT) > size)
                end = size & ~PAGE_CACHE_MASK;
        else
                end = PAGE_CACHE_SIZE;

        ret = block_prepare_write(page, 0, end, get_block);
        if (!ret)
                ret = block_commit_write(page, 0, end);

out_unlock:
        unlock_page(page);
        return ret;
}

作者: sisi8408    时间: 2008-02-17 11:02
u do disk cache, i do get block, hehe

  1. static void balance_leaf_do_remain(struct tree_balance *tb,
  2.                                 struct item_head *ih,
  3.                                 const char *body,
  4.                                 int flag,
  5.                                 int *p_pos_in_item,
  6.                                 int *p_item_pos,
  7.                                 int *p_zeros_num)
  8. {
  9.         struct buffer_info bi;
  10.         int zeros_num, item_pos, pos_in_item;

  11.         struct item_head *pasted;
  12.         struct buffer_head *tbS0 = PATH_PLAST_BUFFER(tb->tb_path);
  13.        
  14.         if (!(flag == M_INSERT || flag == M_PASTE) {
  15.                 reiserfs_panic(tb->tb_sb,
  16.                         "JZ-0001: balance_leaf:unexpectable mode: %s(%d)",
  17.                         (flag == M_DELETE) ? "DELETE" :
  18.                         ((flag == M_CUT) ? "CUT" : "UNKNOWN"), flag);
  19.                 return;
  20.         }

  21.         zeros_num = *p_zeros_num;
  22.         item_pos = *p_item_pos;
  23.         pos_in_item = *p_pos_in_item;
  24.        
  25.         if (flag == M_INSERT) {
  26.                 bi.tb = tb;
  27.                 bi.bi_bh = tbS0;
  28.                 bi.bi_parent = PATH_H_PPARENT(tb->tb_path, 0);
  29.                 bi.bi_position = PATH_H_POSITION(tb->tb_path, 1);
  30.                 /*
  31.                  * zeros_num maybe chged in shifting
  32.                  */
  33.                 leaf_insert_into_buf(&bi, item_pos, ih, body, zeros_num);
  34.                 /* If we insert the first key change the delimiting key */
  35.                 if (item_pos == 0) {
  36.                         if (tb->CFL[0])        /* can be 0 in reiserfsck */
  37.                                 replace_key(tb, tb->CFL[0], tb->lkey[0], tbS0, 0);
  38.                 }
  39.                 goto out;
  40.         }

  41.         pasted = B_N_PITEM_HEAD(tbS0, item_pos);
  42.         /* when directory, may be new entry already pasted */
  43.         if (is_direntry_le_ih(pasted)) {
  44.                 if (0<= pos_in_item && pos_in_item <= ih_entry_count(pasted)) {
  45.                         RFALSE(!tb->insert_size[0],
  46.                                "PAP-12260: insert_size is 0 already");
  47.                         /* prepare space */
  48.                         bi.tb = tb;
  49.                         bi.bi_bh = tbS0;
  50.                         bi.bi_parent = PATH_H_PPARENT(tb->tb_path, 0);
  51.                         bi.bi_position = PATH_H_POSITION(tb->tb_path, 1);
  52.                        
  53.                         leaf_paste_in_buffer(&bi, item_pos, pos_in_item,
  54.                                              tb->insert_size[0],
  55.                                              body, zeros_num);
  56.                         /* paste entry */
  57.                         leaf_paste_entries(bi.bi_bh, item_pos, pos_in_item, 1,
  58.                                            (struct reiserfs_de_head *)body,
  59.                                            body + DEH_SIZE,
  60.                                            tb->insert_size[0]);
  61.                        
  62.                         if (!item_pos && !pos_in_item) {
  63.                                 RFALSE(!tb->CFL[0] || !tb->L[0],
  64.                                        "PAP-12270: CFL[0]/L[0] must be specified");
  65.                                 if (tb->CFL[0])
  66.                                         replace_key(tb, tb->CFL[0], tb->lkey[0],
  67.                                                     tbS0, 0);
  68.                         }
  69.                         tb->insert_size[0] = 0;
  70.                 }
  71.         } else { /* regular object */
  72.                 if (pos_in_item == ih_item_len(pasted)) {
  73.                         RFALSE(tb->insert_size[0] <= 0,
  74.                                "PAP-12275: insert size must not be %d",
  75.                                tb->insert_size[0]);
  76.                         bi.tb = tb;
  77.                         bi.bi_bh = tbS0;
  78.                         bi.bi_parent = PATH_H_PPARENT(tb->tb_path, 0);
  79.                         bi.bi_position = PATH_H_POSITION(tb->tb_path, 1);
  80.                        
  81.                         leaf_paste_in_buffer(&bi, item_pos, pos_in_item,
  82.                                              tb->insert_size[0],
  83.                                              body, zeros_num);
  84.                        
  85.                         if (is_indirect_le_ih(pasted)) {
  86.                 #if 0
  87.                                 RFALSE(tb->insert_size[0] != UNFM_P_SIZE,
  88.                                        "PAP-12280: insert_size for indirect item must be %d, not %d",
  89.                                        UNFM_P_SIZE, tb->insert_size[0]);
  90.                 #endif
  91.                                 set_ih_free_space(pasted, 0);
  92.                         }
  93.                         tb->insert_size[0] = 0;
  94.                 }
  95. #ifdef CONFIG_REISERFS_CHECK
  96.                 else {
  97.                         if (tb->insert_size[0]) {
  98.                                 print_cur_tb("12285");
  99.                                 reiserfs_panic(tb->tb_sb,
  100.                                        "PAP-12285: balance_leaf: insert_size must be 0 (%d)",
  101.                                                tb->insert_size[0]);
  102.                         }
  103.                 }
  104. #endif
  105.         }
  106. out:
  107.         *p_item_pos = item_pos;
  108.         *p_pos_in_item = pos_in_item;
  109.         *p_zeros_num = zeros_num;
  110. }
复制代码





欢迎光临 Chinaunix (http://bbs.chinaunix.net/) Powered by Discuz! X3.2