vserver 1.9.5.x5
[linux-2.6.git] / arch / ia64 / kernel / unwind.c
index 69e095a..d494ff6 100644 (file)
@@ -47,8 +47,6 @@
 #include "entry.h"
 #include "unwind_i.h"
 
-#define p5             5
-
 #define UNW_LOG_CACHE_SIZE     7       /* each unw_script is ~256 bytes in size */
 #define UNW_CACHE_SIZE         (1 << UNW_LOG_CACHE_SIZE)
 
@@ -1269,7 +1267,6 @@ script_new (unsigned long ip)
 {
        struct unw_script *script, *prev, *tmp;
        unw_hash_index_t index;
-       unsigned long flags;
        unsigned short head;
 
        STAT(++unw.stat.script.news);
@@ -1278,13 +1275,9 @@ script_new (unsigned long ip)
         * Can't (easily) use cmpxchg() here because of ABA problem
         * that is intrinsic in cmpxchg()...
         */
-       spin_lock_irqsave(&unw.lock, flags);
-       {
-               head = unw.lru_head;
-               script = unw.cache + head;
-               unw.lru_head = script->lru_chain;
-       }
-       spin_unlock(&unw.lock);
+       head = unw.lru_head;
+       script = unw.cache + head;
+       unw.lru_head = script->lru_chain;
 
        /*
         * We'd deadlock here if we interrupted a thread that is holding a read lock on
@@ -1295,43 +1288,39 @@ script_new (unsigned long ip)
        if (!write_trylock(&script->lock))
                return NULL;
 
-       spin_lock(&unw.lock);
-       {
-               /* re-insert script at the tail of the LRU chain: */
-               unw.cache[unw.lru_tail].lru_chain = head;
-               unw.lru_tail = head;
-
-               /* remove the old script from the hash table (if it's there): */
-               if (script->ip) {
-                       index = hash(script->ip);
-                       tmp = unw.cache + unw.hash[index];
-                       prev = NULL;
-                       while (1) {
-                               if (tmp == script) {
-                                       if (prev)
-                                               prev->coll_chain = tmp->coll_chain;
-                                       else
-                                               unw.hash[index] = tmp->coll_chain;
-                                       break;
-                               } else
-                                       prev = tmp;
-                               if (tmp->coll_chain >= UNW_CACHE_SIZE)
-                               /* old script wasn't in the hash-table */
-                                       break;
-                               tmp = unw.cache + tmp->coll_chain;
-                       }
+       /* re-insert script at the tail of the LRU chain: */
+       unw.cache[unw.lru_tail].lru_chain = head;
+       unw.lru_tail = head;
+
+       /* remove the old script from the hash table (if it's there): */
+       if (script->ip) {
+               index = hash(script->ip);
+               tmp = unw.cache + unw.hash[index];
+               prev = NULL;
+               while (1) {
+                       if (tmp == script) {
+                               if (prev)
+                                       prev->coll_chain = tmp->coll_chain;
+                               else
+                                       unw.hash[index] = tmp->coll_chain;
+                               break;
+                       } else
+                               prev = tmp;
+                       if (tmp->coll_chain >= UNW_CACHE_SIZE)
+                       /* old script wasn't in the hash-table */
+                               break;
+                       tmp = unw.cache + tmp->coll_chain;
                }
+       }
 
-               /* enter new script in the hash table */
-               index = hash(ip);
-               script->coll_chain = unw.hash[index];
-               unw.hash[index] = script - unw.cache;
+       /* enter new script in the hash table */
+       index = hash(ip);
+       script->coll_chain = unw.hash[index];
+       unw.hash[index] = script - unw.cache;
 
-               script->ip = ip;        /* set new IP while we're holding the locks */
+       script->ip = ip;        /* set new IP while we're holding the locks */
 
-               STAT(if (script->coll_chain < UNW_CACHE_SIZE) ++unw.stat.script.collisions);
-       }
-       spin_unlock_irqrestore(&unw.lock, flags);
+       STAT(if (script->coll_chain < UNW_CACHE_SIZE) ++unw.stat.script.collisions);
 
        script->flags = 0;
        script->hint = 0;
@@ -1830,6 +1819,7 @@ find_save_locs (struct unw_frame_info *info)
 {
        int have_write_lock = 0;
        struct unw_script *scr;
+       unsigned long flags = 0;
 
        if ((info->ip & (local_cpu_data->unimpl_va_mask | 0xf)) || info->ip < TASK_SIZE) {
                /* don't let obviously bad addresses pollute the cache */
@@ -1841,8 +1831,10 @@ find_save_locs (struct unw_frame_info *info)
 
        scr = script_lookup(info);
        if (!scr) {
+               spin_lock_irqsave(&unw.lock, flags);
                scr = build_script(info);
                if (!scr) {
+                       spin_unlock_irqrestore(&unw.lock, flags);
                        UNW_DPRINT(0,
                                   "unwind.%s: failed to locate/build unwind script for ip %lx\n",
                                   __FUNCTION__, info->ip);
@@ -1855,9 +1847,10 @@ find_save_locs (struct unw_frame_info *info)
 
        run_script(scr, info);
 
-       if (have_write_lock)
+       if (have_write_lock) {
                write_unlock(&scr->lock);
-       else
+               spin_unlock_irqrestore(&unw.lock, flags);
+       } else
                read_unlock(&scr->lock);
        return 0;
 }
@@ -1904,7 +1897,7 @@ unw_unwind (struct unw_frame_info *info)
        num_regs = 0;
        if ((info->flags & UNW_FLAG_INTERRUPT_FRAME)) {
                info->pt = info->sp + 16;
-               if ((pr & (1UL << pNonSys)) != 0)
+               if ((pr & (1UL << PRED_NON_SYSCALL)) != 0)
                        num_regs = *info->cfm_loc & 0x7f;               /* size of frame */
                info->pfs_loc =
                        (unsigned long *) (info->pt + offsetof(struct pt_regs, ar_pfs));
@@ -1950,7 +1943,7 @@ EXPORT_SYMBOL(unw_unwind);
 int
 unw_unwind_to_user (struct unw_frame_info *info)
 {
-       unsigned long ip;
+       unsigned long ip, sp;
 
        while (unw_unwind(info) >= 0) {
                if (unw_get_rp(info, &ip) < 0) {
@@ -1959,6 +1952,9 @@ unw_unwind_to_user (struct unw_frame_info *info)
                                   __FUNCTION__, ip);
                        return -1;
                }
+               unw_get_sp(info, &sp);
+               if (sp >= (unsigned long)info->task + IA64_STK_OFFSET)
+                       break;
                if (ip < FIXADDR_USER_END)
                        return 0;
        }
@@ -2056,6 +2052,8 @@ unw_init_frame_info (struct unw_frame_info *info, struct task_struct *t, struct
        find_save_locs(info);
 }
 
+EXPORT_SYMBOL(unw_init_frame_info);
+
 void
 unw_init_from_blocked_task (struct unw_frame_info *info, struct task_struct *t)
 {
@@ -2259,7 +2257,7 @@ unw_init (void)
                if (i > 0)
                        unw.cache[i].lru_chain = (i - 1);
                unw.cache[i].coll_chain = -1;
-               unw.cache[i].lock = RW_LOCK_UNLOCKED;
+               rwlock_init(&unw.cache[i].lock);
        }
        unw.lru_head = UNW_CACHE_SIZE - 1;
        unw.lru_tail = 0;