/*
 * Write a page synchronously.
 * Offset is the data offset within the page.
 */
static int
smb_writepage_sync(struct inode *inode, struct page *page,
		   unsigned long pageoffset, unsigned int count)
{
	loff_t offset;
	char *buffer = kmap(page) + pageoffset;
	struct smb_sb_info *server = server_from_inode(inode);
	unsigned int wsize = smb_get_wsize(server);
	int ret = 0;

	offset = ((loff_t)page->index << PAGE_CACHE_SHIFT) + pageoffset;
	VERBOSE("file ino=%ld, fileid=%d, count=%d@%Ld, wsize=%d\n",
		inode->i_ino, SMB_I(inode)->fileid, count, offset, wsize);

	do {
		int write_ret;

		if (count < wsize)
			wsize = count;

		write_ret = server->ops->write(inode, offset, wsize, buffer);
		if (write_ret < 0) {
			PARANOIA("failed write, wsize=%d, write_ret=%d\n",
				 wsize, write_ret);
			ret = write_ret;
			break;
		}
		/* N.B. what if result < wsize?? */
#ifdef SMBFS_PARANOIA
		if (write_ret < wsize)
			PARANOIA("short write, wsize=%d, write_ret=%d\n",
				 wsize, write_ret);
#endif
		buffer += wsize;
		offset += wsize;
		count -= wsize;
		/*
		 * Update the inode now rather than waiting for a refresh.
		 */
		inode->i_mtime = inode->i_atime = current_fs_time(inode->i_sb);
		SMB_I(inode)->flags |= SMB_F_LOCALWRITE;
		if (offset > inode->i_size)
			inode->i_size = offset;
	} while (count);

	kunmap(page);
	return ret;
}
Exemple #2
0
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;
}
Exemple #3
0
/*
 * Copy the inode data to a smb_fattr structure.
 */
void
smb_get_inode_attr(struct inode *inode, struct smb_fattr *fattr)
{
	memset(fattr, 0, sizeof(struct smb_fattr));
	fattr->f_mode	= inode->i_mode;
	fattr->f_nlink	= inode->i_nlink;
	fattr->f_ino	= inode->i_ino;
	fattr->f_uid	= inode->i_uid;
	fattr->f_gid	= inode->i_gid;
	fattr->f_size	= inode->i_size;
	fattr->f_mtime	= inode->i_mtime;
	fattr->f_ctime	= inode->i_ctime;
	fattr->f_atime	= inode->i_atime;
	fattr->f_blksize= inode->i_blksize;
	fattr->f_blocks	= inode->i_blocks;

	fattr->attr	= SMB_I(inode)->attr;
	/*
	 * Keep the attributes in sync with the inode permissions.
	 */
	if (fattr->f_mode & S_IWUSR)
		fattr->attr &= ~aRONLY;
	else
		fattr->attr |= aRONLY;
}
Exemple #4
0
static int
smb_file_release(struct inode *inode, struct file * file)
{
	lock_kernel();
	if (!--SMB_I(inode)->openers) {
		/* We must flush any dirty pages now as we won't be able to
		   write anything after close. mmap can trigger this.
		   "openers" should perhaps include mmap'ers ... */
		filemap_write_and_wait(inode->i_mapping);
		smb_close(inode);
	}
	unlock_kernel();
	return 0;
}
Exemple #5
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 #6
0
static int
smb_file_open(struct inode *inode, struct file * file)
{
	int result;
	struct dentry *dentry = file->f_path.dentry;
	int smb_mode = (file->f_mode & O_ACCMODE) - 1;

	lock_kernel();
	result = smb_open(dentry, smb_mode);
	if (result)
		goto out;
	SMB_I(inode)->openers++;
out:
	unlock_kernel();
	return result;
}
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;
}
Exemple #8
0
/*
 * Update the inode, possibly causing it to invalidate its pages if mtime/size
 * is different from last time.
 */
void
smb_set_inode_attr(struct inode *inode, struct smb_fattr *fattr)
{
	struct smb_inode_info *ei = SMB_I(inode);

	/*
	 * A size change should have a different mtime, or same mtime
	 * but different size.
	 */
	time_t last_time = inode->i_mtime.tv_sec;
	loff_t last_sz = inode->i_size;

	inode->i_mode	= fattr->f_mode;
	inode->i_nlink	= fattr->f_nlink;
	inode->i_uid	= fattr->f_uid;
	inode->i_gid	= fattr->f_gid;
	inode->i_ctime	= fattr->f_ctime;
	inode->i_blksize= fattr->f_blksize;
	inode->i_blocks = fattr->f_blocks;
	inode->i_size	= fattr->f_size;
	inode->i_mtime	= fattr->f_mtime;
	inode->i_atime	= fattr->f_atime;
	ei->attr = fattr->attr;

	/*
	 * Update the "last time refreshed" field for revalidation.
	 */
	ei->oldmtime = jiffies;

	if (inode->i_mtime.tv_sec != last_time || inode->i_size != last_sz) {
		VERBOSE("%ld changed, old=%ld, new=%ld, oz=%ld, nz=%ld\n",
			inode->i_ino,
			(long) last_time, (long) inode->i_mtime,
			(long) last_sz, (long) inode->i_size);

		if (!S_ISDIR(inode->i_mode))
			invalidate_remote_inode(inode);
	}
}
Exemple #9
0
/* We are always generating a new inode here */
struct inode *
smb_iget(struct super_block *sb, struct smb_fattr *fattr)
{
	struct smb_sb_info *server = SMB_SB(sb);
	struct inode *result;

	DEBUG1("smb_iget: %p\n", fattr);

	result = new_inode(sb);
	if (!result)
		return result;
	result->i_ino = fattr->f_ino;
	SMB_I(result)->open = 0;
	SMB_I(result)->fileid = 0;
	SMB_I(result)->access = 0;
	SMB_I(result)->flags = 0;
	SMB_I(result)->closed = 0;
	SMB_I(result)->openers = 0;
	smb_set_inode_attr(result, fattr);
	if (S_ISREG(result->i_mode)) {
		result->i_op = &smb_file_inode_operations;
		result->i_fop = &smb_file_operations;
		result->i_data.a_ops = &smb_file_aops;
	} else if (S_ISDIR(result->i_mode)) {
		if (server->opt.capabilities & SMB_CAP_UNIX)
			result->i_op = &smb_dir_inode_operations_unix;
		else
			result->i_op = &smb_dir_inode_operations;
		result->i_fop = &smb_dir_operations;
	} else if (S_ISLNK(result->i_mode)) {
		result->i_op = &smb_link_inode_operations;
	} else {
		init_special_inode(result, result->i_mode, fattr->f_rdev);
	}
	insert_inode_hash(result);
	return result;
}
Exemple #10
0
static void smb_destroy_inode(struct inode *inode)
{
	kmem_cache_free(smb_inode_cachep, SMB_I(inode));
}