Esempio n. 1
0
/* 
 * Write to a file (through the page cache).
 */
static ssize_t
smb_file_write(struct file *file, const char *buf, size_t count, loff_t *ppos)
{
	struct dentry * dentry = file->f_dentry;
	ssize_t	result;

	VERBOSE("file %s/%s, count=%lu@%lu\n",
		DENTRY_PATH(dentry),
		(unsigned long) count, (unsigned long) *ppos);

	result = smb_revalidate_inode(dentry);
	if (result) {
		PARANOIA("%s/%s validation failed, error=%Zd\n",
			 DENTRY_PATH(dentry), result);
		goto out;
	}

	result = smb_open(dentry, SMB_O_WRONLY);
	if (result)
		goto out;

	if (count > 0) {
		result = generic_file_write(file, buf, count, ppos);
		VERBOSE("pos=%ld, size=%ld, mtime=%ld, atime=%ld\n",
			(long) file->f_pos, (long) dentry->d_inode->i_size,
			dentry->d_inode->i_mtime, dentry->d_inode->i_atime);
	}
out:
	return result;
}
Esempio n. 2
0
static ssize_t
smb_file_aio_read(struct kiocb *iocb, const struct iovec *iov,
			unsigned long nr_segs, loff_t pos)
{
	struct file * file = iocb->ki_filp;
	struct dentry * dentry = file->f_path.dentry;
	ssize_t	status;

	VERBOSE("file %s/%s, count=%lu@%lu\n", DENTRY_PATH(dentry),
		(unsigned long) iocb->ki_left, (unsigned long) pos);

	status = smb_revalidate_inode(dentry);
	if (status) {
		PARANOIA("%s/%s validation failed, error=%Zd\n",
			 DENTRY_PATH(dentry), status);
		goto out;
	}

	VERBOSE("before read, size=%ld, flags=%x, atime=%ld\n",
		(long)dentry->d_inode->i_size,
		dentry->d_inode->i_flags, dentry->d_inode->i_atime.tv_sec);

	status = generic_file_aio_read(iocb, iov, nr_segs, pos);
out:
	return status;
}
Esempio n. 3
0
File: dir.c Progetto: 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;
}
Esempio n. 4
0
/* 
 * Write to a file (through the page cache).
 */
static ssize_t
smb_file_aio_write(struct kiocb *iocb, const struct iovec *iov,
			       unsigned long nr_segs, loff_t pos)
{
	struct file * file = iocb->ki_filp;
	struct dentry * dentry = file->f_path.dentry;
	ssize_t	result;

	VERBOSE("file %s/%s, count=%lu@%lu\n",
		DENTRY_PATH(dentry),
		(unsigned long) iocb->ki_left, (unsigned long) pos);

	result = smb_revalidate_inode(dentry);
	if (result) {
		PARANOIA("%s/%s validation failed, error=%Zd\n",
			 DENTRY_PATH(dentry), result);
		goto out;
	}

	result = smb_open(dentry, SMB_O_WRONLY);
	if (result)
		goto out;

	if (iocb->ki_left > 0) {
		result = generic_file_aio_write(iocb, iov, nr_segs, pos);
		VERBOSE("pos=%ld, size=%ld, mtime=%ld, atime=%ld\n",
			(long) file->f_pos, (long) dentry->d_inode->i_size,
			dentry->d_inode->i_mtime, dentry->d_inode->i_atime);
	}
out:
	return result;
}
Esempio n. 5
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;
}
Esempio n. 6
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);
}
Esempio n. 7
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;
}
Esempio n. 8
0
static int
smb_file_mmap(struct file * file, struct vm_area_struct * vma)
{
	struct dentry * dentry = file->f_dentry;
	int	status;

	VERBOSE("file %s/%s, address %lu - %lu\n",
		DENTRY_PATH(dentry), vma->vm_start, vma->vm_end);

	status = smb_revalidate_inode(dentry);
	if (status) {
		PARANOIA("%s/%s validation failed, error=%d\n",
			 DENTRY_PATH(dentry), status);
		goto out;
	}
	status = generic_file_mmap(file, vma);
out:
	return status;
}
Esempio n. 9
0
static int
smb_updatepage(struct file *file, struct page *page, unsigned long offset,
	       unsigned int count)
{
	struct dentry *dentry = file->f_dentry;

	DEBUG1("(%s/%s %d@%ld)\n", DENTRY_PATH(dentry), 
	       count, (page->index << PAGE_CACHE_SHIFT)+offset);

	return smb_writepage_sync(dentry->d_inode, page, offset, count);
}
Esempio n. 10
0
static ssize_t
smb_file_sendfile(struct file *file, loff_t *ppos,
		  size_t count, read_actor_t actor, void *target)
{
	struct dentry *dentry = file->f_path.dentry;
	ssize_t status;

	VERBOSE("file %s/%s, pos=%Ld, count=%d\n",
		DENTRY_PATH(dentry), *ppos, count);

	status = smb_revalidate_inode(dentry);
	if (status) {
		PARANOIA("%s/%s validation failed, error=%Zd\n",
			 DENTRY_PATH(dentry), status);
		goto out;
	}
	status = generic_file_sendfile(file, ppos, count, actor, target);
out:
	return status;
}
Esempio n. 11
0
int
smb_refill_dircache(struct cache_head * cachep, struct dentry *dentry)
{
	struct inode * inode = dentry->d_inode;
	int result;

	VERBOSE("cache %s/%s, blocks=%d\n", DENTRY_PATH(dentry), cachep->pages);
	/*
	 * Fill the cache, starting at position 2.
	 */
retry:
	inode->u.smbfs_i.cache_valid |= SMB_F_CACHEVALID;
	result = smb_proc_readdir(dentry, 2, cachep);
	if (result < 0)
	{
		PARANOIA("readdir failed, result=%d\n", result);
		goto out;
	}

	/*
	 * Check whether the cache was invalidated while
	 * we were doing the scan ...
	 */
	if (!(inode->u.smbfs_i.cache_valid & SMB_F_CACHEVALID))
	{
		PARANOIA("cache invalidated, retrying\n");
		goto retry;
	}

	result = cachep->status;
	if (!result)
	{
		cachep->valid = 1;
		cachep->mtime = dentry->d_inode->i_mtime;
	}
	VERBOSE("cache %s/%s status=%d, entries=%d\n",
		DENTRY_PATH(dentry), cachep->status, cachep->entries);

out:
	return result;
}
Esempio n. 12
0
static ssize_t
smb_file_splice_read(struct file *file, loff_t *ppos,
		     struct pipe_inode_info *pipe, size_t count,
		     unsigned int flags)
{
	struct dentry *dentry = file->f_path.dentry;
	ssize_t status;

	VERBOSE("file %s/%s, pos=%Ld, count=%lu\n",
		DENTRY_PATH(dentry), *ppos, count);

	status = smb_revalidate_inode(dentry);
	if (status) {
		PARANOIA("%s/%s validation failed, error=%Zd\n",
			 DENTRY_PATH(dentry), status);
		goto out;
	}
	status = generic_file_splice_read(file, ppos, pipe, count, flags);
out:
	return status;
}
Esempio n. 13
0
/*
 * Get a pointer to the cache_head structure,
 * mapped as the page at offset 0. The page is
 * kept locked while we're using the cache.
 */
struct cache_head *
smb_get_dircache(struct dentry * dentry)
{
	struct inode * inode = dentry->d_inode;
	struct cache_head * cachep;

	VERBOSE("finding cache for %s/%s\n", DENTRY_PATH(dentry));
	cachep = (struct cache_head *) get_cached_page(inode, 0, 1);
	if (!cachep)
		goto out;
	if (cachep->valid)
	{
		struct cache_index * index = cachep->index;
		struct cache_block * block;
		unsigned long offset;
		int i;

		cachep->valid = 0;
		/*
		 * Here we only want to find existing cache blocks,
		 * not add new ones.
		 */
		for (i = 0; i < cachep->pages; i++, index++) {
#ifdef SMBFS_PARANOIA
			if (index->block)
				PARANOIA("cache %s/%s has existing block!\n",
					 DENTRY_PATH(dentry));
#endif
			offset = PAGE_SIZE + (i << PAGE_SHIFT);
			block = (struct cache_block *) get_cached_page(inode,
								offset, 0);
			if (!block)
				goto out;
			index->block = block;
		}
		cachep->valid = 1;
	}
out:
	return cachep;
}
Esempio n. 14
0
/*
 * This is called to update the inode attributes after
 * we've made changes to a file or directory.
 */
static int
smb_refresh_inode(struct dentry *dentry)
{
	struct inode *inode = dentry->d_inode;
	int error;
	struct smb_fattr fattr;

	error = smb_proc_getattr(dentry, &fattr);
	if (!error) {
		smb_renew_times(dentry);
		/*
		 * Check whether the type part of the mode changed,
		 * and don't update the attributes if it did.
		 *
		 * And don't dick with the root inode
		 */
		if (inode->i_ino == 2)
			return error;
		if (S_ISLNK(inode->i_mode))
			return error;	/* VFS will deal with it */

		if ((inode->i_mode & S_IFMT) == (fattr.f_mode & S_IFMT)) {
			smb_set_inode_attr(inode, &fattr);
		} else {
			/*
			 * Big trouble! The inode has become a new object,
			 * so any operations attempted on it are invalid.
			 *
			 * To limit damage, mark the inode as bad so that
			 * subsequent lookup validations will fail.
			 */
			PARANOIA("%s/%s changed mode, %07o to %07o\n",
				 DENTRY_PATH(dentry),
				 inode->i_mode, fattr.f_mode);

			fattr.f_mode = inode->i_mode; /* save mode */
			make_bad_inode(inode);
			inode->i_mode = fattr.f_mode; /* restore mode */
			/*
			 * No need to worry about unhashing the dentry: the
			 * lookup validation will see that the inode is bad.
			 * But we do want to invalidate the caches ...
			 */
			if (!S_ISDIR(inode->i_mode))
				invalidate_remote_inode(inode);
			else
				smb_invalid_dir_cache(inode);
			error = -EIO;
		}
	}
	return error;
}
Esempio n. 15
0
static ssize_t
smb_file_read(struct file * file, char * buf, size_t count, loff_t *ppos)
{
	struct dentry * dentry = file->f_dentry;
	ssize_t	status;

	VERBOSE("file %s/%s, count=%lu@%lu\n", DENTRY_PATH(dentry),
		(unsigned long) count, (unsigned long) *ppos);

	status = smb_revalidate_inode(dentry);
	if (status) {
		PARANOIA("%s/%s validation failed, error=%Zd\n",
			 DENTRY_PATH(dentry), status);
		goto out;
	}

	VERBOSE("before read, size=%ld, flags=%x, atime=%ld\n",
		(long)dentry->d_inode->i_size,
		dentry->d_inode->i_flags, dentry->d_inode->i_atime);

	status = generic_file_read(file, buf, count, ppos);
out:
	return status;
}
Esempio n. 16
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;
}
Esempio n. 17
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;
}
Esempio n. 18
0
File: dir.c Progetto: 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;
}
Esempio n. 19
0
static int 
smb_readdir(struct file *filp, void *dirent, filldir_t filldir)
{
	struct dentry *dentry = filp->f_dentry;
	struct inode *dir = dentry->d_inode;
	struct cache_head *cachep = NULL;
	int result;

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

	result = 0;
	switch ((unsigned int) filp->f_pos)
	{
	case 0:
		if (filldir(dirent, ".", 1, 0, dir->i_ino) < 0)
			goto out;
		filp->f_pos = 1;
	case 1:
		if (filldir(dirent, "..", 2, 1,
				dentry->d_parent->d_inode->i_ino) < 0)
			goto out;
		filp->f_pos = 2;
	}

	/*
	 * Make sure our inode is up-to-date.
	 */
	result = smb_revalidate_inode(dentry);
	if (result)
		goto out;
	/*
	 * Get the cache pointer ...
	 */
	result = -EIO;
	cachep = smb_get_dircache(dentry);
	if (!cachep)
		goto out;
	/*
	 * Make sure the cache is up-to-date.
	 *
	 * To detect changes on the server we refill on each "new" access.
	 *
	 * Directory mtime would be nice to use for finding changes,
	 * unfortunately some servers (NT4) doesn't update on local changes.
	 */
	if (!cachep->valid || filp->f_pos == 2)
	{
		result = smb_refill_dircache(cachep, dentry);
		if (result)
			goto out;
	}

	result = 0;

	while (1)
	{
		struct cache_dirent this_dirent, *entry = &this_dirent;

		if (!smb_find_in_cache(cachep, filp->f_pos, entry))
			break;
		/*
		 * Check whether to look up the inode number.
		 */
		if (!entry->ino) {
			struct qstr qname;
			/* N.B. Make cache_dirent name a qstr! */
			qname.name = entry->name;
			qname.len  = entry->len;
			entry->ino = find_inode_number(dentry, &qname);
			if (!entry->ino)
				entry->ino = smb_invent_inos(1);
		}

		if (filldir(dirent, entry->name, entry->len, 
				    filp->f_pos, entry->ino) < 0)
			break;
		filp->f_pos += 1;
	}

	/*
	 * Release the dircache.
	 */
out:
	if (cachep) {
		smb_free_dircache(cachep);
	}
	return result;
}