at v2.6.21 4.8 kB view raw
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 */ 30void 31smb_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); 49out_unlock: 50 unlock_page(page); 51 page_cache_release(page); 52out: 53 return; 54} 55 56/* 57 * Mark all dentries for 'parent' as invalid, forcing them to be re-read 58 */ 59void 60smb_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_u.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 */ 81struct dentry * 82smb_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_u.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; 114out_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 */ 123int 124smb_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_path.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 192end_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}