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