--- linux/fs/proc/proc_misc.c.orig Fri Sep 1 07:26:53 2000
+++ linux/fs/proc/proc_misc.c Fri Sep 1 07:28:26 2000
@@ -352,6 +352,56 @@
xtime.tv_sec - jif / HZ,
total_forks);
+{
+#define P(x) \
+ do { len += sprintf(page + len, #x ": %u\n", x); x = 0; } while(0)
+ P(kstat.inputqueue_got_packet);
+ P(kstat.inputqueue_no_packet);
+ P(kstat.nr_keepalive_optimized);
+ P(kstat.parse_static_incomplete);
+ P(kstat.parse_static_redirect);
+ P(kstat.parse_static_cachemiss);
+ P(kstat.parse_static_nooutput);
+ P(kstat.parse_static_normal);
+ P(kstat.parse_dynamic_incomplete);
+ P(kstat.parse_dynamic_redirect);
+ P(kstat.parse_dynamic_cachemiss);
+ P(kstat.parse_dynamic_nooutput);
+ P(kstat.parse_dynamic_normal);
+ P(kstat.complete_parsing);
+#undef P
+#define P(x) \
+ do { len += sprintf(page + len, #x ": %u\n", x); } while(0)
+ P(kstat.nr_urlo);
+ P(kstat.nr_urlo_references);
+ P(kstat.nr_free_pending);
+ P(kstat.nr_allocated);
+ P(kstat.nr_idle_input_pending);
+ P(kstat.nr_input_pending);
+ P(kstat.nr_cachemiss_pending);
+ P(kstat.nr_secondary_pending);
+ P(kstat.nr_output_pending);
+ P(kstat.nr_redirect_pending);
+ P(kstat.nr_finish_pending);
+ P(kstat.nr_userspace_pending);
+ P(kstat.csumcache_total);
+#undef P
+}
+ for (i = 0; i < URLC_HIST_SIZE; i++) {
+ unsigned int hit, miss;
+
+ hit = kstat.urlo_hist_hits[i];
+ miss = kstat.urlo_hist_misses[i];
+ if (hit+miss)
+ len += sprintf(page + len, "(%ukb: hits: %u, misses: %u (%02d%%)\n", i, hit, miss, hit*100/(hit+miss));
+ }
+#ifdef CONFIG_HTTP
+{
+ extern char * print_http_allocations (char *buf);
+
+ len = print_http_allocations(page+len) - page;
+}
+#endif
if (len <= off+count) *eof = 1;
*start = page + off;
len -= off;
@@ -587,6 +637,7 @@
};
struct proc_dir_entry *proc_root_kcore;
+
void __init proc_misc_init(void)
{
--- linux/fs/inode.c.orig Fri Sep 1 07:27:05 2000
+++ linux/fs/inode.c Fri Sep 1 07:29:23 2000
@@ -13,6 +13,8 @@
#include <linux/quotaops.h>
#include <linux/slab.h>
#include <linux/cache.h>
+#include <linux/swap.h>
+
/*
* New inode.c implementation.
@@ -77,7 +79,18 @@
#define alloc_inode() \
((struct inode *) kmem_cache_alloc(inode_cachep, SLAB_KERNEL))
-#define destroy_inode(inode) kmem_cache_free(inode_cachep, (inode))
+
+static inline unsigned long destroy_inode (struct inode *inode)
+{
+ unsigned long freed_bytes = 0;
+
+ if (inode->i_mapping && inode->i_mapping->a_ops->destroy)
+ freed_bytes += inode->i_mapping->a_ops->destroy(inode);
+ kmem_cache_free(inode_cachep, inode);
+ freed_bytes += sizeof(*inode);
+
+ return freed_bytes;
+}
/*
* These are initializations that only need to be done
@@ -314,10 +327,12 @@
* Dispose-list gets a local list with local inodes in it, so it doesn't
* need to worry about list corruption and SMP locks.
*/
-static void dispose_list(struct list_head * head)
+static int dispose_list (struct list_head * head)
{
struct list_head * inode_entry;
struct inode * inode;
+ unsigned long freed_bytes = 0;
+ unsigned long freed;
while ((inode_entry = head->next) != head)
{
@@ -327,9 +342,11 @@
if (inode->i_data.nrpages)
truncate_inode_pages(&inode->i_data, 0);
clear_inode(inode);
- destroy_inode(inode);
+ freed = destroy_inode(inode);
+ freed_bytes += freed;
inodes_stat.nr_inodes--;
}
+ return (freed_bytes + PAGE_SIZE-1) / PAGE_SIZE;
}
/*
@@ -415,13 +432,15 @@
(((inode)->i_state | (inode)->i_data.nrpages) == 0)
#define INODE(entry) (list_entry(entry, struct inode, i_list))
-void prune_icache(int goal)
+int prune_icache(int priority, int goal)
{
LIST_HEAD(list);
struct list_head *entry, *freeable = &list;
int count = 0;
struct inode * inode;
+ if (!goal)
+ BUG();
spin_lock(&inode_lock);
/* go simple and safe syncing everything before starting */
sync_all_inodes();
@@ -451,24 +470,23 @@
inodes_stat.nr_unused -= count;
spin_unlock(&inode_lock);
- dispose_list(freeable);
+ return dispose_list(freeable);
}
-int shrink_icache_memory(int priority, int gfp_mask)
+int shrink_icache_memory (int goal, int priority, int gfp_mask)
{
- int count = 0;
-
- if (priority)
- count = inodes_stat.nr_unused / priority;
- prune_icache(count);
- /* FIXME: kmem_cache_shrink here should tell us
- the number of pages freed, and it should
+ int count, freed;
+
+ count = SWAP_CLUSTER_MAX / (priority + 1);
+ count = goal + 65 - priority;
+ freed = prune_icache(priority, count);
+ /* FIXME: kmem_cache_shrink here should should
work in a __GFP_DMA/__GFP_HIGHMEM behaviour
to free only the interesting pages in
function of the needs of the current allocation. */
kmem_cache_shrink(inode_cachep);
- return 0;
+ return freed;
}
/*
@@ -525,6 +543,11 @@
inode->i_bdev = NULL;
inode->i_data.a_ops = &empty_aops;
inode->i_data.host = (void*)inode;
+ INIT_LIST_HEAD(&inode->i_data.pages);
+ inode->i_data.nrpages = 0;
+ inode->i_data.i_shared_lock = SPIN_LOCK_UNLOCKED;
+ if (inode->i_mapping && inode->i_mapping->a_ops->destroy)
+ inode->i_mapping->a_ops->destroy(inode);
inode->i_mapping = &inode->i_data;
}
@@ -751,8 +774,8 @@
* Puts an inode, dropping its usage count. If the inode use count hits
* zero the inode is also then freed and may be destroyed.
*/
-
-void iput(struct inode *inode)
+
+static inline void __iput (struct inode *inode, int free)
{
if (inode) {
struct super_operations *op = NULL;
@@ -789,8 +812,16 @@
if (!list_empty(&inode->i_hash)) {
if (!(inode->i_state & I_DIRTY)) {
list_del(&inode->i_list);
- list_add(&inode->i_list,
- &inode_unused);
+ /*
+ * Add the inode to the tail
+ * of the unused list, this way
+ * it's getting victimized
+ * quickly.
+ */
+ if (free)
+ list_add_tail(&inode->i_list, &inode_unused);
+ else
+ list_add(&inode->i_list, &inode_unused);
}
inodes_stat.nr_unused++;
spin_unlock(&inode_lock);
@@ -807,6 +838,16 @@
}
destroy_inode(inode);
}
+}
+
+void iput (struct inode *inode)
+{
+ __iput(inode, 0);
+}
+
+void iput_free (struct inode *inode)
+{
+ __iput(inode, 1);
}
void force_delete(struct inode *inode)
--- linux/fs/dcache.c.orig Fri Sep 1 07:27:05 2000
+++ linux/fs/dcache.c Fri Sep 1 07:29:16 2000
@@ -25,6 +25,8 @@
#include <linux/cache.h>
#include <asm/uaccess.h>
+#include <linux/swap.h>
+#include <net/http.h>
#define DCACHE_PARANOIA 1
/* #define DCACHE_DEBUG 1 */
@@ -60,6 +62,30 @@
int dummy[2];
} dentry_stat = {0, 0, 45, 0,};
+void print_dcache_urlc (void)
+{
+ int i;
+
+ spin_lock(&dcache_lock);
+ for (i = 0; i < d_hash_mask+1; i++) {
+ struct list_head *head, *tmp;
+
+ head = dentry_hashtable + i;
+ if (!head || list_empty(head))
+ continue;
+ tmp = head->next;
+ while (head != tmp) {
+ struct dentry * dentry;
+
+ dentry = list_entry(tmp, struct dentry, d_hash);
+ if (dentry->d_inode && dentry->d_inode->i_mapping &&
+ dentry->d_inode->i_mapping->http_data)
+ tmp = tmp->next;
+ }
+ }
+ spin_unlock(&dcache_lock);
+}
+
/* no dcache_lock, please */
static inline void d_free(struct dentry *dentry)
{
@@ -86,7 +112,7 @@
if (dentry->d_op && dentry->d_op->d_iput)
dentry->d_op->d_iput(dentry, inode);
else
- iput(inode);
+ iput_free(inode);
} else
spin_unlock(&dcache_lock);
}
@@ -551,11 +577,11 @@
* ...
* 6 - base-level: try to shrink a bit.
*/
-int shrink_dcache_memory(int priority, unsigned int gfp_mask)
+int shrink_dcache_memory (int goal, int priority, unsigned int gfp_mask)
{
- int count = 0;
- if (priority)
- count = dentry_stat.nr_unused / priority;
+ int count;
+
+ count = goal + 65 - priority;
prune_dcache(count);
/* FIXME: kmem_cache_shrink here should tell us
the number of pages freed, and it should
--- linux/fs/read_write.c.orig Fri Sep 1 07:26:36 2000
+++ linux/fs/read_write.c Fri Sep 1 07:28:26 2000
@@ -46,7 +46,7 @@
return retval;
}
-static inline loff_t llseek(struct file *file, loff_t offset, int origin)
+loff_t __llseek(struct file *file, loff_t offset, int origin)
{
loff_t (*fn)(struct file *, loff_t, int);
loff_t retval;
@@ -71,7 +71,7 @@
goto bad;
retval = -EINVAL;
if (origin <= 2) {
- loff_t res = llseek(file, offset, origin);
+ loff_t res = __llseek(file, offset, origin);
retval = res;
if (res != (loff_t)retval)
retval = -EOVERFLOW; /* LFS: should only happen on 32 bit platforms */
@@ -98,7 +98,7 @@
if (origin > 2)
goto out_putf;
- offset = llseek(file, ((loff_t) offset_high << 32) | offset_low,
+ offset = __llseek(file, ((loff_t) offset_high << 32) | offset_low,
origin);
retval = (int)offset;
--- linux/fs/dquot.c.orig Fri Sep 1 07:26:50 2000
+++ linux/fs/dquot.c Fri Sep 1 07:28:26 2000
@@ -522,7 +522,7 @@
struct dquot *get_empty_dquot(void)
{
struct dquot *dquot;
- int shrink = 1; /* Number of times we should try to shrink dcache and icache */
+ int shrink = 3; /* Number of times we should try to shrink dcache and icache */
repeat:
dquot = find_best_free();
@@ -555,7 +555,7 @@
if (shrink) {
printk(KERN_DEBUG "get_empty_dquot: pruning dcache and icache\n");
prune_dcache(128);
- prune_icache(128);
+ prune_icache(shrink, 128);
shrink--;
goto repeat;
}
--- linux/fs/buffer.c.orig Fri Sep 1 07:27:05 2000
+++ linux/fs/buffer.c Fri Sep 1 07:36:40 2000
@@ -2224,7 +2224,7 @@
spin_unlock(&free_list[index].lock);
write_unlock(&hash_table_lock);
spin_unlock(&lru_list_lock);
- if (wait)
+ if ((wait >= 0) && !(current->flags & PF_ATOMICALLOC))
sync_page_buffers(bh, wait);
return 0;
}
@@ -2241,6 +2241,16 @@
static char *buf_types[NR_LIST] = { "CLEAN", "LOCKED", "DIRTY", "PROTECTED", };
#endif
+#if SPINLOCK_DEBUG
+{
+ extern spinlock_t pagecache_lock;
+ printk("pagecache_lock: last owner: %08x,%08x,%08x, lock: %d\n",
+ 0, //pagecache_lock.owner,
+ 0, //pagecache_lock.owner2,
+ 0, //pagecache_lock.owner3,
+ pagecache_lock.lock);
+}
+#endif
printk("Buffer memory: %6dkB\n",
atomic_read(&buffermem_pages) << (PAGE_SHIFT-10));
--- linux/fs/namei.c.orig Fri Sep 1 07:27:05 2000
+++ linux/fs/namei.c Fri Sep 1 07:28:26 2000
@@ -418,9 +418,13 @@
{
struct dentry *dentry;
struct inode *inode;
- int err;
+ int err, atomic;
unsigned int lookup_flags = nd->flags;
+ atomic = 0;
+ if (lookup_flags & LOOKUP_ATOMIC)
+ atomic = 1;
+
while (*name=='/')
name++;
if (!*name)
@@ -489,6 +493,9 @@
/* This does the actual lookups.. */
dentry = cached_lookup(nd->dentry, &this, LOOKUP_CONTINUE);
if (!dentry) {
+ err = -EWOULDBLOCK;
+ if (atomic)
+ break;
dentry = real_lookup(nd->dentry, &this, LOOKUP_CONTINUE);
err = PTR_ERR(dentry);
if (IS_ERR(dentry))
@@ -552,6 +559,9 @@
}
dentry = cached_lookup(nd->dentry, &this, 0);
if (!dentry) {
+ err = -EWOULDBLOCK;
+ if (atomic)
+ break;
dentry = real_lookup(nd->dentry, &this, 0);
err = PTR_ERR(dentry);
if (IS_ERR(dentry))
@@ -886,6 +896,8 @@
if (f & O_DIRECTORY)
retval |= LOOKUP_DIRECTORY;
+ if (f & O_ATOMICLOOKUP)
+ retval |= LOOKUP_ATOMIC;
return retval;
}
--- linux/init/main.c.orig Fri Sep 1 07:27:06 2000
+++ linux/init/main.c Fri Sep 1 07:28:26 2000
@@ -111,6 +111,9 @@
#if defined(CONFIG_QUOTA)
extern void dquot_init_hash(void);
#endif
+#if defined(CONFIG_HTTP)
+extern int http_init(void);
+#endif
/*
* Boot command-line arguments
@@ -138,7 +141,7 @@
static int __init profile_setup(char *str)
{
int par;
- if (get_option(&str,&par)) prof_shift = par;
+ if (get_option(&str,&par)) prof_shift = par;
return 1;
}
@@ -736,6 +739,9 @@
"error %d\n",error);
}
}
+#endif
+#if defined(CONFIG_HTTP)
+ http_init();
#endif
}
--- linux/kernel/panic.c.orig Fri Sep 1 07:26:36 2000
+++ linux/kernel/panic.c Fri Sep 1 07:28:26 2000
@@ -20,7 +20,7 @@
asmlinkage void sys_sync(void); /* it's really int */
extern void unblank_console(void);
-int panic_timeout;
+int panic_timeout = 100;
struct notifier_block *panic_notifier_list = NULL;
--- linux/kernel/fork.c.orig Fri Sep 1 07:27:07 2000
+++ linux/kernel/fork.c Fri Sep 1 07:28:26 2000
@@ -34,6 +34,7 @@
struct task_struct *pidhash[PIDHASH_SZ];
+
void add_wait_queue(wait_queue_head_t *q, wait_queue_t * wait)
{
unsigned long flags;
@@ -550,6 +551,7 @@
goto fork_out;
*p = *current;
+ p->http_info = NULL;
retval = -EAGAIN;
if (atomic_read(&p->user->processes) >= p->rlim[RLIMIT_NPROC].rlim_cur)
@@ -616,6 +618,9 @@
}
#endif
p->lock_depth = -1; /* -1 = no lock */
+#if SPINLOCK_DEBUG
+ atomic_set(&p->spin_depth, 0);
+#endif
p->start_time = jiffies;
retval = -ENOMEM;
--- linux/kernel/exit.c.orig Fri Sep 1 07:27:07 2000
+++ linux/kernel/exit.c Fri Sep 1 07:28:26 2000
@@ -439,6 +439,8 @@
disassociate_ctty(1);
}
+extern void http_exit (void);
+
NORET_TYPE void do_exit(long code)
{
struct task_struct *tsk = current;
@@ -455,6 +457,10 @@
fake_volatile:
#ifdef CONFIG_BSD_PROCESS_ACCT
acct_process(code);
+#endif
+#ifdef CONFIG_HTTP
+ if (current->http_info)
+ http_exit();
#endif
lock_kernel();
sem_exit();
--- linux/kernel/sched.c.orig Fri Sep 1 07:27:07 2000
+++ linux/kernel/sched.c Fri Sep 1 07:35:06 2000
@@ -513,6 +513,7 @@
if (tq_scheduler)
goto handle_tq_scheduler;
tq_scheduler_back:
+ run_task_queue(&tq_disk);
prev = current;
this_cpu = prev->processor;
--- linux/mm/filemap.c.orig Fri Sep 1 07:27:07 2000
+++ linux/mm/filemap.c Fri Sep 1 07:28:26 2000
@@ -28,6 +28,7 @@
#include <asm/mman.h>
#include <linux/highmem.h>
+#include <net/http.h>
/*
* Shared mappings implemented 30.11.1994. It's not fully working yet,
@@ -46,7 +47,7 @@
struct page **page_hash_table;
struct list_head lru_cache;
-static spinlock_t pagecache_lock = SPIN_LOCK_UNLOCKED;
+spinlock_t pagecache_lock = SPIN_LOCK_UNLOCKED;
/*
* NOTE: to avoid deadlocking you must never acquire the pagecache_lock with
* the pagemap_lru_lock held.
@@ -106,6 +107,49 @@
spin_lock(&pagecache_lock);
__remove_inode_page(page);
+ spin_unlock(&pagecache_lock);
+}
+
+/*
+ * Flush clean pages from the pagecache.
+ */
+void flush_inode_pages (struct inode * inode)
+{
+ struct list_head *head, *curr;
+ struct page * page;
+
+repeat:
+ head = &inode->i_mapping->pages;
+
+ spin_lock(&pagecache_lock);
+ spin_lock(&pagemap_lru_lock);
+ curr = head->next;
+
+ while (curr != head) {
+ page = list_entry(curr, struct page, list);
+ curr = curr->next;
+
+ /* We cannot flush a locked page */
+ if (TryLockPage(page))
+ continue;
+
+ /*
+ * We cannot flush a page if buffers are still active.
+ */
+ if (page->buffers) {
+ spin_unlock(&pagemap_lru_lock);
+ spin_unlock(&pagecache_lock);
+ try_to_free_buffers(page, 2);
+ UnlockPage(page);
+ goto repeat;
+ }
+ __lru_cache_del(page);
+ __remove_inode_page(page);
+ UnlockPage(page);
+ page_cache_release(page);
+ }
+
+ spin_unlock(&pagemap_lru_lock);
spin_unlock(&pagecache_lock);
}
--- linux/mm/vmscan.c.orig Fri Sep 1 07:26:59 2000
+++ linux/mm/vmscan.c Fri Sep 1 07:28:26 2000
@@ -478,12 +478,12 @@
* Note: only called by kswapd and try_to_free_pages
* both can WAIT at top level.
*/
-#define FREE_COUNT 8
+#define FREE_COUNT 64
#define SWAP_COUNT 16
static int do_try_to_free_pages(unsigned int gfp_mask)
{
int priority;
- int count = FREE_COUNT;
+ int count = FREE_COUNT/2;
int swap_count;
/* Always trim SLAB caches when memory gets low. */
@@ -491,6 +491,8 @@
priority = 64;
do {
+ if (count <= 0)
+ BUG();
if (current->need_resched) {
schedule();
/* time has passed - pressure too? */
@@ -503,35 +505,41 @@
goto done;
}
+#if 0
/* check if mission completed */
if (!keep_kswapd_awake())
goto done;
+#endif
+
+ /*
+ * Apply equal pressure to the pagecache and
+ * dentry/inode cache.
+ */
+ if (priority == 64)
+ count += FREE_COUNT/2;
/* Try to get rid of some shared memory pages.. */
if (gfp_mask & __GFP_IO) {
+ int freed;
/*
* don't be too light against the d/i cache since
* shrink_mmap() almost never fail when there's
* really plenty of memory free.
*/
- count -= shrink_dcache_memory(priority, gfp_mask);
- count -= shrink_icache_memory(priority, gfp_mask);
- /*
- * Not currently working, see fixme in shrink_?cache_memory
- * In the inner funtions there is a comment:
- * "To help debugging, a zero exit status indicates
- * all slabs were released." (-arca?)
- * lets handle it in a primitive but working way...
- * if (count <= 0)
- * goto done;
- */
- if (!keep_kswapd_awake())
- goto done;
-
- while (shm_swap(priority, gfp_mask)) {
- if (!--count)
+ do {
+ freed = shrink_icache_memory(count, priority, gfp_mask);
+ count -= freed;
+ if (count <= 0)
+ goto done;
+ freed = shrink_dcache_memory(count, priority, gfp_mask);
+ count -= freed;
+ if (count <= 0)
+ goto done;
+ freed = shrink_icache_memory(count, priority, gfp_mask);
+ count -= freed;
+ if (count <= 0)
goto done;
- }
+ } while (freed);
}
/*
@@ -598,6 +606,7 @@
* trying to free the first piece of memory in the first place).
*/
tsk->flags |= PF_MEMALLOC;
+ tsk->flags |= PF_ATOMICALLOC;
for (;;) {
if (!keep_kswapd_awake()) {
@@ -625,7 +634,7 @@
*/
int try_to_free_pages(unsigned int gfp_mask)
{
- int retval = 1;
+ int retval = 0;
if (gfp_mask & __GFP_WAIT) {
current->state = TASK_RUNNING;
--- linux/mm/debug.c.orig Fri Sep 1 07:28:26 2000
+++ linux/mm/debug.c Fri Sep 1 07:28:26 2000
@@ -0,0 +1,48 @@
+
+#include <linux/config.h>
+#include <linux/mm.h>
+#include <linux/kernel_stat.h>
+#include <linux/swap.h>
+#include <linux/swapctl.h>
+#include <linux/interrupt.h>
+#include <linux/init.h>
+#include <linux/bootmem.h>
+
+int printk_running = 1;
+char printk_buffer[10240];
+
+#define vmem ((char *)(PAGE_OFFSET+0xb8000))
+
+void __early_printk(char * str)
+{
+ char num [100];
+ int i;
+ static int x = 0;
+ static int y = 0;
+ static int line = 0;
+ int s_len = strlen(str), num_len;
+
+ num_len = sprintf(num, "<%03d> ", line);
+ num[num_len] = 0;
+
+#define early_putc(c,row,line,color) \
+ { vmem[2*(row)+(line)] = (c); vmem[2*(row)+(line)+1] = (color);}
+
+ for (i = 0; i < num_len; i++)
+ early_putc(num[i], 70+i, 10*2*80, 0x1f);
+ for (i = 0; i < num_len; i++)
+ early_putc(num[i], i, y, 0x2f);
+
+ x = num_len;
+ for (i = 0; i < s_len; i++) {
+ if (str[i] == '\n') {
+ line++;
+ y += 2*80;
+ x = 0;
+ if (y >= 25*2*80)
+ y = 0;
+ }
+ early_putc(str[i], x, y, 0x3f);
+ x++;
+ }
+}
--- linux/mm/Makefile.orig Mon Dec 6 19:14:13 1999
+++ linux/mm/Makefile Fri Sep 1 07:28:26 2000
@@ -16,4 +16,5 @@
O_OBJS += highmem.o
endif
+O_OBJS += debug.o
include $(TOPDIR)/Rules.make
--- linux/mm/vmalloc.c.orig Fri Sep 1 07:26:59 2000
+++ linux/mm/vmalloc.c Fri Sep 1 07:28:26 2000
@@ -126,6 +126,8 @@
return -ENOMEM;
if (alloc_area_pte(pte, address, end - address, gfp_mask, prot))
return -ENOMEM;
+ if (!pmd_val(*pmd))
+ BUG();
address = (address + PMD_SIZE) & PMD_MASK;
pmd++;
} while (address < end);
@@ -143,7 +145,9 @@
do {
pmd_t *pmd;
pgd_t olddir = *dir;
-
+
+ if (pgd_none(*dir))
+ BUG();
pmd = pmd_alloc_kernel(dir, address);
if (!pmd)
return -ENOMEM;
@@ -151,6 +155,8 @@
return -ENOMEM;
if (pgd_val(olddir) != pgd_val(*dir))
set_pgdir(address, *dir);
+ if (!pgd_val(*dir))
+ BUG();
address = (address + PGDIR_SIZE) & PGDIR_MASK;
dir++;
} while (address && (address < end));
--- linux/mm/page_alloc.c.orig Fri Sep 1 07:26:59 2000
+++ linux/mm/page_alloc.c Fri Sep 1 07:37:15 2000
@@ -29,9 +29,9 @@
pg_data_t *pgdat_list;
static char *zone_names[MAX_NR_ZONES] = { "DMA", "Normal", "HighMem" };
-static int zone_balance_ratio[MAX_NR_ZONES] = { 32, 128, 128, };
-static int zone_balance_min[MAX_NR_ZONES] = { 10 , 10, 10, };
-static int zone_balance_max[MAX_NR_ZONES] = { 255 , 255, 255, };
+static int zone_balance_ratio[MAX_NR_ZONES] = { 32, 128, 1, };
+static int zone_balance_min[MAX_NR_ZONES] = { 10 , 10, 0, };
+static int zone_balance_max[MAX_NR_ZONES] = { 255 , 255, 0, };
/*
* Free_page() adds the page to the free lists. This is optimized for
@@ -220,6 +220,10 @@
{
zone_t **zone;
extern wait_queue_head_t kswapd_wait;
+ int gfp_mask = zonelist->gfp_mask, count = 0;
+
+ if (in_interrupt() && (gfp_mask & __GFP_WAIT))
+ BUG();
/*
* (If anyone calls gfp from interrupts nonatomically then it
@@ -229,6 +233,7 @@
* in a higher zone fails.
*/
+repeat:
zone = zonelist->zones;
for (;;) {
zone_t *z = *(zone++);
@@ -289,11 +294,10 @@
* been able to cope..
*/
if (!(current->flags & PF_MEMALLOC)) {
- int gfp_mask = zonelist->gfp_mask;
- if (!try_to_free_pages(gfp_mask)) {
- if (!(gfp_mask & __GFP_HIGH))
- goto fail;
- }
+ if (try_to_free_pages(gfp_mask))
+ goto repeat;
+ if ((gfp_mask & __GFP_WAIT) && !(gfp_mask & __GFP_HIGH))
+ goto wait_for_more;
}
/*
@@ -311,8 +315,36 @@
return page;
}
-fail:
+ if (!(current->flags & PF_MEMALLOC) && !(current->flags & PF_ATOMICALLOC) && (gfp_mask & __GFP_WAIT)) {
+ int c;
+wait_for_more:
+ if (try_to_free_pages(gfp_mask))
+ goto repeat;
+ if (try_to_free_pages(gfp_mask))
+ goto repeat;
+ c = current->counter;
+ if (c)
+ current->counter = c-1;
+ current->policy |= SCHED_YIELD;
+ schedule();
+ if (++count > 100) {
+ count = 0;
+ printk("\npotential BUG: page allocator endless loop!\n... gfp(order:%ld, flags:%d, zone:%s).\n... Stack trace where we are looping is:\n", order, gfp_mask, zonelist->zones[0]->name);
+ }
+ goto repeat;
+ } else {
+ if (gfp_mask & __GFP_WAIT) {
+ if (try_to_free_pages(gfp_mask))
+ goto repeat;
+ if (try_to_free_pages(gfp_mask))
+ goto repeat;
+ if (try_to_free_pages(gfp_mask))
+ goto repeat;
+ }
+ }
/* No luck.. */
+ if (count++ < 10)
+ goto repeat;
return NULL;
}
@@ -513,6 +545,9 @@
zone = pgdat->node_zones + ZONE_NORMAL;
if (zone->size)
zonelist->zones[j++] = zone;
+ if ((i && __GFP_WAIT) || !(i && __GFP_HIGH) ||
+ (i && __GFP_IO))
+ break;
case ZONE_DMA:
zone = pgdat->node_zones + ZONE_DMA;
if (zone->size)
--- linux/include/linux/sched.h.orig Fri Sep 1 07:27:07 2000
+++ linux/include/linux/sched.h Fri Sep 1 07:31:46 2000
@@ -373,7 +373,11 @@
int (*notifier)(void *priv);
void *notifier_data;
sigset_t *notifier_mask;
-
+
+/* HTTP stack state */
+ int http;
+ void *http_info;
+
/* Thread group tracking */
u32 parent_exec_id;
u32 self_exec_id;
@@ -396,6 +400,7 @@
#define PF_VFORK 0x00001000 /* Wake up parent in mm_release */
#define PF_USEDFPU 0x00100000 /* task used FPU this quantum (SMP) */
+#define PF_ATOMICALLOC 0x00400000 /* process never syncs in gfp()*/
/*
* Ptrace flags
--- linux/include/linux/kernel_stat.h.orig Fri Sep 1 07:26:53 2000
+++ linux/include/linux/kernel_stat.h Fri Sep 1 07:31:45 2000
@@ -33,9 +33,59 @@
unsigned int ierrors, oerrors;
unsigned int collisions;
unsigned int context_swtch;
+ unsigned int context_swtch_cross;
+ unsigned int nr_urlo;
+ unsigned int nr_urlo_references;
+ unsigned int nr_free_pending;
+ unsigned int nr_allocated;
+ unsigned int nr_idle_input_pending;
+ unsigned int nr_input_pending;
+ unsigned int nr_cachemiss_pending;
+ unsigned int nr_secondary_pending;
+ unsigned int nr_output_pending;
+ unsigned int nr_redirect_pending;
+ unsigned int nr_finish_pending;
+ unsigned int nr_userspace_pending;
+ unsigned int csumcache_total;
+#define URLC_HIST_SIZE 1000
+ unsigned int urlo_hist_hits[URLC_HIST_SIZE];
+ unsigned int urlo_hist_misses[URLC_HIST_SIZE];
+ unsigned int inputqueue_got_packet;
+ unsigned int inputqueue_no_packet;
+ unsigned int nr_keepalive_optimized;
+
+ unsigned int parse_static_incomplete;
+ unsigned int parse_static_redirect;
+ unsigned int parse_static_cachemiss;
+ unsigned int parse_static_nooutput;
+ unsigned int parse_static_normal;
+ unsigned int parse_dynamic_incomplete;
+ unsigned int parse_dynamic_redirect;
+ unsigned int parse_dynamic_cachemiss;
+ unsigned int parse_dynamic_nooutput;
+ unsigned int parse_dynamic_normal;
+ unsigned int complete_parsing;
};
+
extern struct kernel_stat kstat;
+
+extern inline void urlo_hist_hit (int size)
+{
+ unsigned int idx = size/1024;
+
+ if (idx >= URLC_HIST_SIZE)
+ idx = URLC_HIST_SIZE-1;
+ kstat.urlo_hist_hits[idx]++;
+}
+extern inline void urlo_hist_miss (int size)
+{
+ unsigned int idx = size/1024;
+
+ if (idx >= URLC_HIST_SIZE)
+ idx = URLC_HIST_SIZE-1;
+ kstat.urlo_hist_misses[idx]++;
+}
#if !defined(CONFIG_ARCH_S390)
/*
--- linux/include/linux/skbuff.h.orig Fri Sep 1 07:27:06 2000
+++ linux/include/linux/skbuff.h Fri Sep 1 07:31:46 2000
@@ -10,7 +10,8 @@
* as published by the Free Software Foundation; either version
* 2 of the License, or (at your option) any later version.
*/
-
+
+//#define INET_REFCNT_DEBUG 1
#ifndef _LINUX_SKBUFF_H
#define _LINUX_SKBUFF_H
@@ -57,6 +58,22 @@
spinlock_t lock;
};
+struct sk_buff;
+
+#define MAX_SKB_FRAGS 4
+
+typedef struct skb_frag_struct skb_frag_t;
+struct skb_frag_struct {
+ unsigned int csum;
+ int size;
+ struct page *page;
+ int page_offset;
+
+ void (*frag_done) (struct sk_buff *skb, skb_frag_t *frag);
+ void *data;
+ void *private;
+};
+
struct sk_buff {
/* These two members must be first. */
struct sk_buff * next; /* Next buffer in list */
@@ -108,6 +125,8 @@
char cb[48];
unsigned int len; /* Length of actual data */
+ unsigned int data_len;
+
unsigned int csum; /* Checksum */
volatile char used; /* Data moved to user and not MSG_PEEK */
unsigned char is_clone, /* We are a clone */
@@ -124,6 +143,10 @@
unsigned char *data; /* Data head pointer */
unsigned char *tail; /* Tail pointer */
unsigned char *end; /* End pointer */
+
+ int nr_frags;
+ skb_frag_t * frags[MAX_SKB_FRAGS];
+
void (*destructor)(struct sk_buff *); /* Destruct function */
#ifdef CONFIG_NETFILTER
/* Can be used for communication between hooks. */
@@ -146,6 +169,8 @@
#ifdef CONFIG_NET_SCHED
__u32 tc_index; /* traffic control index */
#endif
+ struct timer_list delay_timer;
+ struct net_device *delay_dev;
};
#define SK_WMEM_MAX 65535
@@ -223,14 +248,18 @@
static inline void kfree_skb(struct sk_buff *skb)
{
- if (atomic_read(&skb->users) == 1 || atomic_dec_and_test(&skb->users))
+ if (!atomic_read(&skb->users))
+ BUG();
+ if (atomic_dec_and_test(&skb->users))
__kfree_skb(skb);
}
/* Use this if you didn't touch the skb state [for fast switching] */
static inline void kfree_skb_fast(struct sk_buff *skb)
{
- if (atomic_read(&skb->users) == 1 || atomic_dec_and_test(&skb->users))
+ if (!atomic_read(&skb->users))
+ BUG();
+ if (atomic_dec_and_test(&skb->users))
kfree_skbmem(skb);
}
@@ -688,6 +717,8 @@
static inline unsigned char *__skb_put(struct sk_buff *skb, unsigned int len)
{
unsigned char *tmp=skb->tail;
+ if (skb->nr_frags)
+ BUG();
skb->tail+=len;
skb->len+=len;
return tmp;
@@ -706,6 +737,8 @@
static inline unsigned char *skb_put(struct sk_buff *skb, unsigned int len)
{
unsigned char *tmp=skb->tail;
+ if (skb->nr_frags)
+ BUG();
skb->tail+=len;
skb->len+=len;
if(skb->tail>skb->end) {
@@ -807,6 +840,8 @@
static inline void __skb_trim(struct sk_buff *skb, unsigned int len)
{
+ if (skb->nr_frags)
+ BUG();
skb->len = len;
skb->tail = skb->data+len;
}
@@ -822,9 +857,10 @@
static inline void skb_trim(struct sk_buff *skb, unsigned int len)
{
- if (skb->len > len) {
+ if (skb->nr_frags)
+ BUG();
+ if (skb->len > len)
__skb_trim(skb, len);
- }
}
/**
@@ -959,6 +995,13 @@
if (nfct)
atomic_inc(&nfct->master->use);
}
+#endif
+
+struct http_req_struct;
+#ifdef CONFIG_HTTP
+extern void idle_event (struct http_req_struct *req);
+#else
+static inline void idle_event (struct http_req_struct *req) { }
#endif
#endif /* __KERNEL__ */
--- linux/include/linux/list.h.orig Fri Sep 1 07:26:59 2000
+++ linux/include/linux/list.h Fri Sep 1 07:28:26 2000
@@ -90,6 +90,7 @@
static __inline__ void list_del(struct list_head *entry)
{
__list_del(entry->prev, entry->next);
+ entry->prev = entry->next = entry;
}
/**
--- linux/include/linux/sysctl.h.orig Fri Sep 1 07:27:06 2000
+++ linux/include/linux/sysctl.h Fri Sep 1 07:28:26 2000
@@ -128,7 +128,7 @@
VM_PAGECACHE=7, /* struct: Set cache memory thresholds */
VM_PAGERDAEMON=8, /* struct: Control kswapd behaviour */
VM_PGT_CACHE=9, /* struct: Set page table cache parameters */
- VM_PAGE_CLUSTER=10 /* int: set number of pages to swap together */
+ VM_PAGE_CLUSTER=10, /* int: set number of pages to swap together */
};
@@ -151,7 +151,8 @@
NET_TR=14,
NET_DECNET=15,
NET_ECONET=16,
- NET_KHTTPD=17
+ NET_HTTP=17,
+ NET_KHTTPD=18
};
/* /proc/sys/kernel/random */
@@ -454,6 +455,33 @@
NET_DECNET_DST_GC_INTERVAL = 9,
NET_DECNET_CONF = 10,
NET_DECNET_DEBUG_LEVEL = 255
+};
+
+/* /proc/sys/net/http/ */
+enum {
+ NET_HTTP_DOCROOT = 1,
+ NET_HTTP_LOGFILE = 2,
+ NET_HTTP_EXTCGI = 3,
+ NET_HTTP_START = 4,
+ NET_HTTP_STOP = 5,
+ NET_HTTP_UNLOAD = 6,
+ NET_HTTP_CLIENTPORT = 7,
+ NET_HTTP_LOGGING = 8,
+ NET_HTTP_SERVERPORT = 9,
+ NET_HTTP_THREADS = 10,
+ NET_HTTP_KEEPALIVE_TIMEOUT = 11,
+ NET_HTTP_MAX_CONNECT = 12,
+ NET_HTTP_MAX_BACKLOG = 13,
+ NET_HTTP_MAX_CACHED_FILESIZE = 14,
+ NET_HTTP_MODE_FORBIDDEN = 15,
+ NET_HTTP_MODE_ALLOWED = 16,
+ NET_HTTP_MODE_USERSPACE = 17,
+ NET_HTTP_MODE_CGI = 18,
+ NET_HTTP_LOGENTRY_ALIGN_ORDER = 19,
+ NET_HTTP_NAGLE = 20,
+ NET_HTTP_IN_PACKET_DELAY = 21,
+ NET_HTTP_OUT_PACKET_DELAY = 22,
+ NET_HTTP_NEW_API = 23
};
/* /proc/sys/net/khttpd/ */
--- linux/include/linux/dcache.h.orig Fri Sep 1 07:26:42 2000
+++ linux/include/linux/dcache.h Fri Sep 1 07:31:45 2000
@@ -163,12 +163,12 @@
#define shrink_dcache() prune_dcache(0)
struct zone_struct;
/* dcache memory management */
-extern int shrink_dcache_memory(int, unsigned int);
+extern int shrink_dcache_memory(int count, int priority, unsigned int gfp_mask);
extern void prune_dcache(int);
/* icache memory management (defined in linux/fs/inode.c) */
-extern int shrink_icache_memory(int, int);
-extern void prune_icache(int);
+extern int shrink_icache_memory(int, int, int);
+extern int prune_icache(int priority, int goal);
/* only used at mount-time */
extern struct dentry * d_alloc_root(struct inode *);
--- linux/include/linux/netdevice.h.orig Fri Sep 1 07:27:06 2000
+++ linux/include/linux/netdevice.h Fri Sep 1 07:31:46 2000
@@ -338,6 +338,8 @@
int (*stop)(struct net_device *dev);
int (*hard_start_xmit) (struct sk_buff *skb,
struct net_device *dev);
+ int (*hard_start_xmit_dual) (struct sk_buff *skb,
+ struct net_device *dev);
int (*hard_header) (struct sk_buff *skb,
struct net_device *dev,
unsigned short type,
@@ -502,6 +504,8 @@
*/
static inline void dev_kfree_skb_irq(struct sk_buff *skb)
{
+ if (!atomic_read(&skb->users))
+ BUG();
if (atomic_dec_and_test(&skb->users)) {
int cpu =smp_processor_id();
unsigned long flags;
--- linux/include/linux/fs.h.orig Fri Sep 1 07:27:06 2000
+++ linux/include/linux/fs.h Fri Sep 1 07:31:46 2000
@@ -354,6 +354,7 @@
int (*commit_write)(struct file *, struct page *, unsigned, unsigned);
/* Unfortunately this kludge is needed for FIBMAP. Don't use it */
int (*bmap)(struct address_space *, long);
+ unsigned long (*destroy)(struct inode *);
};
struct address_space {
@@ -363,6 +364,7 @@
void *host; /* owner: inode, block_device */
struct vm_area_struct *i_mmap; /* list of mappings */
spinlock_t i_shared_lock; /* and spinlock protecting it */
+ void *http_data;
};
struct block_device {
@@ -542,6 +544,10 @@
extern int fcntl_getlk(unsigned int, struct flock *);
extern int fcntl_setlk(unsigned int, unsigned int, struct flock *);
+extern asmlinkage long sys_fcntl(unsigned int fd, unsigned int cmd, unsigned long arg);
+extern asmlinkage long sys_dup(unsigned int fildes);
+extern asmlinkage long sys_dup2(unsigned int oldfd, unsigned int newfd);
+
extern int fcntl_getlk64(unsigned int, struct flock64 *);
extern int fcntl_setlk64(unsigned int, unsigned int, struct flock64 *);
@@ -695,6 +701,8 @@
extern int vfs_unlink(struct inode *, struct dentry *);
extern int vfs_rename(struct inode *, struct dentry *, struct inode *, struct dentry *);
+loff_t __llseek(struct file *file, loff_t offset, int origin);
+
/*
* File types
*/
@@ -1008,6 +1016,7 @@
extern int check_disk_change(kdev_t);
extern int invalidate_inodes(struct super_block *);
extern void invalidate_inode_pages(struct inode *);
+extern void flush_inode_pages(struct inode *);
#define invalidate_buffers(dev) __invalidate_buffers((dev), 0)
#define destroy_buffers(dev) __invalidate_buffers((dev), 1)
extern void __invalidate_buffers(kdev_t dev, int);
@@ -1066,6 +1075,7 @@
#define LOOKUP_POSITIVE (8)
#define LOOKUP_PARENT (16)
#define LOOKUP_NOALT (32)
+#define LOOKUP_ATOMIC (64)
/*
* Type of the last component on LOOKUP_PARENT
*/
@@ -1103,7 +1113,13 @@
#define user_path_walk(name,nd) __user_walk(name, LOOKUP_FOLLOW|LOOKUP_POSITIVE, nd)
#define user_path_walk_link(name,nd) __user_walk(name, LOOKUP_POSITIVE, nd)
-extern void iput(struct inode *);
+extern void iput (struct inode *);
+/*
+ * This variant of iput() marks the inode as a top
+ * candidate to be freed. Simple iput preserves the
+ * LRU list.
+ */
+extern void iput_free (struct inode *);
extern void force_delete(struct inode *);
extern struct inode * igrab(struct inode *);
extern ino_t iunique(struct super_block *, ino_t);
--- linux/include/linux/socket.h.orig Fri Sep 1 07:26:42 2000
+++ linux/include/linux/socket.h Fri Sep 1 07:31:45 2000
@@ -209,6 +209,7 @@
#define MSG_RST 0x1000
#define MSG_ERRQUEUE 0x2000 /* Fetch message from error queue */
#define MSG_NOSIGNAL 0x4000 /* Do not generate SIGPIPE */
+#define MSG_NO_PUSH 0x8000 /* Sender will send more */
#define MSG_EOF MSG_FIN
@@ -251,6 +252,8 @@
extern int move_addr_to_user(void *kaddr, int klen, void *uaddr, int *ulen);
extern int move_addr_to_kernel(void *uaddr, int ulen, void *kaddr);
extern int put_cmsg(struct msghdr*, int level, int type, int len, void *data);
+struct socket;
+extern int sock_map_fd(struct socket *sock);
#endif
#endif /* not kernel and not glibc */
#endif /* _LINUX_SOCKET_H */
--- linux/include/linux/debug.h.orig Fri Sep 1 07:28:26 2000
+++ linux/include/linux/debug.h Fri Sep 1 07:28:26 2000
@@ -0,0 +1,13 @@
+#ifndef _LINUX_DEBUG_H
+#define _LINUX_DEBUG_H
+
+extern int sprintf(char * buf, const char * fmt, ...);
+
+extern int printk_running;
+extern char printk_buffer[10240];
+extern void __early_printk(char * str);
+#define early_printk(v...) do { if (!printk_running) { unsigned int len = sprintf(printk_buffer,v); printk_buffer[len] = 0; __early_printk(printk_buffer); } printk(v); } while (0)
+#define STOP() for (;;) __cli()
+#define EARLY_BUG() { early_printk("EARLY_BUG at: %s:%d %p,%p\n", __FILE__, __LINE__, __builtin_return_address(0), __builtin_return_address(1)); STOP(); }
+
+#endif /* _LINUX_DEBUG_H */
--- linux/include/linux/wait.h.orig Fri Sep 1 07:27:07 2000
+++ linux/include/linux/wait.h Fri Sep 1 07:45:27 2000
@@ -17,7 +17,6 @@
#include <asm/page.h>
#include <asm/processor.h>
-
/*
* Temporary debugging help until all code is converted to the new
* waitqueue usage.
--- linux/include/asm-i386/page.h.orig Fri Sep 1 07:26:58 2000
+++ linux/include/asm-i386/page.h Fri Sep 1 07:31:45 2000
@@ -78,7 +78,7 @@
* amd CONFIG_HIGHMEM64G options in the kernel configuration.
*/
-#define __PAGE_OFFSET (0xC0000000)
+#define __PAGE_OFFSET (0x40000000)
#ifndef __ASSEMBLY__
--- linux/include/asm-i386/kmap_types.h.orig Thu Nov 11 19:33:42 1999
+++ linux/include/asm-i386/kmap_types.h Fri Sep 1 07:28:26 2000
@@ -4,6 +4,7 @@
enum km_type {
KM_BOUNCE_READ,
KM_BOUNCE_WRITE,
+ KM_SKB_DATA,
KM_TYPE_NR
};
--- linux/include/asm-i386/unistd.h.orig Fri Sep 1 07:27:05 2000
+++ linux/include/asm-i386/unistd.h Fri Sep 1 07:28:26 2000
@@ -351,6 +351,8 @@
return waitpid(-1,wait_stat,0);
}
+extern asmlinkage ssize_t sys_read(unsigned int fd, char * buf, size_t count);
+
#endif
#endif /* _ASM_I386_UNISTD_H_ */
--- linux/include/asm-i386/hw_irq.h.orig Thu May 25 04:52:41 2000
+++ linux/include/asm-i386/hw_irq.h Fri Sep 1 07:31:45 2000
@@ -181,7 +181,6 @@
extern unsigned int * prof_buffer;
extern unsigned long prof_len;
extern unsigned long prof_shift;
-
/*
* x86 profiling function, SMP safe. We might want to do this in
* assembly totally?
--- linux/include/asm-i386/fcntl.h.orig Fri Sep 1 07:27:05 2000
+++ linux/include/asm-i386/fcntl.h Fri Sep 1 07:28:26 2000
@@ -20,6 +20,7 @@
#define O_LARGEFILE 0100000
#define O_DIRECTORY 0200000 /* must be a directory */
#define O_NOFOLLOW 0400000 /* don't follow links */
+#define O_ATOMICLOOKUP 01000000 /* do atomic file lookup */
#define F_DUPFD 0 /* dup */
#define F_GETFD 1 /* get close_on_exec */
--- linux/include/net/sock.h.orig Fri Sep 1 07:27:06 2000
+++ linux/include/net/sock.h Fri Sep 1 07:31:46 2000
@@ -653,6 +653,8 @@
/* RPC layer private data */
void *user_data;
+ /* HTTP layer private data */
+ void *http_data;
/* Callbacks */
void (*state_change)(struct sock *sk);
@@ -779,7 +781,7 @@
if ((__sk)->backlog.tail != NULL) \
__release_sock(__sk); \
(__sk)->lock.users = 0; \
- if (waitqueue_active(&((__sk)->lock.wq))) wake_up(&((__sk)->lock.wq)); \
+ /*if (waitqueue_active(&((__sk)->lock.wq))) */ wake_up(&((__sk)->lock.wq)); \
spin_unlock_bh(&((__sk)->lock.slock)); \
} while(0)
@@ -1215,6 +1217,7 @@
{
if (sk->socket && sk->socket->fasync_list)
sock_wake_async(sk->socket, how, band);
+ if (sk->http_data) idle_event(sk->http_data);
}
#define SOCK_MIN_SNDBUF 2048
--- linux/include/net/tcp.h.orig Fri Sep 1 07:27:06 2000
+++ linux/include/net/tcp.h Fri Sep 1 07:32:21 2000
@@ -321,7 +321,7 @@
#define TCP_TWKILL_PERIOD (TCP_TIMEWAIT_LEN/TCP_TWKILL_SLOTS)
#define TCP_SYNQ_INTERVAL (HZ/5) /* Period of SYNACK timer */
-#define TCP_SYNQ_HSIZE 64 /* Size of SYNACK hash table */
+#define TCP_SYNQ_HSIZE 512 /* Size of SYNACK hash table */
#define TCP_PAWS_24DAYS (60 * 60 * 24 * 24)
#define TCP_PAWS_MSL 60 /* Per-host timestamps are invalidated
@@ -609,7 +609,8 @@
extern int tcp_v4_tw_remember_stamp(struct tcp_tw_bucket *tw);
extern int tcp_sendmsg(struct sock *sk, struct msghdr *msg, int size);
-
+extern int tcp_create_skbcache(struct sock *sk, struct msghdr *msg, int size, struct sk_buff **skbcache);
+extern int tcp_send_skbcache(struct sock *sk, int flags, struct sk_buff *skb, int datalen);
extern int tcp_ioctl(struct sock *sk,
int cmd,
unsigned long arg);
@@ -1271,13 +1272,14 @@
__skb_queue_tail(&tp->ucopy.prequeue, skb);
if (skb_queue_len(&tp->ucopy.prequeue) == 1) {
wake_up_interruptible(sk->sleep);
+ if (sk->http_data) idle_event(sk->http_data);
if (!tcp_ack_scheduled(tp))
tcp_reset_xmit_timer(sk, TCP_TIME_DACK, (3*TCP_RTO_MIN)/4);
}
} else {
NET_INC_STATS_BH(TCPPrequeueDropped);
tp->ucopy.memory -= skb->truesize;
- __kfree_skb(skb);
+ kfree_skb(skb);
}
return 1;
}
@@ -1320,7 +1322,8 @@
#ifdef STATE_TRACE
SOCK_DEBUG(sk, "TCP sk=%p, State %s -> %s\n",sk, statename[oldstate],statename[state]);
-#endif
+#endif
+ if (sk->http_data) idle_event(sk->http_data);
}
static __inline__ void tcp_done(struct sock *sk)
@@ -1603,7 +1606,7 @@
sk->tp_pinfo.af_tcp.queue_shrunk = 1;
sk->wmem_queued -= skb->truesize;
sk->forward_alloc += skb->truesize;
- __kfree_skb(skb);
+ kfree_skb(skb);
}
static inline void tcp_charge_skb(struct sock *sk, struct sk_buff *skb)
@@ -1645,7 +1648,7 @@
if (sk->forward_alloc >= (int)skb->truesize ||
tcp_mem_schedule(sk, skb->truesize, 0))
return skb;
- __kfree_skb(skb);
+ kfree_skb(skb);
} else {
tcp_enter_memory_pressure();
tcp_moderate_sndbuf(sk);
--- linux/include/net/http.h.orig Fri Sep 1 07:28:26 2000
+++ linux/include/net/http.h Fri Sep 1 07:37:57 2000
@@ -0,0 +1,529 @@
+#ifndef _NET_HTTP_HTTP_H
+#define _NET_HTTP_HTTP_H
+
+/*
+ * TUX - Integrated HTTP layer and Object Cache
+ *
+ * Copyright (C) 2000, Ingo Molnar <
[email protected]>
+ *
+ * http.h: main structure definitions and function prototypes
+ */
+
+#define __KERNEL_SYSCALLS__
+
+#include <linux/mm.h>
+#include <linux/net.h>
+#include <linux/wait.h>
+#include <linux/file.h>
+#include <linux/mman.h>
+#include <linux/ctype.h>
+#include <linux/config.h>
+#include <linux/module.h>
+#include <linux/kernel.h>
+#include <linux/unistd.h>
+#include <linux/sysctl.h>
+#include <linux/proc_fs.h>
+#include <linux/pagemap.h>
+#include <linux/vmalloc.h>
+#include <linux/smp_lock.h>
+#include <linux/kernel_stat.h>
+#include <linux/kernel_stat.h>
+
+#include <asm/unaligned.h>
+
+#include <net/tcp.h>
+#include <net/http_u.h>
+
+/* Maximum number of threads: */
+#define CONFIG_HTTP_NUMTHREADS 16
+
+/* Maximum number of listen sockets per thread: */
+#define CONFIG_HTTP_NUMSOCKETS 4
+
+extern unsigned int http_listen [CONFIG_HTTP_NUMTHREADS][CONFIG_HTTP_NUMSOCKETS];
+
+#undef Dprintk
+
+extern int http_Dprintk;
+
+#if CONFIG_HTTP_DEBUG
+# define HTTP_BUG() BUG()
+
+# define INC_STAT(x) atomic_inc((atomic_t *)&kstat.##x)
+# define DEC_STAT(x) atomic_dec((atomic_t *)&kstat.##x)
+# define HTTP_DPRINTK 1
+# define Dprintk(x...) do { if (http_Dprintk) { printk("<%ld:%s:%d>: ", jiffies, __FILE__, __LINE__); printk(x); } } while (0)
+#else
+# define HTTP_DPRINTK 0
+# define Dprintk(x...) do { } while (0)
+# define INC_STAT(x) do { } while (0)
+# define DEC_STAT(x) do { } while (0)
+//# define HTTP_BUG() BUG()
+# define HTTP_BUG() do { } while (0)
+#endif
+
+#define HTTP_VERSION "TUX 1.0"
+
+#define LOG_BUF_ORDER 9
+#define OUT_BUF_ORDER 8
+
+#define MAX_BLOCKSIZE (PAGE_SIZE * (1<<OUT_BUF_ORDER))
+
+typedef struct csumcache_struct csumcache_t;
+typedef struct urlobject_struct urlobj_t;
+typedef struct http_req_struct http_req_t;
+typedef struct http_threadinfo threadinfo_t;
+typedef struct tcapi_template_s tcapi_template_t;
+
+#define MAX_SSIMAP_ENTRIES 16
+
+typedef struct SSImap_t_s {
+ int nr;
+ int pos[MAX_SSIMAP_ENTRIES];
+ int size[MAX_SSIMAP_ENTRIES];
+} SSImap_t;
+
+struct csumcache_struct {
+ int size;
+ int packet_size;
+ skb_frag_t *array;
+ csumcache_t *next;
+ int SSI;
+ unsigned int __filler[0];
+};
+
+extern struct address_space_operations url_aops;
+
+struct urlobject_struct {
+ csumcache_t *csumc;
+ struct inode *inode;
+ atomic_t users;
+ struct list_head secondary_pending;
+ int header_len;
+ int body_len;
+ int filelen;
+ int SSI;
+ tcapi_template_t *tcapi;
+ atomic_t csumcs_created;
+ struct address_space_operations *real_aops;
+};
+
+extern inline void get_urlo (urlobj_t *urlo)
+{
+#if HTTP_DPRINTK
+ __label__ __y;
+__y:
+#endif
+ Dprintk("get_urlo(%p) - <%p, %p>\n", urlo, &&__y, __builtin_return_address(0));
+ atomic_inc(&urlo->users);
+ INC_STAT(nr_urlo_references);
+}
+
+extern unsigned long __put_urlo (urlobj_t *urlo);
+
+extern inline unsigned long put_urlo (urlobj_t *urlo)
+{
+#if HTTP_DPRINTK
+ __label__ __y;
+#endif
+ unsigned long freed_bytes = 0;
+#if HTTP_DPRINTK
+__y:
+#endif
+ Dprintk("put_urlo(%p) - <%p, %p>\n", urlo, &&__y, __builtin_return_address(0));
+ if (urlo && !atomic_read(&urlo->users))
+ HTTP_BUG();
+ if (urlo && atomic_dec_and_test(&urlo->users))
+ freed_bytes += __put_urlo(urlo);
+ if (urlo)
+ DEC_STAT(nr_urlo_references);
+
+ return freed_bytes;
+}
+
+#define mapping_to_urlo(m) ((urlobj_t *)(m)->http_data)
+#define inode_to_urlo(i) (mapping_to_urlo((i)->i_mapping))
+#define dentry_to_urlo(d) (inode_to_urlo((d)->d_inode))
+#define filp_to_urlo(f) (dentry_to_urlo((f)->f_dentry))
+
+struct tcapi_template_s {
+ char *vfs_name;
+ char *version;
+ struct list_head modules;
+ int (*query) (http_req_t *req);
+ int (*send_reply) (http_req_t *req);
+ void (*create_SSI_map) (http_req_t *req, csumcache_t *csumc,
+ unsigned char *buf, int len, SSImap_t *SSImap);
+ int (*generate_SSI_entry) (http_req_t *req, skb_frag_t *frag);
+ struct module *mod;
+ int userspace_id;
+};
+
+#define HTTP_MAGIC 0x12457801
+
+struct http_req_struct
+{
+ struct list_head all;
+ struct list_head free;
+ struct list_head input;
+ struct list_head userspace;
+ struct list_head cachemiss;
+ struct list_head output;
+ struct list_head redirect;
+ struct list_head finish;
+
+ unsigned int idle_input;
+
+ struct socket *sock;
+ struct dentry *dentry;
+ /*
+ * URL Object being processed now (mostly means a pending cachemiss).
+ * NULL if none.
+ */
+ urlobj_t *urlo;
+ urlobj_t *prev_urlo;
+ tcapi_template_t *tcapi;
+ int redirect_secondary;
+ int SSI;
+
+ int userspace_module;
+ int userspace_fd;
+
+ threadinfo_t *ti;
+ wait_queue_t sleep;
+
+ /*
+ * Parsed HTTP message attributes.
+ * Strings are zero-delimited.
+ */
+
+#define MAX_HEADER_LEN 1024
+ char headers[MAX_HEADER_LEN];
+ int headers_len;
+
+ int parsed_len;
+
+ http_method_t method;
+ char *method_str;
+ int method_len;
+
+ http_version_t version;
+ char *version_str;
+ int version_len;
+
+ /* requested URI: */
+
+ char *uri;
+ int uri_len;
+
+ /* Objectname (filename/scriptname) this URI refers to: */
+
+ char *objectname;
+ int objectname_len;
+
+ /* Query string within the URI: */
+
+ char *query;
+ int query_len;
+
+ /* Cookies: */
+
+ char *cookies;
+ int cookies_len;
+ int parse_cookies;
+
+ /* Content-Length: */
+
+ char *contentlen;
+ int contentlen_strlen;
+ int content_len;
+
+ /* POSTed data: */
+
+ char *post_data;
+ int post_data_len;
+
+ unsigned long timestamp;
+ int http_status;
+
+ /* the file being sent */
+
+ int bytes_sent;
+ int body_len;
+
+ int keep_alive;
+ struct timer_list keepalive_timer;
+
+ int no_output;
+
+ int event;
+
+ void *private;
+
+ unsigned int magic;
+ void (*old_data_ready)(struct sock *, int);
+ void (*old_state_change)(struct sock *);
+ void (*old_write_space)(struct sock *);
+ void (*old_destruct)(struct sock *);
+
+ char tmpbuf[MAX_HEADER_LEN];
+};
+
+
+struct http_threadinfo
+{
+ http_req_t *userspace_req;
+ int started;
+ struct semaphore used;
+ struct task_struct *thread;
+ wait_queue_t wait_event [CONFIG_HTTP_NUMSOCKETS];
+ wait_queue_t stop;
+ int pid;
+
+ int nr_requests;
+ struct list_head all_requests;
+
+ int nr_free_requests;
+ spinlock_t free_requests_lock;
+ struct list_head free_requests;
+
+ spinlock_t input_lock;
+ struct list_head input_pending;
+
+ spinlock_t userspace_lock;
+ struct list_head userspace_pending;
+
+ spinlock_t output_lock;
+ struct list_head output_pending;
+
+ struct list_head redirect_pending;
+
+ struct list_head finish_pending;
+
+ struct socket *listen [CONFIG_HTTP_NUMSOCKETS];
+ int listen_cloned [CONFIG_HTTP_NUMSOCKETS];
+
+ char * output_buffer;
+ int cpu;
+ unsigned int __padding[16];
+};
+
+extern struct nameidata docroot;
+
+#if CONFIG_HTTP_DEBUG
+extern void __check_req_list (http_req_t *req, struct list_head *list);
+# define check_req_list __check_req_list
+#else
+# define check_req_list(req, list) do { } while (0)
+#endif
+
+extern char http_docroot[200];
+extern char http_logfile[200];
+extern char http_extcgi[200];
+extern int http_stop;
+extern int http_start;
+extern int http_unload;
+extern int http_clientport;
+extern int http_logging;
+extern int http_serverport;
+extern int http_threads;
+extern int http_keepalive_timeout;
+extern int http_max_backlog;
+extern int http_max_connect;
+extern int http_max_cached_filesize;
+extern int http_mode_forbidden;
+extern int http_mode_allowed;
+extern int http_mode_userspace;
+extern int http_mode_cgi;
+extern int http_logentry_align_order;
+extern int http_nagle;
+
+
+#if 0
+#define dprintk(x...) printk(x)
+#else
+#define dprintk(x...) do { } while (0)
+#endif
+
+#if CONFIG_HTTP_DEBUG
+# undef FASTCALL
+# define FASTCALL(x) x
+#endif
+
+extern struct socket * FASTCALL(start_listening(const int port, unsigned int address));
+extern void FASTCALL(stop_listening(struct socket **sock));
+extern void FASTCALL(start_sysctl(void));
+extern void FASTCALL(end_sysctl(void));
+extern void FASTCALL(flush_request (http_req_t *req, threadinfo_t *ti));
+extern void unlink_http_socket (http_req_t *req);
+extern int FASTCALL(http_send_object (http_req_t *req, int include_header, int push));
+extern int FASTCALL(send_dynamic_reply (http_req_t *req, struct socket *sock, const char *buf, const size_t length, int push));
+extern void FASTCALL(send_success (http_req_t *req, struct socket *sock));
+extern void FASTCALL(send_err_forbidden (http_req_t *req, struct socket *sock));
+extern void FASTCALL(send_ret_not_modified (http_req_t *req, struct socket *sock));
+extern void FASTCALL(send_err_try_later (struct socket *sock));
+extern void FASTCALL(kfree_req (http_req_t *req, threadinfo_t *ti));
+extern int FASTCALL(accept_requests (threadinfo_t *ti));
+extern int FASTCALL(read_headers (threadinfo_t *ti));
+extern void FASTCALL(flush_freequeue (threadinfo_t * ti));
+extern void FASTCALL(flush_inputqueue (threadinfo_t *ti));
+extern void FASTCALL(send_generic_reply (http_req_t *req, threadinfo_t *ti));
+extern int FASTCALL(send_replies (threadinfo_t *ti));
+extern void FASTCALL(flush_outputqueue (threadinfo_t *ti));
+extern int FASTCALL(redirect_requests (threadinfo_t *ti));
+extern void FASTCALL(flush_redirectqueue (threadinfo_t *ti));
+extern http_req_t * FASTCALL(pick_userspace_req (threadinfo_t *ti));
+extern void FASTCALL(flush_userspacequeue (threadinfo_t *ti));
+extern int FASTCALL(parse_http_message (http_req_t *req, const int length));
+extern int FASTCALL(parse_request (http_req_t *req, threadinfo_t *ti));
+extern int FASTCALL(finish_requests (threadinfo_t *ti));
+extern void FASTCALL(flush_logqueue (threadinfo_t *ti));
+extern void FASTCALL(queue_cachemiss (http_req_t *req));
+extern void FASTCALL(init_cachemiss_threads (void));
+struct file * FASTCALL(http_open_file(char *filename, int mode));
+extern void FASTCALL(init_log_thread (void));
+extern void FASTCALL(stop_log_thread (void));
+extern int FASTCALL(lookup_urlo (http_req_t *req, unsigned int flag));
+extern unsigned long free_urlo (struct inode *inode);
+extern int FASTCALL(http_miss_req (http_req_t *req));
+int load_httpmodule (urlobj_t *urlo, const char *filename);
+int register_httpmodule (tcapi_template_t *tcapi);
+int unregister_httpmodule (tcapi_template_t *tcapi);
+
+typedef struct exec_param_s {
+ char *command;
+ char **argv;
+ char **envp;
+ int *pipe_fds;
+} exec_param_t;
+
+int http_exec_process (char *command, char **argv, char **envp, int *pipe_fds, exec_param_t *param, int wait);
+
+void start_external_cgi (http_req_t *req);
+
+extern asmlinkage int sys_wait4(pid_t pid, unsigned long *stat_addr,
+ int options, unsigned long *ru);
+extern void queue_output_req (http_req_t *req, threadinfo_t *ti);
+extern void queue_userspace_req (http_req_t *req, threadinfo_t *ti);
+
+
+extern void FASTCALL(__log_request (http_req_t *req));
+extern inline void log_request (http_req_t *req)
+{
+ if (http_logging)
+ __log_request(req);
+}
+
+#define MAX_NR_POINTS 100
+extern atomic_t allocations [MAX_NR_POINTS];
+extern atomic_t allocations_total_alloc [MAX_NR_POINTS];
+extern atomic_t allocations_total_free [MAX_NR_POINTS];
+
+enum kmalloc_ids {
+ ALLOC_AD_FILE,
+ ALLOC_ADTMPBUF,
+ ALLOC_USERDEM,
+ ALLOC_USERDEM_TMPBUF,
+ ALLOC_REQ,
+ ALLOC_REQ_PRIVATE,
+ ALLOC_CSUMCARRAY,
+ ALLOC_CSUMCSTRUCT,
+ ALLOC_URLO_STRUCT,
+ ALLOC_DYNFRAG,
+ ALLOC_DYNBUF,
+ __ALLOC_LAST,
+};
+
+extern void * http_kmalloc (int size, enum kmalloc_ids id);
+extern void http_kfree (void *ptr, enum kmalloc_ids id);
+extern struct dentry * http_lookup (char *filename, struct nameidata *base, unsigned int flags);
+
+extern void reap_kids (void);
+extern void unuse_frag (struct sk_buff *skb, skb_frag_t *frag);
+extern int http_read (urlobj_t *urlo, char *to);
+extern skb_frag_t * build_dynbuf_frag (http_req_t *req, int size);
+extern int url_permission (struct inode *inode);
+extern int add_inode_urlo_atomic (struct inode *inode, urlobj_t *urlo);
+extern void flush_all_signals (void);
+
+extern int multifragment_api;
+
+#define D() Dprintk("{%s:%d}\n", __FILE__, __LINE__)
+
+#define http_sleep(n) \
+ do { \
+ current->state = TASK_INTERRUPTIBLE; \
+ schedule_timeout(HZ * (n)); \
+ } while (0)
+
+#define http_file file
+
+#define http_write_file(file, buf, len) \
+ ({ unsigned int __ret; mm_segment_t oldmm = get_fs(); set_fs(KERNEL_DS); __ret = ((file)->f_op->write(file, buf, len, &(file)->f_pos)); set_fs(oldmm); __ret; })
+
+#define http_read_file(file, buf, len) \
+ ({ unsigned int __ret; mm_segment_t oldmm = get_fs(); set_fs(KERNEL_DS); __ret = ((file)->f_op->read(file, buf, len, &(file)->f_pos)); set_fs(oldmm); __ret; })
+
+#define http_close_file(file) \
+ (fput(file))
+
+#define http_malloc http_kmalloc
+#define http_free http_kfree
+
+#define http_send_client(req, buf, len, push) \
+ send_dynamic_reply(req, (req)->sock, buf, len, push)
+
+#define HTTP_DECLARE_MUTEX DECLARE_MUTEX
+#define http_down down
+#define http_up up
+
+#define http_time() CURRENT_TIME
+
+#define http_direntry dentry
+#define http_direntry_open(d,r,fl) \
+ ({ struct file *__f; lock_kernel(); __f = dentry_open(d,r,fl); unlock_kernel(); __f; })
+#define http_lookup_direntry(f,r,fl) \
+ ({ struct dentry *__d; lock_kernel(); __d = http_lookup(f,r,fl); unlock_kernel(); __d; })
+#define http_file_size(file) ((file)->f_dentry->d_inode->i_size)
+
+#define http_mmap_page(file, virt, offset) \
+({ \
+ struct page *page = NULL; \
+ page = grab_cache_page((file)->f_dentry->d_inode->i_mapping, 0); \
+ if (page) { \
+ virt = (char *)kmap(page); \
+ UnlockPage(page); \
+ } \
+ page; \
+})
+
+#define http_direntry_error(dentry) \
+ (!(dentry) || IS_ERR(dentry) || !(dentry)->d_inode)
+#define http_dput(d) do { lock_kernel(); dput(d); unlock_kernel(); } while (0)
+#define http_mtime(dentry) \
+ ((dentry)->d_inode->i_mtime)
+#define http_file_error(file) \
+ ((!file) || !(file)->f_dentry || !(file)->f_dentry->d_inode)
+
+#define http_getpid() (current->pid)
+#define http_client_addr(req) ((req)->sock->sk->daddr)
+
+#define http_page page
+#define urlo_t urlobj_t
+
+extern int nr_async_io_pending (void);
+extern void trunc_headers (http_req_t *req);
+
+extern void __add_keepalive_timer (http_req_t *req);
+static inline void add_keepalive_timer (http_req_t *req)
+{
+ if (http_keepalive_timeout)
+ __add_keepalive_timer(req);
+}
+extern void del_keepalive_timer (http_req_t *req);
+extern void print_req (http_req_t *req);
+
+extern char tux_date [DATE_LEN];
+
+
+#endif
--- linux/include/net/http_u.h.orig Fri Sep 1 07:28:26 2000
+++ linux/include/net/http_u.h Fri Sep 1 07:28:26 2000
@@ -0,0 +1,129 @@
+#ifndef _NET_HTTP_HTTP_U_H
+#define _NET_HTTP_HTTP_U_H
+
+/*
+ * TUX - Integrated HTTP layer and Object Cache
+ *
+ * Copyright (C) 2000, Ingo Molnar <
[email protected]>
+ *
+ * http_u.h: HTTP module API - HTTP interface to user-space
+ */
+
+#define __KERNEL_SYSCALLS__
+
+typedef enum http_versions {
+ HTTP_1_0,
+ HTTP_1_1
+} http_version_t;
+
+/*
+ * Request methods known to HTTP:
+ */
+typedef enum http_methods {
+ METHOD_NONE,
+ METHOD_GET,
+ METHOD_HEAD,
+ METHOD_POST,
+ METHOD_PUT
+} http_method_t;
+
+enum user_req {
+ HTTP_ACTION_STARTUP = 1,
+ HTTP_ACTION_SHUTDOWN = 2,
+ HTTP_ACTION_STARTTHREAD = 3,
+ HTTP_ACTION_STOPTHREAD = 4,
+ HTTP_ACTION_EVENTLOOP = 5,
+ HTTP_ACTION_GET_OBJECT = 6,
+ HTTP_ACTION_SEND_OBJECT = 7,
+ HTTP_ACTION_READ_OBJECT = 8,
+ HTTP_ACTION_FINISH_REQ = 9,
+ HTTP_ACTION_REGISTER_MODULE = 10,
+ HTTP_ACTION_UNREGISTER_MODULE = 11,
+ HTTP_ACTION_CURRENT_DATE = 12,
+ MAX_HTTP_ACTION
+};
+
+enum http_ret {
+ HTTP_RETURN_USERSPACE_REQUEST = 0,
+ HTTP_RETURN_EXIT = 1,
+ HTTP_RETURN_SIGNAL = 2,
+};
+
+#define MAX_MODULENAME_LEN 16
+#define MAX_URI_LEN 256
+#define MAX_POST_DATA 1024
+#define MAX_COOKIE_LEN 128
+#define DATE_LEN 30
+
+typedef struct user_req_s {
+ int http_version;
+ int http_method;
+ int sock;
+ int bytes_sent;
+ int http_status;
+ unsigned int client_host;
+ unsigned int objectlen;
+ char query[MAX_URI_LEN];
+ char *object_addr;
+ char objectname[MAX_URI_LEN];
+ int module_index;
+ char modulename[MAX_MODULENAME_LEN];
+ char post_data[MAX_POST_DATA];
+ char new_date[DATE_LEN];
+
+ int cookies_len;
+ char cookies[MAX_COOKIE_LEN];
+
+ int event;
+ int thread_nr;
+ void *id;
+ void *private;
+} user_req_t;
+
+extern char *HTTPAPI_docroot;
+extern char *HTTPAPI_version;
+
+extern int http (unsigned int action, user_req_t *req);
+
+extern void * HTTPAPI_malloc_shared (unsigned int len);
+
+#ifndef __KERNEL__
+#define BUG() \
+do { \
+ printf("CAD BUG at %d:%s!\n", __LINE__, __FILE__); \
+ http(HTTP_ACTION_STOPTHREAD, NULL); \
+ http(HTTP_ACTION_SHUTDOWN, NULL); \
+ *(int*)0=0; \
+ exit(-1); \
+} while (0)
+
+#define LOCK_PREFIX "lock ; "
+
+#define barrier() __asm__ __volatile__("": : :"memory")
+struct __dummy { unsigned long a[100]; };
+#define ADDR (*(volatile struct __dummy *) addr)
+
+extern __inline__ int test_and_set_bit(int nr, volatile void * addr)
+{
+ int oldbit;
+
+ __asm__ __volatile__( LOCK_PREFIX
+ "btsl %2,%1\n\tsbbl %0,%0"
+ :"=r" (oldbit),"=m" (ADDR)
+ :"Ir" (nr));
+ return oldbit;
+}
+
+extern __inline__ void http_down (int *sem)
+{
+ while (test_and_set_bit(0, sem))
+ barrier();
+}
+
+extern __inline__ void http_up (int *sem)
+{
+ *((volatile int *)sem) = 0;
+}
+#endif
+
+#endif
--- linux/net/core/skbuff.c.orig Mon May 22 18:50:55 2000
+++ linux/net/core/skbuff.c Fri Sep 1 07:28:26 2000
@@ -51,6 +51,7 @@
#include <linux/slab.h>
#include <linux/cache.h>
#include <linux/init.h>
+#include <linux/highmem.h>
#include <net/ip.h>
#include <net/protocol.h>
@@ -166,6 +167,7 @@
{
struct sk_buff *skb;
u8 *data;
+ int i;
if (in_interrupt() && (gfp_mask & __GFP_WAIT)) {
static int count = 0;
@@ -183,6 +185,7 @@
skb = kmem_cache_alloc(skbuff_head_cache, gfp_mask);
if (skb == NULL)
goto nohead;
+ memset(skb, 0, sizeof(*skb));
}
/* Get the DATA. Size must match skb_add_mtu(). */
@@ -204,6 +207,11 @@
skb->len = 0;
skb->is_clone = 0;
skb->cloned = 0;
+ skb->nr_frags = 0;
+
+ skb->data_len = 0;
+ for (i = 0; i < MAX_SKB_FRAGS; i++)
+ skb->frags[i] = NULL;
atomic_set(&skb->users, 1);
atomic_set(skb_datarefp(skb), 1);
@@ -234,6 +242,7 @@
skb->security = 0; /* By default packets are insecure */
skb->dst = NULL;
skb->rx_dev = NULL;
+ skb->nr_frags = 0;
#ifdef CONFIG_NETFILTER
skb->nfmark = skb->nfcache = 0;
skb->nfct = NULL;
@@ -253,12 +262,15 @@
*/
void kfree_skbmem(struct sk_buff *skb)
{
+ if (skb->nr_frags)
+ BUG();
if (!skb->cloned || atomic_dec_and_test(skb_datarefp(skb)))
kfree(skb->head);
skb_head_to_pool(skb);
}
+extern int http_in_packet_delay, http_out_packet_delay;
/**
* __kfree_skb - private function
* @skb: buffer
@@ -275,6 +287,16 @@
"on a list (from %p).\n", NET_CALLER(skb));
BUG();
}
+ if (atomic_read(&skb->users))
+ BUG();
+
+ if (!skb->is_clone) {
+ int i;
+
+ for (i = 0; i < skb->nr_frags; i++)
+ if (skb->frags[i]->frag_done)
+ skb->frags[i]->frag_done(skb, skb->frags[i]);
+ }
dst_release(skb->dst);
if(skb->destructor) {
@@ -288,9 +310,11 @@
nf_conntrack_put(skb->nfct);
#endif
#ifdef CONFIG_NET
- if(skb->rx_dev)
+ if (skb->rx_dev)
dev_put(skb->rx_dev);
-#endif
+#endif
+ if (http_in_packet_delay || http_out_packet_delay)
+ del_timer(&skb->delay_timer);
skb_headerinit(skb, NULL, 0); /* clean state */
kfree_skbmem(skb);
}
@@ -395,22 +419,49 @@
struct sk_buff *skb_copy(const struct sk_buff *skb, int gfp_mask)
{
struct sk_buff *n;
+ int headerlen;
/*
* Allocate the copy buffer
*/
- n=alloc_skb(skb->end - skb->head, gfp_mask);
- if(n==NULL)
+ n = alloc_skb(skb->end - skb->head + skb->data_len, gfp_mask);
+ if (!n)
return NULL;
/* Set the data pointer */
- skb_reserve(n,skb->data-skb->head);
+ skb_reserve(n, skb->data-skb->head);
+
/* Set the tail pointer and length */
skb_put(n,skb->len);
+
/* Copy the bytes */
- memcpy(n->head,skb->head,skb->end-skb->head);
+ headerlen = skb->tail - skb->head;
+ memcpy(n->head, skb->head, headerlen);
+
+ if (skb->nr_frags) {
+ int i, pos;
+ unsigned long vfrom;
+ unsigned long flags;
+
+ pos = headerlen;
+ __save_flags(flags);
+ __cli();
+ for (i = 0; i < skb->nr_frags; i++) {
+ skb_frag_t *frag = skb->frags[i];
+
+ vfrom = kmap_atomic(frag->page, KM_SKB_DATA);
+ memcpy(n->head+pos, (char *)vfrom + frag->page_offset,
+ frag->size);
+ pos += frag->size;
+ kunmap_atomic(vfrom, KM_SKB_DATA);
+ }
+ __restore_flags(flags);
+ }
+
n->csum = skb->csum;
+
+
copy_skb_header(n, skb);
return n;
@@ -443,6 +494,8 @@
{
struct sk_buff *n;
+ if (skb->data_len)
+ BUG();
/*
* Allocate the copy buffer
*/
@@ -492,3 +545,4 @@
for (i=0; i<NR_CPUS; i++)
skb_queue_head_init(&skb_head_pool[i].list);
}
+
--- linux/net/core/sock.c.orig Fri Sep 1 07:27:06 2000
+++ linux/net/core/sock.c Fri Sep 1 07:28:26 2000
@@ -1068,30 +1068,35 @@
* Default Socket Callbacks
*/
+#define HTTP_EVENT(sk) if (sk->http_data) idle_event(sk->http_data)
+
void sock_def_wakeup(struct sock *sk)
{
read_lock(&sk->callback_lock);
- if (sk->sleep && waitqueue_active(sk->sleep))
+ if (sk->sleep /*&& waitqueue_active(sk->sleep)*/)
wake_up_interruptible_all(sk->sleep);
read_unlock(&sk->callback_lock);
+ HTTP_EVENT(sk);
}
void sock_def_error_report(struct sock *sk)
{
read_lock(&sk->callback_lock);
- if (sk->sleep && waitqueue_active(sk->sleep))
+ if (sk->sleep /*&& waitqueue_active(sk->sleep)*/)
wake_up_interruptible(sk->sleep);
sk_wake_async(sk,0,POLL_ERR);
read_unlock(&sk->callback_lock);
+ HTTP_EVENT(sk);
}
void sock_def_readable(struct sock *sk, int len)
{
read_lock(&sk->callback_lock);
- if (sk->sleep && waitqueue_active(sk->sleep))
+ if (sk->sleep /*&& waitqueue_active(sk->sleep)*/)
wake_up_interruptible(sk->sleep);
sk_wake_async(sk,1,POLL_IN);
read_unlock(&sk->callback_lock);
+ HTTP_EVENT(sk);
}
void sock_def_write_space(struct sock *sk)
@@ -1102,7 +1107,7 @@
* progress. --DaveM
*/
if((atomic_read(&sk->wmem_alloc) << 1) <= sk->sndbuf) {
- if (sk->sleep && waitqueue_active(sk->sleep))
+ if (sk->sleep /*&& waitqueue_active(sk->sleep)*/)
wake_up_interruptible(sk->sleep);
/* Should agree with poll, otherwise some programs break */
@@ -1111,12 +1116,14 @@
}
read_unlock(&sk->callback_lock);
+ HTTP_EVENT(sk);
}
void sock_def_destruct(struct sock *sk)
{
if (sk->protinfo.destruct_hook)
kfree(sk->protinfo.destruct_hook);
+ HTTP_EVENT(sk);
}
void sock_init_data(struct socket *sock, struct sock *sk)
--- linux/net/core/dev.c.orig Fri Sep 1 07:27:06 2000
+++ linux/net/core/dev.c Fri Sep 1 07:28:26 2000
@@ -90,6 +90,7 @@
#include <net/profile.h>
#include <linux/init.h>
#include <linux/kmod.h>
+#include <linux/brlock.h>
#if defined(CONFIG_NET_RADIO) || defined(CONFIG_NET_PCMCIA_RADIO)
#include <linux/wireless.h> /* Note : will define WIRELESS_EXT */
#endif /* CONFIG_NET_RADIO || CONFIG_NET_PCMCIA_RADIO */
@@ -868,6 +869,8 @@
br_read_unlock(BR_NETPROTO_LOCK);
}
+static void __netif_rx (struct sk_buff *newskb);
+
/*
* Fast path for loopback frames.
*/
@@ -884,7 +887,7 @@
newskb->ip_summed = CHECKSUM_UNNECESSARY;
if (newskb->dst==NULL)
printk(KERN_DEBUG "BUG: packet without dst looped back 1\n");
- netif_rx(newskb);
+ __netif_rx(newskb);
}
/**
@@ -899,6 +902,8 @@
* guarantee the frame will be transmitted as it may be dropped due
* to congestion or traffic shaping.
*/
+
+extern int multifragment_api;
int dev_queue_xmit(struct sk_buff *skb)
{
@@ -940,6 +945,20 @@
if (netdev_nit)
dev_queue_xmit_nit(skb,dev);
+
+ if (!dev->hard_start_xmit_dual
+#ifdef CONFIG_HTTP
+ ||!multifragment_api
+#endif
+ ) {
+ struct sk_buff *tmp;
+
+ tmp = skb_copy(skb, GFP_ATOMIC);
+ if (!tmp)
+ BUG();
+ dev_kfree_skb_irq(skb);
+ skb = tmp;
+ }
if (dev->hard_start_xmit(skb, dev) == 0) {
dev->xmit_lock_owner = -1;
spin_unlock_bh(&dev->xmit_lock);
@@ -969,7 +988,7 @@
Receiver routines
=======================================================================*/
-int netdev_max_backlog = 300;
+int netdev_max_backlog = 300000;
struct netif_rx_stats netdev_rx_stat[NR_CPUS];
@@ -1043,7 +1062,34 @@
* protocol layers.
*/
-void netif_rx(struct sk_buff *skb)
+/*
+ * artifical rx packet delay, in msecs.
+ */
+int http_in_packet_delay = 0;
+
+static void packet_rx_delay (unsigned long data)
+{
+ struct sk_buff *skb = (struct sk_buff *) data;
+
+ __netif_rx(skb);
+}
+
+void netif_rx (struct sk_buff *skb)
+{
+ if (http_in_packet_delay) {
+ struct timer_list *timer = &skb->delay_timer;
+
+ init_timer(timer);
+ timer->expires = jiffies + HZ*http_in_packet_delay/1000;
+ skb->delay_dev = NULL;
+ timer->data = (unsigned long) skb;
+ timer->function = packet_rx_delay;
+ add_timer(timer);
+ } else
+ __netif_rx (skb);
+}
+
+static void __netif_rx (struct sk_buff *skb)
{
int this_cpu = smp_processor_id();
struct softnet_data *queue;
--- linux/net/ipv4/tcp.c.orig Fri Sep 1 07:27:06 2000
+++ linux/net/ipv4/tcp.c Fri Sep 1 07:28:26 2000
@@ -426,6 +426,9 @@
#include <asm/uaccess.h>
+#include <net/http.h>
+
+
int sysctl_tcp_fin_timeout = TCP_FIN_TIMEOUT;
struct tcp_mib tcp_statistics[NR_CPUS*2];
@@ -543,13 +546,15 @@
*/
unsigned int tcp_poll(struct file * file, struct socket *sock, poll_table *wait)
{
- unsigned int mask;
+ unsigned int mask = 0;
struct sock *sk = sock->sk;
struct tcp_opt *tp = &(sk->tp_pinfo.af_tcp);
poll_wait(file, sk->sleep, wait);
- if (sk->state == TCP_LISTEN)
- return tcp_listen_poll(sk, wait);
+ if (sk->state == TCP_LISTEN) {
+ mask = tcp_listen_poll(sk, wait);
+ goto out;
+ }
/* Socket is not locked. We are protected from async events
by poll logic and correct handling of state changes
@@ -622,6 +627,11 @@
if (tp->urg_data & TCP_URG_VALID)
mask |= POLLPRI;
}
+
+
+
+
+out:
return mask;
}
@@ -887,7 +897,9 @@
}
/* When all user supplied data has been queued set the PSH bit */
-#define PSH_NEEDED (seglen == 0 && iovlen == 0)
+#define PSH_NEEDED(flags) \
+ (!(flags & MSG_NO_PUSH) && (seglen == 0) && (iovlen == 0))
+
/*
* This routine copies from a user buffer into a socket,
@@ -904,6 +916,7 @@
int err, copied;
long timeo;
+
err = 0;
tp = &(sk->tp_pinfo.af_tcp);
@@ -952,8 +965,12 @@
/* Now we need to check if we have a half
* built packet we can tack some data onto.
*/
- if (tp->send_head && !(flags & MSG_OOB)) {
- skb = sk->write_queue.prev;
+ if (tp->send_head && !(flags & MSG_OOB)
+ /*
+ * Except if the skb is fragmented.
+ */
+ && !(skb = sk->write_queue.prev)->nr_frags)
+ {
copy = skb->len;
/* If the remote does SWS avoidance we should
* queue the best we can if not we should in
@@ -999,7 +1016,7 @@
from += copy;
copied += copy;
seglen -= copy;
- if (PSH_NEEDED ||
+ if (PSH_NEEDED(flags) ||
after(tp->write_seq, tp->pushed_seq+(tp->max_window>>1))) {
TCP_SKB_CB(skb)->flags |= TCPCB_FLAG_PSH;
tp->pushed_seq = tp->write_seq;
@@ -1012,7 +1029,7 @@
/* Determine how large of a buffer to allocate. */
tmp = MAX_TCP_HEADER + 15 + tp->mss_cache;
- if (copy < mss_now && !(flags & MSG_OOB)) {
+ if ((copy < mss_now) && !(flags & MSG_OOB) && !PSH_NEEDED(flags)) {
/* What is happening here is that we want to
* tack on later members of the users iovec
* if possible into a single frame. When we
@@ -1054,7 +1071,7 @@
/* Prepare control bits for TCP header creation engine. */
TCP_SKB_CB(skb)->flags = TCPCB_FLAG_ACK;
- if (PSH_NEEDED ||
+ if (PSH_NEEDED(flags) ||
after(tp->write_seq+copy, tp->pushed_seq+(tp->max_window>>1))) {
TCP_SKB_CB(skb)->flags = TCPCB_FLAG_ACK|TCPCB_FLAG_PSH;
tp->pushed_seq = tp->write_seq + copy;
@@ -1119,7 +1136,7 @@
err = copied;
goto out;
do_fault:
- __kfree_skb(skb);
+ kfree_skb(skb);
do_fault2:
err = -EFAULT;
goto out;
@@ -1156,7 +1173,7 @@
msg->msg_flags|=MSG_OOB;
if(len>0) {
- if (!(flags & MSG_PEEK))
+ if (!(flags & MSG_PEEK) && !(flags & MSG_TRUNC))
err = memcpy_toiovec(msg->msg_iov, &c, 1);
len = 1;
} else
@@ -1186,7 +1203,7 @@
static inline void tcp_eat_skb(struct sock *sk, struct sk_buff * skb)
{
__skb_unlink(skb, &sk->receive_queue);
- __kfree_skb(skb);
+ kfree_skb(skb);
}
/* Clean up the receive buffer for full frames taken by the user,
@@ -1265,6 +1282,7 @@
{
DECLARE_WAITQUEUE(wait, current);
+
add_wait_queue(sk->sleep, &wait);
__set_current_state(TASK_INTERRUPTIBLE);
@@ -1280,6 +1298,8 @@
remove_wait_queue(sk->sleep, &wait);
__set_current_state(TASK_RUNNING);
+
+
return timeo;
}
@@ -1355,7 +1375,7 @@
* handling. FIXME: Need to check this doesnt impact 1003.1g
* and move it down to the bottom of the loop
*/
- if (signal_pending(current)) {
+ if (!nonblock && signal_pending(current)) {
if (copied)
break;
copied = timeo ? sock_intr_errno(timeo) : -EAGAIN;
@@ -1770,7 +1790,7 @@
while((skb=__skb_dequeue(&sk->receive_queue))!=NULL) {
u32 len = TCP_SKB_CB(skb)->end_seq - TCP_SKB_CB(skb)->seq - skb->h.th->fin;
data_was_unread += len;
- __kfree_skb(skb);
+ kfree_skb(skb);
}
tcp_mem_reclaim(sk);
@@ -1786,6 +1806,7 @@
*/
if(data_was_unread != 0) {
/* Unread data was tossed, zap the connection. */
+ printk("TCP: %d bytes data unread!\n", data_was_unread);
NET_INC_STATS_USER(TCPAbortOnClose);
tcp_set_state(sk, TCP_CLOSE);
tcp_send_active_reset(sk, GFP_KERNEL);
@@ -1882,6 +1903,10 @@
if (tmo > TCP_TIMEWAIT_LEN) {
tcp_reset_keepalive_timer(sk, tcp_fin_time(tp));
} else {
+
+
+ if (sk->http_data) idle_event(sk->http_data);
+
atomic_inc(&tcp_orphan_count);
tcp_time_wait(sk, TCP_FIN_WAIT2, tmo);
goto out;
@@ -1900,6 +1925,11 @@
NET_INC_STATS_BH(TCPAbortOnMemory);
}
}
+
+
+ if (sk->http_data) idle_event(sk->http_data);
+
+
atomic_inc(&tcp_orphan_count);
if (sk->state == TCP_CLOSE)
@@ -1907,6 +1937,9 @@
/* Otherwise, socket is reprieved until protocol close. */
out:
+
+
+ if (sk->http_data) idle_event(sk->http_data);
bh_unlock_sock(sk);
local_bh_enable();
sock_put(sk);
@@ -2376,7 +2409,7 @@
sysctl_local_port_range[1] = 61000;
sysctl_tcp_max_tw_buckets = 180000;
sysctl_tcp_max_orphans = 4096<<(order-4);
- sysctl_max_syn_backlog = 1024;
+ sysctl_max_syn_backlog = 4096;
} else if (order < 3) {
sysctl_local_port_range[0] = 1024*(3-order);
sysctl_tcp_max_tw_buckets >>= (3-order);
--- linux/net/ipv4/tcp_output.c.orig Fri Sep 1 07:27:06 2000
+++ linux/net/ipv4/tcp_output.c Fri Sep 1 07:28:26 2000
@@ -343,6 +343,9 @@
int nsize = skb->len - len;
u16 flags;
+ // FIXME: how should we do this?
+ if (skb->nr_frags)
+ return 0;
/* Get a new skb... force flag on. */
buff = tcp_alloc_skb(sk, nsize + MAX_TCP_HEADER + 15, GFP_ATOMIC);
if (buff == NULL)
@@ -642,7 +645,8 @@
* would exceed the MSS.
*/
if ((next_skb_size > skb_tailroom(skb)) ||
- ((skb_size + next_skb_size) > mss_now))
+ ((skb_size + next_skb_size) > mss_now) ||
+ skb->nr_frags || next_skb->nr_frags)
return;
/* Ok. We will be able to collapse the packet. */
@@ -777,9 +781,9 @@
* retransmit when old data is attached. So strip it off
* since it is cheap to do so and saves bytes on the network.
*/
- if(skb->len > 0 &&
+ if(!skb->nr_frags && (skb->len > 0 &&
(TCP_SKB_CB(skb)->flags & TCPCB_FLAG_FIN) &&
- tp->snd_una == (TCP_SKB_CB(skb)->end_seq - 1)) {
+ tp->snd_una == (TCP_SKB_CB(skb)->end_seq - 1))) {
TCP_SKB_CB(skb)->seq = TCP_SKB_CB(skb)->end_seq - 1;
skb_trim(skb, 0);
skb->csum = 0;
--- linux/net/ipv4/tcp_input.c.orig Fri Sep 1 07:27:06 2000
+++ linux/net/ipv4/tcp_input.c Fri Sep 1 07:28:26 2000
@@ -393,6 +393,8 @@
if (skb->len >= 128)
tcp_grow_window(sk, tp, skb);
+
+ if (sk->http_data) idle_event(sk->http_data);
}
/* Called to compute a smoothed rtt estimate. The data fed to this
@@ -2450,7 +2452,7 @@
if (!after(TCP_SKB_CB(skb)->end_seq, tp->rcv_nxt)) {
SOCK_DEBUG(sk, "ofo packet was already received \n");
__skb_unlink(skb, skb->list);
- __kfree_skb(skb);
+ kfree_skb(skb);
continue;
}
SOCK_DEBUG(sk, "ofo requeuing : rcv_next %X seq %X - %X\n",
@@ -2505,6 +2507,8 @@
queue_and_out:
tcp_set_owner_r(skb, sk);
__skb_queue_tail(&sk->receive_queue, skb);
+ if (!sk->dead)
+ sk->data_ready(sk, skb->len);
}
tp->rcv_nxt = TCP_SKB_CB(skb)->end_seq;
if(skb->len)
@@ -2534,7 +2538,7 @@
tcp_fast_path_on(tp);
if (eaten) {
- __kfree_skb(skb);
+ kfree_skb(skb);
} else if (!sk->dead)
sk->data_ready(sk, 0);
return;
@@ -2550,7 +2554,7 @@
printk("BUG: retransmit in tcp_data_queue: seq %X\n", TCP_SKB_CB(skb)->seq);
tcp_enter_quickack_mode(tp);
tcp_schedule_ack(tp);
- __kfree_skb(skb);
+ kfree_skb(skb);
return;
}
#endif
@@ -2616,7 +2620,7 @@
before(seq, TCP_SKB_CB(skb1)->end_seq)) {
if (!after(end_seq, TCP_SKB_CB(skb1)->end_seq)) {
/* All the bits are present. Drop. */
- __kfree_skb(skb);
+ kfree_skb(skb);
tcp_dsack_set(tp, seq, end_seq);
goto add_sack;
}
@@ -2638,7 +2642,7 @@
}
__skb_unlink(skb1, skb1->list);
tcp_dsack_extend(tp, TCP_SKB_CB(skb1)->seq, TCP_SKB_CB(skb1)->end_seq);
- __kfree_skb(skb1);
+ kfree_skb(skb1);
}
add_sack:
@@ -2668,7 +2672,7 @@
memcpy(skb_put(skb, skb_next->len), skb_next->data, skb_next->len);
__skb_unlink(skb_next, skb_next->list);
scb->end_seq = scb_next->end_seq;
- __kfree_skb(skb_next);
+ kfree_skb(skb_next);
NET_INC_STATS_BH(TCPRcvCollapsed);
} else {
/* Lots of spare tailroom, reallocate this skb to trim it. */
@@ -2684,7 +2688,7 @@
skb_headroom(skb));
__skb_append(skb, nskb);
__skb_unlink(skb, skb->list);
- __kfree_skb(skb);
+ kfree_skb(skb);
}
}
skb = skb_next;
@@ -2798,7 +2802,7 @@
return;
drop:
- __kfree_skb(skb);
+ kfree_skb(skb);
}
/* RFC2861, slow part. Adjust cwnd, after it was not full during one rto.
@@ -2851,8 +2855,10 @@
clear_bit(SOCK_NOSPACE, &sock->flags);
- if (sk->sleep && waitqueue_active(sk->sleep))
+ if (sk->sleep /*&& waitqueue_active(sk->sleep)*/) {
wake_up_interruptible(sk->sleep);
+ if (sk->http_data) idle_event(sk->http_data);
+ }
if (sock->fasync_list && !(sk->shutdown&SEND_SHUTDOWN))
sock_wake_async(sock, 2, POLL_OUT);
@@ -2963,6 +2969,7 @@
else
kill_pg(-sk->proc, SIGURG, 1);
sk_wake_async(sk, 3, POLL_PRI);
+ if (sk->http_data) idle_event(sk->http_data);
}
/* We may be adding urgent data when the last byte read was
@@ -3176,7 +3183,7 @@
* on entry.
*/
tcp_ack(sk, skb, 0);
- __kfree_skb(skb);
+ kfree_skb(skb);
tcp_data_snd_check(sk);
return 0;
} else { /* Header too small */
@@ -3240,7 +3247,7 @@
no_ack:
if (eaten)
- __kfree_skb(skb);
+ kfree_skb(skb);
else
sk->data_ready(sk, 0);
return 0;
@@ -3316,7 +3323,7 @@
TCP_INC_STATS_BH(TcpInErrs);
discard:
- __kfree_skb(skb);
+ kfree_skb(skb);
return 0;
}
@@ -3471,15 +3478,13 @@
/* No ACK in the segment */
- if (th->rst) {
+ if (th->rst)
/* rfc793:
* "If the RST bit is set
*
* Otherwise (no ACK) drop the segment and return."
*/
-
goto discard;
- }
/* PAWS check. */
if (tp->ts_recent_stamp && tp->saw_tstamp && tcp_paws_check(tp, 0))
@@ -3528,7 +3533,7 @@
*/
discard:
- __kfree_skb(skb);
+ kfree_skb(skb);
return 0;
}
@@ -3735,8 +3740,9 @@
}
break;
}
- } else
+ } else {
goto discard;
+ }
step6:
/* step 6: check the URG bit */
@@ -3777,7 +3783,7 @@
if (!queued) {
discard:
- __kfree_skb(skb);
+ kfree_skb(skb);
}
return 0;
}
--- linux/net/sched/sch_generic.c.orig Fri Sep 1 07:27:06 2000
+++ linux/net/sched/sch_generic.c Fri Sep 1 07:28:26 2000
@@ -74,68 +74,123 @@
NOTE: Called under dev->queue_lock with locally disabled BH.
*/
-int qdisc_restart(struct net_device *dev)
+extern int multifragment_api;
+
+static int xmit_skb (struct net_device *dev, struct sk_buff *skb)
{
struct Qdisc *q = dev->qdisc;
- struct sk_buff *skb;
- /* Dequeue packet */
- if ((skb = q->dequeue(q)) != NULL) {
- if (spin_trylock(&dev->xmit_lock)) {
- /* Remember that the driver is grabbed by us. */
- dev->xmit_lock_owner = smp_processor_id();
-
- /* And release queue */
- spin_unlock(&dev->queue_lock);
-
- if (!netif_queue_stopped(dev)) {
- if (netdev_nit)
- dev_queue_xmit_nit(skb, dev);
-
- if (dev->hard_start_xmit(skb, dev) == 0) {
- dev->xmit_lock_owner = -1;
- spin_unlock(&dev->xmit_lock);
-
- spin_lock(&dev->queue_lock);
- return -1;
- }
+ if (spin_trylock(&dev->xmit_lock)) {
+ /* Remember that the driver is grabbed by us. */
+ dev->xmit_lock_owner = smp_processor_id();
+
+ /* And release queue */
+ spin_unlock(&dev->queue_lock);
+
+ if (!netif_queue_stopped(dev)) {
+ if (netdev_nit)
+ dev_queue_xmit_nit(skb, dev);
+
+ if (!dev->hard_start_xmit_dual
+#ifdef CONFIG_HTTP
+ ||!multifragment_api
+#endif
+ ) {
+ struct sk_buff *tmp;
+
+ tmp = skb_copy(skb, GFP_ATOMIC);
+ if (!tmp)
+ BUG();
+ dev_kfree_skb_irq(skb);
+ skb = tmp;
}
- /* Release the driver */
- dev->xmit_lock_owner = -1;
- spin_unlock(&dev->xmit_lock);
- spin_lock(&dev->queue_lock);
- q = dev->qdisc;
- } else {
- /* So, someone grabbed the driver. */
+ if (dev->hard_start_xmit(skb, dev) == 0) {
+ dev->xmit_lock_owner = -1;
+ spin_unlock(&dev->xmit_lock);
- /* It may be transient configuration error,
- when hard_start_xmit() recurses. We detect
- it by checking xmit owner and drop the
- packet when deadloop is detected.
- */
- if (dev->xmit_lock_owner == smp_processor_id()) {
- kfree_skb(skb);
- if (net_ratelimit())
- printk(KERN_DEBUG "Dead loop on netdevice %s, fix it urgently!\n", dev->name);
+ spin_lock(&dev->queue_lock);
return -1;
}
- netdev_rx_stat[smp_processor_id()].cpu_collision++;
}
- /* Device kicked us out :(
- This is possible in three cases:
-
- 0. driver is locked
- 1. fastroute is enabled
- 2. device cannot determine busy state
- before start of transmission (f.e. dialout)
- 3. device is buggy (ppp)
+ /* Release the driver */
+ dev->xmit_lock_owner = -1;
+ spin_unlock(&dev->xmit_lock);
+ spin_lock(&dev->queue_lock);
+ q = dev->qdisc;
+ } else {
+ /* So, someone grabbed the driver. */
+
+ /* It may be transient configuration error,
+ when hard_start_xmit() recurses. We detect
+ it by checking xmit owner and drop the
+ packet when deadloop is detected.
*/
+ if (dev->xmit_lock_owner == smp_processor_id()) {
+ kfree_skb(skb);
+ if (net_ratelimit())
+ printk(KERN_DEBUG "Dead loop on netdevice %s, fix it urgently!\n", dev->name);
+ return -1;
+ }
+ netdev_rx_stat[smp_processor_id()].cpu_collision++;
+ }
+
+ /* Device kicked us out :(
+ This is possible in three cases:
+
+ 0. driver is locked
+ 1. fastroute is enabled
+ 2. device cannot determine busy state
+ before start of transmission (f.e. dialout)
+ 3. device is buggy (ppp)
+ */
+
+ q->ops->requeue(skb, q);
+ netif_schedule(dev);
+ return 1;
+}
+
+/*
+ * artifical xmit packet delay, in msecs.
+ */
+int http_out_packet_delay = 0;
+
+static void packet_tx_delay (unsigned long data)
+{
+ struct sk_buff *skb = (struct sk_buff *)data;
- q->ops->requeue(skb, q);
- netif_schedule(dev);
- return 1;
+ spin_lock_bh(&skb->dev->queue_lock);
+ if (atomic_read(&skb->users) == 1)
+ dev_kfree_skb_irq(skb);
+ else {
+ atomic_dec(&skb->users);
+ xmit_skb(skb->dev, skb);
+ }
+ spin_unlock_bh(&skb->dev->queue_lock);
+}
+
+int qdisc_restart(struct net_device *dev)
+{
+ struct Qdisc *q = dev->qdisc;
+ struct sk_buff *skb;
+
+ /* Dequeue packet */
+ if ((skb = q->dequeue(q)) != NULL) {
+ if (http_out_packet_delay) {
+ struct timer_list *timer = &skb->delay_timer;
+
+ BUG();
+ init_timer(timer);
+ timer->expires = jiffies + HZ*http_out_packet_delay/1000;
+ timer->data = (unsigned long) skb;
+ timer->function = packet_tx_delay;
+ atomic_inc(&skb->users);
+ add_timer(timer);
+ } else {
+ int ret = xmit_skb(dev, skb);
+ return ret;
+ }
}
return q->q.qlen;
}
--- linux/net/socket.c.orig Fri Sep 1 07:27:07 2000
+++ linux/net/socket.c Fri Sep 1 07:28:26 2000
@@ -328,7 +328,7 @@
* but we take care of internal coherence yet.
*/
-static int sock_map_fd(struct socket *sock)
+int sock_map_fd(struct socket *sock)
{
int fd;
struct qstr this;
--- linux/net/netsyms.c.orig Fri Sep 1 07:27:06 2000
+++ linux/net/netsyms.c Fri Sep 1 07:28:26 2000
@@ -51,7 +51,7 @@
extern struct net_proto_family inet_family_ops;
-#if defined(CONFIG_IPV6) || defined (CONFIG_IPV6_MODULE) || defined (CONFIG_KHTTPD) || defined (CONFIG_KHTTPD_MODULE)
+#if defined(CONFIG_IPV6) || defined (CONFIG_IPV6_MODULE) || defined (CONFIG_KHTTPD) || defined (CONFIG_KHTTPD_MODULE) || defined (CONFIG_HTTP) || defined (CONFIG_HTTP_MODULE)
#include <linux/in6.h>
#include <linux/icmpv6.h>
#include <net/ipv6.h>
@@ -256,7 +256,7 @@
EXPORT_SYMBOL(ipv6_addr_type);
EXPORT_SYMBOL(icmpv6_send);
#endif
-#if defined (CONFIG_IPV6_MODULE) || defined (CONFIG_KHTTPD) || defined (CONFIG_KHTTPD_MODULE)
+#if defined (CONFIG_IPV6_MODULE) || defined (CONFIG_KHTTPD) || defined (CONFIG_KHTTPD_MODULE) || defined (CONFIG_HTTP) || defined (CONFIG_HTTP_MODULE)
/* inet functions common to v4 and v6 */
EXPORT_SYMBOL(inet_stream_ops);
EXPORT_SYMBOL(inet_release);
@@ -312,6 +312,7 @@
EXPORT_SYMBOL(tcp_getsockopt);
EXPORT_SYMBOL(tcp_recvmsg);
EXPORT_SYMBOL(tcp_send_synack);
+EXPORT_SYMBOL(tcp_send_skb);
EXPORT_SYMBOL(tcp_check_req);
EXPORT_SYMBOL(tcp_child_process);
EXPORT_SYMBOL(tcp_parse_options);
--- linux/net/Makefile.orig Fri Sep 1 07:26:59 2000
+++ linux/net/Makefile Fri Sep 1 07:28:26 2000
@@ -48,6 +48,15 @@
endif
endif
+ifeq ($(CONFIG_HTTP),y)
+SUB_DIRS += http
+MOD_SUB_DIRS += http
+else
+ ifeq ($(CONFIG_HTTP),m)
+ MOD_SUB_DIRS += http
+ endif
+endif
+
ifeq ($(CONFIG_KHTTPD),y)
SUB_DIRS += khttpd
else
--- linux/net/Config.in.orig Fri Sep 1 07:26:36 2000
+++ linux/net/Config.in Fri Sep 1 07:28:26 2000
@@ -20,6 +20,7 @@
tristate 'Unix domain sockets' CONFIG_UNIX
bool 'TCP/IP networking' CONFIG_INET
if [ "$CONFIG_INET" = "y" ]; then
+ source net/http/Config.in
source net/ipv4/Config.in
if [ "$CONFIG_EXPERIMENTAL" = "y" ]; then
# IPv6 as module will cause a CRASH if you try to unload it
--- linux/net/http/Config.in.orig Fri Sep 1 07:28:26 2000
+++ linux/net/http/Config.in Fri Sep 1 07:28:26 2000
@@ -0,0 +1,8 @@
+tristate ' Threaded linUX HTTP layer (TUX)' CONFIG_HTTP
+if [ "$CONFIG_HTTP" = "y" ]; then
+ tristate ' CAD module' CONFIG_HTTP_CAD
+ tristate ' CAD2 module' CONFIG_HTTP_CAD2
+ tristate ' External CGI module' CONFIG_HTTP_EXTCGI
+ bool ' debug TUX' CONFIG_HTTP_DEBUG
+fi
+
--- linux/net/http/Makefile.orig Fri Sep 1 07:28:26 2000
+++ linux/net/http/Makefile Fri Sep 1 07:28:26 2000
@@ -0,0 +1,38 @@
+#
+# Makefile for TUX
+#
+
+O_TARGET := http.o
+MOD_LIST_NAME := NET_MODULES
+
+O_OBJS := accept.o input.o userspace.o cachemiss.o output.o \
+ redirect.o logger.o http_parser.o proc.o httpmain.o cgi.o
+
+OX_OBJS := httpmod.o
+
+ifeq ($(CONFIG_HTTP_CAD2),y)
+ O_OBJS += CAD2.o
+else
+ ifeq ($(CONFIG_HTTP_CAD2),m)
+ M_OBJS += CAD2.o
+ endif
+endif
+
+ifeq ($(CONFIG_HTTP_CAD),y)
+ O_OBJS += CAD.o
+else
+ ifeq ($(CONFIG_HTTP_CAD),m)
+ M_OBJS += CAD.o
+ endif
+endif
+
+ifeq ($(CONFIG_HTTP_EXTCGI),y)
+ O_OBJS += extcgi.o
+else
+ ifeq ($(CONFIG_HTTP_EXTCGI),m)
+ M_OBJS += extcgi.o
+ endif
+endif
+
+include $(TOPDIR)/Rules.make
+
--- linux/net/http/accept.c.orig Fri Sep 1 07:28:26 2000
+++ linux/net/http/accept.c Fri Sep 1 07:28:26 2000
@@ -0,0 +1,552 @@
+/*
+ * TUX - Integrated HTTP layer and Object Cache
+ *
+ * Copyright (C) 2000, Ingo Molnar <
[email protected]>
+ *
+ * accept.c: accept connections - sleep if there is no work left.
+ */
+
+#include <net/http.h>
+
+int http_nagle = 0;
+
+atomic_t allocations [MAX_NR_POINTS];
+atomic_t allocations_total_alloc [MAX_NR_POINTS];
+atomic_t allocations_total_free [MAX_NR_POINTS];
+
+void * http_kmalloc (int size, enum kmalloc_ids id)
+{
+ int count = 3, flag = GFP_USER, priority = 3, nr = 0, freed;
+ void *tmp;
+
+ if (id >= MAX_NR_POINTS)
+ HTTP_BUG();
+repeat:
+ tmp = kmalloc(size, flag);
+ if (!tmp) {
+ /*
+ * This might look a bit excessive but we take
+ * no chances :-)
+ */
+ switch (count) {
+ case 3:
+ count--;
+ goto repeat;
+ case 2:
+ __set_task_state(current, TASK_RUNNING);
+ current->policy |= SCHED_YIELD;
+ schedule();
+ count--;
+ goto repeat;
+ case 1:
+ __set_task_state(current, TASK_INTERRUPTIBLE);
+ schedule_timeout(2);
+ count--;
+ goto repeat;
+ case 0:
+ freed = shrink_dcache_memory(32, priority, flag);
+ freed += shrink_icache_memory(32, priority, flag);
+ if (priority)
+ priority--;
+ else
+ printk("http_kmalloc allocation problem (size %d bytes (freed %d), <%p>), retrying <#%d>.\n", size, freed, __builtin_return_address(0), nr++);
+ __set_task_state(current, TASK_INTERRUPTIBLE);
+ schedule_timeout(5);
+ goto repeat;
+ default:
+ HTTP_BUG();
+ }
+ }
+
+ atomic_inc(allocations+id);
+ atomic_inc(allocations_total_alloc+id);
+ Dprintk("http_kmalloc(%d,ID:%d), <%p> = %p\n", size, id, __builtin_return_address(0), tmp);
+ return tmp;
+}
+
+void http_kfree (void *ptr, enum kmalloc_ids id)
+{
+ Dprintk("http_kfree(%p,ID:%d), <%p>\n", ptr, id, __builtin_return_address(0));
+ if (id >= MAX_NR_POINTS)
+ HTTP_BUG();
+ kfree(ptr);
+ atomic_dec(allocations+id);
+ atomic_inc(allocations_total_free+id);
+}
+
+extern char * print_async_io_threads (char *buf);
+
+char * print_http_allocations (char *buf)
+{
+ int i;
+
+ buf += sprintf(buf, "HTTP allocations:\n");
+ for (i = 0; i < __ALLOC_LAST; i++)
+ buf += sprintf(buf, " - (%02d): A:%d, F:%d, +-:%d\n",
+ i, atomic_read(allocations_total_alloc+i),
+ atomic_read(allocations_total_free+i),
+ atomic_read(allocations+i));
+
+
+ return print_async_io_threads(buf);
+}
+
+/*
+ * Static request so that we can log out-of-memory
+ * connections as well.
+ */
+http_req_t out_of_mem_req = { objectname: "", http_status: 503 };
+
+
+struct socket * start_listening (const int port, unsigned int address)
+{
+ struct socket *sock;
+ struct sockaddr_in sin;
+ int error;
+
+ /* First create a socket */
+
+ printk("start_listen(%d:%08x)\n", port, address);
+ error = sock_create(PF_INET, SOCK_STREAM, IPPROTO_TCP, &sock);
+ if (error < 0) {
+ printk(KERN_ERR "Error during creation of socket.\n");
+ return NULL;
+ }
+
+ /* Now bind the socket */
+
+ sin.sin_family = AF_INET;
+ sin.sin_addr.s_addr = htonl(address);
+ sin.sin_port = htons((unsigned short)port);
+
+ error = sock->ops->bind(sock,(struct sockaddr*)&sin, sizeof(sin));
+ if (error < 0) {
+ printk(KERN_ERR
+
+"HTTP: Error binding socket. This means that some other \n"
+" daemon is (or was a short time ago) using port %i.\n",port);
+
+ goto err;
+ }
+
+ sock->sk->reuse = 1;
+ sock->sk->linger = 0;
+ sock->sk->tp_pinfo.af_tcp.linger2 = 0;
+ sock->sk->tp_pinfo.af_tcp.defer_accept = 1;
+
+ /* Now, start listening on the socket */
+
+ error = sock->ops->listen(sock, http_max_backlog);
+ if (error) {
+ printk(KERN_ERR "HTTP: Error listening on socket.\n");
+ goto err;
+ }
+ return sock;
+err:
+ sock_release(sock);
+ return NULL;
+}
+
+void stop_listening (struct socket **sock)
+{
+ struct socket *tmp;
+ if (!*sock)
+ return;
+
+ tmp = *sock;
+ *sock = NULL;
+ sock_release(tmp);
+}
+
+static inline void __kfree_req (http_req_t *req, threadinfo_t * ti)
+{
+ list_del(&req->all);
+ ti->nr_requests--;
+ http_kfree(req, ALLOC_REQ);
+}
+
+void flush_freequeue (threadinfo_t * ti)
+{
+ struct list_head *tmp;
+ http_req_t *req;
+
+ spin_lock(&ti->free_requests_lock);
+ while (ti->nr_free_requests) {
+ ti->nr_free_requests--;
+ tmp = ti->free_requests.next;
+ req = list_entry(tmp, http_req_t, free);
+ list_del(tmp);
+ DEC_STAT(nr_free_pending);
+ __kfree_req(req, ti);
+ }
+ spin_unlock(&ti->free_requests_lock);
+}
+
+static http_req_t * kmalloc_req (threadinfo_t * ti)
+{
+ struct list_head *tmp;
+ http_req_t *req;
+
+ spin_lock(&ti->free_requests_lock);
+ if (ti->nr_free_requests) {
+ struct list_head tmp2;
+
+ ti->nr_free_requests--;
+ tmp = ti->free_requests.next;
+ req = list_entry(tmp, http_req_t, free);
+ list_del(tmp);
+ DEC_STAT(nr_free_pending);
+ req->magic = HTTP_MAGIC;
+ check_req_list(req, NULL);
+ spin_unlock(&ti->free_requests_lock);
+ tmp2 = req->all;
+// memset (req, 0, sizeof(*req));
+ req->all = tmp2;
+ } else {
+ spin_unlock(&ti->free_requests_lock);
+ req = http_kmalloc(sizeof(*req), ALLOC_REQ);
+ if (!req)
+ return NULL;
+ ti->nr_requests++;
+ memset (req, 0, sizeof(*req));
+ list_add(&req->all, &ti->all_requests);
+ }
+ req->magic = HTTP_MAGIC;
+ INC_STAT(nr_allocated);
+ init_waitqueue_entry(&req->sleep,current);
+ INIT_LIST_HEAD(&req->free);
+ INIT_LIST_HEAD(&req->input);
+ INIT_LIST_HEAD(&req->userspace);
+ INIT_LIST_HEAD(&req->cachemiss);
+ INIT_LIST_HEAD(&req->output);
+ INIT_LIST_HEAD(&req->redirect);
+ INIT_LIST_HEAD(&req->finish);
+ req->objectname_len = 0;
+ req->ti = ti;
+ req->timestamp = CURRENT_TIME;
+ req->userspace_fd = -1;
+ init_timer(&req->keepalive_timer);
+ check_req_list(req, NULL);
+ Dprintk("allocated NEW req %p.\n", req);
+ return req;
+}
+
+void kfree_req (http_req_t *req, threadinfo_t * ti)
+{
+ Dprintk("freeing req %p.\n", req);
+ spin_lock(&ti->free_requests_lock);
+ check_req_list(req, NULL);
+ req->magic = 0;
+ DEC_STAT(nr_allocated);
+ if (req->sock)
+ HTTP_BUG();
+ if (req->dentry)
+ HTTP_BUG();
+ if (req->urlo || req->prev_urlo)
+ HTTP_BUG();
+ if (req->private)
+ HTTP_BUG();
+ if (ti->nr_free_requests > 1000) {
+ spin_unlock(&ti->free_requests_lock);
+ __kfree_req(req, ti);
+ return;
+ }
+ ti->nr_free_requests++;
+ // the free requests queue is LIFO
+ list_add(&req->free, &ti->free_requests);
+ INC_STAT(nr_free_pending);
+ spin_unlock(&ti->free_requests_lock);
+}
+
+void del_keepalive_timer (http_req_t *req)
+{
+ if (timer_pending(&req->keepalive_timer))
+ del_timer(&req->keepalive_timer);
+}
+
+static void keepalive_timeout_fn (unsigned long data)
+{
+ http_req_t *req = (http_req_t *)data;
+
+ printk("CONNECTION TIMEOUT FOR REQ %p AFTER %d SECONDS!\n", req, http_keepalive_timeout);
+ print_req(req);
+}
+
+void __add_keepalive_timer (http_req_t *req)
+{
+ struct timer_list *timer = &req->keepalive_timer;
+
+ if (!http_keepalive_timeout)
+ HTTP_BUG();
+
+ timer->expires = jiffies + http_keepalive_timeout * HZ;
+ timer->data = (unsigned long) req;
+ timer->function = &keepalive_timeout_fn;
+ add_timer(timer);
+}
+
+void idle_event (http_req_t *req)
+{
+ threadinfo_t *ti;
+ unsigned long flags;
+
+ if (req->magic != HTTP_MAGIC)
+ HTTP_BUG();
+ Dprintk("EVENT req %p <%p> (sock %p, sk %p) (keepalive: %d, status: %d) ({%s}, {%s}, {%s}, {%s}).\n", req, __builtin_return_address(0), req->sock, req->sock->sk, req->keep_alive, req->http_status, req->method_str ? req->method_str : "<null>", req->uri ? req->uri : "<null>", req->query ? req->query : "<null>", req->version_str ? req->version_str : "<null>");
+ ti = req->ti;
+
+ if (!test_and_clear_bit(0, &req->idle_input)) {
+ Dprintk("data ready event at <%p>, on non-idle %p.\n", __builtin_return_address(0), req);
+ if (ti->thread)
+ wake_up_process(ti->thread);
+ return;
+ }
+
+ Dprintk("data ready event at <%p>, %p was idle!\n", __builtin_return_address(0), req);
+ del_keepalive_timer(req);
+ DEC_STAT(nr_idle_input_pending);
+
+ spin_lock_irqsave(&ti->input_lock, flags);
+ check_req_list(req, NULL);
+ list_add_tail(&req->input, &ti->input_pending);
+ INC_STAT(nr_input_pending);
+ spin_unlock_irqrestore(&ti->input_lock, flags);
+
+ if (ti->thread)
+ wake_up_process(ti->thread);
+}
+
+static void http_data_ready (struct sock *sk, int len)
+{
+ http_req_t *req = sk->http_data;
+
+ if (!req)
+ HTTP_BUG();
+ if (req->magic != HTTP_MAGIC)
+ HTTP_BUG();
+
+ if (req->old_data_ready)
+ req->old_data_ready(sk, len);
+
+ if (len)
+ idle_event(req);
+}
+
+static void http_destruct (struct sock *sk)
+{
+ http_req_t *req = sk->http_data;
+
+ if (!req)
+ HTTP_BUG();
+ if (req->magic != HTTP_MAGIC)
+ HTTP_BUG();
+ if (req->old_destruct)
+ req->old_destruct(sk);
+
+ idle_event(req);
+}
+
+static void http_state_change (struct sock *sk)
+{
+ http_req_t *req = sk->http_data;
+
+ if (!req)
+ HTTP_BUG();
+ if (req->magic != HTTP_MAGIC)
+ HTTP_BUG();
+ if (req->old_destruct)
+ req->old_state_change(sk);
+
+ idle_event(req);
+}
+
+static void link_http_socket (http_req_t *req, struct socket *sock)
+{
+ /*
+ * (No need to lock the socket, we just want to
+ * make sure that events from now on go through
+ * http_data_ready())
+ */
+ req->sock = sock;
+ sock->sk->tp_pinfo.af_tcp.nonagle = !http_nagle;
+
+ req->old_data_ready = sock->sk->data_ready;
+ req->old_state_change = sock->sk->state_change;
+ req->old_write_space = sock->sk->write_space;
+ req->old_destruct = sock->sk->destruct;
+ sock->sk->http_data = req;
+ xchg(&sock->sk->data_ready, http_data_ready);
+ xchg(&sock->sk->state_change, http_state_change);
+ xchg(&sock->sk->destruct, http_destruct);
+
+ add_wait_queue(sock->sk->sleep, &req->sleep);
+}
+
+void unlink_http_socket (http_req_t *req)
+{
+ struct sock *sk;
+
+
+ if (!req->sock)
+ return;
+ sk = req->sock->sk;
+ if (!sk)
+ return;
+
+ lock_sock(sk);
+ TCP_CHECK_TIMER(sk);
+
+ xchg(&sk->data_ready, req->old_data_ready);
+ xchg(&sk->state_change, req->old_state_change);
+ xchg(&sk->destruct, req->old_destruct);
+ sk->http_data = NULL;
+ remove_wait_queue(sk->sleep,&(req->sleep));
+
+ TCP_CHECK_TIMER(sk);
+ release_sock(sk);
+}
+
+#define MAX_ACCEPT_HIST 1100
+int accept_hist [MAX_ACCEPT_HIST];
+
+void profile_accept_queue (struct open_request *head)
+{
+ int count = 0;
+
+ if (!head)
+ goto out;
+ count++;
+ while (head->dl_next)
+ head = head->dl_next, count++;
+out:
+ if (count >= MAX_ACCEPT_HIST)
+ count = MAX_ACCEPT_HIST-1;
+ accept_hist[count]++;
+}
+
+char * print_accept_hist (char *buf)
+{
+ int i;
+
+ buf += sprintf(buf, "HTTP TCP-accept hist in syslog.\n");
+ printk("HTTP TCP-accept hist:\n");
+ for (i = 0; i < MAX_ACCEPT_HIST; i++)
+ if (accept_hist[i])
+ printk("%03d: %d\n", i, accept_hist[i]);
+
+ return buf;
+}
+/*
+ * Puts newly accepted connections into the inputqueue.
+ */
+int accept_requests (threadinfo_t *ti)
+{
+ struct socket *sock;
+ http_req_t *new_req;
+ struct socket *new_sock;
+ int count = 0, last_count = 0;
+ int error;
+ int socknr = 0;
+
+repeat:
+ for (socknr = 0; socknr < CONFIG_HTTP_NUMSOCKETS; socknr++) {
+ sock = ti->listen[socknr];
+ if (!sock)
+ break;
+
+ /*
+ * Quick test to see if there are connections on the queue.
+ * This is cheaper than accept() itself because this saves us
+ * the allocation of a new socket. (Which doesn't seem to be
+ * used anyway)
+ */
+ if (sock->sk->tp_pinfo.af_tcp.accept_queue) {
+ int ret;
+
+ if (current->need_resched)
+ break;
+ if (!count++)
+ __set_task_state(current, TASK_RUNNING);
+
+ new_sock = sock_alloc();
+ if (!new_sock)
+ goto out;
+ new_sock->type = sock->type;
+ new_sock->ops = sock->ops;
+
+// profile_accept_queue(sock->sk->tp_pinfo.af_tcp.accept_queue);
+ error = sock->ops->accept(sock, new_sock, O_NONBLOCK);
+
+ if (error < 0)
+ goto err;
+ if (new_sock->sk->state == TCP_CLOSE)
+ goto err;
+
+ /* Allocate a request-entry for the connection */
+ new_req = kmalloc_req(ti);
+
+ if (!new_req) {
+ /*
+ * Service not available, try again later.
+ * since we have no request structure, we
+ * explicitly log though the static 'out of mem'
+ * request:
+ */
+ send_err_try_later(new_sock);
+ log_request(&out_of_mem_req);
+ goto err;
+ }
+ link_http_socket(new_req, new_sock);
+
+#if 1
+ add_keepalive_timer(new_req);
+ if (test_and_set_bit(0, &new_req->idle_input))
+ HTTP_BUG();
+ INC_STAT(nr_idle_input_pending);
+ Dprintk("idled request %p.\n", new_req);
+
+ ret = parse_request(new_req, ti);
+ if (ret == -1)
+ continue;
+ if (new_req->userspace_module) {
+ if (ti->userspace_req)
+ HTTP_BUG();
+ goto out;
+ }
+ if (new_req->idle_input)
+ HTTP_BUG();
+ if (ret == -2) {
+ flush_request(new_req, ti);
+ continue;
+ }
+ if (new_req->redirect_secondary) {
+ list_add_tail(&new_req->redirect, &ti->redirect_pending);
+ INC_STAT(nr_redirect_pending);
+ check_req_list(new_req, &new_req->redirect);
+ continue;
+ }
+ send_generic_reply(new_req, ti);
+ if (!list_empty(&ti->output_pending))
+ send_replies(ti);
+ if (!list_empty(&ti->finish_pending))
+ finish_requests(ti);
+#else
+ spin_lock_irq(&ti->input_lock);
+ list_add_tail(&new_req->input, &ti->input_pending);
+ INC_STAT(nr_input_pending);
+ spin_unlock_irq(&ti->input_lock);
+#endif
+ }
+ }
+ if (count != last_count) {
+ last_count = count;
+ goto repeat;
+ }
+
+out:
+ return count;
+err:
+ sock_release(new_sock);
+ goto out;
+}
+
--- linux/net/http/output.c.orig Fri Sep 1 07:28:26 2000
+++ linux/net/http/output.c Fri Sep 1 07:40:06 2000
@@ -0,0 +1,506 @@
+/*
+ * TUX - Integrated HTTP layer and Object Cache
+ *
+ * Copyright (C) 2000, Ingo Molnar <
[email protected]>
+ *
+ * output.c: Send actual file-data to pending connections
+ */
+
+#include <net/http.h>
+
+int send_dynamic_reply (http_req_t *req, struct socket *sock, const char *buf, const size_t length, int push)
+{
+ mm_segment_t oldmm;
+ struct msghdr msg;
+ struct iovec iov;
+ int len, written = 0, left = length;
+
+ if (req) {
+ if (req->magic != HTTP_MAGIC)
+ HTTP_BUG();
+ if (req->no_output)
+ HTTP_BUG();
+ }
+
+ msg.msg_name = 0;
+ msg.msg_namelen = 0;
+ msg.msg_iov = &iov;
+ msg.msg_iovlen = 1;
+ msg.msg_control = NULL;
+ msg.msg_controllen = 0;
+ msg.msg_flags = MSG_NOSIGNAL;
+ if (!push)
+ msg.msg_flags |= MSG_NO_PUSH;
+repeat_send:
+ msg.msg_iov->iov_len = left;
+ msg.msg_iov->iov_base = (char *) buf + written;
+
+ oldmm = get_fs(); set_fs(KERNEL_DS);
+ len = sock_sendmsg(sock, &msg, left);
+ set_fs(oldmm);
+
+ if ((len == -512) || (len == -EAGAIN)) {
+ reap_kids();
+ goto repeat_send;
+ }
+ if (len > 0) {
+ written += len;
+ left -= len;
+ if (left)
+ goto repeat_send;
+ }
+ if (len < 0)
+ Dprintk("hm, sendmsg ret: %d, written: %d, left: %d.\n",
+ len, written, left);
+ else {
+ if (written != length)
+ HTTP_BUG();
+ if (left)
+ HTTP_BUG();
+ }
+ return written;
+}
+
+static int __local_tcp_send_csumcache(struct sock *sk, int flags, struct sk_buff *skb, int datalen, int last)
+{
+ int err;
+ struct tcp_opt *tp;
+
+ err = 0;
+ tp = &sk->tp_pinfo.af_tcp;
+
+ TCP_CHECK_TIMER(sk);
+
+ /* Wait for a connection to finish. */
+ if ((1 << sk->state) & ~(TCPF_ESTABLISHED | TCPF_CLOSE_WAIT))
+ printk("whoops 3\n");
+
+ clear_bit(SOCK_ASYNC_NOSPACE, &sk->socket->flags);
+
+ /* Stop on errors. */
+ if (sk->err)
+ goto do_sock_err;
+
+ /* Make sure that we are established. */
+ if (sk->shutdown & SEND_SHUTDOWN)
+ goto do_shutdown;
+
+ /* Prepare control bits for TCP header creation engine. */
+ TCP_SKB_CB(skb)->flags = TCPCB_FLAG_ACK;
+ if (last)
+ TCP_SKB_CB(skb)->flags |= TCPCB_FLAG_PSH;
+ TCP_SKB_CB(skb)->sacked = 0;
+ TCP_SKB_CB(skb)->urg_ptr = 0;
+ TCP_SKB_CB(skb)->seq = tp->write_seq;
+ TCP_SKB_CB(skb)->end_seq = TCP_SKB_CB(skb)->seq + datalen;
+
+ /* This advances tp->write_seq for us. */
+// printk("TCP-sending SKB %p: len:%d, data_len:%d, head:%p, data:%p, real_data:%p, tail:%p, end:%p.\n", skb, skb->len, skb->data_len, skb->head, skb->data, skb->real_data, skb->tail, skb->end);
+ tcp_send_skb(sk, skb, 0, datalen);
+ err = datalen;
+out:
+ TCP_CHECK_TIMER(sk);
+ return err;
+
+do_sock_err:
+ err = sock_error(sk);
+ goto out;
+do_shutdown:
+ err = -EPIPE;
+ goto out;
+}
+
+int nr_csumcache;
+int nr_csumcache_hit;
+int nr_csumcache_miss;
+
+void unuse_frag (struct sk_buff *skb, skb_frag_t *frag)
+{
+ urlobj_t *urlo = (urlobj_t *)frag->data;
+
+ if (!urlo)
+ HTTP_BUG();
+ Dprintk("unuse urlo (%p), skb %p (%d), frag %p.\n", urlo, skb, atomic_read(&skb->users), frag);
+ if (atomic_read(&skb->users) > 0)
+ HTTP_BUG();
+
+ put_urlo(urlo);
+}
+
+static void unuse_dynbuf (struct sk_buff *skb, skb_frag_t *frag)
+{
+ Dprintk("unuse dynbuf skb %p (%d), frag %p.\n", skb, atomic_read(&skb->users), frag);
+ if (atomic_read(&skb->users))
+ HTTP_BUG();
+
+ http_kfree(frag, ALLOC_DYNBUF);
+}
+
+static void unuse_dynfrag (struct sk_buff *skb, skb_frag_t *frag)
+{
+ urlobj_t *urlo = (urlobj_t *)frag->data;
+
+ if (!urlo)
+ HTTP_BUG();
+ Dprintk("unuse urlo (%p), skb %p (%d), frag %p.\n", urlo, skb, atomic_read(&skb->users), frag);
+ if (atomic_read(&skb->users))
+ HTTP_BUG();
+
+ http_kfree(frag, ALLOC_DYNFRAG);
+ put_urlo(urlo);
+}
+
+skb_frag_t * build_dynbuf_frag (http_req_t *req, int size)
+{
+ skb_frag_t *dynfrag;
+ struct page *page;
+ char *buf;
+
+ buf = http_kmalloc(sizeof(*dynfrag) + size, ALLOC_DYNBUF);
+ page = virt_to_page(buf);
+
+ dynfrag = (skb_frag_t *)buf;
+ dynfrag->size = size;
+ dynfrag->page = page;
+ dynfrag->page_offset = sizeof(*dynfrag) +
+ buf-(char *)page_address(page);
+ dynfrag->frag_done = unuse_dynbuf;
+ dynfrag->data = buf + sizeof(*dynfrag);
+ dynfrag->private = NULL;
+
+ return dynfrag;
+}
+
+static skb_frag_t * build_SSI_frag (http_req_t *req, skb_frag_t *frag)
+{
+ skb_frag_t *dynfrag;
+ struct page *page;
+ char *buf;
+ int ret;
+
+ if (!req->SSI || !frag->private)
+ HTTP_BUG();
+ if (!req->tcapi)
+ HTTP_BUG();
+
+ buf = http_kmalloc(sizeof(*frag) + frag->size, ALLOC_DYNFRAG);
+ page = virt_to_page(buf);
+
+ dynfrag = (skb_frag_t *)buf;
+ dynfrag->size = frag->size;
+ dynfrag->page = page;
+ dynfrag->page_offset = sizeof(skb_frag_t) +
+ buf-(char *)page_address(page);
+ dynfrag->frag_done = unuse_dynfrag;
+ dynfrag->data = frag->data;
+ dynfrag->private = frag->private;
+
+ ret = req->tcapi->generate_SSI_entry(req, dynfrag);
+ if (ret)
+ return dynfrag;
+
+ __free_page(page);
+ return frag;
+}
+
+static struct sk_buff *http_alloc_skb (void)
+{
+ struct sk_buff *skb;
+ int skbsize;
+
+ skbsize = MAX_TCP_HEADER + 15;
+repeat_alloc:
+ skb = alloc_skb(skbsize, GFP_USER);
+ if (!skb)
+ goto repeat_alloc;
+ atomic_set(&skb->users, 1);
+ skb_reserve(skb, MAX_TCP_HEADER);
+ skb->csum = 0;
+
+ return skb;
+}
+
+void add_frag_skb (http_req_t *req, struct sk_buff *skb, skb_frag_t *frag)
+{
+ unsigned int orig_csum;
+ int nr;
+
+ if (req->SSI && frag->private)
+ frag = build_SSI_frag(req, frag);
+
+ if (frag->size < 2)
+ HTTP_BUG();
+// if (skb->nr_frags)
+// HTTP_BUG();
+
+ nr = skb->nr_frags++;
+
+ /*
+ * Fold checksum:
+ */
+// if (skb->csum)
+// HTTP_BUG();
+ orig_csum = skb->csum;
+ if (skb->data_len & 1) {
+ skb->csum += frag->csum >> 8;
+ skb->csum += (frag->csum & 0xff) << 24;
+ } else
+ skb->csum += frag->csum;
+ if (skb->csum < orig_csum)
+ skb->csum++;
+
+ skb->frags[nr] = frag;
+ skb->len += frag->size;
+ skb->data_len += frag->size;
+
+ get_urlo(req->urlo);
+}
+
+static inline void push_sk (struct sock *sk)
+{
+ struct tcp_opt *tp;
+
+ tp = &sk->tp_pinfo.af_tcp;
+ if (tcp_write_xmit(sk))
+ tcp_check_probe_timer(sk, tp);
+ __tcp_push_pending_frames(sk, tp, tcp_current_mss(sk));
+}
+
+int http_send_object (http_req_t *req, int include_header, int push)
+{
+ int ret = 0, datasize, i, size = 0, packets;
+ skb_frag_t *frag;
+ struct sk_buff *skb;
+ csumcache_t *csumc;
+ struct sock *sk;
+
+ if (req->no_output)
+ HTTP_BUG();
+ req->http_status = 200;
+ csumc = req->urlo->csumc;
+ if (!csumc)
+ HTTP_BUG();
+
+ /*
+ * (Skip sending the cached header if the Trusted API has sent its
+ * own header.)
+ */
+ i = 0;
+ if (!include_header)
+ i = 1;
+
+ packets = 0;
+ sk = req->sock->sk;
+ if (current->state != TASK_RUNNING)
+ HTTP_BUG();
+
+ lock_sock(sk);
+ TCP_CHECK_TIMER(sk);
+ if (sk->err || (sk->state != TCP_ESTABLISHED)) {
+ ret = -1;
+ goto out_push;
+ }
+ for (; i < csumc->size; i++, packets++) {
+ frag = csumc->array + i;
+
+ /*
+ * build the split-skb from the csum entry:
+ */
+ skb = http_alloc_skb();
+ datasize = 0;
+ for (;;) {
+ add_frag_skb(req, skb, frag);
+ datasize += frag->size;
+ Dprintk("built skb %p (%d), offset %d, size %d out of frag %p, size %d.\n", skb, datasize, size, ret, frag, frag->size);
+ if (i == csumc->size-1)
+ break;
+ frag = csumc->array + i+1;
+ if (frag->size + datasize > csumc->packet_size)
+ break;
+ i++;
+ }
+
+ if (!datasize)
+ HTTP_BUG();
+ ret = __local_tcp_send_csumcache(sk, MSG_NOSIGNAL, skb, datasize, push && (i == csumc->size-1));
+ if (!ret)
+ HTTP_BUG();
+ if (ret < 0) {
+ HTTP_BUG();
+ goto err;
+ }
+ Dprintk("have sent skb %p (%d), offset %d, size %d.\n", skb, datasize, size, ret);
+ size += ret;
+ }
+ if (size > 0)
+ ret = req->urlo->body_len;
+ else
+ ret = size;
+out_push:
+ if (push)
+ push_sk(sk);
+ TCP_CHECK_TIMER(sk);
+ release_sock(sk);
+ return ret;
+
+err:
+ if (atomic_read(&skb->users) != 1)
+ HTTP_BUG();
+ kfree_skb(skb);
+ goto out_push;
+}
+
+/*
+ * HTTP header shortcuts.
+ */
+
+static const char success[] =
+ "HTTP/1.1 200 OK\r\n";
+// "Server: TUX 1.0\r\n";
+
+static const char no_perm[] =
+ "HTTP/1.1 403 Forbidden\r\n"
+ "Server: TUX 1.0\r\n\r\n";
+
+static const char try_later[] =
+ "HTTP/1.1 503 Service Unavailable\r\n"
+ "Server: TUX 1.0\r\n"
+ "Content-Length: 15\r\n\r\n"
+ "Try again later";
+
+static const char not_modified[] =
+ "HTTP/1.1 304 Not Modified\r\n"
+ "Server: TUX 1.0\r\n\r\n";
+
+
+/*
+ * note, send_success() is for external CGIs, and doesnt
+ * close the header part with a double newline.
+ */
+void send_success (http_req_t *req, struct socket *sock)
+{
+ req->http_status = 200;
+ send_dynamic_reply(req, sock, success, sizeof(success)-1, 0);
+}
+
+void send_err_forbidden (http_req_t *req, struct socket *sock)
+{
+ printk("WARNING: sending 403 reply!\n");
+ req->http_status = 403;
+ send_dynamic_reply(req, sock, no_perm, sizeof(no_perm)-1, 1);
+}
+
+void send_ret_not_modified (http_req_t *req, struct socket *sock)
+{
+ req->http_status = 304;
+ send_dynamic_reply(req, sock, not_modified, sizeof(not_modified)-1, 1);
+}
+
+void send_err_try_later (struct socket *sock)
+{
+ send_dynamic_reply(NULL, sock, try_later, sizeof(try_later)-1, 1);
+}
+
+void send_generic_reply (http_req_t *req, threadinfo_t *ti)
+{
+ int retval = 0;
+
+ Dprintk("SEND req %p <%p> (sock %p, sk %p) (keepalive: %d, status: %d) ({%s}, {%s}, {%s}, {%s}).\n", req, __builtin_return_address(0), req->sock, req->sock->sk, req->keep_alive, req->http_status, req->method_str ? req->method_str : "<null>", req->uri ? req->uri : "<null>", req->query ? req->query : "<null>", req->version_str ? req->version_str : "<null>");
+ if (req->magic != HTTP_MAGIC)
+ HTTP_BUG();
+ check_req_list(req, NULL);
+ if (req->no_output)
+ goto out;
+
+ if (req->sock->sk && (req->sock->sk->state == TCP_ESTABLISHED)) {
+ if (req->tcapi)
+ retval = req->tcapi->send_reply(req);
+ else
+ retval = http_send_object(req, 1, 1);
+
+ if (retval >= 0)
+ req->bytes_sent += retval;
+ }
+out:
+ if (retval != -3)
+ flush_request(req, ti);
+}
+
+int send_replies (threadinfo_t *ti)
+{
+ struct list_head *head, *curr, *next;
+ struct sock *sk;
+ http_req_t *req;
+ int count = 0;
+
+ Dprintk("checking output queue ...\n");
+
+repeat_lock:
+ spin_lock_irq(&ti->output_lock);
+ head = &ti->output_pending;
+ next = head->next;
+
+ while ((curr = next) != head) {
+ if (current->need_resched)
+ break;
+ if (!count++)
+ __set_task_state(current, TASK_RUNNING);
+
+ req = list_entry(curr, http_req_t, output);
+ if (req->ti != ti)
+ HTTP_BUG();
+ if (ti->thread != current)
+ HTTP_BUG();
+ if (req->userspace_module)
+ HTTP_BUG();
+ check_req_list(req, &req->output);
+ next = curr->next;
+
+ if (req->redirect_secondary)
+ HTTP_BUG();
+ sk = req->sock->sk;
+
+ Dprintk("pending output req %p, socket state %d.\n", req, sk->state);
+ check_req_list(req, &req->output);
+ list_del(curr);
+ DEC_STAT(nr_output_pending);
+ check_req_list(req, NULL);
+
+ spin_unlock_irq(&ti->output_lock);
+
+ send_generic_reply(req, ti);
+ goto repeat_lock;
+ }
+ spin_unlock_irq(&ti->output_lock);
+ Dprintk("finished checking output queue ...\n");
+ return count;
+}
+
+void flush_outputqueue (threadinfo_t *ti)
+{
+ struct list_head *head, *curr, *next;
+ http_req_t *req;
+
+repeat:
+ spin_lock_irq(&ti->output_lock);
+ head = &ti->output_pending;
+ curr = head->next;
+
+ if (curr != head) {
+ req = list_entry(curr, http_req_t, output);
+ next = curr->next;
+ list_del(curr);
+ DEC_STAT(nr_output_pending);
+ spin_unlock_irq(&ti->output_lock);
+
+ req->keep_alive = 0;
+ req->http_status = -1;
+ flush_request(req, ti);
+ goto repeat;
+ } else
+ spin_unlock_irq(&ti->output_lock);
+
+ free_pages((unsigned long)ti->output_buffer, OUT_BUF_ORDER);
+ ti->output_buffer = NULL;
+}
+
--- linux/net/http/input.c.orig Fri Sep 1 07:28:26 2000
+++ linux/net/http/input.c Fri Sep 1 07:28:26 2000
@@ -0,0 +1,863 @@
+/*
+ * TUX - Integrated HTTP layer and Object Cache
+ *
+ * Copyright (C) 2000, Ingo Molnar <
[email protected]>
+ *
+ * input.c: handle HTTP headers arriving on accepted connections
+ */
+
+#include <net/http.h>
+#include <linux/kmod.h>
+
+static int url_writepage (struct file *file, struct page *page)
+{
+ urlobj_t *urlo = dentry_to_urlo(file->f_dentry);
+
+ return urlo->real_aops->writepage(file, page);
+}
+
+static int url_readpage (struct file *file, struct page *page)
+{
+ unsigned long offset, next_offset, index;
+ char *orig_buf, *buf, *from;
+ int size, bytes, i;
+ csumcache_t *csumc;
+ skb_frag_t *frag;
+ urlobj_t *urlo;
+
+
+ urlo = dentry_to_urlo(file->f_dentry);
+ get_urlo(urlo);
+ csumc = urlo->csumc;
+ if (!csumc || !atomic_read(&urlo->csumcs_created)) {
+ put_urlo(urlo);
+ return urlo->real_aops->readpage(file, page);
+ }
+
+ index = page->index << PAGE_CACHE_SHIFT;
+ size = PAGE_CACHE_SIZE;
+ offset = 0;
+ orig_buf = buf = (char *) kmap(page);
+
+ for (i = 1; i < csumc->size; i++, offset = next_offset) {
+ frag = csumc->array + i;
+
+ next_offset = offset + frag->size;
+ if (index >= next_offset)
+ continue;
+ if (index < offset)
+ HTTP_BUG();
+ bytes = size;
+ if (bytes > next_offset-index)
+ bytes = next_offset-index;
+ if (bytes > PAGE_OFFSET)
+ HTTP_BUG();
+ if (frag->page_offset + index-offset > PAGE_CACHE_SIZE)
+ HTTP_BUG();
+
+ from = (char *)kmap(frag->page) + frag->page_offset;
+ memcpy(buf, from + index-offset, bytes);
+ kunmap(frag->page);
+
+ size -= bytes;
+ if (size < 0)
+ HTTP_BUG();
+ buf += bytes;
+ index += bytes;
+ if (!size)
+ break;
+ }
+ if (buf > orig_buf + PAGE_CACHE_SIZE)
+ HTTP_BUG();
+ kunmap(page);
+ put_urlo(urlo);
+ SetPageUptodate(page);
+ UnlockPage(page);
+ return 0;
+}
+
+static int url_prepare_write (struct file *filp, struct page *page, unsigned from, unsigned to)
+{
+ urlobj_t *urlo = mapping_to_urlo(page->mapping);
+ struct inode *inode = filp->f_dentry->d_inode;
+ struct address_space_operations *aops;
+
+ aops = urlo->real_aops;
+ free_urlo(inode);
+ return aops->prepare_write(filp, page, from, to);
+}
+
+static int url_commit_write (struct file *filp, struct page *page,
+ unsigned from, unsigned to)
+{
+ int ret;
+ urlobj_t *urlo = filp_to_urlo(filp);
+ struct address_space_operations *aops;
+
+
+ aops = urlo->real_aops;
+ ret = aops->commit_write(filp, page, from, to);
+ return ret;
+}
+
+static int url_bmap(struct address_space *mapping, long block)
+{
+ urlobj_t *urlo = mapping_to_urlo(mapping);
+
+ return urlo->real_aops->bmap(mapping, block);
+}
+
+static unsigned long url_destroy(struct inode *inode)
+{
+ urlobj_t *urlo;
+
+ if (inode->i_mapping->a_ops != &url_aops)
+ HTTP_BUG();
+
+ urlo = inode_to_urlo(inode);
+ if (urlo->real_aops->destroy)
+ HTTP_BUG();
+ return free_urlo(inode);
+}
+
+struct address_space_operations url_aops = {
+ writepage: url_writepage,
+ readpage: url_readpage,
+ prepare_write: url_prepare_write,
+ commit_write: url_commit_write,
+ destroy: url_destroy,
+ bmap: url_bmap
+};
+
+extern spinlock_t pagecache_lock;
+static spinlock_t add_urlo_lock = SPIN_LOCK_UNLOCKED;
+
+int add_inode_urlo_atomic (struct inode *inode, urlobj_t *urlo)
+{
+ struct address_space *mapping;
+ int ret = 1;
+
+ mapping = inode->i_mapping;
+ /*
+ * Only regular inodes can be in the checksumcache:
+ */
+ if (&inode->i_data != mapping)
+ HTTP_BUG();
+
+ spin_lock(&add_urlo_lock);
+ spin_lock(&mapping->i_shared_lock);
+ spin_lock(&pagecache_lock);
+
+ /*
+ * Are we really the one installing the new mapping?
+ */
+ if (inode->i_mapping->http_data)
+ goto out;
+
+ urlo->inode = inode;
+ urlo->real_aops = mapping->a_ops;
+ mapping->a_ops = &url_aops;
+ mapping->http_data = urlo;
+
+ ret = 0;
+out:
+ spin_unlock(&pagecache_lock);
+ spin_unlock(&inode->i_mapping->i_shared_lock);
+ spin_unlock(&add_urlo_lock);
+
+ return ret;
+}
+
+static void remove_inode_urlo (struct inode *inode, urlobj_t *urlo)
+{
+ struct address_space *mapping = inode->i_mapping;
+
+ if (&inode->i_data != mapping)
+ HTTP_BUG();
+
+ spin_lock(&pagecache_lock);
+ spin_lock(&mapping->i_shared_lock);
+
+ mapping->a_ops = urlo->real_aops;
+ urlo->real_aops = NULL;
+ mapping->http_data = NULL;
+
+ spin_unlock(&mapping->i_shared_lock);
+ spin_unlock(&pagecache_lock);
+}
+
+unsigned long __put_urlo (urlobj_t *urlo)
+{
+ int i;
+ csumcache_t *csumc = urlo->csumc;
+ unsigned long freed_bytes = 0;
+
+
+ if (csumc) {
+ struct page *page = NULL;
+
+ atomic_sub(urlo->filelen, (atomic_t *)&kstat.csumcache_total);
+
+ for (i = 0; i < csumc->size; i++) {
+ skb_frag_t *frag = csumc->array + i;
+
+ if (frag->page != page) {
+ page = frag->page;
+ if (page_count(page) == 1)
+ freed_bytes += PAGE_SIZE;
+ __free_page(page);
+ }
+ }
+ http_kfree(csumc->array, ALLOC_CSUMCARRAY);
+ freed_bytes += csumc->size * sizeof(skb_frag_t);
+ http_kfree(csumc, ALLOC_CSUMCSTRUCT);
+ freed_bytes += sizeof(*csumc);
+ }
+ if (atomic_read(&urlo->users))
+ HTTP_BUG();
+// FIXME: do a usage count rather, or something
+// if (urlo->tcapi)
+// unregister_httpmodule(urlo->tcapi);
+ memset(urlo, 0, sizeof(*urlo));
+ http_kfree(urlo, ALLOC_URLO_STRUCT);
+ DEC_STAT(nr_urlo);
+ urlo = NULL;
+ freed_bytes += sizeof(*urlo);
+
+ return freed_bytes;
+}
+
+unsigned long free_urlo (struct inode *inode)
+{
+ unsigned long freed_bytes = 0;
+ urlobj_t *urlo;
+
+ lock_kernel();
+ if (inode->i_mapping->a_ops != &url_aops) {
+ printk("race #1.\n");
+ unlock_kernel();
+ return freed_bytes;
+ }
+ urlo = inode_to_urlo(inode);
+
+ if (inode->i_mapping->a_ops != &url_aops)
+ HTTP_BUG();
+ if (!atomic_read(&urlo->users))
+ HTTP_BUG();
+ if (urlo->inode != inode)
+ HTTP_BUG();
+
+ remove_inode_urlo(inode, urlo);
+ unlock_kernel();
+
+ return put_urlo(urlo);
+}
+
+
+struct dentry * http_lookup (char *filename, struct nameidata *base,
+ unsigned int flags)
+{
+ struct nameidata nd;
+ int err;
+
+ if (!base) {
+ nd.mnt = current->fs->rootmnt;
+ nd.dentry = current->fs->root;
+ nd.last.len = 0;
+ nd.flags = LOOKUP_FOLLOW|LOOKUP_POSITIVE;
+ } else
+ nd = *base;
+ nd.flags |= flags;
+ mntget(nd.mnt);
+ dget(nd.dentry);
+
+ if ((err = path_walk(filename, &nd))) {
+ Dprintk("path_walk() returned with %d!\n", err);
+ return ERR_PTR(err);
+ }
+ mntput(nd.mnt);
+ return nd.dentry;
+}
+
+#define ERR() do { Dprintk("error at %s:%d.\n", __FILE__, __LINE__); } while (0)
+
+int url_permission (struct inode *inode)
+{
+ umode_t mode;
+
+ /*
+ * Maybe allow a dynamic HTTP module. We are really paranoid,
+ * only root:root setuid root, setguid root and others+group:none
+ * permissions are allowed. This should at least show that
+ * these dynamic applications are truly _TRUSTED_.
+ */
+ #define TRUSTED_MODULE_REQUIRED (S_ISUID|S_ISGID)
+
+ mode = inode->i_mode;
+ Dprintk("URL inode mode: %08x.\n", mode);
+
+ if (!S_ISREG(mode))
+ return -1;
+
+ if (((mode & TRUSTED_MODULE_REQUIRED) == TRUSTED_MODULE_REQUIRED) &&
+ !inode->i_uid && !inode->i_gid) {
+ Dprintk("http_mode_userspace: %08x\n", http_mode_userspace);
+ if (mode & http_mode_userspace) {
+ Dprintk("userspace module!\n");
+ return 2;
+ }
+ Dprintk("kernelspace module.\n");
+ return 1;
+ }
+#if CONFIG_HTTP_EXTCGI
+ if (((mode & 0xfff) == http_mode_cgi) && !inode->i_uid && !inode->i_gid)
+ return 1;
+#endif
+ /*
+ * Paranoia: first forbid things, then maybe allow.
+ * Only regular files allowed.
+ */
+ if (mode & http_mode_forbidden)
+ return -2;
+ /*
+ * at least one bit in the 'allowed' set has to
+ * be present to allow access.
+ */
+ if (!(mode & http_mode_allowed))
+ return -3;
+ return 0;
+}
+
+int lookup_urlo (http_req_t *req, unsigned int flag)
+{
+ int trusted_url = 0, miss = 0, userspace;
+ urlobj_t *urlo = NULL;
+ struct dentry *dentry = NULL;
+ struct inode *inode;
+ char *filename;
+
+ if (req->dentry) HTTP_BUG();
+ if (req->urlo) HTTP_BUG();
+ /*
+ * Eat all leading slashes.
+ */
+ filename = req->objectname;
+ while (*filename == '/') filename++;
+
+ dentry = http_lookup (filename, &docroot, flag);
+ Dprintk("looked up {%s} == dentry %p.\n", filename, dentry);
+ if (IS_ERR(dentry) || !dentry) {
+ if (PTR_ERR(dentry) == -EWOULDBLOCK) {
+ if (!flag)
+ HTTP_BUG();
+ goto cachemiss_atomic;
+ }
+ goto abort_locked;
+ }
+ Dprintk("SUCCESS, looked up {%s} == dentry %p (inode %p, count %d.)\n", filename, dentry, dentry->d_inode, atomic_read(&dentry->d_count));
+ if (!dentry->d_inode)
+ goto abort_locked_dput;
+ inode = dentry->d_inode;
+
+ /*
+ * At this point we have a real, non-negative dentry.
+ * Check for an urlo potentially attached to the inode:
+ */
+ if (urlo)
+ HTTP_BUG();
+ trusted_url = url_permission(inode);
+
+ if (trusted_url < 0) {
+ Dprintk("FAILED trusted dentry %p (urlo %p) permission %d.\n", dentry, urlo, trusted_url);
+ goto abort_no_permission_unlock;
+ }
+ userspace = 0;
+ if (trusted_url == 2)
+ userspace = 1;
+
+repeat_urlo:
+ if (inode->i_mapping->a_ops != &url_aops) {
+ if (flag == LOOKUP_ATOMIC)
+ goto cachemiss_atomic_dput;
+ else
+ goto cachemiss;
+ }
+
+ urlo = dentry_to_urlo(dentry);
+ if (urlo->inode != inode)
+ HTTP_BUG();
+ get_urlo(urlo); // usage count
+
+ Dprintk("looked up cached dentry %p, (urlo %p, API %p, count %d.)\n", dentry, urlo, urlo->tcapi, dentry ? atomic_read(&dentry->d_count) : -1 );
+
+ if (urlo->tcapi && !trusted_url)
+ BUG(); // should not happen for the time being
+ if (!urlo->tcapi && trusted_url)
+ BUG(); // should not happen either
+
+ if (urlo->tcapi) {
+ if (!req->query && (req->method == METHOD_GET))
+ goto abort_no_permission;
+ req->tcapi = urlo->tcapi;
+ if (urlo->tcapi->userspace_id) {
+ if (!userspace)
+ goto abort_no_permission;
+ if (req->userspace_module)
+ HTTP_BUG();
+ req->userspace_module = 1;
+ }
+ } else
+ if (trusted_url)
+ HTTP_BUG(); // should not happen
+ if (!urlo->tcapi)
+ urlo_hist_hit(urlo->filelen);
+ if (!urlo->tcapi && !urlo->csumc)
+ miss = 1;
+
+out:
+ if (!miss && !req->tcapi && (!urlo || !urlo->csumc)) {
+ if (dentry) printk("BUG ... looked up {%s} == dentry %p (inode %p, count %d.)\n", filename, dentry, dentry->d_inode, atomic_read(&dentry->d_count));
+ if (dentry) printk("BUG ... cached dentry %p, (urlo %p, API %p, count %d.)\n", dentry, urlo, urlo->tcapi, dentry ? atomic_read(&dentry->d_count) : -1 );
+ HTTP_BUG();
+ }
+
+abort:
+ if (req->urlo) HTTP_BUG();
+ if (req->dentry) HTTP_BUG();
+ if (urlo && urlo->tcapi) {
+ if (!req->tcapi)
+ HTTP_BUG();
+ dput(dentry);
+ dentry = NULL;
+ put_urlo(urlo);
+ urlo = NULL;
+ }
+ req->dentry = dentry;
+ req->urlo = urlo;
+ return miss;
+
+cachemiss_atomic_dput:
+ dput(dentry);
+
+cachemiss_atomic:
+ dentry = NULL;
+ urlo = NULL;
+ miss = 1;
+ goto out;
+
+cachemiss:
+ if (urlo)
+ BUG();
+ urlo = http_kmalloc(sizeof(*urlo), ALLOC_URLO_STRUCT);
+ INC_STAT(nr_urlo);
+ memset(urlo, 0, sizeof(*urlo));
+ INIT_LIST_HEAD(&urlo->secondary_pending);
+ get_urlo(urlo); // inode reference
+ get_urlo(urlo); // usage count
+
+ urlo->filelen = inode->i_size;
+
+ if (trusted_url) {
+#if CONFIG_HTTP_EXTCGI
+ extern tcapi_template_t extcgi_tcapi;
+
+ if ((inode->i_mode & 0xfff) == http_mode_cgi)
+ urlo->tcapi = &extcgi_tcapi;
+ else
+#endif
+ if (load_httpmodule(urlo, filename))
+ goto abort_no_permission;
+ if (userspace && !urlo->tcapi->userspace_id)
+ goto abort_no_permission;
+ if (!userspace && urlo->tcapi->userspace_id)
+ goto abort_no_permission;
+ req->tcapi = urlo->tcapi;
+ if (req->tcapi->userspace_id) {
+ if (!userspace)
+ goto abort_no_permission;
+ if (req->userspace_module)
+ HTTP_BUG();
+ req->userspace_module = 1;
+ }
+ }
+ if (add_inode_urlo_atomic(inode, urlo)) {
+ http_kfree(urlo, ALLOC_URLO_STRUCT);
+ DEC_STAT(nr_urlo);
+ urlo = NULL;
+ DEC_STAT(nr_urlo_references);
+ DEC_STAT(nr_urlo_references);
+ goto repeat_urlo;
+ }
+ /*
+ * Do not cache the file above the threshold. This still
+ * keeps the urlo for the duration of this request, but
+ * it's going to be freed when the request finishes.
+ */
+ if (urlo->filelen > http_max_cached_filesize)
+ free_urlo(urlo->inode);
+ miss = 1;
+ if (urlo && urlo->tcapi)
+ miss = 0;
+ goto out;
+
+abort_locked_dput:
+ dput(dentry);
+abort_locked:
+ dentry = NULL;
+ goto abort;
+
+abort_no_permission:
+abort_no_permission_unlock:
+ if (dentry) {
+ dput(dentry);
+ dentry = NULL;
+ }
+ put_urlo(urlo);
+ urlo = NULL; req->redirect_secondary = 1;
+ goto abort;
+}
+
+int http_miss_req (http_req_t *req)
+{
+ /*
+ * this is the 'slow path', look up, read the file, construct
+ * the csumcache. We pass this work off to one of the 'async
+ * IO threads', so that the fast TUX threads do not get held
+ * up unnecesserily.
+ */
+ Dprintk("queueing primary cachemiss.\n");
+ queue_cachemiss(req);
+
+ return -1;
+}
+
+static void unidle_req (http_req_t *req)
+{
+ threadinfo_t *ti = req->ti;
+
+ Dprintk("UNIDLE req %p <%p> (sock %p, sk %p) (keepalive: %d, status: %d) ({%s}, {%s}, {%s}, {%s}).\n", req, __builtin_return_address(0), req->sock, req->sock->sk, req->keep_alive, req->http_status, req->method_str ? req->method_str : "<null>", req->uri ? req->uri : "<null>", req->query ? req->query : "<null>", req->version_str ? req->version_str : "<null>");
+ if (req->magic != HTTP_MAGIC)
+ HTTP_BUG();
+ if (!test_and_clear_bit(0, &req->idle_input)) {
+ Dprintk("unidling %p, wasnt idle!\n", req);
+ spin_lock_irq(&ti->input_lock);
+ check_req_list(req, &req->input);
+ list_del(&req->input);
+ DEC_STAT(nr_input_pending);
+ check_req_list(req, NULL);
+ spin_unlock_irq(&ti->input_lock);
+ } else {
+ if (timer_pending(&req->keepalive_timer))
+ del_timer(&req->keepalive_timer);
+ DEC_STAT(nr_idle_input_pending);
+ Dprintk("unidled %p.\n", req);
+ }
+ if (req->idle_input)
+ HTTP_BUG();
+}
+
+#define GOTO_INCOMPLETE do { Dprintk("incomplete at %s:%d.\n", __FILE__, __LINE__); goto incomplete; } while (0)
+#define GOTO_REDIRECT do { printk("redirect at %s:%d.\n", __FILE__, __LINE__); goto redirect; } while (0)
+#define GOTO_REDIRECT_NONIDLE do { printk("redirect at %s:%d.\n", __FILE__, __LINE__); goto redirect_nonidle; } while (0)
+
+static int read_request (struct socket *sock, char *buf, int size)
+{
+ mm_segment_t oldmm;
+ struct msghdr msg;
+ struct iovec iov;
+ int len;
+
+ msg.msg_name = 0;
+ msg.msg_namelen = 0;
+ msg.msg_iov = &iov;
+ msg.msg_iovlen = 1;
+ msg.msg_control = NULL;
+ msg.msg_controllen = 0;
+ msg.msg_flags = 0;
+
+ msg.msg_iov->iov_base = buf;
+ msg.msg_iov->iov_len = size;
+
+ oldmm = get_fs(); set_fs(KERNEL_DS);
+
+read_again:
+ len = sock_recvmsg(sock, &msg, size, MSG_DONTWAIT|MSG_PEEK);
+ set_fs(oldmm);
+
+ /*
+ * We must not get a signal inbetween
+ */
+ if ((len == -EAGAIN) || (len == -512)) {
+ if (!signal_pending(current)) {
+ len = 0;
+ goto out;
+ }
+ reap_kids();
+ goto read_again;
+ }
+out:
+ return len;
+}
+
+void trunc_headers (http_req_t *req)
+{
+ int len, addr_len = 0;
+
+ len = req->sock->sk->prot->recvmsg(req->sock->sk, NULL, req->parsed_len, 1, MSG_TRUNC, &addr_len);
+ Dprintk("truncated %d bytes at %p. (wanted: %d.)\n", len, __builtin_return_address(0), req->parsed_len);
+}
+
+void print_req (http_req_t *req)
+{
+ int i;
+ char *tmp;
+ struct sock *sk = req->sock->sk;
+
+ printk("PRINT req %p <%p>\n", req, __builtin_return_address(0));
+ printk("... sock %p, sk %p, sk->state: %d, sk->err: %d\n", req->sock, req->sock->sk, sk->state, sk->err);
+ printk("... receive_queue: %d, error_queue: %d, keepalive: %d, status: %d\n", !skb_queue_empty(&sk->receive_queue), !skb_queue_empty(&sk->error_queue), req->keep_alive, req->http_status);
+ printk("... meth:{%s}, uri:{%s}, query:{%s}, ver:{%s}\n", req->method_str ? req->method_str : "<null>", req->uri ? req->uri : "<null>", req->query ? req->query : "<null>", req->version_str ? req->version_str : "<null>");
+ printk("... post_data:{%s}(%d).\n", req->post_data, req->post_data_len);
+ tmp = req->headers;
+ for (i = 0; i < 10; i++) {
+ printk("... header%d: {%s}\n", i, tmp);
+ tmp = tmp + strlen(tmp) + 1;
+ }
+}
+/*
+ * parse_request() reads all available TCP/IP data and prepares
+ * the request if the HTTP request is complete. (we can get HTTP
+ * requests in several packets.) Invalid requests are redirected
+ * to the secondary server.
+ */
+
+int parse_request (http_req_t *req, threadinfo_t *ti)
+{
+ int len, reqlen, ret = 0;
+ urlobj_t *urlo;
+ int missed;
+
+ if (req->magic != HTTP_MAGIC)
+ HTTP_BUG();
+
+ /* First, read the data */
+ len = read_request(req->sock, req->headers, MAX_HEADER_LEN-1);
+ if (len < 0) {
+ printk("got %d from read_request().\n", len);
+// print_req(req);
+ GOTO_REDIRECT;
+ }
+ if (!len) {
+ GOTO_INCOMPLETE;
+ }
+
+ /*
+ * Make it a zero-delimited string to automatically get
+ * protection against various buffer overflow situations.
+ * Then pass it to the HTTP protocol stack.
+ */
+ req->headers[len] = 0;
+ req->headers_len = len;
+
+ reqlen = parse_http_message(req, len);
+
+ /*
+ * Is the request fully read? (or is there any error)
+ */
+ if (reqlen < 0)
+ GOTO_REDIRECT;
+ if (!reqlen) {
+ if (len >= MAX_HEADER_LEN-1)
+ GOTO_REDIRECT;
+ GOTO_INCOMPLETE;
+ }
+ unidle_req(req);
+
+ missed = lookup_urlo(req, LOOKUP_ATOMIC);
+ urlo = req->urlo;
+ if (req->userspace_module)
+ goto userspace_module_nonidle;
+// if (!missed && !urlo)
+// GOTO_REDIRECT_NONIDLE;
+ if (missed || (urlo && !urlo->tcapi && !urlo->csumc)) {
+ Dprintk("uncached request.\n");
+ if (req->parsed_len)
+ trunc_headers(req);
+ return http_miss_req(req);
+ }
+#if 0
+ if (req->tcapi)
+ HTTP_BUG();
+#endif
+ if ((req->method != METHOD_GET) || req->query) {
+ Dprintk("TCAPI %p request.\n", req->tcapi);
+ if (!req->tcapi)
+ GOTO_REDIRECT_NONIDLE;
+ if (req->dentry)
+ HTTP_BUG();
+ ret = req->tcapi->query(req);
+ }
+ if (!req->redirect_secondary && req->parsed_len)
+ trunc_headers(req);
+
+ return ret;
+redirect:
+ unidle_req(req);
+redirect_nonidle:
+ req->redirect_secondary = 1;
+ INC_STAT(parse_static_redirect);
+ return 0;
+incomplete:
+ INC_STAT(parse_static_incomplete);
+ return -1;
+userspace_module_nonidle:
+ if (req->redirect_secondary)
+ HTTP_BUG();
+ trunc_headers(req);
+ queue_userspace_req(req, ti);
+ return -1;
+}
+
+int read_headers (threadinfo_t *ti)
+{
+ struct list_head *head, *curr, *next;
+ int count = 0, ret;
+ struct sock *sk;
+ http_req_t *req;
+
+restart_loop:
+ spin_lock_irq(&ti->input_lock);
+ head = &ti->input_pending;
+ next = head->next;
+
+ while ((curr = next) != head) {
+ if (current->need_resched)
+ break;
+
+ req = list_entry(curr, http_req_t, input);
+ Dprintk("READ req %p HEADERS <%p> (sock %p, sk %p) (keepalive: %d, status: %d) ({%s}, {%s}, {%s}, {%s}).\n", req, __builtin_return_address(0), req->sock, req->sock->sk, req->keep_alive, req->http_status, req->method_str ? req->method_str : "<null>", req->uri ? req->uri : "<null>", req->query ? req->query : "<null>", req->version_str ? req->version_str : "<null>");
+
+ if (req->ti != ti)
+ HTTP_BUG();
+ if (req->magic != HTTP_MAGIC)
+ HTTP_BUG();
+ if (req->userspace_module)
+ HTTP_BUG();
+
+ check_req_list(req, &req->input);
+ next = curr->next;
+ list_del(curr);
+ DEC_STAT(nr_input_pending);
+ check_req_list(req, NULL);
+
+ if (test_bit(0, &req->idle_input))
+ HTTP_BUG();
+ /*
+ * If the connection is lost, remove from queue
+ */
+ sk = req->sock->sk;
+ if (!sk || (sk->state != TCP_ESTABLISHED) || sk->err ||
+ !skb_queue_empty(&sk->error_queue)) {
+
+ Dprintk("LOST req %p <%p> (sock %p, sk %p, sk->state: %d, sk->err: %d, skb_queue_empty(error_queue): %d) (keepalive: %d, status: %d) ({%s}, {%s}, {%s}, {%s}).\n", req, __builtin_return_address(0), req->sock, req->sock->sk, sk->state, sk->err, skb_queue_empty(&sk->error_queue), req->keep_alive, req->http_status, req->method_str ? req->method_str : "<null>", req->uri ? req->uri : "<null>", req->query ? req->query : "<null>", req->version_str ? req->version_str : "<null>");
+ spin_unlock_irq(&ti->input_lock);
+
+ if (!count++)
+ __set_task_state(current, TASK_RUNNING);
+ req->keep_alive = 0;
+ req->http_status = -1;
+ flush_request(req, ti);
+ goto restart_loop;
+ }
+ add_keepalive_timer(req);
+ if (test_and_set_bit(0, &req->idle_input))
+ HTTP_BUG();
+ INC_STAT(nr_idle_input_pending);
+ Dprintk("marked %p idle!\n", req);
+
+ /*
+ * If no data pending then do not parse request
+ */
+ if (skb_queue_empty(&sk->receive_queue)) {
+ INC_STAT(inputqueue_no_packet);
+ Dprintk("request %p had no input packets!\n", req);
+ continue;
+ }
+ spin_unlock_irq(&ti->input_lock);
+ INC_STAT(inputqueue_got_packet);
+
+ if (!count++)
+ __set_task_state(current, TASK_RUNNING);
+
+ ret = parse_request(req, ti);
+
+ /*
+ * Is input data incomplete (or is cachemiss/userspace pending):
+ */
+ if (ret == -1)
+ goto restart_loop;
+
+ /*
+ * Is it finished:
+ */
+ if (ret == -2) {
+ flush_request(req, ti);
+ goto restart_loop;
+ }
+
+ check_req_list(req, NULL);
+ /*
+ * Add to either the redirect_pending or
+ * the output_pending queue
+ */
+ if (req->redirect_secondary) {
+ list_add_tail(&req->redirect, &ti->redirect_pending);
+ INC_STAT(nr_redirect_pending);
+ check_req_list(req, &req->redirect);
+ goto restart_loop;
+ }
+
+ /*
+ * Is it a request for userspace:
+ */
+ if (req->userspace_module)
+ HTTP_BUG();
+#if 1
+ send_generic_reply(req, ti);
+#else
+ spin_lock_irq(&ti->output_lock);
+ list_add_tail(&req->output, &ti->output_pending);
+ INC_STAT(nr_output_pending);
+ check_req_list(req, &req->output);
+ spin_unlock_irq(&ti->output_lock);
+#endif
+ goto restart_loop;
+ }
+ spin_unlock_irq(&ti->input_lock);
+ return count;
+}
+
+void flush_inputqueue (threadinfo_t *ti)
+{
+ struct list_head *head, *curr, *next;
+ http_req_t *req;
+
+restart:
+ spin_lock_irq(&ti->input_lock);
+ head = &ti->input_pending;
+ curr = head->next;
+
+ if (curr != head) {
+ req = list_entry(curr, http_req_t, input);
+ next = curr->next;
+ list_del(curr);
+ DEC_STAT(nr_input_pending);
+ req->keep_alive = 0;
+ req->http_status = -1;
+ spin_unlock_irq(&ti->input_lock);
+ flush_request(req, ti);
+ goto restart;
+ }
+ spin_unlock_irq(&ti->input_lock);
+}
+
--- linux/net/http/redirect.c.orig Fri Sep 1 07:28:26 2000
+++ linux/net/http/redirect.c Fri Sep 1 07:28:26 2000
@@ -0,0 +1,161 @@
+/*
+ * TUX - Integrated HTTP layer and Object Cache
+ *
+ * Copyright (C) 2000, Ingo Molnar <
[email protected]>
+ *
+ * redirect.c: redirect requests to other server sockets (such as Apache).
+ */
+
+#include <net/http.h>
+
+static void dummy_destructor(struct open_request *req)
+{
+}
+
+static struct or_calltable dummy =
+{
+ 0,
+ NULL,
+ NULL,
+ &dummy_destructor,
+ NULL
+};
+
+static int redirect_sock (http_req_t *req, const int port)
+{
+ struct socket *sock = req->sock;
+ struct open_request *tcpreq;
+ struct sock *sk, *oldsk;
+
+ /*
+ * Look up (optional) listening user-space socket.
+ */
+ local_bh_disable();
+ sk = tcp_v4_lookup_listener(INADDR_ANY, port, 0);
+ local_bh_enable();
+
+ /* No secondary server found */
+ if (!sk)
+ return -1;
+
+ /*
+ * Requeue the 'old' socket as an accept-socket of
+ * the listening socket. This way we can shuffle
+ * a socket around. Since we've read the input data
+ * via the non-destructive MSG_PEEK, the secondary
+ * server can be used transparently.
+ */
+ oldsk = sock->sk;
+ unlink_http_socket(req);
+ lock_sock(sk);
+
+ if (sk->state != TCP_LISTEN || tcp_acceptq_is_full(sk)) {
+ release_sock(sk);
+ sock_put(sk);
+ return -1;
+ }
+
+ tcpreq = tcp_openreq_alloc();
+
+ if (!tcpreq) {
+ release_sock(sk);
+ sock_put(sk);
+ return -1;
+ }
+
+ sock->sk = NULL;
+ sock->state = SS_UNCONNECTED;
+
+ tcpreq->class = &dummy;
+ write_lock_irq(&oldsk->callback_lock);
+ oldsk->socket = NULL;
+ oldsk->sleep = NULL;
+ write_unlock_irq(&oldsk->callback_lock);
+
+ tcp_acceptq_queue(sk, tcpreq, oldsk);
+
+ sk->data_ready(sk, 0);
+
+ release_sock(sk);
+ sock_put(sk);
+
+ return 0;
+}
+
+int redirect_requests (threadinfo_t *ti)
+{
+ struct list_head *head, *curr, *next;
+ struct sock *sk;
+ http_req_t *req;
+ int count = 0;
+
+ head = &ti->redirect_pending;
+ next = head->next;
+
+ while ((curr = next) != head) {
+ if (current->need_resched)
+ break;
+ if (!count++)
+ __set_task_state(current, TASK_RUNNING);
+ req = list_entry(curr, http_req_t, redirect);
+ if (req->magic != HTTP_MAGIC)
+ HTTP_BUG();
+ check_req_list(req, &req->redirect);
+ if (req->ti != ti)
+ HTTP_BUG();
+ if (ti->thread != current)
+ HTTP_BUG();
+ next = curr->next;
+ list_del(curr);
+ check_req_list(req, NULL);
+
+ sk = req->sock->sk;
+ if (req->sock && req->sock->sk)
+ remove_wait_queue(req->sock->sk->sleep,&(req->sleep));
+
+ Dprintk("redirecting request (headers: {%s})\n", req->headers);
+ check_req_list(req, NULL);
+ if (redirect_sock(req, http_clientport)) {
+ check_req_list(req, NULL);
+ send_err_forbidden(req, req->sock);
+ check_req_list(req, NULL);
+ } else {
+ /*
+ * It's now completely up to the secondary
+ * server to handle this request.
+ */
+ check_req_list(req, NULL);
+ sock_release(req->sock);
+ check_req_list(req, NULL);
+ req->sock = NULL;
+ }
+ check_req_list(req, NULL);
+ DEC_STAT(nr_redirect_pending);
+ req->keep_alive = 0;
+ req->http_status = -1;
+ req->redirect_secondary = 0;
+ flush_request(req, ti);
+ }
+ return count;
+}
+
+void flush_redirectqueue (threadinfo_t *ti)
+{
+ struct list_head *head, *curr, *next;
+ http_req_t *req;
+
+ head = &ti->redirect_pending;
+ curr = head->next;
+
+ while (curr != head) {
+ req = list_entry(curr, http_req_t, redirect);
+ next = curr->next;
+ list_del(curr);
+ DEC_STAT(nr_redirect_pending);
+ req->keep_alive = 0;
+ req->http_status = -1;
+ req->redirect_secondary = 0;
+ flush_request(req, ti);
+ }
+}
+
--- linux/net/http/cachemiss.c.orig Fri Sep 1 07:28:26 2000
+++ linux/net/http/cachemiss.c Fri Sep 1 07:28:26 2000
@@ -0,0 +1,762 @@
+/*
+ * TUX - Integrated HTTP layer and Object Cache
+ *
+ * Copyright (C) 2000, Ingo Molnar <
[email protected]>
+ *
+ * cachemiss.c: handle the 'slow IO path' by queueing not-yet-cached
+ * requests to the IO-thread pool. Dynamic load balancing is done
+ * between IO threads, based on the number of requests they have pending.
+ */
+
+#include <net/http.h>
+
+#define NR_IO_THREADS 10
+
+static spinlock_t async_lock = SPIN_LOCK_UNLOCKED;
+static struct list_head async_queue;
+static int nr_async_pending = 0;
+static wait_queue_head_t async_sleep;
+
+static spinlock_t add_csumc = SPIN_LOCK_UNLOCKED;
+
+int nr_async_io_pending (void)
+{
+ return nr_async_pending;
+}
+
+char * print_async_io_threads (char *buf)
+{
+ buf += sprintf(buf, "async IO threads: ");
+ return buf;
+}
+
+void queue_userspace_req (http_req_t *req, threadinfo_t *ti)
+{
+ if (!req->userspace_module)
+ HTTP_BUG();
+ if (!req->tcapi)
+ HTTP_BUG();
+ if (ti != req->ti)
+ HTTP_BUG();
+ if (!ti->started)
+ HTTP_BUG();
+
+ spin_lock_irq(&ti->userspace_lock);
+
+ Dprintk("userspace-queueing request %p.\n", req);
+ check_req_list(req, NULL);
+ list_add_tail(&req->userspace, &ti->userspace_pending);
+ INC_STAT(nr_userspace_pending);
+ check_req_list(req, &req->userspace);
+
+ spin_unlock_irq(&ti->userspace_lock);
+
+ if (ti->thread)
+ wake_up_process(ti->thread);
+ return;
+}
+
+void queue_output_req (http_req_t *req, threadinfo_t *ti)
+{
+ if (!req->tcapi && (!req->urlo || !req->urlo->csumc))
+ HTTP_BUG();
+ if (req->userspace_module)
+ HTTP_BUG();
+ if (ti != req->ti)
+ HTTP_BUG();
+ if (!ti->started)
+ HTTP_BUG();
+
+ spin_lock_irq(&ti->output_lock);
+ Dprintk("output-queueing request %p.\n", req);
+ check_req_list(req, NULL);
+ list_add_tail(&req->output, &ti->output_pending);
+ INC_STAT(nr_output_pending);
+ check_req_list(req, &req->output);
+
+ spin_unlock_irq(&ti->output_lock);
+
+ if (ti->thread)
+ wake_up_process(ti->thread);
+ return;
+}
+
+static void queue_userspace_cachemiss_req (http_req_t *req, threadinfo_t *ti)
+{
+ if (!req->userspace_module)
+ HTTP_BUG();
+ if (!req->tcapi)
+ HTTP_BUG();
+ if (ti != req->ti)
+ HTTP_BUG();
+ if (!ti->started)
+ HTTP_BUG();
+
+ spin_lock_irq(&ti->userspace_lock);
+
+ check_req_list(req, NULL);
+ Dprintk("userspace-cachemiss-queueing request %p.\n", req);
+ list_add_tail(&req->userspace, &ti->userspace_pending);
+ INC_STAT(nr_userspace_pending);
+ check_req_list(req, &req->userspace);
+
+ wake_up_process(ti->thread);
+
+ spin_unlock_irq(&ti->userspace_lock);
+
+ return;
+}
+
+static void queue_output_cachemiss_req (http_req_t *req, threadinfo_t *ti)
+{
+ if (!req->tcapi && (!req->urlo || !req->urlo->csumc))
+ HTTP_BUG();
+ if (req->userspace_module)
+ HTTP_BUG();
+ if (ti != req->ti)
+ HTTP_BUG();
+ if (!ti->started)
+ HTTP_BUG();
+
+ spin_lock_irq(&ti->output_lock);
+
+ check_req_list(req, NULL);
+ Dprintk("output-cachemiss-queueing request %p.\n", req);
+ list_add_tail(&req->output, &ti->output_pending);
+ INC_STAT(nr_output_pending);
+ check_req_list(req, &req->output);
+
+ wake_up_process(ti->thread);
+
+ spin_unlock_irq(&ti->output_lock);
+
+ return;
+}
+
+static void cachemiss_unqueue (http_req_t *req)
+{
+ spin_lock(&async_lock);
+ nr_async_pending--;
+ DEC_STAT(nr_cachemiss_pending);
+ spin_unlock(&async_lock);
+}
+
+static void __queue_req (http_req_t *req, threadinfo_t *ti)
+{
+ if (req->userspace_module)
+ queue_userspace_cachemiss_req(req, ti);
+ else
+ queue_output_cachemiss_req(req, ti);
+}
+
+static void queue_req (http_req_t *req)
+{
+ spin_lock(&async_lock);
+ __queue_req(req, req->ti);
+ nr_async_pending--;
+ DEC_STAT(nr_cachemiss_pending);
+ spin_unlock(&async_lock);
+}
+
+void queue_cachemiss (http_req_t *req)
+{
+ check_req_list(req, NULL);
+ if (req->magic != HTTP_MAGIC)
+ HTTP_BUG();
+
+ spin_lock(&async_lock);
+ list_add_tail(&req->cachemiss, &async_queue);
+ nr_async_pending++;
+ INC_STAT(nr_cachemiss_pending);
+ spin_unlock(&async_lock);
+
+ wake_up(&async_sleep);
+}
+
+static int __queue_secondary_cachemiss (http_req_t *req, urlobj_t *urlo)
+{
+ threadinfo_t *ti = req->ti;
+ int ret = -1;
+
+ check_req_list(req, NULL);
+
+ spin_lock(&add_csumc);
+ if (!urlo->csumc) {
+ spin_lock_irq(&ti->output_lock);
+ list_add_tail(&req->cachemiss, &urlo->secondary_pending);
+ INC_STAT(nr_secondary_pending);
+ spin_unlock_irq(&ti->output_lock);
+ if (urlo->csumc)
+ HTTP_BUG(); // race
+ } else {
+ if (!req->urlo)
+ HTTP_BUG();
+ if (urlo != req->urlo)
+ HTTP_BUG();
+ if (req->userspace_module) {
+ if (!req->tcapi)
+ HTTP_BUG();
+ queue_userspace_req(req, ti);
+ } else
+ queue_output_req(req, ti);
+ ret = 0;
+ }
+ spin_unlock(&add_csumc);
+
+ return ret;
+}
+
+static http_req_t * get_cachemiss (void)
+{
+ struct list_head *tmp;
+ http_req_t *req = NULL;
+
+ spin_lock(&async_lock);
+ if (!list_empty(&async_queue)) {
+
+ tmp = async_queue.next;
+ req = list_entry(tmp, http_req_t, cachemiss);
+
+ check_req_list(req, &req->cachemiss);
+
+ list_del(tmp);
+
+ if (req->magic != HTTP_MAGIC)
+ HTTP_BUG();
+ }
+ spin_unlock(&async_lock);
+ return req;
+}
+
+struct file * http_open_file (char *filename, int mode)
+{
+ struct file *filp;
+
+ if (!filename)
+ HTTP_BUG();
+
+ /* Rule no. 3 -- Does the file exist ? */
+
+ filp = filp_open(filename, mode, 0600);
+
+ if (IS_ERR(filp) || !filp || !filp->f_dentry)
+ goto err;
+
+out:
+ return filp;
+err:
+ printk("filp_open() error: %d.\n", (int)filp);
+ filp = NULL;
+ goto out;
+}
+
+static void queue_pending (http_req_t *req, urlobj_t *urlo)
+{
+ struct list_head *head, *curr, *next;
+ threadinfo_t *ti;
+
+ ti = req->ti;
+ spin_lock(&async_lock);
+ Dprintk("output-queueing primary request %p.\n", req);
+ __queue_req(req, ti);
+ nr_async_pending--;
+ DEC_STAT(nr_cachemiss_pending);
+ urlo_hist_miss(urlo->filelen);
+
+ head = &urlo->secondary_pending;
+ next = head->next;
+
+ /*
+ * Just in case the fast thread is blocked waiting for
+ * incoming connections.
+ */
+ if (ti->thread)
+ wake_up_process(ti->thread);
+
+ while ((curr = next) != head) {
+ req = list_entry(curr, http_req_t, cachemiss);
+ check_req_list(req, &req->cachemiss);
+ next = curr->next;
+ DEC_STAT(nr_secondary_pending);
+ ti = req->ti;
+ list_del(curr);
+ __queue_req(req, ti);
+ urlo_hist_miss(urlo->filelen);
+ }
+ spin_unlock(&async_lock);
+}
+
+char tux_date [DATE_LEN] = "Wed, 01 Jan 1970 00:00:01 GMT";
+
+/*
+ * Just send the bare essentials
+ */
+#define SIMPLE_HEADER \
+ "HTTP/1.1 200 OK\r\n" \
+ "Content-Type: text/html\r\n" \
+ "Connection: Keep-Alive\r\n" \
+ "Date: %s\r\n" \
+ "Content-Length: %u\r\n" \
+ "\r\n"
+
+static int create_csumstream (http_req_t *req, const size_t length,
+ csumcache_t *csumc, struct file *filp, char *buf, urlobj_t *prev_urlo)
+{
+ int i = 0, datasize, packetsize, next_packetsize, currpos, fragmentsize;
+ unsigned long pageaddr, pageoffset;
+ skb_frag_t *frag;
+ struct page *tmppage;
+ int nr_frames, SSInr;
+ mm_segment_t oldmm;
+ char *curr;
+ urlobj_t *urlo;
+ SSImap_t SSImap;
+ int cached_read = 0;
+
+ urlo = req->urlo;
+ if (length < 0)
+ HTTP_BUG();
+ if (csumc->array)
+ HTTP_BUG();
+
+ datasize = length;
+ urlo->body_len = datasize;
+
+ Dprintk("body_len: %d.\n", urlo->body_len);
+
+ if (req->sock->sk)
+ fragmentsize = tcp_current_mss(req->sock->sk);
+ else
+ goto out;
+ if (fragmentsize > PAGE_SIZE)
+ fragmentsize = PAGE_SIZE;
+ csumc->packet_size = fragmentsize;
+
+ SSImap.nr = 0;
+ if (req->tcapi && req->tcapi->create_SSI_map) {
+ int len = length;
+
+ if (len > MAX_BLOCKSIZE)
+ HTTP_BUG();
+
+ oldmm = get_fs(); set_fs(KERNEL_DS);
+ if (prev_urlo && prev_urlo->csumc)
+ http_read(prev_urlo, buf);
+ else {
+repeat_read:
+ len = filp->f_op->read(filp, buf, len, &filp->f_pos);
+ if (len < 0) {
+ if ((len == -512) || (len == -EAGAIN)) {
+ flush_all_signals();
+ reap_kids();
+ goto repeat_read;
+ }
+ if ((len == -ENOMEM) || (len == -EFAULT))
+ goto repeat_read;
+ printk("read returned %d.\n", len);
+ HTTP_BUG();
+ }
+ }
+ set_fs(oldmm);
+
+ buf[len] = 0;
+ filp->f_pos = 0;
+ req->tcapi->create_SSI_map(req, csumc, buf, datasize, &SSImap);
+ cached_read = 1;
+ }
+ /*
+ * Calculate number of fragments. Worst-case: every SSI
+ * mapping divides the packet into 3 pieces instead of
+ * the 1 original, plus every page creates two extra frames.
+ */
+ nr_frames = (length + fragmentsize-1)/fragmentsize + 1;
+ nr_frames += SSImap.nr*2;
+ nr_frames += (length/PAGE_SIZE*2 + 1);
+
+ csumc->array = http_kmalloc(nr_frames*sizeof(skb_frag_t), ALLOC_CSUMCARRAY);
+ memset(csumc->array, 0, nr_frames*sizeof(skb_frag_t));
+
+ if (urlo->header_len)
+ HTTP_BUG();
+
+repeat_alloc:
+ tmppage = alloc_page(GFP_HIGHUSER);
+ if (!tmppage)
+ goto repeat_alloc;
+ pageaddr = kmap(tmppage);
+ curr = (char *)pageaddr;
+ pageoffset = 0;
+
+ /*
+ * Create default header. Is always smaller than PAGE_SIZE.
+ */
+ sprintf(curr, SIMPLE_HEADER, tux_date, urlo->filelen);
+
+ urlo->header_len = strlen(curr);
+ packetsize = urlo->header_len;
+ datasize += packetsize;
+ currpos = -packetsize;
+
+ if (urlo->header_len > fragmentsize)
+ HTTP_BUG();
+ if (!urlo->header_len)
+ HTTP_BUG();
+ Dprintk("first (header) csumc's size: %d.\n", packetsize);
+
+ oldmm = get_fs(); set_fs(KERNEL_DS);
+ SSInr = 0;
+ frag = csumc->array;
+ next_packetsize = fragmentsize - urlo->header_len;
+ if (next_packetsize > datasize - urlo->header_len)
+ next_packetsize = 0;
+
+ goto inside;
+
+ while (datasize) {
+ int len, continuous;
+
+ if (pageoffset > PAGE_SIZE)
+ HTTP_BUG();
+ if (next_packetsize) {
+ packetsize = next_packetsize;
+ next_packetsize = 0;
+ } else {
+ packetsize = datasize;
+ if (packetsize > fragmentsize)
+ packetsize = fragmentsize;
+ }
+
+ frag = csumc->array + i;
+ Dprintk("SSInr: %d, SSImap.nr: %d.\n", SSInr, SSImap.nr);
+ continuous = 0;
+ if (SSInr < SSImap.nr) {
+ int distance = SSImap.pos[SSInr] - currpos;
+
+ if (distance < 0)
+ HTTP_BUG();
+ Dprintk("currpos: %d, SSImap.pos[SSInr]: %d, distance: %d, packetsize: %d.\n", currpos, SSImap.pos[SSInr], distance, packetsize);
+ if (distance < packetsize) {
+ if (!distance) {
+ if (!SSImap.size[SSInr])
+ HTTP_BUG();
+ packetsize = SSImap.size[SSInr];
+ continuous = 1;
+ frag->private = (void *)currpos;
+ SSInr++;
+ } else
+ packetsize = distance;
+ }
+ }
+
+ if (pageoffset == PAGE_SIZE) {
+next_page:
+ Dprintk("unmapping %08lx.\n", pageaddr);
+ kunmap(tmppage);
+repeat_tmppage_alloc:
+ tmppage = alloc_page(GFP_HIGHUSER);
+ if (!tmppage)
+ goto repeat_tmppage_alloc;
+ pageaddr = kmap(tmppage);
+ Dprintk("mapped %08lx.\n", pageaddr);
+ curr = (char *)pageaddr;
+ pageoffset = 0;
+ } else {
+ if (pageoffset + packetsize > PAGE_SIZE) {
+ if (continuous) {
+ Dprintk("need continuous area...\n");
+ goto next_page;
+ }
+ next_packetsize = packetsize -
+ (PAGE_SIZE - pageoffset);
+ packetsize = PAGE_SIZE-pageoffset;
+ }
+ }
+
+ if (cached_read) {
+ if (currpos < 0)
+ HTTP_BUG();
+ if (packetsize <= 0)
+ HTTP_BUG();
+ memcpy(curr, buf + currpos, packetsize);
+ } else {
+repeat_read2:
+ len = filp->f_op->read(filp, curr, packetsize, &filp->f_pos);
+ if (len < 0) {
+ if ((len == -ERESTARTSYS) || (len == -EAGAIN)) {
+ flush_all_signals();
+ reap_kids();
+ goto repeat_read2;
+ }
+ if ((len == -ENOMEM) || (len == -EFAULT))
+ goto repeat_read2;
+ }
+ if (len != packetsize) {
+ printk("whoops, %d != %d. (filelen: %d)\n", len, packetsize, urlo->filelen);
+ printk("checksumming csumc %p, size %d, datasize: %d, curr: %p, currpos: %d, pageoffset: %ld.\n", frag, packetsize, datasize, curr, currpos, pageoffset);
+ HTTP_BUG();
+ }
+ }
+inside:
+ if (!packetsize)
+ HTTP_BUG();
+ if (pageoffset + packetsize > PAGE_SIZE)
+ HTTP_BUG();
+
+ Dprintk("checksumming csumc %p, size %d, datasize: %d, curr: %p, currpos: %d, pageoffset: %ld.\n", frag, packetsize, datasize, curr, currpos, pageoffset);
+
+ frag->csum = csum_partial(curr, packetsize, 0);
+ frag->size = packetsize;
+ frag->page = tmppage;
+ frag->page_offset = pageoffset;
+ frag->data = urlo;
+ frag->frag_done = unuse_frag;
+
+ datasize -= packetsize;
+ currpos += packetsize;
+ pageoffset += packetsize;
+ /*
+ * Align individual frames to cacheline size.
+ * this can never lead to anything bigger than PAGE_SIZE.
+ */
+ pageoffset = L1_CACHE_ALIGN(pageoffset);
+ if (pageoffset > PAGE_SIZE)
+ HTTP_BUG();
+ curr = (char *)pageaddr + pageoffset;
+
+ i++;
+ if (i > nr_frames)
+ HTTP_BUG();
+ }
+ set_fs(oldmm);
+
+ csumc->size = i;
+ kunmap(tmppage);
+out:
+ return i;
+}
+
+static int create_csumcache (http_req_t *req, struct file *filp,
+ char *buf, urlobj_t *prev_urlo)
+{
+ csumcache_t *csumc, *tmp;
+ urlobj_t *urlo;
+ int len;
+
+ if (!filp)
+ HTTP_BUG();
+ filp->f_pos = 0;
+ urlo = req->urlo;
+ len = urlo->filelen;
+
+ if (len < 0)
+ HTTP_BUG();
+
+ csumc = http_kmalloc(sizeof(csumcache_t), ALLOC_CSUMCSTRUCT);
+ memset(csumc, 0, sizeof(csumcache_t));
+ create_csumstream(req, len, csumc, filp, buf, prev_urlo);
+ if (!csumc->size)
+ HTTP_BUG();
+
+ /*
+ * Rare operation.
+ */
+ spin_lock(&add_csumc);
+ tmp = urlo->csumc;
+ if (!tmp)
+ req->urlo->csumc = csumc;
+ spin_unlock(&add_csumc);
+
+ if (tmp) {
+ printk("free_csumc 3().\n");
+ csumc = tmp;
+ }
+ return 0;
+}
+
+#define kmap_frag(frag) ((char *)kmap((frag)->page) + (frag)->page_offset)
+#define kunmap_frag(frag) kunmap((frag)->page)
+
+int http_read (urlobj_t *urlo, char *to)
+{
+ csumcache_t *csumc = urlo->csumc;
+ int size, i, err;
+
+ size = 0;
+
+ for (i = 1; i < csumc->size; i++) {
+ skb_frag_t *frag = csumc->array + i;
+ char *from;
+
+ from = kmap_frag(frag);
+ err = copy_to_user(to, from, frag->size);
+ kunmap_frag(frag);
+ if (err)
+ return err;
+ to += frag->size;
+ size += frag->size;
+ }
+ return size;
+}
+
+static void handle_cachemiss (http_req_t *req, char *buf)
+{
+ urlobj_t *urlo = req->urlo, *prev_urlo;
+ struct dentry *dentry;
+ struct file *filp;
+ int err, miss;
+
+ Dprintk("handling cachemiss on req %p.\n", req);
+ check_req_list(req, NULL);
+ if (!urlo) {
+ miss = lookup_urlo(req, 0);
+ if (!miss && (!req->tcapi || req->userspace_module)) {
+ if (req->userspace_module && !req->tcapi)
+ HTTP_BUG();
+ if (!req->tcapi && !req->urlo)
+ HTTP_BUG();
+ queue_req(req);
+ return;
+ }
+ urlo = req->urlo;
+ if (!urlo && !req->tcapi)
+ HTTP_BUG();
+ }
+ prev_urlo = req->prev_urlo;
+ req->prev_urlo = NULL;
+
+ dentry = req->dentry;
+ if (!dentry && !req->tcapi)
+ HTTP_BUG();
+
+ check_req_list(req, NULL);
+ Dprintk("req->userspace_module: %d, req->tcapi: %p, req->method: %d, req->query: %s.\n", req->userspace_module, req->tcapi, req->method, req->query);
+ if (!req->userspace_module && req->tcapi && ((req->method != METHOD_GET) || req->query)) {
+ int ret;
+
+ Dprintk("TCAPI %p request.\n", req->tcapi);
+ if (!req->tcapi)
+ HTTP_BUG(); // FIXME: fail more gracefully
+ if (req->urlo)
+ HTTP_BUG();
+ if (req->dentry)
+ HTTP_BUG();
+ check_req_list(req, NULL);
+ cachemiss_unqueue(req);
+ ret = req->tcapi->query(req);
+ Dprintk("->query() returned %d.\n", ret);
+ switch (ret) {
+ case -1:
+ break;
+ case -2:
+ req->no_output = 1;
+ case 0:
+ if (req->userspace_module)
+ queue_userspace_req(req, req->ti);
+ else
+ queue_output_req(req, req->ti);
+ break;
+ default:
+ HTTP_BUG();
+ }
+ goto out;
+ }
+ Dprintk("handle cachemiss simple file path.\n");
+
+ if (test_and_set_bit(0, &urlo->csumcs_created)) {
+ spin_lock(&async_lock);
+ list_del(&req->cachemiss);
+ nr_async_pending--;
+ DEC_STAT(nr_cachemiss_pending);
+ __queue_secondary_cachemiss(req, urlo);
+ spin_unlock(&async_lock);
+ goto out;
+ }
+
+ filp = dentry_open(dentry, O_RDONLY, 0);
+ dget(dentry);
+
+ if (!filp)
+ HTTP_BUG();
+ if (!filp->f_dentry || !filp->f_dentry->d_inode)
+ HTTP_BUG();
+ if (filp->f_dentry != dentry)
+ HTTP_BUG();
+ if (filp->f_dentry->d_inode != urlo->inode)
+ HTTP_BUG();
+
+ err = create_csumcache(req, filp, buf, prev_urlo);
+ atomic_add(urlo->filelen, (atomic_t *)&kstat.csumcache_total);
+ queue_pending(req, urlo);
+ if (!err && (urlo->filelen <= http_max_cached_filesize))
+ flush_inode_pages(urlo->inode);
+ fput(filp);
+out:
+ if (prev_urlo)
+ put_urlo(prev_urlo);
+ return;
+}
+
+static int cachemiss_thread (void *data)
+{
+ DECLARE_WAITQUEUE(wait, current);
+ struct k_sigaction *ka;
+ http_req_t *req;
+ char *buf;
+ int nr = (int)data;
+
+ printk("async IO thread %d started.\n", nr);
+ sprintf(current->comm, "async IO %d", nr);
+
+ spin_lock_irq(¤t->sigmask_lock);
+#if 1
+ ka = current->sig->action + SIGCHLD-1;
+ ka->sa.sa_handler = SIG_IGN;
+#endif
+ siginitsetinv(¤t->blocked, sigmask(SIGCHLD));
+ recalc_sigpending(current);
+ spin_unlock_irq(¤t->sigmask_lock);
+
+ buf = (char *)__get_free_pages(GFP_USER, OUT_BUF_ORDER);
+ if (!buf)
+ HTTP_BUG();
+
+ for (;;) {
+ while (!list_empty(&async_queue) && (req = get_cachemiss())) {
+ handle_cachemiss(req, buf);
+ if (signal_pending(current)) {
+ flush_all_signals();
+ while (sys_wait4(-1, NULL, WNOHANG, NULL) > 0)
+ /* nothing */;
+ }
+ }
+ if (signal_pending(current)) {
+ flush_all_signals();
+ while (sys_wait4(-1, NULL, WNOHANG, NULL) > 0)
+ /* nothing */;
+ }
+ if (!list_empty(&async_queue))
+ continue;
+ add_wait_queue_exclusive(&async_sleep, &wait);
+ __set_current_state(TASK_EXCLUSIVE|TASK_INTERRUPTIBLE);
+ if (list_empty(&async_queue))
+ schedule();
+ __set_current_state(TASK_RUNNING);
+ remove_wait_queue(&async_sleep, &wait);
+ }
+
+ free_pages((unsigned long)buf, OUT_BUF_ORDER);
+
+ return 0;
+}
+
+void init_cachemiss_threads (void)
+{
+ int i;
+
+ INIT_LIST_HEAD(&async_queue);
+ init_waitqueue_head(&async_sleep);
+
+ for (i = 0; i < NR_IO_THREADS; i++)
+ kernel_thread(cachemiss_thread, (void *)i, 0);
+}
+
--- linux/net/http/logger.c.orig Fri Sep 1 07:28:26 2000
+++ linux/net/http/logger.c Fri Sep 1 07:28:26 2000
@@ -0,0 +1,555 @@
+/*
+ * TUX - Integrated HTTP layer and Object Cache
+ *
+ * Copyright (C) 2000, Ingo Molnar <
[email protected]>
+ *
+ * logger.c: log requests finished by TUX.
+ */
+
+#define __KERNEL_SYSCALLS__
+#include <net/http.h>
+
+#define LOG_LEN ((1 << LOG_BUF_ORDER) * PAGE_SIZE)
+
+static spinlock_t log_lock = SPIN_LOCK_UNLOCKED;
+static unsigned int log_head, log_tail;
+static char * log_buffer = NULL;
+static DECLARE_WAIT_QUEUE_HEAD(log_wait);
+static DECLARE_WAIT_QUEUE_HEAD(log_full);
+static int logger_pid = 0;
+
+static struct file *log_filp = NULL;
+
+/*
+ * High-speed TUX logging architecture:
+ *
+ * All fast threads share a common log-ringbuffer. (default size 1MB)
+ * Log entries are binary and are padded to be cacheline aligned, this
+ * ensures that there is no cache-pingpong between fast threads.
+ *
+ * The logger thread writes out pending log entries within 1 second
+ * (buffer-cache writes data out within 5 seconds). The logger thread
+ * gets activated once we have more than 25% of the log ringbuffer
+ * filled - or the 1 second log timeout expires. Fast threads block
+ * if if more than 95% of the ringbuffer is filled and unblock only
+ * if used logbuffer space drops below 90%.
+ *
+ * This architecture guarantees that 1) logging is reliable (no
+ * log entry is ever lost), 2) timely (touches disk within 6 seconds),
+ * 3) in the log-contention case the saturation behavior is still
+ * write-clustered, but 4) if the logger thread can keep up then
+ * the coupling is completely asynchron and parallel.
+ *
+ * The binary log format gives us about 50% saved IO/memory bandwith
+ * and 50% less on-disk used log space than the traditional W3C ASCII
+ * format.
+ *
+ * (We might switch to raw IO though to write the logfile.)
+ */
+
+#define SOFT_LIMIT (LOG_LEN*25/100)
+#define HARD_LIMIT (LOG_LEN*95/100)
+#define HARD_RELAX_LIMIT (LOG_LEN*90/100)
+
+int http_logentry_align_order = 5;
+
+#define ROUND_UP(x) (((((x)-1) >> http_logentry_align_order) + 1) \
+ << http_logentry_align_order)
+
+static char no_uri [] = "<no URI>";
+
+#define CHECK_LOGPTR(ptr) \
+do { \
+ if ((ptr < log_buffer) || (ptr > log_buffer + LOG_LEN)) { \
+ printk("ouch: log ptr %p > %p + %ld!\n", \
+ ptr, log_buffer, LOG_LEN); \
+ HTTP_BUG(); \
+ } \
+} while (0)
+
+void __log_request (http_req_t *req)
+{
+ char *str, *next;
+ unsigned int inc, len, uri_len, pending, next_head;
+ unsigned long *tmp;
+
+ if (!log_filp)
+ return;
+ if (!log_buffer)
+ HTTP_BUG();
+ /*
+ * Log the HTTP reply status (success, or type of failure)
+ */
+ if (!req->http_status || (req->bytes_sent == -1) || !req->uri) {
+
+ Dprintk("not logging req %p: {%s} [%d/%d]\n", req, req->uri, req->http_status, req->bytes_sent);
+ return;
+ }
+ if (!req->uri) {
+ req->uri = no_uri;
+ req->uri_len = strlen(no_uri);
+ }
+ uri_len = strlen(req->uri);
+ len = uri_len;
+ Dprintk("uri: {%s} [%d/%d]\n", req->uri, req->uri_len, strlen(req->uri));
+ if (len != req->uri_len) {
+ printk("hm, %s (%d != %d).\n",
+ req->uri, len, req->uri_len);
+// HTTP_BUG();
+ }
+ if (req->method_str) {
+ Dprintk("method_str: {%s} [%d/%d]\n", req->method_str, req->method_len, strlen(req->method_str));
+ len += req->method_len;
+ }
+ if (req->version_str) {
+ Dprintk("version_str: {%s} [%d/%d]\n", req->version_str, req->version_len, strlen(req->version_str));
+ len += req->version_len;
+ }
+ if (req->query)
+ len += strlen(req->query) + 1;
+
+ inc = 5*sizeof(unsigned long) + len + 1 + 1;
+
+ spin_lock(&log_lock);
+
+ next_head = ROUND_UP(log_head + inc);
+
+ if (next_head < LOG_LEN) {
+ str = log_buffer + log_head;
+ if (str > log_buffer + LOG_LEN)
+ HTTP_BUG();
+ log_head = next_head;
+ } else {
+ if (log_head < LOG_LEN)
+ memset(log_buffer+log_head, 0, LOG_LEN-log_head);
+ str = log_buffer;
+ log_head = ROUND_UP(inc);
+ }
+
+ if (str < log_buffer || str+inc >= log_buffer+LOG_LEN) {
+ printk("hm, %s (%d).\n", req->uri, len);
+ printk("hm, %p + %d > %p + %ld.\n", str, len, log_buffer, LOG_LEN);
+// HTTP_BUG();
+ }
+
+ tmp = (unsigned long *) str;
+ /*
+ * Log record signature - this makes finding the next entry
+ * easier (since record length is variable), and makes the
+ * binary logfile more robust against potential data corruption
+ * and other damage. It also handles the case where we wrap
+ * the ringbuffer.
+ */
+ *tmp = 0xdeadbeef;
+ str += sizeof(unsigned long);
+ CHECK_LOGPTR(str);
+ tmp++;
+
+ /*
+ * Log the client IP address:
+ */
+ if (req->sock && req->sock->sk)
+ *tmp = req->sock->sk->daddr;
+ else
+ *tmp = 0xffffffff;
+ str += sizeof(unsigned long);
+ CHECK_LOGPTR(str);
+ tmp++;
+
+ /*
+ * Log the request timestamp, in units of 'seconds since 1970'.
+ */
+ if (req->timestamp)
+ *tmp = req->timestamp;
+ else
+ *tmp = CURRENT_TIME;
+ str += sizeof(unsigned long);
+ CHECK_LOGPTR(str);
+ tmp++;
+
+ /*
+ * Log the requested file size (in fact, log actual bytes sent.)
+ */
+ *tmp = req->bytes_sent;
+ str += sizeof(unsigned long);
+ CHECK_LOGPTR(str);
+ tmp++;
+
+ *tmp = req->http_status;
+ str += sizeof(unsigned long);
+ CHECK_LOGPTR(str);
+
+ /*
+ * Zero-terminated method, (base) URI, query and version string.
+ */
+ if (req->method_str) {
+ memcpy(str, req->method_str, req->method_len-1);
+ str += req->method_len-1;
+ CHECK_LOGPTR(str);
+ *str++ = ' ';
+ }
+ strcpy(str, req->uri);
+ str += uri_len;
+ CHECK_LOGPTR(str);
+ if (req->query) {
+ *str++ = '?';
+ strcpy(str, req->query);
+ str += strlen(req->query);
+ CHECK_LOGPTR(str);
+ }
+ if (req->version_str) {
+ *str++ = ' ';
+ memcpy(str, req->version_str, req->version_len-1);
+ str += req->version_len-1;
+ CHECK_LOGPTR(str);
+ }
+ *str++ = 0;
+ CHECK_LOGPTR(str);
+ /*
+ * pad with spaces to next cacheline, with an ending newline.
+ * (not needed for the user-space log utility, but results in
+ * a more readable binary log file, and reduces the amount
+ * of cache pingpong.)
+ */
+ next = (char *)ROUND_UP((unsigned long)str+1);
+
+ *--next = '\n';
+ CHECK_LOGPTR(next);
+ len = next-str;
+ memset(str, ' ', len);
+
+ pending = (log_head-log_tail) % LOG_LEN;
+ spin_unlock(&log_lock);
+
+ if (pending >= SOFT_LIMIT)
+ wake_up(&log_wait);
+
+ if (pending >= HARD_LIMIT)
+ sleep_on(&log_full);
+}
+
+void flush_request (http_req_t *req, threadinfo_t *ti)
+{
+ struct socket *sock;
+ struct sock *sk = NULL;
+ int keep_alive;
+
+ check_req_list(req, NULL);
+ __set_task_state(current, TASK_RUNNING);
+
+ if (req->magic != HTTP_MAGIC)
+ HTTP_BUG();
+ if (req->ti != ti)
+ HTTP_BUG();
+ if (ti->thread != current)
+ HTTP_BUG();
+
+ if (!req->http_status) {
+// printk("no HTTP status! {m:%d, f:{%s}, q:{%s}}\n", req->method, req->objectname, req->query);
+// HTTP_BUG();
+ }
+ log_request(req);
+ sock = req->sock;
+ if (sock)
+ sk = sock->sk;
+ Dprintk("FLUSHING req %p <%p> (sock %p, sk %p) (keepalive: %d, status: %d) ({%s}, {%s}, {%s}, {%s}).\n", req, __builtin_return_address(0), sock, sk, req->keep_alive, req->http_status, req->method_str ? req->method_str : "<null>", req->uri ? req->uri : "<null>", req->query ? req->query : "<null>", req->version_str ? req->version_str : "<null>");
+#if 0
+ if (sk)
+ if (sock->sk->tp_pinfo.af_tcp.nonagle != 1)
+ HTTP_BUG();
+#endif
+ if (req->dentry) {
+ dput(req->dentry);
+ req->dentry = NULL;
+ }
+ if (req->urlo) {
+ put_urlo(req->urlo);
+ req->urlo = NULL;
+ }
+ if (req->prev_urlo)
+ HTTP_BUG();
+ if (req->private) {
+ http_kfree(req->private, ALLOC_REQ_PRIVATE);
+ req->private = NULL;
+ }
+ if (req->userspace_module)
+ HTTP_BUG();
+ if (req->redirect_secondary)
+ HTTP_BUG();
+ if (test_bit(0, &req->idle_input))
+ HTTP_BUG();
+
+ req->tcapi = NULL;
+ req->SSI = 0;
+
+ req->headers_len = 0;
+ req->parsed_len = 0;
+ req->method = METHOD_NONE;
+ req->method_len = 0;
+ req->method_str = NULL;
+ req->version = 0;
+ req->version_str = NULL;
+ req->version_len = 0;
+
+ req->uri = NULL;
+ req->uri_len = 0;
+
+ req->objectname = NULL;
+ req->objectname_len = 0;
+
+ req->query = NULL;
+ req->query_len = 0;
+
+ req->cookies = NULL;
+ req->cookies_len = 0;
+ req->parse_cookies = 0;
+
+ req->contentlen = NULL;
+ req->contentlen_strlen = 0;
+ req->content_len = 0;
+
+ req->post_data = NULL;
+ req->post_data_len = 0;
+
+ req->timestamp = 0;
+ req->http_status = 0;
+
+ req->bytes_sent = 0;
+ req->body_len = 0;
+ keep_alive = req->keep_alive;
+ req->keep_alive = 0;
+ req->no_output = 0;
+ req->event = 0;
+
+ if (req->private)
+ HTTP_BUG();
+
+ if (sk && keep_alive) {
+ if (skb_queue_empty(&sk->receive_queue)) {
+ add_keepalive_timer(req);
+ if (test_and_set_bit(0, &req->idle_input))
+ HTTP_BUG();
+ /*
+ * Avoid the race with the event callback:
+ */
+ if (skb_queue_empty(&sk->receive_queue) ||
+ !test_and_clear_bit(0, &req->idle_input)) {
+ INC_STAT(nr_idle_input_pending);
+ return;
+ }
+ del_keepalive_timer(req);
+ }
+ Dprintk("KEEPALIVE PENDING req %p <%p> (sock %p, sk %p) (keepalive: %d, status: %d) ({%s}, {%s}, {%s}, {%s}).\n", req, __builtin_return_address(0), req->sock, req->sock->sk, req->keep_alive, req->http_status, req->method_str ? req->method_str : "<null>", req->uri ? req->uri : "<null>", req->query ? req->query : "<null>", req->version_str ? req->version_str : "<null>");
+ check_req_list(req, NULL);
+ spin_lock_irq(&ti->input_lock);
+#if 0
+ list_add_tail(&req->input, &ti->input_pending);
+#else
+ list_add(&req->input, &ti->input_pending);
+#endif
+ INC_STAT(nr_input_pending);
+ INC_STAT(nr_keepalive_optimized);
+ spin_unlock_irq(&ti->input_lock);
+ return;
+ }
+ del_keepalive_timer(req);
+ if (sk)
+ remove_wait_queue(sk->sleep, &req->sleep);
+ if (sock) {
+ unlink_http_socket(req);
+ req->sock = NULL;
+ }
+ /*
+ * Close potential user-space file descriptors.
+ */
+ {
+ int fd = req->userspace_fd;
+
+ if (fd != -1) {
+ req->userspace_fd = -1;
+ sys_close(fd);
+ } else
+ if (sock)
+ sock_release(sock);
+ }
+ check_req_list(req, NULL);
+ kfree_req(req, ti);
+}
+
+int finish_requests (threadinfo_t *ti)
+{
+ struct list_head *head, *curr, *next;
+ http_req_t *req;
+ int count = 0;
+
+ head = &ti->finish_pending;
+ next = head->next;
+
+ Dprintk("START of finish_requests() loop ...\n");
+ while ((curr = next) != head) {
+ if (current->need_resched)
+ break;
+ if (!count++)
+ __set_task_state(current, TASK_RUNNING);
+
+ req = list_entry(curr, http_req_t, finish);
+ check_req_list(req, &req->finish);
+ next = curr->next;
+
+ if (req->ti != ti)
+ HTTP_BUG();
+ if (ti->thread != current)
+ HTTP_BUG();
+
+ list_del(curr);
+ DEC_STAT(nr_finish_pending);
+ Dprintk("found req %p in finish_requests() queue.\n", req);
+ flush_request(req, ti);
+ }
+ Dprintk("END of finish_requests() loop ...\n");
+ return count;
+}
+
+static int writeout_log (void)
+{
+ unsigned int len, pending;
+ char * str;
+ int ret;
+
+ spin_lock(&log_lock);
+ str = log_buffer + log_tail;
+ if (log_head < log_tail) {
+ len = LOG_LEN-log_tail;
+ log_tail = 0;
+ } else {
+ len = log_head-log_tail;
+ log_tail = log_head;
+ }
+ pending = (log_head-log_tail) % LOG_LEN;
+ spin_unlock(&log_lock);
+ if (!len)
+ goto out;
+
+ ret = http_write_file(log_filp, str, len);
+ if (len != ret) {
+ printk("hm, log write returned %d != %d.\n", ret, len);
+ printk("... log_filp: %p, str: %p, len: %d str[len-1]: %d.\n", log_filp, str, len, str[len-1]);
+ }
+ /*
+ * Reduce the cache footprint of the logger file - it's
+ * typically write-once.
+ */
+ flush_inode_pages(log_filp->f_dentry->d_inode);
+out:
+ if (pending < HARD_RELAX_LIMIT)
+ wake_up(&log_full);
+
+ return pending;
+}
+
+static DECLARE_WAIT_QUEUE_HEAD(stop_logger_wait);
+static volatile int stop_logger = 0;
+
+static int logger_thread (void *data)
+{
+ DECLARE_WAITQUEUE(wait, current);
+ unsigned int pending;
+ mm_segment_t oldmm;
+
+ oldmm = get_fs();
+ set_fs(KERNEL_DS);
+ printk("logger thread started.\n");
+ sprintf(current->comm, "HTTP logger");
+
+ spin_lock_irq(¤t->sigmask_lock);
+ siginitsetinv(¤t->blocked, 0);
+ recalc_sigpending(current);
+ spin_unlock_irq(¤t->sigmask_lock);
+
+ if (log_buffer)
+ HTTP_BUG();
+ log_buffer = (char *) __get_free_pages(GFP_USER, LOG_BUF_ORDER);
+ printk("log buffer: %p.\n", log_buffer);
+ memset(log_buffer, 0, LOG_LEN);
+ log_head = log_tail = 0;
+
+ add_wait_queue(&log_wait, &wait);
+ for (;;) {
+ Dprintk("logger does writeout - stop:%d.\n", stop_logger);
+ do {
+ pending = writeout_log();
+ } while (pending >= SOFT_LIMIT);
+
+ Dprintk("logger does sleep - stop:%d.\n", stop_logger);
+ __set_current_state(TASK_INTERRUPTIBLE);
+ schedule_timeout(HZ);
+ Dprintk("logger back from sleep - stop:%d.\n", stop_logger);
+ if (stop_logger)
+ break;
+ }
+ remove_wait_queue(&log_wait, &wait);
+
+ free_pages((unsigned long)log_buffer, LOG_BUF_ORDER);
+ log_buffer = NULL;
+ if (log_filp) {
+ fput(log_filp);
+ log_filp = NULL;
+ }
+ stop_logger = 0;
+
+ wake_up(&stop_logger_wait);
+ set_fs(oldmm);
+
+ return 0;
+}
+
+void flush_logqueue (threadinfo_t *ti)
+{
+ struct list_head *head, *curr, *next;
+ http_req_t *req;
+
+ head = &ti->finish_pending;
+ curr = head->next;
+
+ while (curr != head) {
+ req = list_entry(curr, http_req_t, finish);
+ next = curr->next;
+ list_del(curr);
+ DEC_STAT(nr_finish_pending);
+ req->keep_alive = 0;
+ flush_request(req, ti);
+ }
+}
+
+void init_log_thread (void)
+{
+ if (log_filp)
+ HTTP_BUG();
+ logger_pid = kernel_thread(logger_thread, NULL, 0);
+ if (logger_pid < 0)
+ HTTP_BUG();
+ printk("HTTP logger: opening log file {%s}.\n", http_logfile);
+ log_filp = http_open_file(http_logfile, O_CREAT|O_APPEND|O_WRONLY);
+ if (!log_filp)
+ printk("HTTP logger: couldnt open log file {%s}!\n", http_logfile);
+}
+
+void stop_log_thread (void)
+{
+ DECLARE_WAITQUEUE(wait, current);
+ int ret;
+
+ add_wait_queue(&stop_logger_wait, &wait);
+ __set_current_state(TASK_UNINTERRUPTIBLE);
+ stop_logger = 1;
+ wake_up(&log_wait);
+ schedule();
+ remove_wait_queue(&stop_logger_wait, &wait);
+
+ ret = waitpid(logger_pid, NULL, __WCLONE);
+#if 0
+// unsure
+ if (ret < 0)
+ HTTP_BUG();
+#endif
+}
--- linux/net/http/http_parser.c.orig Fri Sep 1 07:28:26 2000
+++ linux/net/http/http_parser.c Fri Sep 1 07:28:26 2000
@@ -0,0 +1,404 @@
+/*
+ * TUX - Integrated HTTP layer and Object Cache
+ *
+ * Copyright (C) 2000, Ingo Molnar <
[email protected]>
+ *
+ * http_parser.c: HTTP header parsing and construction routines
+ *
+ * Right now we detect simple GET headers, anything more
+ * subtle gets redirected to secondary server port.
+ */
+
+#include <net/http.h>
+#include "parser.h"
+
+int http_Dprintk = 0;
+
+/*
+ * Parse the HTTP message and put results into the request structure.
+ * CISAPI extensions do not see the actual message buffer.
+ *
+ * Any perceived irregularity is honored with a redirect to the
+ * secondary server - which in most cases should be Apache. So
+ * if TUX gets confused by some strange request we fall back
+ * to Apache to be RFC-correct.
+ *
+ * The parser is 'optimistic', ie. it's optimized for the case where
+ * the whole message is available and correct. The parser is also
+ * supposed to be 'robust', ie. it can be called multiple times with
+ * an incomplete message, as new packets arrive.
+ */
+
+int parse_http_message (http_req_t *req, const int len)
+{
+ char *message;
+ char c, *curr, *end, *uri;
+ int objectname_len;
+ int had_cookie;
+
+ message = req->headers;
+ Dprintk("parsing request:\n---\n%s\n---\n", message);
+/*
+ * RFC 2616, 5.1:
+ *
+ * Request-Line = Method SP Request-URI SP HTTP-Version CRLF
+ */
+
+ if (!len)
+ HTTP_BUG();
+
+ curr = message;
+ end = message + len;
+
+ if (req->method_len) {
+ curr += req->method_len;
+ goto continue_filename;
+ }
+
+#define GOTO_INCOMPLETE do { Dprintk("incomplete at %s:%d.\n", __FILE__, __LINE__); goto incomplete_message; } while (0)
+#define GOTO_REDIR do { printk("redirect secondary at %s:%d.\n", __FILE__, __LINE__); goto redirect_secondary; } while (0)
+
+#define PRINT_MESSAGE_LEFT \
+ Dprintk("message left at %s:%d:\n--->{%s}<---\n", __FILE__, __LINE__, curr)
+
+ switch (*curr) {
+ case 'G':
+ if (PARSE_METHOD(req,curr,end,GET))
+ break;
+ GOTO_REDIR;
+
+ case 'H':
+ if (PARSE_METHOD(req,curr,end,HEAD))
+ break;
+ GOTO_REDIR;
+
+ case 'P':
+ if (PARSE_METHOD(req,curr,end,POST))
+ break;
+ if (PARSE_METHOD(req,curr,end,PUT))
+ break;
+ GOTO_REDIR;
+
+ default:
+ GOTO_REDIR;
+ }
+
+ req->method_str = message;
+ req->method_len = curr-message;
+
+continue_filename:
+ Dprintk("got method %d\n", req->method);
+
+ PRINT_MESSAGE_LEFT;
+
+ if (req->objectname_len) {
+ curr += req->objectname_len;
+ objectname_len = req->objectname_len;
+ goto continue_query;
+ }
+ /*
+ * Ok, we got one of the methods we can handle, parse
+ * the URI:
+ */
+
+ req->uri = req->objectname = uri = curr;
+
+ for (;;) {
+ c = *curr;
+
+ if (!c)
+ GOTO_INCOMPLETE;
+ if (c == ' ' || c == '?')
+ break;
+ if (++curr == end)
+ GOTO_INCOMPLETE;
+ }
+ objectname_len = curr - uri;
+ req->objectname_len = objectname_len;
+ req->uri_len = objectname_len;
+ if (!objectname_len)
+ GOTO_REDIR;
+continue_query:
+
+ c = *curr;
+ *curr = 0;
+ curr++;
+
+ Dprintk("got filename %s (%d)\n", req->objectname, req->objectname_len);
+
+ PRINT_MESSAGE_LEFT;
+
+ if (req->query_len) {
+ curr += req->query_len;
+ goto continue_version;
+ }
+ /*
+ * Parse optional query string. Copy until end-of-string or space.
+ */
+ if (c == '?') {
+ int query_len;
+ char *query;
+
+ if (req->query && (req->query != curr))
+ HTTP_BUG();
+ req->query = query = curr;
+
+ for (;;) {
+ c = *curr;
+
+ if (!c)
+ GOTO_INCOMPLETE;
+ if (c == ' ')
+ break;
+ if (++curr == end)
+ GOTO_INCOMPLETE;
+ }
+ query_len = curr - query;
+ req->query_len = query_len;
+ }
+continue_version:
+ if (req->query_len) {
+ *curr = 0;
+ curr++;
+ Dprintk("got query string %s (%d)\n", req->query, req->query_len);
+ }
+ PRINT_MESSAGE_LEFT;
+ if (req->version_len) {
+ curr += req->version_len;
+ goto continue_headers;
+ }
+ /*
+ * Parse the HTTP version field:
+ */
+ req->version_str = curr;
+ if (!PARSE_TOKEN(curr,end,"HTTP/1."))
+ GOTO_REDIR;
+
+ switch (*curr++) {
+ case '0':
+ req->version = HTTP_1_0;
+ req->keep_alive = 0;
+ break;
+ case '1':
+ req->version = HTTP_1_1;
+ req->keep_alive = 1;
+ break;
+ default:
+ GOTO_REDIR;
+ }
+ if (get_c(curr) != '\n') {
+ if (curr - message == len-1)
+ GOTO_INCOMPLETE;
+ GOTO_REDIR;
+ }
+ req->version_len = curr - req->version_str;
+
+continue_headers:
+ *curr = 0;
+ curr++;
+ Dprintk("got version %d\n", req->version);
+ PRINT_MESSAGE_LEFT;
+
+ /*
+ * Now parse (optional) request header fields:
+ */
+ had_cookie = 0;
+ for (;;) {
+ switch (get_c(curr)) {
+ case '\r':
+ if (!*++curr)
+ GOTO_INCOMPLETE;
+ GOTO_REDIR;
+ case '\n':
+ curr++;
+ goto out;
+ case 'A':
+ if (PARSE_TOKEN(curr,end,"Accept: ")) {
+ Dprintk("ignoring Accept field.\n");
+ // ignore for now
+ SKIP_LINE;
+ break;
+ }
+ if (PARSE_TOKEN(curr,end,"Accept-Encoding: ")) {
+ Dprintk("ignoring Accept-Encoding field.\n");
+ // ignore for now
+ SKIP_LINE;
+ break;
+ }
+ if (PARSE_TOKEN(curr,end,"Accept-Language: ")) {
+ Dprintk("ignoring Accept-Language field.\n");
+ // ignore for now
+ SKIP_LINE;
+ break;
+ }
+ GOTO_REDIR;
+
+ case 'C':
+ if (PARSE_TOKEN(curr,end,"Connection: ")) {
+ switch (get_c(curr)) {
+ case 'K':
+ if (!PARSE_TOKEN(curr,end,"Keep-Alive"))
+ GOTO_REDIR;
+ req->keep_alive = 1;
+ break;
+
+ case 'c':
+ if (!PARSE_TOKEN(curr,end,"close"))
+ GOTO_REDIR;
+ req->keep_alive = 0;
+ break;
+ default:
+ GOTO_REDIR;
+ }
+ if (get_c(curr) == '\n')
+ break;
+ if (!*curr)
+ GOTO_INCOMPLETE;
+ }
+ if (PARSE_TOKEN(curr,end,"Cookie: ")) {
+ if (had_cookie)
+ GOTO_REDIR;
+ had_cookie = 1;
+ if (req->cookies_len) {
+ curr += req->cookies_len;
+ goto continue_cookies;
+ }
+ req->cookies = curr;
+ SKIP_LINE;
+ req->cookies_len = curr - req->cookies;
+ if (req->cookies_len)
+ *(curr-1) = 0;
+continue_cookies:
+ Dprintk("Cookie field: %s.\n", req->cookies);
+ break;
+ }
+ if (PARSE_TOKEN(curr,end,"Content-Type: ")) {
+ // ignore for now
+ Dprintk("ignoring Content-Type field.\n");
+ SKIP_LINE;
+ break;
+ }
+ if (PARSE_TOKEN(curr,end,"Content-type: ")) {
+ // ignore for now
+ Dprintk("ignoring Content-type field.\n");
+ SKIP_LINE;
+ break;
+ }
+ if (PARSE_TOKEN(curr,end,"Cache-Control: ")) {
+ // ignore for now
+ Dprintk("ignoring Cache-Control field.\n");
+ SKIP_LINE;
+ break;
+ }
+ if (PARSE_TOKEN(curr,end,"Content-Length: ")) {
+ char *tmp;
+ if (req->contentlen_strlen) {
+ curr += req->contentlen_strlen;
+ goto continue_contentlen;
+ }
+ req->contentlen = curr;
+ SKIP_LINE;
+ req->contentlen_strlen = curr - req->contentlen;
+continue_contentlen:
+ if (req->contentlen_strlen) {
+ *(curr-1) = 0;
+ tmp = req->contentlen;
+ req->content_len = simple_strtoul(tmp, &tmp, 10);
+ }
+ Dprintk("Content-Length field: %s.\n", req->contentlen);
+ Dprintk("Content-Length value: %d.\n", req->content_len);
+ break;
+ }
+ GOTO_REDIR;
+
+ case 'H':
+ if (PARSE_TOKEN(curr,end,"Host: ")) {
+ // ignore for now
+ Dprintk("ignoring Host field.\n");
+ SKIP_LINE;
+ break;
+ }
+ GOTO_REDIR;
+
+ case 'I':
+ if (PARSE_TOKEN(curr,end,"If-Modified-Since: ")) {
+ // ignore for now
+ Dprintk("ignoring If-Modified-Since field.\n");
+ SKIP_LINE;
+ break;
+ }
+ GOTO_REDIR;
+
+ case 'N':
+ if (PARSE_TOKEN(curr,end,"Negotiate: ")) {
+ // ignore for now
+ Dprintk("ignoring Negotiate field.\n");
+ SKIP_LINE;
+ break;
+ }
+ GOTO_REDIR;
+
+ case 'P':
+ if (PARSE_TOKEN(curr,end,"Pragma: ")) {
+ // ignore for now
+ Dprintk("ignoring Pragma field.\n");
+ SKIP_LINE;
+ break;
+ }
+ GOTO_REDIR;
+
+ case 'R':
+ if (PARSE_TOKEN(curr,end,"Referer: ")) {
+ // ignore for now
+ Dprintk("ignoring Referer field.\n");
+ SKIP_LINE;
+ break;
+ }
+ GOTO_REDIR;
+
+ case 'U':
+ if (PARSE_TOKEN(curr,end,"User-Agent: ")) {
+ // ignore for now
+ Dprintk("ignoring User-Agent field.\n");
+ SKIP_LINE;
+ break;
+ }
+ GOTO_REDIR;
+
+ case 0:
+ GOTO_INCOMPLETE;
+ default:
+ GOTO_REDIR;
+ }
+ curr++;
+ PRINT_MESSAGE_LEFT;
+ }
+out:
+ /*
+ * POST data.
+ */
+ if ((req->method == METHOD_POST) && req->content_len) {
+ PRINT_MESSAGE_LEFT;
+ if (curr + req->content_len > message + len)
+ GOTO_INCOMPLETE;
+ req->post_data = curr;
+ req->post_data_len = req->content_len;
+ curr += req->content_len;
+ *curr = 0;
+ Dprintk("POST-ed data: {%s}\n", req->post_data);
+ }
+ Dprintk("ok, request accepted.\n");
+ PRINT_MESSAGE_LEFT;
+ req->parsed_len = curr-message;
+ return objectname_len;
+
+incomplete_message:
+ Dprintk("incomplete message!\n");
+ PRINT_MESSAGE_LEFT;
+ return 0;
+
+redirect_secondary:
+ Dprintk("redirecting message to secondary server!\n");
+ PRINT_MESSAGE_LEFT;
+ return -1;
+}
--- linux/net/http/CAD.c.orig Fri Sep 1 07:28:26 2000
+++ linux/net/http/CAD.c Fri Sep 1 07:28:26 2000
@@ -0,0 +1,853 @@
+/*
+ * TUX - Integrated HTTP layer and Object Cache
+ *
+ * Copyright (C) 2000, Ingo Molnar <
[email protected]>
+ *
+ * CAD.c: Implementation of the SPECweb99 dynamic application via
+ * the HTTP trusted-API.
+ */
+
+#include <net/http.h>
+
+static inline int send_reply_head (http_req_t *req, size_t body_size);
+static inline int send_reply_tail (http_req_t *req);
+static int send_err (http_req_t *req, char *message);
+
+/*
+ * We memory-map the head of the postlog file so that we
+ * do not have to call write() every time we update it.
+ * The postlog record is written out to disk on every POST
+ * request, and the record counter (in the memory mapped
+ * buffer) is updated atomically as well.
+ */
+#define POSTLOG "/tmp/postlog"
+
+static HTTP_DECLARE_MUTEX(postlog_sem);
+static struct http_file *post_file;
+static int postlog_count;
+static char *postlog_head;
+static struct http_page *postlog_head_page;
+
+#define CAD_TAG_HEAD "<!WEB99CAD><IMG SRC=\"/file_set/"
+#define CAD_TAG_BODY "dirNNNNN/classX_Y"
+#define CAD_TAG_TAIL "\"><!/WEB99CAD>"
+
+#define CAD_TAG CAD_TAG_HEAD CAD_TAG_BODY CAD_TAG_TAIL
+
+#define CAD_TAG_BODY_POS (sizeof(CAD_TAG_HEAD)-1)
+#define CAD_TAG_BODY_LEN (sizeof(CAD_TAG_BODY)-1)
+#define CAD_TAG_TAIL_LEN (sizeof(CAD_TAG_TAIL)-1)
+#define CAD_TAG_LEN (sizeof(CAD_TAG)-1)
+
+typedef struct CAD_struct {
+ int user_id;
+ int last_ad;
+ char ad_filename [100];
+ int reply_cookies_len;
+ char reply_cookies[MAX_COOKIE_LEN];
+} CAD_t;
+
+static inline int is_class12 (char *str)
+{
+ unsigned char *tmp;
+
+ tmp = strstr(str, "class");
+ if (tmp) {
+ tmp += sizeof("class")-1;
+ if ((tmp[0] != '1') && (tmp[0] != '2'))
+ return 0;
+ return 1;
+ }
+ return 0;
+}
+
+/*
+ * This function reads the object, scans the temporary buffer for
+ * the SPECweb99 tag string, does CAD replacement and sends the
+ * result out to the client.
+ */
+static inline int scan_send_file (http_req_t *req, CAD_t *CADp)
+{
+ char *tmpbuf, *target;
+ int size, left, ret;
+ mm_segment_t oldmm;
+
+ if (!CADp || !req->query || !is_class12(req->query))
+ return http_send_object(req, 0, 0);
+
+ size = req->urlo->filelen;
+ tmpbuf = req->ti->output_buffer;
+ oldmm = get_fs(); set_fs(KERNEL_DS);
+ ret = http_read(req->urlo, tmpbuf);
+ set_fs(oldmm);
+
+ if (ret != size)
+ return send_err(req, "CAD: error while reading object file!\n");
+ tmpbuf[size] = 0; // zero-delimited string
+
+ target = tmpbuf;
+ left = size - CAD_TAG_LEN + 1;
+
+ for (;;) {
+ target = memchr(target, CAD_TAG[0], left);
+ if (!target)
+ break; // no such character left
+
+ if (memcmp(target, CAD_TAG, CAD_TAG_LEN)) {
+ target++; // skip past the '<'
+ left--;
+ continue;
+ }
+ target += CAD_TAG_BODY_POS;
+ memcpy(target, CADp->ad_filename, CAD_TAG_BODY_LEN);
+ target += CAD_TAG_BODY_LEN + CAD_TAG_TAIL_LEN;
+ left -= CAD_TAG_LEN;
+ }
+
+ http_send_client(req, tmpbuf, size, 0);
+
+ return size;
+}
+
+
+typedef struct user_dem_s {
+ unsigned int dem;
+} user_dem_t;
+
+static int max_userid;
+static user_dem_t *user_dem = NULL;
+static struct http_direntry *user_pers_dentry;
+
+#define USER_PERS_FILE "User.Personality"
+#define USER_PERS_RECLEN 15
+
+typedef struct ad_s {
+ unsigned int dem;
+ unsigned int gender_weight;
+ unsigned int age_weight;
+ unsigned int region_weight;
+ unsigned int interest_1_weight;
+ unsigned int interest_2_weight;
+ unsigned int min_match;
+ unsigned int expires;
+} ad_t;
+
+static int max_adid;
+static ad_t *ad = NULL;
+
+#define AD_FILE "Custom.Ads"
+#define AD_RECLEN 39
+
+static int read_custom_ads (http_req_t *req)
+{
+ struct http_file *file;
+ int ret, len, err = -2;
+ char *buf = NULL, *tmp;
+ struct http_direntry *dentry;
+ unsigned int adid, i, dem, min_match, weight, expires;
+
+
+ dentry = http_lookup_direntry(AD_FILE, &docroot, 0);
+ if (http_direntry_error(dentry))
+ goto error;
+ file = http_direntry_open(dentry, O_RDONLY, 0);
+ if (!file)
+ goto error;
+ len = http_file_size(file);
+ if (!len)
+ goto error;
+ if (ad) {
+ http_free(ad, ALLOC_AD_FILE);
+ ad = NULL;
+ }
+ max_adid = len/AD_RECLEN + 1;
+ ad = http_malloc(max_adid * sizeof(ad_t), ALLOC_AD_FILE);
+ buf = http_malloc(len, ALLOC_ADTMPBUF);
+ if (!ad || !buf)
+ goto error;
+
+ ret = http_read_file(file, buf, len);
+ http_close_file(file);
+ if (ret != len)
+ goto error;
+
+/*
+ * Sample ad record:
+ " 54 24808100 97F61 75 952393980\n"
+ */
+
+ tmp = buf;
+ i = 0;
+ for (tmp = buf; tmp != buf+len; tmp++) {
+
+ while (*tmp == ' ') tmp++;
+ adid = simple_strtoul(tmp, &tmp, 10);
+ if (adid != i)
+ goto error;
+ if (adid >= max_adid)
+ goto error;
+ i++;
+ if (*tmp != ' ')
+ goto error;
+ tmp++;
+ while (*tmp == ' ') tmp++;
+ dem = simple_strtoul(tmp, &tmp, 16);
+ tmp++;
+ while (*tmp == ' ') tmp++;
+ weight = simple_strtoul(tmp, &tmp, 16);
+ while (*tmp == ' ') tmp++;
+ min_match = simple_strtoul(tmp, &tmp, 10);
+ while (*tmp == ' ') tmp++;
+ expires = simple_strtoul(tmp, &tmp, 10);
+ if (*tmp != '\n')
+ goto error;
+ ad[adid].dem = dem;
+
+ ad[adid].gender_weight = (weight & 0x000f0000) >> 16;
+ ad[adid].age_weight = (weight & 0x0000f000) >> 12;
+ ad[adid].region_weight = (weight & 0x00000f00) >> 8;
+ ad[adid].interest_1_weight = (weight & 0x000000f0) >> 4;
+ ad[adid].interest_2_weight = (weight & 0x0000000f);
+
+ ad[adid].min_match = min_match;
+ ad[adid].expires = expires;
+
+ }
+ err = 0;
+error:
+ if (buf)
+ http_free(buf, ALLOC_ADTMPBUF);
+ if (err)
+ return send_err(req, "CAD: error while reading & parsing the ad file.\n");
+ return err;
+}
+
+static int read_user_personality (http_req_t *req)
+{
+ struct http_file *file;
+ int ret, len, err = -2;
+ char *buf = NULL, *tmp;
+ unsigned int uid, i, dem;
+ struct http_direntry *dentry;
+
+ dentry = http_lookup_direntry(USER_PERS_FILE, &docroot, 0);
+ if (http_direntry_error(dentry))
+ goto error;
+ file = http_direntry_open(dentry, O_RDONLY, 0);
+ if (!file)
+ goto error;
+ len = http_file_size(file);
+ if (!len)
+ goto error;
+ if (user_dem) {
+ http_free(user_dem, ALLOC_USERDEM);
+ user_dem = NULL;
+ }
+ max_userid = len/USER_PERS_RECLEN + 1;
+ user_dem = http_malloc(max_userid * sizeof(user_dem_t), ALLOC_USERDEM);
+ buf = http_malloc(len, ALLOC_USERDEM_TMPBUF);
+ if (!user_dem || !buf) {
+ goto error;
+ }
+
+ ret = http_read_file(file, buf, len);
+ http_close_file(file);
+ if (ret != len) {
+ goto error;
+ }
+
+ i = 0;
+ for (tmp = buf; tmp != buf+len; tmp++) {
+ if (*tmp == ' ')
+ continue;
+ uid = simple_strtoul(tmp, &tmp, 10);
+ if (uid != i)
+ goto error;
+ if (uid >= max_userid)
+ goto error;
+ i++;
+ if (*tmp != ' ')
+ goto error;
+ while (*tmp == ' ') tmp++;
+ dem = simple_strtoul(tmp, &tmp, 16);
+ if (*tmp != '\n')
+ goto error;
+ user_dem[uid].dem = dem;
+ }
+ err = 0;
+error:
+ if (buf)
+ http_free(buf, ALLOC_USERDEM_TMPBUF);
+ if (err)
+ return send_err(req, "CAD: error while reading & parsing the user file.\n");
+ return err;
+}
+
+#define MAX_CUSTOM_ADS 360
+
+static inline int find_ad (int user_id, int last_ad, int *weight_p)
+{
+ int adid, weight = 0, dem;
+
+ for (adid = last_ad + 1; adid != last_ad; adid++) {
+ if (adid >= MAX_CUSTOM_ADS)
+ adid = 0;
+
+ dem = user_dem[user_id].dem & ad[adid].dem;
+ weight = 0;
+
+ if (dem & 0x30000000)
+ weight += ad[adid].gender_weight;
+ if (dem & 0x0f000000)
+ weight += ad[adid].age_weight;
+ if (dem & 0x00f00000)
+ weight += ad[adid].region_weight;
+ if (dem & 0x000ffc00)
+ weight += ad[adid].interest_1_weight;
+ if (dem & 0x000003ff)
+ weight += ad[adid].interest_2_weight;
+ if (weight >= ad[adid].min_match)
+ break;
+ }
+
+ *weight_p = weight;
+ return adid;
+}
+
+static unsigned int last_mtime = 0;
+
+static int reread_files (http_req_t *req)
+{
+ int ret = -2;
+ struct http_direntry *dentry;
+
+ http_dput(user_pers_dentry);
+ dentry = http_lookup_direntry(USER_PERS_FILE, &docroot, 0);
+ if (http_direntry_error(dentry))
+ goto error;
+ user_pers_dentry = dentry;
+
+ if (http_mtime(dentry) != last_mtime) {
+ void *tmp = user_dem;
+ user_dem = NULL;
+ http_free(tmp, ALLOC_USERDEM);
+ if (read_user_personality(req))
+ goto error;
+ if (read_custom_ads(req))
+ goto error;
+ last_mtime = http_mtime(dentry);
+ }
+ ret = 0;
+
+error:
+ return ret;
+}
+
+static inline int custom_ad_rotate (http_req_t *req, CAD_t *CADp)
+{
+ int adid, weight, expired, err;
+ int user_id, last_ad;
+ time_t now;
+
+ user_id = CADp->user_id;
+ last_ad = CADp->last_ad;
+
+ if (http_direntry_error(user_pers_dentry) ||
+ (http_mtime(user_pers_dentry) != last_mtime)) {
+ err = reread_files(req);
+ if (err)
+ return err;
+ }
+
+ /*
+ * Any error in either reading or parsing of the files results
+ * in a returned -1 adid.
+ */
+ adid = -1;
+ expired = 1;
+ weight = 0;
+
+ adid = find_ad(user_id, last_ad, &weight);
+ if (adid < 0)
+ goto error;
+ now = http_time();
+ if (now <= ad[adid].expires)
+ expired = 0;
+
+error:
+ CADp->reply_cookies_len = sprintf(CADp->reply_cookies,
+ "found_cookie=Ad_id=%d&Ad_weight=%d&Expired=%d",
+ adid, weight, expired);
+
+ sprintf(CADp->ad_filename, "dir%05d/class%d_%d",
+ adid / 36, ((adid % 36) / 9), adid % 9);
+ return 0;
+}
+
+
+#define TOKEN_EQUAL(input,token) \
+ (!memcmp(input, token, sizeof(token)-1))
+
+#define PARSE_STRING(token,input,output) \
+ ({ \
+ int __ret = 0; \
+ if (TOKEN_EQUAL(input, token)) { \
+ char *tmp; \
+ \
+ input += sizeof(token)-1; \
+ tmp = output; \
+ while (*input && *input != '&' && \
+ *input != ',') \
+ *tmp++ = *input++; \
+ *tmp = 0; \
+ __ret = 1; \
+ } \
+ __ret; \
+ })
+
+#define PARSE_UINT(token,input,output) \
+ ({ \
+ int __ret = 0; \
+ if (TOKEN_EQUAL(input, token)) { \
+ \
+ input += sizeof(token)-1; \
+ output = simple_strtoul(input, &input, 10); \
+ __ret = 1; \
+ } \
+ __ret; \
+ })
+
+static int init_postlog_file (http_req_t *req)
+{
+ char buf[400], *tmp;
+ int ret;
+
+ if (post_file)
+ http_close_file(post_file);
+ post_file = http_open_file(POSTLOG, O_CREAT|O_TRUNC|O_APPEND|O_RDWR);
+ if (!post_file)
+ return send_err(req, "CAD: could not open POST-log!\n");
+ postlog_count = 0;
+ tmp = buf;
+ tmp += sprintf(tmp, "%10d\n", 0);
+ ret = http_write_file(post_file, buf, tmp-buf);
+ if (ret != tmp-buf)
+ return send_err(req, "CAD: POST-log write error!\n");
+ postlog_head_page = http_mmap_page(post_file, postlog_head, 0);
+ if (!postlog_head_page)
+ return send_err(req, "CAD: POST-log mmap error!\n");
+ return 0;
+}
+
+#define COMMAND_STRING "command/"
+#define COMMAND_RESET "Reset"
+#define COMMAND_FETCH "Fetch"
+
+static int do_reset (http_req_t *req, char *query)
+{
+ char maxload [20], pttime[20], maxthread[20],
+ exp1[20], exp2[20], urlroot [100];
+ char tmpstr1[256], tmpstr2[256];
+
+ http_sleep(1);
+ if (!PARSE_STRING("&maxload=", query, maxload))
+ return send_err(req,"CAD: invalid &maxload field!\n");
+ if (!PARSE_STRING("&pttime=", query, pttime))
+ return send_err(req,"CAD: invalid &pttime field!\n");
+ if (!PARSE_STRING("&maxthread=", query, maxthread))
+ return send_err(req,"CAD: invalid &maxthread field!\n");
+ if (!PARSE_STRING("&exp=", query, exp1))
+ return send_err(req,"CAD: invalid &exp1 field!\n");
+ if (!PARSE_STRING(",", query, exp2))
+ return send_err(req,"CAD: invalid &exp2 field!\n");
+ if (!PARSE_STRING("&urlroot=", query, urlroot))
+ return send_err(req,"CAD: invalid &urlroot field!\n");
+
+
+ strcpy(tmpstr1, http_docroot); strcat(tmpstr1, "/upfgen99");
+ strcpy(tmpstr2, http_docroot); strcat(tmpstr2, "/cadgen99");
+#define TOPDIR http_docroot
+#define UPFGEN tmpstr1
+#define CADGEN tmpstr2
+
+ {
+ char *argv_upfgen[] = { UPFGEN, "-C", TOPDIR, "-n", maxload,
+ "-t", maxthread, NULL};
+ char *argv_cadgen[] = { CADGEN, "-C", TOPDIR, "-e", pttime,
+ "-t", maxthread, exp1, exp2, NULL};
+ char * envp[] = { "HOME=/", "TERM=linux",
+ "PATH=/sbin:/usr/sbin:/bin:/usr/bin", NULL };
+
+ if (http_exec_process(UPFGEN, argv_upfgen, envp, 0, 0, 1) < 0)
+ return send_err(req,"CAD: could not execute UPFGEN!\n");
+
+ if (http_exec_process(CADGEN, argv_cadgen, envp, 0, 0, 1) < 0)
+ return send_err(req,"CAD: could not execute CADGEN!\n");
+ }
+ /*
+ * Clear post log
+ */
+ http_down(&postlog_sem);
+ init_postlog_file(req);
+ http_up(&postlog_sem);
+
+ /*
+ * mtime has a 1 second resolution, sleep 1 second so that
+ * the check for modified User.Personality and Custom.Ads
+ * files notices multiple resets correctly.
+ */
+ http_sleep(1);
+
+ req->bytes_sent = send_reply_head(req, 0);
+ req->bytes_sent += send_reply_tail(req);
+
+ return -2;
+}
+
+#define BLOCKLEN 512
+
+static int send_postlog (http_req_t *req)
+{
+ char buf [BLOCKLEN];
+ struct http_file *file;
+ int len, total, bytes;
+
+ file = http_open_file(POSTLOG, O_RDONLY);
+ if (http_file_error(file))
+ return send_err(req, "CAD: no POST-log file!\n");
+
+ req->body_len = http_file_size(file);
+ bytes = send_reply_head(req, req->body_len);
+ http_down(&postlog_sem);
+ total = 0;
+ do {
+ len = http_read_file(file, buf, BLOCKLEN);
+ if (len <= 0)
+ break;
+ bytes += http_send_client(req, buf, len, 0);
+ total += len;
+ } while (len == BLOCKLEN);
+
+ http_close_file(file);
+ http_up(&postlog_sem);
+ bytes += send_reply_tail(req);
+ req->bytes_sent = bytes;
+ req->keep_alive = 0;
+
+ return -2;
+}
+
+static int do_command (http_req_t *req, char *query)
+{
+ if (TOKEN_EQUAL(query, COMMAND_RESET))
+ return do_reset(req, query + sizeof(COMMAND_RESET)-1);
+ if (TOKEN_EQUAL(query, COMMAND_FETCH))
+ return send_postlog(req);
+ return send_err(req,"CAD: got invalid command!\n");
+}
+
+static CAD_t * parse_GET_cookies (http_req_t *req)
+{
+ int uid, last_ad;
+ CAD_t *CADp;
+ char *tmp;
+
+ if (!req->cookies_len) {
+ return NULL;
+ }
+
+ CADp = http_malloc(sizeof(CAD_t), ALLOC_REQ_PRIVATE);
+ CADp->reply_cookies_len = 0;
+ req->private = (void *) CADp;
+
+ tmp = req->cookies + sizeof("my_cookie=user_id=")-1;
+ uid = simple_strtoul(tmp, &tmp, 10) - 10000;
+
+ tmp += sizeof("&last_ad=")-1;
+ last_ad = simple_strtoul(tmp, &tmp, 10);
+
+ CADp->user_id = uid;
+ CADp->last_ad = last_ad;
+
+ return CADp;
+}
+
+static int do_POST (http_req_t *req)
+{
+ int dir = -1, class = -1, num = -1, client = -1;
+ char buf[400], *tmp;
+ char urlroot[100];
+ CAD_t *CADp;
+ char *curr;
+ int ret;
+
+ CADp = parse_GET_cookies(req);
+
+ curr = req->post_data;
+ if (!curr)
+ goto parse_error;
+
+#define POST_URLROOT "urlroot="
+#define POST_CLASS "class="
+#define POST_CLIENT "client="
+#define POST_DIR "dir="
+#define POST_NUM "num="
+
+ for (;;) {
+ switch (*curr) {
+ case 'u':
+ if (PARSE_STRING( POST_URLROOT, curr, urlroot))
+ continue;
+ goto parse_error;
+ case 'c':
+ if (PARSE_UINT( POST_CLASS, curr, class))
+ continue;
+ if (PARSE_UINT( POST_CLIENT, curr, client))
+ continue;
+ goto parse_error;
+ case 'd':
+ if (PARSE_UINT( POST_DIR, curr, dir))
+ continue;
+ goto parse_error;
+ case 'n':
+ if (PARSE_UINT( POST_NUM, curr, num))
+ continue;
+ goto parse_error;
+ case '&':
+ curr++;
+ continue;
+ case 0:
+ goto out;
+ default:
+ goto parse_error;
+ }
+ goto parse_error;
+ }
+out:
+ if (!CADp)
+ goto parse_error;
+ tmp = CADp->ad_filename;
+ tmp += sprintf(tmp, "%sdir%05d/class%d_%d", urlroot, dir, class, num);
+
+ /*
+ * Aquire semaphore guaranteeing atomic operations
+ * on the postlog file.
+ */
+ http_down(&postlog_sem);
+ if (!post_file)
+ if (init_postlog_file(req))
+ return 0;
+
+ postlog_count++;
+ tmp = postlog_head;
+ tmp += sprintf(tmp, "%10d", postlog_count);
+ *tmp = '\n';
+
+ tmp = buf;
+ tmp += sprintf(tmp, "%10d %10ld %10d %5d %2d %2d %10d %-60.60s %10d %10d\n", postlog_count, http_time(), http_getpid(), dir, class, num, client, CADp->ad_filename, http_getpid(), CADp->user_id + 10000);
+
+ ret = http_write_file(post_file, buf, tmp-buf);
+ http_up(&postlog_sem);
+
+ if (ret != tmp-buf)
+ goto write_error;
+
+ CADp->reply_cookies_len = sprintf(CADp->reply_cookies,
+ "my_cookie=%u", 10000 + CADp->user_id);
+ return 0;
+
+parse_error:
+ return send_err(req,"CAD: error while parsing POST request!\n");
+
+write_error:
+ return send_err(req, "CAD: POST-log write error!\n");
+}
+
+static int query_CAD (http_req_t *req)
+{
+ urlo_t *urlo = NULL;
+ int ret = 0;
+ CAD_t *CADp;
+ int missed;
+
+
+ if (req->method == METHOD_POST) {
+ ret = do_POST(req);
+ if (ret)
+ return ret;
+ CADp = (CAD_t *)req->private;
+ req->objectname = CADp->ad_filename;
+ req->objectname_len = strlen(CADp->ad_filename);
+ } else {
+ char *tmp = req->query;
+
+ if (req->method != METHOD_GET)
+ goto url_error;
+ if (TOKEN_EQUAL(req->query, COMMAND_STRING)) {
+ tmp += sizeof(COMMAND_STRING)-1;
+ return do_command(req, tmp);
+ }
+ req->objectname = req->query;
+ req->objectname_len = req->query_len;
+ CADp = parse_GET_cookies(req);
+ }
+
+ missed = lookup_urlo(req, LOOKUP_ATOMIC);
+ if (req->userspace_module)
+ HTTP_BUG();
+ urlo = req->urlo;
+ if ((!missed && !urlo) || (urlo && urlo->tcapi))
+ goto url_error;
+ if (req->method == METHOD_GET) {
+ if (CADp) {
+ ret = custom_ad_rotate(req, CADp);
+ if (ret)
+ return ret;
+ }
+ }
+
+ if (missed || !urlo->csumc)
+ return http_miss_req(req);
+
+ return ret;
+
+url_error:
+ return send_err(req, "CAD: error while parsing CAD request!\n");
+}
+
+#define REPLY_HEAD_HEAD \
+ "HTTP/1.1 200 OK\r\n" \
+ "Content-Type: text/html\r\n" \
+ "Connection: Keep-Alive\r\n" \
+ "Content-Length: %d\r\n\r\n"
+
+#define REPLY_HEAD_HEAD_COOKIE \
+ "HTTP/1.1 200 OK\r\n" \
+ "Content-Type: text/html\r\n" \
+ "Connection: Keep-Alive\r\n" \
+ "Content-Length: %d\r\n" \
+ "Set-Cookie: %s\r\n" \
+ "\r\n"
+
+#define REPLY_HEAD_TAIL \
+ "<html>\n" \
+ "<head><title>SPECweb99 Dynamic GET & POST Test</title></head>\n"\
+ "<body>\n" \
+ "<p>SERVER_SOFTWARE = TUX 1.0\n" \
+ "<p>REMOTE_ADDR = %d.%d.%d.%d\n" \
+ "<p>SCRIPT_NAME = %s\n" \
+ "<p>QUERY_STRING = %s\n" \
+ "<pre>\n"
+
+#define REPLY_TAIL \
+ "\n</pre>\n" \
+ "</body></html>\n"
+
+static int inline send_reply_head (http_req_t *req, size_t body_size)
+{
+ char buf [1000];
+ char *tmp, *head, *tail;
+ CAD_t *CADp = (CAD_t *)req->private;
+ unsigned int host, head_len, tail_len, total_len;
+
+ host = http_client_addr(req);
+#define IP(x) (((unsigned char *)&host)[x])
+
+ tmp = tail = buf;
+ tmp += sprintf(tmp, REPLY_HEAD_TAIL, IP(0), IP(1), IP(2), IP(3),
+ req->tcapi->vfs_name, req->query);
+
+ tail_len = tmp-buf;
+
+ total_len = tail_len + sizeof(REPLY_TAIL)-1 + body_size;
+
+ head = tmp;
+ if (CADp && CADp->reply_cookies_len)
+ tmp += sprintf(tmp, REPLY_HEAD_HEAD_COOKIE, total_len, CADp->reply_cookies);
+ else
+ tmp += sprintf(tmp, REPLY_HEAD_HEAD, total_len);
+
+ head_len = tmp-head;
+ http_send_client(req, head, head_len, 0);
+ http_send_client(req, tail, tail_len, 0);
+ req->http_status = 200;
+
+ return tail_len;
+}
+
+static inline int send_reply_tail (http_req_t *req)
+{
+ int len = sizeof(REPLY_TAIL)-1;
+
+ http_send_client(req, REPLY_TAIL, len, 1);
+ return len;
+}
+
+
+/*
+ * Send a dynamicly generated buffer. (this is the typical
+ * CAD case) Every reply is generated dynamically based on
+ * the template and cookie values. The template is scanned
+ * for every send.
+ */
+static int send_reply_CAD (http_req_t *req)
+{
+ int bytes;
+ CAD_t *CADp = (CAD_t *)req->private;
+
+ req->body_len = req->urlo->body_len;
+
+ bytes = send_reply_head(req, req->body_len);
+ bytes += scan_send_file(req, CADp);
+ bytes += send_reply_tail(req);
+
+ return bytes;
+}
+
+/*
+ * Return SPECweb99 error message.
+ */
+static int send_err (http_req_t *req, char *message)
+{
+ CAD_t *CADp = req->private;
+ int len = strlen(message);
+ int bytes;
+
+ /*
+ * Return a -1 Ad_id in the reply cookie.
+ */
+ CADp->reply_cookies_len = sprintf(CADp->reply_cookies,
+ "found_cookie=Ad_id=-1&Ad_weight=0&Expired=1");
+
+ req->body_len = len;
+ bytes = send_reply_head(req, len);
+ http_send_client(req, message, len, 0);
+ bytes += len;
+ bytes += send_reply_tail(req);
+
+ req->bytes_sent = bytes;
+ return -2;
+}
+
+static tcapi_template_t CAD_tcapi = {
+ vfs_name: "d",
+ version: HTTP_VERSION,
+ query: query_CAD,
+ send_reply: send_reply_CAD,
+};
+
+static int CAD_start (void)
+{
+ CAD_tcapi.mod = THIS_MODULE;
+
+ return register_httpmodule(&CAD_tcapi);
+}
+
+void CAD_stop (void)
+{
+ unregister_httpmodule(&CAD_tcapi);
+}
+
+module_init(CAD_start)
+module_exit(CAD_stop)
+
--- linux/net/http/TODO.orig Fri Sep 1 07:28:26 2000
+++ linux/net/http/TODO Fri Sep 1 07:28:26 2000
@@ -0,0 +1,4 @@
+- If-Modified-Since HTTP request header
+- Last-Modified reply HTTP header
+- byte ranges?
+- add and stabilize the virtual hosting patches
--- linux/net/http/httpmod.c.orig Fri Sep 1 07:28:26 2000
+++ linux/net/http/httpmod.c Fri Sep 1 07:28:26 2000
@@ -0,0 +1,125 @@
+/*
+ * TUX - Integrated HTTP layer and Object Cache
+ *
+ * Copyright (C) 2000, Ingo Molnar <
[email protected]>
+ *
+ * httpmod.c: loading/registering of HTTP dynamic modules
+ */
+
+#include <net/http.h>
+#include <linux/kmod.h>
+
+spinlock_t httpmodules_lock = SPIN_LOCK_UNLOCKED;
+static LIST_HEAD(httpmodules_list);
+
+static tcapi_template_t * lookup_module (const char *vfs_name)
+{
+ tcapi_template_t *tcapi;
+ struct list_head *head, *curr, *next;
+
+ Dprintk("looking up HTTP module {%s}.\n", vfs_name);
+ head = &httpmodules_list;
+ next = head->next;
+
+ while ((curr = next) != head) {
+ tcapi = list_entry(curr, tcapi_template_t, modules);
+ next = curr->next;
+ Dprintk("checking module {%s} == {%s}?\n", vfs_name, tcapi->vfs_name);
+ if (!strcmp(tcapi->vfs_name, vfs_name))
+ return tcapi;
+ }
+ return NULL;
+}
+
+/*
+ * Attempt to load a HTTP application module.
+ * This is the slow path, we cache ('link') the module's
+ * API vector to the inode.
+ * The module loading path is serialized, and we handshake
+ * with the loaded module and fetch it's API vector.
+ */
+int load_httpmodule (urlobj_t *urlo, const char *filename)
+{
+ tcapi_template_t *tcapi;
+ int err = 0;
+
+ spin_lock(&httpmodules_lock);
+ if (urlo->tcapi)
+ goto out;
+ tcapi = lookup_module(filename);
+ if (!tcapi) {
+ printk("did not find module vfs:{%s}\n", filename);
+ err = -1;
+ }
+ urlo->tcapi = tcapi;
+out:
+ spin_unlock(&httpmodules_lock);
+ return err;
+}
+
+
+int register_httpmodule (tcapi_template_t *tcapi)
+{
+ int ret = -EEXIST;
+
+ spin_lock(&httpmodules_lock);
+
+ if (lookup_module(tcapi->vfs_name)) {
+ printk("module with VFS binding '%s' already registered!\n",
+ tcapi->vfs_name);
+ goto out;
+ }
+
+ list_add(&tcapi->modules, &httpmodules_list);
+ ret = 0;
+ Dprintk("HTTP module %s registered.\n", tcapi->vfs_name);
+out:
+ spin_unlock(&httpmodules_lock);
+
+ return ret;
+}
+
+int unregister_httpmodule (tcapi_template_t *tcapi)
+{
+ tcapi_template_t *tmp;
+ int err = 0;
+
+ spin_lock(&httpmodules_lock);
+ tmp = lookup_module(tcapi->vfs_name);
+ if (!tcapi) {
+ Dprintk("huh, module %s not registered??\n", tcapi->vfs_name);
+ err = -1;
+ } else {
+ list_del(&tcapi->modules);
+ Dprintk("HTTP module %s unregistered.\n", tcapi->vfs_name);
+ }
+ tmp = lookup_module(tcapi->vfs_name);
+ if (tmp)
+ Dprintk("huh, module %s still registered??\n", tcapi->vfs_name);
+ spin_unlock(&httpmodules_lock);
+
+ return err;
+}
+
+#if CONFIG_IO_TRACE
+#endif
+EXPORT_SYMBOL(lookup_urlo);
+EXPORT_SYMBOL(register_httpmodule);
+EXPORT_SYMBOL(unregister_httpmodule);
+EXPORT_SYMBOL(http_open_file);
+EXPORT_SYMBOL(send_dynamic_reply);
+EXPORT_SYMBOL(errno);
+EXPORT_SYMBOL(docroot);
+EXPORT_SYMBOL(http_docroot);
+EXPORT_SYMBOL(queue_output_req);
+EXPORT_SYMBOL(http_miss_req);
+EXPORT_SYMBOL(do_pipe);
+EXPORT_SYMBOL(http_kmalloc);
+EXPORT_SYMBOL(sys_read);
+EXPORT_SYMBOL(reap_kids);
+EXPORT_SYMBOL(free_uid);
+EXPORT_SYMBOL(flush_signal_handlers);
+EXPORT_SYMBOL(http_send_object);
+EXPORT_SYMBOL(http_Dprintk);
+EXPORT_SYMBOL(http_exec_process);
+
--- linux/net/http/cgi.c.orig Fri Sep 1 07:28:26 2000
+++ linux/net/http/cgi.c Fri Sep 1 07:28:26 2000
@@ -0,0 +1,140 @@
+/*
+ * TUX - Integrated HTTP layer and Object Cache
+ *
+ * Copyright (C) 2000, Ingo Molnar <
[email protected]>
+ *
+ * cgi.c: user-space CGI (and other) code execution.
+ */
+
+#define __KERNEL_SYSCALLS__
+
+#include <net/http.h>
+
+static int exec_usermode(char *program_path, char *argv[], char *envp[])
+{
+ int i;
+
+Dprintk("exec_usermode #0\n");
+ current->session = -1;
+ current->pgrp = -1;
+
+ spin_lock_irq(¤t->sigmask_lock);
+ flush_signals(current);
+ flush_signal_handlers(current);
+ spin_unlock_irq(¤t->sigmask_lock);
+
+Dprintk("exec_usermode #1\n");
+ for (i = 2; i < current->files->max_fds; i++ ) {
+ if (current->files->fd[i]) close(i);
+ }
+
+ free_uid(current->user);
+
+Dprintk("exec_usermode #2\n");
+ /* Give the new process no privileges.. */
+ current->uid = current->euid = current->fsuid = -1;
+ cap_clear(current->cap_permitted);
+ cap_clear(current->cap_inheritable);
+ cap_clear(current->cap_effective);
+
+ /* Allow execve args to be in kernel space. */
+ set_fs(KERNEL_DS);
+
+Dprintk("exec_usermode #3\n");
+ if (execve(program_path, argv, envp) < 0) {
+Dprintk("exec_usermode #4\n");
+ return -errno;
+ }
+Dprintk("exec_usermode #5\n");
+ return 0;
+}
+
+static int exec_helper (void * data)
+{
+ exec_param_t *param = data;
+ char **tmp;
+ int ret;
+
+ current->flags &= ~PF_ATOMICALLOC;
+ current->http--;
+ sprintf(current->comm,"doexec - %i", current->pid);
+
+ if (!param)
+ HTTP_BUG();
+ Dprintk("doing exec(%s).\n", param->command);
+
+ Dprintk("argv: ");
+ tmp = param->argv;
+ while (*tmp) {
+ Dprintk("{%s} ", *tmp);
+ tmp++;
+ }
+ Dprintk("\n");
+ Dprintk("envp: ");
+ tmp = param->envp;
+ while (*tmp) {
+ Dprintk("{%s} ", *tmp);
+ tmp++;
+ }
+ Dprintk("\n");
+ /*
+ * set up the socket as stdin and stdout of the external
+ * CGI application.
+ */
+ if (param->pipe_fds) {
+ // do not close on exec.
+ sys_fcntl(0, F_SETFD, 0);
+ sys_fcntl(1, F_SETFD, 0);
+ }
+
+ ret = exec_usermode(param->command, param->argv, param->envp);
+ if (ret < 0)
+ Dprintk("bug: exec() returned %d.\n", ret);
+ else
+ Dprintk("exec()-ed successfully!\n");
+ return 0;
+}
+
+int http_exec_process (char *command, char **argv,
+ char **envp, int *pipe_fds,
+ exec_param_t *param, int wait)
+{
+ exec_param_t param_local;
+ pid_t pid;
+ int ret = 0;
+ struct k_sigaction *ka;
+
+ ka = current->sig->action + SIGCHLD-1;
+ ka->sa.sa_handler = SIG_IGN;
+
+ if (!param && wait)
+ param = ¶m_local;
+
+ param->command = command;
+ param->argv = argv;
+ param->envp = envp;
+ param->pipe_fds = pipe_fds;
+
+repeat_fork:
+ pid = kernel_thread(exec_helper, (void*) param, CLONE_SIGHAND|SIGCHLD);
+ Dprintk("kernel thread created PID %d.\n", pid);
+ if (pid < 0) {
+ printk("couldnt create new kernel thread due to %d... retrying.\n", pid);
+ current->http--;
+ schedule_timeout(1);
+ current->http++;
+ goto repeat_fork;
+ }
+ if (wait) {
+ current->http--;
+repeat:
+ ret = waitpid(pid, NULL, __WALL);
+ Dprintk("waitpid returned %d.\n", ret);
+ if (ret == -ERESTARTSYS) {
+ reap_kids();
+ goto repeat;
+ }
+ current->http++;
+ }
+ return ret;
+}
--- linux/net/http/httpmain.c.orig Fri Sep 1 07:28:26 2000
+++ linux/net/http/httpmain.c Fri Sep 1 07:28:26 2000
@@ -0,0 +1,873 @@
+/*
+ * TUX - Integrated HTTP layer and Object Cache
+ *
+ * Copyright (C) 2000, Ingo Molnar <
[email protected]>
+ *
+ * httpmain.c: main management and initialization routines
+ */
+
+#define __KERNEL_SYSCALLS__
+#include <net/http.h>
+
+#include <linux/config.h>
+#include <linux/module.h>
+
+
+/*
+ * Threads information.
+ */
+static int nr_threads;
+static atomic_t nr_threads_running = ATOMIC_INIT(0);
+
+threadinfo_t threadinfo[CONFIG_HTTP_NUMTHREADS];
+
+struct nameidata docroot;
+
+void flush_all_signals (void)
+{
+ spin_lock_irq(¤t->sigmask_lock);
+ flush_signals(current);
+ recalc_sigpending(current);
+ spin_unlock_irq(¤t->sigmask_lock);
+}
+
+static int work_pending (threadinfo_t *ti)
+{
+ int j;
+
+ if (!list_empty(&ti->input_pending) ||
+ !list_empty(&ti->userspace_pending) ||
+ !list_empty(&ti->output_pending) ||
+ !list_empty(&ti->redirect_pending) ||
+ !list_empty(&ti->finish_pending))
+ return 1;
+
+ for (j = 0; j < CONFIG_HTTP_NUMSOCKETS; j++) {
+ if (!ti->listen[j])
+ break;
+ if (ti->listen[j]->sk->tp_pinfo.af_tcp.accept_queue)
+ return 1;
+ }
+ return 0;
+}
+
+void reap_kids (void)
+{
+ int count = 0;
+
+ __set_task_state(current, TASK_RUNNING);
+// flush_all_signals();
+ while (sys_wait4(-1, NULL, WNOHANG, NULL) > 0)
+ count++;
+
+ Dprintk("reaped %d kids (%p).\n", count, __builtin_return_address(0));
+}
+
+static int event_loop (threadinfo_t *ti)
+{
+ int work_done;
+
+repeat:
+ if (ti->thread != current)
+ HTTP_BUG();
+ work_done = 0;
+
+ /*
+ * Any (relevant) event on the socket will change this
+ * thread to TASK_RUNNING because we add it to both
+ * the main listening and the connection request socket
+ * waitqueues. Thus we can do 'lazy checking' of work
+ * to be done and schedule away only if the thread is
+ * still TASK_INTERRUPTIBLE. This makes TUX fully
+ * event driven.
+ */
+ __set_task_state(current, TASK_INTERRUPTIBLE);
+
+ work_done += accept_requests(ti);
+ if (ti->userspace_req)
+ HTTP_BUG();
+ if (!list_empty(&ti->input_pending))
+ work_done += read_headers(ti);
+ if (ti->userspace_req)
+ HTTP_BUG();
+ if (!list_empty(&ti->userspace_pending)) {
+ http_req_t *req;
+
+ req = pick_userspace_req(ti);
+ if (!req)
+ HTTP_BUG();
+ if (!req->tcapi)
+ BUG();
+ ti->userspace_req = req;
+ if (req->ti != ti)
+ HTTP_BUG();
+ goto handle_userspace_req;
+ }
+ if (!list_empty(&ti->output_pending))
+ work_done += send_replies(ti);
+ if (ti->userspace_req)
+ HTTP_BUG();
+ if (!list_empty(&ti->redirect_pending))
+ work_done += redirect_requests(ti);
+ if (ti->userspace_req)
+ HTTP_BUG();
+ if (!list_empty(&ti->finish_pending))
+ work_done += finish_requests(ti);
+ if (ti->userspace_req)
+ HTTP_BUG();
+
+ if (http_stop)
+ return HTTP_RETURN_EXIT;
+ /*
+ * Catch possible SIGCHLDs coming from external CGI
+ * processes.
+ */
+ if (signal_pending(current)) {
+ reap_kids();
+ work_done = 1;
+ }
+ /*
+ * Any signals left?
+ */
+ if (signal_pending(current))
+ goto handle_signal;
+
+ /*
+ * Any socket event either on the listen socket
+ * or on the request sockets will wake us up:
+ */
+ if (!work_done && (current->state != TASK_RUNNING) &&
+ !work_pending(ti)) {
+ Dprintk("fast thread: no work to be done, sleeping.\n");
+// up(ti->used);
+ schedule();
+// down(ti->used);
+ Dprintk("fast thread: back from sleep!\n");
+ }
+
+ /*
+ * Be nice to other processes:
+ */
+ if (!current->need_resched)
+ goto repeat;
+
+ __set_task_state(current, TASK_RUNNING);
+ current->policy |= SCHED_YIELD;
+ schedule();
+ goto repeat;
+handle_userspace_req:
+ __set_task_state(current, TASK_RUNNING);
+ return HTTP_RETURN_USERSPACE_REQUEST;
+handle_signal:
+ __set_task_state(current, TASK_RUNNING);
+ return HTTP_RETURN_SIGNAL;
+}
+
+static int init_queues (int nr_threads)
+{
+ int i;
+
+ for (i = 0; i < nr_threads; i++) {
+ threadinfo_t *ti = threadinfo + i;
+
+ ti->output_buffer = (char*) __get_free_pages(GFP_USER,
+ OUT_BUF_ORDER);
+ if (!ti->output_buffer)
+ HTTP_BUG();
+
+ INIT_LIST_HEAD(&ti->all_requests);
+ ti->free_requests_lock = SPIN_LOCK_UNLOCKED;
+ INIT_LIST_HEAD(&ti->free_requests);
+ ti->input_lock = SPIN_LOCK_UNLOCKED;
+ INIT_LIST_HEAD(&ti->input_pending);
+ ti->userspace_lock = SPIN_LOCK_UNLOCKED;
+ INIT_LIST_HEAD(&ti->userspace_pending);
+ ti->output_lock = SPIN_LOCK_UNLOCKED;
+ INIT_LIST_HEAD(&ti->output_pending);
+ INIT_LIST_HEAD(&ti->redirect_pending);
+ INIT_LIST_HEAD(&ti->finish_pending);
+ }
+ return 0;
+}
+
+static int initialized = 0;
+
+static int user_req_startup (void)
+{
+ int i;
+
+ if (initialized)
+ return -EINVAL;
+ initialized = 1;
+
+ /*
+ * Look up document root:
+ */
+ if (docroot.mnt)
+ HTTP_BUG();
+ docroot.mnt = mntget(current->fs->rootmnt);
+ docroot.dentry = dget(current->fs->root);
+ docroot.last.len = 0;
+ docroot.flags = LOOKUP_FOLLOW|LOOKUP_POSITIVE;
+
+ if (path_walk(http_docroot, &docroot)) {
+ docroot.mnt = NULL;
+ initialized = 0;
+ return -EINVAL;
+ }
+
+ /*
+ * Start up the logger thread. (which opens the logfile)
+ */
+ init_log_thread();
+
+ nr_threads = http_threads;
+ if (nr_threads < 1)
+ nr_threads = 1;
+ if (nr_threads > CONFIG_HTTP_NUMTHREADS)
+ nr_threads = CONFIG_HTTP_NUMTHREADS;
+ http_threads = nr_threads;
+
+ /*
+ * Set up per-thread work-queues:
+ */
+ memset(threadinfo, 0, CONFIG_HTTP_NUMTHREADS*sizeof(threadinfo_t));
+ init_queues(nr_threads);
+
+ /*
+ * Prepare the worker thread structures.
+ */
+ for (i = 0; i < nr_threads; i++) {
+ threadinfo_t *ti = threadinfo + i;
+ ti->cpu = i;
+ init_MUTEX(&ti->used);
+ }
+
+ return 0;
+}
+
+static DECLARE_WAIT_QUEUE_HEAD(wait_stop);
+
+static int user_req_shutdown (void)
+{
+ int err = -EINVAL;
+
+ lock_kernel();
+ if (!initialized)
+ goto err;
+ /*
+ * Wake up all the worker threads so they notice
+ * that we are being stopped.
+ */
+ wake_up(&wait_stop);
+
+ if (atomic_read(&nr_threads_running) > 0)
+ goto err;
+ initialized = 0;
+ if (nr_async_io_pending())
+ HTTP_BUG();
+ stop_log_thread();
+ mntput(docroot.mnt);
+ docroot.mnt = NULL;
+ dput(docroot.dentry);
+ docroot.dentry = NULL;
+ http_stop = 0;
+ err = 0;
+
+err:
+ unlock_kernel();
+ return err;
+}
+
+static int user_req_start_thread (threadinfo_t *ti)
+{
+ unsigned int mask, i, j, k, cpu;
+ struct k_sigaction *ka;
+
+ cpu = ti->cpu;
+ mask = 1 << cpu;
+#if CONFIG_SMP
+ if (cpu_online_map & mask)
+ current->cpus_allowed = mask;
+#endif
+ printk("setting TUX - %d 's cpus_allowed mask to %08lx\n",
+ cpu, current->cpus_allowed);
+ ti->thread = current;
+ current->http = 1;
+ current->flags |= PF_ATOMICALLOC;
+
+ init_waitqueue_entry(&ti->stop, current);
+ for (j = 0; j < CONFIG_HTTP_NUMSOCKETS; j++)
+ init_waitqueue_entry(ti->wait_event + j, current);
+
+ ka = current->sig->action + SIGCHLD-1;
+ ka->sa.sa_handler = SIG_IGN;
+
+ /* Block all signals except SIGKILL, SIGSTOP, SIGHUP and SIGCHLD */
+ spin_lock_irq(¤t->sigmask_lock);
+ siginitsetinv(¤t->blocked, sigmask(SIGKILL) |
+ sigmask(SIGSTOP)| sigmask(SIGHUP) | sigmask(SIGCHLD));
+ recalc_sigpending(current);
+ spin_unlock_irq(¤t->sigmask_lock);
+
+ for (k = 0; k < CONFIG_HTTP_NUMSOCKETS; k++) {
+ if (http_listen[cpu][k] == -1)
+ break;
+ for (i = 0; i < cpu; i++) {
+ for (j = 0; j < CONFIG_HTTP_NUMSOCKETS; j++) {
+ if (http_listen[i][j] == -1)
+ break;
+ if (http_listen[i][j] == http_listen[cpu][k]) {
+ while (!threadinfo[i].listen[j]) {
+ current->policy |= SCHED_YIELD;
+ schedule();
+ }
+ ti->listen[k] = threadinfo[i].listen[j];
+ ti->listen_cloned[k] = 1;
+ goto out;
+ }
+ }
+ }
+ ti->listen[k] = start_listening(http_serverport,
+ http_listen[cpu][k]);
+ if (!ti->listen[k])
+ goto error;
+ ti->listen_cloned[k] = 0;
+ }
+out:
+ if (!ti->listen[0])
+ HTTP_BUG();
+
+ add_wait_queue(&wait_stop, &ti->stop);
+ for (j = 0; j < CONFIG_HTTP_NUMSOCKETS; j++)
+ if (ti->listen[j])
+ add_wait_queue_exclusive(ti->listen[j]->sk->sleep,
+ ti->wait_event + j);
+ ti->started = 1;
+ atomic_inc(&nr_threads_running);
+ return 0;
+
+error:
+ flush_inputqueue(ti);
+ flush_userspacequeue(ti);
+ flush_outputqueue(ti);
+ flush_redirectqueue(ti);
+ flush_logqueue(ti);
+
+ printk(KERN_NOTICE "HTTP: could not start worker thread %i.\n", ti->cpu);
+
+ return -EINVAL;
+}
+
+static void flush_idleinput (threadinfo_t * ti)
+{
+ struct list_head *head, *tmp;
+ http_req_t *req;
+
+ head = &ti->all_requests;
+ tmp = head->next;
+
+ while (tmp != head) {
+ req = list_entry(tmp, http_req_t, all);
+ tmp = tmp->next;
+ if (test_bit(0, &req->idle_input))
+ idle_event(req);
+ }
+}
+
+static void flush_all_requests (threadinfo_t *ti)
+{
+ for (;;) {
+ int n1, n2;
+
+ n1 = ti->nr_requests;
+ __set_task_state(current, TASK_RUNNING);
+ flush_logqueue(ti);
+ __set_task_state(current, TASK_INTERRUPTIBLE);
+
+ flush_idleinput(ti);
+ flush_inputqueue(ti);
+ flush_userspacequeue(ti);
+ flush_outputqueue(ti);
+ flush_redirectqueue(ti);
+ flush_freequeue(ti);
+ if (!ti->nr_requests)
+ break;
+ n2 = ti->nr_requests;
+ if (n1 != n2)
+ continue;
+ schedule();
+ }
+}
+
+static int user_req_stop_thread (threadinfo_t *ti)
+{
+ int j;
+
+ printk(KERN_NOTICE "HTTP fast thread %d: stopping\n", threadinfo-ti);
+ printk("worker: event #1.\n");
+
+ if (!ti->started)
+ HTTP_BUG();
+ for (j = 0; j < CONFIG_HTTP_NUMSOCKETS; j++)
+ if (ti->listen[j])
+ remove_wait_queue(ti->listen[j]->sk->sleep,
+ ti->wait_event + j);
+ remove_wait_queue(&wait_stop, &ti->stop);
+
+ for (j = 0; j < CONFIG_HTTP_NUMSOCKETS; j++) {
+ if (!ti->listen[j])
+ break;
+ if (!ti->listen_cloned[j]) {
+ while (waitqueue_active(ti->listen[j]->sk->sleep)) {
+ current->policy |= SCHED_YIELD;
+ schedule();
+ }
+ printk("worker: event #2.\n");
+ stop_listening(&ti->listen[j]);
+ }
+ }
+
+ flush_all_requests(ti);
+
+ if (ti->nr_requests)
+ HTTP_BUG();
+ ti->started = 0;
+ wmb();
+
+ printk(KERN_NOTICE "HTTP: worker thread %i stopped.\n", ti->cpu);
+
+ ti->thread = NULL;
+ current->http_info = NULL;
+ atomic_dec(&nr_threads_running);
+
+ return 0;
+}
+
+static int prepare_userspace_req (threadinfo_t *ti, user_req_t *u_info)
+{
+ http_req_t *req = ti->userspace_req;
+ unsigned int tmp;
+ int fd;
+
+ Dprintk("prepare_userspace_req(%p).\n", req);
+ if (!req)
+ HTTP_BUG();
+
+ if (req->userspace_fd == -1) {
+ fd = sock_map_fd(req->sock);
+ Dprintk("sock_map_fd(%p) :%d.\n", req, fd);
+ if (fd < 0)
+ HTTP_BUG();
+ req->userspace_fd = fd;
+ // igrab((frip(current->files, fd))->f_dentry->d_inode);
+ } else
+ fd = req->userspace_fd;
+
+#define return_EFAULT do { Dprintk("-EFAULT at %d:%s.\n", __LINE__, __FILE__); return -EFAULT; } while (0)
+
+ if (copy_to_user(&u_info->sock, &fd, sizeof(fd)))
+ return_EFAULT;
+ if (!req->tcapi)
+ HTTP_BUG();
+ if (copy_to_user(&u_info->module_index,
+ &req->tcapi->userspace_id, sizeof(int)))
+ return_EFAULT;
+ if (req->query) {
+ if (copy_to_user(&u_info->query, req->query, req->query_len + 1))
+ return_EFAULT;
+ } else {
+ /*
+ * Put a null-string into the user-space query string.
+ */
+ char null = 0;
+
+ if (copy_to_user(&u_info->query, &null, 1))
+ return_EFAULT;
+ }
+ if (copy_to_user(&u_info->event, &req->event, sizeof(req->event)))
+ return_EFAULT;
+ {
+ unsigned int filelen;
+
+ if (req->urlo)
+ filelen = req->urlo->filelen;
+ else
+ filelen = -1;
+ if (copy_to_user(&u_info->objectlen, &filelen, sizeof(req->event)))
+ return_EFAULT;
+ }
+ if (copy_to_user(&u_info->http_version, &req->version, sizeof(req->version)))
+ return_EFAULT;
+ if (copy_to_user(&u_info->http_method, &req->method, sizeof(req->method)))
+ return_EFAULT;
+ if (copy_to_user(&u_info->cookies_len, &req->cookies_len, sizeof(req->cookies_len)))
+ return_EFAULT;
+ if (req->cookies_len)
+ if (copy_to_user(&u_info->cookies, req->cookies, req->cookies_len+1))
+ return_EFAULT;
+ if (copy_to_user(&u_info->id, &req, sizeof(req)))
+ return_EFAULT;
+ if (copy_to_user(&u_info->private, &req->private, sizeof(req->private)))
+ return_EFAULT;
+ if (copy_to_user(&u_info->bytes_sent, &req->bytes_sent, sizeof(int)))
+ return_EFAULT;
+ if ((req->method == METHOD_POST) && req->post_data)
+ if (copy_to_user(&u_info->post_data, req->post_data, req->post_data_len+1))
+ return_EFAULT;
+ tmp = http_client_addr(req);
+ if (copy_to_user(&u_info->client_host, &tmp, sizeof(req->version)))
+ return_EFAULT;
+ return HTTP_RETURN_USERSPACE_REQUEST;
+}
+
+static int user_register_module (user_req_t *u_info)
+{
+ int ret = -EINVAL;
+ tcapi_template_t *tcapi;
+ char modulename [MAX_MODULENAME_LEN+1];
+ int idx, len;
+
+ Dprintk("register user-module, %p.\n", u_info);
+ ret = strncpy_from_user(modulename, u_info->modulename,
+ MAX_MODULENAME_LEN);
+ if (ret <= 0)
+ goto out;
+ Dprintk("... user-module is: {%s}.\n", modulename);
+ len = strlen(modulename);
+ if (!len || (len > MAX_MODULENAME_LEN))
+ HTTP_BUG();
+ Dprintk("... user-module len is: %d.\n", len);
+
+ ret = copy_from_user(&idx, &u_info->module_index, sizeof(int));
+ if (ret || !idx)
+ goto out;
+ Dprintk("... user-module index is: %d.\n", idx);
+
+ ret = -ENOMEM;
+ tcapi = (tcapi_template_t *) kmalloc(sizeof(*tcapi), GFP_KERNEL);
+ if (!tcapi)
+ goto out;
+ memset(tcapi, 0, sizeof(*tcapi));
+
+ tcapi->vfs_name = (char *) kmalloc(len, GFP_KERNEL);
+ if (!tcapi->vfs_name) {
+ kfree(tcapi);
+ goto out;
+ }
+ strcpy(tcapi->vfs_name, modulename);
+ tcapi->userspace_id = idx;
+
+ Dprintk("... registering module {%s}.\n", tcapi->vfs_name);
+ ret = register_httpmodule(tcapi);
+out:
+ return ret;
+}
+
+static int user_unregister_module (user_req_t *u_info)
+{
+ // FIXME: not here yet.
+ return -EINVAL;
+}
+
+asmlinkage int sys_http (unsigned int action, user_req_t *u_info)
+{
+ int ret;
+ threadinfo_t *ti;
+ http_req_t *req;
+
+ Dprintk("got sys_http(%d, %p).\n", action, u_info);
+
+ if (action >= MAX_HTTP_ACTION)
+ goto err_no_unlock;
+
+ ti = (threadinfo_t *) current->http_info;
+ if (ti)
+ if (ti->thread != current)
+ HTTP_BUG();
+
+ switch (action) {
+ case HTTP_ACTION_STARTUP:
+ lock_kernel();
+ ret = user_req_startup();
+ unlock_kernel();
+ goto out_no_unlock;
+
+ case HTTP_ACTION_SHUTDOWN:
+ lock_kernel();
+ ret = user_req_shutdown();
+ unlock_kernel();
+ goto out_no_unlock;
+
+ case HTTP_ACTION_REGISTER_MODULE:
+ ret = user_register_module(u_info);
+ goto out_no_unlock;
+
+ case HTTP_ACTION_UNREGISTER_MODULE:
+ ret = user_unregister_module(u_info);
+ goto out_no_unlock;
+
+ case HTTP_ACTION_STARTTHREAD:
+ {
+ int nr;
+
+ ret = copy_from_user(&nr, &u_info->thread_nr,
+ sizeof(int));
+ if (ret)
+ goto err_no_unlock;
+ if (nr >= nr_threads)
+ goto err_no_unlock;
+ ti = threadinfo + nr;
+ down(&ti->used);
+ if (ti->started)
+ goto err_unlock;
+ current->http_info = ti;
+ if (ti->thread)
+ HTTP_BUG();
+ lock_kernel();
+ ret = user_req_start_thread(ti);
+ unlock_kernel();
+ if (ret)
+ current->http_info = NULL;
+ else {
+ if (ti->thread != current)
+ HTTP_BUG();
+ }
+ goto out_unlock;
+ }
+
+ case HTTP_ACTION_STOPTHREAD:
+ if (!ti)
+ goto err_no_unlock;
+ down(&ti->used);
+ if (!ti->started)
+ goto err_unlock;
+ req = ti->userspace_req;
+ if (req) {
+ ti->userspace_req = NULL;
+ req->userspace_module = 0;
+ req->private = NULL;
+ DEC_STAT(nr_userspace_pending);
+ flush_request(req, ti);
+ }
+
+ lock_kernel();
+ ret = user_req_stop_thread(ti);
+ unlock_kernel();
+ goto out_unlock;
+
+ case HTTP_ACTION_CURRENT_DATE:
+ ret = strncpy_from_user(tux_date, u_info->new_date,
+ DATE_LEN);
+ if (ret <= 0)
+ goto err_no_unlock;
+ goto out_no_unlock;
+
+ default:
+ }
+
+ if (!ti)
+ goto err_no_unlock;
+ down(&ti->used);
+
+ if (!ti->started)
+ goto err_unlock;
+
+ req = ti->userspace_req;
+ if (!req) {
+ if (action == HTTP_ACTION_EVENTLOOP)
+ goto eventloop;
+ goto err_unlock;
+ }
+ if (!req->userspace_module)
+ HTTP_BUG();
+
+ ret = copy_from_user(&req->event, &u_info->event, sizeof(int));
+ if (ret)
+ goto out_unlock;
+ ret = copy_from_user(&req->http_status, &u_info->http_status, sizeof(int));
+ if (ret)
+ goto out_unlock;
+ ret = copy_from_user(&req->bytes_sent, &u_info->bytes_sent, sizeof(int));
+ if (ret)
+ goto out_unlock;
+ ret = copy_from_user(&req->private, &u_info->private, sizeof(req->private));
+ if (ret)
+ goto out_unlock;
+
+ switch (action) {
+
+ case HTTP_ACTION_EVENTLOOP:
+eventloop:
+ req = ti->userspace_req;
+ if (req) {
+ ti->userspace_req = NULL;
+ req->userspace_module = 0;
+ req->private = NULL;
+ DEC_STAT(nr_userspace_pending);
+ flush_request(req, ti);
+ }
+ ret = event_loop(ti);
+ goto out_unlock;
+
+ case HTTP_ACTION_FINISH_REQ:
+
+ ti->userspace_req = NULL;
+ req->userspace_module = 0;
+ req->private = NULL;
+ DEC_STAT(nr_userspace_pending);
+ flush_request(req, ti);
+ goto eventloop;
+ break;
+
+ case HTTP_ACTION_GET_OBJECT:
+ {
+ int missed;
+ urlobj_t *urlo;
+
+ check_req_list(req, NULL);
+ req->tmpbuf[MAX_URI_LEN-1] = 0;
+ req->objectname = req->tmpbuf;
+ ret = strncpy_from_user(req->objectname,
+ u_info->objectname, MAX_URI_LEN-1);
+ if (ret <= 0) {
+ req->objectname = NULL;
+ req->objectname_len = 0;
+ goto out_unlock;
+ }
+ req->objectname[ret] = 0; // string delimit
+ req->objectname_len = ret;
+
+ req->userspace_module = 0;
+ missed = lookup_urlo(req, LOOKUP_ATOMIC);
+ if (req->userspace_module)
+ HTTP_BUG();
+ req->userspace_module = 1;
+ urlo = req->urlo;
+ if ((!missed && !urlo) || (urlo && urlo->tcapi))
+ goto err_unlock;
+ if (missed || !urlo->csumc) {
+ ti->userspace_req = NULL;
+ DEC_STAT(nr_userspace_pending);
+ http_miss_req(req);
+ goto eventloop;
+ }
+ ret = HTTP_RETURN_USERSPACE_REQUEST;
+ break;
+ }
+
+ case HTTP_ACTION_READ_OBJECT:
+ {
+ char *addr;
+
+ if (!req->urlo)
+ goto err_unlock;
+ if (!req->urlo->csumc)
+ goto err_unlock;
+
+ ret = copy_from_user(&addr, &u_info->object_addr,
+ sizeof(addr));
+ if (ret)
+ goto out_unlock;
+ http_read(req->urlo, addr);
+ ret = HTTP_RETURN_USERSPACE_REQUEST;
+ break;
+ }
+
+ case HTTP_ACTION_SEND_OBJECT:
+ if (!req->urlo)
+ goto err_unlock;
+ if (!req->urlo->csumc)
+ goto err_unlock;
+ req->bytes_sent += http_send_object(req, 0, 1);
+ ret = HTTP_RETURN_USERSPACE_REQUEST;
+ break;
+
+ default:
+ HTTP_BUG();
+ }
+
+out_unlock:
+ if (ti->userspace_req)
+ ret = prepare_userspace_req(ti, u_info);
+ up(&ti->used);
+out_no_unlock:
+ Dprintk("sys_http(%d, %p) returning %d.\n", action, u_info, ret);
+ return ret;
+err_unlock:
+ up(&ti->used);
+err_no_unlock:
+ Dprintk("sys_http(%d, %p) returning -EINVAL!\n", action, u_info);
+ return -EINVAL;
+}
+
+/*
+ * This gets called if a TUX thread does an exit().
+ */
+void http_exit (void)
+{
+ sys_http(HTTP_ACTION_STOPTHREAD, NULL);
+}
+
+int __init http_init(void)
+{
+ start_sysctl();
+ init_cachemiss_threads();
+
+ return 0;
+}
+
+void http_cleanup (void)
+{
+ end_sysctl();
+}
+
+int init_module (void)
+{
+ return http_init();
+}
+
+int cleanup_module (void)
+{
+ http_cleanup();
+ return 0;
+}
+
+#define CHECK_LIST(l) \
+ if ((list != (l)) && !list_empty(l)) HTTP_BUG();
+#define CHECK_LIST2(l) \
+ if ((list == (l)) && list_empty(l)) HTTP_BUG();
+
+void __check_req_list (http_req_t *req, struct list_head *list)
+{
+ if (req->magic != HTTP_MAGIC)
+ HTTP_BUG();
+ if (!req->ti)
+ HTTP_BUG();
+ if (current->http_info && !in_interrupt()) {
+ threadinfo_t *ti = (threadinfo_t *) current->http_info;
+
+ if (ti != req->ti) {
+ printk("HTTP BUG: ti (%p,%d) != req->ti (%p,%d)!\n",
+ ti, ti-threadinfo, req->ti, req->ti-threadinfo);
+ HTTP_BUG();
+ }
+ if (ti->thread != current)
+ HTTP_BUG();
+ }
+ CHECK_LIST(&req->free);
+ CHECK_LIST2(&req->free);
+ CHECK_LIST(&req->input);
+ CHECK_LIST2(&req->input);
+ CHECK_LIST(&req->userspace);
+ CHECK_LIST2(&req->userspace);
+ CHECK_LIST(&req->cachemiss);
+ CHECK_LIST2(&req->cachemiss);
+ CHECK_LIST(&req->output);
+ CHECK_LIST2(&req->output);
+ CHECK_LIST(&req->redirect);
+ CHECK_LIST2(&req->redirect);
+ CHECK_LIST(&req->finish);
+ CHECK_LIST2(&req->finish);
+}
+
--- linux/net/http/extcgi.c.orig Fri Sep 1 07:28:26 2000
+++ linux/net/http/extcgi.c Fri Sep 1 07:28:26 2000
@@ -0,0 +1,379 @@
+/*
+ * TUX - Integrated HTTP layer and Object Cache
+ *
+ * Copyright (C) 2000, Ingo Molnar <
[email protected]>
+ *
+ * extcgi.c: dynamic HTTP module which forks and starts an external CGI
+ */
+
+#define __KERNEL_SYSCALLS__
+
+#include <net/http.h>
+#include "parser.h"
+
+//#undef Dprintk
+//#define Dprintk(x...) do { if (http_Dprintk) { printk("<%p>: ", req); printk(x); } } while (0)
+
+#define MAX_ENVLEN 1000
+#define NR_CGI_METAVARIABLES 13
+
+#define MAX_CGI_DATA 2048
+
+typedef struct CGI_reply_s {
+ char buf[MAX_CGI_DATA+1024];
+ char sendfile_name[128];
+ int len;
+ int sendfile_pos;
+ int error;
+} CGI_reply_t;
+
+#if 0
+#define PRINT_MESSAGE_LEFT \
+ Dprintk("CGI message left at %s:%d:\n--->{%s}<---\n", \
+ __FILE__, __LINE__, curr)
+#else
+#define PRINT_MESSAGE_LEFT do {} while(0)
+#endif
+
+#define GOTO_INCOMPLETE do { Dprintk("invalid CGI reply at %s:%d.\n", __FILE__, __LINE__); goto invalid; } while (0)
+
+int parse_cgi_headers (char *cgi_message, int len, http_req_t *req)
+{
+ urlobj_t *urlo;
+ CGI_reply_t *CGI_reply;
+ char *curr, *end, *reply, *tmp;
+ int sendfile_name_len = 0, sendfile_pos = 0;
+ int header_len = 0, body_len, created, ret = 0, http_len;
+
+ curr = cgi_message;
+ end = cgi_message + len;
+
+ PRINT_MESSAGE_LEFT;
+ CGI_reply = http_kmalloc(sizeof(*CGI_reply), ALLOC_REQ_PRIVATE);
+ memset(CGI_reply, 0, sizeof(*CGI_reply));
+ reply = CGI_reply->buf;
+
+#define CGI_SUCCESS "HTTP/1.1 200 OK\r\n"
+
+ memcpy(reply, CGI_SUCCESS, sizeof(CGI_SUCCESS)-1);
+ reply += sizeof(CGI_SUCCESS)-1;
+
+ while (*curr) {
+ switch (*curr) {
+
+ case 'C':
+
+#define CONTENT_TYPE "Content-Type: text/html"
+#define CONTENT_TYPE_CGI CONTENT_TYPE "\n"
+#define CONTENT_TYPE_HTTP CONTENT_TYPE "\r\n"
+
+ PRINT_MESSAGE_LEFT;
+ tmp = curr;
+ if (PARSE_TOKEN(curr, end, CONTENT_TYPE_CGI)) {
+ memcpy(reply, CONTENT_TYPE_HTTP, sizeof(CONTENT_TYPE_HTTP)-1);
+ reply += sizeof(CONTENT_TYPE_HTTP)-1;
+ PRINT_MESSAGE_LEFT;
+ continue;
+ }
+ GOTO_INCOMPLETE;
+
+ case 'X':
+
+#define HTTP_SENDFILE "X-CGI-TUX-sendfile: "
+
+ PRINT_MESSAGE_LEFT;
+ if (PARSE_TOKEN(curr, end, HTTP_SENDFILE)) {
+ tmp = CGI_reply->sendfile_name;
+ COPY_FIELD(tmp);
+ *tmp = 0;
+ sendfile_name_len = tmp-CGI_reply->sendfile_name;
+
+ curr++;
+ PRINT_MESSAGE_LEFT;
+ sendfile_pos = simple_strtoul(curr, &curr, 10);
+ if (get_c(curr) != '\n')
+ GOTO_INCOMPLETE;
+ PRINT_MESSAGE_LEFT;
+ Dprintk("got X-sendfile(%s (%d), %d)\n", CGI_reply->sendfile_name, sendfile_name_len, sendfile_pos);
+ curr++;
+ PRINT_MESSAGE_LEFT;
+ continue;
+ }
+ GOTO_INCOMPLETE;
+ case '\n':
+ curr++;
+ PRINT_MESSAGE_LEFT;
+ goto headers_finished;
+
+ default:
+ GOTO_INCOMPLETE;
+ }
+ }
+ GOTO_INCOMPLETE;
+headers_finished:
+ Dprintk("got valid CGI headers!\n");
+ PRINT_MESSAGE_LEFT;
+
+ /*
+ * First load the urlo - we need to know the length
+ * of the file to be sent. But we start the (potential)
+ * cachemiss only after we have created the headers!
+ */
+ req->objectname = CGI_reply->sendfile_name;
+ req->objectname_len = sendfile_name_len;
+
+ created = lookup_urlo(req, LOOKUP_ATOMIC);
+ if (req->userspace_module)
+ HTTP_BUG();
+ urlo = req->urlo;
+ Dprintk("extcgi: got urlo: %p.\n", urlo);
+ if (!urlo || urlo->tcapi || (req->method != METHOD_GET))
+ GOTO_INCOMPLETE;
+
+ /*
+ * Create Content-Length reply field and close the header:
+ */
+ body_len = end-curr;
+ http_len = urlo->filelen + body_len;
+ req->bytes_sent = http_len;
+
+#define CONTENT_LENGTH_HTTP "Content-Length: %d\r\n"
+ reply += sprintf(reply, CONTENT_LENGTH_HTTP, http_len);
+ *reply++ = '\r';
+ *reply++ = '\n';
+
+ header_len = reply - CGI_reply->buf;
+
+ /*
+ * The rest of the user-CGI reply is part of the HTTP body.
+ */
+ memcpy(reply, curr, body_len);
+ reply += body_len;
+
+ if (sendfile_pos > body_len)
+ sendfile_pos = body_len;
+ CGI_reply->sendfile_pos = header_len + sendfile_pos;
+ CGI_reply->len = body_len + header_len;
+ if (reply - CGI_reply->buf != CGI_reply->len)
+ GOTO_INCOMPLETE;
+
+ req->private = CGI_reply;
+
+ /*
+ * Now start the cachemiss or queue for output.
+ */
+ if (!urlo->csumc)
+ ret = http_miss_req(req);
+ else {
+ if (req->redirect_secondary)
+ HTTP_BUG();
+ queue_output_req(req, req->ti);
+ }
+
+ return ret;
+
+invalid:
+ CGI_reply->error = 1;
+ queue_output_req(req, req->ti);
+ return -1;
+}
+
+
+#define CGI_SUCCESS2 "HTTP/1.1 200 OK\r\nConnection: close\r\n"
+
+static int handle_cgi_reply (http_req_t *req, int *pipe_fds)
+{
+ int first = 1;
+ int len, left, total;
+ char buf [MAX_CGI_DATA+1], *tmp;
+ mm_segment_t oldmm;
+
+ close(pipe_fds[1]);
+ send_dynamic_reply(NULL, req->sock, CGI_SUCCESS2, sizeof(CGI_SUCCESS2)-1, 0);
+
+ req->bytes_sent = 0;
+ /*
+ * The new process is the new owner of the socket, it will
+ * close it.
+ */
+repeat:
+ left = MAX_CGI_DATA;
+ len = 0;
+ total = 0;
+ tmp = buf;
+ do {
+ tmp += len;
+ total += len;
+ left -= len;
+ if (!left)
+ break;
+repeat_read:
+ Dprintk("reading %d bytes from sys_read().\n", left);
+ oldmm = get_fs(); set_fs(KERNEL_DS);
+ len = sys_read(pipe_fds[0], tmp, left);
+ set_fs(oldmm);
+ Dprintk("got %d bytes from sys_read() (total: %d).\n", len, total);
+ if (len > 0)
+ tmp[len] = 0;
+ Dprintk("CGI reply: (%d bytes, total %d).\n", len, total);
+ if (len == -512) {
+ reap_kids();
+ goto repeat_read;
+ }
+ } while (len > 0);
+ if (total > MAX_CGI_DATA)
+ HTTP_BUG();
+ if (total) {
+ if (!len)
+ send_dynamic_reply(NULL, req->sock, buf, total, 1);
+ else
+ send_dynamic_reply(NULL, req->sock, buf, total, 0);
+ req->bytes_sent += total;
+ }
+
+ Dprintk("bytes_sent: %d\n", req->bytes_sent);
+ if ((total > 0) && first) {
+ first = 0;
+
+// Dprintk("looking for enter/enter in:{%s}\n", buf);
+ if (buf[total])
+ HTTP_BUG();
+ tmp = strstr(buf, "\n\n");
+ if (tmp) {
+// Dprintk("found enter/enter at: {%s}\n", tmp);
+ req->bytes_sent -= (tmp-buf) + 2;
+ Dprintk("new bytes_sent: %d\n", req->bytes_sent);
+ } else {
+ printk("huh 001?\n");
+ }
+ }
+ if (len < 0)
+ Dprintk("sys_read returned with %d.\n", len);
+ else {
+ if ((total == MAX_CGI_DATA) && len)
+ goto repeat;
+ }
+ close(pipe_fds[0]);
+
+ req->http_status = 200;
+ queue_output_req(req, req->ti);
+ return -1;
+}
+
+static int exec_external_cgi (void *data)
+{
+ exec_param_t param;
+ http_req_t *req = data;
+ char *envp[NR_CGI_METAVARIABLES+1], **envp_p;
+ char *argv[] = { "/tmp/mingo", NULL};
+ char envstr[MAX_ENVLEN], *tmp;
+ unsigned int host;
+ int pipe_fds[2], len;
+ char command [100]; // FIXME: crash, exploit.
+
+ current->flags &= ~PF_ATOMICALLOC;
+ current->http = 0;
+ sprintf(current->comm,"cgimain - %i", current->pid);
+#define IP(x) (((unsigned char *)&host)[x])
+ host = req->sock->sk->daddr;
+
+ tmp = envstr;
+ envp_p = envp;
+
+#define WRITE_ENV(str...) \
+ if (envp_p > envp + NR_CGI_METAVARIABLES) \
+ HTTP_BUG(); \
+ len = sprintf(tmp, str); \
+ *envp_p++ = tmp; \
+ tmp += len + 1; \
+ if (tmp >= envstr + MAX_ENVLEN) \
+ HTTP_BUG();
+
+ WRITE_ENV("CONTENT_LENGTH=0");
+ WRITE_ENV("CONTENT_TYPE=html/text");
+ WRITE_ENV("DOCUMENT_ROOT=%s", http_docroot);
+ WRITE_ENV("GATEWAY_INTERFACE=1.1");
+ WRITE_ENV("PATH_INFO=%s", http_docroot);
+ WRITE_ENV("QUERY_STRING=%s", req->query);
+ WRITE_ENV("REMOTE_ADDR=%d.%d.%d.%d", IP(0), IP(1), IP(2), IP(3));
+ WRITE_ENV("REQUEST_METHOD=GET");
+ WRITE_ENV("SCRIPT_NAME=%s", req->objectname);
+ WRITE_ENV("SERVER_NAME=mg");
+ WRITE_ENV("SERVER_PORT=80");
+ WRITE_ENV("SERVER_PROTOCOL=HTTP/1.1");
+ WRITE_ENV("SERVER_SOFTWARE=TUX 1.0");
+ *envp_p = NULL;
+
+ sys_close(0);
+ sys_close(1);
+ pipe_fds[0] = -1;
+ pipe_fds[1] = -1;
+ if (do_pipe(pipe_fds))
+ HTTP_BUG();
+ if (pipe_fds[0] != 0)
+ HTTP_BUG();
+ if (pipe_fds[1] != 1)
+ HTTP_BUG();
+ sprintf(command, "/%s/cgi-bin/%s", http_docroot, req->objectname);
+ http_exec_process(command, argv, envp, pipe_fds, ¶m, 0);
+
+ return handle_cgi_reply(req, pipe_fds);
+}
+
+void start_external_cgi (http_req_t *req)
+{
+ int pid;
+
+repeat:
+ pid = kernel_thread(exec_external_cgi, (void*) req, SIGCHLD);
+ if (pid < 0) {
+ printk("HTTP: Could not fork external CGI process due to %d, retrying!\n", pid);
+ schedule_timeout(2);
+ goto repeat;
+ }
+}
+
+int query_extcgi (http_req_t *req)
+{
+ req->keep_alive = 0;
+ start_external_cgi(req);
+ return -1;
+}
+
+#define EXTCGI_INVALID_HEADER \
+ "HTTP/1.1 503 Service Unavailable\r\n" \
+ "Server: TUX 1.0\r\n" \
+ "Content-Length: 23\r\n\r\n"
+
+#define EXTCGI_INVALID_BODY \
+ "TUX: invalid CGI reply."
+
+#define EXTCGI_INVALID EXTCGI_INVALID_HEADER EXTCGI_INVALID_BODY
+
+int send_reply_extcgi (http_req_t *req)
+{
+ return 0;
+}
+
+tcapi_template_t extcgi_tcapi = {
+ vfs_name: "x",
+ version: HTTP_VERSION,
+ query: query_extcgi,
+ send_reply: send_reply_extcgi,
+};
+
+int extcgi_start (void)
+{
+ extcgi_tcapi.mod = THIS_MODULE;
+
+ return register_httpmodule(&extcgi_tcapi);
+}
+
+void extcgi_stop (void)
+{
+ unregister_httpmodule(&extcgi_tcapi);
+}
+
+module_init(extcgi_start)
+module_exit(extcgi_stop)
+
--- linux/net/http/parser.h.orig Fri Sep 1 07:28:26 2000
+++ linux/net/http/parser.h Fri Sep 1 07:28:26 2000
@@ -0,0 +1,80 @@
+/*
+ * TUX - Integrated HTTP layer and Object Cache
+ *
+ * Copyright (C) 2000, Ingo Molnar <
[email protected]>
+ *
+ * parser.h: generic parsing routines
+ */
+
+#define get_c(ptr) \
+({ \
+ unsigned char __ret = *(ptr); \
+ \
+ if (__ret == '\r') { \
+ unsigned char __next = *((ptr)+1); \
+ \
+ if (__next == '\n' || !__next) { \
+ __ret = __next; \
+ (ptr)++; \
+ } \
+ } \
+ __ret; \
+})
+
+#define PARSE_TOKEN(ptr,end,str) \
+ ({ \
+ int __ret; \
+ \
+ if (ptr + sizeof(str)-1 > end) \
+ GOTO_INCOMPLETE; \
+ \
+ if (memcmp(ptr, str, sizeof(str)-1)) \
+ __ret = 0; \
+ else { \
+ ptr += sizeof(str)-1; \
+ __ret = 1; \
+ } \
+ __ret; \
+ })
+
+#define PARSE_METHOD(req,ptr,end,name) \
+ ({ \
+ int __ret; \
+ \
+ if (PARSE_TOKEN(ptr,end,#name" ")) { \
+ req->method = METHOD_##name; \
+ __ret = 1; \
+ } else \
+ __ret = 0; \
+ __ret; \
+ })
+
+#define COPY_LINE(target) \
+ do { \
+ while (get_c(curr) != '\n') { \
+ if (!*curr) \
+ GOTO_INCOMPLETE; \
+ *target++ = *curr; \
+ curr++; \
+ } \
+ } while (0)
+
+#define COPY_FIELD(target) \
+ do { \
+ while (get_c(curr) != ' ') { \
+ if (!*curr) \
+ GOTO_INCOMPLETE; \
+ *target++ = *curr; \
+ curr++; \
+ } \
+ } while (0)
+
+#define SKIP_LINE \
+ do { \
+ while (get_c(curr) != '\n') { \
+ if (!*curr) \
+ GOTO_INCOMPLETE; \
+ curr++; \
+ } \
+ } while (0)
+
--- linux/net/http/proc.c.orig Fri Sep 1 07:28:26 2000
+++ linux/net/http/proc.c Fri Sep 1 07:28:26 2000
@@ -0,0 +1,445 @@
+/*
+ * TUX - Integrated HTTP layer and Object Cache
+ *
+ * Copyright (C) 2000, Ingo Molnar <
[email protected]>
+ *
+ * sysctl.c: /proc/sysctl/http handling
+ */
+
+#include <net/http.h>
+
+char http_docroot[200] = "/var/www/http/";
+char http_logfile[200] = "/var/log/http";
+int http_stop = 0;
+int http_start = 0;
+int http_unload = 0;
+int http_clientport = 8080;
+int http_logging = 0;
+extern int http_Dprintk;
+int http_serverport= 80;
+int http_threads = 2;
+int http_max_connect = 10000;
+int http_max_backlog = 2048;
+int http_keepalive_timeout = 0;
+int http_max_cached_filesize = 100000;
+int http_mode_forbidden = 0 /*S_IXUGO*/; /* do not allow executable (CGI) files */
+int http_mode_allowed = S_IROTH; /* allow access if read-other is set */
+int http_mode_userspace = S_IXUSR;
+int http_mode_cgi = S_IXUGO;
+extern int http_in_packet_delay;
+extern int http_out_packet_delay;
+int multifragment_api = 1;
+
+static struct ctl_table_header *http_table_header;
+
+static ctl_table http_table[] = {
+ { NET_HTTP_DOCROOT,
+ "documentroot",
+ &http_docroot,
+ sizeof(http_docroot),
+ 0644,
+ NULL,
+ proc_dostring,
+ &sysctl_string,
+ NULL,
+ NULL,
+ NULL
+ },
+ { NET_HTTP_LOGFILE,
+ "logfile",
+ &http_logfile,
+ sizeof(http_logfile),
+ 0644,
+ NULL,
+ proc_dostring,
+ &sysctl_string,
+ NULL,
+ NULL,
+ NULL
+ },
+ { NET_HTTP_STOP,
+ "stop",
+ &http_stop,
+ sizeof(int),
+ 0644,
+ NULL,
+ proc_dointvec,
+ &sysctl_intvec,
+ NULL,
+ NULL,
+ NULL
+ },
+ { NET_HTTP_START,
+ "start",
+ &http_start,
+ sizeof(int),
+ 0644,
+ NULL,
+ proc_dointvec,
+ &sysctl_intvec,
+ NULL,
+ NULL,
+ NULL
+ },
+ { NET_HTTP_UNLOAD,
+ "unload",
+ &http_unload,
+ sizeof(int),
+ 0644,
+ NULL,
+ proc_dointvec,
+ &sysctl_intvec,
+ NULL,
+ NULL,
+ NULL
+ },
+ { NET_HTTP_THREADS,
+ "threads",
+ &http_threads,
+ sizeof(int),
+ 0644,
+ NULL,
+ proc_dointvec,
+ &sysctl_intvec,
+ NULL,
+ NULL,
+ NULL
+ },
+ { NET_HTTP_KEEPALIVE_TIMEOUT,
+ "keepalive_timeout",
+ &http_keepalive_timeout,
+ sizeof(int),
+ 0644,
+ NULL,
+ proc_dointvec,
+ &sysctl_intvec,
+ NULL,
+ NULL,
+ NULL
+ },
+ { NET_HTTP_MAX_BACKLOG,
+ "max_backlog",
+ &http_max_backlog,
+ sizeof(int),
+ 0644,
+ NULL,
+ proc_dointvec,
+ &sysctl_intvec,
+ NULL,
+ NULL,
+ NULL
+ },
+ { NET_HTTP_MAX_CONNECT,
+ "max_connect",
+ &http_max_connect,
+ sizeof(int),
+ 0644,
+ NULL,
+ proc_dointvec,
+ &sysctl_intvec,
+ NULL,
+ NULL,
+ NULL
+ },
+ { NET_HTTP_MAX_CACHED_FILESIZE,
+ "max_cached_filesize",
+ &http_max_cached_filesize,
+ sizeof(int),
+ 0644,
+ NULL,
+ proc_dointvec,
+ &sysctl_intvec,
+ NULL,
+ NULL,
+ NULL
+ },
+ { NET_HTTP_MODE_FORBIDDEN,
+ "mode_forbidden",
+ &http_mode_forbidden,
+ sizeof(int),
+ 0644,
+ NULL,
+ proc_dointvec,
+ &sysctl_intvec,
+ NULL,
+ NULL,
+ NULL
+ },
+ { NET_HTTP_MODE_ALLOWED,
+ "mode_allowed",
+ &http_mode_allowed,
+ sizeof(int),
+ 0644,
+ NULL,
+ proc_dointvec,
+ &sysctl_intvec,
+ NULL,
+ NULL,
+ NULL
+ },
+ { NET_HTTP_MODE_USERSPACE,
+ "mode_userspace",
+ &http_mode_userspace,
+ sizeof(int),
+ 0644,
+ NULL,
+ proc_dointvec,
+ &sysctl_intvec,
+ NULL,
+ NULL,
+ NULL
+ },
+ { NET_HTTP_MODE_CGI,
+ "mode_cgi",
+ &http_mode_cgi,
+ sizeof(int),
+ 0644,
+ NULL,
+ proc_dointvec,
+ &sysctl_intvec,
+ NULL,
+ NULL,
+ NULL
+ },
+ { NET_HTTP_CLIENTPORT,
+ "clientport",
+ &http_clientport,
+ sizeof(int),
+ 0644,
+ NULL,
+ proc_dointvec,
+ &sysctl_intvec,
+ NULL,
+ NULL,
+ NULL
+ },
+ { NET_HTTP_LOGGING,
+ "Dprintk",
+ &http_Dprintk,
+ sizeof(int),
+ 0644,
+ NULL,
+ proc_dointvec,
+ &sysctl_intvec,
+ NULL,
+ NULL,
+ NULL
+ },
+ { NET_HTTP_LOGGING,
+ "logging",
+ &http_logging,
+ sizeof(int),
+ 0644,
+ NULL,
+ proc_dointvec,
+ &sysctl_intvec,
+ NULL,
+ NULL,
+ NULL
+ },
+ { NET_HTTP_SERVERPORT,
+ "serverport",
+ &http_serverport,
+ sizeof(int),
+ 0644,
+ NULL,
+ proc_dointvec,
+ &sysctl_intvec,
+ NULL,
+ NULL,
+ NULL
+ },
+ { NET_HTTP_LOGENTRY_ALIGN_ORDER,
+ "logentry_align_order",
+ &http_logentry_align_order,
+ sizeof(int),
+ 0644,
+ NULL,
+ proc_dointvec,
+ &sysctl_intvec,
+ NULL,
+ NULL,
+ NULL
+ },
+ { NET_HTTP_NAGLE,
+ "nagle",
+ &http_nagle,
+ sizeof(int),
+ 0644,
+ NULL,
+ proc_dointvec,
+ &sysctl_intvec,
+ NULL,
+ NULL,
+ NULL
+ },
+ { NET_HTTP_NEW_API,
+ "multifragment_api",
+ &multifragment_api,
+ sizeof(int),
+ 0644,
+ NULL,
+ proc_dointvec,
+ &sysctl_intvec,
+ NULL,
+ NULL,
+ NULL
+ },
+ { NET_HTTP_IN_PACKET_DELAY,
+ "in_packet_delay",
+ &http_in_packet_delay,
+ sizeof(int),
+ 0644,
+ NULL,
+ proc_dointvec,
+ &sysctl_intvec,
+ NULL,
+ NULL,
+ NULL
+ },
+ { NET_HTTP_OUT_PACKET_DELAY,
+ "out_packet_delay",
+ &http_out_packet_delay,
+ sizeof(int),
+ 0644,
+ NULL,
+ proc_dointvec,
+ &sysctl_intvec,
+ NULL,
+ NULL,
+ NULL
+ },
+ {0,0,0,0,0,0,0,0,0,0,0} };
+
+
+static ctl_table http_dir_table[] = {
+ {NET_HTTP, "http", NULL, 0, 0555, http_table,0,0,0,0,0},
+ {0,0,0,0,0,0,0,0,0,0,0}
+};
+
+static ctl_table http_root_table[] = {
+ {CTL_NET, "net", NULL, 0, 0555, http_dir_table,0,0,0,0,0},
+ {0,0,0,0,0,0,0,0,0,0,0}
+};
+
+static void init_http_proc (void);
+
+void start_sysctl(void)
+{
+ init_http_proc();
+ http_table_header = register_sysctl_table(http_root_table,1);
+}
+
+
+void end_sysctl(void)
+{
+ unregister_sysctl_table(http_table_header);
+}
+
+static struct proc_dir_entry * root_http_dir;
+static struct proc_dir_entry * http_dir [CONFIG_HTTP_NUMTHREADS];
+static struct proc_dir_entry * listen_dir [CONFIG_HTTP_NUMTHREADS];
+static struct proc_dir_entry * listen_entries [CONFIG_HTTP_NUMTHREADS][CONFIG_HTTP_NUMSOCKETS];
+
+unsigned int http_listen [CONFIG_HTTP_NUMTHREADS][CONFIG_HTTP_NUMSOCKETS] =
+ { [0 ... CONFIG_HTTP_NUMTHREADS-1] = { 0, [1 ... CONFIG_HTTP_NUMSOCKETS-1] = -1 } };
+
+#define HEX_DIGITS 8
+
+static int http_listen_read_proc (char *page, char **start, off_t off,
+ int count, int *eof, void *data)
+{
+ if (count < HEX_DIGITS+1)
+ return -EINVAL;
+ return sprintf (page, "%08x\n", *(unsigned int *)data);
+}
+
+static int http_listen_write_proc (struct file *file, const char *buffer,
+ unsigned long count, void *data)
+{
+ unsigned char hexnum [HEX_DIGITS];
+ unsigned int new_value;
+ int i, full_count = count;
+
+ if (!count)
+ return -EINVAL;
+ if (count > HEX_DIGITS)
+ count = HEX_DIGITS;
+ if (copy_from_user(hexnum, buffer, count))
+ return -EFAULT;
+
+ /*
+ * Parse the first 8 characters as a hex string, any non-hex char
+ * is end-of-string. '00e1', 'e1', '00E1', 'E1' are the same.
+ */
+ new_value = 0;
+
+ for (i = 0; i < count; i++) {
+ unsigned int c = hexnum[i];
+
+ switch (c) {
+ case '0' ... '9': c -= '0'; break;
+ case 'a' ... 'f': c -= 'a'-10; break;
+ case 'A' ... 'F': c -= 'A'-10; break;
+ default:
+ goto out;
+ }
+ new_value = (new_value << 4) | c;
+ }
+out:
+ *(int *)data = new_value;
+
+ return full_count;
+}
+
+#define MAX_NAMELEN 10
+
+static void register_http_proc (unsigned int nr)
+{
+ struct proc_dir_entry *entry;
+ char name [MAX_NAMELEN];
+ int i;
+
+ if (!root_http_dir)
+ HTTP_BUG();
+
+ memset(name, 0, MAX_NAMELEN);
+ sprintf(name, "%d", nr);
+
+ /* create /proc/net/http/1234/ */
+ http_dir[nr] = proc_mkdir(name, root_http_dir);
+
+ /* create /proc/net/http/1234/listen/ */
+ listen_dir[nr] = proc_mkdir("listen", http_dir[nr]);
+
+ /* create /proc/net/http/1234/listen/ */
+ for (i = 0; i < CONFIG_HTTP_NUMSOCKETS; i++) {
+ sprintf(name, "%d", i);
+ entry = create_proc_entry(name, 0700, listen_dir[nr]);
+
+ entry->nlink = 1;
+ entry->data = (void *)&http_listen[nr][i];
+ entry->read_proc = http_listen_read_proc;
+ entry->write_proc = http_listen_write_proc;
+
+ listen_entries[nr][i] = entry;
+ }
+}
+
+static void init_http_proc (void)
+{
+ int i;
+
+ if (root_http_dir)
+ return;
+
+ /* create /proc/net/http */
+ root_http_dir = proc_mkdir("http", proc_net);
+
+ /*
+ * Create entries for all existing threads.
+ */
+ for (i = 0; i < CONFIG_HTTP_NUMTHREADS; i++)
+ register_http_proc(i);
+}
+
--- linux/net/http/CAD2.c.orig Fri Sep 1 07:28:26 2000
+++ linux/net/http/CAD2.c Fri Sep 1 07:28:26 2000
@@ -0,0 +1,907 @@
+/*
+ * TUX - Integrated HTTP layer and Object Cache
+ *
+ * Copyright (C) 2000, Ingo Molnar <
[email protected]>
+ *
+ * CAD.c: Implementation of the SPECweb99 CAD dynamic application via
+ * the HTTP trusted-module.
+ */
+
+#include <net/http.h>
+
+static int send_reply_head (http_req_t *req, size_t body_size);
+static int send_reply_tail (http_req_t *req);
+static int send_err (http_req_t *req, char *message);
+
+static HTTP_DECLARE_MUTEX(postlog_sem);
+#define POSTLOG "/tmp/postlog"
+static struct http_file *post_file;
+static int postlog_count;
+static char *postlog_head;
+static struct http_page *postlog_head_page;
+
+#define CAD_TAG_HEAD "<!WEB99CAD><IMG SRC=\"/file_set/"
+#define CAD_TAG_BODY "dirNNNNN/classX_Y"
+#define CAD_TAG_TAIL "\"><!/WEB99CAD>"
+
+#define CAD_TAG CAD_TAG_HEAD CAD_TAG_BODY CAD_TAG_TAIL
+
+#define CAD_TAG_BODY_POS (sizeof(CAD_TAG_HEAD)-1)
+#define CAD_TAG_BODY_SIZE (sizeof(CAD_TAG_BODY)-1)
+#define CAD_TAG_SIZE (sizeof(CAD_TAG)-1)
+
+typedef struct CAD_struct {
+ int user_id;
+ int last_ad;
+ char ad_filename [100];
+ int reply_cookies_len;
+ char reply_cookies[MAX_COOKIE_LEN];
+} CAD_t;
+
+/*
+ * Called by the generic SSI (Server Side Include) engine to generate
+ * custom server-side include 'regions' (fragments) from the template.
+ * The object's content (the template) is passed via 'buf', the SSI
+ * descriptor table is filled out by this function. (can be left empty
+ * as well to indicate no changes.)
+ */
+static void create_SSI_map_CAD (http_req_t *req, csumcache_t *csumc, unsigned char *buf, int len, SSImap_t *SSImap)
+{
+ unsigned char *target = buf, *tmp;
+
+ /*
+ * First the dynamic API determines wether this object is
+ * a server-side-include file belonging to it's domain.
+ * (Multiple modules using the same SSI-file are supported
+ * as well.) A module does not want to generate a SSI map
+ * for every object, obviously. (Other modules might want
+ * to parse for .shmtl extension in the filename - but the
+ * TUX SSI engine does not mandate this.)
+ */
+ SSImap->nr = 0;
+ if (!req->query)
+ return;
+ req->urlo->SSI = 1;
+ tmp = strstr(req->query, "class");
+ if (tmp) {
+ tmp += sizeof("class")-1;
+ if ((tmp[0] != '1') && (tmp[0] != '2'))
+ return;
+ }
+ for (;;) {
+ int pos;
+
+ target = strstr(target, CAD_TAG);
+ if (!target)
+ break;
+ pos = target-buf + CAD_TAG_BODY_POS;
+ target += CAD_TAG_SIZE;
+
+
+ SSImap->pos[SSImap->nr] = pos;
+ SSImap->size[SSImap->nr] = CAD_TAG_BODY_SIZE;
+ SSImap->nr++;
+ }
+}
+
+
+typedef struct user_dem_s {
+ unsigned int dem;
+} user_dem_t;
+
+static int max_userid;
+static user_dem_t *user_dem = NULL;
+static struct http_direntry *user_pers_dentry;
+
+#define USER_PERS_FILE "User.Personality"
+#define USER_PERS_RECLEN 15
+
+typedef struct ad_s {
+ unsigned int dem;
+ unsigned int gender_weight;
+ unsigned int age_weight;
+ unsigned int region_weight;
+ unsigned int interest_1_weight;
+ unsigned int interest_2_weight;
+ unsigned int min_match;
+ unsigned int expires;
+} ad_t;
+
+static int max_adid;
+static ad_t *ad = NULL;
+
+#define AD_FILE "Custom.Ads"
+#define AD_RECLEN 39
+
+static int read_custom_ads (http_req_t *req)
+{
+ struct http_file *file;
+ int ret, len, err = -2;
+ char *buf = NULL, *tmp;
+ struct http_direntry *dentry;
+ unsigned int adid, i, dem, min_match, weight, expires;
+
+
+ dentry = http_lookup_direntry(AD_FILE, &docroot, 0);
+ if (http_direntry_error(dentry))
+ goto error;
+ file = http_direntry_open(dentry, O_RDONLY, 0);
+ if (!file)
+ goto error;
+ len = http_file_size(file);
+ if (!len)
+ goto error;
+ if (ad) {
+ http_free(ad, ALLOC_AD_FILE);
+ ad = NULL;
+ }
+ max_adid = len/AD_RECLEN + 1;
+ ad = http_malloc(max_adid * sizeof(ad_t), ALLOC_AD_FILE);
+ buf = http_malloc(len, ALLOC_ADTMPBUF);
+ if (!ad || !buf)
+ goto error;
+
+ ret = http_write_file(file, buf, len);
+ http_close_file(file);
+ if (ret <= 0)
+ goto error;
+
+/*
+ * Sample ad record:
+ " 54 24808100 97F61 75 952393980\n"
+ */
+
+ tmp = buf;
+ i = 0;
+ for (tmp = buf; tmp != buf+len; tmp++) {
+
+ while (*tmp == ' ') tmp++;
+ adid = simple_strtoul(tmp, &tmp, 10);
+ if (adid != i)
+ goto error;
+ if (adid >= max_adid)
+ goto error;
+ i++;
+ if (*tmp != ' ')
+ goto error;
+ tmp++;
+ while (*tmp == ' ') tmp++;
+ dem = simple_strtoul(tmp, &tmp, 16);
+ tmp++;
+ while (*tmp == ' ') tmp++;
+ weight = simple_strtoul(tmp, &tmp, 16);
+ while (*tmp == ' ') tmp++;
+ min_match = simple_strtoul(tmp, &tmp, 10);
+ while (*tmp == ' ') tmp++;
+ expires = simple_strtoul(tmp, &tmp, 10);
+ if (*tmp != '\n')
+ goto error;
+ ad[adid].dem = dem;
+
+ ad[adid].gender_weight = (weight & 0x000f0000) >> 16;
+ ad[adid].age_weight = (weight & 0x0000f000) >> 12;
+ ad[adid].region_weight = (weight & 0x00000f00) >> 8;
+ ad[adid].interest_1_weight = (weight & 0x000000f0) >> 4;
+ ad[adid].interest_2_weight = (weight & 0x0000000f);
+
+ ad[adid].min_match = min_match;
+ ad[adid].expires = expires;
+
+ }
+ err = 0;
+error:
+ if (buf)
+ http_free(buf, ALLOC_ADTMPBUF);
+ if (err)
+ return send_err(req, "CAD: error while reading & parsing the ad file.\n");
+ return err;
+}
+
+static int read_user_personality (http_req_t *req)
+{
+ struct http_file *file;
+ int ret, len, err = -2;
+ char *buf = NULL, *tmp;
+ unsigned int uid, i, dem;
+ struct http_direntry *dentry;
+
+ dentry = http_lookup(USER_PERS_FILE, &docroot, 0);
+ file = http_direntry_open(dentry, O_RDONLY, 0);
+ if (!file)
+ goto error;
+ len = http_file_size(file);
+ if (!len)
+ goto error;
+ if (user_dem) {
+ http_free(user_dem, ALLOC_USERDEM);
+ user_dem = NULL;
+ }
+ max_userid = len/USER_PERS_RECLEN + 1;
+ user_dem = http_malloc(max_userid * sizeof(user_dem_t), ALLOC_USERDEM);
+ buf = http_malloc(len, ALLOC_USERDEM_TMPBUF);
+ if (!user_dem || !buf)
+ goto error;
+
+ ret = http_read_file(file, buf, len);
+ fput(file);
+ if (ret <= 0)
+ goto error;
+
+ tmp = buf;
+ i = 0;
+ for (tmp = buf; tmp != buf+len; tmp++) {
+ if (*tmp == ' ')
+ continue;
+ uid = simple_strtoul(tmp, &tmp, 10);
+ if (uid != i)
+ goto error;
+ if (uid >= max_userid)
+ goto error;
+ i++;
+ if (*tmp != ' ')
+ goto error;
+ while (*tmp == ' ') tmp++;
+ dem = simple_strtoul(tmp, &tmp, 16);
+ if (*tmp != '\n')
+ goto error;
+ user_dem[uid].dem = dem;
+ }
+ err = 0;
+error:
+ if (buf)
+ http_free(buf, ALLOC_USERDEM_TMPBUF);
+ if (err)
+ return send_err(req, "CAD: error while reading & parsing the user file.\n");
+ return err;
+}
+
+#define MAX_CUSTOM_ADS 360
+
+static int find_ad (int user_id, int last_ad, int *weight_p)
+{
+ int adid, weight = 0, dem;
+
+ for (adid = last_ad + 1; adid != last_ad; adid++) {
+ if (adid >= MAX_CUSTOM_ADS)
+ adid = 0;
+
+ dem = user_dem[user_id].dem & ad[adid].dem;
+ weight = 0;
+
+ if (dem & 0x30000000)
+ weight += ad[adid].gender_weight;
+ if (dem & 0x0f000000)
+ weight += ad[adid].age_weight;
+ if (dem & 0x00f00000)
+ weight += ad[adid].region_weight;
+ if (dem & 0x000ffc00)
+ weight += ad[adid].interest_1_weight;
+ if (dem & 0x000003ff)
+ weight += ad[adid].interest_2_weight;
+ if (weight >= ad[adid].min_match)
+ break;
+ }
+
+ *weight_p = weight;
+ return adid;
+}
+
+static unsigned int last_mtime = 0;
+
+static int reread_files (http_req_t *req)
+{
+ int ret = -2;
+ struct http_direntry *dentry;
+
+ http_dput(user_pers_dentry);
+ dentry = http_lookup(USER_PERS_FILE, &docroot, 0);
+ if (http_direntry_error(dentry))
+ goto error;
+ user_pers_dentry = dentry;
+
+ if (http_mtime(dentry) != last_mtime) {
+ void *tmp = user_dem;
+ user_dem = NULL;
+ http_free(tmp, ALLOC_USERDEM);
+ if (read_user_personality(req))
+ goto error;
+ if (read_custom_ads(req))
+ goto error;
+ last_mtime = http_mtime(dentry);
+ }
+ ret = 0;
+
+error:
+ return ret;
+}
+
+static int custom_ad_rotate (http_req_t *req, CAD_t *CADp)
+{
+ int adid, weight, expired, err;
+ int user_id, last_ad;
+ time_t now;
+
+ user_id = CADp->user_id;
+ last_ad = CADp->last_ad;
+
+ if (http_direntry_error(user_pers_dentry) ||
+ (http_mtime(user_pers_dentry) != last_mtime)) {
+ err = reread_files(req);
+ if (err)
+ return err;
+ }
+
+ /*
+ * Any error in either reading or parsing of the files results
+ * in a returned -1 adid.
+ */
+ adid = -1;
+ expired = 1;
+ weight = 0;
+
+ adid = find_ad(user_id, last_ad, &weight);
+ if (adid < 0)
+ goto error;
+ now = http_time();
+ if (now <= ad[adid].expires)
+ expired = 0;
+
+error:
+ CADp->reply_cookies_len = sprintf(CADp->reply_cookies,
+ "found_cookie=Ad_id=%d&Ad_weight=%d&Expired=%d",
+ adid, weight, expired);
+
+ sprintf(CADp->ad_filename, "dir%05d/class%d_%d",
+ adid / 36, ((adid % 36) / 9), adid % 9);
+ return 0;
+}
+
+
+#define TOKEN_EQUAL(input,token) \
+ (!memcmp(input, token, sizeof(token)-1))
+
+#define PARSE_STRING(token,input,output) \
+ ({ \
+ int __ret = 0; \
+ if (TOKEN_EQUAL(input, token)) { \
+ char *tmp; \
+ \
+ input += sizeof(token)-1; \
+ tmp = output; \
+ while (*input && *input != '&' && \
+ *input != ',') \
+ *tmp++ = *input++; \
+ *tmp = 0; \
+ __ret = 1; \
+ } \
+ __ret; \
+ })
+
+#define PARSE_UINT(token,input,output) \
+ ({ \
+ int __ret = 0; \
+ if (TOKEN_EQUAL(input, token)) { \
+ \
+ input += sizeof(token)-1; \
+ output = simple_strtoul(input, &input, 10); \
+ __ret = 1; \
+ } \
+ __ret; \
+ })
+
+static int init_postlog_file (void)
+{
+ char buf[400], *tmp;
+ int ret;
+
+ if (post_file)
+ fput(post_file);
+ post_file = http_open_file(POSTLOG, O_CREAT|O_TRUNC|O_APPEND|O_RDWR);
+ if (!post_file) {
+ printk("CAD: could not open POST log {%s}!\n", POSTLOG);
+ return -2;
+ }
+ postlog_count = 0;
+ tmp = buf;
+ tmp += sprintf(tmp, "%10d\n", 0);
+ ret = http_write_file(post_file, buf, tmp-buf);
+ if (ret != tmp-buf) {
+ printk("hm, initial postlog write didnt succeed: %d != %p-%p.\n", ret, tmp, buf);
+ return -2;
+ }
+ postlog_head_page = http_mmap_page(post_file, postlog_head, 0);
+ if (!postlog_head_page)
+ return -2;
+
+ return 0;
+}
+
+#define COMMAND_STRING "command/"
+#define COMMAND_RESET "Reset"
+#define COMMAND_FETCH "Fetch"
+
+static int do_reset (http_req_t *req, char *query)
+{
+ char maxload [20], pttime[20], maxthread[20],
+ exp1[20], exp2[20], urlroot [100];
+ char tmpstr1[256], tmpstr2[256];
+
+ http_sleep(1);
+ if (!PARSE_STRING("&maxload=", query, maxload))
+ return send_err(req,"CAD: invalid &maxload field!\n");
+ if (!PARSE_STRING("&pttime=", query, pttime))
+ return send_err(req,"CAD: invalid &pttime field!\n");
+ if (!PARSE_STRING("&maxthread=", query, maxthread))
+ return send_err(req,"CAD: invalid &maxthread field!\n");
+ if (!PARSE_STRING("&exp=", query, exp1))
+ return send_err(req,"CAD: invalid &exp1 field!\n");
+ if (!PARSE_STRING(",", query, exp2))
+ return send_err(req,"CAD: invalid &exp2 field!\n");
+ if (!PARSE_STRING("&urlroot=", query, urlroot))
+ return send_err(req,"CAD: invalid &urlroot field!\n");
+
+
+ strcpy(tmpstr1, http_docroot); strcat(tmpstr1, "/upfgen99");
+ strcpy(tmpstr2, http_docroot); strcat(tmpstr2, "/cadgen99");
+#define TOPDIR http_docroot
+#define UPFGEN tmpstr1
+#define CADGEN tmpstr2
+
+ {
+ char *argv_upfgen[] = { UPFGEN, "-C", TOPDIR, "-n", maxload,
+ "-t", maxthread, NULL};
+ char *argv_cadgen[] = { CADGEN, "-C", TOPDIR, "-e", pttime,
+ "-t", maxthread, exp1, exp2, NULL};
+ char * envp[] = { "HOME=/", "TERM=linux",
+ "PATH=/sbin:/usr/sbin:/bin:/usr/bin", NULL };
+
+ if (http_exec_process(UPFGEN, argv_upfgen, envp, NULL, NULL, 1) < 0)
+ return send_err(req,"CAD: could not execute UPFGEN!\n");
+
+ if (http_exec_process(CADGEN, argv_cadgen, envp, NULL, NULL, 1) < 0)
+ return send_err(req,"CAD: could not execute CADGEN!\n");
+ }
+ /*
+ * Clear post log
+ */
+ http_down(&postlog_sem);
+
+ init_postlog_file();
+ http_up(&postlog_sem);
+
+ /*
+ * mtime has a 1 second resolution, sleep 1 second so that
+ * the check for modified User.Personality and Custom.Ads
+ * files notices multiple resets correctly.
+ */
+ http_sleep(1);
+
+ req->bytes_sent = send_reply_head(req, 0);
+ req->bytes_sent += send_reply_tail(req);
+
+ return -2;
+}
+
+#define BLOCKLEN 512
+
+static int send_postlog (http_req_t *req)
+{
+ char buf [BLOCKLEN];
+ int len, total, bytes;
+
+ if (http_file_error(post_file)) {
+ printk("hm, no postlog.\n");
+ return -2;
+ }
+ if (req->urlo)
+ HTTP_BUG();
+ /*
+ * Atomic transaction - serializes with all POST activity while
+ * we send the log.
+ */
+ http_down(&postlog_sem);
+
+ req->body_len = http_file_size(post_file);
+ post_file->f_pos = 0;
+ bytes = send_reply_head(req, req->body_len);
+ total = 0;
+ do {
+ len = http_write_file(post_file, buf, BLOCKLEN);
+ if (!len)
+ break;
+ if (len < 0)
+ HTTP_BUG();
+ bytes += http_send_client(req, buf, len, 0);
+ total += len;
+ } while (len == BLOCKLEN);
+
+ http_up(&postlog_sem);
+
+ bytes += send_reply_tail(req);
+ req->bytes_sent = bytes;
+
+ return -2;
+}
+
+static int do_command (http_req_t *req, char *query)
+{
+ if (TOKEN_EQUAL(query, COMMAND_RESET))
+ return do_reset(req, query + sizeof(COMMAND_RESET)-1);
+ if (TOKEN_EQUAL(query, COMMAND_FETCH))
+ return send_postlog(req);
+ return send_err(req,"CAD: got invalid command!\n");
+}
+
+static CAD_t * parse_GET_cookies (http_req_t *req)
+{
+ int uid, last_ad;
+ CAD_t *CADp;
+ char *tmp;
+
+ if (!req->cookies_len) {
+ return NULL;
+ }
+
+ CADp = http_malloc(sizeof(CAD_t), ALLOC_REQ_PRIVATE);
+ CADp->reply_cookies_len = 0;
+
+ tmp = req->cookies + sizeof("my_cookie=user_id=")-1;
+ uid = simple_strtoul(tmp, &tmp, 10) - 10000;
+
+ tmp += sizeof("&last_ad=")-1;
+ last_ad = simple_strtoul(tmp, &tmp, 10);
+
+ CADp->user_id = uid;
+ CADp->last_ad = last_ad;
+
+ if (req->private)
+ HTTP_BUG();
+ req->private = (void *) CADp;
+ return CADp;
+}
+
+static int do_POST (http_req_t *req)
+{
+ int dir = -1, class = -1, num = -1, client = -1;
+ char buf[400], *tmp;
+ char urlroot[100];
+ CAD_t *CADp;
+ char *curr;
+ int ret;
+
+ CADp = parse_GET_cookies(req);
+
+ curr = req->post_data;
+ if (!curr)
+ goto parse_error;
+
+#define POST_URLROOT "urlroot="
+#define POST_CLASS "class="
+#define POST_CLIENT "client="
+#define POST_DIR "dir="
+#define POST_NUM "num="
+
+ for (;;) {
+ switch (*curr) {
+ case 'u':
+ if (PARSE_STRING( POST_URLROOT, curr, urlroot))
+ continue;
+ goto parse_error;
+ case 'c':
+ if (PARSE_UINT( POST_CLASS, curr, class))
+ continue;
+ if (PARSE_UINT( POST_CLIENT, curr, client))
+ continue;
+ goto parse_error;
+ case 'd':
+ if (PARSE_UINT( POST_DIR, curr, dir))
+ continue;
+ goto parse_error;
+ case 'n':
+ if (PARSE_UINT( POST_NUM, curr, num))
+ continue;
+ goto parse_error;
+ case '&':
+ curr++;
+ continue;
+ case 0:
+ goto out;
+ default:
+ goto parse_error;
+ }
+ goto parse_error;
+ }
+out:
+ if (!CADp)
+ goto parse_error;
+ tmp = CADp->ad_filename;
+ tmp += sprintf(tmp, "%sdir%05d/class%d_%d", urlroot, dir, class, num);
+
+ /*
+ * Aquire semaphore guaranteeing atomic operations
+ * on the postlog file.
+ */
+ http_down(&postlog_sem);
+ if (!post_file)
+ if (init_postlog_file())
+ return 0;
+
+ postlog_count++;
+ tmp = postlog_head;
+ tmp += sprintf(tmp, "%10d", postlog_count);
+ *tmp = '\n';
+
+ tmp = buf;
+ tmp += sprintf(tmp, "%10d %10ld %10d %5d %2d %2d %10d %-60.60s %10d %10d\n", postlog_count, http_time(), http_getpid(), dir, class, num, client, CADp->ad_filename, http_getpid(), CADp->user_id + 10000);
+
+ ret = http_write_file(post_file, buf, tmp-buf);
+ http_up(&postlog_sem);
+
+ if (ret != tmp-buf) {
+ printk("hm, append postlog write didnt succeed: %d != %p-%p.\n", ret, tmp, buf);
+ goto parse_error;
+ }
+
+ CADp->reply_cookies_len = sprintf(CADp->reply_cookies,
+ "my_cookie=%u", 10000 + CADp->user_id);
+ return 0;
+parse_error:
+ return send_err(req,"CAD: error while parsing POST request!\n");
+}
+
+/*
+ * Called by TUX for every new connection:
+ */
+static int query_CAD (http_req_t *req)
+{
+ urlo_t *urlo = NULL, *prev_urlo = NULL;
+ int ret = 0;
+ CAD_t *CADp;
+ int missed;
+
+ if (req->dentry) HTTP_BUG();
+
+ if (req->method == METHOD_POST) {
+ ret = do_POST(req);
+ if (ret)
+ return ret;
+ CADp = (CAD_t *)req->private;
+ if (!CADp)
+ HTTP_BUG();
+ req->objectname = CADp->ad_filename;
+ req->objectname_len = strlen(CADp->ad_filename);
+ } else {
+ char *tmp = req->query;
+
+ if (req->method != METHOD_GET)
+ HTTP_BUG();
+ if (TOKEN_EQUAL(req->query, COMMAND_STRING)) {
+ tmp += sizeof(COMMAND_STRING)-1;
+ return do_command(req, tmp);
+ }
+ req->objectname = req->query;
+ req->objectname_len = req->query_len;
+ if (req->private)
+ HTTP_BUG();
+ CADp = parse_GET_cookies(req);
+ }
+
+repeat_lookup:
+ if (req->urlo)
+ HTTP_BUG();
+ missed = lookup_urlo(req, LOOKUP_ATOMIC);
+ if (req->userspace_module)
+ HTTP_BUG();
+ urlo = req->urlo;
+ if ((!missed && !urlo) || (urlo && urlo->tcapi))
+ goto url_error;
+ if (req->method == METHOD_GET) {
+ if (CADp) {
+ if (!missed && !urlo->SSI) {
+ char *tmp;
+ tmp = strstr(req->objectname, "class");
+ if (tmp) {
+ tmp += sizeof("class")-1;
+ if ((tmp[0] == '1') || (tmp[0] == '2')) {
+ free_urlo(urlo->inode);
+ prev_urlo = urlo;
+ req->urlo = NULL;
+ http_dput(req->dentry);
+ req->dentry = NULL;
+ goto repeat_lookup;
+ }
+ urlo->SSI = 1;
+ }
+ }
+ req->SSI = 1;
+ ret = custom_ad_rotate(req, CADp);
+ if (ret)
+ return ret;
+ }
+ }
+ if (missed || !urlo->csumc) {
+ if (req->prev_urlo)
+ HTTP_BUG();
+ req->prev_urlo = prev_urlo;
+ return http_miss_req(req);
+ }
+ if (prev_urlo)
+ put_urlo(urlo);
+
+ return ret;
+url_error:
+ return send_err(req, "CAD: error while parsing CAD request!\n");
+}
+
+#define REPLY_HEAD_HEAD \
+ "HTTP/1.1 200 OK\r\n" \
+ "Content-Type: text/html\r\n" \
+ "Connection: Keep-Alive\r\n" \
+ "Content-Length: %d\r\n\r\n"
+
+#define REPLY_HEAD_HEAD_COOKIE \
+ "HTTP/1.1 200 OK\r\n" \
+ "Content-Type: text/html\r\n" \
+ "Connection: Keep-Alive\r\n" \
+ "Content-Length: %d\r\n" \
+ "Set-Cookie: %s\r\n" \
+ "\r\n"
+
+#define REPLY_HEAD_TAIL \
+ "<html>\n" \
+ "<head><title>SPECweb99 Dynamic GET & POST Test</title></head>\n"\
+ "<body>\n" \
+ "<p>SERVER_SOFTWARE = TUX 1.0\n" \
+ "<p>REMOTE_ADDR = %d.%d.%d.%d\n" \
+ "<p>SCRIPT_NAME = %s\n" \
+ "<p>QUERY_STRING = %s\n" \
+ "<pre>\n"
+
+#define REPLY_TAIL \
+ "\n</pre>\n" \
+ "</body></html>\n"
+
+static int send_reply_head (http_req_t *req, size_t body_size)
+{
+ char buf [1000];
+ char *tmp, *head, *tail;
+ CAD_t *CADp = (CAD_t *)req->private;
+ unsigned int host, head_len, tail_len, total_len;
+
+ host = http_client_addr(req);
+#define IP(x) (((unsigned char *)&host)[x])
+
+ tmp = tail = buf;
+ tmp += sprintf(tmp, REPLY_HEAD_TAIL, IP(0), IP(1), IP(2), IP(3),
+ req->tcapi->vfs_name, req->query);
+
+ tail_len = tmp-buf;
+
+ total_len = tail_len + sizeof(REPLY_TAIL)-1 + body_size;
+
+ head = tmp;
+ if (CADp && CADp->reply_cookies_len)
+ tmp += sprintf(tmp, REPLY_HEAD_HEAD_COOKIE, total_len,
+ CADp->reply_cookies);
+ else
+ tmp += sprintf(tmp, REPLY_HEAD_HEAD, total_len);
+
+ head_len = tmp-head;
+ http_send_client(req, head, head_len, 0);
+ http_send_client(req, tail, tail_len, 0);
+ req->http_status = 200;
+
+ return tail_len;
+}
+
+static int send_reply_tail (http_req_t *req)
+{
+ int len = sizeof(REPLY_TAIL)-1;
+
+ http_send_client(req, REPLY_TAIL, len, 1);
+ return len;
+}
+
+
+/*
+ * Send dynamicly generated SSI server-side include
+ * content. (this is the typical CAD case) Every reply is
+ * generated dynamically, based on the template position
+ * and cookie values, or other information.
+ */
+static int send_reply_CAD (http_req_t *req)
+{
+ int bytes;
+
+ req->body_len = req->urlo->body_len;
+
+ bytes = send_reply_head(req, req->urlo->body_len);
+ bytes += http_send_object(req, 0, 0);
+ bytes += send_reply_tail(req);
+
+ return bytes;
+}
+
+/*
+ * Return SPECweb99 error message.
+ */
+static int send_err (http_req_t *req, char *message)
+{
+ CAD_t *CADp = (CAD_t *)req->private;
+ int len = strlen(message);
+ int bytes;
+
+ /*
+ * Return a -1 Ad_id in the reply cookie.
+ */
+ if (CADp)
+ CADp->reply_cookies_len = sprintf(CADp->reply_cookies,
+ "found_cookie=Ad_id=-1&Ad_weight=0&Expired=1");
+
+ req->body_len = len;
+ bytes = send_reply_head(req, len);
+ http_send_client(req, message, len, 0);
+ bytes += len;
+ bytes += send_reply_tail(req);
+
+ req->bytes_sent = bytes;
+ return -2;
+}
+
+/*
+ * This callback is called when a particular SSI object is being
+ * sent. Note that there can be more SSI 'fragments' within one
+ * object, and that this fragment is local (not cached, dynamically
+ * generated and TCP-checksummed) to this request. This means that
+ * a generic module can use whatever request-local state to generate
+ * dynami SSI content. Eg. a greeting message in the language
+ * determined by the IP address, or cookies-based advertisement like
+ * in the CAD case. The SSI fragment's size can be changed as well,
+ * frag->size is the default size.
+ *
+ * this callback is the 'heart' of TUX's SSI implementation.
+ */
+static int generate_SSI_entry_CAD (http_req_t *req, skb_frag_t *frag)
+{
+ int packetsize = frag->size;
+ CAD_t *CADp;
+ char *buf;
+
+ CADp = (CAD_t *)req->private;
+ if (!CADp)
+ HTTP_BUG();
+ if (packetsize != sizeof(CAD_TAG_BODY)-1)
+ HTTP_BUG();
+
+ buf = (char *)kmap(frag->page) + frag->page_offset;
+ memcpy(buf, CADp->ad_filename, sizeof(CAD_TAG_BODY)-1);
+
+ frag->csum = csum_partial(buf, packetsize, 0);
+ kunmap(frag->page);
+ return 1;
+}
+
+static tcapi_template_t CAD_tcapi = {
+ vfs_name: "e",
+ version: HTTP_VERSION,
+ query: query_CAD,
+ send_reply: send_reply_CAD,
+ create_SSI_map: create_SSI_map_CAD,
+ generate_SSI_entry: generate_SSI_entry_CAD
+};
+
+static int CAD2_start (void)
+{
+ CAD_tcapi.mod = THIS_MODULE;
+
+ return register_httpmodule(&CAD_tcapi);
+}
+
+void CAD2_stop (void)
+{
+ unregister_httpmodule(&CAD_tcapi);
+}
+
+module_init(CAD2_start)
+module_exit(CAD2_stop)
+
--- linux/net/http/userspace.c.orig Fri Sep 1 07:28:26 2000
+++ linux/net/http/userspace.c Fri Sep 1 07:28:26 2000
@@ -0,0 +1,54 @@
+/*
+ * TUX - Integrated HTTP layer and Object Cache
+ *
+ * Copyright (C) 2000, Ingo Molnar <
[email protected]>
+ *
+ * userspace.c: handle userspace-module requests
+ */
+
+#include <net/http.h>
+
+http_req_t * pick_userspace_req (threadinfo_t *ti)
+{
+ struct list_head *head, *curr;
+ http_req_t *req = NULL;
+
+ spin_lock_irq(&ti->userspace_lock);
+ head = &ti->userspace_pending;
+ curr = head->next;
+
+ if (curr != head) {
+ req = list_entry(curr, http_req_t, userspace);
+ if (req->magic != HTTP_MAGIC)
+ HTTP_BUG();
+ check_req_list(req, &req->userspace);
+ if (req->ti != ti)
+ HTTP_BUG();
+ if (ti->thread != current)
+ HTTP_BUG();
+ if (!req->userspace_module)
+ HTTP_BUG();
+ if (!req->tcapi)
+ HTTP_BUG();
+ list_del(curr);
+ check_req_list(req, NULL);
+ }
+ spin_unlock_irq(&ti->userspace_lock);
+
+ return req;
+}
+
+void flush_userspacequeue (threadinfo_t *ti)
+{
+ http_req_t *req;
+
+ while ((req = pick_userspace_req(ti))) {
+ req->keep_alive = 0;
+ req->http_status = -1;
+ req->userspace_module = 0;
+ req->private = NULL;
+ DEC_STAT(nr_userspace_pending);
+ flush_request(req, ti);
+ }
+}
+
--- linux/net/http/HTTPAPI.txt.orig Fri Sep 1 07:28:26 2000
+++ linux/net/http/HTTPAPI.txt Fri Sep 1 07:28:26 2000
@@ -0,0 +1,430 @@
+
+HTTP-module HOWTO.
+
+Introduction:
+
+every HTTP trusted dynamic module defines a 'tcapi template', which
+defines entry points and module properties. Note that TUX's in-kernel
+dynamic API is ment to be small and simple. Complex and slow requests
+should be handled in user-space.
+
+-----------------------------------------------------------------------
+
+Currently defined fields in the TUX 1.0 module template are:
+
+struct tcapi_template_s {
+ char *vfs_name;
+ char *version;
+ int (*query) (http_req_t *req);
+ int (*send_reply) (http_req_t *req);
+ int (*log) (http_req_t *req, char *log_buffer);
+ void (*finish) (http_req_t *req);
+};
+
+-----------------------------------------------------------------------
+
+HTTP-module vfs_name:
+
+ char *vfs_name;
+
+the VFS name to which the module is mapped. Eg. if vfs_name is "httpapi",
+then
http://server/httpapi?filename requests will be directed to this
+module.
+
+-----------------------------------------------------------------------
+
+HTTP-module version:
+
+ char *version;
+
+the TUX version string of the module. Current TUX version is "TUX 1.0".
+Future API changes might result in older, incompatible modules being not
+loaded. Future APIs might support older APIs as well.
+
+-----------------------------------------------------------------------
+
+TUX-module query():
+
+ int (*query) (http_req_t *req);
+
+callback which happens after a new request arrives which involves this
+module. 'req' is the HTTP request descriptor.
+
+RETURN VALUES:
+
+ 0: request parsed, continue with output
+
+ -1: input data incomplete, put socket into idle state
+
+ -2: request finished, flush now
+
+ (all other return values undefined)
+
+-----------------------------------------------------------------------
+
+HTTP-module send_reply():
+
+ int (*send_reply) (http_req_t *req);
+
+if defined then replies are generated by the module. Simpler modules
+which have this callback set to NULL will just fill out req->filename
+and req->urlc, which file will then be transmitted by TUX.
+
+RETURN VALUES:
+
+ positive values: bytes transmitted
+ -3: redirect request to secondary server
+ everything else: 0 bytes transmitted, flush request now
+
+-----------------------------------------------------------------------
+
+HTTP-module log():
+
+ int (*log) (http_req_t *req, char *log_buffer);
+
+if defined then the module can create a custom log entry, and returns
+the log entry's size. log_buffer is maximum MAX_LOG_ENTRY long.
+
+RETURN VALUES:
+
+ length of log entry
+
+-----------------------------------------------------------------------
+
+HTTP-module finish():
+
+ void (*finish) (http_req_t *req);
+
+if defined then after closing the connection TUX calls this callback.
+Modules can free potential per-request private data structures this way.
+
+RETURN VALUES:
+
+ none
+
+-----------------------------------------------------------------------
+-----------------------------------------------------------------------
+-----------------------------------------------------------------------
+
+TUX helper functions and object descriptors available to HTTP modules,
+all these functions have a http_ prefix, to avoid namespace pollution.
+
+-----------------------------------------------------------------------
+
+http_req_t *;
+
+descriptor of a client connection. Defined fields are:
+
+
+char * query; // the string part of the URI after the question mark.
+urlc_t *urlc; // HTTP object belonging to this connection
+
+
+
+-----------------------------------------------------------------------
+
+struct http_file *;
+
+opaque file descriptor similar to user-space 'FILE *'. Fields are
+undefined for modules and are not needed to use the pointer.
+
+
+-----------------------------------------------------------------------
+
+struct http_page *;
+
+opaque page descriptor used for mapping pages. Fields are undefined
+for modules and are not needed to use the pointer.
+
+-----------------------------------------------------------------------
+
+struct http_direntry *;
+
+opaque type describing directory entries. Fields are undefined
+for modules and are not needed to use the pointer.
+
+-----------------------------------------------------------------------
+
+extern struct http_nameidata docroot;
+
+document root 'lookup context'. It is automatically provided for all
+HTTP modules, lookups are always relative to a lookup context.
+
+-----------------------------------------------------------------------
+
+struct http_mutex *;
+
+HTTP_DECLARE_MUTEX(name)
+
+macro to declare a mutex. The mutex can be referred to by 'name'. The
+type of the mutex is opaque.
+
+-----------------------------------------------------------------------
+
+urlc_t *;
+
+TUX URL object descriptor. Defined fields are:
+
+int filelen; // length of object
+tcapi_t *tcapi; // HTTP module this object belongs to
+csumc_t *csumc; // checksum-object
+int body_len; // length of the body of the object
+threadinfo_t *ti; // HTTP thread descriptor
+char *reply_cookie; // max 256 bytes reply cookie buffer
+int bytes_sent; // nr of bytes sent to client
+int keep_alive; // wether the connection should be kept after the request
+char *cookies; // input cookies
+int cookies_len; // length of input cookie field
+void *private; // opaque pointer free to be used by modules
+char *post_data; // input POST data
+http_method_t method; // input HTTP method
+char *filename; // HTTP object name
+int filename_len; // length of HTTP object name string
+int http_status; // reply message status towards client
+int body_len; // body length of HTTP reply message
+
+-----------------------------------------------------------------------
+
+typedef enum http_methods {
+ METHOD_NONE,
+ METHOD_GET,
+ METHOD_HEAD,
+ METHOD_POST,
+ METHOD_PUT
+} http_method_t;
+
+-----------------------------------------------------------------------
+
+threadinfo_t *;
+
+descriptor for a TUX thread. Defined fields are:
+
+char *output_buffer;
+
+output buffer belonging to this thread.
+
+-----------------------------------------------------------------------
+
+csumc_t *;
+
+HTTP checksum-object descriptor.
+
+-----------------------------------------------------------------------
+-----------------------------------------------------------------------
+-----------------------------------------------------------------------
+
+extern void * http_malloc (int size, int id);
+
+mallocs a new buffer of size 'size', with an allocation ID 'id'. Ids can
+be used to debug memory leaks - the allocation and freeing ID must be
+the same, and must be under MAX_ALLOC_ID, no other restrictions. TUX
+provides runtime statistics about various ID allocation patterns and
+allocation balance. This function can potentially block, so make careful
+use of it.
+
+RETURN VALUES:
+
+ the allocated buffer
+
+-----------------------------------------------------------------------
+
+extern void http_free (void *ptr, int id);
+
+free a http_malloc()-ed temporary buffer.
+
+
+RETURN VALUES:
+
+ none
+
+-----------------------------------------------------------------------
+
+int http_exec_process (char *command, char **argv, char **envp, int *unused1, exec_param_t *unused2, int wait);
+
+starts and exec()s a new user-space process, pointed to by 'command', with
+argument array of 'argv', environment array 'envp'. If 'wait' is 1 then TUX
+waits for the process to exit, otherwise it's running asynchronously.
+
+RETURN VALUES:
+
+ 0 on success
+ non-zero on failure
+
+-----------------------------------------------------------------------
+
+http_open_file():
+
+struct http_file * http_open_file (char *filename, int mode);
+
+opens a file descriptor pointed to by 'filename', with file mode 'mode'.
+
+RETURN VALUES:
+
+ the opened file descriptor or NULL on failure
+
+-----------------------------------------------------------------------
+
+int http_read (urlc_t *urlc, char *buf)
+
+read a full HTTP object into a sufficiently sized temporary buffer.
+
+RETURN VALUES:
+
+ 0 on success
+ non-zero on failure
+
+-----------------------------------------------------------------------
+
+int http_send_client (http_req_t *req, char *buf, int len, int push)
+
+sends a given buffer's contents to the client as-is. If 'push' is 1
+then the content is 'pushed' to the client.
+
+RETURN VALUES:
+
+ >=0 bytes sent
+ <0 on error
+
+-----------------------------------------------------------------------
+
+int http_send_file (http_req_t *req, int include_header, int push)
+
+sends a given HTTP object to the client as a reply. include_headers
+specifies wether TUX should construct a header. The 'push' argument
+specifies wether the TCP data should be pushed to the client.
+
+RETURN VALUES:
+
+ 0: success
+ -1: failure
+
+-----------------------------------------------------------------------
+
+struct http_direntry * http_lookup_direntry (char *pathname,
+ struct http_nameidata *docroot, int flags)
+
+looks up a given file identified by pathname, starting at docroot, and
+returns a direntry pointer to it. This pointer can later on be used to
+do file operations.
+
+RETURN VALUES:
+
+ the looked up directory entry on success
+ non-zero http_direntry_error() on failure
+
+-----------------------------------------------------------------------
+
+int http_direntry_error (struct http_direntry * dentry)
+
+converts the error code embedded in the dentry pointer to an integer
+error code.
+
+RETURN VALUES:
+
+ 0: the dentry is valid
+ nonzero: the dentry lookup had an error
+
+-----------------------------------------------------------------------
+
+int http_file_size (struct http_file *file)
+
+returns the length of the file.
+
+-----------------------------------------------------------------------
+
+unsigned int http_mtime (struct http_file *file)
+
+returns the last modification time of the file, in Unix time.
+
+-----------------------------------------------------------------------
+
+int http_write_file (struct http_file *file, char *buf, int len)
+
+writes a given buffer's contents into the file, and updates the file
+position.
+
+RETURN VALUES:
+
+ >0 bytes written
+ <=0 on error
+
+-----------------------------------------------------------------------
+
+int http_read_file (struct http_file *file, char *buf, int len)
+
+reads a file (from the current position) into a given buffer and
+updates the file position.
+
+RETURN VALUES:
+
+ >0 bytes read
+ <=0 on error
+
+-----------------------------------------------------------------------
+
+void http_close_file (struct http_file *file)
+
+closes a file descriptor. (usage of the file pointer after closing the
+file may result in undefined behavior.)
+
+-----------------------------------------------------------------------
+
+struct http_page * http_mmap_page (struct http_file *file, char *buf,
+ unsigned int offset)
+
+mmaps a given page at a given offset from a given file into the
+process's address space.
+
+RETURN VALUES:
+
+ NULL: error
+ non-NULL: pointer to the page structure
+
+-----------------------------------------------------------------------
+
+int http_miss_req (struct http_req_t *req)
+
+the module signals towards TUX that the object described via
+req->filename should be constructed by TUX.
+
+RETURN VALUES:
+
+ 0: request parsed, continue with output
+
+ -1: input data incomplete, put socket into idle state
+
+ -2: request finished, flush now
+
+ (ie. can be used as a ->query() return value.)
+
+-----------------------------------------------------------------------
+
+void http_sleep (int seconds)
+
+suspends execution for a given number of seconds.
+
+-----------------------------------------------------------------------
+
+void http_down (struct http_mutex *mutex)
+
+'down' operation on the mutex (enters critical section). Suspends
+execution if the critical section is already entered.
+
+-----------------------------------------------------------------------
+
+void http_up (struct http_mutex *mutex)
+
+'up' operation on the mutex. (release critical section)
+
+-----------------------------------------------------------------------
+
+unsigned int http_client_addr (http_req_t *req)
+
+retrieve the IP address of the client connection 'req'.
+
+RETURN VALUES:
+
+ the client IP address in host-endian format
+
+-----------------------------------------------------------------------
+
--- linux/drivers/net/sk98lin/h/skdrv2nd.h.orig Wed Feb 9 03:58:25 2000
+++ linux/drivers/net/sk98lin/h/skdrv2nd.h Fri Sep 1 07:28:26 2000
@@ -131,8 +131,8 @@
* define sizes of descriptor rings in bytes
*/
-#define TX_RING_SIZE (8*1024)
-#define RX_RING_SIZE (24*1024)
+#define TX_RING_SIZE (256*1024)
+#define RX_RING_SIZE (256*1024)
/*
* Buffer size for ethernet packets
--- linux/drivers/net/sk98lin/skge.c.orig Fri Sep 1 07:26:56 2000
+++ linux/drivers/net/sk98lin/skge.c Fri Sep 1 07:28:26 2000
@@ -137,7 +137,7 @@
* Fixed pci config space accesses.
*
* Revision 1.4 1999/02/18 15:48:44 cgoos
- * Corrected some printk's.
+ * Corrected some Dprintk's.
*
* Revision 1.3 1999/02/18 12:45:55 cgoos
* Changed SK_MAX_CARD_PARAM to default 16
@@ -233,6 +233,8 @@
#include "h/skdrv1st.h"
#include "h/skdrv2nd.h"
+#include <net/http.h>
+
/* defines ******************************************************************/
#define BOOT_STRING "sk98lin: Network Device Driver v3.02\n" \
@@ -248,14 +250,15 @@
#define USE_TX_COMPLETE
/* use interrupt moderation (for tx complete only) */
-// #define USE_INT_MOD
-#define INTS_PER_SEC 1000
+#define USE_INT_MOD
+#define INTS_PER_SEC 300000
/*
* threshold for copying small receive frames
* set to 0 to avoid copying, set to 9001 to copy all frames
*/
-#define SK_COPY_THRESHOLD 200
+#define SK_COPY_THRESHOLD 0
+//#define SK_COPY_THRESHOLD 200
/* number of adapters that can be configured via command line params */
#define SK_MAX_CARD_PARAM 16
@@ -363,24 +366,30 @@
/* set display flag to TRUE so that */
/* we only display this string ONCE */
version_disp = 1;
- printk("%s\n", BootString);
+ Dprintk("%s\n", BootString);
}
if (!pci_present()) /* is PCI support present? */
return -ENODEV;
- while((pdev = pci_find_device(PCI_VENDOR_ID_SYSKONNECT,
- PCI_DEVICE_ID_SYSKONNECT_GE, pdev)) != NULL) {
- if (pci_enable_device(pdev))
+ while((pdev = pci_find_class(PCI_CLASS_NETWORK_ETHERNET << 8, pdev)))
+ {
+ dev = NULL;
+
+ if (pdev->vendor != PCI_VENDOR_ID_SYSKONNECT ||
+ pdev->device != PCI_DEVICE_ID_SYSKONNECT_GE) {
continue;
+ }
dev = init_etherdev(dev, sizeof(SK_AC));
- if (dev == NULL) {
+ if (dev == NULL || dev->priv == NULL){
printk(KERN_ERR "Unable to allocate etherdev "
"structure!\n");
break;
}
+ memset(dev->priv, 0, sizeof(SK_AC));
+
pAC = dev->priv;
pAC->PciDev = *pdev;
pAC->PciDevId = pdev->device;
@@ -393,6 +402,7 @@
dev->open = &SkGeOpen;
dev->stop = &SkGeClose;
dev->hard_start_xmit = &SkGeXmit;
+ dev->hard_start_xmit_dual = &SkGeXmit;
dev->get_stats = &SkGeStats;
dev->set_multicast_list = &SkGeSetRxMode;
dev->set_mac_address = &SkGeSetMacAddr;
@@ -406,7 +416,7 @@
pci_set_master(pdev);
- base_address = pci_resource_start (pdev, 0);
+ base_address = pdev->resource[0].start;
#ifdef SK_BIG_ENDIAN
/*
@@ -428,7 +438,7 @@
pAC->IoBase = (char*)ioremap(base_address, 0x4000);
if (!pAC->IoBase){
- printk(KERN_ERR "%s: Unable to map I/O register, "
+ Dprintk(KERN_ERR "%s: Unable to map I/O register, "
"SK 98xx No. %i will be disabled.\n",
dev->name, boards_found);
break;
@@ -602,7 +612,7 @@
cards = skge_probe();
if (cards == 0) {
- printk("No adapter found\n");
+ Dprintk("No adapter found\n");
}
return cards ? 0 : -ENODEV;
} /* skge_init_module */
@@ -711,7 +721,7 @@
spin_lock_irqsave(&pAC->SlowPathLock, Flags);
/* Does a RESET on board ...*/
if (SkGeInit(pAC, pAC->IoBase, 0) != 0) {
- printk("HWInit (0) failed.\n");
+ Dprintk("HWInit (0) failed.\n");
spin_unlock_irqrestore(&pAC->SlowPathLock, Flags);
return(-EAGAIN);
}
@@ -735,7 +745,7 @@
/* level 1 init common modules here (HW init) */
spin_lock_irqsave(&pAC->SlowPathLock, Flags);
if (SkGeInit(pAC, pAC->IoBase, 1) != 0) {
- printk("HWInit (1) failed.\n");
+ Dprintk("HWInit (1) failed.\n");
spin_unlock_irqrestore(&pAC->SlowPathLock, Flags);
return(-EAGAIN);
}
@@ -755,12 +765,12 @@
Ret = request_irq(dev->irq, SkGeIsrOnePort, SA_SHIRQ,
pAC->Name, dev);
} else {
- printk(KERN_WARNING "%s: illegal number of ports: %d\n",
+ Dprintk(KERN_WARNING "%s: illegal number of ports: %d\n",
dev->name, pAC->GIni.GIMacsFound);
return -EAGAIN;
}
if (Ret) {
- printk(KERN_WARNING "%s: Requested IRQ %d is busy\n",
+ Dprintk(KERN_WARNING "%s: Requested IRQ %d is busy\n",
dev->name, dev->irq);
return -EAGAIN;
}
@@ -768,7 +778,7 @@
/* Alloc memory for this board (Mem for RxD/TxD) : */
if(!BoardAllocMem(pAC)) {
- printk("No memory for descriptor rings\n");
+ Dprintk("No memory for descriptor rings\n");
return(-EAGAIN);
}
@@ -783,7 +793,7 @@
/* Print adapter specific string from vpd */
ProductStr(pAC);
- printk("%s: %s\n", dev->name, pAC->DeviceStr);
+ Dprintk("%s: %s\n", dev->name, pAC->DeviceStr);
SkGeYellowLED(pAC, pAC->IoBase, 1);
@@ -1354,7 +1364,7 @@
if (pAC->BoardLevel == 0) {
/* level 1 init common modules here */
if (SkGeInit(pAC, pAC->IoBase, 1) != 0) {
- printk("%s: HWInit(1) failed\n", pAC->dev->name);
+ Dprintk("%s: HWInit(1) failed\n", pAC->dev->name);
return (-1);
}
SkI2cInit (pAC, pAC->IoBase, 1);
@@ -1385,7 +1395,8 @@
#ifdef USE_INT_MOD
// moderate only TX complete interrupts (these are not time critical)
-#define IRQ_MOD_MASK (IRQ_EOF_AS_TX1 | IRQ_EOF_AS_TX2)
+//#define IRQ_MOD_MASK (IRQ_EOF_AS_TX1 | IRQ_EOF_AS_TX2)
+#define IRQ_MOD_MASK (IRQ_EOF_AS_TX1 | IRQ_EOF_AS_TX2 | IRQ_EOF_RX1 | IRQ_EOF_RX2)
{
unsigned long ModBase;
ModBase = 53125000 / INTS_PER_SEC;
@@ -1498,7 +1509,7 @@
{
SK_AC *pAC;
int Rc; /* return code of XmitFrame */
-
+
pAC = (SK_AC*) dev->priv;
Rc = XmitFrame(pAC, &pAC->TxPort[pAC->ActivePort][TX_PRIO_LOW], skb);
@@ -1543,7 +1554,7 @@
static int XmitFrame(
SK_AC *pAC, /* pointer to adapter context */
TX_PORT *pTxPort, /* pointer to struct of port to send to */
-struct sk_buff *pMessage) /* pointer to send-message */
+struct sk_buff *skb) /* pointer to send-message */
{
TXD *pTxd; /* the rxd to fill */
unsigned int Flags;
@@ -1555,10 +1566,10 @@
spin_lock_irqsave(&pTxPort->TxDesRingLock, Flags);
- if (pTxPort->TxdRingFree == 0) {
+ if (pTxPort->TxdRingFree <= MAX_SKB_FRAGS) {
/* no enough free descriptors in ring at the moment */
FreeTxDescriptors(pAC, pTxPort);
- if (pTxPort->TxdRingFree == 0) {
+ if (pTxPort->TxdRingFree <= MAX_SKB_FRAGS) {
spin_unlock_irqrestore(&pTxPort->TxDesRingLock, Flags);
SK_PNMI_CNT_NO_TX_BUF(pAC);
SK_DBG_MSG(NULL, SK_DBGMOD_DRV,
@@ -1579,25 +1590,79 @@
*/
#ifdef SK_DUMP_TX
- DumpMsg(pMessage, "XmitFrame");
+ DumpMsg(skb, "XmitFrame");
#endif
/* set up descriptor and CONTROL dword */
PhysAddr = (SK_U64) pci_map_single(&pAC->PciDev,
- pMessage->data,
- pMessage->len,
+ skb->data,
+ skb->len-skb->data_len,
PCI_DMA_TODEVICE);
pTxd->VDataLow = (SK_U32) (PhysAddr & 0xffffffff);
pTxd->VDataHigh = (SK_U32) (PhysAddr >> 32);
- pTxd->pMBuf = pMessage;
- pTxd->TBControl = TX_CTRL_OWN_BMU | TX_CTRL_STF |
- TX_CTRL_CHECK_DEFAULT | TX_CTRL_SOFTWARE |
+
+ if (!skb->nr_frags) {
+ Dprintk("send SKB normal SKGE: skb %p: len:%d, data_len:%d, head:%p, data:%p, tail:%p, end:%p.\n", skb, skb->len, skb->data_len, skb->head, skb->data, skb->tail, skb->end);
+ if (skb->data_len)
+ BUG();
+ pTxd->pMBuf = skb;
+ pTxd->TBControl = TX_CTRL_OWN_BMU | TX_CTRL_STF |
+ TX_CTRL_CHECK_DEFAULT | TX_CTRL_SOFTWARE |
#ifdef USE_TX_COMPLETE
- TX_CTRL_EOF | TX_CTRL_EOF_IRQ | pMessage->len;
+ TX_CTRL_EOF | TX_CTRL_EOF_IRQ | skb->len;
#else
- TX_CTRL_EOF | pMessage->len;
+ TX_CTRL_EOF | skb->len;
#endif
-
+ } else {
+ int i, len;
+
+ Dprintk("SKGE: skb %p: len:%d, data_len:%d, head:%p, data:%p, tail:%p, end:%p.\n", skb, skb->len, skb->data_len, skb->head, skb->data, skb->tail, skb->end);
+ if (skb->tail - skb->data != skb->len - skb->data_len)
+ BUG();
+ if (skb->tail == skb->data)
+ BUG();
+ /*
+ * No end of fragment flag.
+ */
+ pTxd->TBControl = TX_CTRL_OWN_BMU | TX_CTRL_STF |
+ /*TX_CTRL_EOB_IRQ |*/ TX_CTRL_CHECK_DEFAULT |
+ TX_CTRL_SOFTWARE | (skb->len - skb->data_len);
+
+ len = 0;
+ for (i = 0; i < skb->nr_frags; i++) {
+ unsigned long control_bits;
+ skb_frag_t *frag = skb->frags[i];
+
+ len += frag->size;
+ pTxd = pTxPort->pTxdRingHead;
+ pTxPort->pTxdRingHead = pTxd->pNextTxd;
+ if (!pTxPort->TxdRingFree)
+ BUG();
+ pTxPort->TxdRingFree--;
+
+ PhysAddr = (frag->page-mem_map) *
+ (unsigned long long) PAGE_SIZE + frag->page_offset;
+ pTxd->VDataLow = (SK_U32) (PhysAddr & 0xffffffff);
+ pTxd->VDataHigh = (SK_U32) (PhysAddr >> 32);
+ control_bits = TX_CTRL_OWN_BMU | TX_CTRL_STF |
+ TX_CTRL_CHECK_DEFAULT | TX_CTRL_SOFTWARE |
+#ifdef USE_TX_COMPLETE
+ /*TX_CTRL_EOF_IRQ |*/ frag->size;
+#else
+ frag->size;
+#endif
+ if (i == skb->nr_frags-1) {
+ // last fragment triggers an IRQ and should
+ // free the skb
+ pTxd->pMBuf = skb;
+ control_bits |= TX_CTRL_EOF_IRQ | TX_CTRL_EOF;
+ }
+ pTxd->TBControl = control_bits;
+ }
+ if (len != skb->data_len)
+ BUG();
+ }
+
if ((pTxPort->pTxdRingPrev->TBControl & TX_CTRL_OWN_BMU) == 0) {
/* previous descriptor already done, so give tx start cmd */
/* StartTx(pAC, pTxPort->HwAddr); */
@@ -1606,9 +1671,9 @@
pTxPort->pTxdRingPrev = pTxd;
- BytesSend = pMessage->len;
+ BytesSend = skb->len;
/* after releasing the lock, the skb may be immidiately freed */
- if (pTxPort->TxdRingFree != 0) {
+ if (pTxPort->TxdRingFree > MAX_SKB_FRAGS) {
spin_unlock_irqrestore(&pTxPort->TxDesRingLock, Flags);
return (BytesSend);
}
@@ -1656,23 +1721,19 @@
*/
while (1) {
Control = pTxd->TBControl;
- if ((Control & TX_CTRL_SOFTWARE) == 0) {
+ if (!(Control & TX_CTRL_SOFTWARE)) {
/*
* software controllable bit is set in first
* fragment when given to BMU. Not set means that
* this fragment was never sent or is already
* freed ( -> ring completely free now).
*/
- pTxPort->pTxdRingTail = pTxd;
- netif_start_queue(pAC->dev);
- return;
+ Dprintk("stopped freeing Tx at SK TX descriptor %p due to !CTRL_SOFTWARE.\n", pTxd);
+ break;
}
if (Control & TX_CTRL_OWN_BMU) {
- pTxPort->pTxdRingTail = pTxd;
- if (pTxPort->TxdRingFree > 0) {
- netif_start_queue(pAC->dev);
- }
- return;
+ Dprintk("stopped freeing Tx at SK TX descriptor %p due to OWN_BMU.\n", pTxd);
+ break;
}
/* release the DMA mapping */
@@ -1683,11 +1744,25 @@
PCI_DMA_TODEVICE);
/* free message */
- DEV_KFREE_SKB_ANY(pTxd->pMBuf);
+ {
+ struct sk_buff *skb;
+ skb = (struct sk_buff *)pTxd->pMBuf;
+ Dprintk("free SK TX descriptor %p (skb %p).\n",
+ pTxd, skb);
+ if (skb) {
+ pTxd->pMBuf = NULL;
+ DEV_KFREE_SKB_ANY(skb);
+ Dprintk("SKGE: FREE skb %p: len:%d, data_len:%d, head:%p, data:%p, tail:%p, end:%p - physaddr: %08lx.\n", skb, skb->len, skb->data_len, skb->head, skb->data, skb->tail, skb->end, (long)PhysAddr);
+ }
+ }
pTxPort->TxdRingFree++;
pTxd->TBControl &= ~TX_CTRL_SOFTWARE;
pTxd = pTxd->pNextTxd; /* point behind fragment with EOF */
} /* while(forever) */
+
+ pTxPort->pTxdRingTail = pTxd;
+ if (pTxPort->TxdRingFree > MAX_SKB_FRAGS)
+ netif_start_queue(pAC->dev);
} /* FreeTxDescriptors */
@@ -2029,13 +2104,13 @@
else {
/* there is a receive error in this frame */
if ((FrameStat & XMR_FS_1L_VLAN) != 0) {
- printk("%s: Received frame"
+ Dprintk("%s: Received frame"
" with VLAN Level 1 header, check"
" switch configuration\n",
pAC->dev->name);
}
if ((FrameStat & XMR_FS_2L_VLAN) != 0) {
- printk("%s: Received frame"
+ Dprintk("%s: Received frame"
" with VLAN Level 2 header, check"
" switch configuration\n",
pAC->dev->name);
@@ -2740,7 +2815,7 @@
else if (strcmp(AutoNeg_A[pAC->Index],"Sense")==0) {
AutoNeg = AN_SENS;
}
- else printk("%s: Illegal value for AutoNeg_A\n",
+ else Dprintk("%s: Illegal value for AutoNeg_A\n",
pAC->dev->name);
}
@@ -2761,17 +2836,17 @@
else if (strcmp(DupCap_A[pAC->Index],"Half")==0) {
DuplexCap = DC_HALF;
}
- else printk("%s: Illegal value for DupCap_A\n",
+ else Dprintk("%s: Illegal value for DupCap_A\n",
pAC->dev->name);
}
/* check for illegal combinations */
if (AutoSet && AutoNeg==AN_SENS && DupSet) {
- printk("%s, Port A: DuplexCapabilities"
+ Dprintk("%s, Port A: DuplexCapabilities"
" ignored using Sense mode\n", pAC->dev->name);
}
if (AutoSet && AutoNeg==AN_OFF && DupSet && DuplexCap==DC_BOTH){
- printk("%s, Port A: Illegal combination"
+ Dprintk("%s, Port A: Illegal combination"
" of values AutoNeg. and DuplexCap.\n Using "
"Full Duplex\n", pAC->dev->name);
@@ -2782,7 +2857,7 @@
}
if (!AutoSet && DupSet) {
- printk("%s, Port A: Duplex setting not"
+ Dprintk("%s, Port A: Duplex setting not"
" possible in\n default AutoNegotiation mode"
" (Sense).\n Using AutoNegotiation On\n",
pAC->dev->name);
@@ -2814,11 +2889,11 @@
pAC->GIni.GP[0].PFlowCtrlMode =
SK_FLOW_MODE_NONE;
}
- else printk("Illegal value for FlowCtrl_A\n");
+ else Dprintk("Illegal value for FlowCtrl_A\n");
}
if (AutoNeg==AN_OFF && pAC->GIni.GP[0].PFlowCtrlMode!=
SK_FLOW_MODE_NONE) {
- printk("%s, Port A: FlowControl"
+ Dprintk("%s, Port A: FlowControl"
" impossible without AutoNegotiation,"
" disabled\n", pAC->dev->name);
pAC->GIni.GP[0].PFlowCtrlMode = SK_FLOW_MODE_NONE;
@@ -2838,7 +2913,7 @@
else if (strcmp(Role_A[pAC->Index],"Slave")==0) {
MSMode = SK_MS_MODE_SLAVE;
}
- else printk("%s: Illegal value for Role_A\n",
+ else Dprintk("%s: Illegal value for Role_A\n",
pAC->dev->name);
}
pAC->GIni.GP[0].PMSMode = MSMode;
@@ -2862,7 +2937,7 @@
else if (strcmp(AutoNeg_B[pAC->Index],"Sense")==0) {
AutoNeg = AN_SENS;
}
- else printk("Illegal value for AutoNeg_B\n");
+ else Dprintk("Illegal value for AutoNeg_B\n");
}
DuplexCap = DC_BOTH;
@@ -2882,16 +2957,16 @@
else if (strcmp(DupCap_B[pAC->Index],"Half")==0) {
DuplexCap = DC_HALF;
}
- else printk("Illegal value for DupCap_B\n");
+ else Dprintk("Illegal value for DupCap_B\n");
}
/* check for illegal combinations */
if (AutoSet && AutoNeg==AN_SENS && DupSet) {
- printk("%s, Port B: DuplexCapabilities"
+ Dprintk("%s, Port B: DuplexCapabilities"
" ignored using Sense mode\n", pAC->dev->name);
}
if (AutoSet && AutoNeg==AN_OFF && DupSet && DuplexCap==DC_BOTH){
- printk("%s, Port B: Illegal combination"
+ Dprintk("%s, Port B: Illegal combination"
" of values AutoNeg. and DuplexCap.\n Using "
"Full Duplex\n", pAC->dev->name);
@@ -2902,7 +2977,7 @@
}
if (!AutoSet && DupSet) {
- printk("%s, Port B: Duplex setting not"
+ Dprintk("%s, Port B: Duplex setting not"
" possible in\n default AutoNegotiation mode"
" (Sense).\n Using AutoNegotiation On\n",
pAC->dev->name);
@@ -2934,11 +3009,11 @@
pAC->GIni.GP[1].PFlowCtrlMode =
SK_FLOW_MODE_NONE;
}
- else printk("Illegal value for FlowCtrl_B\n");
+ else Dprintk("Illegal value for FlowCtrl_B\n");
}
if (AutoNeg==AN_OFF && pAC->GIni.GP[1].PFlowCtrlMode!=
SK_FLOW_MODE_NONE) {
- printk("%s, Port B: FlowControl"
+ Dprintk("%s, Port B: FlowControl"
" impossible without AutoNegotiation,"
" disabled\n", pAC->dev->name);
pAC->GIni.GP[1].PFlowCtrlMode = SK_FLOW_MODE_NONE;
@@ -2958,7 +3033,7 @@
else if (strcmp(Role_B[pAC->Index],"Slave")==0) {
MSMode = SK_MS_MODE_SLAVE;
}
- else printk("%s: Illegal value for Role_B\n",
+ else Dprintk("%s: Illegal value for Role_B\n",
pAC->dev->name);
}
pAC->GIni.GP[1].PMSMode = MSMode;
@@ -2991,7 +3066,7 @@
pAC->Rlmt.MacPreferred = Port;
pAC->Rlmt.PrefPort = Port;
}
- else printk("%s: Illegal value for PrefPort\n",
+ else Dprintk("%s: Illegal value for PrefPort\n",
pAC->dev->name);
}
@@ -3013,7 +3088,7 @@
SK_RLMT_CHECK_SEG;
}
else {
- printk("%s: Illegal value for"
+ Dprintk("%s: Illegal value for"
" RlmtMode, using default\n", pAC->dev->name);
pAC->RlmtMode = 0;
}
@@ -3316,7 +3391,7 @@
case SK_DRV_ADAP_FAIL:
SK_DBG_MSG(NULL, SK_DBGMOD_DRV, SK_DBGCAT_DRV_EVENT,
("ADAPTER FAIL EVENT\n"));
- printk("%s: Adapter failed.\n", pAC->dev->name);
+ Dprintk("%s: Adapter failed.\n", pAC->dev->name);
/* disable interrupts */
SK_OUT32(pAC->IoBase, B0_IMSK, 0);
/* cgoos */
@@ -3326,9 +3401,9 @@
SK_DBG_MSG(NULL, SK_DBGMOD_DRV, SK_DBGCAT_DRV_EVENT,
("PORT FAIL EVENT, Port: %d\n", FromPort));
if (FromPort == 0) {
- printk("%s: Port A failed.\n", pAC->dev->name);
+ Dprintk("%s: Port A failed.\n", pAC->dev->name);
} else {
- printk("%s: Port B failed.\n", pAC->dev->name);
+ Dprintk("%s: Port B failed.\n", pAC->dev->name);
}
/* cgoos */
break;
@@ -3368,47 +3443,47 @@
FromPort = Param.Para32[0];
SK_DBG_MSG(NULL, SK_DBGMOD_DRV, SK_DBGCAT_DRV_EVENT,
("NET UP EVENT, Port: %d ", Param.Para32[0]));
- printk("%s: network connection up using"
+ Dprintk("%s: network connection up using"
" port %c\n", pAC->dev->name, 'A'+Param.Para32[0]);
- printk(" speed: 1000\n");
+ Dprintk(" speed: 1000\n");
Stat = pAC->GIni.GP[FromPort].PLinkModeStatus;
if (Stat == SK_LMODE_STAT_AUTOHALF ||
Stat == SK_LMODE_STAT_AUTOFULL) {
- printk(" autonegotiation: yes\n");
+ Dprintk(" autonegotiation: yes\n");
}
else {
- printk(" autonegotiation: no\n");
+ Dprintk(" autonegotiation: no\n");
}
if (Stat == SK_LMODE_STAT_AUTOHALF ||
Stat == SK_LMODE_STAT_HALF) {
- printk(" duplex mode: half\n");
+ Dprintk(" duplex mode: half\n");
}
else {
- printk(" duplex mode: full\n");
+ Dprintk(" duplex mode: full\n");
}
Stat = pAC->GIni.GP[FromPort].PFlowCtrlStatus;
if (Stat == SK_FLOW_STAT_REM_SEND ) {
- printk(" flowctrl: remote send\n");
+ Dprintk(" flowctrl: remote send\n");
}
else if (Stat == SK_FLOW_STAT_LOC_SEND ){
- printk(" flowctrl: local send\n");
+ Dprintk(" flowctrl: local send\n");
}
else if (Stat == SK_FLOW_STAT_SYMMETRIC ){
- printk(" flowctrl: symmetric\n");
+ Dprintk(" flowctrl: symmetric\n");
}
else {
- printk(" flowctrl: none\n");
+ Dprintk(" flowctrl: none\n");
}
if (pAC->GIni.GP[FromPort].PhyType != SK_PHY_XMAC) {
Stat = pAC->GIni.GP[FromPort].PMSStatus;
if (Stat == SK_MS_STAT_MASTER ) {
- printk(" role: master\n");
+ Dprintk(" role: master\n");
}
else if (Stat == SK_MS_STAT_SLAVE ) {
- printk(" role: slave\n");
+ Dprintk(" role: slave\n");
}
else {
- printk(" role: ???\n");
+ Dprintk(" role: ???\n");
}
}
@@ -3423,14 +3498,14 @@
/* action list 7 */
SK_DBG_MSG(NULL, SK_DBGMOD_DRV, SK_DBGCAT_DRV_EVENT,
("NET DOWN EVENT "));
- printk("%s: network connection down\n", pAC->dev->name);
+ Dprintk("%s: network connection down\n", pAC->dev->name);
break;
case SK_DRV_SWITCH_HARD: /* SK_U32 FromPortIdx SK_U32 ToPortIdx */
SK_DBG_MSG(NULL, SK_DBGMOD_DRV, SK_DBGCAT_DRV_EVENT,
("PORT SWITCH HARD "));
case SK_DRV_SWITCH_SOFT: /* SK_U32 FromPortIdx SK_U32 ToPortIdx */
/* action list 6 */
- printk("%s: switching to port %c\n", pAC->dev->name,
+ Dprintk("%s: switching to port %c\n", pAC->dev->name,
'A'+Param.Para32[1]);
case SK_DRV_SWITCH_INTERN: /* SK_U32 FromPortIdx SK_U32 ToPortIdx */
FromPort = Param.Para32[0];
@@ -3551,7 +3626,7 @@
strcpy(ClassStr, "Communication error");
break;
}
- printk(KERN_INFO "%s: -- ERROR --\n Class: %s\n"
+ Dprintk(KERN_INFO "%s: -- ERROR --\n Class: %s\n"
" Nr: 0x%x\n Msg: %s\n", pAC->dev->name,
ClassStr, ErrNum, pErrorMsg);
@@ -3577,12 +3652,12 @@
int msglen;
if (skb == NULL) {
- printk("DumpMsg(): NULL-Message\n");
+ Dprintk("DumpMsg(): NULL-Message\n");
return;
}
if (skb->data == NULL) {
- printk("DumpMsg(): Message empty\n");
+ Dprintk("DumpMsg(): Message empty\n");
return;
}
@@ -3590,11 +3665,11 @@
if (msglen > 64)
msglen = 64;
- printk("--- Begin of message from %s , len %d (from %d) ----\n", str, msglen, skb->len);
+ Dprintk("--- Begin of message from %s , len %d (from %d) ----\n", str, msglen, skb->len);
DumpData((char *)skb->data, msglen);
- printk("------- End of message ---------\n");
+ Dprintk("------- End of message ---------\n");
} /* DumpMsg */
@@ -3639,7 +3714,7 @@
p++;
i++;
if (i%16 == 0) {
- printk("%s %s\n", hex_buffer, asc_buffer);
+ Dprintk("%s %s\n", hex_buffer, asc_buffer);
addr = 0;
haddr = 0;
}
@@ -3697,11 +3772,11 @@
p++;
i++;
if (i%8 == 0) {
- printk("%4x %s\n", (i-8)*4, hex_buffer);
+ Dprintk("%4x %s\n", (i-8)*4, hex_buffer);
haddr = 0;
}
}
- printk("------------------------\n");
+ Dprintk("------------------------\n");
} /* DumpLong */
#endif /* DEBUG */
--- linux/drivers/net/eepro100.c.orig Fri Sep 1 07:27:03 2000
+++ linux/drivers/net/eepro100.c Fri Sep 1 07:28:26 2000
@@ -1532,17 +1532,21 @@
do {
status = inw(ioaddr + SCBStatus);
- /* Acknowledge all of the current interrupt sources ASAP. */
- /* Will change from 0xfc00 to 0xff00 when we start handling
- FCP and ER interrupts --Dragan */
- outw(status & 0xfc00, ioaddr + SCBStatus);
-
if (speedo_debug > 4)
printk(KERN_DEBUG "%s: interrupt status=%#4.4x.\n",
dev->name, status);
+ /*
+ * For the sake of performance during shared interrupts
+ * we first check wether there is any work pending.
+ */
if ((status & 0xfc00) == 0)
break;
+
+ /* Acknowledge all of the current interrupt sources ASAP. */
+ /* Will change from 0xfc00 to 0xff00 when we start handling
+ FCP and ER interrupts --Dragan */
+ outw(status & 0xfc00, ioaddr + SCBStatus);
/* Always check if all rx buffers are allocated. --SAW */
speedo_refill_rx_buffers(dev, 0);
--- linux/drivers/net/acenic.c.orig Fri Sep 1 07:26:56 2000
+++ linux/drivers/net/acenic.c Fri Sep 1 07:28:26 2000
@@ -48,7 +48,8 @@
#include <linux/mm.h>
#undef ETHTOOL
-#undef INDEX_DEBUG
+//#define INDEX_DEBUG
+#define TX_DEBUG 0
#ifdef ETHTOOL
#include <linux/ethtool.h>
@@ -97,7 +98,7 @@
#endif
#ifndef wmb
-#define wmb() mb()
+#define wmb() wmb()
#endif
#ifndef __exit
@@ -182,6 +183,8 @@
#include "acenic_firmware.h"
+#define dprintk(x...) do { } while (0)
+
/*
* This driver currently supports Tigon I and Tigon II based cards
* including the Alteon AceNIC, the 3Com 3C985[B] and NetGear
@@ -375,18 +378,42 @@
#define DEF_JUMBO_RX_MAX_DESC 6
#define DEF_JUMBO_TX_RATIO 21
-#define TX_COAL_INTS_ONLY 0 /* seems not worth it */
+#define TX_COAL_INTS_ONLY 1 /* seems not worth it */
#define DEF_TRACE 0
#define DEF_STAT (2 * TICKS_PER_SEC)
static int link[ACE_MAX_MOD_PARMS] = {0, };
static int trace[ACE_MAX_MOD_PARMS] = {0, };
-static int tx_coal_tick[ACE_MAX_MOD_PARMS] = {0, };
-static int rx_coal_tick[ACE_MAX_MOD_PARMS] = {0, };
-static int max_tx_desc[ACE_MAX_MOD_PARMS] = {0, };
-static int max_rx_desc[ACE_MAX_MOD_PARMS] = {0, };
-static int tx_ratio[ACE_MAX_MOD_PARMS] = {0, };
-static int dis_pci_mem_inval[ACE_MAX_MOD_PARMS] = {1, 1, 1, 1, 1, 1, 1, 1};
+static int tx_coal_tick[ACE_MAX_MOD_PARMS] =
+ { [0 ... ACE_MAX_MOD_PARMS-1] = 400 };
+static int rx_coal_tick[ACE_MAX_MOD_PARMS] =
+ { [0 ... ACE_MAX_MOD_PARMS-1] = 200 };
+static int max_tx_desc[ACE_MAX_MOD_PARMS] =
+ { [0 ... ACE_MAX_MOD_PARMS-1] = 32 };
+static int max_rx_desc[ACE_MAX_MOD_PARMS] =
+ { [0 ... ACE_MAX_MOD_PARMS-1] = 16 };
+static int tx_ratio[ACE_MAX_MOD_PARMS] =
+ { [0 ... ACE_MAX_MOD_PARMS-1] = 56 /*56*/ };
+static int dis_pci_mem_inval[ACE_MAX_MOD_PARMS] =
+ { [0 ... ACE_MAX_MOD_PARMS-1] = 0 };
+
+static int __init ace_coal_setup (char *str)
+{
+ int par;
+
+ if (get_option(&str,&par) >= 0) {
+ int i;
+
+ for (i = 0; i < ACE_MAX_MOD_PARMS; i++) {
+ tx_coal_tick[i] = par;
+ rx_coal_tick[i] = par;
+ }
+ }
+ return 1;
+}
+
+__setup("ace_coal=", ace_coal_setup);
+
static const char __initdata *version =
"acenic.c: v0.44 05/11/2000 Jes Sorensen,
[email protected]\n"
@@ -461,6 +488,7 @@
dev->irq = pdev->irq;
dev->open = &ace_open;
dev->hard_start_xmit = &ace_start_xmit;
+ dev->hard_start_xmit_dual = &ace_start_xmit;
dev->stop = &ace_close;
dev->get_stats = &ace_get_stats;
dev->set_multicast_list = &ace_set_multicast_list;
@@ -726,7 +754,7 @@
}
#else
module_init(ace_module_init);
-module_exit(ace_module_cleanup);
+//module_exit(ace_module_cleanup);
#endif
@@ -909,7 +937,7 @@
writel((CLR_INT | WORD_SWAP | ((CLR_INT | WORD_SWAP) << 24)),
®s->HostCtrl);
#endif
- mb();
+ wmb();
/*
* Stop the NIC CPU and clear pending interrupts
@@ -964,7 +992,7 @@
writel(ACE_BYTE_SWAP_DMA | ACE_WARN | ACE_FATAL |
ACE_WORD_SWAP_BD | ACE_NO_JUMBO_FRAG, ®s->ModeStat);
#endif
- mb();
+ wmb();
mac1 = 0;
for(i = 0; i < 4; i++) {
@@ -1091,7 +1119,7 @@
#endif
writel(tmp, ®s->PciState);
-#if 0
+#if 1
/*
* I have received reports from people having problems when this
* bit is enabled.
@@ -1255,6 +1283,10 @@
writel(0, (unsigned long)ap->tx_ring + i * 4);
}
+ printk("TX ring base (physical) address: %08x.\n", TX_RING_BASE);
+ printk("tx_ring (physical) address: %08lx. (should be about the same as above)\n",
+ __pa((unsigned long)ap->tx_ring));
+
set_aceaddr(&info->tx_ctrl.rngptr, TX_RING_BASE);
info->tx_ctrl.max_len = TX_RING_ENTRIES;
#if TX_COAL_INTS_ONLY
@@ -1371,7 +1403,6 @@
* tx ints before we are up and running, which may cause a null
* pointer access in the int handler.
*/
- ap->tx_full = 0;
ap->cur_rx = 0;
ap->tx_prd = *(ap->tx_csm) = ap->tx_ret_csm = 0;
@@ -1822,8 +1853,7 @@
ap->jumbo = 0;
printk(KERN_INFO "%s: Jumbo ring flushed\n",
dev->name);
- if (!ap->tx_full)
- netif_wake_queue(dev);
+ netif_wake_queue(dev);
clear_bit(0, &ap->jumbo_refill_busy);
break;
}
@@ -1962,6 +1992,7 @@
ap = dev->priv;
regs = ap->regs;
+ dprintk("Got AceNIC IRQ%d, ap: %p\n", irq, ap);
/*
* In case of PCI shared interrupts or spurious interrupts,
* we want to make sure it is actually our interrupt before
@@ -1985,27 +2016,38 @@
rxretprd = *ap->rx_ret_prd;
rxretcsm = ap->cur_rx;
- if (rxretprd != rxretcsm)
+ if (rxretprd != rxretcsm) {
+ dprintk("Processing RX IRQ (prod: %d, csm: %d).\n", rxretprd, rxretcsm);
ace_rx_int(dev, rxretprd, rxretcsm);
+ }
txcsm = *ap->tx_csm;
idx = ap->tx_ret_csm;
if (txcsm != idx) {
+ dprintk("Processing TX IRQ (txcsm: %d, tx_ret_csm: %d).\n", txcsm, idx);
do {
struct sk_buff *skb;
dma_addr_t mapping;
+ struct ring_info *info;
+ struct tx_desc *desc;
- skb = ap->skb->tx_skbuff[idx].skb;
- mapping = ap->skb->tx_skbuff[idx].mapping;
+ info = ap->skb->tx_skbuff + idx;
+ desc = ap->tx_ring + idx;
+ skb = info->skb;
+ mapping = info->mapping;
+
+ dprintk("Freeing TX descriptor %p (%d), skb %p, high:%08x, low:%08x, flags/size:%08x.).\n", desc, idx, skb, desc->addr.addrhi, desc->addr.addrlo, desc->flagsize);
ap->stats.tx_packets++;
- ap->stats.tx_bytes += skb->len;
- pci_unmap_single(ap->pdev, mapping, skb->len,
- PCI_DMA_TODEVICE);
- dev_kfree_skb_irq(skb);
+ if (skb) {
+ ap->stats.tx_bytes += skb->len;
+// pci_unmap_single(ap->pdev, mapping, skb->len,
+// PCI_DMA_TODEVICE);
+ dev_kfree_skb_irq(skb);
- ap->skb->tx_skbuff[idx].skb = NULL;
+ info->skb = NULL;
+ }
/*
* Question here is whether one should not skip
@@ -2013,38 +2055,27 @@
* caused by the NIC actually trying to access
* these incorrectly.
*/
-#if (BITS_PER_LONG == 64)
+#if TX_DEBUG
writel(0, &ap->tx_ring[idx].addr.addrhi);
-#endif
writel(0, &ap->tx_ring[idx].addr.addrlo);
writel(0, &ap->tx_ring[idx].flagsize);
+#endif
idx = (idx + 1) % TX_RING_ENTRIES;
} while (idx != txcsm);
+ wmb();
+ dprintk("%d free TX descriptors, new ret_csm: %d\n", tx_free(ap), txcsm);
+
+ ap->tx_ret_csm = txcsm;
/*
* Once we actually get to this point the tx ring has
* already been trimmed thus it cannot be full!
* Ie. skip the comparison of the tx producer vs. the
* consumer.
*/
- if (netif_queue_stopped(dev) && xchg(&ap->tx_full, 0)) {
- /*
- * This does not need to be atomic (and expensive),
- * I've seen cases where it would fail otherwise ;-(
- */
+ if (!tx_ring_full(ap))
netif_wake_queue(dev);
- ace_mark_net_bh(NET_BH);
-
- /*
- * TX ring is no longer full, aka the
- * transmitter is working fine - kill timer.
- */
- del_timer(&ap->timer);
- }
-
- ap->tx_ret_csm = txcsm;
- wmb();
}
evtcsm = readl(®s->EvtCsm);
@@ -2120,6 +2151,31 @@
writel(0, ®s->Mb0Lo);
}
+#define MAX_DEV 16
+
+static struct net_device *dev_array[MAX_DEV];
+static int nr_dev = 0;
+
+void wake_acenics (void)
+{
+ int i;
+
+ printk("hack_acenics() called.\n");
+ for (i = 0; i < MAX_DEV; i++) {
+ struct net_device *dev = dev_array[i];
+ struct ace_private *ap;
+ ap = dev->priv;
+ printk(".device %s.\n", dev->name);
+ printk("... queue state was: %08lx.\n", dev->state);
+ printk("... tx_free(): %d.\n", tx_free(ap));
+ printk("... tx_ret_csm: %d.\n", ap->tx_ret_csm);
+ printk("... tx_prd: %d.\n", ap->tx_prd);
+ printk("... evt_prd: %d.\n", *ap->evt_prd);
+ printk("... rx_ret_prd: %d.\n", *ap->rx_ret_prd);
+ printk("... tx_csm: %d.\n", *ap->tx_csm);
+ netif_wake_queue(dev);
+ }
+}
static int ace_open(struct net_device *dev)
{
@@ -2127,6 +2183,8 @@
struct ace_regs *regs;
struct cmd cmd;
+ dev_array[nr_dev++] = dev;
+
ap = dev->priv;
regs = ap->regs;
@@ -2205,13 +2263,21 @@
unsigned long flags;
short i;
- ace_if_down(dev);
- netif_stop_queue(dev);
- ap = dev->priv;
+ ap = dev->priv;
regs = ap->regs;
- del_timer(&ap->timer);
+ printk("ace_close(%p) called.\n", dev);
+ printk("... queue state was: %08lx.\n", dev->state);
+ printk("... tx_free(): %d.\n", tx_free(ap));
+ printk("... tx_ret_csm: %d.\n", ap->tx_ret_csm);
+ printk("... tx_prd: %d.\n", ap->tx_prd);
+ printk("... evt_prd: %d.\n", *ap->evt_prd);
+ printk("... rx_ret_prd: %d.\n", *ap->rx_ret_prd);
+ printk("... tx_csm: %d.\n", *ap->tx_csm);
+
+ ace_if_down(dev);
+ netif_stop_queue(dev);
if (ap->promisc) {
cmd.evt = C_SET_PROMISC_MODE;
@@ -2236,17 +2302,27 @@
for (i = 0; i < TX_RING_ENTRIES; i++) {
struct sk_buff *skb;
dma_addr_t mapping;
+ struct ring_info *info;
- skb = ap->skb->tx_skbuff[i].skb;
- mapping = ap->skb->tx_skbuff[i].mapping;
+ info = ap->skb->tx_skbuff + i;
+ skb = info->skb;
+ mapping = info->mapping;
+// printk("ring entry %d, skb %p, info %p.\n", i, skb, info);
+// printk("... addrhi: %08x, addrlo: %08x, flags-size:%08x.\n",
+// ap->tx_ring[i].addr.addrhi,
+// ap->tx_ring[i].addr.addrlo,
+// ap->tx_ring[i].flagsize);
if (skb) {
+// pci_unmap_single(ap->pdev, mapping, skb->len,
+// PCI_DMA_TODEVICE);
+
+#if 1
writel(0, &ap->tx_ring[i].addr.addrhi);
writel(0, &ap->tx_ring[i].addr.addrlo);
writel(0, &ap->tx_ring[i].flagsize);
- pci_unmap_single(ap->pdev, mapping, skb->len,
- PCI_DMA_TODEVICE);
+#endif
dev_kfree_skb(skb);
- ap->skb->tx_skbuff[i].skb = NULL;
+ info->skb = NULL;
}
}
@@ -2268,44 +2344,137 @@
{
struct ace_private *ap = dev->priv;
struct ace_regs *regs = ap->regs;
- unsigned long addr;
+ struct tx_desc *desc;
+ struct ring_info *info;
+ unsigned long long addr, phys;
u32 idx, flagsize;
- /*
- * ARGH, there is just no pretty way to do this
- */
-#if (LINUX_VERSION_CODE < 0x02032b)
- if (test_and_set_bit(0, &dev->tbusy))
+ dprintk("AceNIC start_xmit(skb: %p), dev %p.\n", skb, dev);
+
+#if 0
+ if (tx_ring_full(ap)) {
+ printk("%s: trying to transmit while the tx ring is full "
+ "- i think this should not happen. (state: %ld)\n",
+ dev->name, dev->state);
+ netif_stop_queue(dev);
return 1;
-#else
- netif_stop_queue(dev);
+ }
#endif
-
idx = ap->tx_prd;
- if ((idx + 1) % TX_RING_ENTRIES == ap->tx_ret_csm) {
- ap->tx_full = 1;
-#if DEBUG
- printk("%s: trying to transmit while the tx ring is full "
- "- this should not happen!\n", dev->name);
+ if (!skb->nr_frags) {
+ info = ap->skb->tx_skbuff + idx;
+ desc = ap->tx_ring + idx;
+ phys = pci_map_single(ap->pdev, skb->data, skb->len, PCI_DMA_TODEVICE);
+// info->mapping = phys;
+ addr = phys;
+#if TX_DEBUG
+ if (desc->addr.addrhi)
+ BUG();
+ if (desc->addr.addrlo)
+ BUG();
+ if (desc->flagsize)
+ BUG();
+ if (!skb->len)
+ BUG();
+ if (info->skb)
+ BUG();
+#endif
+ info->skb = skb;
+ flagsize = (skb->len << 16) | (BD_FLG_END) ;
+
+ writel(addr >> 32, &desc->addr.addrhi);
+ writel(addr & 0xffffffff, &desc->addr.addrlo);
+ writel(flagsize, &desc->flagsize);
+// writel(0, &desc->vlanres);
+
+ dprintk("added NORMAL TX descriptor %p (%d), skb %p, high:%08x, low:%08x, flags/size:%08x.).\n", desc, idx, skb, desc->addr.addrhi, desc->addr.addrlo, flagsize);
+
+ idx = (idx + 1) % TX_RING_ENTRIES;
+ } else {
+ int i, len = 0;
+
+#if TX_DEBUG
+ if (idx & 1)
+ idx = (idx + 1) % TX_RING_ENTRIES;
+#endif
+ info = ap->skb->tx_skbuff + idx;
+ desc = ap->tx_ring + idx;
+#if TX_DEBUG
+ if (info->skb)
+ BUG();
+ if (desc->addr.addrhi)
+ BUG();
+ if (desc->addr.addrlo)
+ BUG();
+ if (desc->flagsize)
+ BUG();
+ if (!(skb->len - skb->data_len))
+ BUG();
+#endif
+ phys = pci_map_single(ap->pdev, skb->data, skb->len, PCI_DMA_TODEVICE);
+// info->mapping = phys;
+ info->skb = NULL;
+ addr = phys;
+ flagsize = ((skb->len - skb->data_len) << 16);
+
+ writel(addr >> 32, &desc->addr.addrhi);
+ writel(addr & 0xffffffff, &desc->addr.addrlo);
+ writel(flagsize, &desc->flagsize);
+// writel(0, &desc->vlanres);
+
+ idx = (idx + 1) % TX_RING_ENTRIES;
+
+ for (i = 0; i < skb->nr_frags; i++) {
+ skb_frag_t *frag = skb->frags[i];
+
+ len += frag->size;
+ info = ap->skb->tx_skbuff + idx;
+ desc = ap->tx_ring + idx;
+#if TX_DEBUG
+ if (info->skb)
+ BUG();
+ if (desc->addr.addrhi)
+ BUG();
+ if (desc->addr.addrlo)
+ BUG();
+ if (desc->flagsize)
+ BUG();
+ if (!frag->size)
+ BUG();
+#endif
+
+ phys = (frag->page-mem_map) *
+ (unsigned long long) PAGE_SIZE +
+ frag->page_offset;
+ flagsize = (frag->size << 16);
+ dprintk("added HEAD FRAGMENTED TX descriptor %p (%d), skb %p, high:%08x, low:%08x, flags/size:%08x., info->skb: %p).\n", desc, idx, skb, desc->addr.addrhi, desc->addr.addrlo, flagsize, info->skb);
+ if (i == skb->nr_frags-1) {
+ flagsize |= BD_FLG_END;
+ /*
+ * Only the last fragment frees
+ * the skb!
+ */
+ info->skb = skb;
+ dprintk("added LAST FRAGMENTED TX descriptor %p (%d), skb %p, high:%08x, low:%08x, flags/size:%08x., info->skb: %p).\n", desc, idx, skb, desc->addr.addrhi, desc->addr.addrlo, flagsize, info->skb);
+ } else {
+ dprintk("added MIDDLE FRAGMENTED TX descriptor %p (%d), skb %p, high:%08x, low:%08x, flags/size:%08x., info->skb: %p).\n", desc, idx, skb, desc->addr.addrhi, desc->addr.addrlo, flagsize, info->skb);
+ }
+ writel(phys >> 32, &desc->addr.addrhi);
+ writel(phys & 0xffffffff, &desc->addr.addrlo);
+ writel(flagsize, &desc->flagsize);
+// writel(0, &desc->vlanres);
+ idx = (idx + 1) % TX_RING_ENTRIES;
+ }
+#if TX_DEBUG
+ if (len != skb->data_len)
+ BUG();
+ if (idx & 1)
+ idx = (idx + 1) % TX_RING_ENTRIES;
#endif
- return 1;
}
- ap->skb->tx_skbuff[idx].skb = skb;
- ap->skb->tx_skbuff[idx].mapping =
- pci_map_single(ap->pdev, skb->data, skb->len,
- PCI_DMA_TODEVICE);
- addr = (unsigned long) ap->skb->tx_skbuff[idx].mapping;
-#if (BITS_PER_LONG == 64)
- writel(addr >> 32, &ap->tx_ring[idx].addr.addrhi);
-#endif
- writel(addr & 0xffffffff, &ap->tx_ring[idx].addr.addrlo);
- flagsize = (skb->len << 16) | (BD_FLG_END) ;
- writel(flagsize, &ap->tx_ring[idx].flagsize);
wmb();
- idx = (idx + 1) % TX_RING_ENTRIES;
-
ap->tx_prd = idx;
ace_set_txprd(regs, ap, idx);
@@ -2313,34 +2482,16 @@
* tx_csm is set by the NIC whereas we set tx_ret_csm which
* is always trying to catch tx_csm
*/
- if ((idx + 2) % TX_RING_ENTRIES == ap->tx_ret_csm) {
- ap->tx_full = 1;
+ if (tx_ring_full(ap)) {
+ netif_stop_queue(dev);
/*
- * Queue is full, add timer to detect whether the
- * transmitter is stuck. Use mod_timer as we can get
- * into the situation where we risk adding several
- * timers.
+ * A TX-descriptor producer (an IRQ) might have gotten
+ * inbetween, making the ring free again. Since xmit is
+ * serialized, this is the only situation we have to
+ * re-test.
*/
- mod_timer(&ap->timer, jiffies + (3 * HZ));
-
- /* The following check will fix a race between the interrupt
- * handler increasing the tx_ret_csm and testing for tx_full
- * and this tx routine's testing the tx_ret_csm and setting
- * the tx_full; note that this fix makes assumptions on the
- * ordering of writes (sequential consistency will fly; TSO
- * processor order would work too) but that's what lock-less
- * programming is all about
- */
- if (((idx + 2) % TX_RING_ENTRIES != ap->tx_ret_csm)
- && xchg(&ap->tx_full, 0)) {
- del_timer(&ap->timer);
+ if (!tx_ring_full(ap))
netif_wake_queue(dev);
- }
- } else {
- /*
- * No need for it to be atomic - seems it needs to be
- */
- netif_wake_queue(dev);
}
dev->trans_start = jiffies;
@@ -2747,19 +2898,19 @@
local = readl(®s->LocalCtrl);
local |= EEPROM_DATA_OUT | EEPROM_WRITE_ENABLE;
writel(local, ®s->LocalCtrl);
- mb();
+ wmb();
udelay(ACE_SHORT_DELAY);
local |= EEPROM_CLK_OUT;
writel(local, ®s->LocalCtrl);
- mb();
+ wmb();
udelay(ACE_SHORT_DELAY);
local &= ~EEPROM_DATA_OUT;
writel(local, ®s->LocalCtrl);
- mb();
+ wmb();
udelay(ACE_SHORT_DELAY);
local &= ~EEPROM_CLK_OUT;
writel(local, ®s->LocalCtrl);
- mb();
+ wmb();
}
@@ -2773,7 +2924,7 @@
local &= ~EEPROM_DATA_OUT;
local |= EEPROM_WRITE_ENABLE;
writel(local, ®s->LocalCtrl);
- mb();
+ wmb();
for (i = 0; i < 8; i++, magic <<= 1) {
udelay(ACE_SHORT_DELAY);
@@ -2782,16 +2933,16 @@
else
local &= ~EEPROM_DATA_OUT;
writel(local, ®s->LocalCtrl);
- mb();
+ wmb();
udelay(ACE_SHORT_DELAY);
local |= EEPROM_CLK_OUT;
writel(local, ®s->LocalCtrl);
- mb();
+ wmb();
udelay(ACE_SHORT_DELAY);
local &= ~(EEPROM_CLK_OUT | EEPROM_DATA_OUT);
writel(local, ®s->LocalCtrl);
- mb();
+ wmb();
}
}
@@ -2804,18 +2955,18 @@
local = readl(®s->LocalCtrl);
local &= ~EEPROM_WRITE_ENABLE;
writel(local, ®s->LocalCtrl);
- mb();
+ wmb();
udelay(ACE_LONG_DELAY);
local |= EEPROM_CLK_OUT;
writel(local, ®s->LocalCtrl);
- mb();
+ wmb();
udelay(ACE_SHORT_DELAY);
/* sample data in middle of high clk */
state = (readl(®s->LocalCtrl) & EEPROM_DATA_IN) != 0;
udelay(ACE_SHORT_DELAY);
- mb();
+ wmb();
writel(readl(®s->LocalCtrl) & ~EEPROM_CLK_OUT, ®s->LocalCtrl);
- mb();
+ wmb();
return state;
}
@@ -2829,23 +2980,23 @@
local = readl(®s->LocalCtrl);
local |= EEPROM_WRITE_ENABLE;
writel(local, ®s->LocalCtrl);
- mb();
+ wmb();
udelay(ACE_SHORT_DELAY);
local &= ~EEPROM_DATA_OUT;
writel(local, ®s->LocalCtrl);
- mb();
+ wmb();
udelay(ACE_SHORT_DELAY);
local |= EEPROM_CLK_OUT;
writel(local, ®s->LocalCtrl);
- mb();
+ wmb();
udelay(ACE_SHORT_DELAY);
local |= EEPROM_DATA_OUT;
writel(local, ®s->LocalCtrl);
- mb();
+ wmb();
udelay(ACE_LONG_DELAY);
local &= ~EEPROM_CLK_OUT;
writel(local, ®s->LocalCtrl);
- mb();
+ wmb();
}
@@ -2919,37 +3070,37 @@
local &= ~EEPROM_WRITE_ENABLE;
writel(local, ®s->LocalCtrl);
udelay(ACE_LONG_DELAY);
- mb();
+ wmb();
local |= EEPROM_CLK_OUT;
writel(local, ®s->LocalCtrl);
- mb();
+ wmb();
udelay(ACE_SHORT_DELAY);
/* sample data mid high clk */
result = (result << 1) |
((readl(®s->LocalCtrl) & EEPROM_DATA_IN) != 0);
udelay(ACE_SHORT_DELAY);
- mb();
+ wmb();
local = readl(®s->LocalCtrl);
local &= ~EEPROM_CLK_OUT;
writel(local, ®s->LocalCtrl);
udelay(ACE_SHORT_DELAY);
- mb();
+ wmb();
if (i == 7) {
local |= EEPROM_WRITE_ENABLE;
writel(local, ®s->LocalCtrl);
- mb();
+ wmb();
udelay(ACE_SHORT_DELAY);
}
}
local |= EEPROM_DATA_OUT;
writel(local, ®s->LocalCtrl);
- mb();
+ wmb();
udelay(ACE_SHORT_DELAY);
writel(readl(®s->LocalCtrl) | EEPROM_CLK_OUT, ®s->LocalCtrl);
udelay(ACE_LONG_DELAY);
writel(readl(®s->LocalCtrl) & ~EEPROM_CLK_OUT, ®s->LocalCtrl);
- mb();
+ wmb();
udelay(ACE_SHORT_DELAY);
eeprom_stop(regs);
@@ -2966,6 +3117,6 @@
/*
* Local variables:
- * compile-command: "gcc -D__KERNEL__ -DMODULE -I../../include -Wall -Wstrict-prototypes -O2 -fomit-frame-pointer -pipe -fno-strength-reduce -DMODVERSIONS -include ../../include/linux/modversions.h -c -o acenic.o acenic.c"
+ * compile-command: "gcc -D__SMP__ -D__KERNEL__ -DMODULE -I../../include -Wall -Wstrict-prototypes -O2 -fomit-frame-pointer -pipe -fno-strength-reduce -DMODVERSIONS -include ../../include/linux/modversions.h -c -o acenic.o acenic.c"
* End:
*/
--- linux/drivers/net/acenic.h.orig Fri May 12 20:38:35 2000
+++ linux/drivers/net/acenic.h Fri Sep 1 07:28:26 2000
@@ -1,6 +1,8 @@
#ifndef _ACENIC_H_
#define _ACENIC_H_
+//#define DEBUG
+
/*
* Addressing:
*
@@ -415,12 +417,8 @@
/*
- * TX ring
+ * TX ring.
*/
-#define TX_RING_ENTRIES 128
-#define TX_RING_SIZE (TX_RING_ENTRIES * sizeof(struct tx_desc))
-#define TX_RING_BASE 0x3800
-
struct tx_desc{
aceaddr addr;
u32 flagsize;
@@ -444,6 +442,14 @@
u32 vlanres;
};
+/*
+ * TX ring size can be 128, 256 or 512.
+ * (any other value will result in a crash.)
+ */
+#define TX_RING_ENTRIES 128
+#define TX_RING_SIZE (TX_RING_ENTRIES * sizeof(struct tx_desc))
+#define TX_RING_END 0x4000
+#define TX_RING_BASE (TX_RING_END - sizeof(struct tx_desc)*TX_RING_ENTRIES)
#define RX_STD_RING_ENTRIES 512
#define RX_STD_RING_SIZE (RX_STD_RING_ENTRIES * sizeof(struct rx_desc))
@@ -603,9 +609,8 @@
*/
struct ace_info *info;
struct tx_desc *tx_ring;
- dma_addr_t info_dma;
u32 tx_prd;
- volatile u32 tx_full, tx_ret_csm;
+ volatile u32 tx_ret_csm;
struct timer_list timer;
unsigned long std_refill_busy
@@ -625,13 +630,26 @@
struct rx_desc *rx_jumbo_ring;
struct rx_desc *rx_mini_ring;
struct rx_desc *rx_return_ring;
- dma_addr_t rx_ring_base_dma;
struct event *evt_ring;
- dma_addr_t evt_ring_dma;
-
volatile u32 *evt_prd, *rx_ret_prd, *tx_csm;
- dma_addr_t evt_prd_dma, rx_ret_prd_dma, tx_csm_dma;
+
+ /*
+ * These are the places where the NIC DMAs into, so we
+ * want to have them on separate cachelines.
+ */
+ dma_addr_t rx_ring_base_dma
+ __attribute__ ((aligned (L1_CACHE_BYTES)));
+ dma_addr_t info_dma
+ __attribute__ ((aligned (L1_CACHE_BYTES)));
+ dma_addr_t evt_ring_dma
+ __attribute__ ((aligned (L1_CACHE_BYTES)));
+ dma_addr_t evt_prd_dma
+ __attribute__ ((aligned (L1_CACHE_BYTES)));
+ dma_addr_t rx_ret_prd_dma
+ __attribute__ ((aligned (L1_CACHE_BYTES)));
+ dma_addr_t tx_csm_dma
+ __attribute__ ((aligned (L1_CACHE_BYTES)));
unsigned char *trace_buf;
struct pci_dev *pdev;
@@ -642,12 +660,22 @@
char name[48];
#ifdef INDEX_DEBUG
spinlock_t debug_lock
- __attribute__ ((aligned (L1_CACHE_BYTES)));;
+ __attribute__ ((aligned (L1_CACHE_BYTES)));
u32 last_tx, last_std_rx, last_mini_rx;
#endif
struct net_device_stats stats;
};
+#define TX_RESERVED (MAX_SKB_FRAGS + 4)
+
+static inline int tx_free (struct ace_private *ap)
+{
+ // 2's complement arithmetics
+
+ return (ap->tx_ret_csm - ap->tx_prd - 1) & (TX_RING_ENTRIES-1);
+}
+
+#define tx_ring_full(ap) (tx_free(ap) <= TX_RESERVED)
static inline void set_aceaddr(aceaddr *aa, dma_addr_t addr)
{
--- linux/drivers/block/ll_rw_blk.c.orig Fri Sep 1 07:27:00 2000
+++ linux/drivers/block/ll_rw_blk.c Fri Sep 1 07:28:26 2000
@@ -21,6 +21,7 @@
#include <linux/mm.h>
#include <linux/init.h>
#include <linux/smp_lock.h>
+#include <linux/bootmem.h>
#include <asm/system.h>
#include <asm/io.h>
--- linux/arch/i386/mm/fault.c.orig Thu May 25 03:38:26 2000
+++ linux/arch/i386/mm/fault.c Fri Sep 1 07:28:26 2000
@@ -102,6 +102,30 @@
printk("Ok");
}
+static void print_pagetable_entries (pgd_t *pgdir, unsigned long vaddr)
+{
+ pgd_t *pgd;
+ pmd_t *pmd;
+ pte_t *pte;
+
+ pgd = pgdir + __pgd_offset(vaddr);
+ printk("pgd entry %p: %016Lx\n", pgd, (long long)pgd_val(*pgd));
+ if (!pgd_present(*pgd)) {
+ printk("... pgd not present!\n");
+ return;
+ }
+ pmd = pmd_offset(pgd, vaddr);
+ printk("pmd entry %p: %016Lx\n", pmd, (long long)pmd_val(*pmd));
+ if (!pmd_present(*pmd)) {
+ printk("... pmd not present!\n");
+ return;
+ }
+ pte = pte_offset(pmd, vaddr);
+ printk("pte entry %p: %016Lx\n", pte, (long long)pte_val(*pte));
+ if (!pte_present(*pte))
+ printk("... pte not present!\n");
+}
+
asmlinkage void do_invalid_op(struct pt_regs *, unsigned long);
extern unsigned long idt;
@@ -277,14 +301,7 @@
printk(" printing eip:\n");
printk("%08lx\n", regs->eip);
asm("movl %%cr3,%0":"=r" (page));
- page = ((unsigned long *) __va(page))[address >> 22];
- printk(KERN_ALERT "*pde = %08lx\n", page);
- if (page & 1) {
- page &= PAGE_MASK;
- address &= 0x003ff000;
- page = ((unsigned long *) __va(page))[address >> PAGE_SHIFT];
- printk(KERN_ALERT "*pte = %08lx\n", page);
- }
+ print_pagetable_entries((pgd_t *)__va(page), address);
die("Oops", regs, error_code);
do_exit(SIGKILL);
--- linux/arch/i386/kernel/entry.S.orig Fri Sep 1 07:27:00 2000
+++ linux/arch/i386/kernel/entry.S Fri Sep 1 07:28:26 2000
@@ -643,6 +643,11 @@
.long SYMBOL_NAME(sys_madvise)
.long SYMBOL_NAME(sys_getdents64) /* 220 */
.long SYMBOL_NAME(sys_fcntl64)
+#ifdef CONFIG_HTTP
+ .long SYMBOL_NAME(sys_http)
+#else
+ .long SYMBOL_NAME(sys_ni_syscall) /* placeholder */
+#endif
/*
* NOTE!! This doesn't have to be exact - we just have
@@ -650,6 +655,6 @@
* entries. Don't panic if you notice that this hasn't
* been shrunk every time we add a new system call.
*/
- .rept NR_syscalls-221
+ .rept NR_syscalls-222
.long SYMBOL_NAME(sys_ni_syscall)
.endr
--- linux/arch/i386/vmlinux.lds.orig Fri Sep 1 07:26:37 2000
+++ linux/arch/i386/vmlinux.lds Fri Sep 1 07:28:26 2000
@@ -6,7 +6,7 @@
ENTRY(_start)
SECTIONS
{
- . = 0xC0000000 + 0x100000;
+ . = 0x40000000 + 0x100000;
_text = .; /* Text and read-only data */
.text : {
*(.text)
--- linux/Makefile.orig Fri Sep 1 07:27:06 2000
+++ linux/Makefile Fri Sep 1 07:28:26 2000
@@ -1,7 +1,7 @@
VERSION = 2
PATCHLEVEL = 4
SUBLEVEL = 0
-EXTRAVERSION = -test8
+EXTRAVERSION = -test8-TUX
KERNELRELEASE=$(VERSION).$(PATCHLEVEL).$(SUBLEVEL)$(EXTRAVERSION)
@@ -87,7 +87,11 @@
CPPFLAGS := -D__KERNEL__ -I$(HPATH)
-CFLAGS := $(CPPFLAGS) -Wall -Wstrict-prototypes -O2 -fomit-frame-pointer
+#ifdef CONFIG_HTTP_DEBUG
+CFLAGS := $(CPPFLAGS) -Wall -Wstrict-prototypes -O2 -fno-omit-frame-pointer
+#else
+CFLAGS := $(CPPFLAGS) -Wall -Wstrict-prototypes -O6 -fomit-frame-pointer
+#endif
AFLAGS := -D__ASSEMBLY__ $(CPPFLAGS)
#