| Eric Van Hensbergen | 2bad847 | 2005-09-09 13:04:19 -0700 | [diff] [blame] | 1 | /* | 
|  | 2 | *  linux/fs/9p/vfs_inode.c | 
|  | 3 | * | 
| Eric Van Hensbergen | 73c592b | 2005-09-09 13:04:26 -0700 | [diff] [blame] | 4 | * This file contains vfs inode ops for the 9P2000 protocol. | 
| Eric Van Hensbergen | 2bad847 | 2005-09-09 13:04:19 -0700 | [diff] [blame] | 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 | 
| Eric Van Hensbergen | 42e8c50 | 2006-03-25 03:07:28 -0800 | [diff] [blame] | 10 | *  it under the terms of the GNU General Public License version 2 | 
|  | 11 | *  as published by the Free Software Foundation. | 
| Eric Van Hensbergen | 2bad847 | 2005-09-09 13:04:19 -0700 | [diff] [blame] | 12 | * | 
|  | 13 | *  This program is distributed in the hope that it will be useful, | 
|  | 14 | *  but WITHOUT ANY WARRANTY; without even the implied warranty of | 
|  | 15 | *  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the | 
|  | 16 | *  GNU General Public License for more details. | 
|  | 17 | * | 
|  | 18 | *  You should have received a copy of the GNU General Public License | 
|  | 19 | *  along with this program; if not, write to: | 
|  | 20 | *  Free Software Foundation | 
|  | 21 | *  51 Franklin Street, Fifth Floor | 
|  | 22 | *  Boston, MA  02111-1301  USA | 
|  | 23 | * | 
|  | 24 | */ | 
|  | 25 |  | 
|  | 26 | #include <linux/module.h> | 
|  | 27 | #include <linux/errno.h> | 
|  | 28 | #include <linux/fs.h> | 
|  | 29 | #include <linux/file.h> | 
|  | 30 | #include <linux/pagemap.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/namei.h> | 
|  | 36 | #include <linux/idr.h> | 
|  | 37 |  | 
|  | 38 | #include "debug.h" | 
|  | 39 | #include "v9fs.h" | 
|  | 40 | #include "9p.h" | 
|  | 41 | #include "v9fs_vfs.h" | 
| Eric Van Hensbergen | 2bad847 | 2005-09-09 13:04:19 -0700 | [diff] [blame] | 42 | #include "fid.h" | 
|  | 43 |  | 
| Arjan van de Ven | 754661f | 2007-02-12 00:55:38 -0800 | [diff] [blame] | 44 | static const struct inode_operations v9fs_dir_inode_operations; | 
|  | 45 | static const struct inode_operations v9fs_dir_inode_operations_ext; | 
|  | 46 | static const struct inode_operations v9fs_file_inode_operations; | 
|  | 47 | static const struct inode_operations v9fs_symlink_inode_operations; | 
| Eric Van Hensbergen | 2bad847 | 2005-09-09 13:04:19 -0700 | [diff] [blame] | 48 |  | 
|  | 49 | /** | 
|  | 50 | * unixmode2p9mode - convert unix mode bits to plan 9 | 
|  | 51 | * @v9ses: v9fs session information | 
|  | 52 | * @mode: mode to convert | 
|  | 53 | * | 
|  | 54 | */ | 
|  | 55 |  | 
| Eric Van Hensbergen | 73c592b | 2005-09-09 13:04:26 -0700 | [diff] [blame] | 56 | static int unixmode2p9mode(struct v9fs_session_info *v9ses, int mode) | 
| Eric Van Hensbergen | 2bad847 | 2005-09-09 13:04:19 -0700 | [diff] [blame] | 57 | { | 
|  | 58 | int res; | 
|  | 59 | res = mode & 0777; | 
|  | 60 | if (S_ISDIR(mode)) | 
|  | 61 | res |= V9FS_DMDIR; | 
|  | 62 | if (v9ses->extended) { | 
|  | 63 | if (S_ISLNK(mode)) | 
|  | 64 | res |= V9FS_DMSYMLINK; | 
|  | 65 | if (v9ses->nodev == 0) { | 
|  | 66 | if (S_ISSOCK(mode)) | 
|  | 67 | res |= V9FS_DMSOCKET; | 
|  | 68 | if (S_ISFIFO(mode)) | 
|  | 69 | res |= V9FS_DMNAMEDPIPE; | 
|  | 70 | if (S_ISBLK(mode)) | 
|  | 71 | res |= V9FS_DMDEVICE; | 
|  | 72 | if (S_ISCHR(mode)) | 
|  | 73 | res |= V9FS_DMDEVICE; | 
|  | 74 | } | 
|  | 75 |  | 
|  | 76 | if ((mode & S_ISUID) == S_ISUID) | 
|  | 77 | res |= V9FS_DMSETUID; | 
|  | 78 | if ((mode & S_ISGID) == S_ISGID) | 
|  | 79 | res |= V9FS_DMSETGID; | 
|  | 80 | if ((mode & V9FS_DMLINK)) | 
|  | 81 | res |= V9FS_DMLINK; | 
|  | 82 | } | 
|  | 83 |  | 
|  | 84 | return res; | 
|  | 85 | } | 
|  | 86 |  | 
|  | 87 | /** | 
|  | 88 | * p9mode2unixmode- convert plan9 mode bits to unix mode bits | 
|  | 89 | * @v9ses: v9fs session information | 
|  | 90 | * @mode: mode to convert | 
|  | 91 | * | 
|  | 92 | */ | 
|  | 93 |  | 
| Eric Van Hensbergen | 73c592b | 2005-09-09 13:04:26 -0700 | [diff] [blame] | 94 | static int p9mode2unixmode(struct v9fs_session_info *v9ses, int mode) | 
| Eric Van Hensbergen | 2bad847 | 2005-09-09 13:04:19 -0700 | [diff] [blame] | 95 | { | 
|  | 96 | int res; | 
|  | 97 |  | 
|  | 98 | res = mode & 0777; | 
|  | 99 |  | 
|  | 100 | if ((mode & V9FS_DMDIR) == V9FS_DMDIR) | 
|  | 101 | res |= S_IFDIR; | 
|  | 102 | else if ((mode & V9FS_DMSYMLINK) && (v9ses->extended)) | 
|  | 103 | res |= S_IFLNK; | 
|  | 104 | else if ((mode & V9FS_DMSOCKET) && (v9ses->extended) | 
|  | 105 | && (v9ses->nodev == 0)) | 
|  | 106 | res |= S_IFSOCK; | 
|  | 107 | else if ((mode & V9FS_DMNAMEDPIPE) && (v9ses->extended) | 
|  | 108 | && (v9ses->nodev == 0)) | 
|  | 109 | res |= S_IFIFO; | 
|  | 110 | else if ((mode & V9FS_DMDEVICE) && (v9ses->extended) | 
|  | 111 | && (v9ses->nodev == 0)) | 
|  | 112 | res |= S_IFBLK; | 
|  | 113 | else | 
|  | 114 | res |= S_IFREG; | 
|  | 115 |  | 
|  | 116 | if (v9ses->extended) { | 
|  | 117 | if ((mode & V9FS_DMSETUID) == V9FS_DMSETUID) | 
|  | 118 | res |= S_ISUID; | 
|  | 119 |  | 
|  | 120 | if ((mode & V9FS_DMSETGID) == V9FS_DMSETGID) | 
|  | 121 | res |= S_ISGID; | 
|  | 122 | } | 
|  | 123 |  | 
|  | 124 | return res; | 
|  | 125 | } | 
|  | 126 |  | 
| Latchesar Ionkov | 6a3124a | 2006-03-02 02:54:30 -0800 | [diff] [blame] | 127 | int v9fs_uflags2omode(int uflags) | 
|  | 128 | { | 
|  | 129 | int ret; | 
|  | 130 |  | 
|  | 131 | ret = 0; | 
|  | 132 | switch (uflags&3) { | 
|  | 133 | default: | 
|  | 134 | case O_RDONLY: | 
|  | 135 | ret = V9FS_OREAD; | 
|  | 136 | break; | 
|  | 137 |  | 
|  | 138 | case O_WRONLY: | 
|  | 139 | ret = V9FS_OWRITE; | 
|  | 140 | break; | 
|  | 141 |  | 
|  | 142 | case O_RDWR: | 
|  | 143 | ret = V9FS_ORDWR; | 
|  | 144 | break; | 
|  | 145 | } | 
|  | 146 |  | 
|  | 147 | if (uflags & O_EXCL) | 
|  | 148 | ret |= V9FS_OEXCL; | 
|  | 149 |  | 
|  | 150 | if (uflags & O_TRUNC) | 
|  | 151 | ret |= V9FS_OTRUNC; | 
|  | 152 |  | 
|  | 153 | if (uflags & O_APPEND) | 
|  | 154 | ret |= V9FS_OAPPEND; | 
|  | 155 |  | 
|  | 156 | return ret; | 
|  | 157 | } | 
|  | 158 |  | 
| Eric Van Hensbergen | 2bad847 | 2005-09-09 13:04:19 -0700 | [diff] [blame] | 159 | /** | 
| Latchesar Ionkov | 531b109 | 2006-01-08 01:05:00 -0800 | [diff] [blame] | 160 | * v9fs_blank_wstat - helper function to setup a 9P stat structure | 
| Eric Van Hensbergen | 2bad847 | 2005-09-09 13:04:19 -0700 | [diff] [blame] | 161 | * @v9ses: 9P session info (for determining extended mode) | 
| Latchesar Ionkov | 531b109 | 2006-01-08 01:05:00 -0800 | [diff] [blame] | 162 | * @wstat: structure to initialize | 
| Eric Van Hensbergen | 2bad847 | 2005-09-09 13:04:19 -0700 | [diff] [blame] | 163 | * | 
|  | 164 | */ | 
|  | 165 |  | 
| Eric Van Hensbergen | 73c592b | 2005-09-09 13:04:26 -0700 | [diff] [blame] | 166 | static void | 
| Latchesar Ionkov | 531b109 | 2006-01-08 01:05:00 -0800 | [diff] [blame] | 167 | v9fs_blank_wstat(struct v9fs_wstat *wstat) | 
| Eric Van Hensbergen | 2bad847 | 2005-09-09 13:04:19 -0700 | [diff] [blame] | 168 | { | 
| Latchesar Ionkov | 531b109 | 2006-01-08 01:05:00 -0800 | [diff] [blame] | 169 | wstat->type = ~0; | 
|  | 170 | wstat->dev = ~0; | 
|  | 171 | wstat->qid.type = ~0; | 
|  | 172 | wstat->qid.version = ~0; | 
|  | 173 | *((long long *)&wstat->qid.path) = ~0; | 
|  | 174 | wstat->mode = ~0; | 
|  | 175 | wstat->atime = ~0; | 
|  | 176 | wstat->mtime = ~0; | 
|  | 177 | wstat->length = ~0; | 
|  | 178 | wstat->name = NULL; | 
|  | 179 | wstat->uid = NULL; | 
|  | 180 | wstat->gid = NULL; | 
|  | 181 | wstat->muid = NULL; | 
|  | 182 | wstat->n_uid = ~0; | 
|  | 183 | wstat->n_gid = ~0; | 
|  | 184 | wstat->n_muid = ~0; | 
|  | 185 | wstat->extension = NULL; | 
| Eric Van Hensbergen | 2bad847 | 2005-09-09 13:04:19 -0700 | [diff] [blame] | 186 | } | 
|  | 187 |  | 
|  | 188 | /** | 
|  | 189 | * v9fs_get_inode - helper function to setup an inode | 
|  | 190 | * @sb: superblock | 
|  | 191 | * @mode: mode to setup inode with | 
|  | 192 | * | 
|  | 193 | */ | 
|  | 194 |  | 
|  | 195 | struct inode *v9fs_get_inode(struct super_block *sb, int mode) | 
|  | 196 | { | 
| Latchesar Ionkov | 6a3124a | 2006-03-02 02:54:30 -0800 | [diff] [blame] | 197 | struct inode *inode; | 
| Eric Van Hensbergen | b501611 | 2005-09-09 13:04:27 -0700 | [diff] [blame] | 198 | struct v9fs_session_info *v9ses = sb->s_fs_info; | 
| Eric Van Hensbergen | 2bad847 | 2005-09-09 13:04:19 -0700 | [diff] [blame] | 199 |  | 
|  | 200 | dprintk(DEBUG_VFS, "super block: %p mode: %o\n", sb, mode); | 
|  | 201 |  | 
|  | 202 | inode = new_inode(sb); | 
|  | 203 | if (inode) { | 
|  | 204 | inode->i_mode = mode; | 
|  | 205 | inode->i_uid = current->fsuid; | 
|  | 206 | inode->i_gid = current->fsgid; | 
| Eric Van Hensbergen | 2bad847 | 2005-09-09 13:04:19 -0700 | [diff] [blame] | 207 | inode->i_blocks = 0; | 
|  | 208 | inode->i_rdev = 0; | 
|  | 209 | inode->i_atime = inode->i_mtime = inode->i_ctime = CURRENT_TIME; | 
| Eric Van Hensbergen | 147b31c | 2006-01-18 17:43:02 -0800 | [diff] [blame] | 210 | inode->i_mapping->a_ops = &v9fs_addr_operations; | 
| Eric Van Hensbergen | 2bad847 | 2005-09-09 13:04:19 -0700 | [diff] [blame] | 211 |  | 
|  | 212 | switch (mode & S_IFMT) { | 
|  | 213 | case S_IFIFO: | 
|  | 214 | case S_IFBLK: | 
|  | 215 | case S_IFCHR: | 
|  | 216 | case S_IFSOCK: | 
| Eric Van Hensbergen | b501611 | 2005-09-09 13:04:27 -0700 | [diff] [blame] | 217 | if(!v9ses->extended) { | 
|  | 218 | dprintk(DEBUG_ERROR, "special files without extended mode\n"); | 
|  | 219 | return ERR_PTR(-EINVAL); | 
|  | 220 | } | 
| Eric Van Hensbergen | 5d58bec | 2005-09-09 13:04:27 -0700 | [diff] [blame] | 221 | init_special_inode(inode, inode->i_mode, | 
|  | 222 | inode->i_rdev); | 
|  | 223 | break; | 
| Eric Van Hensbergen | 2bad847 | 2005-09-09 13:04:19 -0700 | [diff] [blame] | 224 | case S_IFREG: | 
|  | 225 | inode->i_op = &v9fs_file_inode_operations; | 
|  | 226 | inode->i_fop = &v9fs_file_operations; | 
|  | 227 | break; | 
| Eric Van Hensbergen | b501611 | 2005-09-09 13:04:27 -0700 | [diff] [blame] | 228 | case S_IFLNK: | 
|  | 229 | if(!v9ses->extended) { | 
|  | 230 | dprintk(DEBUG_ERROR, "extended modes used w/o 9P2000.u\n"); | 
|  | 231 | return ERR_PTR(-EINVAL); | 
|  | 232 | } | 
|  | 233 | inode->i_op = &v9fs_symlink_inode_operations; | 
|  | 234 | break; | 
| Eric Van Hensbergen | 2bad847 | 2005-09-09 13:04:19 -0700 | [diff] [blame] | 235 | case S_IFDIR: | 
| Dave Hansen | d8c76e6 | 2006-09-30 23:29:04 -0700 | [diff] [blame] | 236 | inc_nlink(inode); | 
| Eric Van Hensbergen | b501611 | 2005-09-09 13:04:27 -0700 | [diff] [blame] | 237 | if(v9ses->extended) | 
|  | 238 | inode->i_op = &v9fs_dir_inode_operations_ext; | 
|  | 239 | else | 
|  | 240 | inode->i_op = &v9fs_dir_inode_operations; | 
| Eric Van Hensbergen | 2bad847 | 2005-09-09 13:04:19 -0700 | [diff] [blame] | 241 | inode->i_fop = &v9fs_dir_operations; | 
|  | 242 | break; | 
| Eric Van Hensbergen | 2bad847 | 2005-09-09 13:04:19 -0700 | [diff] [blame] | 243 | default: | 
|  | 244 | dprintk(DEBUG_ERROR, "BAD mode 0x%x S_IFMT 0x%x\n", | 
|  | 245 | mode, mode & S_IFMT); | 
|  | 246 | return ERR_PTR(-EINVAL); | 
|  | 247 | } | 
|  | 248 | } else { | 
|  | 249 | eprintk(KERN_WARNING, "Problem allocating inode\n"); | 
|  | 250 | return ERR_PTR(-ENOMEM); | 
|  | 251 | } | 
|  | 252 | return inode; | 
|  | 253 | } | 
|  | 254 |  | 
| Eric Van Hensbergen | 2bad847 | 2005-09-09 13:04:19 -0700 | [diff] [blame] | 255 | static int | 
| Latchesar Ionkov | 16cce6d | 2006-03-25 03:07:26 -0800 | [diff] [blame] | 256 | v9fs_create(struct v9fs_session_info *v9ses, u32 pfid, char *name, u32 perm, | 
|  | 257 | u8 mode, char *extension, u32 *fidp, struct v9fs_qid *qid, u32 *iounit) | 
| Eric Van Hensbergen | 2bad847 | 2005-09-09 13:04:19 -0700 | [diff] [blame] | 258 | { | 
| Mika Kukkonen | 736c4b8 | 2006-12-06 20:36:29 -0800 | [diff] [blame] | 259 | int fid; | 
| Latchesar Ionkov | 3cf6429 | 2006-01-08 01:04:58 -0800 | [diff] [blame] | 260 | int err; | 
| Latchesar Ionkov | 6a3124a | 2006-03-02 02:54:30 -0800 | [diff] [blame] | 261 | struct v9fs_fcall *fcall; | 
| Eric Van Hensbergen | 2bad847 | 2005-09-09 13:04:19 -0700 | [diff] [blame] | 262 |  | 
| Latchesar Ionkov | 6a3124a | 2006-03-02 02:54:30 -0800 | [diff] [blame] | 263 | fid = v9fs_get_idpool(&v9ses->fidpool); | 
|  | 264 | if (fid < 0) { | 
| Eric Van Hensbergen | 2bad847 | 2005-09-09 13:04:19 -0700 | [diff] [blame] | 265 | eprintk(KERN_WARNING, "no free fids available\n"); | 
| Latchesar Ionkov | 731805b | 2006-03-07 21:55:42 -0800 | [diff] [blame] | 266 | return -ENOSPC; | 
| Eric Van Hensbergen | 2bad847 | 2005-09-09 13:04:19 -0700 | [diff] [blame] | 267 | } | 
|  | 268 |  | 
| Latchesar Ionkov | 6a3124a | 2006-03-02 02:54:30 -0800 | [diff] [blame] | 269 | err = v9fs_t_walk(v9ses, pfid, fid, NULL, &fcall); | 
|  | 270 | if (err < 0) { | 
| Latchesar Ionkov | 531b109 | 2006-01-08 01:05:00 -0800 | [diff] [blame] | 271 | PRINT_FCALL_ERROR("clone error", fcall); | 
| Latchesar Ionkov | 41e5a6a | 2006-05-15 09:44:21 -0700 | [diff] [blame] | 272 | if (fcall && fcall->id == RWALK) | 
|  | 273 | goto clunk_fid; | 
|  | 274 | else | 
|  | 275 | goto put_fid; | 
| Eric Van Hensbergen | 2bad847 | 2005-09-09 13:04:19 -0700 | [diff] [blame] | 276 | } | 
| Eric Van Hensbergen | 2bad847 | 2005-09-09 13:04:19 -0700 | [diff] [blame] | 277 | kfree(fcall); | 
|  | 278 |  | 
| Latchesar Ionkov | 16cce6d | 2006-03-25 03:07:26 -0800 | [diff] [blame] | 279 | err = v9fs_t_create(v9ses, fid, name, perm, mode, extension, &fcall); | 
| Latchesar Ionkov | 6a3124a | 2006-03-02 02:54:30 -0800 | [diff] [blame] | 280 | if (err < 0) { | 
| Latchesar Ionkov | 531b109 | 2006-01-08 01:05:00 -0800 | [diff] [blame] | 281 | PRINT_FCALL_ERROR("create fails", fcall); | 
| Latchesar Ionkov | 16cce6d | 2006-03-25 03:07:26 -0800 | [diff] [blame] | 282 | goto clunk_fid; | 
| Eric Van Hensbergen | 2bad847 | 2005-09-09 13:04:19 -0700 | [diff] [blame] | 283 | } | 
|  | 284 |  | 
| Latchesar Ionkov | 6a3124a | 2006-03-02 02:54:30 -0800 | [diff] [blame] | 285 | if (iounit) | 
|  | 286 | *iounit = fcall->params.rcreate.iounit; | 
|  | 287 |  | 
|  | 288 | if (qid) | 
|  | 289 | *qid = fcall->params.rcreate.qid; | 
|  | 290 |  | 
|  | 291 | if (fidp) | 
|  | 292 | *fidp = fid; | 
|  | 293 |  | 
| Eric Van Hensbergen | 2bad847 | 2005-09-09 13:04:19 -0700 | [diff] [blame] | 294 | kfree(fcall); | 
| Eric Van Hensbergen | 2bad847 | 2005-09-09 13:04:19 -0700 | [diff] [blame] | 295 | return 0; | 
|  | 296 |  | 
| Latchesar Ionkov | 16cce6d | 2006-03-25 03:07:26 -0800 | [diff] [blame] | 297 | clunk_fid: | 
|  | 298 | v9fs_t_clunk(v9ses, fid); | 
|  | 299 | fid = V9FS_NOFID; | 
|  | 300 |  | 
|  | 301 | put_fid: | 
| Latchesar Ionkov | 9d7fa40 | 2006-06-28 04:26:51 -0700 | [diff] [blame] | 302 | if (fid != V9FS_NOFID) | 
| Latchesar Ionkov | 6a3124a | 2006-03-02 02:54:30 -0800 | [diff] [blame] | 303 | v9fs_put_idpool(fid, &v9ses->fidpool); | 
|  | 304 |  | 
|  | 305 | kfree(fcall); | 
|  | 306 | return err; | 
|  | 307 | } | 
|  | 308 |  | 
|  | 309 | static struct v9fs_fid* | 
|  | 310 | v9fs_clone_walk(struct v9fs_session_info *v9ses, u32 fid, struct dentry *dentry) | 
|  | 311 | { | 
|  | 312 | int err; | 
| Mika Kukkonen | 736c4b8 | 2006-12-06 20:36:29 -0800 | [diff] [blame] | 313 | int nfid; | 
| Latchesar Ionkov | 6a3124a | 2006-03-02 02:54:30 -0800 | [diff] [blame] | 314 | struct v9fs_fid *ret; | 
|  | 315 | struct v9fs_fcall *fcall; | 
|  | 316 |  | 
|  | 317 | nfid = v9fs_get_idpool(&v9ses->fidpool); | 
|  | 318 | if (nfid < 0) { | 
|  | 319 | eprintk(KERN_WARNING, "no free fids available\n"); | 
| Latchesar Ionkov | 731805b | 2006-03-07 21:55:42 -0800 | [diff] [blame] | 320 | return ERR_PTR(-ENOSPC); | 
| Latchesar Ionkov | 6a3124a | 2006-03-02 02:54:30 -0800 | [diff] [blame] | 321 | } | 
|  | 322 |  | 
|  | 323 | err = v9fs_t_walk(v9ses, fid, nfid, (char *) dentry->d_name.name, | 
|  | 324 | &fcall); | 
|  | 325 |  | 
|  | 326 | if (err < 0) { | 
| Latchesar Ionkov | 41e5a6a | 2006-05-15 09:44:21 -0700 | [diff] [blame] | 327 | if (fcall && fcall->id == RWALK) | 
|  | 328 | goto clunk_fid; | 
|  | 329 |  | 
| Latchesar Ionkov | 6a3124a | 2006-03-02 02:54:30 -0800 | [diff] [blame] | 330 | PRINT_FCALL_ERROR("walk error", fcall); | 
|  | 331 | v9fs_put_idpool(nfid, &v9ses->fidpool); | 
|  | 332 | goto error; | 
|  | 333 | } | 
|  | 334 |  | 
| Eric Van Hensbergen | 2bad847 | 2005-09-09 13:04:19 -0700 | [diff] [blame] | 335 | kfree(fcall); | 
| Latchesar Ionkov | 3cf6429 | 2006-01-08 01:04:58 -0800 | [diff] [blame] | 336 | fcall = NULL; | 
| Latchesar Ionkov | 6a3124a | 2006-03-02 02:54:30 -0800 | [diff] [blame] | 337 | ret = v9fs_fid_create(v9ses, nfid); | 
|  | 338 | if (!ret) { | 
|  | 339 | err = -ENOMEM; | 
|  | 340 | goto clunk_fid; | 
|  | 341 | } | 
| Eric Van Hensbergen | 2bad847 | 2005-09-09 13:04:19 -0700 | [diff] [blame] | 342 |  | 
| Latchesar Ionkov | 6a3124a | 2006-03-02 02:54:30 -0800 | [diff] [blame] | 343 | err = v9fs_fid_insert(ret, dentry); | 
|  | 344 | if (err < 0) { | 
|  | 345 | v9fs_fid_destroy(ret); | 
|  | 346 | goto clunk_fid; | 
| Latchesar Ionkov | 0b8dd17 | 2005-09-27 21:45:24 -0700 | [diff] [blame] | 347 | } | 
| Latchesar Ionkov | 6a3124a | 2006-03-02 02:54:30 -0800 | [diff] [blame] | 348 |  | 
|  | 349 | return ret; | 
|  | 350 |  | 
|  | 351 | clunk_fid: | 
|  | 352 | v9fs_t_clunk(v9ses, nfid); | 
|  | 353 |  | 
|  | 354 | error: | 
|  | 355 | kfree(fcall); | 
|  | 356 | return ERR_PTR(err); | 
|  | 357 | } | 
|  | 358 |  | 
| Latchesar Ionkov | 5174fda | 2006-03-25 03:07:25 -0800 | [diff] [blame] | 359 | static struct inode * | 
| Latchesar Ionkov | 6a3124a | 2006-03-02 02:54:30 -0800 | [diff] [blame] | 360 | v9fs_inode_from_fid(struct v9fs_session_info *v9ses, u32 fid, | 
|  | 361 | struct super_block *sb) | 
|  | 362 | { | 
|  | 363 | int err, umode; | 
|  | 364 | struct inode *ret; | 
|  | 365 | struct v9fs_fcall *fcall; | 
|  | 366 |  | 
|  | 367 | ret = NULL; | 
|  | 368 | err = v9fs_t_stat(v9ses, fid, &fcall); | 
|  | 369 | if (err) { | 
|  | 370 | PRINT_FCALL_ERROR("stat error", fcall); | 
|  | 371 | goto error; | 
| Eric Van Hensbergen | 2bad847 | 2005-09-09 13:04:19 -0700 | [diff] [blame] | 372 | } | 
| Latchesar Ionkov | 6a3124a | 2006-03-02 02:54:30 -0800 | [diff] [blame] | 373 |  | 
|  | 374 | umode = p9mode2unixmode(v9ses, fcall->params.rstat.stat.mode); | 
|  | 375 | ret = v9fs_get_inode(sb, umode); | 
|  | 376 | if (IS_ERR(ret)) { | 
|  | 377 | err = PTR_ERR(ret); | 
|  | 378 | ret = NULL; | 
|  | 379 | goto error; | 
|  | 380 | } | 
|  | 381 |  | 
|  | 382 | v9fs_stat2inode(&fcall->params.rstat.stat, ret, sb); | 
|  | 383 | kfree(fcall); | 
|  | 384 | return ret; | 
|  | 385 |  | 
|  | 386 | error: | 
|  | 387 | kfree(fcall); | 
|  | 388 | if (ret) | 
|  | 389 | iput(ret); | 
|  | 390 |  | 
|  | 391 | return ERR_PTR(err); | 
| Eric Van Hensbergen | 2bad847 | 2005-09-09 13:04:19 -0700 | [diff] [blame] | 392 | } | 
|  | 393 |  | 
|  | 394 | /** | 
|  | 395 | * v9fs_remove - helper function to remove files and directories | 
| Eric Van Hensbergen | 73c592b | 2005-09-09 13:04:26 -0700 | [diff] [blame] | 396 | * @dir: directory inode that is being deleted | 
|  | 397 | * @file:  dentry that is being deleted | 
|  | 398 | * @rmdir: removing a directory | 
| Eric Van Hensbergen | 2bad847 | 2005-09-09 13:04:19 -0700 | [diff] [blame] | 399 | * | 
|  | 400 | */ | 
|  | 401 |  | 
|  | 402 | static int v9fs_remove(struct inode *dir, struct dentry *file, int rmdir) | 
|  | 403 | { | 
|  | 404 | struct v9fs_fcall *fcall = NULL; | 
|  | 405 | struct super_block *sb = NULL; | 
|  | 406 | struct v9fs_session_info *v9ses = NULL; | 
|  | 407 | struct v9fs_fid *v9fid = NULL; | 
|  | 408 | struct inode *file_inode = NULL; | 
|  | 409 | int fid = -1; | 
|  | 410 | int result = 0; | 
|  | 411 |  | 
|  | 412 | dprintk(DEBUG_VFS, "inode: %p dentry: %p rmdir: %d\n", dir, file, | 
|  | 413 | rmdir); | 
|  | 414 |  | 
|  | 415 | file_inode = file->d_inode; | 
|  | 416 | sb = file_inode->i_sb; | 
|  | 417 | v9ses = v9fs_inode2v9ses(file_inode); | 
| Latchesar Ionkov | 0b8dd17 | 2005-09-27 21:45:24 -0700 | [diff] [blame] | 418 | v9fid = v9fs_fid_lookup(file); | 
| Eric Van Hensbergen | da977b2 | 2007-01-26 00:57:06 -0800 | [diff] [blame] | 419 | if(IS_ERR(v9fid)) | 
|  | 420 | return PTR_ERR(v9fid); | 
| Eric Van Hensbergen | 2bad847 | 2005-09-09 13:04:19 -0700 | [diff] [blame] | 421 |  | 
|  | 422 | fid = v9fid->fid; | 
|  | 423 | if (fid < 0) { | 
|  | 424 | dprintk(DEBUG_ERROR, "inode #%lu, no fid!\n", | 
|  | 425 | file_inode->i_ino); | 
|  | 426 | return -EBADF; | 
|  | 427 | } | 
|  | 428 |  | 
|  | 429 | result = v9fs_t_remove(v9ses, fid, &fcall); | 
| Latchesar Ionkov | 531b109 | 2006-01-08 01:05:00 -0800 | [diff] [blame] | 430 | if (result < 0) { | 
|  | 431 | PRINT_FCALL_ERROR("remove fails", fcall); | 
| Eric Van Hensbergen | da977b2 | 2007-01-26 00:57:06 -0800 | [diff] [blame] | 432 | goto Error; | 
| Eric Van Hensbergen | 2bad847 | 2005-09-09 13:04:19 -0700 | [diff] [blame] | 433 | } | 
|  | 434 |  | 
| Eric Van Hensbergen | 834a9b8 | 2006-07-30 03:04:16 -0700 | [diff] [blame] | 435 | v9fs_put_idpool(fid, &v9ses->fidpool); | 
|  | 436 | v9fs_fid_destroy(v9fid); | 
|  | 437 |  | 
| Eric Van Hensbergen | da977b2 | 2007-01-26 00:57:06 -0800 | [diff] [blame] | 438 | Error: | 
| Eric Van Hensbergen | 2bad847 | 2005-09-09 13:04:19 -0700 | [diff] [blame] | 439 | kfree(fcall); | 
|  | 440 | return result; | 
|  | 441 | } | 
|  | 442 |  | 
| Latchesar Ionkov | 6a3124a | 2006-03-02 02:54:30 -0800 | [diff] [blame] | 443 | static int | 
|  | 444 | v9fs_open_created(struct inode *inode, struct file *file) | 
|  | 445 | { | 
|  | 446 | return 0; | 
|  | 447 | } | 
|  | 448 |  | 
| Eric Van Hensbergen | 2bad847 | 2005-09-09 13:04:19 -0700 | [diff] [blame] | 449 | /** | 
|  | 450 | * v9fs_vfs_create - VFS hook to create files | 
|  | 451 | * @inode: directory inode that is being deleted | 
|  | 452 | * @dentry:  dentry that is being deleted | 
| Latchesar Ionkov | 6a3124a | 2006-03-02 02:54:30 -0800 | [diff] [blame] | 453 | * @mode: create permissions | 
| Eric Van Hensbergen | 2bad847 | 2005-09-09 13:04:19 -0700 | [diff] [blame] | 454 | * @nd: path information | 
|  | 455 | * | 
|  | 456 | */ | 
|  | 457 |  | 
|  | 458 | static int | 
| Latchesar Ionkov | 6a3124a | 2006-03-02 02:54:30 -0800 | [diff] [blame] | 459 | v9fs_vfs_create(struct inode *dir, struct dentry *dentry, int mode, | 
| Eric Van Hensbergen | 2bad847 | 2005-09-09 13:04:19 -0700 | [diff] [blame] | 460 | struct nameidata *nd) | 
|  | 461 | { | 
| Latchesar Ionkov | 6a3124a | 2006-03-02 02:54:30 -0800 | [diff] [blame] | 462 | int err; | 
|  | 463 | u32 fid, perm, iounit; | 
|  | 464 | int flags; | 
|  | 465 | struct v9fs_session_info *v9ses; | 
|  | 466 | struct v9fs_fid *dfid, *vfid, *ffid; | 
|  | 467 | struct inode *inode; | 
|  | 468 | struct v9fs_qid qid; | 
|  | 469 | struct file *filp; | 
|  | 470 |  | 
|  | 471 | inode = NULL; | 
|  | 472 | vfid = NULL; | 
|  | 473 | v9ses = v9fs_inode2v9ses(dir); | 
| Eric Van Hensbergen | da977b2 | 2007-01-26 00:57:06 -0800 | [diff] [blame] | 474 | dfid = v9fs_fid_clone(dentry->d_parent); | 
|  | 475 | if(IS_ERR(dfid)) { | 
|  | 476 | err = PTR_ERR(dfid); | 
|  | 477 | goto error; | 
|  | 478 | } | 
| Latchesar Ionkov | 6a3124a | 2006-03-02 02:54:30 -0800 | [diff] [blame] | 479 |  | 
| Eric Van Hensbergen | da977b2 | 2007-01-26 00:57:06 -0800 | [diff] [blame] | 480 | perm = unixmode2p9mode(v9ses, mode); | 
| Latchesar Ionkov | 6a3124a | 2006-03-02 02:54:30 -0800 | [diff] [blame] | 481 | if (nd && nd->flags & LOOKUP_OPEN) | 
|  | 482 | flags = nd->intent.open.flags - 1; | 
|  | 483 | else | 
|  | 484 | flags = O_RDWR; | 
|  | 485 |  | 
|  | 486 | err = v9fs_create(v9ses, dfid->fid, (char *) dentry->d_name.name, | 
| Latchesar Ionkov | 16cce6d | 2006-03-25 03:07:26 -0800 | [diff] [blame] | 487 | perm, v9fs_uflags2omode(flags), NULL, &fid, &qid, &iounit); | 
| Latchesar Ionkov | 6a3124a | 2006-03-02 02:54:30 -0800 | [diff] [blame] | 488 |  | 
|  | 489 | if (err) | 
| Eric Van Hensbergen | da977b2 | 2007-01-26 00:57:06 -0800 | [diff] [blame] | 490 | goto clunk_dfid; | 
| Latchesar Ionkov | 6a3124a | 2006-03-02 02:54:30 -0800 | [diff] [blame] | 491 |  | 
|  | 492 | vfid = v9fs_clone_walk(v9ses, dfid->fid, dentry); | 
| Eric Van Hensbergen | da977b2 | 2007-01-26 00:57:06 -0800 | [diff] [blame] | 493 | v9fs_fid_clunk(v9ses, dfid); | 
| Latchesar Ionkov | 6a3124a | 2006-03-02 02:54:30 -0800 | [diff] [blame] | 494 | if (IS_ERR(vfid)) { | 
|  | 495 | err = PTR_ERR(vfid); | 
|  | 496 | vfid = NULL; | 
|  | 497 | goto error; | 
|  | 498 | } | 
|  | 499 |  | 
|  | 500 | inode = v9fs_inode_from_fid(v9ses, vfid->fid, dir->i_sb); | 
|  | 501 | if (IS_ERR(inode)) { | 
|  | 502 | err = PTR_ERR(inode); | 
|  | 503 | inode = NULL; | 
|  | 504 | goto error; | 
|  | 505 | } | 
|  | 506 |  | 
| Eric Van Hensbergen | e03abc0 | 2007-02-11 13:21:39 -0600 | [diff] [blame] | 507 | if(v9ses->cache) | 
|  | 508 | dentry->d_op = &v9fs_cached_dentry_operations; | 
|  | 509 | else | 
|  | 510 | dentry->d_op = &v9fs_dentry_operations; | 
| Latchesar Ionkov | 6a3124a | 2006-03-02 02:54:30 -0800 | [diff] [blame] | 511 | d_instantiate(dentry, inode); | 
|  | 512 |  | 
|  | 513 | if (nd && nd->flags & LOOKUP_OPEN) { | 
|  | 514 | ffid = v9fs_fid_create(v9ses, fid); | 
|  | 515 | if (!ffid) | 
|  | 516 | return -ENOMEM; | 
|  | 517 |  | 
|  | 518 | filp = lookup_instantiate_filp(nd, dentry, v9fs_open_created); | 
|  | 519 | if (IS_ERR(filp)) { | 
|  | 520 | v9fs_fid_destroy(ffid); | 
|  | 521 | return PTR_ERR(filp); | 
|  | 522 | } | 
|  | 523 |  | 
|  | 524 | ffid->rdir_pos = 0; | 
|  | 525 | ffid->rdir_fcall = NULL; | 
|  | 526 | ffid->fidopen = 1; | 
|  | 527 | ffid->iounit = iounit; | 
|  | 528 | ffid->filp = filp; | 
|  | 529 | filp->private_data = ffid; | 
|  | 530 | } | 
|  | 531 |  | 
|  | 532 | return 0; | 
|  | 533 |  | 
| Eric Van Hensbergen | da977b2 | 2007-01-26 00:57:06 -0800 | [diff] [blame] | 534 | clunk_dfid: | 
|  | 535 | v9fs_fid_clunk(v9ses, dfid); | 
|  | 536 |  | 
| Latchesar Ionkov | 6a3124a | 2006-03-02 02:54:30 -0800 | [diff] [blame] | 537 | error: | 
|  | 538 | if (vfid) | 
|  | 539 | v9fs_fid_destroy(vfid); | 
|  | 540 |  | 
| Latchesar Ionkov | 6a3124a | 2006-03-02 02:54:30 -0800 | [diff] [blame] | 541 | return err; | 
| Eric Van Hensbergen | 2bad847 | 2005-09-09 13:04:19 -0700 | [diff] [blame] | 542 | } | 
|  | 543 |  | 
|  | 544 | /** | 
|  | 545 | * v9fs_vfs_mkdir - VFS mkdir hook to create a directory | 
| Eric Van Hensbergen | 73c592b | 2005-09-09 13:04:26 -0700 | [diff] [blame] | 546 | * @inode:  inode that is being unlinked | 
| Eric Van Hensbergen | 2bad847 | 2005-09-09 13:04:19 -0700 | [diff] [blame] | 547 | * @dentry: dentry that is being unlinked | 
|  | 548 | * @mode: mode for new directory | 
|  | 549 | * | 
|  | 550 | */ | 
|  | 551 |  | 
| Latchesar Ionkov | 6a3124a | 2006-03-02 02:54:30 -0800 | [diff] [blame] | 552 | static int v9fs_vfs_mkdir(struct inode *dir, struct dentry *dentry, int mode) | 
| Eric Van Hensbergen | 2bad847 | 2005-09-09 13:04:19 -0700 | [diff] [blame] | 553 | { | 
| Latchesar Ionkov | 6a3124a | 2006-03-02 02:54:30 -0800 | [diff] [blame] | 554 | int err; | 
|  | 555 | u32 fid, perm; | 
|  | 556 | struct v9fs_session_info *v9ses; | 
|  | 557 | struct v9fs_fid *dfid, *vfid; | 
|  | 558 | struct inode *inode; | 
|  | 559 |  | 
|  | 560 | inode = NULL; | 
|  | 561 | vfid = NULL; | 
|  | 562 | v9ses = v9fs_inode2v9ses(dir); | 
| Eric Van Hensbergen | da977b2 | 2007-01-26 00:57:06 -0800 | [diff] [blame] | 563 | dfid = v9fs_fid_clone(dentry->d_parent); | 
|  | 564 | if(IS_ERR(dfid)) { | 
|  | 565 | err = PTR_ERR(dfid); | 
|  | 566 | goto error; | 
|  | 567 | } | 
|  | 568 |  | 
| Latchesar Ionkov | 6a3124a | 2006-03-02 02:54:30 -0800 | [diff] [blame] | 569 | perm = unixmode2p9mode(v9ses, mode | S_IFDIR); | 
|  | 570 |  | 
|  | 571 | err = v9fs_create(v9ses, dfid->fid, (char *) dentry->d_name.name, | 
| Latchesar Ionkov | 16cce6d | 2006-03-25 03:07:26 -0800 | [diff] [blame] | 572 | perm, V9FS_OREAD, NULL, &fid, NULL, NULL); | 
| Latchesar Ionkov | 6a3124a | 2006-03-02 02:54:30 -0800 | [diff] [blame] | 573 |  | 
|  | 574 | if (err) { | 
|  | 575 | dprintk(DEBUG_ERROR, "create error %d\n", err); | 
| Eric Van Hensbergen | da977b2 | 2007-01-26 00:57:06 -0800 | [diff] [blame] | 576 | goto clean_up_dfid; | 
| Latchesar Ionkov | 6a3124a | 2006-03-02 02:54:30 -0800 | [diff] [blame] | 577 | } | 
|  | 578 |  | 
|  | 579 | vfid = v9fs_clone_walk(v9ses, dfid->fid, dentry); | 
|  | 580 | if (IS_ERR(vfid)) { | 
|  | 581 | err = PTR_ERR(vfid); | 
|  | 582 | vfid = NULL; | 
| Eric Van Hensbergen | da977b2 | 2007-01-26 00:57:06 -0800 | [diff] [blame] | 583 | goto clean_up_dfid; | 
| Latchesar Ionkov | 6a3124a | 2006-03-02 02:54:30 -0800 | [diff] [blame] | 584 | } | 
|  | 585 |  | 
| Eric Van Hensbergen | da977b2 | 2007-01-26 00:57:06 -0800 | [diff] [blame] | 586 | v9fs_fid_clunk(v9ses, dfid); | 
| Latchesar Ionkov | 6a3124a | 2006-03-02 02:54:30 -0800 | [diff] [blame] | 587 | inode = v9fs_inode_from_fid(v9ses, vfid->fid, dir->i_sb); | 
|  | 588 | if (IS_ERR(inode)) { | 
|  | 589 | err = PTR_ERR(inode); | 
|  | 590 | inode = NULL; | 
| Adrian Bunk | 835d90c | 2007-02-08 14:20:38 -0800 | [diff] [blame] | 591 | v9fs_fid_destroy(vfid); | 
|  | 592 | goto error; | 
| Latchesar Ionkov | 6a3124a | 2006-03-02 02:54:30 -0800 | [diff] [blame] | 593 | } | 
|  | 594 |  | 
| Eric Van Hensbergen | e03abc0 | 2007-02-11 13:21:39 -0600 | [diff] [blame] | 595 | if(v9ses->cache) | 
|  | 596 | dentry->d_op = &v9fs_cached_dentry_operations; | 
|  | 597 | else | 
|  | 598 | dentry->d_op = &v9fs_dentry_operations; | 
| Latchesar Ionkov | 6a3124a | 2006-03-02 02:54:30 -0800 | [diff] [blame] | 599 | d_instantiate(dentry, inode); | 
|  | 600 | return 0; | 
|  | 601 |  | 
| Eric Van Hensbergen | da977b2 | 2007-01-26 00:57:06 -0800 | [diff] [blame] | 602 | clean_up_dfid: | 
|  | 603 | v9fs_fid_clunk(v9ses, dfid); | 
|  | 604 |  | 
|  | 605 | error: | 
| Latchesar Ionkov | 6a3124a | 2006-03-02 02:54:30 -0800 | [diff] [blame] | 606 | return err; | 
| Eric Van Hensbergen | 2bad847 | 2005-09-09 13:04:19 -0700 | [diff] [blame] | 607 | } | 
|  | 608 |  | 
|  | 609 | /** | 
|  | 610 | * v9fs_vfs_lookup - VFS lookup hook to "walk" to a new inode | 
|  | 611 | * @dir:  inode that is being walked from | 
|  | 612 | * @dentry: dentry that is being walked to? | 
|  | 613 | * @nameidata: path data | 
|  | 614 | * | 
|  | 615 | */ | 
|  | 616 |  | 
|  | 617 | static struct dentry *v9fs_vfs_lookup(struct inode *dir, struct dentry *dentry, | 
|  | 618 | struct nameidata *nameidata) | 
|  | 619 | { | 
|  | 620 | struct super_block *sb; | 
|  | 621 | struct v9fs_session_info *v9ses; | 
|  | 622 | struct v9fs_fid *dirfid; | 
|  | 623 | struct v9fs_fid *fid; | 
|  | 624 | struct inode *inode; | 
|  | 625 | struct v9fs_fcall *fcall = NULL; | 
| Eric Van Hensbergen | 2bad847 | 2005-09-09 13:04:19 -0700 | [diff] [blame] | 626 | int dirfidnum = -1; | 
|  | 627 | int newfid = -1; | 
|  | 628 | int result = 0; | 
|  | 629 |  | 
|  | 630 | dprintk(DEBUG_VFS, "dir: %p dentry: (%s) %p nameidata: %p\n", | 
| Latchesar Ionkov | 731805b | 2006-03-07 21:55:42 -0800 | [diff] [blame] | 631 | dir, dentry->d_name.name, dentry, nameidata); | 
| Eric Van Hensbergen | 2bad847 | 2005-09-09 13:04:19 -0700 | [diff] [blame] | 632 |  | 
|  | 633 | sb = dir->i_sb; | 
|  | 634 | v9ses = v9fs_inode2v9ses(dir); | 
| Latchesar Ionkov | 0b8dd17 | 2005-09-27 21:45:24 -0700 | [diff] [blame] | 635 | dirfid = v9fs_fid_lookup(dentry->d_parent); | 
| Eric Van Hensbergen | 2bad847 | 2005-09-09 13:04:19 -0700 | [diff] [blame] | 636 |  | 
| Eric Van Hensbergen | da977b2 | 2007-01-26 00:57:06 -0800 | [diff] [blame] | 637 | if(IS_ERR(dirfid)) | 
|  | 638 | return ERR_PTR(PTR_ERR(dirfid)); | 
| Eric Van Hensbergen | 2bad847 | 2005-09-09 13:04:19 -0700 | [diff] [blame] | 639 |  | 
|  | 640 | dirfidnum = dirfid->fid; | 
|  | 641 |  | 
| Eric Van Hensbergen | 2bad847 | 2005-09-09 13:04:19 -0700 | [diff] [blame] | 642 | newfid = v9fs_get_idpool(&v9ses->fidpool); | 
|  | 643 | if (newfid < 0) { | 
|  | 644 | eprintk(KERN_WARNING, "newfid fails!\n"); | 
| Eric Van Hensbergen | da977b2 | 2007-01-26 00:57:06 -0800 | [diff] [blame] | 645 | result = -ENOSPC; | 
|  | 646 | goto Release_Dirfid; | 
| Eric Van Hensbergen | 2bad847 | 2005-09-09 13:04:19 -0700 | [diff] [blame] | 647 | } | 
|  | 648 |  | 
| Latchesar Ionkov | 6a3124a | 2006-03-02 02:54:30 -0800 | [diff] [blame] | 649 | result = v9fs_t_walk(v9ses, dirfidnum, newfid, | 
| Latchesar Ionkov | 41e5a6a | 2006-05-15 09:44:21 -0700 | [diff] [blame] | 650 | (char *)dentry->d_name.name, &fcall); | 
|  | 651 |  | 
| Eric Van Hensbergen | da977b2 | 2007-01-26 00:57:06 -0800 | [diff] [blame] | 652 | up(&dirfid->lock); | 
|  | 653 |  | 
| Eric Van Hensbergen | 2bad847 | 2005-09-09 13:04:19 -0700 | [diff] [blame] | 654 | if (result < 0) { | 
| Latchesar Ionkov | 41e5a6a | 2006-05-15 09:44:21 -0700 | [diff] [blame] | 655 | if (fcall && fcall->id == RWALK) | 
|  | 656 | v9fs_t_clunk(v9ses, newfid); | 
|  | 657 | else | 
|  | 658 | v9fs_put_idpool(newfid, &v9ses->fidpool); | 
|  | 659 |  | 
| Eric Van Hensbergen | 2bad847 | 2005-09-09 13:04:19 -0700 | [diff] [blame] | 660 | if (result == -ENOENT) { | 
|  | 661 | d_add(dentry, NULL); | 
| Latchesar Ionkov | 0b8dd17 | 2005-09-27 21:45:24 -0700 | [diff] [blame] | 662 | dprintk(DEBUG_VFS, | 
| Eric Van Hensbergen | 2bad847 | 2005-09-09 13:04:19 -0700 | [diff] [blame] | 663 | "Return negative dentry %p count %d\n", | 
|  | 664 | dentry, atomic_read(&dentry->d_count)); | 
| Latchesar Ionkov | 41e5a6a | 2006-05-15 09:44:21 -0700 | [diff] [blame] | 665 | kfree(fcall); | 
| Eric Van Hensbergen | 2bad847 | 2005-09-09 13:04:19 -0700 | [diff] [blame] | 666 | return NULL; | 
|  | 667 | } | 
|  | 668 | dprintk(DEBUG_ERROR, "walk error:%d\n", result); | 
|  | 669 | goto FreeFcall; | 
|  | 670 | } | 
| Latchesar Ionkov | 41e5a6a | 2006-05-15 09:44:21 -0700 | [diff] [blame] | 671 | kfree(fcall); | 
| Eric Van Hensbergen | 2bad847 | 2005-09-09 13:04:19 -0700 | [diff] [blame] | 672 |  | 
|  | 673 | result = v9fs_t_stat(v9ses, newfid, &fcall); | 
|  | 674 | if (result < 0) { | 
|  | 675 | dprintk(DEBUG_ERROR, "stat error\n"); | 
|  | 676 | goto FreeFcall; | 
|  | 677 | } | 
|  | 678 |  | 
| Latchesar Ionkov | 531b109 | 2006-01-08 01:05:00 -0800 | [diff] [blame] | 679 | inode = v9fs_get_inode(sb, p9mode2unixmode(v9ses, | 
|  | 680 | fcall->params.rstat.stat.mode)); | 
| Eric Van Hensbergen | 2bad847 | 2005-09-09 13:04:19 -0700 | [diff] [blame] | 681 |  | 
|  | 682 | if (IS_ERR(inode) && (PTR_ERR(inode) == -ENOSPC)) { | 
|  | 683 | eprintk(KERN_WARNING, "inode alloc failes, returns %ld\n", | 
|  | 684 | PTR_ERR(inode)); | 
|  | 685 |  | 
|  | 686 | result = -ENOSPC; | 
|  | 687 | goto FreeFcall; | 
|  | 688 | } | 
|  | 689 |  | 
| Latchesar Ionkov | 531b109 | 2006-01-08 01:05:00 -0800 | [diff] [blame] | 690 | inode->i_ino = v9fs_qid2ino(&fcall->params.rstat.stat.qid); | 
| Eric Van Hensbergen | 2bad847 | 2005-09-09 13:04:19 -0700 | [diff] [blame] | 691 |  | 
| Latchesar Ionkov | 6a3124a | 2006-03-02 02:54:30 -0800 | [diff] [blame] | 692 | fid = v9fs_fid_create(v9ses, newfid); | 
| Eric Van Hensbergen | 2bad847 | 2005-09-09 13:04:19 -0700 | [diff] [blame] | 693 | if (fid == NULL) { | 
|  | 694 | dprintk(DEBUG_ERROR, "couldn't insert\n"); | 
|  | 695 | result = -ENOMEM; | 
|  | 696 | goto FreeFcall; | 
|  | 697 | } | 
|  | 698 |  | 
| Latchesar Ionkov | 6a3124a | 2006-03-02 02:54:30 -0800 | [diff] [blame] | 699 | result = v9fs_fid_insert(fid, dentry); | 
|  | 700 | if (result < 0) | 
|  | 701 | goto FreeFcall; | 
|  | 702 |  | 
| Latchesar Ionkov | 531b109 | 2006-01-08 01:05:00 -0800 | [diff] [blame] | 703 | fid->qid = fcall->params.rstat.stat.qid; | 
| Latchesar Ionkov | 531b109 | 2006-01-08 01:05:00 -0800 | [diff] [blame] | 704 | v9fs_stat2inode(&fcall->params.rstat.stat, inode, inode->i_sb); | 
| Eric Van Hensbergen | e03abc0 | 2007-02-11 13:21:39 -0600 | [diff] [blame] | 705 | if((fid->qid.version)&&(v9ses->cache)) | 
|  | 706 | dentry->d_op = &v9fs_cached_dentry_operations; | 
|  | 707 | else | 
|  | 708 | dentry->d_op = &v9fs_dentry_operations; | 
| Eric Van Hensbergen | 2bad847 | 2005-09-09 13:04:19 -0700 | [diff] [blame] | 709 |  | 
|  | 710 | d_add(dentry, inode); | 
|  | 711 | kfree(fcall); | 
|  | 712 |  | 
|  | 713 | return NULL; | 
|  | 714 |  | 
| Eric Van Hensbergen | da977b2 | 2007-01-26 00:57:06 -0800 | [diff] [blame] | 715 | Release_Dirfid: | 
|  | 716 | up(&dirfid->lock); | 
|  | 717 |  | 
|  | 718 | FreeFcall: | 
| Eric Van Hensbergen | 2bad847 | 2005-09-09 13:04:19 -0700 | [diff] [blame] | 719 | kfree(fcall); | 
| Eric Van Hensbergen | da977b2 | 2007-01-26 00:57:06 -0800 | [diff] [blame] | 720 |  | 
| Eric Van Hensbergen | 2bad847 | 2005-09-09 13:04:19 -0700 | [diff] [blame] | 721 | return ERR_PTR(result); | 
|  | 722 | } | 
|  | 723 |  | 
|  | 724 | /** | 
|  | 725 | * v9fs_vfs_unlink - VFS unlink hook to delete an inode | 
|  | 726 | * @i:  inode that is being unlinked | 
| Eric Van Hensbergen | 73c592b | 2005-09-09 13:04:26 -0700 | [diff] [blame] | 727 | * @d: dentry that is being unlinked | 
| Eric Van Hensbergen | 2bad847 | 2005-09-09 13:04:19 -0700 | [diff] [blame] | 728 | * | 
|  | 729 | */ | 
|  | 730 |  | 
|  | 731 | static int v9fs_vfs_unlink(struct inode *i, struct dentry *d) | 
|  | 732 | { | 
|  | 733 | return v9fs_remove(i, d, 0); | 
|  | 734 | } | 
|  | 735 |  | 
|  | 736 | /** | 
|  | 737 | * v9fs_vfs_rmdir - VFS unlink hook to delete a directory | 
|  | 738 | * @i:  inode that is being unlinked | 
| Eric Van Hensbergen | 73c592b | 2005-09-09 13:04:26 -0700 | [diff] [blame] | 739 | * @d: dentry that is being unlinked | 
| Eric Van Hensbergen | 2bad847 | 2005-09-09 13:04:19 -0700 | [diff] [blame] | 740 | * | 
|  | 741 | */ | 
|  | 742 |  | 
|  | 743 | static int v9fs_vfs_rmdir(struct inode *i, struct dentry *d) | 
|  | 744 | { | 
|  | 745 | return v9fs_remove(i, d, 1); | 
|  | 746 | } | 
|  | 747 |  | 
|  | 748 | /** | 
|  | 749 | * v9fs_vfs_rename - VFS hook to rename an inode | 
|  | 750 | * @old_dir:  old dir inode | 
|  | 751 | * @old_dentry: old dentry | 
|  | 752 | * @new_dir: new dir inode | 
|  | 753 | * @new_dentry: new dentry | 
|  | 754 | * | 
|  | 755 | */ | 
|  | 756 |  | 
|  | 757 | static int | 
|  | 758 | v9fs_vfs_rename(struct inode *old_dir, struct dentry *old_dentry, | 
|  | 759 | struct inode *new_dir, struct dentry *new_dentry) | 
|  | 760 | { | 
|  | 761 | struct inode *old_inode = old_dentry->d_inode; | 
|  | 762 | struct v9fs_session_info *v9ses = v9fs_inode2v9ses(old_inode); | 
| Latchesar Ionkov | 0b8dd17 | 2005-09-27 21:45:24 -0700 | [diff] [blame] | 763 | struct v9fs_fid *oldfid = v9fs_fid_lookup(old_dentry); | 
| Eric Van Hensbergen | da977b2 | 2007-01-26 00:57:06 -0800 | [diff] [blame] | 764 | struct v9fs_fid *olddirfid; | 
|  | 765 | struct v9fs_fid *newdirfid; | 
| Latchesar Ionkov | 531b109 | 2006-01-08 01:05:00 -0800 | [diff] [blame] | 766 | struct v9fs_wstat wstat; | 
| Eric Van Hensbergen | 2bad847 | 2005-09-09 13:04:19 -0700 | [diff] [blame] | 767 | struct v9fs_fcall *fcall = NULL; | 
|  | 768 | int fid = -1; | 
|  | 769 | int olddirfidnum = -1; | 
|  | 770 | int newdirfidnum = -1; | 
|  | 771 | int retval = 0; | 
|  | 772 |  | 
|  | 773 | dprintk(DEBUG_VFS, "\n"); | 
|  | 774 |  | 
| Eric Van Hensbergen | da977b2 | 2007-01-26 00:57:06 -0800 | [diff] [blame] | 775 | if(IS_ERR(oldfid)) | 
|  | 776 | return PTR_ERR(oldfid); | 
|  | 777 |  | 
|  | 778 | olddirfid = v9fs_fid_clone(old_dentry->d_parent); | 
|  | 779 | if(IS_ERR(olddirfid)) { | 
|  | 780 | retval = PTR_ERR(olddirfid); | 
|  | 781 | goto Release_lock; | 
|  | 782 | } | 
|  | 783 |  | 
|  | 784 | newdirfid = v9fs_fid_clone(new_dentry->d_parent); | 
|  | 785 | if(IS_ERR(newdirfid)) { | 
|  | 786 | retval = PTR_ERR(newdirfid); | 
|  | 787 | goto Clunk_olddir; | 
| Eric Van Hensbergen | 2bad847 | 2005-09-09 13:04:19 -0700 | [diff] [blame] | 788 | } | 
|  | 789 |  | 
|  | 790 | /* 9P can only handle file rename in the same directory */ | 
|  | 791 | if (memcmp(&olddirfid->qid, &newdirfid->qid, sizeof(newdirfid->qid))) { | 
|  | 792 | dprintk(DEBUG_ERROR, "old dir and new dir are different\n"); | 
| Eric Van Hensbergen | 621997c | 2007-01-26 00:57:04 -0800 | [diff] [blame] | 793 | retval = -EXDEV; | 
| Eric Van Hensbergen | da977b2 | 2007-01-26 00:57:06 -0800 | [diff] [blame] | 794 | goto Clunk_newdir; | 
| Eric Van Hensbergen | 2bad847 | 2005-09-09 13:04:19 -0700 | [diff] [blame] | 795 | } | 
|  | 796 |  | 
|  | 797 | fid = oldfid->fid; | 
|  | 798 | olddirfidnum = olddirfid->fid; | 
|  | 799 | newdirfidnum = newdirfid->fid; | 
|  | 800 |  | 
|  | 801 | if (fid < 0) { | 
|  | 802 | dprintk(DEBUG_ERROR, "no fid for old file #%lu\n", | 
|  | 803 | old_inode->i_ino); | 
|  | 804 | retval = -EBADF; | 
| Eric Van Hensbergen | da977b2 | 2007-01-26 00:57:06 -0800 | [diff] [blame] | 805 | goto Clunk_newdir; | 
| Eric Van Hensbergen | 2bad847 | 2005-09-09 13:04:19 -0700 | [diff] [blame] | 806 | } | 
|  | 807 |  | 
| Latchesar Ionkov | 531b109 | 2006-01-08 01:05:00 -0800 | [diff] [blame] | 808 | v9fs_blank_wstat(&wstat); | 
|  | 809 | wstat.muid = v9ses->name; | 
|  | 810 | wstat.name = (char *) new_dentry->d_name.name; | 
| Eric Van Hensbergen | 2bad847 | 2005-09-09 13:04:19 -0700 | [diff] [blame] | 811 |  | 
| Latchesar Ionkov | 531b109 | 2006-01-08 01:05:00 -0800 | [diff] [blame] | 812 | retval = v9fs_t_wstat(v9ses, fid, &wstat, &fcall); | 
| Eric Van Hensbergen | 2bad847 | 2005-09-09 13:04:19 -0700 | [diff] [blame] | 813 |  | 
| Eric Van Hensbergen | 2bad847 | 2005-09-09 13:04:19 -0700 | [diff] [blame] | 814 | if (retval < 0) | 
| Latchesar Ionkov | 531b109 | 2006-01-08 01:05:00 -0800 | [diff] [blame] | 815 | PRINT_FCALL_ERROR("wstat error", fcall); | 
| Eric Van Hensbergen | 2bad847 | 2005-09-09 13:04:19 -0700 | [diff] [blame] | 816 |  | 
|  | 817 | kfree(fcall); | 
| Eric Van Hensbergen | da977b2 | 2007-01-26 00:57:06 -0800 | [diff] [blame] | 818 |  | 
|  | 819 | Clunk_newdir: | 
|  | 820 | v9fs_fid_clunk(v9ses, newdirfid); | 
|  | 821 |  | 
|  | 822 | Clunk_olddir: | 
|  | 823 | v9fs_fid_clunk(v9ses, olddirfid); | 
|  | 824 |  | 
|  | 825 | Release_lock: | 
|  | 826 | up(&oldfid->lock); | 
|  | 827 |  | 
| Eric Van Hensbergen | 2bad847 | 2005-09-09 13:04:19 -0700 | [diff] [blame] | 828 | return retval; | 
|  | 829 | } | 
|  | 830 |  | 
|  | 831 | /** | 
| Adrian Bunk | 943ffb5 | 2006-01-10 00:10:13 +0100 | [diff] [blame] | 832 | * v9fs_vfs_getattr - retrieve file metadata | 
| Eric Van Hensbergen | 2bad847 | 2005-09-09 13:04:19 -0700 | [diff] [blame] | 833 | * @mnt - mount information | 
|  | 834 | * @dentry - file to get attributes on | 
|  | 835 | * @stat - metadata structure to populate | 
|  | 836 | * | 
|  | 837 | */ | 
|  | 838 |  | 
|  | 839 | static int | 
|  | 840 | v9fs_vfs_getattr(struct vfsmount *mnt, struct dentry *dentry, | 
|  | 841 | struct kstat *stat) | 
|  | 842 | { | 
|  | 843 | struct v9fs_fcall *fcall = NULL; | 
|  | 844 | struct v9fs_session_info *v9ses = v9fs_inode2v9ses(dentry->d_inode); | 
| Eric Van Hensbergen | da977b2 | 2007-01-26 00:57:06 -0800 | [diff] [blame] | 845 | struct v9fs_fid *fid = v9fs_fid_clone(dentry); | 
| Eric Van Hensbergen | 2bad847 | 2005-09-09 13:04:19 -0700 | [diff] [blame] | 846 | int err = -EPERM; | 
|  | 847 |  | 
|  | 848 | dprintk(DEBUG_VFS, "dentry: %p\n", dentry); | 
| Eric Van Hensbergen | da977b2 | 2007-01-26 00:57:06 -0800 | [diff] [blame] | 849 | if(IS_ERR(fid)) | 
|  | 850 | return PTR_ERR(fid); | 
| Eric Van Hensbergen | 2bad847 | 2005-09-09 13:04:19 -0700 | [diff] [blame] | 851 |  | 
|  | 852 | err = v9fs_t_stat(v9ses, fid->fid, &fcall); | 
|  | 853 |  | 
|  | 854 | if (err < 0) | 
|  | 855 | dprintk(DEBUG_ERROR, "stat error\n"); | 
|  | 856 | else { | 
| Latchesar Ionkov | 531b109 | 2006-01-08 01:05:00 -0800 | [diff] [blame] | 857 | v9fs_stat2inode(&fcall->params.rstat.stat, dentry->d_inode, | 
| Eric Van Hensbergen | 2bad847 | 2005-09-09 13:04:19 -0700 | [diff] [blame] | 858 | dentry->d_inode->i_sb); | 
|  | 859 | generic_fillattr(dentry->d_inode, stat); | 
|  | 860 | } | 
|  | 861 |  | 
|  | 862 | kfree(fcall); | 
| Eric Van Hensbergen | da977b2 | 2007-01-26 00:57:06 -0800 | [diff] [blame] | 863 | v9fs_fid_clunk(v9ses, fid); | 
| Eric Van Hensbergen | 2bad847 | 2005-09-09 13:04:19 -0700 | [diff] [blame] | 864 | return err; | 
|  | 865 | } | 
|  | 866 |  | 
|  | 867 | /** | 
|  | 868 | * v9fs_vfs_setattr - set file metadata | 
|  | 869 | * @dentry: file whose metadata to set | 
|  | 870 | * @iattr: metadata assignment structure | 
|  | 871 | * | 
|  | 872 | */ | 
|  | 873 |  | 
|  | 874 | static int v9fs_vfs_setattr(struct dentry *dentry, struct iattr *iattr) | 
|  | 875 | { | 
|  | 876 | struct v9fs_session_info *v9ses = v9fs_inode2v9ses(dentry->d_inode); | 
| Eric Van Hensbergen | da977b2 | 2007-01-26 00:57:06 -0800 | [diff] [blame] | 877 | struct v9fs_fid *fid = v9fs_fid_clone(dentry); | 
| Eric Van Hensbergen | 2bad847 | 2005-09-09 13:04:19 -0700 | [diff] [blame] | 878 | struct v9fs_fcall *fcall = NULL; | 
| Latchesar Ionkov | 531b109 | 2006-01-08 01:05:00 -0800 | [diff] [blame] | 879 | struct v9fs_wstat wstat; | 
| Eric Van Hensbergen | 2bad847 | 2005-09-09 13:04:19 -0700 | [diff] [blame] | 880 | int res = -EPERM; | 
|  | 881 |  | 
|  | 882 | dprintk(DEBUG_VFS, "\n"); | 
| Eric Van Hensbergen | da977b2 | 2007-01-26 00:57:06 -0800 | [diff] [blame] | 883 | if(IS_ERR(fid)) | 
|  | 884 | return PTR_ERR(fid); | 
| Eric Van Hensbergen | 2bad847 | 2005-09-09 13:04:19 -0700 | [diff] [blame] | 885 |  | 
| Latchesar Ionkov | 531b109 | 2006-01-08 01:05:00 -0800 | [diff] [blame] | 886 | v9fs_blank_wstat(&wstat); | 
| Eric Van Hensbergen | 2bad847 | 2005-09-09 13:04:19 -0700 | [diff] [blame] | 887 | if (iattr->ia_valid & ATTR_MODE) | 
| Latchesar Ionkov | 531b109 | 2006-01-08 01:05:00 -0800 | [diff] [blame] | 888 | wstat.mode = unixmode2p9mode(v9ses, iattr->ia_mode); | 
| Eric Van Hensbergen | 2bad847 | 2005-09-09 13:04:19 -0700 | [diff] [blame] | 889 |  | 
|  | 890 | if (iattr->ia_valid & ATTR_MTIME) | 
| Latchesar Ionkov | 531b109 | 2006-01-08 01:05:00 -0800 | [diff] [blame] | 891 | wstat.mtime = iattr->ia_mtime.tv_sec; | 
| Eric Van Hensbergen | 2bad847 | 2005-09-09 13:04:19 -0700 | [diff] [blame] | 892 |  | 
|  | 893 | if (iattr->ia_valid & ATTR_ATIME) | 
| Latchesar Ionkov | 531b109 | 2006-01-08 01:05:00 -0800 | [diff] [blame] | 894 | wstat.atime = iattr->ia_atime.tv_sec; | 
| Eric Van Hensbergen | 2bad847 | 2005-09-09 13:04:19 -0700 | [diff] [blame] | 895 |  | 
|  | 896 | if (iattr->ia_valid & ATTR_SIZE) | 
| Latchesar Ionkov | 531b109 | 2006-01-08 01:05:00 -0800 | [diff] [blame] | 897 | wstat.length = iattr->ia_size; | 
| Eric Van Hensbergen | 2bad847 | 2005-09-09 13:04:19 -0700 | [diff] [blame] | 898 |  | 
|  | 899 | if (v9ses->extended) { | 
| Latchesar Ionkov | 531b109 | 2006-01-08 01:05:00 -0800 | [diff] [blame] | 900 | if (iattr->ia_valid & ATTR_UID) | 
|  | 901 | wstat.n_uid = iattr->ia_uid; | 
| Eric Van Hensbergen | 2bad847 | 2005-09-09 13:04:19 -0700 | [diff] [blame] | 902 |  | 
| Latchesar Ionkov | 531b109 | 2006-01-08 01:05:00 -0800 | [diff] [blame] | 903 | if (iattr->ia_valid & ATTR_GID) | 
|  | 904 | wstat.n_gid = iattr->ia_gid; | 
| Eric Van Hensbergen | 2bad847 | 2005-09-09 13:04:19 -0700 | [diff] [blame] | 905 | } | 
|  | 906 |  | 
| Latchesar Ionkov | 531b109 | 2006-01-08 01:05:00 -0800 | [diff] [blame] | 907 | res = v9fs_t_wstat(v9ses, fid->fid, &wstat, &fcall); | 
| Eric Van Hensbergen | 2bad847 | 2005-09-09 13:04:19 -0700 | [diff] [blame] | 908 |  | 
|  | 909 | if (res < 0) | 
| Latchesar Ionkov | 531b109 | 2006-01-08 01:05:00 -0800 | [diff] [blame] | 910 | PRINT_FCALL_ERROR("wstat error", fcall); | 
| Eric Van Hensbergen | 2bad847 | 2005-09-09 13:04:19 -0700 | [diff] [blame] | 911 |  | 
| Eric Van Hensbergen | 2bad847 | 2005-09-09 13:04:19 -0700 | [diff] [blame] | 912 | kfree(fcall); | 
| Eric Van Hensbergen | 2bad847 | 2005-09-09 13:04:19 -0700 | [diff] [blame] | 913 | if (res >= 0) | 
|  | 914 | res = inode_setattr(dentry->d_inode, iattr); | 
|  | 915 |  | 
| Eric Van Hensbergen | da977b2 | 2007-01-26 00:57:06 -0800 | [diff] [blame] | 916 | v9fs_fid_clunk(v9ses, fid); | 
| Eric Van Hensbergen | 2bad847 | 2005-09-09 13:04:19 -0700 | [diff] [blame] | 917 | return res; | 
|  | 918 | } | 
|  | 919 |  | 
|  | 920 | /** | 
| Latchesar Ionkov | 531b109 | 2006-01-08 01:05:00 -0800 | [diff] [blame] | 921 | * v9fs_stat2inode - populate an inode structure with mistat info | 
|  | 922 | * @stat: Plan 9 metadata (mistat) structure | 
| Eric Van Hensbergen | 2bad847 | 2005-09-09 13:04:19 -0700 | [diff] [blame] | 923 | * @inode: inode to populate | 
|  | 924 | * @sb: superblock of filesystem | 
|  | 925 | * | 
|  | 926 | */ | 
|  | 927 |  | 
|  | 928 | void | 
| Latchesar Ionkov | 531b109 | 2006-01-08 01:05:00 -0800 | [diff] [blame] | 929 | v9fs_stat2inode(struct v9fs_stat *stat, struct inode *inode, | 
|  | 930 | struct super_block *sb) | 
| Eric Van Hensbergen | 2bad847 | 2005-09-09 13:04:19 -0700 | [diff] [blame] | 931 | { | 
| Latchesar Ionkov | 1dac06b | 2006-01-08 01:05:02 -0800 | [diff] [blame] | 932 | int n; | 
| Latchesar Ionkov | 531b109 | 2006-01-08 01:05:00 -0800 | [diff] [blame] | 933 | char ext[32]; | 
| Eric Van Hensbergen | 2bad847 | 2005-09-09 13:04:19 -0700 | [diff] [blame] | 934 | struct v9fs_session_info *v9ses = sb->s_fs_info; | 
|  | 935 |  | 
|  | 936 | inode->i_nlink = 1; | 
|  | 937 |  | 
| Latchesar Ionkov | 531b109 | 2006-01-08 01:05:00 -0800 | [diff] [blame] | 938 | inode->i_atime.tv_sec = stat->atime; | 
|  | 939 | inode->i_mtime.tv_sec = stat->mtime; | 
|  | 940 | inode->i_ctime.tv_sec = stat->mtime; | 
| Eric Van Hensbergen | 2bad847 | 2005-09-09 13:04:19 -0700 | [diff] [blame] | 941 |  | 
| Latchesar Ionkov | 531b109 | 2006-01-08 01:05:00 -0800 | [diff] [blame] | 942 | inode->i_uid = v9ses->uid; | 
|  | 943 | inode->i_gid = v9ses->gid; | 
| Eric Van Hensbergen | 2bad847 | 2005-09-09 13:04:19 -0700 | [diff] [blame] | 944 |  | 
|  | 945 | if (v9ses->extended) { | 
| Latchesar Ionkov | 531b109 | 2006-01-08 01:05:00 -0800 | [diff] [blame] | 946 | inode->i_uid = stat->n_uid; | 
|  | 947 | inode->i_gid = stat->n_gid; | 
| Eric Van Hensbergen | 2bad847 | 2005-09-09 13:04:19 -0700 | [diff] [blame] | 948 | } | 
|  | 949 |  | 
| Latchesar Ionkov | 531b109 | 2006-01-08 01:05:00 -0800 | [diff] [blame] | 950 | inode->i_mode = p9mode2unixmode(v9ses, stat->mode); | 
| Eric Van Hensbergen | 2bad847 | 2005-09-09 13:04:19 -0700 | [diff] [blame] | 951 | if ((S_ISBLK(inode->i_mode)) || (S_ISCHR(inode->i_mode))) { | 
|  | 952 | char type = 0; | 
|  | 953 | int major = -1; | 
|  | 954 | int minor = -1; | 
| Latchesar Ionkov | 531b109 | 2006-01-08 01:05:00 -0800 | [diff] [blame] | 955 |  | 
| Latchesar Ionkov | 1dac06b | 2006-01-08 01:05:02 -0800 | [diff] [blame] | 956 | n = stat->extension.len; | 
|  | 957 | if (n > sizeof(ext)-1) | 
|  | 958 | n = sizeof(ext)-1; | 
|  | 959 | memmove(ext, stat->extension.str, n); | 
|  | 960 | ext[n] = 0; | 
| Latchesar Ionkov | 531b109 | 2006-01-08 01:05:00 -0800 | [diff] [blame] | 961 | sscanf(ext, "%c %u %u", &type, &major, &minor); | 
| Eric Van Hensbergen | 2bad847 | 2005-09-09 13:04:19 -0700 | [diff] [blame] | 962 | switch (type) { | 
|  | 963 | case 'c': | 
|  | 964 | inode->i_mode &= ~S_IFBLK; | 
|  | 965 | inode->i_mode |= S_IFCHR; | 
|  | 966 | break; | 
|  | 967 | case 'b': | 
|  | 968 | break; | 
|  | 969 | default: | 
| Latchesar Ionkov | 531b109 | 2006-01-08 01:05:00 -0800 | [diff] [blame] | 970 | dprintk(DEBUG_ERROR, "Unknown special type %c (%.*s)\n", | 
|  | 971 | type, stat->extension.len, stat->extension.str); | 
| Eric Van Hensbergen | 2bad847 | 2005-09-09 13:04:19 -0700 | [diff] [blame] | 972 | }; | 
|  | 973 | inode->i_rdev = MKDEV(major, minor); | 
|  | 974 | } else | 
|  | 975 | inode->i_rdev = 0; | 
|  | 976 |  | 
| Latchesar Ionkov | 531b109 | 2006-01-08 01:05:00 -0800 | [diff] [blame] | 977 | inode->i_size = stat->length; | 
| Eric Van Hensbergen | 2bad847 | 2005-09-09 13:04:19 -0700 | [diff] [blame] | 978 |  | 
| Eric Van Hensbergen | 2bad847 | 2005-09-09 13:04:19 -0700 | [diff] [blame] | 979 | inode->i_blocks = | 
| Theodore Ts'o | ba52de1 | 2006-09-27 01:50:49 -0700 | [diff] [blame] | 980 | (inode->i_size + sb->s_blocksize - 1) >> sb->s_blocksize_bits; | 
| Eric Van Hensbergen | 2bad847 | 2005-09-09 13:04:19 -0700 | [diff] [blame] | 981 | } | 
|  | 982 |  | 
|  | 983 | /** | 
|  | 984 | * v9fs_qid2ino - convert qid into inode number | 
|  | 985 | * @qid: qid to hash | 
|  | 986 | * | 
|  | 987 | * BUG: potential for inode number collisions? | 
|  | 988 | */ | 
|  | 989 |  | 
|  | 990 | ino_t v9fs_qid2ino(struct v9fs_qid *qid) | 
|  | 991 | { | 
|  | 992 | u64 path = qid->path + 2; | 
|  | 993 | ino_t i = 0; | 
|  | 994 |  | 
|  | 995 | if (sizeof(ino_t) == sizeof(path)) | 
|  | 996 | memcpy(&i, &path, sizeof(ino_t)); | 
|  | 997 | else | 
|  | 998 | i = (ino_t) (path ^ (path >> 32)); | 
|  | 999 |  | 
|  | 1000 | return i; | 
|  | 1001 | } | 
|  | 1002 |  | 
|  | 1003 | /** | 
| Eric Van Hensbergen | 2bad847 | 2005-09-09 13:04:19 -0700 | [diff] [blame] | 1004 | * v9fs_readlink - read a symlink's location (internal version) | 
|  | 1005 | * @dentry: dentry for symlink | 
| Eric Van Hensbergen | 73c592b | 2005-09-09 13:04:26 -0700 | [diff] [blame] | 1006 | * @buffer: buffer to load symlink location into | 
| Eric Van Hensbergen | 2bad847 | 2005-09-09 13:04:19 -0700 | [diff] [blame] | 1007 | * @buflen: length of buffer | 
|  | 1008 | * | 
|  | 1009 | */ | 
|  | 1010 |  | 
|  | 1011 | static int v9fs_readlink(struct dentry *dentry, char *buffer, int buflen) | 
|  | 1012 | { | 
|  | 1013 | int retval = -EPERM; | 
|  | 1014 |  | 
|  | 1015 | struct v9fs_fcall *fcall = NULL; | 
|  | 1016 | struct v9fs_session_info *v9ses = v9fs_inode2v9ses(dentry->d_inode); | 
| Eric Van Hensbergen | da977b2 | 2007-01-26 00:57:06 -0800 | [diff] [blame] | 1017 | struct v9fs_fid *fid = v9fs_fid_clone(dentry); | 
| Eric Van Hensbergen | 2bad847 | 2005-09-09 13:04:19 -0700 | [diff] [blame] | 1018 |  | 
| Eric Van Hensbergen | da977b2 | 2007-01-26 00:57:06 -0800 | [diff] [blame] | 1019 | if(IS_ERR(fid)) | 
|  | 1020 | return PTR_ERR(fid); | 
| Eric Van Hensbergen | 2bad847 | 2005-09-09 13:04:19 -0700 | [diff] [blame] | 1021 |  | 
|  | 1022 | if (!v9ses->extended) { | 
|  | 1023 | retval = -EBADF; | 
|  | 1024 | dprintk(DEBUG_ERROR, "not extended\n"); | 
| Eric Van Hensbergen | da977b2 | 2007-01-26 00:57:06 -0800 | [diff] [blame] | 1025 | goto ClunkFid; | 
| Eric Van Hensbergen | 2bad847 | 2005-09-09 13:04:19 -0700 | [diff] [blame] | 1026 | } | 
|  | 1027 |  | 
|  | 1028 | dprintk(DEBUG_VFS, " %s\n", dentry->d_name.name); | 
|  | 1029 | retval = v9fs_t_stat(v9ses, fid->fid, &fcall); | 
|  | 1030 |  | 
|  | 1031 | if (retval < 0) { | 
|  | 1032 | dprintk(DEBUG_ERROR, "stat error\n"); | 
|  | 1033 | goto FreeFcall; | 
|  | 1034 | } | 
|  | 1035 |  | 
| Eric Van Hensbergen | da977b2 | 2007-01-26 00:57:06 -0800 | [diff] [blame] | 1036 | if (!fcall) { | 
|  | 1037 | retval = -EIO; | 
|  | 1038 | goto ClunkFid; | 
|  | 1039 | } | 
| Eric Van Hensbergen | 2bad847 | 2005-09-09 13:04:19 -0700 | [diff] [blame] | 1040 |  | 
| Latchesar Ionkov | 531b109 | 2006-01-08 01:05:00 -0800 | [diff] [blame] | 1041 | if (!(fcall->params.rstat.stat.mode & V9FS_DMSYMLINK)) { | 
| Eric Van Hensbergen | 2bad847 | 2005-09-09 13:04:19 -0700 | [diff] [blame] | 1042 | retval = -EINVAL; | 
|  | 1043 | goto FreeFcall; | 
|  | 1044 | } | 
|  | 1045 |  | 
|  | 1046 | /* copy extension buffer into buffer */ | 
| Latchesar Ionkov | 6a3124a | 2006-03-02 02:54:30 -0800 | [diff] [blame] | 1047 | if (fcall->params.rstat.stat.extension.len < buflen) | 
| Latchesar Ionkov | 16cce6d | 2006-03-25 03:07:26 -0800 | [diff] [blame] | 1048 | buflen = fcall->params.rstat.stat.extension.len + 1; | 
| Eric Van Hensbergen | 2bad847 | 2005-09-09 13:04:19 -0700 | [diff] [blame] | 1049 |  | 
| Latchesar Ionkov | 16cce6d | 2006-03-25 03:07:26 -0800 | [diff] [blame] | 1050 | memmove(buffer, fcall->params.rstat.stat.extension.str, buflen - 1); | 
| Latchesar Ionkov | 531b109 | 2006-01-08 01:05:00 -0800 | [diff] [blame] | 1051 | buffer[buflen-1] = 0; | 
| Eric Van Hensbergen | 2bad847 | 2005-09-09 13:04:19 -0700 | [diff] [blame] | 1052 |  | 
| Latchesar Ionkov | 16cce6d | 2006-03-25 03:07:26 -0800 | [diff] [blame] | 1053 | dprintk(DEBUG_ERROR, "%s -> %.*s (%s)\n", dentry->d_name.name, fcall->params.rstat.stat.extension.len, | 
|  | 1054 | fcall->params.rstat.stat.extension.str, buffer); | 
| Eric Van Hensbergen | 2bad847 | 2005-09-09 13:04:19 -0700 | [diff] [blame] | 1055 | retval = buflen; | 
|  | 1056 |  | 
| Eric Van Hensbergen | da977b2 | 2007-01-26 00:57:06 -0800 | [diff] [blame] | 1057 | FreeFcall: | 
| Eric Van Hensbergen | 2bad847 | 2005-09-09 13:04:19 -0700 | [diff] [blame] | 1058 | kfree(fcall); | 
|  | 1059 |  | 
| Eric Van Hensbergen | da977b2 | 2007-01-26 00:57:06 -0800 | [diff] [blame] | 1060 | ClunkFid: | 
|  | 1061 | v9fs_fid_clunk(v9ses, fid); | 
|  | 1062 |  | 
| Eric Van Hensbergen | 2bad847 | 2005-09-09 13:04:19 -0700 | [diff] [blame] | 1063 | return retval; | 
|  | 1064 | } | 
|  | 1065 |  | 
|  | 1066 | /** | 
|  | 1067 | * v9fs_vfs_readlink - read a symlink's location | 
|  | 1068 | * @dentry: dentry for symlink | 
|  | 1069 | * @buf: buffer to load symlink location into | 
|  | 1070 | * @buflen: length of buffer | 
|  | 1071 | * | 
|  | 1072 | */ | 
|  | 1073 |  | 
|  | 1074 | static int v9fs_vfs_readlink(struct dentry *dentry, char __user * buffer, | 
|  | 1075 | int buflen) | 
|  | 1076 | { | 
|  | 1077 | int retval; | 
|  | 1078 | int ret; | 
|  | 1079 | char *link = __getname(); | 
|  | 1080 |  | 
| Florin Malita | 0710d36 | 2006-06-25 05:48:31 -0700 | [diff] [blame] | 1081 | if (unlikely(!link)) | 
|  | 1082 | return -ENOMEM; | 
|  | 1083 |  | 
| Latchesar Ionkov | a1f9d8d | 2005-09-22 21:43:52 -0700 | [diff] [blame] | 1084 | if (buflen > PATH_MAX) | 
|  | 1085 | buflen = PATH_MAX; | 
| Eric Van Hensbergen | 2bad847 | 2005-09-09 13:04:19 -0700 | [diff] [blame] | 1086 |  | 
|  | 1087 | dprintk(DEBUG_VFS, " dentry: %s (%p)\n", dentry->d_iname, dentry); | 
|  | 1088 |  | 
|  | 1089 | retval = v9fs_readlink(dentry, link, buflen); | 
|  | 1090 |  | 
|  | 1091 | if (retval > 0) { | 
|  | 1092 | if ((ret = copy_to_user(buffer, link, retval)) != 0) { | 
|  | 1093 | dprintk(DEBUG_ERROR, "problem copying to user: %d\n", | 
|  | 1094 | ret); | 
|  | 1095 | retval = ret; | 
|  | 1096 | } | 
|  | 1097 | } | 
|  | 1098 |  | 
| Davi Arnaut | ce44eeb | 2005-11-07 00:59:36 -0800 | [diff] [blame] | 1099 | __putname(link); | 
| Eric Van Hensbergen | 2bad847 | 2005-09-09 13:04:19 -0700 | [diff] [blame] | 1100 | return retval; | 
|  | 1101 | } | 
|  | 1102 |  | 
|  | 1103 | /** | 
|  | 1104 | * v9fs_vfs_follow_link - follow a symlink path | 
|  | 1105 | * @dentry: dentry for symlink | 
|  | 1106 | * @nd: nameidata | 
|  | 1107 | * | 
|  | 1108 | */ | 
|  | 1109 |  | 
|  | 1110 | static void *v9fs_vfs_follow_link(struct dentry *dentry, struct nameidata *nd) | 
|  | 1111 | { | 
|  | 1112 | int len = 0; | 
|  | 1113 | char *link = __getname(); | 
|  | 1114 |  | 
|  | 1115 | dprintk(DEBUG_VFS, "%s n", dentry->d_name.name); | 
|  | 1116 |  | 
|  | 1117 | if (!link) | 
|  | 1118 | link = ERR_PTR(-ENOMEM); | 
|  | 1119 | else { | 
| Latchesar Ionkov | 16cce6d | 2006-03-25 03:07:26 -0800 | [diff] [blame] | 1120 | len = v9fs_readlink(dentry, link, PATH_MAX); | 
| Eric Van Hensbergen | 2bad847 | 2005-09-09 13:04:19 -0700 | [diff] [blame] | 1121 |  | 
|  | 1122 | if (len < 0) { | 
| Davi Arnaut | ce44eeb | 2005-11-07 00:59:36 -0800 | [diff] [blame] | 1123 | __putname(link); | 
| Eric Van Hensbergen | 2bad847 | 2005-09-09 13:04:19 -0700 | [diff] [blame] | 1124 | link = ERR_PTR(len); | 
|  | 1125 | } else | 
|  | 1126 | link[len] = 0; | 
|  | 1127 | } | 
|  | 1128 | nd_set_link(nd, link); | 
|  | 1129 |  | 
|  | 1130 | return NULL; | 
|  | 1131 | } | 
|  | 1132 |  | 
|  | 1133 | /** | 
|  | 1134 | * v9fs_vfs_put_link - release a symlink path | 
|  | 1135 | * @dentry: dentry for symlink | 
|  | 1136 | * @nd: nameidata | 
|  | 1137 | * | 
|  | 1138 | */ | 
|  | 1139 |  | 
|  | 1140 | static void v9fs_vfs_put_link(struct dentry *dentry, struct nameidata *nd, void *p) | 
|  | 1141 | { | 
|  | 1142 | char *s = nd_get_link(nd); | 
|  | 1143 |  | 
|  | 1144 | dprintk(DEBUG_VFS, " %s %s\n", dentry->d_name.name, s); | 
|  | 1145 | if (!IS_ERR(s)) | 
| Davi Arnaut | ce44eeb | 2005-11-07 00:59:36 -0800 | [diff] [blame] | 1146 | __putname(s); | 
| Eric Van Hensbergen | 2bad847 | 2005-09-09 13:04:19 -0700 | [diff] [blame] | 1147 | } | 
|  | 1148 |  | 
| Latchesar Ionkov | 531b109 | 2006-01-08 01:05:00 -0800 | [diff] [blame] | 1149 | static int v9fs_vfs_mkspecial(struct inode *dir, struct dentry *dentry, | 
|  | 1150 | int mode, const char *extension) | 
|  | 1151 | { | 
| Latchesar Ionkov | 6a3124a | 2006-03-02 02:54:30 -0800 | [diff] [blame] | 1152 | int err; | 
|  | 1153 | u32 fid, perm; | 
| Latchesar Ionkov | 531b109 | 2006-01-08 01:05:00 -0800 | [diff] [blame] | 1154 | struct v9fs_session_info *v9ses; | 
| Eric Van Hensbergen | da977b2 | 2007-01-26 00:57:06 -0800 | [diff] [blame] | 1155 | struct v9fs_fid *dfid, *vfid = NULL; | 
|  | 1156 | struct inode *inode = NULL; | 
| Latchesar Ionkov | 531b109 | 2006-01-08 01:05:00 -0800 | [diff] [blame] | 1157 |  | 
| Latchesar Ionkov | 6a3124a | 2006-03-02 02:54:30 -0800 | [diff] [blame] | 1158 | v9ses = v9fs_inode2v9ses(dir); | 
| Latchesar Ionkov | 531b109 | 2006-01-08 01:05:00 -0800 | [diff] [blame] | 1159 | if (!v9ses->extended) { | 
|  | 1160 | dprintk(DEBUG_ERROR, "not extended\n"); | 
| Latchesar Ionkov | 6a3124a | 2006-03-02 02:54:30 -0800 | [diff] [blame] | 1161 | return -EPERM; | 
| Latchesar Ionkov | 531b109 | 2006-01-08 01:05:00 -0800 | [diff] [blame] | 1162 | } | 
|  | 1163 |  | 
| Eric Van Hensbergen | da977b2 | 2007-01-26 00:57:06 -0800 | [diff] [blame] | 1164 | dfid = v9fs_fid_clone(dentry->d_parent); | 
|  | 1165 | if(IS_ERR(dfid)) { | 
|  | 1166 | err = PTR_ERR(dfid); | 
|  | 1167 | goto error; | 
|  | 1168 | } | 
|  | 1169 |  | 
|  | 1170 | perm = unixmode2p9mode(v9ses, mode); | 
|  | 1171 |  | 
| Latchesar Ionkov | 6a3124a | 2006-03-02 02:54:30 -0800 | [diff] [blame] | 1172 | err = v9fs_create(v9ses, dfid->fid, (char *) dentry->d_name.name, | 
| Latchesar Ionkov | 16cce6d | 2006-03-25 03:07:26 -0800 | [diff] [blame] | 1173 | perm, V9FS_OREAD, (char *) extension, &fid, NULL, NULL); | 
| Latchesar Ionkov | 531b109 | 2006-01-08 01:05:00 -0800 | [diff] [blame] | 1174 |  | 
| Latchesar Ionkov | 6a3124a | 2006-03-02 02:54:30 -0800 | [diff] [blame] | 1175 | if (err) | 
| Eric Van Hensbergen | da977b2 | 2007-01-26 00:57:06 -0800 | [diff] [blame] | 1176 | goto clunk_dfid; | 
| Latchesar Ionkov | 6a3124a | 2006-03-02 02:54:30 -0800 | [diff] [blame] | 1177 |  | 
|  | 1178 | err = v9fs_t_clunk(v9ses, fid); | 
|  | 1179 | if (err) | 
| Eric Van Hensbergen | da977b2 | 2007-01-26 00:57:06 -0800 | [diff] [blame] | 1180 | goto clunk_dfid; | 
| Latchesar Ionkov | 6a3124a | 2006-03-02 02:54:30 -0800 | [diff] [blame] | 1181 |  | 
|  | 1182 | vfid = v9fs_clone_walk(v9ses, dfid->fid, dentry); | 
|  | 1183 | if (IS_ERR(vfid)) { | 
|  | 1184 | err = PTR_ERR(vfid); | 
|  | 1185 | vfid = NULL; | 
| Eric Van Hensbergen | da977b2 | 2007-01-26 00:57:06 -0800 | [diff] [blame] | 1186 | goto clunk_dfid; | 
| Latchesar Ionkov | 6a3124a | 2006-03-02 02:54:30 -0800 | [diff] [blame] | 1187 | } | 
|  | 1188 |  | 
|  | 1189 | inode = v9fs_inode_from_fid(v9ses, vfid->fid, dir->i_sb); | 
|  | 1190 | if (IS_ERR(inode)) { | 
|  | 1191 | err = PTR_ERR(inode); | 
|  | 1192 | inode = NULL; | 
| Eric Van Hensbergen | da977b2 | 2007-01-26 00:57:06 -0800 | [diff] [blame] | 1193 | goto free_vfid; | 
| Latchesar Ionkov | 531b109 | 2006-01-08 01:05:00 -0800 | [diff] [blame] | 1194 | } | 
|  | 1195 |  | 
| Eric Van Hensbergen | e03abc0 | 2007-02-11 13:21:39 -0600 | [diff] [blame] | 1196 | if(v9ses->cache) | 
|  | 1197 | dentry->d_op = &v9fs_cached_dentry_operations; | 
|  | 1198 | else | 
|  | 1199 | dentry->d_op = &v9fs_dentry_operations; | 
| Latchesar Ionkov | 6a3124a | 2006-03-02 02:54:30 -0800 | [diff] [blame] | 1200 | d_instantiate(dentry, inode); | 
|  | 1201 | return 0; | 
|  | 1202 |  | 
| Eric Van Hensbergen | da977b2 | 2007-01-26 00:57:06 -0800 | [diff] [blame] | 1203 | free_vfid: | 
|  | 1204 | v9fs_fid_destroy(vfid); | 
| Latchesar Ionkov | 6a3124a | 2006-03-02 02:54:30 -0800 | [diff] [blame] | 1205 |  | 
| Eric Van Hensbergen | da977b2 | 2007-01-26 00:57:06 -0800 | [diff] [blame] | 1206 | clunk_dfid: | 
|  | 1207 | v9fs_fid_clunk(v9ses, dfid); | 
|  | 1208 |  | 
|  | 1209 | error: | 
| Latchesar Ionkov | 6a3124a | 2006-03-02 02:54:30 -0800 | [diff] [blame] | 1210 | return err; | 
|  | 1211 |  | 
| Latchesar Ionkov | 531b109 | 2006-01-08 01:05:00 -0800 | [diff] [blame] | 1212 | } | 
|  | 1213 |  | 
|  | 1214 | /** | 
|  | 1215 | * v9fs_vfs_symlink - helper function to create symlinks | 
|  | 1216 | * @dir: directory inode containing symlink | 
|  | 1217 | * @dentry: dentry for symlink | 
|  | 1218 | * @symname: symlink data | 
|  | 1219 | * | 
|  | 1220 | * See 9P2000.u RFC for more information | 
|  | 1221 | * | 
|  | 1222 | */ | 
|  | 1223 |  | 
|  | 1224 | static int | 
|  | 1225 | v9fs_vfs_symlink(struct inode *dir, struct dentry *dentry, const char *symname) | 
|  | 1226 | { | 
|  | 1227 | dprintk(DEBUG_VFS, " %lu,%s,%s\n", dir->i_ino, dentry->d_name.name, | 
|  | 1228 | symname); | 
|  | 1229 |  | 
|  | 1230 | return v9fs_vfs_mkspecial(dir, dentry, S_IFLNK, symname); | 
|  | 1231 | } | 
|  | 1232 |  | 
| Eric Van Hensbergen | 2bad847 | 2005-09-09 13:04:19 -0700 | [diff] [blame] | 1233 | /** | 
|  | 1234 | * v9fs_vfs_link - create a hardlink | 
|  | 1235 | * @old_dentry: dentry for file to link to | 
|  | 1236 | * @dir: inode destination for new link | 
| Eric Van Hensbergen | 73c592b | 2005-09-09 13:04:26 -0700 | [diff] [blame] | 1237 | * @dentry: dentry for link | 
| Eric Van Hensbergen | 2bad847 | 2005-09-09 13:04:19 -0700 | [diff] [blame] | 1238 | * | 
|  | 1239 | */ | 
|  | 1240 |  | 
|  | 1241 | /* XXX - lots of code dup'd from symlink and creates, | 
|  | 1242 | * figure out a better reuse strategy | 
|  | 1243 | */ | 
|  | 1244 |  | 
|  | 1245 | static int | 
|  | 1246 | v9fs_vfs_link(struct dentry *old_dentry, struct inode *dir, | 
|  | 1247 | struct dentry *dentry) | 
|  | 1248 | { | 
| Latchesar Ionkov | 531b109 | 2006-01-08 01:05:00 -0800 | [diff] [blame] | 1249 | int retval; | 
| Eric Van Hensbergen | da977b2 | 2007-01-26 00:57:06 -0800 | [diff] [blame] | 1250 | struct v9fs_session_info *v9ses = v9fs_inode2v9ses(dir); | 
| Latchesar Ionkov | 531b109 | 2006-01-08 01:05:00 -0800 | [diff] [blame] | 1251 | struct v9fs_fid *oldfid; | 
|  | 1252 | char *name; | 
| Eric Van Hensbergen | 2bad847 | 2005-09-09 13:04:19 -0700 | [diff] [blame] | 1253 |  | 
|  | 1254 | dprintk(DEBUG_VFS, " %lu,%s,%s\n", dir->i_ino, dentry->d_name.name, | 
|  | 1255 | old_dentry->d_name.name); | 
|  | 1256 |  | 
| Eric Van Hensbergen | da977b2 | 2007-01-26 00:57:06 -0800 | [diff] [blame] | 1257 | oldfid = v9fs_fid_clone(old_dentry); | 
|  | 1258 | if(IS_ERR(oldfid)) | 
|  | 1259 | return PTR_ERR(oldfid); | 
| Eric Van Hensbergen | 2bad847 | 2005-09-09 13:04:19 -0700 | [diff] [blame] | 1260 |  | 
| Latchesar Ionkov | 531b109 | 2006-01-08 01:05:00 -0800 | [diff] [blame] | 1261 | name = __getname(); | 
| Eric Van Hensbergen | da977b2 | 2007-01-26 00:57:06 -0800 | [diff] [blame] | 1262 | if (unlikely(!name)) { | 
|  | 1263 | retval = -ENOMEM; | 
|  | 1264 | goto clunk_fid; | 
|  | 1265 | } | 
| Florin Malita | 0710d36 | 2006-06-25 05:48:31 -0700 | [diff] [blame] | 1266 |  | 
| Latchesar Ionkov | 16cce6d | 2006-03-25 03:07:26 -0800 | [diff] [blame] | 1267 | sprintf(name, "%d\n", oldfid->fid); | 
| Latchesar Ionkov | 531b109 | 2006-01-08 01:05:00 -0800 | [diff] [blame] | 1268 | retval = v9fs_vfs_mkspecial(dir, dentry, V9FS_DMLINK, name); | 
|  | 1269 | __putname(name); | 
| Eric Van Hensbergen | 2bad847 | 2005-09-09 13:04:19 -0700 | [diff] [blame] | 1270 |  | 
| Eric Van Hensbergen | da977b2 | 2007-01-26 00:57:06 -0800 | [diff] [blame] | 1271 | clunk_fid: | 
|  | 1272 | v9fs_fid_clunk(v9ses, oldfid); | 
| Eric Van Hensbergen | 2bad847 | 2005-09-09 13:04:19 -0700 | [diff] [blame] | 1273 | return retval; | 
|  | 1274 | } | 
|  | 1275 |  | 
|  | 1276 | /** | 
|  | 1277 | * v9fs_vfs_mknod - create a special file | 
|  | 1278 | * @dir: inode destination for new link | 
|  | 1279 | * @dentry: dentry for file | 
|  | 1280 | * @mode: mode for creation | 
|  | 1281 | * @dev_t: device associated with special file | 
|  | 1282 | * | 
|  | 1283 | */ | 
|  | 1284 |  | 
|  | 1285 | static int | 
|  | 1286 | v9fs_vfs_mknod(struct inode *dir, struct dentry *dentry, int mode, dev_t rdev) | 
|  | 1287 | { | 
| Latchesar Ionkov | 531b109 | 2006-01-08 01:05:00 -0800 | [diff] [blame] | 1288 | int retval; | 
|  | 1289 | char *name; | 
| Eric Van Hensbergen | 2bad847 | 2005-09-09 13:04:19 -0700 | [diff] [blame] | 1290 |  | 
|  | 1291 | dprintk(DEBUG_VFS, " %lu,%s mode: %x MAJOR: %u MINOR: %u\n", dir->i_ino, | 
|  | 1292 | dentry->d_name.name, mode, MAJOR(rdev), MINOR(rdev)); | 
|  | 1293 |  | 
| Latchesar Ionkov | 531b109 | 2006-01-08 01:05:00 -0800 | [diff] [blame] | 1294 | if (!new_valid_dev(rdev)) | 
|  | 1295 | return -EINVAL; | 
| Eric Van Hensbergen | 73c592b | 2005-09-09 13:04:26 -0700 | [diff] [blame] | 1296 |  | 
| Latchesar Ionkov | 531b109 | 2006-01-08 01:05:00 -0800 | [diff] [blame] | 1297 | name = __getname(); | 
| Eugene Teo | c0291a0 | 2006-03-25 03:07:27 -0800 | [diff] [blame] | 1298 | if (!name) | 
|  | 1299 | return -ENOMEM; | 
| Eric Van Hensbergen | 2bad847 | 2005-09-09 13:04:19 -0700 | [diff] [blame] | 1300 | /* build extension */ | 
|  | 1301 | if (S_ISBLK(mode)) | 
| Latchesar Ionkov | 531b109 | 2006-01-08 01:05:00 -0800 | [diff] [blame] | 1302 | sprintf(name, "b %u %u", MAJOR(rdev), MINOR(rdev)); | 
| Eric Van Hensbergen | 2bad847 | 2005-09-09 13:04:19 -0700 | [diff] [blame] | 1303 | else if (S_ISCHR(mode)) | 
| Latchesar Ionkov | 531b109 | 2006-01-08 01:05:00 -0800 | [diff] [blame] | 1304 | sprintf(name, "c %u %u", MAJOR(rdev), MINOR(rdev)); | 
| Eric Van Hensbergen | 73c592b | 2005-09-09 13:04:26 -0700 | [diff] [blame] | 1305 | else if (S_ISFIFO(mode)) | 
| Latchesar Ionkov | 531b109 | 2006-01-08 01:05:00 -0800 | [diff] [blame] | 1306 | *name = 0; | 
| Eric Van Hensbergen | 2bad847 | 2005-09-09 13:04:19 -0700 | [diff] [blame] | 1307 | else { | 
| Latchesar Ionkov | 531b109 | 2006-01-08 01:05:00 -0800 | [diff] [blame] | 1308 | __putname(name); | 
|  | 1309 | return -EINVAL; | 
| Eric Van Hensbergen | 2bad847 | 2005-09-09 13:04:19 -0700 | [diff] [blame] | 1310 | } | 
|  | 1311 |  | 
| Latchesar Ionkov | 531b109 | 2006-01-08 01:05:00 -0800 | [diff] [blame] | 1312 | retval = v9fs_vfs_mkspecial(dir, dentry, mode, name); | 
|  | 1313 | __putname(name); | 
| Eric Van Hensbergen | 2bad847 | 2005-09-09 13:04:19 -0700 | [diff] [blame] | 1314 |  | 
|  | 1315 | return retval; | 
|  | 1316 | } | 
|  | 1317 |  | 
| Arjan van de Ven | 754661f | 2007-02-12 00:55:38 -0800 | [diff] [blame] | 1318 | static const struct inode_operations v9fs_dir_inode_operations_ext = { | 
| Eric Van Hensbergen | 2bad847 | 2005-09-09 13:04:19 -0700 | [diff] [blame] | 1319 | .create = v9fs_vfs_create, | 
|  | 1320 | .lookup = v9fs_vfs_lookup, | 
|  | 1321 | .symlink = v9fs_vfs_symlink, | 
|  | 1322 | .link = v9fs_vfs_link, | 
|  | 1323 | .unlink = v9fs_vfs_unlink, | 
|  | 1324 | .mkdir = v9fs_vfs_mkdir, | 
|  | 1325 | .rmdir = v9fs_vfs_rmdir, | 
|  | 1326 | .mknod = v9fs_vfs_mknod, | 
|  | 1327 | .rename = v9fs_vfs_rename, | 
|  | 1328 | .readlink = v9fs_vfs_readlink, | 
|  | 1329 | .getattr = v9fs_vfs_getattr, | 
|  | 1330 | .setattr = v9fs_vfs_setattr, | 
|  | 1331 | }; | 
|  | 1332 |  | 
| Arjan van de Ven | 754661f | 2007-02-12 00:55:38 -0800 | [diff] [blame] | 1333 | static const struct inode_operations v9fs_dir_inode_operations = { | 
| Eric Van Hensbergen | b501611 | 2005-09-09 13:04:27 -0700 | [diff] [blame] | 1334 | .create = v9fs_vfs_create, | 
|  | 1335 | .lookup = v9fs_vfs_lookup, | 
|  | 1336 | .unlink = v9fs_vfs_unlink, | 
|  | 1337 | .mkdir = v9fs_vfs_mkdir, | 
|  | 1338 | .rmdir = v9fs_vfs_rmdir, | 
|  | 1339 | .mknod = v9fs_vfs_mknod, | 
|  | 1340 | .rename = v9fs_vfs_rename, | 
|  | 1341 | .getattr = v9fs_vfs_getattr, | 
|  | 1342 | .setattr = v9fs_vfs_setattr, | 
|  | 1343 | }; | 
|  | 1344 |  | 
| Arjan van de Ven | 754661f | 2007-02-12 00:55:38 -0800 | [diff] [blame] | 1345 | static const struct inode_operations v9fs_file_inode_operations = { | 
| Eric Van Hensbergen | 2bad847 | 2005-09-09 13:04:19 -0700 | [diff] [blame] | 1346 | .getattr = v9fs_vfs_getattr, | 
|  | 1347 | .setattr = v9fs_vfs_setattr, | 
|  | 1348 | }; | 
|  | 1349 |  | 
| Arjan van de Ven | 754661f | 2007-02-12 00:55:38 -0800 | [diff] [blame] | 1350 | static const struct inode_operations v9fs_symlink_inode_operations = { | 
| Eric Van Hensbergen | 2bad847 | 2005-09-09 13:04:19 -0700 | [diff] [blame] | 1351 | .readlink = v9fs_vfs_readlink, | 
|  | 1352 | .follow_link = v9fs_vfs_follow_link, | 
|  | 1353 | .put_link = v9fs_vfs_put_link, | 
|  | 1354 | .getattr = v9fs_vfs_getattr, | 
|  | 1355 | .setattr = v9fs_vfs_setattr, | 
|  | 1356 | }; |