1 /* 2 * (C) 2001 Clemson University and The University of Chicago 3 * 4 * See COPYING in top-level directory. 5 */ 6 7 /* 8 * Linux VFS namei operations. 9 */ 10 11 #include "protocol.h" 12 #include "orangefs-kernel.h" 13 14 /* 15 * Get a newly allocated inode to go with a negative dentry. 16 */ 17 static int orangefs_create(struct inode *dir, 18 struct dentry *dentry, 19 umode_t mode, 20 bool exclusive) 21 { 22 struct orangefs_inode_s *parent = ORANGEFS_I(dir); 23 struct orangefs_kernel_op_s *new_op; 24 struct inode *inode; 25 int ret; 26 27 gossip_debug(GOSSIP_NAME_DEBUG, "%s: %pd\n", 28 __func__, 29 dentry); 30 31 new_op = op_alloc(ORANGEFS_VFS_OP_CREATE); 32 if (!new_op) 33 return -ENOMEM; 34 35 new_op->upcall.req.create.parent_refn = parent->refn; 36 37 fill_default_sys_attrs(new_op->upcall.req.create.attributes, 38 ORANGEFS_TYPE_METAFILE, mode); 39 40 strncpy(new_op->upcall.req.create.d_name, 41 dentry->d_name.name, ORANGEFS_NAME_MAX); 42 43 ret = service_operation(new_op, __func__, get_interruptible_flag(dir)); 44 45 gossip_debug(GOSSIP_NAME_DEBUG, 46 "%s: %pd: handle:%pU: fsid:%d: new_op:%p: ret:%d:\n", 47 __func__, 48 dentry, 49 &new_op->downcall.resp.create.refn.khandle, 50 new_op->downcall.resp.create.refn.fs_id, 51 new_op, 52 ret); 53 54 if (ret < 0) 55 goto out; 56 57 inode = orangefs_new_inode(dir->i_sb, dir, S_IFREG | mode, 0, 58 &new_op->downcall.resp.create.refn); 59 if (IS_ERR(inode)) { 60 gossip_err("%s: Failed to allocate inode for file :%pd:\n", 61 __func__, 62 dentry); 63 ret = PTR_ERR(inode); 64 goto out; 65 } 66 67 gossip_debug(GOSSIP_NAME_DEBUG, 68 "%s: Assigned inode :%pU: for file :%pd:\n", 69 __func__, 70 get_khandle_from_ino(inode), 71 dentry); 72 73 d_instantiate(dentry, inode); 74 unlock_new_inode(inode); 75 orangefs_set_timeout(dentry); 76 ORANGEFS_I(inode)->getattr_time = jiffies - 1; 77 78 gossip_debug(GOSSIP_NAME_DEBUG, 79 "%s: dentry instantiated for %pd\n", 80 __func__, 81 dentry); 82 83 SetMtimeFlag(parent); 84 dir->i_mtime = dir->i_ctime = current_time(dir); 85 mark_inode_dirty_sync(dir); 86 ret = 0; 87 out: 88 op_release(new_op); 89 gossip_debug(GOSSIP_NAME_DEBUG, 90 "%s: %pd: returning %d\n", 91 __func__, 92 dentry, 93 ret); 94 return ret; 95 } 96 97 /* 98 * Attempt to resolve an object name (dentry->d_name), parent handle, and 99 * fsid into a handle for the object. 100 */ 101 static struct dentry *orangefs_lookup(struct inode *dir, struct dentry *dentry, 102 unsigned int flags) 103 { 104 struct orangefs_inode_s *parent = ORANGEFS_I(dir); 105 struct orangefs_kernel_op_s *new_op; 106 struct inode *inode; 107 struct dentry *res; 108 int ret = -EINVAL; 109 110 /* 111 * in theory we could skip a lookup here (if the intent is to 112 * create) in order to avoid a potentially failed lookup, but 113 * leaving it in can skip a valid lookup and try to create a file 114 * that already exists (e.g. the vfs already handles checking for 115 * -EEXIST on O_EXCL opens, which is broken if we skip this lookup 116 * in the create path) 117 */ 118 gossip_debug(GOSSIP_NAME_DEBUG, "%s called on %pd\n", 119 __func__, dentry); 120 121 if (dentry->d_name.len > (ORANGEFS_NAME_MAX - 1)) 122 return ERR_PTR(-ENAMETOOLONG); 123 124 new_op = op_alloc(ORANGEFS_VFS_OP_LOOKUP); 125 if (!new_op) 126 return ERR_PTR(-ENOMEM); 127 128 new_op->upcall.req.lookup.sym_follow = ORANGEFS_LOOKUP_LINK_NO_FOLLOW; 129 130 gossip_debug(GOSSIP_NAME_DEBUG, "%s:%s:%d using parent %pU\n", 131 __FILE__, 132 __func__, 133 __LINE__, 134 &parent->refn.khandle); 135 new_op->upcall.req.lookup.parent_refn = parent->refn; 136 137 strncpy(new_op->upcall.req.lookup.d_name, dentry->d_name.name, 138 ORANGEFS_NAME_MAX); 139 140 gossip_debug(GOSSIP_NAME_DEBUG, 141 "%s: doing lookup on %s under %pU,%d\n", 142 __func__, 143 new_op->upcall.req.lookup.d_name, 144 &new_op->upcall.req.lookup.parent_refn.khandle, 145 new_op->upcall.req.lookup.parent_refn.fs_id); 146 147 ret = service_operation(new_op, __func__, get_interruptible_flag(dir)); 148 149 gossip_debug(GOSSIP_NAME_DEBUG, 150 "Lookup Got %pU, fsid %d (ret=%d)\n", 151 &new_op->downcall.resp.lookup.refn.khandle, 152 new_op->downcall.resp.lookup.refn.fs_id, 153 ret); 154 155 if (ret < 0) { 156 if (ret == -ENOENT) { 157 /* 158 * if no inode was found, add a negative dentry to 159 * dcache anyway; if we don't, we don't hold expected 160 * lookup semantics and we most noticeably break 161 * during directory renames. 162 * 163 * however, if the operation failed or exited, do not 164 * add the dentry (e.g. in the case that a touch is 165 * issued on a file that already exists that was 166 * interrupted during this lookup -- no need to add 167 * another negative dentry for an existing file) 168 */ 169 170 gossip_debug(GOSSIP_NAME_DEBUG, 171 "orangefs_lookup: Adding *negative* dentry " 172 "%p for %pd\n", 173 dentry, 174 dentry); 175 176 d_add(dentry, NULL); 177 res = NULL; 178 goto out; 179 } 180 181 /* must be a non-recoverable error */ 182 res = ERR_PTR(ret); 183 goto out; 184 } 185 186 orangefs_set_timeout(dentry); 187 188 inode = orangefs_iget(dir->i_sb, &new_op->downcall.resp.lookup.refn); 189 if (IS_ERR(inode)) { 190 gossip_debug(GOSSIP_NAME_DEBUG, 191 "error %ld from iget\n", PTR_ERR(inode)); 192 res = ERR_CAST(inode); 193 goto out; 194 } 195 196 ORANGEFS_I(inode)->getattr_time = jiffies - 1; 197 198 gossip_debug(GOSSIP_NAME_DEBUG, 199 "%s:%s:%d " 200 "Found good inode [%lu] with count [%d]\n", 201 __FILE__, 202 __func__, 203 __LINE__, 204 inode->i_ino, 205 (int)atomic_read(&inode->i_count)); 206 207 /* update dentry/inode pair into dcache */ 208 res = d_splice_alias(inode, dentry); 209 210 gossip_debug(GOSSIP_NAME_DEBUG, 211 "Lookup success (inode ct = %d)\n", 212 (int)atomic_read(&inode->i_count)); 213 out: 214 op_release(new_op); 215 return res; 216 } 217 218 /* return 0 on success; non-zero otherwise */ 219 static int orangefs_unlink(struct inode *dir, struct dentry *dentry) 220 { 221 struct inode *inode = dentry->d_inode; 222 struct orangefs_inode_s *parent = ORANGEFS_I(dir); 223 struct orangefs_kernel_op_s *new_op; 224 int ret; 225 226 gossip_debug(GOSSIP_NAME_DEBUG, 227 "%s: called on %pd\n" 228 " (inode %pU): Parent is %pU | fs_id %d\n", 229 __func__, 230 dentry, 231 get_khandle_from_ino(inode), 232 &parent->refn.khandle, 233 parent->refn.fs_id); 234 235 new_op = op_alloc(ORANGEFS_VFS_OP_REMOVE); 236 if (!new_op) 237 return -ENOMEM; 238 239 new_op->upcall.req.remove.parent_refn = parent->refn; 240 strncpy(new_op->upcall.req.remove.d_name, dentry->d_name.name, 241 ORANGEFS_NAME_MAX); 242 243 ret = service_operation(new_op, "orangefs_unlink", 244 get_interruptible_flag(inode)); 245 246 gossip_debug(GOSSIP_NAME_DEBUG, 247 "%s: service_operation returned:%d:\n", 248 __func__, 249 ret); 250 251 op_release(new_op); 252 253 if (!ret) { 254 drop_nlink(inode); 255 256 SetMtimeFlag(parent); 257 dir->i_mtime = dir->i_ctime = current_time(dir); 258 mark_inode_dirty_sync(dir); 259 } 260 return ret; 261 } 262 263 static int orangefs_symlink(struct inode *dir, 264 struct dentry *dentry, 265 const char *symname) 266 { 267 struct orangefs_inode_s *parent = ORANGEFS_I(dir); 268 struct orangefs_kernel_op_s *new_op; 269 struct inode *inode; 270 int mode = 755; 271 int ret; 272 273 gossip_debug(GOSSIP_NAME_DEBUG, "%s: called\n", __func__); 274 275 if (!symname) 276 return -EINVAL; 277 278 if (strlen(symname)+1 > ORANGEFS_NAME_MAX) 279 return -ENAMETOOLONG; 280 281 new_op = op_alloc(ORANGEFS_VFS_OP_SYMLINK); 282 if (!new_op) 283 return -ENOMEM; 284 285 new_op->upcall.req.sym.parent_refn = parent->refn; 286 287 fill_default_sys_attrs(new_op->upcall.req.sym.attributes, 288 ORANGEFS_TYPE_SYMLINK, 289 mode); 290 291 strncpy(new_op->upcall.req.sym.entry_name, 292 dentry->d_name.name, 293 ORANGEFS_NAME_MAX); 294 strncpy(new_op->upcall.req.sym.target, symname, ORANGEFS_NAME_MAX); 295 296 ret = service_operation(new_op, __func__, get_interruptible_flag(dir)); 297 298 gossip_debug(GOSSIP_NAME_DEBUG, 299 "Symlink Got ORANGEFS handle %pU on fsid %d (ret=%d)\n", 300 &new_op->downcall.resp.sym.refn.khandle, 301 new_op->downcall.resp.sym.refn.fs_id, ret); 302 303 if (ret < 0) { 304 gossip_debug(GOSSIP_NAME_DEBUG, 305 "%s: failed with error code %d\n", 306 __func__, ret); 307 goto out; 308 } 309 310 inode = orangefs_new_inode(dir->i_sb, dir, S_IFLNK | mode, 0, 311 &new_op->downcall.resp.sym.refn); 312 if (IS_ERR(inode)) { 313 gossip_err 314 ("*** Failed to allocate orangefs symlink inode\n"); 315 ret = PTR_ERR(inode); 316 goto out; 317 } 318 319 gossip_debug(GOSSIP_NAME_DEBUG, 320 "Assigned symlink inode new number of %pU\n", 321 get_khandle_from_ino(inode)); 322 323 d_instantiate(dentry, inode); 324 unlock_new_inode(inode); 325 orangefs_set_timeout(dentry); 326 ORANGEFS_I(inode)->getattr_time = jiffies - 1; 327 328 gossip_debug(GOSSIP_NAME_DEBUG, 329 "Inode (Symlink) %pU -> %pd\n", 330 get_khandle_from_ino(inode), 331 dentry); 332 333 SetMtimeFlag(parent); 334 dir->i_mtime = dir->i_ctime = current_time(dir); 335 mark_inode_dirty_sync(dir); 336 ret = 0; 337 out: 338 op_release(new_op); 339 return ret; 340 } 341 342 static int orangefs_mkdir(struct inode *dir, struct dentry *dentry, umode_t mode) 343 { 344 struct orangefs_inode_s *parent = ORANGEFS_I(dir); 345 struct orangefs_kernel_op_s *new_op; 346 struct inode *inode; 347 int ret; 348 349 new_op = op_alloc(ORANGEFS_VFS_OP_MKDIR); 350 if (!new_op) 351 return -ENOMEM; 352 353 new_op->upcall.req.mkdir.parent_refn = parent->refn; 354 355 fill_default_sys_attrs(new_op->upcall.req.mkdir.attributes, 356 ORANGEFS_TYPE_DIRECTORY, mode); 357 358 strncpy(new_op->upcall.req.mkdir.d_name, 359 dentry->d_name.name, ORANGEFS_NAME_MAX); 360 361 ret = service_operation(new_op, __func__, get_interruptible_flag(dir)); 362 363 gossip_debug(GOSSIP_NAME_DEBUG, 364 "Mkdir Got ORANGEFS handle %pU on fsid %d\n", 365 &new_op->downcall.resp.mkdir.refn.khandle, 366 new_op->downcall.resp.mkdir.refn.fs_id); 367 368 if (ret < 0) { 369 gossip_debug(GOSSIP_NAME_DEBUG, 370 "%s: failed with error code %d\n", 371 __func__, ret); 372 goto out; 373 } 374 375 inode = orangefs_new_inode(dir->i_sb, dir, S_IFDIR | mode, 0, 376 &new_op->downcall.resp.mkdir.refn); 377 if (IS_ERR(inode)) { 378 gossip_err("*** Failed to allocate orangefs dir inode\n"); 379 ret = PTR_ERR(inode); 380 goto out; 381 } 382 383 gossip_debug(GOSSIP_NAME_DEBUG, 384 "Assigned dir inode new number of %pU\n", 385 get_khandle_from_ino(inode)); 386 387 d_instantiate(dentry, inode); 388 unlock_new_inode(inode); 389 orangefs_set_timeout(dentry); 390 ORANGEFS_I(inode)->getattr_time = jiffies - 1; 391 392 gossip_debug(GOSSIP_NAME_DEBUG, 393 "Inode (Directory) %pU -> %pd\n", 394 get_khandle_from_ino(inode), 395 dentry); 396 397 /* 398 * NOTE: we have no good way to keep nlink consistent for directories 399 * across clients; keep constant at 1. 400 */ 401 SetMtimeFlag(parent); 402 dir->i_mtime = dir->i_ctime = current_time(dir); 403 mark_inode_dirty_sync(dir); 404 out: 405 op_release(new_op); 406 return ret; 407 } 408 409 static int orangefs_rename(struct inode *old_dir, 410 struct dentry *old_dentry, 411 struct inode *new_dir, 412 struct dentry *new_dentry, 413 unsigned int flags) 414 { 415 struct orangefs_kernel_op_s *new_op; 416 int ret; 417 418 if (flags) 419 return -EINVAL; 420 421 gossip_debug(GOSSIP_NAME_DEBUG, 422 "orangefs_rename: called (%pd2 => %pd2) ct=%d\n", 423 old_dentry, new_dentry, d_count(new_dentry)); 424 425 ORANGEFS_I(new_dentry->d_parent->d_inode)->getattr_time = jiffies - 1; 426 427 new_op = op_alloc(ORANGEFS_VFS_OP_RENAME); 428 if (!new_op) 429 return -EINVAL; 430 431 new_op->upcall.req.rename.old_parent_refn = ORANGEFS_I(old_dir)->refn; 432 new_op->upcall.req.rename.new_parent_refn = ORANGEFS_I(new_dir)->refn; 433 434 strncpy(new_op->upcall.req.rename.d_old_name, 435 old_dentry->d_name.name, 436 ORANGEFS_NAME_MAX); 437 strncpy(new_op->upcall.req.rename.d_new_name, 438 new_dentry->d_name.name, 439 ORANGEFS_NAME_MAX); 440 441 ret = service_operation(new_op, 442 "orangefs_rename", 443 get_interruptible_flag(old_dentry->d_inode)); 444 445 gossip_debug(GOSSIP_NAME_DEBUG, 446 "orangefs_rename: got downcall status %d\n", 447 ret); 448 449 if (new_dentry->d_inode) 450 new_dentry->d_inode->i_ctime = current_time(new_dentry->d_inode); 451 452 op_release(new_op); 453 return ret; 454 } 455 456 /* ORANGEFS implementation of VFS inode operations for directories */ 457 const struct inode_operations orangefs_dir_inode_operations = { 458 .lookup = orangefs_lookup, 459 .get_acl = orangefs_get_acl, 460 .set_acl = orangefs_set_acl, 461 .create = orangefs_create, 462 .unlink = orangefs_unlink, 463 .symlink = orangefs_symlink, 464 .mkdir = orangefs_mkdir, 465 .rmdir = orangefs_unlink, 466 .rename = orangefs_rename, 467 .setattr = orangefs_setattr, 468 .getattr = orangefs_getattr, 469 .listxattr = orangefs_listxattr, 470 .permission = orangefs_permission, 471 }; 472