1 /* 2 * linux/fs/9p/vfs_file.c 3 * 4 * This file contians vfs file ops for 9P2000. 5 * 6 * Copyright (C) 2004 by Eric Van Hensbergen <ericvh@gmail.com> 7 * Copyright (C) 2002 by Ron Minnich <rminnich@lanl.gov> 8 * 9 * This program is free software; you can redistribute it and/or modify 10 * it under the terms of the GNU General Public License as published by 11 * the Free Software Foundation; either version 2 of the License, or 12 * (at your option) any later version. 13 * 14 * This program is distributed in the hope that it will be useful, 15 * but WITHOUT ANY WARRANTY; without even the implied warranty of 16 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 17 * GNU General Public License for more details. 18 * 19 * You should have received a copy of the GNU General Public License 20 * along with this program; if not, write to: 21 * Free Software Foundation 22 * 51 Franklin Street, Fifth Floor 23 * Boston, MA 02111-1301 USA 24 * 25 */ 26 27 #include <linux/module.h> 28 #include <linux/errno.h> 29 #include <linux/fs.h> 30 #include <linux/file.h> 31 #include <linux/stat.h> 32 #include <linux/string.h> 33 #include <linux/smp_lock.h> 34 #include <linux/inet.h> 35 #include <linux/version.h> 36 #include <linux/list.h> 37 #include <asm/uaccess.h> 38 #include <linux/idr.h> 39 40 #include "debug.h" 41 #include "v9fs.h" 42 #include "9p.h" 43 #include "v9fs_vfs.h" 44 #include "fid.h" 45 46 /** 47 * v9fs_file_open - open a file (or directory) 48 * @inode: inode to be opened 49 * @file: file being opened 50 * 51 */ 52 53 int v9fs_file_open(struct inode *inode, struct file *file) 54 { 55 struct v9fs_session_info *v9ses = v9fs_inode2v9ses(inode); 56 struct v9fs_fid *v9fid, *fid; 57 struct v9fs_fcall *fcall = NULL; 58 int open_mode = 0; 59 unsigned int iounit = 0; 60 int newfid = -1; 61 long result = -1; 62 63 dprintk(DEBUG_VFS, "inode: %p file: %p \n", inode, file); 64 65 v9fid = v9fs_fid_get_created(file->f_dentry); 66 if (!v9fid) 67 v9fid = v9fs_fid_lookup(file->f_dentry); 68 69 if (!v9fid) { 70 dprintk(DEBUG_ERROR, "Couldn't resolve fid from dentry\n"); 71 return -EBADF; 72 } 73 74 if (!v9fid->fidcreate) { 75 fid = kmalloc(sizeof(struct v9fs_fid), GFP_KERNEL); 76 if (fid == NULL) { 77 dprintk(DEBUG_ERROR, "Out of Memory\n"); 78 return -ENOMEM; 79 } 80 81 fid->fidopen = 0; 82 fid->fidcreate = 0; 83 fid->fidclunked = 0; 84 fid->iounit = 0; 85 fid->v9ses = v9ses; 86 87 newfid = v9fs_get_idpool(&v9ses->fidpool); 88 if (newfid < 0) { 89 eprintk(KERN_WARNING, "newfid fails!\n"); 90 return -ENOSPC; 91 } 92 93 result = 94 v9fs_t_walk(v9ses, v9fid->fid, newfid, NULL, NULL); 95 96 if (result < 0) { 97 v9fs_put_idpool(newfid, &v9ses->fidpool); 98 dprintk(DEBUG_ERROR, "rewalk didn't work\n"); 99 return -EBADF; 100 } 101 102 fid->fid = newfid; 103 v9fid = fid; 104 /* TODO: do special things for O_EXCL, O_NOFOLLOW, O_SYNC */ 105 /* translate open mode appropriately */ 106 open_mode = file->f_flags & 0x3; 107 108 if (file->f_flags & O_EXCL) 109 open_mode |= V9FS_OEXCL; 110 111 if (v9ses->extended) { 112 if (file->f_flags & O_TRUNC) 113 open_mode |= V9FS_OTRUNC; 114 115 if (file->f_flags & O_APPEND) 116 open_mode |= V9FS_OAPPEND; 117 } 118 119 result = v9fs_t_open(v9ses, newfid, open_mode, &fcall); 120 if (result < 0) { 121 PRINT_FCALL_ERROR("open failed", fcall); 122 kfree(fcall); 123 return result; 124 } 125 126 iounit = fcall->params.ropen.iounit; 127 kfree(fcall); 128 } else { 129 /* create case */ 130 newfid = v9fid->fid; 131 iounit = v9fid->iounit; 132 v9fid->fidcreate = 0; 133 } 134 135 file->private_data = v9fid; 136 137 v9fid->rdir_pos = 0; 138 v9fid->rdir_fcall = NULL; 139 v9fid->fidopen = 1; 140 v9fid->filp = file; 141 v9fid->iounit = iounit; 142 143 return 0; 144 } 145 146 /** 147 * v9fs_file_lock - lock a file (or directory) 148 * @inode: inode to be opened 149 * @file: file being opened 150 * 151 * XXX - this looks like a local only lock, we should extend into 9P 152 * by using open exclusive 153 */ 154 155 static int v9fs_file_lock(struct file *filp, int cmd, struct file_lock *fl) 156 { 157 int res = 0; 158 struct inode *inode = filp->f_dentry->d_inode; 159 160 dprintk(DEBUG_VFS, "filp: %p lock: %p\n", filp, fl); 161 162 /* No mandatory locks */ 163 if ((inode->i_mode & (S_ISGID | S_IXGRP)) == S_ISGID) 164 return -ENOLCK; 165 166 if ((IS_SETLK(cmd) || IS_SETLKW(cmd)) && fl->fl_type != F_UNLCK) { 167 filemap_write_and_wait(inode->i_mapping); 168 invalidate_inode_pages(&inode->i_data); 169 } 170 171 return res; 172 } 173 174 /** 175 * v9fs_file_read - read from a file 176 * @filep: file pointer to read 177 * @data: data buffer to read data into 178 * @count: size of buffer 179 * @offset: offset at which to read data 180 * 181 */ 182 static ssize_t 183 v9fs_file_read(struct file *filp, char __user * data, size_t count, 184 loff_t * offset) 185 { 186 struct inode *inode = filp->f_dentry->d_inode; 187 struct v9fs_session_info *v9ses = v9fs_inode2v9ses(inode); 188 struct v9fs_fid *v9f = filp->private_data; 189 struct v9fs_fcall *fcall = NULL; 190 int fid = v9f->fid; 191 int rsize = 0; 192 int result = 0; 193 int total = 0; 194 int n; 195 196 dprintk(DEBUG_VFS, "\n"); 197 198 rsize = v9ses->maxdata - V9FS_IOHDRSZ; 199 if (v9f->iounit != 0 && rsize > v9f->iounit) 200 rsize = v9f->iounit; 201 202 do { 203 if (count < rsize) 204 rsize = count; 205 206 result = v9fs_t_read(v9ses, fid, *offset, rsize, &fcall); 207 208 if (result < 0) { 209 printk(KERN_ERR "9P2000: v9fs_t_read returned %d\n", 210 result); 211 212 kfree(fcall); 213 return total; 214 } else 215 *offset += result; 216 217 n = copy_to_user(data, fcall->params.rread.data, result); 218 if (n) { 219 dprintk(DEBUG_ERROR, "Problem copying to user %d\n", n); 220 kfree(fcall); 221 return -EFAULT; 222 } 223 224 count -= result; 225 data += result; 226 total += result; 227 228 kfree(fcall); 229 230 if (result < rsize) 231 break; 232 } while (count); 233 234 return total; 235 } 236 237 /** 238 * v9fs_file_write - write to a file 239 * @filep: file pointer to write 240 * @data: data buffer to write data from 241 * @count: size of buffer 242 * @offset: offset at which to write data 243 * 244 */ 245 246 static ssize_t 247 v9fs_file_write(struct file *filp, const char __user * data, 248 size_t count, loff_t * offset) 249 { 250 struct inode *inode = filp->f_dentry->d_inode; 251 struct v9fs_session_info *v9ses = v9fs_inode2v9ses(inode); 252 struct v9fs_fid *v9fid = filp->private_data; 253 struct v9fs_fcall *fcall; 254 int fid = v9fid->fid; 255 int result = -EIO; 256 int rsize = 0; 257 int total = 0; 258 259 dprintk(DEBUG_VFS, "data %p count %d offset %x\n", data, (int)count, 260 (int)*offset); 261 rsize = v9ses->maxdata - V9FS_IOHDRSZ; 262 if (v9fid->iounit != 0 && rsize > v9fid->iounit) 263 rsize = v9fid->iounit; 264 265 do { 266 if (count < rsize) 267 rsize = count; 268 269 result = v9fs_t_write(v9ses, fid, *offset, rsize, data, &fcall); 270 if (result < 0) { 271 PRINT_FCALL_ERROR("error while writing", fcall); 272 kfree(fcall); 273 return result; 274 } else 275 *offset += result; 276 277 kfree(fcall); 278 fcall = NULL; 279 280 if (result != rsize) { 281 eprintk(KERN_ERR, 282 "short write: v9fs_t_write returned %d\n", 283 result); 284 break; 285 } 286 287 count -= result; 288 data += result; 289 total += result; 290 } while (count); 291 292 return total; 293 } 294 295 struct file_operations v9fs_file_operations = { 296 .llseek = generic_file_llseek, 297 .read = v9fs_file_read, 298 .write = v9fs_file_write, 299 .open = v9fs_file_open, 300 .release = v9fs_dir_release, 301 .lock = v9fs_file_lock, 302 }; 303