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