vfs_file.c 5.8 KB
Newer Older
1 2 3 4 5 6 7 8 9
/*
 *  linux/fs/9p/vfs_file.c
 *
 * This file contians vfs file ops for 9P2000.
 *
 *  Copyright (C) 2004 by Eric Van Hensbergen <ericvh@gmail.com>
 *  Copyright (C) 2002 by Ron Minnich <rminnich@lanl.gov>
 *
 *  This program is free software; you can redistribute it and/or modify
10 11
 *  it under the terms of the GNU General Public License version 2
 *  as published by the Free Software Foundation.
12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28
 *
 *  This program is distributed in the hope that it will be useful,
 *  but WITHOUT ANY WARRANTY; without even the implied warranty of
 *  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
 *  GNU General Public License for more details.
 *
 *  You should have received a copy of the GNU General Public License
 *  along with this program; if not, write to:
 *  Free Software Foundation
 *  51 Franklin Street, Fifth Floor
 *  Boston, MA  02111-1301  USA
 *
 */

#include <linux/module.h>
#include <linux/errno.h>
#include <linux/fs.h>
29
#include <linux/sched.h>
30 31 32 33 34 35 36
#include <linux/file.h>
#include <linux/stat.h>
#include <linux/string.h>
#include <linux/inet.h>
#include <linux/list.h>
#include <asm/uaccess.h>
#include <linux/idr.h>
37 38
#include <net/9p/9p.h>
#include <net/9p/client.h>
39 40 41 42 43

#include "v9fs.h"
#include "v9fs_vfs.h"
#include "fid.h"

44 45
static const struct file_operations v9fs_cached_file_operations;

46 47 48 49 50 51 52 53 54
/**
 * v9fs_file_open - open a file (or directory)
 * @inode: inode to be opened
 * @file: file being opened
 *
 */

int v9fs_file_open(struct inode *inode, struct file *file)
{
55
	int err;
56 57 58
	struct v9fs_session_info *v9ses;
	struct p9_fid *fid;
	int omode;
59

60 61
	P9_DPRINTK(P9_DEBUG_VFS, "inode: %p file: %p \n", inode, file);
	v9ses = v9fs_inode2v9ses(inode);
62
	omode = v9fs_uflags2omode(file->f_flags, v9fs_extended(v9ses));
63 64 65 66 67 68 69
	fid = file->private_data;
	if (!fid) {
		fid = v9fs_fid_clone(file->f_path.dentry);
		if (IS_ERR(fid))
			return PTR_ERR(fid);

		err = p9_client_open(fid, omode);
70
		if (err < 0) {
71 72 73
			p9_client_clunk(fid);
			return err;
		}
74 75 76 77
		if (omode & P9_OTRUNC) {
			inode->i_size = 0;
			inode->i_blocks = 0;
		}
78 79
		if ((file->f_flags & O_APPEND) && (!v9fs_extended(v9ses)))
			generic_file_llseek(file, 0, SEEK_END);
80
	}
81

82 83 84
	file->private_data = fid;
	if ((fid->qid.version) && (v9ses->cache)) {
		P9_DPRINTK(P9_DEBUG_VFS, "cached");
85 86 87 88 89
		/* enable cached file options */
		if(file->f_op == &v9fs_file_operations)
			file->f_op = &v9fs_cached_file_operations;
	}

90
	return 0;
91 92 93 94
}

/**
 * v9fs_file_lock - lock a file (or directory)
E
Eric Van Hensbergen 已提交
95 96 97
 * @filp: file to be locked
 * @cmd: lock command
 * @fl: file lock structure
98
 *
E
Eric Van Hensbergen 已提交
99
 * Bugs: this looks like a local only lock, we should extend into 9P
100 101 102 103 104 105
 *       by using open exclusive
 */

static int v9fs_file_lock(struct file *filp, int cmd, struct file_lock *fl)
{
	int res = 0;
106
	struct inode *inode = filp->f_path.dentry->d_inode;
107

108
	P9_DPRINTK(P9_DEBUG_VFS, "filp: %p lock: %p\n", filp, fl);
109 110

	/* No mandatory locks */
111
	if (__mandatory_lock(inode))
112 113 114
		return -ENOLCK;

	if ((IS_SETLK(cmd) || IS_SETLKW(cmd)) && fl->fl_type != F_UNLCK) {
115
		filemap_write_and_wait(inode->i_mapping);
116
		invalidate_mapping_pages(&inode->i_data, 0, -1);
117 118 119 120 121 122
	}

	return res;
}

/**
123
 * v9fs_file_readn - read from a file
E
Eric Van Hensbergen 已提交
124
 * @filp: file pointer to read
125
 * @data: data buffer to read data into
126
 * @udata: user data buffer to read data into
127 128 129 130
 * @count: size of buffer
 * @offset: offset at which to read data
 *
 */
131 132 133 134 135 136 137 138 139 140 141 142 143 144 145 146 147 148 149 150 151 152 153 154 155 156 157 158 159 160 161 162 163 164 165 166 167 168 169 170 171 172 173

ssize_t
v9fs_file_readn(struct file *filp, char *data, char __user *udata, u32 count,
	       u64 offset)
{
	int n, total;
	struct p9_fid *fid = filp->private_data;

	P9_DPRINTK(P9_DEBUG_9P, "fid %d offset %llu count %d\n", fid->fid,
					(long long unsigned) offset, count);

	n = 0;
	total = 0;
	do {
		n = p9_client_read(fid, data, udata, offset, count);
		if (n <= 0)
			break;

		if (data)
			data += n;
		if (udata)
			udata += n;

		offset += n;
		count -= n;
		total += n;
	} while (count > 0 && n == (fid->clnt->msize - P9_IOHDRSZ));

	if (n < 0)
		total = n;

	return total;
}

/**
 * v9fs_file_read - read from a file
 * @filp: file pointer to read
 * @udata: user data buffer to read data into
 * @count: size of buffer
 * @offset: offset at which to read data
 *
 */

174
static ssize_t
175
v9fs_file_read(struct file *filp, char __user *udata, size_t count,
176
	       loff_t * offset)
177
{
178 179
	int ret;
	struct p9_fid *fid;
180

181
	P9_DPRINTK(P9_DEBUG_VFS, "count %d offset %lld\n", count, *offset);
182
	fid = filp->private_data;
183 184 185 186 187 188

	if (count > (fid->clnt->msize - P9_IOHDRSZ))
		ret = v9fs_file_readn(filp, NULL, udata, count, *offset);
	else
		ret = p9_client_read(fid, NULL, udata, *offset, count);

189 190
	if (ret > 0)
		*offset += ret;
191

192
	return ret;
193 194 195
}

/**
196
 * v9fs_file_write - write to a file
E
Eric Van Hensbergen 已提交
197
 * @filp: file pointer to write
198 199 200 201 202 203 204
 * @data: data buffer to write data from
 * @count: size of buffer
 * @offset: offset at which to write data
 *
 */

static ssize_t
205 206
v9fs_file_write(struct file *filp, const char __user * data,
		size_t count, loff_t * offset)
207
{
208 209
	int ret;
	struct p9_fid *fid;
210
	struct inode *inode = filp->f_path.dentry->d_inode;
211

212 213
	P9_DPRINTK(P9_DEBUG_VFS, "data %p count %d offset %x\n", data,
		(int)count, (int)*offset);
214

215
	fid = filp->private_data;
216
	ret = p9_client_write(fid, NULL, data, *offset, count);
217 218 219
	if (ret > 0) {
		invalidate_inode_pages2_range(inode->i_mapping, *offset,
								*offset+ret);
220
		*offset += ret;
221
	}
222

223 224 225 226 227
	if (*offset > inode->i_size) {
		inode->i_size = *offset;
		inode->i_blocks = (inode->i_size + 512 - 1) >> 9;
	}

228
	return ret;
229 230
}

231
static const struct file_operations v9fs_cached_file_operations = {
232 233 234 235 236 237 238
	.llseek = generic_file_llseek,
	.read = do_sync_read,
	.aio_read = generic_file_aio_read,
	.write = v9fs_file_write,
	.open = v9fs_file_open,
	.release = v9fs_dir_release,
	.lock = v9fs_file_lock,
239
	.mmap = generic_file_readonly_mmap,
240 241
};

242
const struct file_operations v9fs_file_operations = {
243 244 245 246 247 248
	.llseek = generic_file_llseek,
	.read = v9fs_file_read,
	.write = v9fs_file_write,
	.open = v9fs_file_open,
	.release = v9fs_dir_release,
	.lock = v9fs_file_lock,
249
	.mmap = generic_file_readonly_mmap,
250
};