linux/fs/cifs/smb2file.c
<<
>>
Prefs
   1/*
   2 *   fs/cifs/smb2file.c
   3 *
   4 *   Copyright (C) International Business Machines  Corp., 2002, 2011
   5 *   Author(s): Steve French (sfrench@us.ibm.com),
   6 *              Pavel Shilovsky ((pshilovsky@samba.org) 2012
   7 *
   8 *   This library is free software; you can redistribute it and/or modify
   9 *   it under the terms of the GNU Lesser General Public License as published
  10 *   by the Free Software Foundation; either version 2.1 of the License, or
  11 *   (at your option) any later version.
  12 *
  13 *   This library is distributed in the hope that it will be useful,
  14 *   but WITHOUT ANY WARRANTY; without even the implied warranty of
  15 *   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See
  16 *   the GNU Lesser General Public License for more details.
  17 *
  18 *   You should have received a copy of the GNU Lesser General Public License
  19 *   along with this library; if not, write to the Free Software
  20 *   Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
  21 */
  22#include <linux/fs.h>
  23#include <linux/stat.h>
  24#include <linux/slab.h>
  25#include <linux/pagemap.h>
  26#include <asm/div64.h>
  27#include "cifsfs.h"
  28#include "cifspdu.h"
  29#include "cifsglob.h"
  30#include "cifsproto.h"
  31#include "cifs_debug.h"
  32#include "cifs_fs_sb.h"
  33#include "cifs_unicode.h"
  34#include "fscache.h"
  35#include "smb2proto.h"
  36
  37void
  38smb2_set_oplock_level(struct cifsInodeInfo *cinode, __u32 oplock)
  39{
  40        oplock &= 0xFF;
  41        if (oplock == SMB2_OPLOCK_LEVEL_NOCHANGE)
  42                return;
  43        if (oplock == SMB2_OPLOCK_LEVEL_EXCLUSIVE) {
  44                cinode->clientCanCacheAll = true;
  45                cinode->clientCanCacheRead = true;
  46                cFYI(1, "Exclusive Oplock granted on inode %p",
  47                     &cinode->vfs_inode);
  48        } else if (oplock == SMB2_OPLOCK_LEVEL_II) {
  49                cinode->clientCanCacheAll = false;
  50                cinode->clientCanCacheRead = true;
  51                cFYI(1, "Level II Oplock granted on inode %p",
  52                    &cinode->vfs_inode);
  53        } else {
  54                cinode->clientCanCacheAll = false;
  55                cinode->clientCanCacheRead = false;
  56        }
  57}
  58
  59int
  60smb2_open_file(const unsigned int xid, struct cifs_tcon *tcon, const char *path,
  61               int disposition, int desired_access, int create_options,
  62               struct cifs_fid *fid, __u32 *oplock, FILE_ALL_INFO *buf,
  63               struct cifs_sb_info *cifs_sb)
  64{
  65        int rc;
  66        __le16 *smb2_path;
  67        struct smb2_file_all_info *smb2_data = NULL;
  68        __u8 smb2_oplock[17];
  69
  70        smb2_path = cifs_convert_path_to_utf16(path, cifs_sb);
  71        if (smb2_path == NULL) {
  72                rc = -ENOMEM;
  73                goto out;
  74        }
  75
  76        smb2_data = kzalloc(sizeof(struct smb2_file_all_info) + MAX_NAME * 2,
  77                            GFP_KERNEL);
  78        if (smb2_data == NULL) {
  79                rc = -ENOMEM;
  80                goto out;
  81        }
  82
  83        desired_access |= FILE_READ_ATTRIBUTES;
  84        *smb2_oplock = SMB2_OPLOCK_LEVEL_EXCLUSIVE;
  85
  86        if (tcon->ses->server->capabilities & SMB2_GLOBAL_CAP_LEASING)
  87                memcpy(smb2_oplock + 1, fid->lease_key, SMB2_LEASE_KEY_SIZE);
  88
  89        rc = SMB2_open(xid, tcon, smb2_path, &fid->persistent_fid,
  90                       &fid->volatile_fid, desired_access, disposition,
  91                       0, 0, smb2_oplock, smb2_data);
  92        if (rc)
  93                goto out;
  94
  95        if (buf) {
  96                /* open response does not have IndexNumber field - get it */
  97                rc = SMB2_get_srv_num(xid, tcon, fid->persistent_fid,
  98                                      fid->volatile_fid,
  99                                      &smb2_data->IndexNumber);
 100                if (rc) {
 101                        /* let get_inode_info disable server inode numbers */
 102                        smb2_data->IndexNumber = 0;
 103                        rc = 0;
 104                }
 105                move_smb2_info_to_cifs(buf, smb2_data);
 106        }
 107
 108        *oplock = *smb2_oplock;
 109out:
 110        kfree(smb2_data);
 111        kfree(smb2_path);
 112        return rc;
 113}
 114
 115int
 116smb2_unlock_range(struct cifsFileInfo *cfile, struct file_lock *flock,
 117                  const unsigned int xid)
 118{
 119        int rc = 0, stored_rc;
 120        unsigned int max_num, num = 0, max_buf;
 121        struct smb2_lock_element *buf, *cur;
 122        struct cifs_tcon *tcon = tlink_tcon(cfile->tlink);
 123        struct cifsInodeInfo *cinode = CIFS_I(cfile->dentry->d_inode);
 124        struct cifsLockInfo *li, *tmp;
 125        __u64 length = 1 + flock->fl_end - flock->fl_start;
 126        struct list_head tmp_llist;
 127
 128        INIT_LIST_HEAD(&tmp_llist);
 129
 130        /*
 131         * Accessing maxBuf is racy with cifs_reconnect - need to store value
 132         * and check it for zero before using.
 133         */
 134        max_buf = tcon->ses->server->maxBuf;
 135        if (!max_buf)
 136                return -EINVAL;
 137
 138        max_num = max_buf / sizeof(struct smb2_lock_element);
 139        buf = kzalloc(max_num * sizeof(struct smb2_lock_element), GFP_KERNEL);
 140        if (!buf)
 141                return -ENOMEM;
 142
 143        cur = buf;
 144
 145        down_write(&cinode->lock_sem);
 146        list_for_each_entry_safe(li, tmp, &cfile->llist->locks, llist) {
 147                if (flock->fl_start > li->offset ||
 148                    (flock->fl_start + length) <
 149                    (li->offset + li->length))
 150                        continue;
 151                if (current->tgid != li->pid)
 152                        continue;
 153                if (cinode->can_cache_brlcks) {
 154                        /*
 155                         * We can cache brlock requests - simply remove a lock
 156                         * from the file's list.
 157                         */
 158                        list_del(&li->llist);
 159                        cifs_del_lock_waiters(li);
 160                        kfree(li);
 161                        continue;
 162                }
 163                cur->Length = cpu_to_le64(li->length);
 164                cur->Offset = cpu_to_le64(li->offset);
 165                cur->Flags = cpu_to_le32(SMB2_LOCKFLAG_UNLOCK);
 166                /*
 167                 * We need to save a lock here to let us add it again to the
 168                 * file's list if the unlock range request fails on the server.
 169                 */
 170                list_move(&li->llist, &tmp_llist);
 171                if (++num == max_num) {
 172                        stored_rc = smb2_lockv(xid, tcon,
 173                                               cfile->fid.persistent_fid,
 174                                               cfile->fid.volatile_fid,
 175                                               current->tgid, num, buf);
 176                        if (stored_rc) {
 177                                /*
 178                                 * We failed on the unlock range request - add
 179                                 * all locks from the tmp list to the head of
 180                                 * the file's list.
 181                                 */
 182                                cifs_move_llist(&tmp_llist,
 183                                                &cfile->llist->locks);
 184                                rc = stored_rc;
 185                        } else
 186                                /*
 187                                 * The unlock range request succeed - free the
 188                                 * tmp list.
 189                                 */
 190                                cifs_free_llist(&tmp_llist);
 191                        cur = buf;
 192                        num = 0;
 193                } else
 194                        cur++;
 195        }
 196        if (num) {
 197                stored_rc = smb2_lockv(xid, tcon, cfile->fid.persistent_fid,
 198                                       cfile->fid.volatile_fid, current->tgid,
 199                                       num, buf);
 200                if (stored_rc) {
 201                        cifs_move_llist(&tmp_llist, &cfile->llist->locks);
 202                        rc = stored_rc;
 203                } else
 204                        cifs_free_llist(&tmp_llist);
 205        }
 206        up_write(&cinode->lock_sem);
 207
 208        kfree(buf);
 209        return rc;
 210}
 211
 212static int
 213smb2_push_mand_fdlocks(struct cifs_fid_locks *fdlocks, const unsigned int xid,
 214                       struct smb2_lock_element *buf, unsigned int max_num)
 215{
 216        int rc = 0, stored_rc;
 217        struct cifsFileInfo *cfile = fdlocks->cfile;
 218        struct cifsLockInfo *li;
 219        unsigned int num = 0;
 220        struct smb2_lock_element *cur = buf;
 221        struct cifs_tcon *tcon = tlink_tcon(cfile->tlink);
 222
 223        list_for_each_entry(li, &fdlocks->locks, llist) {
 224                cur->Length = cpu_to_le64(li->length);
 225                cur->Offset = cpu_to_le64(li->offset);
 226                cur->Flags = cpu_to_le32(li->type |
 227                                                SMB2_LOCKFLAG_FAIL_IMMEDIATELY);
 228                if (++num == max_num) {
 229                        stored_rc = smb2_lockv(xid, tcon,
 230                                               cfile->fid.persistent_fid,
 231                                               cfile->fid.volatile_fid,
 232                                               current->tgid, num, buf);
 233                        if (stored_rc)
 234                                rc = stored_rc;
 235                        cur = buf;
 236                        num = 0;
 237                } else
 238                        cur++;
 239        }
 240        if (num) {
 241                stored_rc = smb2_lockv(xid, tcon,
 242                                       cfile->fid.persistent_fid,
 243                                       cfile->fid.volatile_fid,
 244                                       current->tgid, num, buf);
 245                if (stored_rc)
 246                        rc = stored_rc;
 247        }
 248
 249        return rc;
 250}
 251
 252int
 253smb2_push_mandatory_locks(struct cifsFileInfo *cfile)
 254{
 255        int rc = 0, stored_rc;
 256        unsigned int xid;
 257        unsigned int max_num, max_buf;
 258        struct smb2_lock_element *buf;
 259        struct cifsInodeInfo *cinode = CIFS_I(cfile->dentry->d_inode);
 260        struct cifs_fid_locks *fdlocks;
 261
 262        xid = get_xid();
 263        /* we are going to update can_cache_brlcks here - need a write access */
 264        down_write(&cinode->lock_sem);
 265        if (!cinode->can_cache_brlcks) {
 266                up_write(&cinode->lock_sem);
 267                free_xid(xid);
 268                return rc;
 269        }
 270
 271        /*
 272         * Accessing maxBuf is racy with cifs_reconnect - need to store value
 273         * and check it for zero before using.
 274         */
 275        max_buf = tlink_tcon(cfile->tlink)->ses->server->maxBuf;
 276        if (!max_buf) {
 277                up_write(&cinode->lock_sem);
 278                free_xid(xid);
 279                return -EINVAL;
 280        }
 281
 282        max_num = max_buf / sizeof(struct smb2_lock_element);
 283        buf = kzalloc(max_num * sizeof(struct smb2_lock_element), GFP_KERNEL);
 284        if (!buf) {
 285                up_write(&cinode->lock_sem);
 286                free_xid(xid);
 287                return -ENOMEM;
 288        }
 289
 290        list_for_each_entry(fdlocks, &cinode->llist, llist) {
 291                stored_rc = smb2_push_mand_fdlocks(fdlocks, xid, buf, max_num);
 292                if (stored_rc)
 293                        rc = stored_rc;
 294        }
 295
 296        cinode->can_cache_brlcks = false;
 297        kfree(buf);
 298
 299        up_write(&cinode->lock_sem);
 300        free_xid(xid);
 301        return rc;
 302}
 303
lxr.linux.no kindly hosted by Redpill Linpro AS, provider of Linux consulting and operations services since 1995.