11da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds/*
21da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds *  file.c
31da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds *
41da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds *  Copyright (C) 1995, 1996 by Volker Lendecke
51da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds *  Modified 1997 Peter Waltenberg, Bill Hawes, David Woodhouse for 2.1 dcache
61da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds *
71da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds */
81da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
9b41f8b84d01d32ea618dbbe5679bd07ce3444b88Joe Perches#define pr_fmt(fmt) KBUILD_MODNAME ": " fmt
10b41f8b84d01d32ea618dbbe5679bd07ce3444b88Joe Perches
111da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds#include <asm/uaccess.h>
121da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
131da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds#include <linux/time.h>
141da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds#include <linux/kernel.h>
151da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds#include <linux/errno.h>
161da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds#include <linux/fcntl.h>
171da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds#include <linux/stat.h>
181da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds#include <linux/mm.h>
191da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds#include <linux/vmalloc.h>
20e8edc6e03a5c8562dc70a6d969f732bdb355a7e7Alexey Dobriyan#include <linux/sched.h>
211da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
2232c419d95f3d1da891ab9bd032a214ee05b94ed4Al Viro#include "ncp_fs.h"
231da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
2402c24a82187d5a628c68edfe71ae60dc135cd178Josef Bacikstatic int ncp_fsync(struct file *file, loff_t start, loff_t end, int datasync)
251da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds{
2602c24a82187d5a628c68edfe71ae60dc135cd178Josef Bacik	return filemap_write_and_wait_range(file->f_mapping, start, end);
271da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds}
281da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
291da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds/*
301da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * Open a file with the specified read/write mode.
311da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds */
321da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvaldsint ncp_make_open(struct inode *inode, int right)
331da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds{
341da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	int error;
351da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	int access;
361da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
371da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	error = -EINVAL;
381da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	if (!inode) {
39b41f8b84d01d32ea618dbbe5679bd07ce3444b88Joe Perches		pr_err("%s: got NULL inode\n", __func__);
401da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		goto out;
411da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	}
421da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
43d3b73ca1be3236fc33f896af7e2ba637a677d5c9Joe Perches	ncp_dbg(1, "opened=%d, volume # %u, dir entry # %u\n",
441da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		atomic_read(&NCP_FINFO(inode)->opened),
451da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		NCP_FINFO(inode)->volNumber,
461da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		NCP_FINFO(inode)->dirEntNum);
471da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	error = -EACCES;
488e3f90459b7052c31a9669417b837fb14aa6d313Ingo Molnar	mutex_lock(&NCP_FINFO(inode)->open_mutex);
491da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	if (!atomic_read(&NCP_FINFO(inode)->opened)) {
501da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		struct ncp_entry_info finfo;
511da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		int result;
521da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
531da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		/* tries max. rights */
541da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		finfo.access = O_RDWR;
551da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		result = ncp_open_create_file_or_subdir(NCP_SERVER(inode),
561da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds					inode, NULL, OC_MODE_OPEN,
571da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds					0, AR_READ | AR_WRITE, &finfo);
581da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		if (!result)
591da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds			goto update;
601da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		/* RDWR did not succeeded, try readonly or writeonly as requested */
611da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		switch (right) {
621da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds			case O_RDONLY:
631da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds				finfo.access = O_RDONLY;
641da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds				result = ncp_open_create_file_or_subdir(NCP_SERVER(inode),
651da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds					inode, NULL, OC_MODE_OPEN,
661da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds					0, AR_READ, &finfo);
671da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds				break;
681da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds			case O_WRONLY:
691da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds				finfo.access = O_WRONLY;
701da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds				result = ncp_open_create_file_or_subdir(NCP_SERVER(inode),
711da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds					inode, NULL, OC_MODE_OPEN,
721da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds					0, AR_WRITE, &finfo);
731da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds				break;
741da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		}
751da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		if (result) {
76e45ca8baa33e0c0228e84126c3a20df3abfd1771Joe Perches			ncp_vdbg("failed, result=%d\n", result);
771da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds			goto out_unlock;
781da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		}
791da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		/*
801da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		 * Update the inode information.
811da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		 */
821da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	update:
831da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		ncp_update_inode(inode, &finfo);
841da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		atomic_set(&NCP_FINFO(inode)->opened, 1);
851da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	}
861da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
871da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	access = NCP_FINFO(inode)->access;
88e45ca8baa33e0c0228e84126c3a20df3abfd1771Joe Perches	ncp_vdbg("file open, access=%x\n", access);
891da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	if (access == right || access == O_RDWR) {
901da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		atomic_inc(&NCP_FINFO(inode)->opened);
911da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		error = 0;
921da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	}
931da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
941da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvaldsout_unlock:
958e3f90459b7052c31a9669417b837fb14aa6d313Ingo Molnar	mutex_unlock(&NCP_FINFO(inode)->open_mutex);
961da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvaldsout:
971da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	return error;
981da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds}
991da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
1001da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvaldsstatic ssize_t
1011da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvaldsncp_file_read(struct file *file, char __user *buf, size_t count, loff_t *ppos)
1021da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds{
10392e5baef8578a03335059a3dec933955c361edc1Josef Sipek	struct dentry *dentry = file->f_path.dentry;
1041da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	struct inode *inode = dentry->d_inode;
1051da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	size_t already_read = 0;
1061da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	off_t pos;
1071da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	size_t bufsize;
1081da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	int error;
1091da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	void* freepage;
1101da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	size_t freelen;
1111da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
112d3b73ca1be3236fc33f896af7e2ba637a677d5c9Joe Perches	ncp_dbg(1, "enter %pd2\n", dentry);
1131da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
1141da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	pos = *ppos;
1151da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
1161da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	if ((ssize_t) count < 0) {
1171da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		return -EINVAL;
1181da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	}
1191da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	if (!count)
1201da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		return 0;
1211da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	if (pos > inode->i_sb->s_maxbytes)
1221da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		return 0;
1231da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	if (pos + count > inode->i_sb->s_maxbytes) {
1241da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		count = inode->i_sb->s_maxbytes - pos;
1251da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	}
1261da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
1271da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	error = ncp_make_open(inode, O_RDONLY);
1281da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	if (error) {
129d3b73ca1be3236fc33f896af7e2ba637a677d5c9Joe Perches		ncp_dbg(1, "open failed, error=%d\n", error);
1301da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		return error;
1311da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	}
1321da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
1331da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	bufsize = NCP_SERVER(inode)->buffer_size;
1341da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
1351da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	error = -EIO;
1361da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	freelen = ncp_read_bounce_size(bufsize);
1371da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	freepage = vmalloc(freelen);
1381da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	if (!freepage)
1391da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		goto outrel;
1401da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	error = 0;
1411da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	/* First read in as much as possible for each bufsize. */
1421da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	while (already_read < count) {
1431da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		int read_this_time;
1441da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		size_t to_read = min_t(unsigned int,
1451da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds				     bufsize - (pos % bufsize),
1461da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds				     count - already_read);
1471da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
1481da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		error = ncp_read_bounce(NCP_SERVER(inode),
1491da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds			 	NCP_FINFO(inode)->file_handle,
1501da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds				pos, to_read, buf, &read_this_time,
1511da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds				freepage, freelen);
1521da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		if (error) {
1531da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds			error = -EIO;	/* NW errno -> Linux errno */
1541da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds			break;
1551da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		}
1561da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		pos += read_this_time;
1571da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		buf += read_this_time;
1581da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		already_read += read_this_time;
1591da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
1601da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		if (read_this_time != to_read) {
1611da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds			break;
1621da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		}
1631da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	}
1641da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	vfree(freepage);
1651da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
1661da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	*ppos = pos;
1671da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
1681da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	file_accessed(file);
1691da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
170d3b73ca1be3236fc33f896af7e2ba637a677d5c9Joe Perches	ncp_dbg(1, "exit %pd2\n", dentry);
1711da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvaldsoutrel:
1721da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	ncp_inode_close(inode);
1731da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	return already_read ? already_read : error;
1741da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds}
1751da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
1761da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvaldsstatic ssize_t
1771da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvaldsncp_file_write(struct file *file, const char __user *buf, size_t count, loff_t *ppos)
1781da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds{
17992e5baef8578a03335059a3dec933955c361edc1Josef Sipek	struct dentry *dentry = file->f_path.dentry;
1801da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	struct inode *inode = dentry->d_inode;
1811da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	size_t already_written = 0;
1821da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	off_t pos;
1831da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	size_t bufsize;
1841da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	int errno;
1851da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	void* bouncebuffer;
1861da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
187d3b73ca1be3236fc33f896af7e2ba637a677d5c9Joe Perches	ncp_dbg(1, "enter %pd2\n", dentry);
1881da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	if ((ssize_t) count < 0)
1891da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		return -EINVAL;
1901da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	pos = *ppos;
1911da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	if (file->f_flags & O_APPEND) {
1922e54eb96e2c801f33d95b5dade15212ac4d6c4a5Petr Vandrovec		pos = i_size_read(inode);
1931da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	}
1941da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
1951da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	if (pos + count > MAX_NON_LFS && !(file->f_flags&O_LARGEFILE)) {
1961da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		if (pos >= MAX_NON_LFS) {
1971da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds			return -EFBIG;
1981da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		}
1991da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		if (count > MAX_NON_LFS - (u32)pos) {
2001da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds			count = MAX_NON_LFS - (u32)pos;
2011da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		}
2021da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	}
2031da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	if (pos >= inode->i_sb->s_maxbytes) {
2041da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		if (count || pos > inode->i_sb->s_maxbytes) {
2051da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds			return -EFBIG;
2061da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		}
2071da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	}
2081da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	if (pos + count > inode->i_sb->s_maxbytes) {
2091da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		count = inode->i_sb->s_maxbytes - pos;
2101da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	}
2111da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
2121da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	if (!count)
2131da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		return 0;
2141da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	errno = ncp_make_open(inode, O_WRONLY);
2151da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	if (errno) {
216d3b73ca1be3236fc33f896af7e2ba637a677d5c9Joe Perches		ncp_dbg(1, "open failed, error=%d\n", errno);
2171da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		return errno;
2181da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	}
2191da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	bufsize = NCP_SERVER(inode)->buffer_size;
2201da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
2211da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	already_written = 0;
2221da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
223c3b2da314834499f34cba94f7053e55f6d6f92d8Josef Bacik	errno = file_update_time(file);
224c3b2da314834499f34cba94f7053e55f6d6f92d8Josef Bacik	if (errno)
225c3b2da314834499f34cba94f7053e55f6d6f92d8Josef Bacik		goto outrel;
226c3b2da314834499f34cba94f7053e55f6d6f92d8Josef Bacik
2271da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	bouncebuffer = vmalloc(bufsize);
2281da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	if (!bouncebuffer) {
2291da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		errno = -EIO;	/* -ENOMEM */
2301da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		goto outrel;
2311da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	}
2321da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	while (already_written < count) {
2331da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		int written_this_time;
2341da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		size_t to_write = min_t(unsigned int,
2351da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds				      bufsize - (pos % bufsize),
2361da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds				      count - already_written);
2371da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
2381da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		if (copy_from_user(bouncebuffer, buf, to_write)) {
2391da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds			errno = -EFAULT;
2401da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds			break;
2411da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		}
2421da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		if (ncp_write_kernel(NCP_SERVER(inode),
2431da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		    NCP_FINFO(inode)->file_handle,
2441da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		    pos, to_write, bouncebuffer, &written_this_time) != 0) {
2451da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds			errno = -EIO;
2461da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds			break;
2471da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		}
2481da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		pos += written_this_time;
2491da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		buf += written_this_time;
2501da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		already_written += written_this_time;
2511da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
2521da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		if (written_this_time != to_write) {
2531da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds			break;
2541da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		}
2551da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	}
2561da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	vfree(bouncebuffer);
2571da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
2581da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	*ppos = pos;
2591da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
2602e54eb96e2c801f33d95b5dade15212ac4d6c4a5Petr Vandrovec	if (pos > i_size_read(inode)) {
2612e54eb96e2c801f33d95b5dade15212ac4d6c4a5Petr Vandrovec		mutex_lock(&inode->i_mutex);
2622e54eb96e2c801f33d95b5dade15212ac4d6c4a5Petr Vandrovec		if (pos > i_size_read(inode))
2632e54eb96e2c801f33d95b5dade15212ac4d6c4a5Petr Vandrovec			i_size_write(inode, pos);
2642e54eb96e2c801f33d95b5dade15212ac4d6c4a5Petr Vandrovec		mutex_unlock(&inode->i_mutex);
2651da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	}
266d3b73ca1be3236fc33f896af7e2ba637a677d5c9Joe Perches	ncp_dbg(1, "exit %pd2\n", dentry);
2671da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvaldsoutrel:
2681da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	ncp_inode_close(inode);
2691da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	return already_written ? already_written : errno;
2701da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds}
2711da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
2721da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvaldsstatic int ncp_release(struct inode *inode, struct file *file) {
2731da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	if (ncp_make_closed(inode)) {
274d3b73ca1be3236fc33f896af7e2ba637a677d5c9Joe Perches		ncp_dbg(1, "failed to close\n");
2751da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	}
2761da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	return 0;
2771da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds}
2781da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
2794b6f5d20b04dcbc3d888555522b90ba6d36c4106Arjan van de Venconst struct file_operations ncp_file_operations =
2801da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds{
2812e54eb96e2c801f33d95b5dade15212ac4d6c4a5Petr Vandrovec	.llseek		= generic_file_llseek,
2821da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	.read		= ncp_file_read,
2831da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	.write		= ncp_file_write,
28493d84b6d99f5ddb911b318990c759a0fefa0f7eaJohn Kacur	.unlocked_ioctl	= ncp_ioctl,
28554f67f631dfc25ca7a8b19200e34013abc974337Petr Vandrovec#ifdef CONFIG_COMPAT
28654f67f631dfc25ca7a8b19200e34013abc974337Petr Vandrovec	.compat_ioctl	= ncp_compat_ioctl,
28754f67f631dfc25ca7a8b19200e34013abc974337Petr Vandrovec#endif
2881da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	.mmap		= ncp_mmap,
2891da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	.release	= ncp_release,
2901da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	.fsync		= ncp_fsync,
2911da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds};
2921da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
29392e1d5be91a0e3ffa5c4697eeb09b2aa22792122Arjan van de Venconst struct inode_operations ncp_file_inode_operations =
2941da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds{
2951da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	.setattr	= ncp_notify_change,
2961da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds};
297