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