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