Linux kernel mirror (for testing) git.kernel.org/pub/scm/linux/kernel/git/torvalds/linux.git
kernel os linux
fork

Configure Feed

Select the types of activity you want to include in your feed.

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