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