1 /* 2 * Copyright (c) 2014 Anna Schumaker <Anna.Schumaker@Netapp.com> 3 */ 4 #include <linux/fs.h> 5 #include <linux/sunrpc/sched.h> 6 #include <linux/nfs.h> 7 #include <linux/nfs3.h> 8 #include <linux/nfs4.h> 9 #include <linux/nfs_xdr.h> 10 #include <linux/nfs_fs.h> 11 #include "nfs4_fs.h" 12 #include "nfs42.h" 13 14 static int nfs42_set_rw_stateid(nfs4_stateid *dst, struct file *file, 15 fmode_t fmode) 16 { 17 struct nfs_open_context *open; 18 struct nfs_lock_context *lock; 19 int ret; 20 21 open = get_nfs_open_context(nfs_file_open_context(file)); 22 lock = nfs_get_lock_context(open); 23 if (IS_ERR(lock)) { 24 put_nfs_open_context(open); 25 return PTR_ERR(lock); 26 } 27 28 ret = nfs4_set_rw_stateid(dst, open, lock, fmode); 29 30 nfs_put_lock_context(lock); 31 put_nfs_open_context(open); 32 return ret; 33 } 34 35 loff_t nfs42_proc_llseek(struct file *filep, loff_t offset, int whence) 36 { 37 struct inode *inode = file_inode(filep); 38 struct nfs42_seek_args args = { 39 .sa_fh = NFS_FH(inode), 40 .sa_offset = offset, 41 .sa_what = (whence == SEEK_HOLE) ? 42 NFS4_CONTENT_HOLE : NFS4_CONTENT_DATA, 43 }; 44 struct nfs42_seek_res res; 45 struct rpc_message msg = { 46 .rpc_proc = &nfs4_procedures[NFSPROC4_CLNT_SEEK], 47 .rpc_argp = &args, 48 .rpc_resp = &res, 49 }; 50 struct nfs_server *server = NFS_SERVER(inode); 51 int status; 52 53 if (!(server->caps & NFS_CAP_SEEK)) 54 return -ENOTSUPP; 55 56 status = nfs42_set_rw_stateid(&args.sa_stateid, filep, FMODE_READ); 57 if (status) 58 return status; 59 60 nfs_wb_all(inode); 61 status = nfs4_call_sync(server->client, server, &msg, 62 &args.seq_args, &res.seq_res, 0); 63 if (status == -ENOTSUPP) 64 server->caps &= ~NFS_CAP_SEEK; 65 if (status) 66 return status; 67 68 return vfs_setpos(filep, res.sr_offset, inode->i_sb->s_maxbytes); 69 } 70