X-Git-Url: http://git.onelab.eu/?a=blobdiff_plain;f=fs%2Fnfsd%2Fnfscache.c;h=fdf7cf3dfadcf0f7775f4aa54cd4acf43e7ffed1;hb=16c70f8c1b54b61c3b951b6fb220df250fe09b32;hp=a3236dfedf98ba4fabdf16b915799ad788c7454a;hpb=6a77f38946aaee1cd85eeec6cf4229b204c15071;p=linux-2.6.git diff --git a/fs/nfsd/nfscache.c b/fs/nfsd/nfscache.c index a3236dfed..fdf7cf3df 100644 --- a/fs/nfsd/nfscache.c +++ b/fs/nfsd/nfscache.c @@ -15,6 +15,7 @@ #include #include #include +#include #include #include @@ -30,15 +31,8 @@ #define HASHSIZE 64 #define REQHASH(xid) ((((xid) >> 24) ^ (xid)) & (HASHSIZE-1)) -struct nfscache_head { - struct svc_cacherep * next; - struct svc_cacherep * prev; -}; - -static struct nfscache_head * hash_list; -static struct svc_cacherep * lru_head; -static struct svc_cacherep * lru_tail; -static struct svc_cacherep * nfscache; +static struct hlist_head * hash_list; +static struct list_head lru_head; static int cache_disabled = 1; static int nfsd_cache_append(struct svc_rqst *rqstp, struct kvec *vec); @@ -54,46 +48,32 @@ void nfsd_cache_init(void) { struct svc_cacherep *rp; - struct nfscache_head *rh; - size_t i; - unsigned long order; - - - i = CACHESIZE * sizeof (struct svc_cacherep); - for (order = 0; (PAGE_SIZE << order) < i; order++) - ; - nfscache = (struct svc_cacherep *) - __get_free_pages(GFP_KERNEL, order); - if (!nfscache) { - printk (KERN_ERR "nfsd: cannot allocate %Zd bytes for reply cache\n", i); - return; + int i; + + INIT_LIST_HEAD(&lru_head); + i = CACHESIZE; + while(i) { + rp = kmalloc(sizeof(*rp), GFP_KERNEL); + if (!rp) break; + list_add(&rp->c_lru, &lru_head); + rp->c_state = RC_UNUSED; + rp->c_type = RC_NOCACHE; + INIT_HLIST_NODE(&rp->c_hash); + i--; } - memset(nfscache, 0, i); - i = HASHSIZE * sizeof (struct nfscache_head); - hash_list = kmalloc (i, GFP_KERNEL); + if (i) + printk (KERN_ERR "nfsd: cannot allocate all %d cache entries, only got %d\n", + CACHESIZE, CACHESIZE-i); + + hash_list = kmalloc (HASHSIZE * sizeof(struct hlist_head), GFP_KERNEL); if (!hash_list) { - free_pages ((unsigned long)nfscache, order); - nfscache = NULL; - printk (KERN_ERR "nfsd: cannot allocate %Zd bytes for hash list\n", i); + nfsd_cache_shutdown(); + printk (KERN_ERR "nfsd: cannot allocate %Zd bytes for hash list\n", + HASHSIZE * sizeof(struct hlist_head)); return; } - - for (i = 0, rh = hash_list; i < HASHSIZE; i++, rh++) - rh->next = rh->prev = (struct svc_cacherep *) rh; - - for (i = 0, rp = nfscache; i < CACHESIZE; i++, rp++) { - rp->c_state = RC_UNUSED; - rp->c_type = RC_NOCACHE; - rp->c_hash_next = - rp->c_hash_prev = rp; - rp->c_lru_next = rp + 1; - rp->c_lru_prev = rp - 1; - } - lru_head = nfscache; - lru_tail = nfscache + CACHESIZE - 1; - lru_head->c_lru_prev = NULL; - lru_tail->c_lru_next = NULL; + memset(hash_list, 0, HASHSIZE * sizeof(struct hlist_head)); cache_disabled = 0; } @@ -102,48 +82,28 @@ void nfsd_cache_shutdown(void) { struct svc_cacherep *rp; - size_t i; - unsigned long order; - for (rp = lru_head; rp; rp = rp->c_lru_next) { + while (!list_empty(&lru_head)) { + rp = list_entry(lru_head.next, struct svc_cacherep, c_lru); if (rp->c_state == RC_DONE && rp->c_type == RC_REPLBUFF) kfree(rp->c_replvec.iov_base); + list_del(&rp->c_lru); + kfree(rp); } cache_disabled = 1; - i = CACHESIZE * sizeof (struct svc_cacherep); - for (order = 0; (PAGE_SIZE << order) < i; order++) - ; - free_pages ((unsigned long)nfscache, order); - nfscache = NULL; kfree (hash_list); hash_list = NULL; } /* - * Move cache entry to front of LRU list + * Move cache entry to end of LRU list */ static void -lru_put_front(struct svc_cacherep *rp) +lru_put_end(struct svc_cacherep *rp) { - struct svc_cacherep *prev = rp->c_lru_prev, - *next = rp->c_lru_next; - - if (prev) - prev->c_lru_next = next; - else - lru_head = next; - if (next) - next->c_lru_prev = prev; - else - lru_tail = prev; - - rp->c_lru_next = lru_head; - rp->c_lru_prev = NULL; - if (lru_head) - lru_head->c_lru_prev = rp; - lru_head = rp; + list_move_tail(&rp->c_lru, &lru_head); } /* @@ -152,17 +112,8 @@ lru_put_front(struct svc_cacherep *rp) static void hash_refile(struct svc_cacherep *rp) { - struct svc_cacherep *prev = rp->c_hash_prev, - *next = rp->c_hash_next; - struct nfscache_head *head = hash_list + REQHASH(rp->c_xid); - - prev->c_hash_next = next; - next->c_hash_prev = prev; - - rp->c_hash_next = head->next; - rp->c_hash_prev = (struct svc_cacherep *) head; - head->next->c_hash_prev = rp; - head->next = rp; + hlist_del_init(&rp->c_hash); + hlist_add_head(&rp->c_hash, hash_list + REQHASH(rp->c_xid)); } /* @@ -173,7 +124,9 @@ hash_refile(struct svc_cacherep *rp) int nfsd_cache_lookup(struct svc_rqst *rqstp, int type) { - struct svc_cacherep *rh, *rp; + struct hlist_node *hn; + struct hlist_head *rh; + struct svc_cacherep *rp; u32 xid = rqstp->rq_xid, proto = rqstp->rq_prot, vers = rqstp->rq_vers, @@ -190,8 +143,8 @@ nfsd_cache_lookup(struct svc_rqst *rqstp, int type) spin_lock(&cache_lock); rtn = RC_DOIT; - rp = rh = (struct svc_cacherep *) &hash_list[REQHASH(xid)]; - while ((rp = rp->c_hash_next) != rh) { + rh = &hash_list[REQHASH(xid)]; + hlist_for_each_entry(rp, hn, rh, c_hash) { if (rp->c_state != RC_UNUSED && xid == rp->c_xid && proc == rp->c_proc && proto == rp->c_prot && vers == rp->c_vers && @@ -206,7 +159,7 @@ nfsd_cache_lookup(struct svc_rqst *rqstp, int type) /* This loop shouldn't take more than a few iterations normally */ { int safe = 0; - for (rp = lru_tail; rp; rp = rp->c_lru_prev) { + list_for_each_entry(rp, &lru_head, c_lru) { if (rp->c_state != RC_INPROG) break; if (safe++ > CACHESIZE) { @@ -254,7 +207,7 @@ found_entry: /* We found a matching entry which is either in progress or done. */ age = jiffies - rp->c_timestamp; rp->c_timestamp = jiffies; - lru_put_front(rp); + lru_put_end(rp); rtn = RC_DROPIT; /* Request being processed or excessive rexmits */ @@ -343,7 +296,7 @@ nfsd_cache_update(struct svc_rqst *rqstp, int cachetype, u32 *statp) break; } spin_lock(&cache_lock); - lru_put_front(rp); + lru_put_end(rp); rp->c_secure = rqstp->rq_secure; rp->c_type = cachetype; rp->c_state = RC_DONE;