linux/fs/orangefs/inode.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 inode operations.
  10 */
  11
  12#include <linux/bvec.h>
  13#include "protocol.h"
  14#include "orangefs-kernel.h"
  15#include "orangefs-bufmap.h"
  16
  17static int read_one_page(struct page *page)
  18{
  19        int ret;
  20        int max_block;
  21        ssize_t bytes_read = 0;
  22        struct inode *inode = page->mapping->host;
  23        const __u32 blocksize = PAGE_SIZE;
  24        const __u32 blockbits = PAGE_SHIFT;
  25        struct iov_iter to;
  26        struct bio_vec bv = {.bv_page = page, .bv_len = PAGE_SIZE};
  27
  28        iov_iter_bvec(&to, ITER_BVEC | READ, &bv, 1, PAGE_SIZE);
  29
  30        gossip_debug(GOSSIP_INODE_DEBUG,
  31                    "orangefs_readpage called with page %p\n",
  32                     page);
  33
  34        max_block = ((inode->i_size / blocksize) + 1);
  35
  36        if (page->index < max_block) {
  37                loff_t blockptr_offset = (((loff_t) page->index) << blockbits);
  38
  39                bytes_read = orangefs_inode_read(inode,
  40                                                 &to,
  41                                                 &blockptr_offset,
  42                                                 inode->i_size);
  43        }
  44        /* this will only zero remaining unread portions of the page data */
  45        iov_iter_zero(~0U, &to);
  46        /* takes care of potential aliasing */
  47        flush_dcache_page(page);
  48        if (bytes_read < 0) {
  49                ret = bytes_read;
  50                SetPageError(page);
  51        } else {
  52                SetPageUptodate(page);
  53                if (PageError(page))
  54                        ClearPageError(page);
  55                ret = 0;
  56        }
  57        /* unlock the page after the ->readpage() routine completes */
  58        unlock_page(page);
  59        return ret;
  60}
  61
  62static int orangefs_readpage(struct file *file, struct page *page)
  63{
  64        return read_one_page(page);
  65}
  66
  67static int orangefs_readpages(struct file *file,
  68                           struct address_space *mapping,
  69                           struct list_head *pages,
  70                           unsigned nr_pages)
  71{
  72        int page_idx;
  73        int ret;
  74
  75        gossip_debug(GOSSIP_INODE_DEBUG, "orangefs_readpages called\n");
  76
  77        for (page_idx = 0; page_idx < nr_pages; page_idx++) {
  78                struct page *page;
  79
  80                page = list_entry(pages->prev, struct page, lru);
  81                list_del(&page->lru);
  82                if (!add_to_page_cache(page,
  83                                       mapping,
  84                                       page->index,
  85                                       readahead_gfp_mask(mapping))) {
  86                        ret = read_one_page(page);
  87                        gossip_debug(GOSSIP_INODE_DEBUG,
  88                                "failure adding page to cache, read_one_page returned: %d\n",
  89                                ret);
  90              } else {
  91                        put_page(page);
  92              }
  93        }
  94        BUG_ON(!list_empty(pages));
  95        return 0;
  96}
  97
  98static void orangefs_invalidatepage(struct page *page,
  99                                 unsigned int offset,
 100                                 unsigned int length)
 101{
 102        gossip_debug(GOSSIP_INODE_DEBUG,
 103                     "orangefs_invalidatepage called on page %p "
 104                     "(offset is %u)\n",
 105                     page,
 106                     offset);
 107
 108        ClearPageUptodate(page);
 109        ClearPageMappedToDisk(page);
 110        return;
 111
 112}
 113
 114static int orangefs_releasepage(struct page *page, gfp_t foo)
 115{
 116        gossip_debug(GOSSIP_INODE_DEBUG,
 117                     "orangefs_releasepage called on page %p\n",
 118                     page);
 119        return 0;
 120}
 121
 122/*
 123 * Having a direct_IO entry point in the address_space_operations
 124 * struct causes the kernel to allows us to use O_DIRECT on
 125 * open. Nothing will ever call this thing, but in the future we
 126 * will need to be able to use O_DIRECT on open in order to support
 127 * AIO. Modeled after NFS, they do this too.
 128 */
 129
 130static ssize_t orangefs_direct_IO(struct kiocb *iocb,
 131                                  struct iov_iter *iter)
 132{
 133        gossip_debug(GOSSIP_INODE_DEBUG,
 134                     "orangefs_direct_IO: %pD\n",
 135                     iocb->ki_filp);
 136
 137        return -EINVAL;
 138}
 139
 140/** ORANGEFS2 implementation of address space operations */
 141static const struct address_space_operations orangefs_address_operations = {
 142        .readpage = orangefs_readpage,
 143        .readpages = orangefs_readpages,
 144        .invalidatepage = orangefs_invalidatepage,
 145        .releasepage = orangefs_releasepage,
 146        .direct_IO = orangefs_direct_IO,
 147};
 148
 149static int orangefs_setattr_size(struct inode *inode, struct iattr *iattr)
 150{
 151        struct orangefs_inode_s *orangefs_inode = ORANGEFS_I(inode);
 152        struct orangefs_kernel_op_s *new_op;
 153        loff_t orig_size;
 154        int ret = -EINVAL;
 155
 156        gossip_debug(GOSSIP_INODE_DEBUG,
 157                     "%s: %pU: Handle is %pU | fs_id %d | size is %llu\n",
 158                     __func__,
 159                     get_khandle_from_ino(inode),
 160                     &orangefs_inode->refn.khandle,
 161                     orangefs_inode->refn.fs_id,
 162                     iattr->ia_size);
 163
 164        /* Ensure that we have a up to date size, so we know if it changed. */
 165        ret = orangefs_inode_getattr(inode, 0, 1, STATX_SIZE);
 166        if (ret == -ESTALE)
 167                ret = -EIO;
 168        if (ret) {
 169                gossip_err("%s: orangefs_inode_getattr failed, ret:%d:.\n",
 170                    __func__, ret);
 171                return ret;
 172        }
 173        orig_size = i_size_read(inode);
 174
 175        truncate_setsize(inode, iattr->ia_size);
 176
 177        new_op = op_alloc(ORANGEFS_VFS_OP_TRUNCATE);
 178        if (!new_op)
 179                return -ENOMEM;
 180
 181        new_op->upcall.req.truncate.refn = orangefs_inode->refn;
 182        new_op->upcall.req.truncate.size = (__s64) iattr->ia_size;
 183
 184        ret = service_operation(new_op,
 185                __func__,
 186                get_interruptible_flag(inode));
 187
 188        /*
 189         * the truncate has no downcall members to retrieve, but
 190         * the status value tells us if it went through ok or not
 191         */
 192        gossip_debug(GOSSIP_INODE_DEBUG, "%s: ret:%d:\n", __func__, ret);
 193
 194        op_release(new_op);
 195
 196        if (ret != 0)
 197                return ret;
 198
 199        if (orig_size != i_size_read(inode))
 200                iattr->ia_valid |= ATTR_CTIME | ATTR_MTIME;
 201
 202        return ret;
 203}
 204
 205/*
 206 * Change attributes of an object referenced by dentry.
 207 */
 208int orangefs_setattr(struct dentry *dentry, struct iattr *iattr)
 209{
 210        int ret = -EINVAL;
 211        struct inode *inode = dentry->d_inode;
 212
 213        gossip_debug(GOSSIP_INODE_DEBUG,
 214                "%s: called on %pd\n",
 215                __func__,
 216                dentry);
 217
 218        ret = setattr_prepare(dentry, iattr);
 219        if (ret)
 220                goto out;
 221
 222        if (iattr->ia_valid & ATTR_SIZE) {
 223                ret = orangefs_setattr_size(inode, iattr);
 224                if (ret)
 225                        goto out;
 226        }
 227
 228        setattr_copy(inode, iattr);
 229        mark_inode_dirty(inode);
 230
 231        ret = orangefs_inode_setattr(inode, iattr);
 232        gossip_debug(GOSSIP_INODE_DEBUG,
 233                "%s: orangefs_inode_setattr returned %d\n",
 234                __func__,
 235                ret);
 236
 237        if (!ret && (iattr->ia_valid & ATTR_MODE))
 238                /* change mod on a file that has ACLs */
 239                ret = posix_acl_chmod(inode, inode->i_mode);
 240
 241out:
 242        gossip_debug(GOSSIP_INODE_DEBUG, "%s: ret:%d:\n", __func__, ret);
 243        return ret;
 244}
 245
 246/*
 247 * Obtain attributes of an object given a dentry
 248 */
 249int orangefs_getattr(const struct path *path, struct kstat *stat,
 250                     u32 request_mask, unsigned int flags)
 251{
 252        int ret = -ENOENT;
 253        struct inode *inode = path->dentry->d_inode;
 254        struct orangefs_inode_s *orangefs_inode = NULL;
 255
 256        gossip_debug(GOSSIP_INODE_DEBUG,
 257                     "orangefs_getattr: called on %pd\n",
 258                     path->dentry);
 259
 260        ret = orangefs_inode_getattr(inode, 0, 0, request_mask);
 261        if (ret == 0) {
 262                generic_fillattr(inode, stat);
 263
 264                /* override block size reported to stat */
 265                orangefs_inode = ORANGEFS_I(inode);
 266
 267                if (request_mask & STATX_SIZE)
 268                        stat->result_mask = STATX_BASIC_STATS;
 269                else
 270                        stat->result_mask = STATX_BASIC_STATS &
 271                            ~STATX_SIZE;
 272
 273                stat->attributes_mask = STATX_ATTR_IMMUTABLE |
 274                    STATX_ATTR_APPEND;
 275                if (inode->i_flags & S_IMMUTABLE)
 276                        stat->attributes |= STATX_ATTR_IMMUTABLE;
 277                if (inode->i_flags & S_APPEND)
 278                        stat->attributes |= STATX_ATTR_APPEND;
 279        }
 280        return ret;
 281}
 282
 283int orangefs_permission(struct inode *inode, int mask)
 284{
 285        int ret;
 286
 287        if (mask & MAY_NOT_BLOCK)
 288                return -ECHILD;
 289
 290        gossip_debug(GOSSIP_INODE_DEBUG, "%s: refreshing\n", __func__);
 291
 292        /* Make sure the permission (and other common attrs) are up to date. */
 293        ret = orangefs_inode_getattr(inode, 0, 0, STATX_MODE);
 294        if (ret < 0)
 295                return ret;
 296
 297        return generic_permission(inode, mask);
 298}
 299
 300int orangefs_update_time(struct inode *inode, struct timespec64 *time, int flags)
 301{
 302        struct iattr iattr;
 303        gossip_debug(GOSSIP_INODE_DEBUG, "orangefs_update_time: %pU\n",
 304            get_khandle_from_ino(inode));
 305        generic_update_time(inode, time, flags);
 306        memset(&iattr, 0, sizeof iattr);
 307        if (flags & S_ATIME)
 308                iattr.ia_valid |= ATTR_ATIME;
 309        if (flags & S_CTIME)
 310                iattr.ia_valid |= ATTR_CTIME;
 311        if (flags & S_MTIME)
 312                iattr.ia_valid |= ATTR_MTIME;
 313        return orangefs_inode_setattr(inode, &iattr);
 314}
 315
 316/* ORANGEFS2 implementation of VFS inode operations for files */
 317static const struct inode_operations orangefs_file_inode_operations = {
 318        .get_acl = orangefs_get_acl,
 319        .set_acl = orangefs_set_acl,
 320        .setattr = orangefs_setattr,
 321        .getattr = orangefs_getattr,
 322        .listxattr = orangefs_listxattr,
 323        .permission = orangefs_permission,
 324        .update_time = orangefs_update_time,
 325};
 326
 327static int orangefs_init_iops(struct inode *inode)
 328{
 329        inode->i_mapping->a_ops = &orangefs_address_operations;
 330
 331        switch (inode->i_mode & S_IFMT) {
 332        case S_IFREG:
 333                inode->i_op = &orangefs_file_inode_operations;
 334                inode->i_fop = &orangefs_file_operations;
 335                break;
 336        case S_IFLNK:
 337                inode->i_op = &orangefs_symlink_inode_operations;
 338                break;
 339        case S_IFDIR:
 340                inode->i_op = &orangefs_dir_inode_operations;
 341                inode->i_fop = &orangefs_dir_operations;
 342                break;
 343        default:
 344                gossip_debug(GOSSIP_INODE_DEBUG,
 345                             "%s: unsupported mode\n",
 346                             __func__);
 347                return -EINVAL;
 348        }
 349
 350        return 0;
 351}
 352
 353/*
 354 * Given an ORANGEFS object identifier (fsid, handle), convert it into
 355 * a ino_t type that will be used as a hash-index from where the handle will
 356 * be searched for in the VFS hash table of inodes.
 357 */
 358static inline ino_t orangefs_handle_hash(struct orangefs_object_kref *ref)
 359{
 360        if (!ref)
 361                return 0;
 362        return orangefs_khandle_to_ino(&(ref->khandle));
 363}
 364
 365/*
 366 * Called to set up an inode from iget5_locked.
 367 */
 368static int orangefs_set_inode(struct inode *inode, void *data)
 369{
 370        struct orangefs_object_kref *ref = (struct orangefs_object_kref *) data;
 371        ORANGEFS_I(inode)->refn.fs_id = ref->fs_id;
 372        ORANGEFS_I(inode)->refn.khandle = ref->khandle;
 373        return 0;
 374}
 375
 376/*
 377 * Called to determine if handles match.
 378 */
 379static int orangefs_test_inode(struct inode *inode, void *data)
 380{
 381        struct orangefs_object_kref *ref = (struct orangefs_object_kref *) data;
 382        struct orangefs_inode_s *orangefs_inode = NULL;
 383
 384        orangefs_inode = ORANGEFS_I(inode);
 385        /* test handles and fs_ids... */
 386        return (!ORANGEFS_khandle_cmp(&(orangefs_inode->refn.khandle),
 387                                &(ref->khandle)) &&
 388                        orangefs_inode->refn.fs_id == ref->fs_id);
 389}
 390
 391/*
 392 * Front-end to lookup the inode-cache maintained by the VFS using the ORANGEFS
 393 * file handle.
 394 *
 395 * @sb: the file system super block instance.
 396 * @ref: The ORANGEFS object for which we are trying to locate an inode.
 397 */
 398struct inode *orangefs_iget(struct super_block *sb,
 399                struct orangefs_object_kref *ref)
 400{
 401        struct inode *inode = NULL;
 402        unsigned long hash;
 403        int error;
 404
 405        hash = orangefs_handle_hash(ref);
 406        inode = iget5_locked(sb,
 407                        hash,
 408                        orangefs_test_inode,
 409                        orangefs_set_inode,
 410                        ref);
 411        if (!inode || !(inode->i_state & I_NEW))
 412                return inode;
 413
 414        error = orangefs_inode_getattr(inode, 1, 1, STATX_ALL);
 415        if (error) {
 416                iget_failed(inode);
 417                return ERR_PTR(error);
 418        }
 419
 420        inode->i_ino = hash;    /* needed for stat etc */
 421        orangefs_init_iops(inode);
 422        unlock_new_inode(inode);
 423
 424        gossip_debug(GOSSIP_INODE_DEBUG,
 425                     "iget handle %pU, fsid %d hash %ld i_ino %lu\n",
 426                     &ref->khandle,
 427                     ref->fs_id,
 428                     hash,
 429                     inode->i_ino);
 430
 431        return inode;
 432}
 433
 434/*
 435 * Allocate an inode for a newly created file and insert it into the inode hash.
 436 */
 437struct inode *orangefs_new_inode(struct super_block *sb, struct inode *dir,
 438                int mode, dev_t dev, struct orangefs_object_kref *ref)
 439{
 440        unsigned long hash = orangefs_handle_hash(ref);
 441        struct inode *inode;
 442        int error;
 443
 444        gossip_debug(GOSSIP_INODE_DEBUG,
 445                     "%s:(sb is %p | MAJOR(dev)=%u | MINOR(dev)=%u mode=%o)\n",
 446                     __func__,
 447                     sb,
 448                     MAJOR(dev),
 449                     MINOR(dev),
 450                     mode);
 451
 452        inode = new_inode(sb);
 453        if (!inode)
 454                return NULL;
 455
 456        orangefs_set_inode(inode, ref);
 457        inode->i_ino = hash;    /* needed for stat etc */
 458
 459        error = orangefs_inode_getattr(inode, 1, 1, STATX_ALL);
 460        if (error)
 461                goto out_iput;
 462
 463        orangefs_init_iops(inode);
 464
 465        inode->i_mode = mode;
 466        inode->i_uid = current_fsuid();
 467        inode->i_gid = current_fsgid();
 468        inode->i_atime = inode->i_mtime = inode->i_ctime = current_time(inode);
 469        inode->i_size = PAGE_SIZE;
 470        inode->i_rdev = dev;
 471
 472        error = insert_inode_locked4(inode, hash, orangefs_test_inode, ref);
 473        if (error < 0)
 474                goto out_iput;
 475
 476        gossip_debug(GOSSIP_INODE_DEBUG,
 477                     "Initializing ACL's for inode %pU\n",
 478                     get_khandle_from_ino(inode));
 479        orangefs_init_acl(inode, dir);
 480        return inode;
 481
 482out_iput:
 483        iput(inode);
 484        return ERR_PTR(error);
 485}
 486