linux/fs/nfs/nfs4file.c
<<
>>
Prefs
   1/*
   2 *  linux/fs/nfs/file.c
   3 *
   4 *  Copyright (C) 1992  Rick Sladkey
   5 */
   6#include <linux/fs.h>
   7#include <linux/falloc.h>
   8#include <linux/nfs_fs.h>
   9#include "internal.h"
  10#include "fscache.h"
  11#include "pnfs.h"
  12
  13#ifdef CONFIG_NFS_V4_2
  14#include "nfs42.h"
  15#endif
  16
  17#define NFSDBG_FACILITY         NFSDBG_FILE
  18
  19static int
  20nfs4_file_open(struct inode *inode, struct file *filp)
  21{
  22        struct nfs_open_context *ctx;
  23        struct dentry *dentry = filp->f_path.dentry;
  24        struct dentry *parent = NULL;
  25        struct inode *dir;
  26        unsigned openflags = filp->f_flags;
  27        struct iattr attr;
  28        int opened = 0;
  29        int err;
  30
  31        /*
  32         * If no cached dentry exists or if it's negative, NFSv4 handled the
  33         * opens in ->lookup() or ->create().
  34         *
  35         * We only get this far for a cached positive dentry.  We skipped
  36         * revalidation, so handle it here by dropping the dentry and returning
  37         * -EOPENSTALE.  The VFS will retry the lookup/create/open.
  38         */
  39
  40        dprintk("NFS: open file(%pd2)\n", dentry);
  41
  42        if ((openflags & O_ACCMODE) == 3)
  43                openflags--;
  44
  45        /* We can't create new files here */
  46        openflags &= ~(O_CREAT|O_EXCL);
  47
  48        parent = dget_parent(dentry);
  49        dir = parent->d_inode;
  50
  51        ctx = alloc_nfs_open_context(filp->f_path.dentry, filp->f_mode);
  52        err = PTR_ERR(ctx);
  53        if (IS_ERR(ctx))
  54                goto out;
  55
  56        attr.ia_valid = ATTR_OPEN;
  57        if (openflags & O_TRUNC) {
  58                attr.ia_valid |= ATTR_SIZE;
  59                attr.ia_size = 0;
  60                nfs_wb_all(inode);
  61        }
  62
  63        inode = NFS_PROTO(dir)->open_context(dir, ctx, openflags, &attr, &opened);
  64        if (IS_ERR(inode)) {
  65                err = PTR_ERR(inode);
  66                switch (err) {
  67                case -EPERM:
  68                case -EACCES:
  69                case -EDQUOT:
  70                case -ENOSPC:
  71                case -EROFS:
  72                        goto out_put_ctx;
  73                default:
  74                        goto out_drop;
  75                }
  76        }
  77        if (inode != dentry->d_inode)
  78                goto out_drop;
  79
  80        nfs_set_verifier(dentry, nfs_save_change_attribute(dir));
  81        nfs_file_set_open_context(filp, ctx);
  82        nfs_fscache_open_file(inode, filp);
  83        err = 0;
  84
  85out_put_ctx:
  86        put_nfs_open_context(ctx);
  87out:
  88        dput(parent);
  89        return err;
  90
  91out_drop:
  92        d_drop(dentry);
  93        err = -EOPENSTALE;
  94        goto out_put_ctx;
  95}
  96
  97static int
  98nfs4_file_fsync(struct file *file, loff_t start, loff_t end, int datasync)
  99{
 100        int ret;
 101        struct inode *inode = file_inode(file);
 102
 103        do {
 104                ret = filemap_write_and_wait_range(inode->i_mapping, start, end);
 105                if (ret != 0)
 106                        break;
 107                mutex_lock(&inode->i_mutex);
 108                ret = nfs_file_fsync_commit(file, start, end, datasync);
 109                if (!ret)
 110                        ret = pnfs_layoutcommit_inode(inode, true);
 111                mutex_unlock(&inode->i_mutex);
 112                /*
 113                 * If nfs_file_fsync_commit detected a server reboot, then
 114                 * resend all dirty pages that might have been covered by
 115                 * the NFS_CONTEXT_RESEND_WRITES flag
 116                 */
 117                start = 0;
 118                end = LLONG_MAX;
 119        } while (ret == -EAGAIN);
 120
 121        return ret;
 122}
 123
 124#ifdef CONFIG_NFS_V4_2
 125static loff_t nfs4_file_llseek(struct file *filep, loff_t offset, int whence)
 126{
 127        loff_t ret;
 128
 129        switch (whence) {
 130        case SEEK_HOLE:
 131        case SEEK_DATA:
 132                ret = nfs42_proc_llseek(filep, offset, whence);
 133                if (ret != -ENOTSUPP)
 134                        return ret;
 135        default:
 136                return nfs_file_llseek(filep, offset, whence);
 137        }
 138}
 139
 140static long nfs42_fallocate(struct file *filep, int mode, loff_t offset, loff_t len)
 141{
 142        struct inode *inode = file_inode(filep);
 143        long ret;
 144
 145        if (!S_ISREG(inode->i_mode))
 146                return -EOPNOTSUPP;
 147
 148        if ((mode != 0) && (mode != (FALLOC_FL_PUNCH_HOLE | FALLOC_FL_KEEP_SIZE)))
 149                return -EOPNOTSUPP;
 150
 151        ret = inode_newsize_ok(inode, offset + len);
 152        if (ret < 0)
 153                return ret;
 154
 155        mutex_lock(&inode->i_mutex);
 156        if (mode & FALLOC_FL_PUNCH_HOLE)
 157                ret = nfs42_proc_deallocate(filep, offset, len);
 158        else
 159                ret = nfs42_proc_allocate(filep, offset, len);
 160        mutex_unlock(&inode->i_mutex);
 161
 162        nfs_zap_caches(inode);
 163        return ret;
 164}
 165#endif /* CONFIG_NFS_V4_2 */
 166
 167const struct file_operations nfs4_file_operations = {
 168#ifdef CONFIG_NFS_V4_2
 169        .llseek         = nfs4_file_llseek,
 170#else
 171        .llseek         = nfs_file_llseek,
 172#endif
 173        .read           = new_sync_read,
 174        .write          = new_sync_write,
 175        .read_iter      = nfs_file_read,
 176        .write_iter     = nfs_file_write,
 177        .mmap           = nfs_file_mmap,
 178        .open           = nfs4_file_open,
 179        .flush          = nfs_file_flush,
 180        .release        = nfs_file_release,
 181        .fsync          = nfs4_file_fsync,
 182        .lock           = nfs_lock,
 183        .flock          = nfs_flock,
 184        .splice_read    = nfs_file_splice_read,
 185        .splice_write   = iter_file_splice_write,
 186#ifdef CONFIG_NFS_V4_2
 187        .fallocate      = nfs42_fallocate,
 188#endif /* CONFIG_NFS_V4_2 */
 189        .check_flags    = nfs_check_flags,
 190        .setlease       = simple_nosetlease,
 191};
 192