These changes are the raw update to linux-4.4.6-rt14. Kernel sources
[kvmfornfv.git] / kernel / fs / nfs / nfs42proc.c
index 3a9e752..6b1ce98 100644 (file)
 #include <linux/nfs_fs.h>
 #include "nfs4_fs.h"
 #include "nfs42.h"
+#include "iostat.h"
+#include "pnfs.h"
+#include "internal.h"
+
+#define NFSDBG_FACILITY NFSDBG_PROC
 
 static int nfs42_set_rw_stateid(nfs4_stateid *dst, struct file *file,
                                fmode_t fmode)
@@ -130,7 +135,7 @@ int nfs42_proc_deallocate(struct file *filep, loff_t offset, loff_t len)
        return err;
 }
 
-loff_t nfs42_proc_llseek(struct file *filep, loff_t offset, int whence)
+static loff_t _nfs42_proc_llseek(struct file *filep, loff_t offset, int whence)
 {
        struct inode *inode = file_inode(filep);
        struct nfs42_seek_args args = {
@@ -165,3 +170,176 @@ loff_t nfs42_proc_llseek(struct file *filep, loff_t offset, int whence)
 
        return vfs_setpos(filep, res.sr_offset, inode->i_sb->s_maxbytes);
 }
+
+loff_t nfs42_proc_llseek(struct file *filep, loff_t offset, int whence)
+{
+       struct nfs_server *server = NFS_SERVER(file_inode(filep));
+       struct nfs4_exception exception = { };
+       loff_t err;
+
+       do {
+               err = _nfs42_proc_llseek(filep, offset, whence);
+               if (err >= 0)
+                       break;
+               if (err == -ENOTSUPP)
+                       return -EOPNOTSUPP;
+               err = nfs4_handle_exception(server, err, &exception);
+       } while (exception.retry);
+
+       return err;
+}
+
+
+static void
+nfs42_layoutstat_prepare(struct rpc_task *task, void *calldata)
+{
+       struct nfs42_layoutstat_data *data = calldata;
+       struct nfs_server *server = NFS_SERVER(data->args.inode);
+
+       nfs41_setup_sequence(nfs4_get_session(server), &data->args.seq_args,
+                            &data->res.seq_res, task);
+}
+
+static void
+nfs42_layoutstat_done(struct rpc_task *task, void *calldata)
+{
+       struct nfs42_layoutstat_data *data = calldata;
+
+       if (!nfs4_sequence_done(task, &data->res.seq_res))
+               return;
+
+       switch (task->tk_status) {
+       case 0:
+               break;
+       case -ENOTSUPP:
+       case -EOPNOTSUPP:
+               NFS_SERVER(data->inode)->caps &= ~NFS_CAP_LAYOUTSTATS;
+       default:
+               dprintk("%s server returns %d\n", __func__, task->tk_status);
+       }
+}
+
+static void
+nfs42_layoutstat_release(void *calldata)
+{
+       struct nfs42_layoutstat_data *data = calldata;
+       struct nfs_server *nfss = NFS_SERVER(data->args.inode);
+
+       if (nfss->pnfs_curr_ld->cleanup_layoutstats)
+               nfss->pnfs_curr_ld->cleanup_layoutstats(data);
+
+       pnfs_put_layout_hdr(NFS_I(data->args.inode)->layout);
+       smp_mb__before_atomic();
+       clear_bit(NFS_INO_LAYOUTSTATS, &NFS_I(data->args.inode)->flags);
+       smp_mb__after_atomic();
+       nfs_iput_and_deactive(data->inode);
+       kfree(data->args.devinfo);
+       kfree(data);
+}
+
+static const struct rpc_call_ops nfs42_layoutstat_ops = {
+       .rpc_call_prepare = nfs42_layoutstat_prepare,
+       .rpc_call_done = nfs42_layoutstat_done,
+       .rpc_release = nfs42_layoutstat_release,
+};
+
+int nfs42_proc_layoutstats_generic(struct nfs_server *server,
+                                  struct nfs42_layoutstat_data *data)
+{
+       struct rpc_message msg = {
+               .rpc_proc = &nfs4_procedures[NFSPROC4_CLNT_LAYOUTSTATS],
+               .rpc_argp = &data->args,
+               .rpc_resp = &data->res,
+       };
+       struct rpc_task_setup task_setup = {
+               .rpc_client = server->client,
+               .rpc_message = &msg,
+               .callback_ops = &nfs42_layoutstat_ops,
+               .callback_data = data,
+               .flags = RPC_TASK_ASYNC,
+       };
+       struct rpc_task *task;
+
+       data->inode = nfs_igrab_and_active(data->args.inode);
+       if (!data->inode) {
+               nfs42_layoutstat_release(data);
+               return -EAGAIN;
+       }
+       nfs4_init_sequence(&data->args.seq_args, &data->res.seq_res, 0);
+       task = rpc_run_task(&task_setup);
+       if (IS_ERR(task))
+               return PTR_ERR(task);
+       return 0;
+}
+
+static int _nfs42_proc_clone(struct rpc_message *msg, struct file *src_f,
+                            struct file *dst_f, loff_t src_offset,
+                            loff_t dst_offset, loff_t count)
+{
+       struct inode *src_inode = file_inode(src_f);
+       struct inode *dst_inode = file_inode(dst_f);
+       struct nfs_server *server = NFS_SERVER(dst_inode);
+       struct nfs42_clone_args args = {
+               .src_fh = NFS_FH(src_inode),
+               .dst_fh = NFS_FH(dst_inode),
+               .src_offset = src_offset,
+               .dst_offset = dst_offset,
+               .count = count,
+               .dst_bitmask = server->cache_consistency_bitmask,
+       };
+       struct nfs42_clone_res res = {
+               .server = server,
+       };
+       int status;
+
+       msg->rpc_argp = &args;
+       msg->rpc_resp = &res;
+
+       status = nfs42_set_rw_stateid(&args.src_stateid, src_f, FMODE_READ);
+       if (status)
+               return status;
+
+       status = nfs42_set_rw_stateid(&args.dst_stateid, dst_f, FMODE_WRITE);
+       if (status)
+               return status;
+
+       res.dst_fattr = nfs_alloc_fattr();
+       if (!res.dst_fattr)
+               return -ENOMEM;
+
+       status = nfs4_call_sync(server->client, server, msg,
+                               &args.seq_args, &res.seq_res, 0);
+       if (status == 0)
+               status = nfs_post_op_update_inode(dst_inode, res.dst_fattr);
+
+       kfree(res.dst_fattr);
+       return status;
+}
+
+int nfs42_proc_clone(struct file *src_f, struct file *dst_f,
+                    loff_t src_offset, loff_t dst_offset, loff_t count)
+{
+       struct rpc_message msg = {
+               .rpc_proc = &nfs4_procedures[NFSPROC4_CLNT_CLONE],
+       };
+       struct inode *inode = file_inode(src_f);
+       struct nfs_server *server = NFS_SERVER(file_inode(src_f));
+       struct nfs4_exception exception = { };
+       int err;
+
+       if (!nfs_server_capable(inode, NFS_CAP_CLONE))
+               return -EOPNOTSUPP;
+
+       do {
+               err = _nfs42_proc_clone(&msg, src_f, dst_f, src_offset,
+                                       dst_offset, count);
+               if (err == -ENOTSUPP || err == -EOPNOTSUPP) {
+                       NFS_SERVER(inode)->caps &= ~NFS_CAP_CLONE;
+                       return -EOPNOTSUPP;
+               }
+               err = nfs4_handle_exception(server, err, &exception);
+       } while (exception.retry);
+
+       return err;
+
+}