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 dprintk(DEBUG_ERROR, 122 "open failed, open_mode 0x%x: %s\n", open_mode, 123 FCALL_ERROR(fcall)); 124 kfree(fcall); 125 return result; 126 } 127 128 iounit = fcall->params.ropen.iounit; 129 kfree(fcall); 130 } else { 131 /* create case */ 132 newfid = v9fid->fid; 133 iounit = v9fid->iounit; 134 v9fid->fidcreate = 0; 135 } 136 137 file->private_data = v9fid; 138 139 v9fid->rdir_pos = 0; 140 v9fid->rdir_fcall = NULL; 141 v9fid->fidopen = 1; 142 v9fid->filp = file; 143 v9fid->iounit = iounit; 144 145 return 0; 146 } 147 148 /** 149 * v9fs_file_lock - lock a file (or directory) 150 * @inode: inode to be opened 151 * @file: file being opened 152 * 153 * XXX - this looks like a local only lock, we should extend into 9P 154 * by using open exclusive 155 */ 156 157 static int v9fs_file_lock(struct file *filp, int cmd, struct file_lock *fl) 158 { 159 int res = 0; 160 struct inode *inode = filp->f_dentry->d_inode; 161 162 dprintk(DEBUG_VFS, "filp: %p lock: %p\n", filp, fl); 163 164 /* No mandatory locks */ 165 if ((inode->i_mode & (S_ISGID | S_IXGRP)) == S_ISGID) 166 return -ENOLCK; 167 168 if ((IS_SETLK(cmd) || IS_SETLKW(cmd)) && fl->fl_type != F_UNLCK) { 169 filemap_fdatawrite(inode->i_mapping); 170 filemap_fdatawait(inode->i_mapping); 171 invalidate_inode_pages(&inode->i_data); 172 } 173 174 return res; 175 } 176 177 /** 178 * v9fs_read - read from a file (internal) 179 * @filep: file pointer to read 180 * @data: data buffer to read data into 181 * @count: size of buffer 182 * @offset: offset at which to read data 183 * 184 */ 185 186 static ssize_t 187 v9fs_read(struct file *filp, char *buffer, size_t count, loff_t * offset) 188 { 189 struct inode *inode = filp->f_dentry->d_inode; 190 struct v9fs_session_info *v9ses = v9fs_inode2v9ses(inode); 191 struct v9fs_fid *v9f = filp->private_data; 192 struct v9fs_fcall *fcall = NULL; 193 int fid = v9f->fid; 194 int rsize = 0; 195 int result = 0; 196 int total = 0; 197 198 dprintk(DEBUG_VFS, "\n"); 199 200 rsize = v9ses->maxdata - V9FS_IOHDRSZ; 201 if (v9f->iounit != 0 && rsize > v9f->iounit) 202 rsize = v9f->iounit; 203 204 do { 205 if (count < rsize) 206 rsize = count; 207 208 result = v9fs_t_read(v9ses, fid, *offset, rsize, &fcall); 209 210 if (result < 0) { 211 printk(KERN_ERR "9P2000: v9fs_t_read returned %d\n", 212 result); 213 214 kfree(fcall); 215 return total; 216 } else 217 *offset += result; 218 219 /* XXX - extra copy */ 220 memcpy(buffer, fcall->params.rread.data, result); 221 count -= result; 222 buffer += result; 223 total += result; 224 225 kfree(fcall); 226 227 if (result < rsize) 228 break; 229 } while (count); 230 231 return total; 232 } 233 234 /** 235 * v9fs_file_read - read from a file 236 * @filep: file pointer to read 237 * @data: data buffer to read data into 238 * @count: size of buffer 239 * @offset: offset at which to read data 240 * 241 */ 242 243 static ssize_t 244 v9fs_file_read(struct file *filp, char __user * data, size_t count, 245 loff_t * offset) 246 { 247 int retval = -1; 248 int ret = 0; 249 char *buffer; 250 251 buffer = kmalloc(count, GFP_KERNEL); 252 if (!buffer) 253 return -ENOMEM; 254 255 retval = v9fs_read(filp, buffer, count, offset); 256 if (retval > 0) { 257 if ((ret = copy_to_user(data, buffer, retval)) != 0) { 258 dprintk(DEBUG_ERROR, "Problem copying to user %d\n", 259 ret); 260 retval = ret; 261 } 262 } 263 264 kfree(buffer); 265 266 return retval; 267 } 268 269 /** 270 * v9fs_write - write to a file 271 * @filep: file pointer to write 272 * @data: data buffer to write data from 273 * @count: size of buffer 274 * @offset: offset at which to write data 275 * 276 */ 277 278 static ssize_t 279 v9fs_write(struct file *filp, char *buffer, size_t count, loff_t * offset) 280 { 281 struct inode *inode = filp->f_dentry->d_inode; 282 struct v9fs_session_info *v9ses = v9fs_inode2v9ses(inode); 283 struct v9fs_fid *v9fid = filp->private_data; 284 struct v9fs_fcall *fcall; 285 int fid = v9fid->fid; 286 int result = -EIO; 287 int rsize = 0; 288 int total = 0; 289 290 dprintk(DEBUG_VFS, "data %p count %d offset %x\n", buffer, (int)count, 291 (int)*offset); 292 rsize = v9ses->maxdata - V9FS_IOHDRSZ; 293 if (v9fid->iounit != 0 && rsize > v9fid->iounit) 294 rsize = v9fid->iounit; 295 296 dump_data(buffer, count); 297 298 do { 299 if (count < rsize) 300 rsize = count; 301 302 result = 303 v9fs_t_write(v9ses, fid, *offset, rsize, buffer, &fcall); 304 if (result < 0) { 305 eprintk(KERN_ERR, "error while writing: %s(%d)\n", 306 FCALL_ERROR(fcall), result); 307 kfree(fcall); 308 return result; 309 } else 310 *offset += result; 311 312 kfree(fcall); 313 314 if (result != rsize) { 315 eprintk(KERN_ERR, 316 "short write: v9fs_t_write returned %d\n", 317 result); 318 break; 319 } 320 321 count -= result; 322 buffer += result; 323 total += result; 324 } while (count); 325 326 return total; 327 } 328 329 /** 330 * v9fs_file_write - write to a file 331 * @filep: file pointer to write 332 * @data: data buffer to write data from 333 * @count: size of buffer 334 * @offset: offset at which to write data 335 * 336 */ 337 338 static ssize_t 339 v9fs_file_write(struct file *filp, const char __user * data, 340 size_t count, loff_t * offset) 341 { 342 int ret = -1; 343 char *buffer; 344 345 buffer = kmalloc(count, GFP_KERNEL); 346 if (buffer == NULL) 347 return -ENOMEM; 348 349 ret = copy_from_user(buffer, data, count); 350 if (ret) { 351 dprintk(DEBUG_ERROR, "Problem copying from user\n"); 352 ret = -EFAULT; 353 } else { 354 ret = v9fs_write(filp, buffer, count, offset); 355 } 356 357 kfree(buffer); 358 359 return ret; 360 } 361 362 struct file_operations v9fs_file_operations = { 363 .llseek = generic_file_llseek, 364 .read = v9fs_file_read, 365 .write = v9fs_file_write, 366 .open = v9fs_file_open, 367 .release = v9fs_dir_release, 368 .lock = v9fs_file_lock, 369 }; 370