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