The Design and Implementation of the FreeBSD Operating System, Second Edition
Now available: The Design and Implementation of the FreeBSD Operating System (Second Edition)


[ source navigation ] [ diff markup ] [ identifier search ] [ freetext search ] [ file search ] [ list types ] [ track identifier ]

FreeBSD/Linux Kernel Cross Reference
sys/fs/smbfs/cache.c

Version: -  FREEBSD  -  FREEBSD-13-STABLE  -  FREEBSD-13-0  -  FREEBSD-12-STABLE  -  FREEBSD-12-0  -  FREEBSD-11-STABLE  -  FREEBSD-11-0  -  FREEBSD-10-STABLE  -  FREEBSD-10-0  -  FREEBSD-9-STABLE  -  FREEBSD-9-0  -  FREEBSD-8-STABLE  -  FREEBSD-8-0  -  FREEBSD-7-STABLE  -  FREEBSD-7-0  -  FREEBSD-6-STABLE  -  FREEBSD-6-0  -  FREEBSD-5-STABLE  -  FREEBSD-5-0  -  FREEBSD-4-STABLE  -  FREEBSD-3-STABLE  -  FREEBSD22  -  l41  -  OPENBSD  -  linux-2.6  -  MK84  -  PLAN9  -  xnu-8792 
SearchContext: -  none  -  3  -  10 

    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 #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  */
   29 void
   30 smb_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 (!Page_Uptodate(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);
   48 out_unlock:
   49         UnlockPage(page);
   50         page_cache_release(page);
   51 out:
   52         return;
   53 }
   54 
   55 /*
   56  * Mark all dentries for 'parent' as invalid, forcing them to be re-read
   57  */
   58 void
   59 smb_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_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  */
   80 struct dentry *
   81 smb_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_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;
  113 out_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  */
  122 int
  123 smb_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_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                         UnlockPage(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 
  191 end_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 }

Cache object: a597f064fbb4a6fd0c601eb2824d923e


[ source navigation ] [ diff markup ] [ identifier search ] [ freetext search ] [ file search ] [ list types ] [ track identifier ]


This page is part of the FreeBSD/Linux Linux Kernel Cross-Reference, and was automatically generated using a modified version of the LXR engine.