Example #1
0
File: dir.c Project: 274914765/C
/*
 * 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;
}
Example #2
0
/*
 * Note: in order to allow the smbclient process to open the
 * mount point, we don't revalidate if conn_pid is NULL.
 */
static int
smb_dir_open(struct inode *dir, struct file *file)
{
	struct dentry *dentry = file->f_dentry;
	struct smb_sb_info *server = server_from_dentry(dentry);
	int error = 0;
#ifdef SMBFS_DEBUG_VERBOSE
printk("smb_dir_open: (%s/%s)\n", dentry->d_parent->d_name.name, 
file->f_dentry->d_name.name);
#endif
	/*
	 * Directory timestamps in the core protocol aren't updated
	 * when a file is added, so we give them a very short TTL.
	 */
	if (server->opt.protocol < SMB_PROTOCOL_LANMAN2)
	{
		unsigned long age = jiffies - dir->u.smbfs_i.oldmtime;
		if (age > 2*HZ)
			smb_invalid_dir_cache(dir);
	}

	if (server->conn_pid)
		error = smb_revalidate_inode(dentry);
	return error;
}
Example #3
0
File: dir.c Project: 274914765/C
static int
smb_dir_open(struct inode *dir, struct file *file)
{
    struct dentry *dentry = file->f_path.dentry;
    struct smb_sb_info *server;
    int error = 0;

    VERBOSE("(%s/%s)\n", dentry->d_parent->d_name.name,
        file->f_path.dentry->d_name.name);

    /*
     * Directory timestamps in the core protocol aren't updated
     * when a file is added, so we give them a very short TTL.
     */
    lock_kernel();
    server = server_from_dentry(dentry);
    if (server->opt.protocol < SMB_PROTOCOL_LANMAN2) {
        unsigned long age = jiffies - SMB_I(dir)->oldmtime;
        if (age > 2*HZ)
            smb_invalid_dir_cache(dir);
    }

    /*
     * Note: in order to allow the smbmount process to open the
     * mount point, we only revalidate if the connection is valid or
     * if the process is trying to access something other than the root.
     */
    if (server->state == CONN_VALID || !IS_ROOT(dentry))
        error = smb_revalidate_inode(dentry);
    unlock_kernel();
    return error;
}
Example #4
0
int smb_follow_link(struct dentry *dentry, struct nameidata *nd)
{
	char *link;
	int result;

	DEBUG1("followlink of %s/%s\n", DENTRY_PATH(dentry));

	result = -ENOMEM;
	link = kmalloc(SMB_MAXNAMELEN + 1, GFP_KERNEL);
	if (!link)
		goto out;

	result = smb_proc_read_link(server_from_dentry(dentry), dentry, link,
				    SMB_MAXNAMELEN);
	if (result < 0 || result >= SMB_MAXNAMELEN)
		goto out_free;
	link[result] = 0;

	result = vfs_follow_link(nd, link);

out_free:
	kfree(link);
out:
	return result;
}
Example #5
0
int smb_symlink(struct inode *dir, struct dentry *dentry, const char *oldname)
{
	DEBUG1("create symlink %s -> %s/%s\n", oldname, DENTRY_PATH(dentry));

	smb_invalid_dir_cache(dir);
	return smb_proc_symlink(server_from_dentry(dentry), dentry, oldname);
}
Example #6
0
/*
 * Note: in order to allow the smbclient process to open the
 * mount point, we don't revalidate if conn_pid is NULL.
 */
static int
smb_dir_open(struct inode *dir, struct file *file)
{
	struct dentry *dentry = file->f_dentry;
	struct smb_sb_info *server = server_from_dentry(dentry);
	int error = 0;

	VERBOSE("(%s/%s)\n", dentry->d_parent->d_name.name, 
		file->f_dentry->d_name.name);
	if (server->conn_pid)
		error = smb_revalidate_inode(dentry);
	return error;
}
Example #7
0
/*
 * Mark all dentries for 'parent' as invalid, forcing them to be re-read
 */
void
smb_invalidate_dircache_entries(struct dentry *parent)
{
	struct smb_sb_info *server = server_from_dentry(parent);
	struct list_head *next;
	struct dentry *dentry;

	spin_lock(&dcache_lock);
	next = parent->d_subdirs.next;
	while (next != &parent->d_subdirs) {
		dentry = list_entry(next, struct dentry, d_u.d_child);
		dentry->d_fsdata = NULL;
		smb_age_dentry(server, dentry);
		next = next->next;
	}
	spin_unlock(&dcache_lock);
}
Example #8
0
/*
 * Read a page synchronously.
 */
static int
smb_readpage_sync(struct dentry *dentry, struct page *page)
{
	char *buffer = kmap(page);
	loff_t offset = (loff_t)page->index << PAGE_CACHE_SHIFT;
	struct smb_sb_info *server = server_from_dentry(dentry);
	unsigned int rsize = smb_get_rsize(server);
	int count = PAGE_SIZE;
	int result;

	VERBOSE("file %s/%s, count=%d@%ld, rsize=%d\n",
		DENTRY_PATH(dentry), count, offset, rsize);

	result = smb_open(dentry, SMB_O_RDONLY);
	if (result < 0) {
		PARANOIA("%s/%s open failed, error=%d\n",
			 DENTRY_PATH(dentry), result);
		goto io_error;
	}

	do {
		if (count < rsize)
			rsize = count;

		result = server->ops->read(dentry->d_inode,offset,rsize,buffer);
		if (result < 0)
			goto io_error;

		count -= result;
		offset += result;
		buffer += result;
		dentry->d_inode->i_atime = CURRENT_TIME;
		if (result < rsize)
			break;
	} while (count);

	memset(buffer, 0, count);
	flush_dcache_page(page);
	SetPageUptodate(page);
	result = 0;

io_error:
	kunmap(page);
	UnlockPage(page);
	return result;
}
Example #9
0
static int
smb_fsync(struct file *file, struct dentry * dentry, int datasync)
{
	struct smb_sb_info *server = server_from_dentry(dentry);
	int result;

	VERBOSE("sync file %s/%s\n", DENTRY_PATH(dentry));

	/*
	 * The VFS will writepage() all dirty pages for us, but we
	 * should send a SMBflush to the server, letting it know that
	 * we want things synchronized with actual storage.
	 *
	 * Note: this function requires all pages to have been written already
	 *       (should be ok with writepage_sync)
	 */
	result = smb_proc_flush(server, SMB_I(dentry->d_inode)->fileid);
	return result;
}
Example #10
0
static int smb_follow_link(struct dentry *dentry, struct nameidata *nd)
{
	char *link = __getname();
	DEBUG1("followlink of %s/%s\n", DENTRY_PATH(dentry));

	if (!link) {
		link = ERR_PTR(-ENOMEM);
	} else {
		int len = smb_proc_read_link(server_from_dentry(dentry),
						dentry, link, PATH_MAX - 1);
		if (len < 0) {
			__putname(link);
			link = ERR_PTR(len);
		} else {
			link[len] = 0;
		}
	}
	nd_set_link(nd, link);
	return 0;
}
Example #11
0
int smb_read_link(struct dentry *dentry, char *buffer, int len)
{
	char *link;
	int result;
	DEBUG1("read link buffer len = %d\n", len);

	result = -ENOMEM;
	link = kmalloc(SMB_MAXNAMELEN + 1, GFP_KERNEL);
	if (!link)
		goto out;

	result = smb_proc_read_link(server_from_dentry(dentry), dentry, link,
				    SMB_MAXNAMELEN);
	if (result < 0)
		goto out_free;
	result = vfs_readlink(dentry, buffer, len, link);

out_free:
	kfree(link);
out:
	return result;
}
Example #12
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;
}
Example #13
0
File: dir.c Project: 274914765/C
/*
 * 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;
}