~ [ source navigation ] ~ [ diff markup ] ~ [ identifier search ] ~ [ freetext search ] ~ [ file search ] ~

Linux Cross Reference
Linux/fs/smbfs/cache.c

Version: ~ [ 2.4.0 ] ~
Architecture: ~ [ i386 ] ~ [ alpha ] ~ [ m68k ] ~ [ mips ] ~ [ ppc ] ~ [ sparc ] ~ [ sparc64 ] ~

  1 /*
  2  *  cache.c
  3  *
  4  * Copyright (C) 1997 by Bill Hawes
  5  *
  6  * Routines to support directory cacheing using the page cache.
  7  * Right now this only works for smbfs, but will be generalized
  8  * for use with other filesystems.
  9  *
 10  * Please add a note about your changes to smbfs in the ChangeLog file.
 11  */
 12 
 13 #include <linux/sched.h>
 14 #include <linux/errno.h>
 15 #include <linux/kernel.h>
 16 #include <linux/mm.h>
 17 #include <linux/dirent.h>
 18 #include <linux/smb_fs.h>
 19 #include <linux/pagemap.h>
 20 
 21 #include <asm/page.h>
 22 
 23 #include "smb_debug.h"
 24 
 25 
 26 static inline struct address_space * 
 27 get_cache_inode(struct cache_head *cachep)
 28 {
 29         return page_cache_entry((unsigned long) cachep)->mapping;
 30 }
 31 
 32 /*
 33  * Try to reassemble the old dircache. If we fail - set ->valid to 0.
 34  * In any case, get at least the page at offset 0 (with ->valid==0 if
 35  * the old one didn't make it, indeed).
 36  */
 37 struct cache_head *
 38 smb_get_dircache(struct dentry * dentry)
 39 {
 40         struct address_space * mapping = &dentry->d_inode->i_data;
 41         struct cache_head * cachep = NULL;
 42         struct page *page;
 43 
 44         page = find_lock_page(mapping, 0);
 45         if (!page) {
 46                 /* Sorry, not even page 0 around */
 47                 page = grab_cache_page(mapping, 0);
 48                 if (!page)
 49                         goto out;
 50                 cachep = kmap(page);
 51                 memset((char*)cachep, 0, PAGE_SIZE);
 52                 goto out;
 53         }
 54         cachep = kmap(page);
 55         if (cachep->valid) {
 56                 /*
 57                  * OK, at least the page 0 survived and seems to be promising.
 58                  * Let's try to reassemble the rest.
 59                  */
 60                 struct cache_index * index = cachep->index;
 61                 unsigned long offset;
 62                 int i;
 63 
 64                 for (offset = 0, i = 0; i < cachep->pages; i++, index++) {
 65                         offset += PAGE_SIZE;
 66                         page = find_lock_page(mapping,offset>>PAGE_CACHE_SHIFT);
 67                         if (!page) {
 68                                 /* Alas, poor Yorick */
 69                                 cachep->valid = 0;
 70                                 goto out;
 71                         }
 72                         index->block = kmap(page);
 73                 }
 74         }
 75 out:
 76         return cachep;
 77 }
 78 
 79 /*
 80  * Unlock and release the data blocks.
 81  */
 82 static void
 83 smb_free_cache_blocks(struct cache_head * cachep)
 84 {
 85         struct cache_index * index = cachep->index;
 86         struct page * page;
 87         int i;
 88 
 89         VERBOSE("freeing %d blocks\n", cachep->pages);
 90         for (i = 0; i < cachep->pages; i++, index++) {
 91                 if (!index->block)
 92                         continue;
 93                 page = page_cache_entry((unsigned long) index->block);
 94                 index->block = NULL;
 95                 kunmap(page);
 96                 UnlockPage(page);
 97                 page_cache_release(page);
 98         }
 99 }
100 
101 /*
102  * Unlocks and releases the dircache.
103  */
104 void
105 smb_free_dircache(struct cache_head * cachep)
106 {
107         struct page *page;
108         VERBOSE("freeing cache\n");
109         smb_free_cache_blocks(cachep);
110         page = page_cache_entry((unsigned long) cachep);
111         kunmap(page);
112         UnlockPage(page);
113         page_cache_release(page);
114 }
115 
116 /*
117  * Initializes the dircache. We release any existing data blocks,
118  * and then clear the cache_head structure.
119  */
120 void
121 smb_init_dircache(struct cache_head * cachep)
122 {
123         VERBOSE("initializing cache, %d blocks\n", cachep->pages);
124         smb_free_cache_blocks(cachep);
125         memset(cachep, 0, sizeof(struct cache_head));
126 }
127 
128 /*
129  * Add a new entry to the cache.  This assumes that the
130  * entries are coming in order and are added to the end.
131  */
132 void
133 smb_add_to_cache(struct cache_head * cachep, struct cache_dirent *entry,
134                         off_t fpos)
135 {
136         struct address_space * mapping = get_cache_inode(cachep);
137         struct cache_index * index;
138         struct cache_block * block;
139         struct page *page;
140         unsigned long page_off;
141         unsigned int nent, offset, len = entry->len;
142         unsigned int needed = len + sizeof(struct cache_entry);
143 
144         VERBOSE("cache %p, status %d, adding %.*s at %ld\n",
145                 mapping, cachep->status, entry->len, entry->name, fpos);
146 
147         /*
148          * Don't do anything if we've had an error ...
149          */
150         if (cachep->status)
151                 goto out;
152 
153         index = &cachep->index[cachep->idx];
154         if (!index->block)
155                 goto get_block;
156 
157         /* space available? */
158         if (needed < index->space) {
159         add_entry:
160                 nent = index->num_entries;
161                 index->num_entries++;
162                 index->space -= needed;
163                 offset = index->space + 
164                          index->num_entries * sizeof(struct cache_entry);
165                 block = index->block;
166                 memcpy(&block->cb_data.names[offset], entry->name, len);
167                 block->cb_data.table[nent].namelen = len;
168                 block->cb_data.table[nent].offset = offset;
169                 block->cb_data.table[nent].ino = entry->ino;
170                 cachep->entries++;
171 
172                 VERBOSE("added entry %.*s, len=%d, pos=%ld, entries=%d\n",
173                         entry->len, entry->name, len, fpos, cachep->entries);
174                 return;
175         }
176         /*
177          * This block is full ... advance the index.
178          */
179         cachep->idx++;
180         if (cachep->idx > NINDEX) /* not likely */
181                 goto out_full;
182         index++;
183         /*
184          * Get the next cache block. We don't care for its contents.
185          */
186 get_block:
187         cachep->pages++;
188         page_off = PAGE_SIZE + (cachep->idx << PAGE_SHIFT);
189         page = grab_cache_page(mapping, page_off>>PAGE_CACHE_SHIFT);
190         if (page) {
191                 block = kmap(page);
192                 index->block = block;
193                 index->space = PAGE_SIZE;
194                 goto add_entry;
195         }
196         /*
197          * On failure, just set the return status ...
198          */
199 out_full:
200         cachep->status = -ENOMEM;
201 out:
202         return;
203 }
204 
205 int
206 smb_find_in_cache(struct cache_head * cachep, off_t pos, 
207                 struct cache_dirent *entry)
208 {
209         struct cache_index * index = cachep->index;
210         struct cache_block * block;
211         unsigned int i, nent, offset = 0;
212         off_t next_pos = 2;
213 
214         VERBOSE("smb_find_in_cache: cache %p, looking for pos=%ld\n",
215                 cachep, pos);
216         for (i = 0; i < cachep->pages; i++, index++)
217         {
218                 if (pos < next_pos)
219                         break;
220                 nent = pos - next_pos;
221                 next_pos += index->num_entries;
222                 if (pos >= next_pos)
223                         continue;
224                 /*
225                  * The entry is in this block. Note: we return
226                  * then name as a reference with _no_ null byte.
227                  */
228                 block = index->block;
229                 entry->ino = block->cb_data.table[nent].ino;
230                 entry->len = block->cb_data.table[nent].namelen;
231                 offset = block->cb_data.table[nent].offset;
232                 entry->name = &block->cb_data.names[offset];
233 
234                 VERBOSE("found %.*s, len=%d, pos=%ld\n",
235                         entry->len, entry->name, entry->len, pos);
236                 break;
237         }
238         return offset;
239 }
240 
241 int
242 smb_refill_dircache(struct cache_head * cachep, struct dentry *dentry)
243 {
244         struct inode * inode = dentry->d_inode;
245         int result;
246 
247         VERBOSE("smb_refill_dircache: cache %s/%s, blocks=%d\n",
248                 DENTRY_PATH(dentry), cachep->pages);
249         /*
250          * Fill the cache, starting at position 2.
251          */
252 retry:
253         inode->u.smbfs_i.cache_valid |= SMB_F_CACHEVALID;
254         result = smb_proc_readdir(dentry, 2, cachep);
255         if (result < 0)
256         {
257                 PARANOIA("readdir failed, result=%d\n", result);
258                 goto out;
259         }
260 
261         /*
262          * Check whether the cache was invalidated while
263          * we were doing the scan ...
264          */
265         if (!(inode->u.smbfs_i.cache_valid & SMB_F_CACHEVALID))
266         {
267                 PARANOIA("cache invalidated, retrying\n");
268                 goto retry;
269         }
270 
271         result = cachep->status;
272         if (!result)
273         {
274                 cachep->valid = 1;
275         }
276         VERBOSE("cache %s/%s status=%d, entries=%d\n",
277                 DENTRY_PATH(dentry), cachep->status, cachep->entries);
278 out:
279         return result;
280 }
281 
282 void
283 smb_invalid_dir_cache(struct inode * dir)
284 {
285         /*
286          * Get rid of any unlocked pages, and clear the
287          * 'valid' flag in case a scan is in progress.
288          */
289         invalidate_inode_pages(dir);
290         dir->u.smbfs_i.cache_valid &= ~SMB_F_CACHEVALID;
291         dir->u.smbfs_i.oldmtime = 0;
292 }
293 

~ [ source navigation ] ~ [ diff markup ] ~ [ identifier search ] ~ [ freetext search ] ~ [ file search ] ~

This page was automatically generated by the LXR engine.
Visit the LXR main site for more information.