Exemple #1
0
/*
 * Force the next attempt to use the cache to be a timeout.
 * If we can't find the page that's fine, it will cause a refresh.
 */
void
smb_invalid_dir_cache(struct inode * dir)
{
	struct smb_sb_info *server = server_from_inode(dir);
	union  smb_dir_cache *cache = NULL;
	struct page *page = NULL;

	page = grab_cache_page(&dir->i_data, 0);
	if (!page)
		goto out;

	if (!PageUptodate(page))
		goto out_unlock;

	cache = kmap(page);
	cache->head.time = jiffies - SMB_MAX_AGE(server);

	kunmap(page);
	SetPageUptodate(page);
out_unlock:
	unlock_page(page);
	page_cache_release(page);
out:
	return;
}
Exemple #2
0
/*
 * This is the callback when the dcache has a lookup hit.
 */
static int
smb_lookup_validate(struct dentry * dentry, struct nameidata *nd)
{
    struct smb_sb_info *server = server_from_dentry(dentry);
    struct inode * inode = dentry->d_inode;
    unsigned long age = jiffies - dentry->d_time;
    int valid;

    /*
     * The default validation is based on dentry age:
     * we believe in dentries for a few seconds.  (But each
     * successful server lookup renews the timestamp.)
     */
    valid = (age <= SMB_MAX_AGE(server));
#ifdef SMBFS_DEBUG_VERBOSE
    if (!valid)
        VERBOSE("%s/%s not valid, age=%lu\n", 
            DENTRY_PATH(dentry), age);
#endif

    if (inode) {
        lock_kernel();
        if (is_bad_inode(inode)) {
            PARANOIA("%s/%s has dud inode\n", DENTRY_PATH(dentry));
            valid = 0;
        } else if (!valid)
            valid = (smb_revalidate_inode(dentry) == 0);
        unlock_kernel();
    } else {
        /*
         * What should we do for negative dentries?
         */
    }
    return valid;
}
Exemple #3
0
/*
 * This is called when we want to check whether the inode
 * has changed on the server.  If it has changed, we must
 * invalidate our local caches.
 */
int
smb_revalidate_inode(struct dentry *dentry)
{
	struct smb_sb_info *s = server_from_dentry(dentry);
	struct inode *inode = dentry->d_inode;
	int error = 0;

	DEBUG1("smb_revalidate_inode\n");
	lock_kernel();

	/*
	 * Check whether we've recently refreshed the inode.
	 */
	if (time_before(jiffies, SMB_I(inode)->oldmtime + SMB_MAX_AGE(s))) {
		VERBOSE("up-to-date, ino=%ld, jiffies=%lu, oldtime=%lu\n",
			inode->i_ino, jiffies, SMB_I(inode)->oldmtime);
		goto out;
	}

	error = smb_refresh_inode(dentry);
out:
	unlock_kernel();
	return error;
}
Exemple #4
0
/*
 * Read a directory, using filldir to fill the dirent memory.
 * smb_proc_readdir does the actual reading from the smb server.
 *
 * The cache code is almost directly taken from ncpfs
 */
static int 
smb_readdir(struct file *filp, void *dirent, filldir_t filldir)
{
    struct dentry *dentry = filp->f_path.dentry;
    struct inode *dir = dentry->d_inode;
    struct smb_sb_info *server = server_from_dentry(dentry);
    union  smb_dir_cache *cache = NULL;
    struct smb_cache_control ctl;
    struct page *page = NULL;
    int result;

    ctl.page  = NULL;
    ctl.cache = NULL;

    VERBOSE("reading %s/%s, f_pos=%d\n",
        DENTRY_PATH(dentry),  (int) filp->f_pos);

    result = 0;

    lock_kernel();

    switch ((unsigned int) filp->f_pos) {
    case 0:
        if (filldir(dirent, ".", 1, 0, dir->i_ino, DT_DIR) < 0)
            goto out;
        filp->f_pos = 1;
        /* fallthrough */
    case 1:
        if (filldir(dirent, "..", 2, 1, parent_ino(dentry), DT_DIR) < 0)
            goto out;
        filp->f_pos = 2;
    }

    /*
     * Make sure our inode is up-to-date.
     */
    result = smb_revalidate_inode(dentry);
    if (result)
        goto out;


    page = grab_cache_page(&dir->i_data, 0);
    if (!page)
        goto read_really;

    ctl.cache = cache = kmap(page);
    ctl.head  = cache->head;

    if (!PageUptodate(page) || !ctl.head.eof) {
        VERBOSE("%s/%s, page uptodate=%d, eof=%d\n",
             DENTRY_PATH(dentry), PageUptodate(page),ctl.head.eof);
        goto init_cache;
    }

    if (filp->f_pos == 2) {
        if (jiffies - ctl.head.time >= SMB_MAX_AGE(server))
            goto init_cache;

        /*
         * N.B. ncpfs checks mtime of dentry too here, we don't.
         *   1. common smb servers do not update mtime on dir changes
         *   2. it requires an extra smb request
         *      (revalidate has the same timeout as ctl.head.time)
         *
         * Instead smbfs invalidates its own cache on local changes
         * and remote changes are not seen until timeout.
         */
    }

    if (filp->f_pos > ctl.head.end)
        goto finished;

    ctl.fpos = filp->f_pos + (SMB_DIRCACHE_START - 2);
    ctl.ofs  = ctl.fpos / SMB_DIRCACHE_SIZE;
    ctl.idx  = ctl.fpos % SMB_DIRCACHE_SIZE;

    for (;;) {
        if (ctl.ofs != 0) {
            ctl.page = find_lock_page(&dir->i_data, ctl.ofs);
            if (!ctl.page)
                goto invalid_cache;
            ctl.cache = kmap(ctl.page);
            if (!PageUptodate(ctl.page))
                goto invalid_cache;
        }
        while (ctl.idx < SMB_DIRCACHE_SIZE) {
            struct dentry *dent;
            int res;

            dent = smb_dget_fpos(ctl.cache->dentry[ctl.idx],
                         dentry, filp->f_pos);
            if (!dent)
                goto invalid_cache;

            res = filldir(dirent, dent->d_name.name,
                      dent->d_name.len, filp->f_pos,
                      dent->d_inode->i_ino, DT_UNKNOWN);
            dput(dent);
            if (res)
                goto finished;
            filp->f_pos += 1;
            ctl.idx += 1;
            if (filp->f_pos > ctl.head.end)
                goto finished;
        }
        if (ctl.page) {
            kunmap(ctl.page);
            SetPageUptodate(ctl.page);
            unlock_page(ctl.page);
            page_cache_release(ctl.page);
            ctl.page = NULL;
        }
        ctl.idx  = 0;
        ctl.ofs += 1;
    }
invalid_cache:
    if (ctl.page) {
        kunmap(ctl.page);
        unlock_page(ctl.page);
        page_cache_release(ctl.page);
        ctl.page = NULL;
    }
    ctl.cache = cache;
init_cache:
    smb_invalidate_dircache_entries(dentry);
    ctl.head.time = jiffies;
    ctl.head.eof = 0;
    ctl.fpos = 2;
    ctl.ofs = 0;
    ctl.idx = SMB_DIRCACHE_START;
    ctl.filled = 0;
    ctl.valid  = 1;
read_really:
    result = server->ops->readdir(filp, dirent, filldir, &ctl);
    if (result == -ERESTARTSYS && page)
        ClearPageUptodate(page);
    if (ctl.idx == -1)
        goto invalid_cache;    /* retry */
    ctl.head.end = ctl.fpos - 1;
    ctl.head.eof = ctl.valid;
finished:
    if (page) {
        cache->head = ctl.head;
        kunmap(page);
        if (result != -ERESTARTSYS)
            SetPageUptodate(page);
        unlock_page(page);
        page_cache_release(page);
    }
    if (ctl.page) {
        kunmap(ctl.page);
        SetPageUptodate(ctl.page);
        unlock_page(ctl.page);
        page_cache_release(ctl.page);
    }
out:
    unlock_kernel();
    return result;
}