linux/fs/orangefs/namei.c
<<
>>
Prefs
   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 */
  18static int orangefs_create(struct user_namespace *mnt_userns,
  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;
  91out:
  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 */
 105static 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 */
 173static 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
 219static int orangefs_symlink(struct user_namespace *mnt_userns,
 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;
 303out:
 304        op_release(new_op);
 305        return ret;
 306}
 307
 308static int orangefs_mkdir(struct user_namespace *mnt_userns, 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);
 373out:
 374        op_release(new_op);
 375        return ret;
 376}
 377
 378static int orangefs_rename(struct user_namespace *mnt_userns,
 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                new_dentry->d_inode->i_ctime = current_time(new_dentry->d_inode);
 425
 426        op_release(new_op);
 427        return ret;
 428}
 429
 430/* ORANGEFS implementation of VFS inode operations for directories */
 431const struct inode_operations orangefs_dir_inode_operations = {
 432        .lookup = orangefs_lookup,
 433        .get_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