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_file_read - read from a file 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 static ssize_t 186 v9fs_file_read(struct file *filp, char __user * data, size_t count, 187 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 int n; 198 199 dprintk(DEBUG_VFS, "\n"); 200 201 rsize = v9ses->maxdata - V9FS_IOHDRSZ; 202 if (v9f->iounit != 0 && rsize > v9f->iounit) 203 rsize = v9f->iounit; 204 205 do { 206 if (count < rsize) 207 rsize = count; 208 209 result = v9fs_t_read(v9ses, fid, *offset, rsize, &fcall); 210 211 if (result < 0) { 212 printk(KERN_ERR "9P2000: v9fs_t_read returned %d\n", 213 result); 214 215 kfree(fcall); 216 return total; 217 } else 218 *offset += result; 219 220 n = copy_to_user(data, fcall->params.rread.data, result); 221 if (n) { 222 dprintk(DEBUG_ERROR, "Problem copying to user %d\n", n); 223 kfree(fcall); 224 return -EFAULT; 225 } 226 227 count -= result; 228 data += result; 229 total += result; 230 231 kfree(fcall); 232 233 if (result < rsize) 234 break; 235 } while (count); 236 237 return total; 238 } 239 240 /** 241 * v9fs_file_write - write to a file 242 * @filep: file pointer to write 243 * @data: data buffer to write data from 244 * @count: size of buffer 245 * @offset: offset at which to write data 246 * 247 */ 248 249 static ssize_t 250 v9fs_file_write(struct file *filp, const char __user * data, 251 size_t count, loff_t * offset) 252 { 253 struct inode *inode = filp->f_dentry->d_inode; 254 struct v9fs_session_info *v9ses = v9fs_inode2v9ses(inode); 255 struct v9fs_fid *v9fid = filp->private_data; 256 struct v9fs_fcall *fcall; 257 int fid = v9fid->fid; 258 int result = -EIO; 259 int rsize = 0; 260 int total = 0; 261 char *buf; 262 263 dprintk(DEBUG_VFS, "data %p count %d offset %x\n", data, (int)count, 264 (int)*offset); 265 rsize = v9ses->maxdata - V9FS_IOHDRSZ; 266 if (v9fid->iounit != 0 && rsize > v9fid->iounit) 267 rsize = v9fid->iounit; 268 269 buf = kmalloc(v9ses->maxdata - V9FS_IOHDRSZ, GFP_KERNEL); 270 if (!buf) 271 return -ENOMEM; 272 273 do { 274 if (count < rsize) 275 rsize = count; 276 277 result = copy_from_user(buf, data, rsize); 278 if (result) { 279 dprintk(DEBUG_ERROR, "Problem copying from user\n"); 280 kfree(buf); 281 return -EFAULT; 282 } 283 284 dump_data(buf, rsize); 285 result = v9fs_t_write(v9ses, fid, *offset, rsize, buf, &fcall); 286 if (result < 0) { 287 eprintk(KERN_ERR, "error while writing: %s(%d)\n", 288 FCALL_ERROR(fcall), result); 289 kfree(fcall); 290 kfree(buf); 291 return result; 292 } else 293 *offset += result; 294 295 kfree(fcall); 296 fcall = NULL; 297 298 if (result != rsize) { 299 eprintk(KERN_ERR, 300 "short write: v9fs_t_write returned %d\n", 301 result); 302 break; 303 } 304 305 count -= result; 306 data += result; 307 total += result; 308 } while (count); 309 310 kfree(buf); 311 return total; 312 } 313 314 struct file_operations v9fs_file_operations = { 315 .llseek = generic_file_llseek, 316 .read = v9fs_file_read, 317 .write = v9fs_file_write, 318 .open = v9fs_file_open, 319 .release = v9fs_dir_release, 320 .lock = v9fs_file_lock, 321 }; 322