CIFS: Add writepage support for SMB2
[deliverable/linux.git] / fs / cifs / smb2ops.c
index 826209bf36842c904259533a0199fc6f5138a0b9..f9c3dbee9010f4ceafddae9d2e468c7c0c906994 100644 (file)
@@ -17,6 +17,7 @@
  *  Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
  */
 
+#include <linux/pagemap.h>
 #include "cifsglob.h"
 #include "smb2pdu.h"
 #include "smb2proto.h"
@@ -157,6 +158,48 @@ smb2_negotiate(const unsigned int xid, struct cifs_ses *ses)
        return rc;
 }
 
+static unsigned int
+smb2_negotiate_wsize(struct cifs_tcon *tcon, struct smb_vol *volume_info)
+{
+       struct TCP_Server_Info *server = tcon->ses->server;
+       unsigned int wsize;
+
+       /* start with specified wsize, or default */
+       wsize = volume_info->wsize ? volume_info->wsize : CIFS_DEFAULT_IOSIZE;
+       wsize = min_t(unsigned int, wsize, server->max_write);
+       /*
+        * limit write size to 2 ** 16, because we don't support multicredit
+        * requests now.
+        */
+       wsize = min_t(unsigned int, wsize, 2 << 15);
+
+       /* limit to the amount that we can kmap at once */
+       wsize = min_t(unsigned int, wsize, CIFS_KMAP_SIZE_LIMIT);
+
+       return wsize;
+}
+
+static unsigned int
+smb2_negotiate_rsize(struct cifs_tcon *tcon, struct smb_vol *volume_info)
+{
+       struct TCP_Server_Info *server = tcon->ses->server;
+       unsigned int rsize;
+
+       /* start with specified rsize, or default */
+       rsize = volume_info->rsize ? volume_info->rsize : CIFS_DEFAULT_IOSIZE;
+       rsize = min_t(unsigned int, rsize, server->max_read);
+       /*
+        * limit write size to 2 ** 16, because we don't support multicredit
+        * requests now.
+        */
+       rsize = min_t(unsigned int, rsize, 2 << 15);
+
+       /* limit to the amount that we can kmap at once */
+       rsize = min_t(unsigned int, rsize, CIFS_KMAP_SIZE_LIMIT);
+
+       return rsize;
+}
+
 static int
 smb2_is_path_accessible(const unsigned int xid, struct cifs_tcon *tcon,
                        struct cifs_sb_info *cifs_sb, const char *full_path)
@@ -170,7 +213,7 @@ smb2_is_path_accessible(const unsigned int xid, struct cifs_tcon *tcon,
                return -ENOMEM;
 
        rc = SMB2_open(xid, tcon, utf16_path, &persistent_fid, &volatile_fid,
-                      FILE_READ_ATTRIBUTES, FILE_OPEN, 0, 0);
+                      FILE_READ_ATTRIBUTES, FILE_OPEN, 0, 0, NULL);
        if (rc) {
                kfree(utf16_path);
                return rc;
@@ -190,6 +233,26 @@ smb2_get_srv_inum(const unsigned int xid, struct cifs_tcon *tcon,
        return 0;
 }
 
+static int
+smb2_query_file_info(const unsigned int xid, struct cifs_tcon *tcon,
+                    struct cifs_fid *fid, FILE_ALL_INFO *data)
+{
+       int rc;
+       struct smb2_file_all_info *smb2_data;
+
+       smb2_data = kzalloc(sizeof(struct smb2_file_all_info) + MAX_NAME * 2,
+                           GFP_KERNEL);
+       if (smb2_data == NULL)
+               return -ENOMEM;
+
+       rc = SMB2_query_info(xid, tcon, fid->persistent_fid, fid->volatile_fid,
+                            smb2_data);
+       if (!rc)
+               move_smb2_info_to_cifs(data, smb2_data);
+       kfree(smb2_data);
+       return rc;
+}
+
 static char *
 smb2_build_path_to_root(struct smb_vol *vol, struct cifs_sb_info *cifs_sb,
                        struct cifs_tcon *tcon)
@@ -292,6 +355,66 @@ smb2_print_stats(struct seq_file *m, struct cifs_tcon *tcon)
 #endif
 }
 
+static void
+smb2_set_fid(struct cifsFileInfo *cfile, struct cifs_fid *fid, __u32 oplock)
+{
+       /* struct cifsInodeInfo *cinode = CIFS_I(cfile->dentry->d_inode); */
+       cfile->fid.persistent_fid = fid->persistent_fid;
+       cfile->fid.volatile_fid = fid->volatile_fid;
+       /* cifs_set_oplock_level(cinode, oplock); */
+       /* cinode->can_cache_brlcks = cinode->clientCanCacheAll; */
+}
+
+static int
+smb2_close_file(const unsigned int xid, struct cifs_tcon *tcon,
+               struct cifs_fid *fid)
+{
+       return SMB2_close(xid, tcon, fid->persistent_fid, fid->volatile_fid);
+}
+
+static int
+smb2_flush_file(const unsigned int xid, struct cifs_tcon *tcon,
+               struct cifs_fid *fid)
+{
+       return SMB2_flush(xid, tcon, fid->persistent_fid, fid->volatile_fid);
+}
+
+static unsigned int
+smb2_read_data_offset(char *buf)
+{
+       struct smb2_read_rsp *rsp = (struct smb2_read_rsp *)buf;
+       return rsp->DataOffset;
+}
+
+static unsigned int
+smb2_read_data_length(char *buf)
+{
+       struct smb2_read_rsp *rsp = (struct smb2_read_rsp *)buf;
+       return le32_to_cpu(rsp->DataLength);
+}
+
+
+static int
+smb2_sync_read(const unsigned int xid, struct cifsFileInfo *cfile,
+              struct cifs_io_parms *parms, unsigned int *bytes_read,
+              char **buf, int *buf_type)
+{
+       parms->persistent_fid = cfile->fid.persistent_fid;
+       parms->volatile_fid = cfile->fid.volatile_fid;
+       return SMB2_read(xid, parms, bytes_read, buf, buf_type);
+}
+
+static int
+smb2_sync_write(const unsigned int xid, struct cifsFileInfo *cfile,
+               struct cifs_io_parms *parms, unsigned int *written,
+               struct kvec *iov, unsigned long nr_segs)
+{
+
+       parms->persistent_fid = cfile->fid.persistent_fid;
+       parms->volatile_fid = cfile->fid.volatile_fid;
+       return SMB2_write(xid, parms, written, iov, nr_segs);
+}
+
 struct smb_version_operations smb21_operations = {
        .setup_request = smb2_setup_request,
        .setup_async_request = smb2_setup_async_request,
@@ -301,6 +424,9 @@ struct smb_version_operations smb21_operations = {
        .get_credits_field = smb2_get_credits_field,
        .get_credits = smb2_get_credits,
        .get_next_mid = smb2_get_next_mid,
+       .read_data_offset = smb2_read_data_offset,
+       .read_data_length = smb2_read_data_length,
+       .map_error = map_smb2_to_linux_error,
        .find_mid = smb2_find_mid,
        .check_message = smb2_check_message,
        .dump_detail = smb2_dump_detail,
@@ -308,6 +434,8 @@ struct smb_version_operations smb21_operations = {
        .print_stats = smb2_print_stats,
        .need_neg = smb2_need_neg,
        .negotiate = smb2_negotiate,
+       .negotiate_wsize = smb2_negotiate_wsize,
+       .negotiate_rsize = smb2_negotiate_rsize,
        .sess_setup = SMB2_sess_setup,
        .logoff = SMB2_logoff,
        .tree_connect = SMB2_tcon,
@@ -317,16 +445,27 @@ struct smb_version_operations smb21_operations = {
        .echo = SMB2_echo,
        .query_path_info = smb2_query_path_info,
        .get_srv_inum = smb2_get_srv_inum,
+       .query_file_info = smb2_query_file_info,
        .build_path_to_root = smb2_build_path_to_root,
        .mkdir = smb2_mkdir,
        .mkdir_setinfo = smb2_mkdir_setinfo,
        .rmdir = smb2_rmdir,
+       .unlink = smb2_unlink,
+       .open = smb2_open_file,
+       .set_fid = smb2_set_fid,
+       .close = smb2_close_file,
+       .flush = smb2_flush_file,
+       .async_readv = smb2_async_readv,
+       .async_writev = smb2_async_writev,
+       .sync_read = smb2_sync_read,
+       .sync_write = smb2_sync_write,
 };
 
 struct smb_version_values smb21_values = {
        .version_string = SMB21_VERSION_STRING,
        .header_size = sizeof(struct smb2_hdr),
        .max_header_size = MAX_SMB2_HDR_SIZE,
+       .read_rsp_size = sizeof(struct smb2_read_rsp) - 1,
        .lock_cmd = SMB2_LOCK,
        .cap_unix = 0,
        .cap_nt_find = SMB2_NT_FIND,
This page took 0.025182 seconds and 5 git commands to generate.