Back to home page

OSCL-LXR

 
 

    


0001 // SPDX-License-Identifier: GPL-2.0
0002 /*
0003  * (C) 2001 Clemson University and The University of Chicago
0004  *
0005  * See COPYING in top-level directory.
0006  */
0007 
0008 /*
0009  *  Linux VFS namei operations.
0010  */
0011 
0012 #include "protocol.h"
0013 #include "orangefs-kernel.h"
0014 
0015 /*
0016  * Get a newly allocated inode to go with a negative dentry.
0017  */
0018 static int orangefs_create(struct user_namespace *mnt_userns,
0019             struct inode *dir,
0020             struct dentry *dentry,
0021             umode_t mode,
0022             bool exclusive)
0023 {
0024     struct orangefs_inode_s *parent = ORANGEFS_I(dir);
0025     struct orangefs_kernel_op_s *new_op;
0026     struct orangefs_object_kref ref;
0027     struct inode *inode;
0028     struct iattr iattr;
0029     int ret;
0030 
0031     gossip_debug(GOSSIP_NAME_DEBUG, "%s: %pd\n",
0032              __func__,
0033              dentry);
0034 
0035     new_op = op_alloc(ORANGEFS_VFS_OP_CREATE);
0036     if (!new_op)
0037         return -ENOMEM;
0038 
0039     new_op->upcall.req.create.parent_refn = parent->refn;
0040 
0041     fill_default_sys_attrs(new_op->upcall.req.create.attributes,
0042                    ORANGEFS_TYPE_METAFILE, mode);
0043 
0044     strncpy(new_op->upcall.req.create.d_name,
0045         dentry->d_name.name, ORANGEFS_NAME_MAX - 1);
0046 
0047     ret = service_operation(new_op, __func__, get_interruptible_flag(dir));
0048 
0049     gossip_debug(GOSSIP_NAME_DEBUG,
0050              "%s: %pd: handle:%pU: fsid:%d: new_op:%p: ret:%d:\n",
0051              __func__,
0052              dentry,
0053              &new_op->downcall.resp.create.refn.khandle,
0054              new_op->downcall.resp.create.refn.fs_id,
0055              new_op,
0056              ret);
0057 
0058     if (ret < 0)
0059         goto out;
0060 
0061     ref = new_op->downcall.resp.create.refn;
0062 
0063     inode = orangefs_new_inode(dir->i_sb, dir, S_IFREG | mode, 0, &ref);
0064     if (IS_ERR(inode)) {
0065         gossip_err("%s: Failed to allocate inode for file :%pd:\n",
0066                __func__,
0067                dentry);
0068         ret = PTR_ERR(inode);
0069         goto out;
0070     }
0071 
0072     gossip_debug(GOSSIP_NAME_DEBUG,
0073              "%s: Assigned inode :%pU: for file :%pd:\n",
0074              __func__,
0075              get_khandle_from_ino(inode),
0076              dentry);
0077 
0078     d_instantiate_new(dentry, inode);
0079     orangefs_set_timeout(dentry);
0080 
0081     gossip_debug(GOSSIP_NAME_DEBUG,
0082              "%s: dentry instantiated for %pd\n",
0083              __func__,
0084              dentry);
0085 
0086     memset(&iattr, 0, sizeof iattr);
0087     iattr.ia_valid |= ATTR_MTIME | ATTR_CTIME;
0088     iattr.ia_mtime = iattr.ia_ctime = current_time(dir);
0089     __orangefs_setattr(dir, &iattr);
0090     ret = 0;
0091 out:
0092     op_release(new_op);
0093     gossip_debug(GOSSIP_NAME_DEBUG,
0094              "%s: %pd: returning %d\n",
0095              __func__,
0096              dentry,
0097              ret);
0098     return ret;
0099 }
0100 
0101 /*
0102  * Attempt to resolve an object name (dentry->d_name), parent handle, and
0103  * fsid into a handle for the object.
0104  */
0105 static struct dentry *orangefs_lookup(struct inode *dir, struct dentry *dentry,
0106                    unsigned int flags)
0107 {
0108     struct orangefs_inode_s *parent = ORANGEFS_I(dir);
0109     struct orangefs_kernel_op_s *new_op;
0110     struct inode *inode;
0111     int ret = -EINVAL;
0112 
0113     /*
0114      * in theory we could skip a lookup here (if the intent is to
0115      * create) in order to avoid a potentially failed lookup, but
0116      * leaving it in can skip a valid lookup and try to create a file
0117      * that already exists (e.g. the vfs already handles checking for
0118      * -EEXIST on O_EXCL opens, which is broken if we skip this lookup
0119      * in the create path)
0120      */
0121     gossip_debug(GOSSIP_NAME_DEBUG, "%s called on %pd\n",
0122              __func__, dentry);
0123 
0124     if (dentry->d_name.len > (ORANGEFS_NAME_MAX - 1))
0125         return ERR_PTR(-ENAMETOOLONG);
0126 
0127     new_op = op_alloc(ORANGEFS_VFS_OP_LOOKUP);
0128     if (!new_op)
0129         return ERR_PTR(-ENOMEM);
0130 
0131     new_op->upcall.req.lookup.sym_follow = ORANGEFS_LOOKUP_LINK_NO_FOLLOW;
0132 
0133     gossip_debug(GOSSIP_NAME_DEBUG, "%s:%s:%d using parent %pU\n",
0134              __FILE__,
0135              __func__,
0136              __LINE__,
0137              &parent->refn.khandle);
0138     new_op->upcall.req.lookup.parent_refn = parent->refn;
0139 
0140     strncpy(new_op->upcall.req.lookup.d_name, dentry->d_name.name,
0141         ORANGEFS_NAME_MAX - 1);
0142 
0143     gossip_debug(GOSSIP_NAME_DEBUG,
0144              "%s: doing lookup on %s under %pU,%d\n",
0145              __func__,
0146              new_op->upcall.req.lookup.d_name,
0147              &new_op->upcall.req.lookup.parent_refn.khandle,
0148              new_op->upcall.req.lookup.parent_refn.fs_id);
0149 
0150     ret = service_operation(new_op, __func__, get_interruptible_flag(dir));
0151 
0152     gossip_debug(GOSSIP_NAME_DEBUG,
0153              "Lookup Got %pU, fsid %d (ret=%d)\n",
0154              &new_op->downcall.resp.lookup.refn.khandle,
0155              new_op->downcall.resp.lookup.refn.fs_id,
0156              ret);
0157 
0158     if (ret == 0) {
0159         orangefs_set_timeout(dentry);
0160         inode = orangefs_iget(dir->i_sb, &new_op->downcall.resp.lookup.refn);
0161     } else if (ret == -ENOENT) {
0162         inode = NULL;
0163     } else {
0164         /* must be a non-recoverable error */
0165         inode = ERR_PTR(ret);
0166     }
0167 
0168     op_release(new_op);
0169     return d_splice_alias(inode, dentry);
0170 }
0171 
0172 /* return 0 on success; non-zero otherwise */
0173 static int orangefs_unlink(struct inode *dir, struct dentry *dentry)
0174 {
0175     struct inode *inode = dentry->d_inode;
0176     struct orangefs_inode_s *parent = ORANGEFS_I(dir);
0177     struct orangefs_kernel_op_s *new_op;
0178     struct iattr iattr;
0179     int ret;
0180 
0181     gossip_debug(GOSSIP_NAME_DEBUG,
0182              "%s: called on %pd\n"
0183              "  (inode %pU): Parent is %pU | fs_id %d\n",
0184              __func__,
0185              dentry,
0186              get_khandle_from_ino(inode),
0187              &parent->refn.khandle,
0188              parent->refn.fs_id);
0189 
0190     new_op = op_alloc(ORANGEFS_VFS_OP_REMOVE);
0191     if (!new_op)
0192         return -ENOMEM;
0193 
0194     new_op->upcall.req.remove.parent_refn = parent->refn;
0195     strncpy(new_op->upcall.req.remove.d_name, dentry->d_name.name,
0196         ORANGEFS_NAME_MAX - 1);
0197 
0198     ret = service_operation(new_op, "orangefs_unlink",
0199                 get_interruptible_flag(inode));
0200 
0201     gossip_debug(GOSSIP_NAME_DEBUG,
0202              "%s: service_operation returned:%d:\n",
0203              __func__,
0204              ret);
0205 
0206     op_release(new_op);
0207 
0208     if (!ret) {
0209         drop_nlink(inode);
0210 
0211         memset(&iattr, 0, sizeof iattr);
0212         iattr.ia_valid |= ATTR_MTIME | ATTR_CTIME;
0213         iattr.ia_mtime = iattr.ia_ctime = current_time(dir);
0214         __orangefs_setattr(dir, &iattr);
0215     }
0216     return ret;
0217 }
0218 
0219 static int orangefs_symlink(struct user_namespace *mnt_userns,
0220                  struct inode *dir,
0221              struct dentry *dentry,
0222              const char *symname)
0223 {
0224     struct orangefs_inode_s *parent = ORANGEFS_I(dir);
0225     struct orangefs_kernel_op_s *new_op;
0226     struct orangefs_object_kref ref;
0227     struct inode *inode;
0228     struct iattr iattr;
0229     int mode = 0755;
0230     int ret;
0231 
0232     gossip_debug(GOSSIP_NAME_DEBUG, "%s: called\n", __func__);
0233 
0234     if (!symname)
0235         return -EINVAL;
0236 
0237     if (strlen(symname)+1 > ORANGEFS_NAME_MAX)
0238         return -ENAMETOOLONG;
0239 
0240     new_op = op_alloc(ORANGEFS_VFS_OP_SYMLINK);
0241     if (!new_op)
0242         return -ENOMEM;
0243 
0244     new_op->upcall.req.sym.parent_refn = parent->refn;
0245 
0246     fill_default_sys_attrs(new_op->upcall.req.sym.attributes,
0247                    ORANGEFS_TYPE_SYMLINK,
0248                    mode);
0249 
0250     strncpy(new_op->upcall.req.sym.entry_name,
0251         dentry->d_name.name,
0252         ORANGEFS_NAME_MAX - 1);
0253     strncpy(new_op->upcall.req.sym.target, symname, ORANGEFS_NAME_MAX - 1);
0254 
0255     ret = service_operation(new_op, __func__, get_interruptible_flag(dir));
0256 
0257     gossip_debug(GOSSIP_NAME_DEBUG,
0258              "Symlink Got ORANGEFS handle %pU on fsid %d (ret=%d)\n",
0259              &new_op->downcall.resp.sym.refn.khandle,
0260              new_op->downcall.resp.sym.refn.fs_id, ret);
0261 
0262     if (ret < 0) {
0263         gossip_debug(GOSSIP_NAME_DEBUG,
0264                 "%s: failed with error code %d\n",
0265                 __func__, ret);
0266         goto out;
0267     }
0268 
0269     ref = new_op->downcall.resp.sym.refn;
0270 
0271     inode = orangefs_new_inode(dir->i_sb, dir, S_IFLNK | mode, 0, &ref);
0272     if (IS_ERR(inode)) {
0273         gossip_err
0274             ("*** Failed to allocate orangefs symlink inode\n");
0275         ret = PTR_ERR(inode);
0276         goto out;
0277     }
0278     /*
0279      * This is necessary because orangefs_inode_getattr will not
0280      * re-read symlink size as it is impossible for it to change.
0281      * Invalidating the cache does not help.  orangefs_new_inode
0282      * does not set the correct size (it does not know symname).
0283      */
0284     inode->i_size = strlen(symname);
0285 
0286     gossip_debug(GOSSIP_NAME_DEBUG,
0287              "Assigned symlink inode new number of %pU\n",
0288              get_khandle_from_ino(inode));
0289 
0290     d_instantiate_new(dentry, inode);
0291     orangefs_set_timeout(dentry);
0292 
0293     gossip_debug(GOSSIP_NAME_DEBUG,
0294              "Inode (Symlink) %pU -> %pd\n",
0295              get_khandle_from_ino(inode),
0296              dentry);
0297 
0298     memset(&iattr, 0, sizeof iattr);
0299     iattr.ia_valid |= ATTR_MTIME | ATTR_CTIME;
0300     iattr.ia_mtime = iattr.ia_ctime = current_time(dir);
0301     __orangefs_setattr(dir, &iattr);
0302     ret = 0;
0303 out:
0304     op_release(new_op);
0305     return ret;
0306 }
0307 
0308 static int orangefs_mkdir(struct user_namespace *mnt_userns, struct inode *dir,
0309               struct dentry *dentry, umode_t mode)
0310 {
0311     struct orangefs_inode_s *parent = ORANGEFS_I(dir);
0312     struct orangefs_kernel_op_s *new_op;
0313     struct orangefs_object_kref ref;
0314     struct inode *inode;
0315     struct iattr iattr;
0316     int ret;
0317 
0318     new_op = op_alloc(ORANGEFS_VFS_OP_MKDIR);
0319     if (!new_op)
0320         return -ENOMEM;
0321 
0322     new_op->upcall.req.mkdir.parent_refn = parent->refn;
0323 
0324     fill_default_sys_attrs(new_op->upcall.req.mkdir.attributes,
0325                   ORANGEFS_TYPE_DIRECTORY, mode);
0326 
0327     strncpy(new_op->upcall.req.mkdir.d_name,
0328         dentry->d_name.name, ORANGEFS_NAME_MAX - 1);
0329 
0330     ret = service_operation(new_op, __func__, get_interruptible_flag(dir));
0331 
0332     gossip_debug(GOSSIP_NAME_DEBUG,
0333              "Mkdir Got ORANGEFS handle %pU on fsid %d\n",
0334              &new_op->downcall.resp.mkdir.refn.khandle,
0335              new_op->downcall.resp.mkdir.refn.fs_id);
0336 
0337     if (ret < 0) {
0338         gossip_debug(GOSSIP_NAME_DEBUG,
0339                  "%s: failed with error code %d\n",
0340                  __func__, ret);
0341         goto out;
0342     }
0343 
0344     ref = new_op->downcall.resp.mkdir.refn;
0345 
0346     inode = orangefs_new_inode(dir->i_sb, dir, S_IFDIR | mode, 0, &ref);
0347     if (IS_ERR(inode)) {
0348         gossip_err("*** Failed to allocate orangefs dir inode\n");
0349         ret = PTR_ERR(inode);
0350         goto out;
0351     }
0352 
0353     gossip_debug(GOSSIP_NAME_DEBUG,
0354              "Assigned dir inode new number of %pU\n",
0355              get_khandle_from_ino(inode));
0356 
0357     d_instantiate_new(dentry, inode);
0358     orangefs_set_timeout(dentry);
0359 
0360     gossip_debug(GOSSIP_NAME_DEBUG,
0361              "Inode (Directory) %pU -> %pd\n",
0362              get_khandle_from_ino(inode),
0363              dentry);
0364 
0365     /*
0366      * NOTE: we have no good way to keep nlink consistent for directories
0367      * across clients; keep constant at 1.
0368      */
0369     memset(&iattr, 0, sizeof iattr);
0370     iattr.ia_valid |= ATTR_MTIME | ATTR_CTIME;
0371     iattr.ia_mtime = iattr.ia_ctime = current_time(dir);
0372     __orangefs_setattr(dir, &iattr);
0373 out:
0374     op_release(new_op);
0375     return ret;
0376 }
0377 
0378 static int orangefs_rename(struct user_namespace *mnt_userns,
0379             struct inode *old_dir,
0380             struct dentry *old_dentry,
0381             struct inode *new_dir,
0382             struct dentry *new_dentry,
0383             unsigned int flags)
0384 {
0385     struct orangefs_kernel_op_s *new_op;
0386     struct iattr iattr;
0387     int ret;
0388 
0389     if (flags)
0390         return -EINVAL;
0391 
0392     gossip_debug(GOSSIP_NAME_DEBUG,
0393              "orangefs_rename: called (%pd2 => %pd2) ct=%d\n",
0394              old_dentry, new_dentry, d_count(new_dentry));
0395 
0396     memset(&iattr, 0, sizeof iattr);
0397     iattr.ia_valid |= ATTR_MTIME | ATTR_CTIME;
0398     iattr.ia_mtime = iattr.ia_ctime = current_time(new_dir);
0399     __orangefs_setattr(new_dir, &iattr);
0400 
0401     new_op = op_alloc(ORANGEFS_VFS_OP_RENAME);
0402     if (!new_op)
0403         return -EINVAL;
0404 
0405     new_op->upcall.req.rename.old_parent_refn = ORANGEFS_I(old_dir)->refn;
0406     new_op->upcall.req.rename.new_parent_refn = ORANGEFS_I(new_dir)->refn;
0407 
0408     strncpy(new_op->upcall.req.rename.d_old_name,
0409         old_dentry->d_name.name,
0410         ORANGEFS_NAME_MAX - 1);
0411     strncpy(new_op->upcall.req.rename.d_new_name,
0412         new_dentry->d_name.name,
0413         ORANGEFS_NAME_MAX - 1);
0414 
0415     ret = service_operation(new_op,
0416                 "orangefs_rename",
0417                 get_interruptible_flag(old_dentry->d_inode));
0418 
0419     gossip_debug(GOSSIP_NAME_DEBUG,
0420              "orangefs_rename: got downcall status %d\n",
0421              ret);
0422 
0423     if (new_dentry->d_inode)
0424         new_dentry->d_inode->i_ctime = current_time(new_dentry->d_inode);
0425 
0426     op_release(new_op);
0427     return ret;
0428 }
0429 
0430 /* ORANGEFS implementation of VFS inode operations for directories */
0431 const struct inode_operations orangefs_dir_inode_operations = {
0432     .lookup = orangefs_lookup,
0433     .get_acl = orangefs_get_acl,
0434     .set_acl = orangefs_set_acl,
0435     .create = orangefs_create,
0436     .unlink = orangefs_unlink,
0437     .symlink = orangefs_symlink,
0438     .mkdir = orangefs_mkdir,
0439     .rmdir = orangefs_unlink,
0440     .rename = orangefs_rename,
0441     .setattr = orangefs_setattr,
0442     .getattr = orangefs_getattr,
0443     .listxattr = orangefs_listxattr,
0444     .permission = orangefs_permission,
0445     .update_time = orangefs_update_time,
0446 };