Linux kernel & device driver programming

Cross-Referenced Linux and Device Driver Code

[ source navigation ] [ diff markup ] [ identifier search ] [ freetext search ] [ file search ]
Version: [ 2.6.11.8 ] [ 2.6.25 ] [ 2.6.25.8 ] [ 2.6.31.13 ] Architecture: [ i386 ]
  1 /*
  2  *  cache.c
  3  *
  4  * Copyright (C) 1997 by Bill Hawes
  5  *
  6  * Routines to support directory cacheing using the page cache.
  7  * This cache code is almost directly taken from ncpfs.
  8  *
  9  * Please add a note about your changes to smbfs in the ChangeLog file.
 10  */
 11 
 12 #include <linux/time.h>
 13 #include <linux/errno.h>
 14 #include <linux/kernel.h>
 15 #include <linux/mm.h>
 16 #include <linux/dirent.h>
 17 #include <linux/smb_fs.h>
 18 #include <linux/pagemap.h>
 19 #include <linux/net.h>
 20 
 21 #include <asm/page.h>
 22 
 23 #include "smb_debug.h"
 24 #include "proto.h"
 25 
 26 /*
 27  * Force the next attempt to use the cache to be a timeout.
 28  * If we can't find the page that's fine, it will cause a refresh.
 29  */
 30 void
 31 smb_invalid_dir_cache(struct inode * dir)
 32 {
 33         struct smb_sb_info *server = server_from_inode(dir);
 34         union  smb_dir_cache *cache = NULL;
 35         struct page *page = NULL;
 36 
 37         page = grab_cache_page(&dir->i_data, 0);
 38         if (!page)
 39                 goto out;
 40 
 41         if (!PageUptodate(page))
 42                 goto out_unlock;
 43 
 44         cache = kmap(page);
 45         cache->head.time = jiffies - SMB_MAX_AGE(server);
 46 
 47         kunmap(page);
 48         SetPageUptodate(page);
 49 out_unlock:
 50         unlock_page(page);
 51         page_cache_release(page);
 52 out:
 53         return;
 54 }
 55 
 56 /*
 57  * Mark all dentries for 'parent' as invalid, forcing them to be re-read
 58  */
 59 void
 60 smb_invalidate_dircache_entries(struct dentry *parent)
 61 {
 62         struct smb_sb_info *server = server_from_dentry(parent);
 63         struct list_head *next;
 64         struct dentry *dentry;
 65 
 66         spin_lock(&dcache_lock);
 67         next = parent->d_subdirs.next;
 68         while (next != &parent->d_subdirs) {
 69                 dentry = list_entry(next, struct dentry, d_child);
 70                 dentry->d_fsdata = NULL;
 71                 smb_age_dentry(server, dentry);
 72                 next = next->next;
 73         }
 74         spin_unlock(&dcache_lock);
 75 }
 76 
 77 /*
 78  * dget, but require that fpos and parent matches what the dentry contains.
 79  * dentry is not known to be a valid pointer at entry.
 80  */
 81 struct dentry *
 82 smb_dget_fpos(struct dentry *dentry, struct dentry *parent, unsigned long fpos)
 83 {
 84         struct dentry *dent = dentry;
 85         struct list_head *next;
 86 
 87         if (d_validate(dent, parent)) {
 88                 if (dent->d_name.len <= SMB_MAXNAMELEN &&
 89                     (unsigned long)dent->d_fsdata == fpos) {
 90                         if (!dent->d_inode) {
 91                                 dput(dent);
 92                                 dent = NULL;
 93                         }
 94                         return dent;
 95                 }
 96                 dput(dent);
 97         }
 98 
 99         /* If a pointer is invalid, we search the dentry. */
100         spin_lock(&dcache_lock);
101         next = parent->d_subdirs.next;
102         while (next != &parent->d_subdirs) {
103                 dent = list_entry(next, struct dentry, d_child);
104                 if ((unsigned long)dent->d_fsdata == fpos) {
105                         if (dent->d_inode)
106                                 dget_locked(dent);
107                         else
108                                 dent = NULL;
109                         goto out_unlock;
110                 }
111                 next = next->next;
112         }
113         dent = NULL;
114 out_unlock:
115         spin_unlock(&dcache_lock);
116         return dent;
117 }
118 
119 
120 /*
121  * Create dentry/inode for this file and add it to the dircache.
122  */
123 int
124 smb_fill_cache(struct file *filp, void *dirent, filldir_t filldir,
125                struct smb_cache_control *ctrl, struct qstr *qname,
126                struct smb_fattr *entry)
127 {
128         struct dentry *newdent, *dentry = filp->f_dentry;
129         struct inode *newino, *inode = dentry->d_inode;
130         struct smb_cache_control ctl = *ctrl;
131         int valid = 0;
132         int hashed = 0;
133         ino_t ino = 0;
134 
135         qname->hash = full_name_hash(qname->name, qname->len);
136 
137         if (dentry->d_op && dentry->d_op->d_hash)
138                 if (dentry->d_op->d_hash(dentry, qname) != 0)
139                         goto end_advance;
140 
141         newdent = d_lookup(dentry, qname);
142 
143         if (!newdent) {
144                 newdent = d_alloc(dentry, qname);
145                 if (!newdent)
146                         goto end_advance;
147         } else {
148                 hashed = 1;
149                 memcpy((char *) newdent->d_name.name, qname->name,
150                        newdent->d_name.len);
151         }
152 
153         if (!newdent->d_inode) {
154                 smb_renew_times(newdent);
155                 entry->f_ino = iunique(inode->i_sb, 2);
156                 newino = smb_iget(inode->i_sb, entry);
157                 if (newino) {
158                         smb_new_dentry(newdent);
159                         d_instantiate(newdent, newino);
160                         if (!hashed)
161                                 d_rehash(newdent);
162                 }
163         } else
164                 smb_set_inode_attr(newdent->d_inode, entry);
165 
166         if (newdent->d_inode) {
167                 ino = newdent->d_inode->i_ino;
168                 newdent->d_fsdata = (void *) ctl.fpos;
169                 smb_new_dentry(newdent);
170         }
171 
172         if (ctl.idx >= SMB_DIRCACHE_SIZE) {
173                 if (ctl.page) {
174                         kunmap(ctl.page);
175                         SetPageUptodate(ctl.page);
176                         unlock_page(ctl.page);
177                         page_cache_release(ctl.page);
178                 }
179                 ctl.cache = NULL;
180                 ctl.idx  -= SMB_DIRCACHE_SIZE;
181                 ctl.ofs  += 1;
182                 ctl.page  = grab_cache_page(&inode->i_data, ctl.ofs);
183                 if (ctl.page)
184                         ctl.cache = kmap(ctl.page);
185         }
186         if (ctl.cache) {
187                 ctl.cache->dentry[ctl.idx] = newdent;
188                 valid = 1;
189         }
190         dput(newdent);
191 
192 end_advance:
193         if (!valid)
194                 ctl.valid = 0;
195         if (!ctl.filled && (ctl.fpos == filp->f_pos)) {
196                 if (!ino)
197                         ino = find_inode_number(dentry, qname);
198                 if (!ino)
199                         ino = iunique(inode->i_sb, 2);
200                 ctl.filled = filldir(dirent, qname->name, qname->len,
201                                      filp->f_pos, ino, DT_UNKNOWN);
202                 if (!ctl.filled)
203                         filp->f_pos += 1;
204         }
205         ctl.fpos += 1;
206         ctl.idx  += 1;
207         *ctrl = ctl;
208         return (ctl.valid || !ctl.filled);
209 }
210 
  This page was automatically generated by the LXR engine.