file.c 106 KB
Newer Older
Linus Torvalds's avatar
Linus Torvalds committed
1 2 3 4
/*
 *   fs/cifs/file.c
 *
 *   vfs operations that deal with files
Steve French's avatar
Steve French committed
5
 *
6
 *   Copyright (C) International Business Machines  Corp., 2002,2010
Linus Torvalds's avatar
Linus Torvalds committed
7
 *   Author(s): Steve French ([email protected])
Jeremy Allison's avatar
Jeremy Allison committed
8
 *              Jeremy Allison ([email protected])
Linus Torvalds's avatar
Linus Torvalds committed
9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24
 *
 *   This library is free software; you can redistribute it and/or modify
 *   it under the terms of the GNU Lesser General Public License as published
 *   by the Free Software Foundation; either version 2.1 of the License, or
 *   (at your option) any later version.
 *
 *   This library is distributed in the hope that it will be useful,
 *   but WITHOUT ANY WARRANTY; without even the implied warranty of
 *   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See
 *   the GNU Lesser General Public License for more details.
 *
 *   You should have received a copy of the GNU Lesser General Public License
 *   along with this library; if not, write to the Free Software
 *   Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
 */
#include <linux/fs.h>
25
#include <linux/backing-dev.h>
Linus Torvalds's avatar
Linus Torvalds committed
26 27 28 29
#include <linux/stat.h>
#include <linux/fcntl.h>
#include <linux/pagemap.h>
#include <linux/pagevec.h>
30
#include <linux/writeback.h>
31
#include <linux/task_io_accounting_ops.h>
32
#include <linux/delay.h>
33
#include <linux/mount.h>
34
#include <linux/slab.h>
35
#include <linux/swap.h>
Linus Torvalds's avatar
Linus Torvalds committed
36 37 38 39 40 41 42 43
#include <asm/div64.h>
#include "cifsfs.h"
#include "cifspdu.h"
#include "cifsglob.h"
#include "cifsproto.h"
#include "cifs_unicode.h"
#include "cifs_debug.h"
#include "cifs_fs_sb.h"
44
#include "fscache.h"
45
#include "smbdirect.h"
46

Linus Torvalds's avatar
Linus Torvalds committed
47 48 49 50 51 52 53 54 55 56 57 58 59
static inline int cifs_convert_flags(unsigned int flags)
{
	if ((flags & O_ACCMODE) == O_RDONLY)
		return GENERIC_READ;
	else if ((flags & O_ACCMODE) == O_WRONLY)
		return GENERIC_WRITE;
	else if ((flags & O_ACCMODE) == O_RDWR) {
		/* GENERIC_ALL is too much permission to request
		   can cause unnecessary access denied on create */
		/* return GENERIC_ALL; */
		return (GENERIC_READ | GENERIC_WRITE);
	}

60 61 62
	return (READ_CONTROL | FILE_WRITE_ATTRIBUTES | FILE_READ_ATTRIBUTES |
		FILE_WRITE_EA | FILE_APPEND_DATA | FILE_WRITE_DATA |
		FILE_READ_DATA);
63
}
64

65
static u32 cifs_posix_convert_flags(unsigned int flags)
66
{
67
	u32 posix_flags = 0;
68

69
	if ((flags & O_ACCMODE) == O_RDONLY)
70
		posix_flags = SMB_O_RDONLY;
71
	else if ((flags & O_ACCMODE) == O_WRONLY)
72 73 74 75
		posix_flags = SMB_O_WRONLY;
	else if ((flags & O_ACCMODE) == O_RDWR)
		posix_flags = SMB_O_RDWR;

76
	if (flags & O_CREAT) {
77
		posix_flags |= SMB_O_CREAT;
78 79 80
		if (flags & O_EXCL)
			posix_flags |= SMB_O_EXCL;
	} else if (flags & O_EXCL)
81 82
		cifs_dbg(FYI, "Application %s pid %d has incorrectly set O_EXCL flag but not O_CREAT on file open. Ignoring O_EXCL\n",
			 current->comm, current->tgid);
83

84 85 86
	if (flags & O_TRUNC)
		posix_flags |= SMB_O_TRUNC;
	/* be safe and imply O_SYNC for O_DSYNC */
87
	if (flags & O_DSYNC)
88
		posix_flags |= SMB_O_SYNC;
89
	if (flags & O_DIRECTORY)
90
		posix_flags |= SMB_O_DIRECTORY;
91
	if (flags & O_NOFOLLOW)
92
		posix_flags |= SMB_O_NOFOLLOW;
93
	if (flags & O_DIRECT)
94
		posix_flags |= SMB_O_DIRECT;
95 96

	return posix_flags;
Linus Torvalds's avatar
Linus Torvalds committed
97 98 99 100 101 102 103 104 105 106
}

static inline int cifs_get_disposition(unsigned int flags)
{
	if ((flags & (O_CREAT | O_EXCL)) == (O_CREAT | O_EXCL))
		return FILE_CREATE;
	else if ((flags & (O_CREAT | O_TRUNC)) == (O_CREAT | O_TRUNC))
		return FILE_OVERWRITE_IF;
	else if ((flags & O_CREAT) == O_CREAT)
		return FILE_OPEN_IF;
107 108
	else if ((flags & O_TRUNC) == O_TRUNC)
		return FILE_OVERWRITE;
Linus Torvalds's avatar
Linus Torvalds committed
109 110 111 112
	else
		return FILE_OPEN;
}

113 114
int cifs_posix_open(char *full_path, struct inode **pinode,
			struct super_block *sb, int mode, unsigned int f_flags,
115
			__u32 *poplock, __u16 *pnetfid, unsigned int xid)
116 117 118 119 120 121 122
{
	int rc;
	FILE_UNIX_BASIC_INFO *presp_data;
	__u32 posix_flags = 0;
	struct cifs_sb_info *cifs_sb = CIFS_SB(sb);
	struct cifs_fattr fattr;
	struct tcon_link *tlink;
123
	struct cifs_tcon *tcon;
124

125
	cifs_dbg(FYI, "posix open %s\n", full_path);
126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142

	presp_data = kzalloc(sizeof(FILE_UNIX_BASIC_INFO), GFP_KERNEL);
	if (presp_data == NULL)
		return -ENOMEM;

	tlink = cifs_sb_tlink(cifs_sb);
	if (IS_ERR(tlink)) {
		rc = PTR_ERR(tlink);
		goto posix_open_ret;
	}

	tcon = tlink_tcon(tlink);
	mode &= ~current_umask();

	posix_flags = cifs_posix_convert_flags(f_flags);
	rc = CIFSPOSIXCreate(xid, tcon, posix_flags, mode, pnetfid, presp_data,
			     poplock, full_path, cifs_sb->local_nls,
143
			     cifs_remap(cifs_sb));
144 145 146 147 148 149 150 151 152 153 154 155 156 157 158 159 160 161 162 163 164 165 166 167 168 169 170 171 172 173
	cifs_put_tlink(tlink);

	if (rc)
		goto posix_open_ret;

	if (presp_data->Type == cpu_to_le32(-1))
		goto posix_open_ret; /* open ok, caller does qpathinfo */

	if (!pinode)
		goto posix_open_ret; /* caller does not need info */

	cifs_unix_basic_to_fattr(&fattr, presp_data, cifs_sb);

	/* get new inode and set it up */
	if (*pinode == NULL) {
		cifs_fill_uniqueid(sb, &fattr);
		*pinode = cifs_iget(sb, &fattr);
		if (!*pinode) {
			rc = -ENOMEM;
			goto posix_open_ret;
		}
	} else {
		cifs_fattr_to_inode(*pinode, &fattr);
	}

posix_open_ret:
	kfree(presp_data);
	return rc;
}

174 175
static int
cifs_nt_open(char *full_path, struct inode *inode, struct cifs_sb_info *cifs_sb,
176 177
	     struct cifs_tcon *tcon, unsigned int f_flags, __u32 *oplock,
	     struct cifs_fid *fid, unsigned int xid)
178 179
{
	int rc;
180
	int desired_access;
181
	int disposition;
182
	int create_options = CREATE_NOT_DIR;
183
	FILE_ALL_INFO *buf;
184
	struct TCP_Server_Info *server = tcon->ses->server;
185
	struct cifs_open_parms oparms;
186

187
	if (!server->ops->open)
188 189 190
		return -ENOSYS;

	desired_access = cifs_convert_flags(f_flags);
191 192 193 194 195 196 197 198 199 200 201 202 203 204 205 206 207 208 209 210 211 212 213 214 215 216 217 218 219 220 221 222 223

/*********************************************************************
 *  open flag mapping table:
 *
 *	POSIX Flag            CIFS Disposition
 *	----------            ----------------
 *	O_CREAT               FILE_OPEN_IF
 *	O_CREAT | O_EXCL      FILE_CREATE
 *	O_CREAT | O_TRUNC     FILE_OVERWRITE_IF
 *	O_TRUNC               FILE_OVERWRITE
 *	none of the above     FILE_OPEN
 *
 *	Note that there is not a direct match between disposition
 *	FILE_SUPERSEDE (ie create whether or not file exists although
 *	O_CREAT | O_TRUNC is similar but truncates the existing
 *	file rather than creating a new file as FILE_SUPERSEDE does
 *	(which uses the attributes / metadata passed in on open call)
 *?
 *?  O_SYNC is a reasonable match to CIFS writethrough flag
 *?  and the read write flags match reasonably.  O_LARGEFILE
 *?  is irrelevant because largefile support is always used
 *?  by this client. Flags O_APPEND, O_DIRECT, O_DIRECTORY,
 *	 O_FASYNC, O_NOFOLLOW, O_NONBLOCK need further investigation
 *********************************************************************/

	disposition = cifs_get_disposition(f_flags);

	/* BB pass O_SYNC flag through on file attributes .. BB */

	buf = kmalloc(sizeof(FILE_ALL_INFO), GFP_KERNEL);
	if (!buf)
		return -ENOMEM;

224 225 226
	if (backup_cred(cifs_sb))
		create_options |= CREATE_OPEN_BACKUP_INTENT;

227 228 229 230 231 232 233
	/* O_SYNC also has bit for O_DSYNC so following check picks up either */
	if (f_flags & O_SYNC)
		create_options |= CREATE_WRITE_THROUGH;

	if (f_flags & O_DIRECT)
		create_options |= CREATE_NO_BUFFER;

234 235 236 237 238 239 240
	oparms.tcon = tcon;
	oparms.cifs_sb = cifs_sb;
	oparms.desired_access = desired_access;
	oparms.create_options = create_options;
	oparms.disposition = disposition;
	oparms.path = full_path;
	oparms.fid = fid;
241
	oparms.reconnect = false;
242 243

	rc = server->ops->open(xid, &oparms, oplock, buf);
244 245 246 247 248 249 250 251 252

	if (rc)
		goto out;

	if (tcon->unix_ext)
		rc = cifs_get_inode_info_unix(&inode, full_path, inode->i_sb,
					      xid);
	else
		rc = cifs_get_inode_info(&inode, full_path, buf, inode->i_sb,
253
					 xid, fid);
254 255 256 257 258 259

out:
	kfree(buf);
	return rc;
}

260 261 262 263 264 265 266 267 268 269 270 271 272 273 274 275 276
static bool
cifs_has_mand_locks(struct cifsInodeInfo *cinode)
{
	struct cifs_fid_locks *cur;
	bool has_locks = false;

	down_read(&cinode->lock_sem);
	list_for_each_entry(cur, &cinode->llist, llist) {
		if (!list_empty(&cur->locks)) {
			has_locks = true;
			break;
		}
	}
	up_read(&cinode->lock_sem);
	return has_locks;
}

277
struct cifsFileInfo *
278
cifs_new_fileinfo(struct cifs_fid *fid, struct file *file,
279 280
		  struct tcon_link *tlink, __u32 oplock)
{
Goldwyn Rodrigues's avatar
Goldwyn Rodrigues committed
281
	struct dentry *dentry = file_dentry(file);
282
	struct inode *inode = d_inode(dentry);
283 284
	struct cifsInodeInfo *cinode = CIFS_I(inode);
	struct cifsFileInfo *cfile;
285
	struct cifs_fid_locks *fdlocks;
286
	struct cifs_tcon *tcon = tlink_tcon(tlink);
287
	struct TCP_Server_Info *server = tcon->ses->server;
288 289 290 291 292

	cfile = kzalloc(sizeof(struct cifsFileInfo), GFP_KERNEL);
	if (cfile == NULL)
		return cfile;

293 294 295 296 297 298 299 300 301
	fdlocks = kzalloc(sizeof(struct cifs_fid_locks), GFP_KERNEL);
	if (!fdlocks) {
		kfree(cfile);
		return NULL;
	}

	INIT_LIST_HEAD(&fdlocks->locks);
	fdlocks->cfile = cfile;
	cfile->llist = fdlocks;
302
	down_write(&cinode->lock_sem);
303
	list_add(&fdlocks->llist, &cinode->llist);
304
	up_write(&cinode->lock_sem);
305

306 307 308 309 310 311 312 313
	cfile->count = 1;
	cfile->pid = current->tgid;
	cfile->uid = current_fsuid();
	cfile->dentry = dget(dentry);
	cfile->f_flags = file->f_flags;
	cfile->invalidHandle = false;
	cfile->tlink = cifs_get_tlink(tlink);
	INIT_WORK(&cfile->oplock_break, cifs_oplock_break);
314
	mutex_init(&cfile->fh_mutex);
315
	spin_lock_init(&cfile->file_info_lock);
316

317 318
	cifs_sb_active(inode->i_sb);

319 320 321 322
	/*
	 * If the server returned a read oplock and we have mandatory brlocks,
	 * set oplock level to None.
	 */
323
	if (server->ops->is_read_op(oplock) && cifs_has_mand_locks(cinode)) {
324
		cifs_dbg(FYI, "Reset oplock val from read to None due to mand locks\n");
325 326 327
		oplock = 0;
	}

328
	spin_lock(&tcon->open_file_lock);
329
	if (fid->pending_open->oplock != CIFS_OPLOCK_NO_CHANGE && oplock)
330 331 332
		oplock = fid->pending_open->oplock;
	list_del(&fid->pending_open->olist);

333
	fid->purge_cache = false;
334
	server->ops->set_fid(cfile, fid, oplock);
335 336

	list_add(&cfile->tlist, &tcon->openFileList);
337

338 339
	/* if readable file instance put first in list*/
	if (file->f_mode & FMODE_READ)
340
		list_add(&cfile->flist, &cinode->openFileList);
341
	else
342
		list_add_tail(&cfile->flist, &cinode->openFileList);
343
	spin_unlock(&tcon->open_file_lock);
344

345
	if (fid->purge_cache)
346
		cifs_zap_mapping(inode);
347

348 349
	file->private_data = cfile;
	return cfile;
350 351
}

352 353 354
struct cifsFileInfo *
cifsFileInfo_get(struct cifsFileInfo *cifs_file)
{
355
	spin_lock(&cifs_file->file_info_lock);
356
	cifsFileInfo_get_locked(cifs_file);
357
	spin_unlock(&cifs_file->file_info_lock);
358 359 360
	return cifs_file;
}

361 362
/*
 * Release a reference on the file private data. This may involve closing
363
 * the filehandle out on the server. Must be called without holding
364
 * tcon->open_file_lock and cifs_file->file_info_lock.
365
 */
366 367
void cifsFileInfo_put(struct cifsFileInfo *cifs_file)
{
368
	struct inode *inode = d_inode(cifs_file->dentry);
369
	struct cifs_tcon *tcon = tlink_tcon(cifs_file->tlink);
370
	struct TCP_Server_Info *server = tcon->ses->server;
371
	struct cifsInodeInfo *cifsi = CIFS_I(inode);
372 373
	struct super_block *sb = inode->i_sb;
	struct cifs_sb_info *cifs_sb = CIFS_SB(sb);
374
	struct cifsLockInfo *li, *tmp;
375 376
	struct cifs_fid fid;
	struct cifs_pending_open open;
377
	bool oplock_break_cancelled;
378

379 380 381
	spin_lock(&tcon->open_file_lock);

	spin_lock(&cifs_file->file_info_lock);
382
	if (--cifs_file->count > 0) {
383 384
		spin_unlock(&cifs_file->file_info_lock);
		spin_unlock(&tcon->open_file_lock);
385 386
		return;
	}
387
	spin_unlock(&cifs_file->file_info_lock);
388

389 390 391 392 393 394
	if (server->ops->get_lease_key)
		server->ops->get_lease_key(inode, &fid);

	/* store open in pending opens to make sure we don't miss lease break */
	cifs_add_pending_open_locked(&fid, cifs_file->tlink, &open);

395 396 397 398 399
	/* remove it from the lists */
	list_del(&cifs_file->flist);
	list_del(&cifs_file->tlist);

	if (list_empty(&cifsi->openFileList)) {
400
		cifs_dbg(FYI, "closing last open instance for inode %p\n",
401
			 d_inode(cifs_file->dentry));
402 403 404 405 406
		/*
		 * In strict cache mode we need invalidate mapping on the last
		 * close  because it may cause a error when we open this file
		 * again and get at least level II oplock.
		 */
407
		if (cifs_sb->mnt_cifs_flags & CIFS_MOUNT_STRICT_IO)
408
			set_bit(CIFS_INO_INVALID_MAPPING, &cifsi->flags);
409
		cifs_set_oplock_level(cifsi, 0);
410
	}
411 412

	spin_unlock(&tcon->open_file_lock);
413

414
	oplock_break_cancelled = cancel_work_sync(&cifs_file->oplock_break);
415

416
	if (!tcon->need_reconnect && !cifs_file->invalidHandle) {
417
		struct TCP_Server_Info *server = tcon->ses->server;
418
		unsigned int xid;
419

420
		xid = get_xid();
421
		if (server->ops->close)
422 423
			server->ops->close(xid, tcon, &cifs_file->fid);
		_free_xid(xid);
424 425
	}

426 427 428
	if (oplock_break_cancelled)
		cifs_done_oplock_break(cifsi);

429 430
	cifs_del_pending_open(&open);

431 432
	/*
	 * Delete any outstanding lock records. We'll lose them when the file
433 434
	 * is closed anyway.
	 */
435
	down_write(&cifsi->lock_sem);
436
	list_for_each_entry_safe(li, tmp, &cifs_file->llist->locks, llist) {
437
		list_del(&li->llist);
438
		cifs_del_lock_waiters(li);
439
		kfree(li);
440
	}
441 442
	list_del(&cifs_file->llist->llist);
	kfree(cifs_file->llist);
443
	up_write(&cifsi->lock_sem);
444 445 446

	cifs_put_tlink(cifs_file->tlink);
	dput(cifs_file->dentry);
447
	cifs_sb_deactive(sb);
448
	kfree(cifs_file);
449 450
}

Linus Torvalds's avatar
Linus Torvalds committed
451
int cifs_open(struct inode *inode, struct file *file)
452

Linus Torvalds's avatar
Linus Torvalds committed
453 454
{
	int rc = -EACCES;
455
	unsigned int xid;
456
	__u32 oplock;
Linus Torvalds's avatar
Linus Torvalds committed
457
	struct cifs_sb_info *cifs_sb;
458
	struct TCP_Server_Info *server;
459
	struct cifs_tcon *tcon;
460
	struct tcon_link *tlink;
461
	struct cifsFileInfo *cfile = NULL;
Linus Torvalds's avatar
Linus Torvalds committed
462
	char *full_path = NULL;
463
	bool posix_open_ok = false;
464
	struct cifs_fid fid;
465
	struct cifs_pending_open open;
Linus Torvalds's avatar
Linus Torvalds committed
466

467
	xid = get_xid();
Linus Torvalds's avatar
Linus Torvalds committed
468 469

	cifs_sb = CIFS_SB(inode->i_sb);
470 471
	tlink = cifs_sb_tlink(cifs_sb);
	if (IS_ERR(tlink)) {
472
		free_xid(xid);
473 474 475
		return PTR_ERR(tlink);
	}
	tcon = tlink_tcon(tlink);
476
	server = tcon->ses->server;
Linus Torvalds's avatar
Linus Torvalds committed
477

Goldwyn Rodrigues's avatar
Goldwyn Rodrigues committed
478
	full_path = build_path_from_dentry(file_dentry(file));
Linus Torvalds's avatar
Linus Torvalds committed
479
	if (full_path == NULL) {
480
		rc = -ENOMEM;
481
		goto out;
Linus Torvalds's avatar
Linus Torvalds committed
482 483
	}

484
	cifs_dbg(FYI, "inode = 0x%p file flags are 0x%x for %s\n",
485
		 inode, file->f_flags, full_path);
486

487 488 489 490 491 492 493 494
	if (file->f_flags & O_DIRECT &&
	    cifs_sb->mnt_cifs_flags & CIFS_MOUNT_STRICT_IO) {
		if (cifs_sb->mnt_cifs_flags & CIFS_MOUNT_NO_BRL)
			file->f_op = &cifs_file_direct_nobrl_ops;
		else
			file->f_op = &cifs_file_direct_ops;
	}

495
	if (server->oplocks)
496 497 498 499
		oplock = REQ_OPLOCK;
	else
		oplock = 0;

500
	if (!tcon->broken_posix_open && tcon->unix_ext &&
501 502
	    cap_unix(tcon->ses) && (CIFS_UNIX_POSIX_PATH_OPS_CAP &
				le64_to_cpu(tcon->fsUnixInfo.Capability))) {
503
		/* can not refresh inode info since size could be stale */
504
		rc = cifs_posix_open(full_path, &inode, inode->i_sb,
505
				cifs_sb->mnt_file_mode /* ignored */,
506
				file->f_flags, &oplock, &fid.netfid, xid);
507
		if (rc == 0) {
508
			cifs_dbg(FYI, "posix open succeeded\n");
509
			posix_open_ok = true;
510 511
		} else if ((rc == -EINVAL) || (rc == -EOPNOTSUPP)) {
			if (tcon->ses->serverNOS)
512 513 514
				cifs_dbg(VFS, "server %s of type %s returned unexpected error on SMB posix open, disabling posix open support. Check if server update available.\n",
					 tcon->ses->serverName,
					 tcon->ses->serverNOS);
515
			tcon->broken_posix_open = true;
516 517 518
		} else if ((rc != -EIO) && (rc != -EREMOTE) &&
			 (rc != -EOPNOTSUPP)) /* path not found or net err */
			goto out;
519 520 521 522
		/*
		 * Else fallthrough to retry open the old way on network i/o
		 * or DFS errors.
		 */
523 524
	}

525 526 527 528 529
	if (server->ops->get_lease_key)
		server->ops->get_lease_key(inode, &fid);

	cifs_add_pending_open(&fid, tlink, &open);

530
	if (!posix_open_ok) {
531 532 533
		if (server->ops->get_lease_key)
			server->ops->get_lease_key(inode, &fid);

534
		rc = cifs_nt_open(full_path, inode, cifs_sb, tcon,
535
				  file->f_flags, &oplock, &fid, xid);
536 537
		if (rc) {
			cifs_del_pending_open(&open);
538
			goto out;
539
		}
540
	}
541

542 543
	cfile = cifs_new_fileinfo(&fid, file, tlink, oplock);
	if (cfile == NULL) {
544 545
		if (server->ops->close)
			server->ops->close(xid, tcon, &fid);
546
		cifs_del_pending_open(&open);
Linus Torvalds's avatar
Linus Torvalds committed
547 548 549 550
		rc = -ENOMEM;
		goto out;
	}

551 552
	cifs_fscache_set_inode_cookie(inode, file);

553
	if ((oplock & CIFS_CREATE_ACTION) && !posix_open_ok && tcon->unix_ext) {
554 555 556 557
		/*
		 * Time to set mode which we can not set earlier due to
		 * problems creating new read-only files.
		 */
558 559
		struct cifs_unix_set_info_args args = {
			.mode	= inode->i_mode,
560 561
			.uid	= INVALID_UID, /* no change */
			.gid	= INVALID_GID, /* no change */
562 563 564 565 566
			.ctime	= NO_CHANGE_64,
			.atime	= NO_CHANGE_64,
			.mtime	= NO_CHANGE_64,
			.device	= 0,
		};
567 568
		CIFSSMBUnixSetFileInfo(xid, tcon, &args, fid.netfid,
				       cfile->pid);
Linus Torvalds's avatar
Linus Torvalds committed
569 570 571 572
	}

out:
	kfree(full_path);
573
	free_xid(xid);
574
	cifs_put_tlink(tlink);
Linus Torvalds's avatar
Linus Torvalds committed
575 576 577
	return rc;
}

578 579
static int cifs_push_posix_locks(struct cifsFileInfo *cfile);

580 581
/*
 * Try to reacquire byte range locks that were released when session
582
 * to server was lost.
583
 */
584 585
static int
cifs_relock_file(struct cifsFileInfo *cfile)
Linus Torvalds's avatar
Linus Torvalds committed
586
{
587
	struct cifs_sb_info *cifs_sb = CIFS_SB(cfile->dentry->d_sb);
588
	struct cifsInodeInfo *cinode = CIFS_I(d_inode(cfile->dentry));
589
	struct cifs_tcon *tcon = tlink_tcon(cfile->tlink);
Linus Torvalds's avatar
Linus Torvalds committed
590 591
	int rc = 0;

592
	down_read_nested(&cinode->lock_sem, SINGLE_DEPTH_NESTING);
593
	if (cinode->can_cache_brlcks) {
594 595
		/* can cache locks - no need to relock */
		up_read(&cinode->lock_sem);
596 597 598 599 600 601 602 603 604
		return rc;
	}

	if (cap_unix(tcon->ses) &&
	    (CIFS_UNIX_FCNTL_CAP & le64_to_cpu(tcon->fsUnixInfo.Capability)) &&
	    ((cifs_sb->mnt_cifs_flags & CIFS_MOUNT_NOPOSIXBRL) == 0))
		rc = cifs_push_posix_locks(cfile);
	else
		rc = tcon->ses->server->ops->push_mand_locks(cfile);
Linus Torvalds's avatar
Linus Torvalds committed
605

606
	up_read(&cinode->lock_sem);
Linus Torvalds's avatar
Linus Torvalds committed
607 608 609
	return rc;
}

610 611
static int
cifs_reopen_file(struct cifsFileInfo *cfile, bool can_flush)
Linus Torvalds's avatar
Linus Torvalds committed
612 613
{
	int rc = -EACCES;
614
	unsigned int xid;
615
	__u32 oplock;
Linus Torvalds's avatar
Linus Torvalds committed
616
	struct cifs_sb_info *cifs_sb;
617
	struct cifs_tcon *tcon;
618 619
	struct TCP_Server_Info *server;
	struct cifsInodeInfo *cinode;
Steve French's avatar
Steve French committed
620
	struct inode *inode;
Linus Torvalds's avatar
Linus Torvalds committed
621
	char *full_path = NULL;
622
	int desired_access;
Linus Torvalds's avatar
Linus Torvalds committed
623
	int disposition = FILE_OPEN;
624
	int create_options = CREATE_NOT_DIR;
625
	struct cifs_open_parms oparms;
Linus Torvalds's avatar
Linus Torvalds committed
626

627
	xid = get_xid();
628 629 630
	mutex_lock(&cfile->fh_mutex);
	if (!cfile->invalidHandle) {
		mutex_unlock(&cfile->fh_mutex);
631
		rc = 0;
632
		free_xid(xid);
633
		return rc;
Linus Torvalds's avatar
Linus Torvalds committed
634 635
	}

636
	inode = d_inode(cfile->dentry);
Linus Torvalds's avatar
Linus Torvalds committed
637
	cifs_sb = CIFS_SB(inode->i_sb);
638 639 640 641 642 643 644 645 646 647
	tcon = tlink_tcon(cfile->tlink);
	server = tcon->ses->server;

	/*
	 * Can not grab rename sem here because various ops, including those
	 * that already have the rename sem can end up causing writepage to get
	 * called and if the server was down that means we end up here, and we
	 * can never tell if the caller already has the rename_sem.
	 */
	full_path = build_path_from_dentry(cfile->dentry);
Linus Torvalds's avatar
Linus Torvalds committed
648
	if (full_path == NULL) {
649
		rc = -ENOMEM;
650
		mutex_unlock(&cfile->fh_mutex);
651
		free_xid(xid);
652
		return rc;
Linus Torvalds's avatar
Linus Torvalds committed
653 654
	}

655 656
	cifs_dbg(FYI, "inode = 0x%p file flags 0x%x for %s\n",
		 inode, cfile->f_flags, full_path);
Linus Torvalds's avatar
Linus Torvalds committed
657

658
	if (tcon->ses->server->oplocks)
Linus Torvalds's avatar
Linus Torvalds committed
659 660
		oplock = REQ_OPLOCK;
	else
661
		oplock = 0;
Linus Torvalds's avatar
Linus Torvalds committed
662

663
	if (tcon->unix_ext && cap_unix(tcon->ses) &&
664
	    (CIFS_UNIX_POSIX_PATH_OPS_CAP &
665
				le64_to_cpu(tcon->fsUnixInfo.Capability))) {
666 667 668 669
		/*
		 * O_CREAT, O_EXCL and O_TRUNC already had their effect on the
		 * original open. Must mask them off for a reopen.
		 */
670
		unsigned int oflags = cfile->f_flags &
671
						~(O_CREAT | O_EXCL | O_TRUNC);
672

673
		rc = cifs_posix_open(full_path, NULL, inode->i_sb,
674
				     cifs_sb->mnt_file_mode /* ignored */,
675
				     oflags, &oplock, &cfile->fid.netfid, xid);
676
		if (rc == 0) {
677
			cifs_dbg(FYI, "posix reopen succeeded\n");
678
			oparms.reconnect = true;
679 680
			goto reopen_success;
		}
681 682 683 684
		/*
		 * fallthrough to retry open the old way on errors, especially
		 * in the reconnect path it is important to retry hard
		 */
685 686
	}

687
	desired_access = cifs_convert_flags(cfile->f_flags);
688

689 690 691
	if (backup_cred(cifs_sb))
		create_options |= CREATE_OPEN_BACKUP_INTENT;

692
	if (server->ops->get_lease_key)
693
		server->ops->get_lease_key(inode, &cfile->fid);
694

695 696 697 698 699 700
	oparms.tcon = tcon;
	oparms.cifs_sb = cifs_sb;
	oparms.desired_access = desired_access;
	oparms.create_options = create_options;
	oparms.disposition = disposition;
	oparms.path = full_path;
701 702
	oparms.fid = &cfile->fid;
	oparms.reconnect = true;
703

704 705
	/*
	 * Can not refresh inode by passing in file_info buf to be returned by
706
	 * ops->open and then calling get_inode_info with returned buf since
707 708 709 710
	 * file might have write behind data that needs to be flushed and server
	 * version of file size can be stale. If we knew for sure that inode was
	 * not dirty locally we could do this.
	 */
711
	rc = server->ops->open(xid, &oparms, &oplock, NULL);
712 713 714 715 716 717 718
	if (rc == -ENOENT && oparms.reconnect == false) {
		/* durable handle timeout is expired - open the file again */
		rc = server->ops->open(xid, &oparms, &oplock, NULL);
		/* indicate that we need to relock the file */
		oparms.reconnect = true;
	}

Linus Torvalds's avatar
Linus Torvalds committed
719
	if (rc) {
720
		mutex_unlock(&cfile->fh_mutex);
721 722
		cifs_dbg(FYI, "cifs_reopen returned 0x%x\n", rc);
		cifs_dbg(FYI, "oplock: %d\n", oplock);
723 724 725
		goto reopen_error_exit;
	}

726
reopen_success:
727 728 729
	cfile->invalidHandle = false;
	mutex_unlock(&cfile->fh_mutex);
	cinode = CIFS_I(inode);
730 731 732

	if (can_flush) {
		rc = filemap_write_and_wait(inode->i_mapping);
733
		mapping_set_error(inode->i_mapping, rc);
734 735

		if (tcon->unix_ext)
736 737
			rc = cifs_get_inode_info_unix(&inode, full_path,
						      inode->i_sb, xid);
738
		else
739 740 741 742 743 744 745 746 747 748
			rc = cifs_get_inode_info(&inode, full_path, NULL,
						 inode->i_sb, xid, NULL);
	}
	/*
	 * Else we are writing out data to server already and could deadlock if
	 * we tried to flush data, and since we do not know if we have data that
	 * would invalidate the current end of file on the server we can not go
	 * to the server to get the new inode info.
	 */

749 750 751 752 753 754 755 756 757
	/*
	 * If the server returned a read oplock and we have mandatory brlocks,
	 * set oplock level to None.
	 */
	if (server->ops->is_read_op(oplock) && cifs_has_mand_locks(cinode)) {
		cifs_dbg(FYI, "Reset oplock val from read to None due to mand locks\n");
		oplock = 0;
	}

758 759 760
	server->ops->set_fid(cfile, &cfile->fid, oplock);
	if (oparms.reconnect)
		cifs_relock_file(cfile);
761 762

reopen_error_exit:
Linus Torvalds's avatar
Linus Torvalds committed
763
	kfree(full_path);
764
	free_xid(xid);
Linus Torvalds's avatar
Linus Torvalds committed
765 766 767 768 769
	return rc;
}

int cifs_close(struct inode *inode, struct file *file)
{
770 771 772 773
	if (file->private_data != NULL) {
		cifsFileInfo_put(file->private_data);
		file->private_data = NULL;
	}
Jeremy Allison's avatar
Jeremy Allison committed
774

775 776
	/* return code from the ->release op is always ignored */
	return 0;
Linus Torvalds's avatar
Linus Torvalds committed
777 778
}

779 780 781
void
cifs_reopen_persistent_handles(struct cifs_tcon *tcon)
{
782
	struct cifsFileInfo *open_file;
783 784
	struct list_head *tmp;
	struct list_head *tmp1;
785 786
	struct list_head tmp_list;

787 788 789 790 791
	if (!tcon->use_persistent || !tcon->need_reopen_files)
		return;

	tcon->need_reopen_files = false;

792 793
	cifs_dbg(FYI, "Reopen persistent handles");
	INIT_LIST_HEAD(&tmp_list);
794 795 796

	/* list all files open on tree connection, reopen resilient handles  */
	spin_lock(&tcon->open_file_lock);
797
	list_for_each(tmp, &tcon->openFileList) {
798
		open_file = list_entry(tmp, struct cifsFileInfo, tlist);
799 800 801 802
		if (!open_file->invalidHandle)
			continue;
		cifsFileInfo_get(open_file);
		list_add_tail(&open_file->rlist, &tmp_list);
803 804
	}
	spin_unlock(&tcon->open_file_lock);
805 806 807

	list_for_each_safe(tmp, tmp1, &tmp_list) {
		open_file = list_entry(tmp, struct cifsFileInfo, rlist);
808 809
		if (cifs_reopen_file(open_file, false /* do not flush */))
			tcon->need_reopen_files = true;
810 811 812
		list_del_init(&open_file->rlist);
		cifsFileInfo_put(open_file);
	}
813 814
}

Linus Torvalds's avatar
Linus Torvalds committed
815 816 817
int cifs_closedir(struct inode *inode, struct file *file)
{
	int rc = 0;
818
	unsigned int xid;
819
	struct cifsFileInfo *cfile = file->private_data;
820 821 822
	struct cifs_tcon *tcon;
	struct TCP_Server_Info *server;
	char *buf;
Linus Torvalds's avatar
Linus Torvalds committed
823

824
	cifs_dbg(FYI, "Closedir inode = 0x%p\n", inode);
Linus Torvalds's avatar
Linus Torvalds committed
825

826 827 828
	if (cfile == NULL)
		return rc;

829
	xid = get_xid();
830 831
	tcon = tlink_tcon(cfile->tlink);
	server = tcon->ses->server;
Linus Torvalds's avatar
Linus Torvalds committed
832

833
	cifs_dbg(FYI, "Freeing private data in close dir\n");
834
	spin_lock(&cfile->file_info_lock);
835
	if (server->ops->dir_needs_close(cfile)) {
836
		cfile->invalidHandle = true;
837
		spin_unlock(&cfile->file_info_lock);
838 839 840 841
		if (server->ops->close_dir)
			rc = server->ops->close_dir(xid, tcon, &cfile->fid);
		else
			rc = -ENOSYS;
842
		cifs_dbg(FYI, "Closing uncompleted readdir with rc %d\n", rc);
843 844 845
		/* not much we can do if it fails anyway, ignore rc */
		rc = 0;
	} else
846
		spin_unlock(&cfile->file_info_lock);
847 848 849

	buf = cfile->srch_inf.ntwrk_buf_start;
	if (buf) {
850
		cifs_dbg(FYI, "closedir free smb buf in srch struct\n");
851 852 853 854 855
		cfile->srch_inf.ntwrk_buf_start = NULL;
		if (cfile->srch_inf.smallBuf)
			cifs_small_buf_release(buf);
		else
			cifs_buf_release(buf);
Linus Torvalds's avatar
Linus Torvalds committed
856
	}
857 858 859 860

	cifs_put_tlink(cfile->tlink);
	kfree(file->private_data);
	file->private_data = NULL;
Linus Torvalds's avatar
Linus Torvalds committed
861
	/* BB can we lock the filestruct while this is going on? */
862
	free_xid(xid);
Linus Torvalds's avatar
Linus Torvalds committed
863 864 865
	return rc;
}

866
static struct cifsLockInfo *
867
cifs_lock_init(__u64 offset, __u64 length, __u8 type)
Jeremy Allison's avatar
Jeremy Allison committed
868
{
869
	struct cifsLockInfo *lock =
Steve French's avatar
Steve French committed
870
		kmalloc(sizeof(struct cifsLockInfo), GFP_KERNEL);
871 872 873 874 875 876 877 878 879
	if (!lock)
		return lock;
	lock->offset = offset;
	lock->length = length;
	lock->type = type;
	lock->pid = current->tgid;
	INIT_LIST_HEAD(&lock->blist);
	init_waitqueue_head(&lock->block_q);
	return lock;
880 881
}

882
void
883 884 885 886 887 888 889 890 891
cifs_del_lock_waiters(struct cifsLockInfo *lock)
{
	struct cifsLockInfo *li, *tmp;
	list_for_each_entry_safe(li, tmp, &lock->blist, blist) {
		list_del_init(&li->blist);
		wake_up(&li->block_q);
	}
}

892 893 894 895 896
#define CIFS_LOCK_OP	0
#define CIFS_READ_OP	1
#define CIFS_WRITE_OP	2

/* @rw_check : 0 - no op, 1 - read, 2 - write */
897
static bool
898 899
cifs_find_fid_lock_conflict(struct cifs_fid_locks *fdlocks, __u64 offset,
			    __u64 length, __u8 type, struct cifsFileInfo *cfile,
900
			    struct cifsLockInfo **conf_lock, int rw_check)
901
{
902
	struct cifsLockInfo *li;
903
	struct cifsFileInfo *cur_cfile = fdlocks->cfile;
904
	struct TCP_Server_Info *server = tlink_tcon(cfile->tlink)->ses->server;
905

906
	list_for_each_entry(li, &fdlocks->locks, llist) {
907 908 909
		if (offset + length <= li->offset ||
		    offset >= li->offset + li->length)
			continue;
910 911 912 913 914 915 916
		if (rw_check != CIFS_LOCK_OP && current->tgid == li->pid &&
		    server->ops->compare_fids(cfile, cur_cfile)) {
			/* shared lock prevents write op through the same fid */
			if (!(li->type & server->vals->shared_lock_type) ||
			    rw_check != CIFS_WRITE_OP)
				continue;
		}
917 918 919
		if ((type & server->vals->shared_lock_type) &&
		    ((server->ops->compare_fids(cfile, cur_cfile) &&
		     current->tgid == li->pid) || type == li->type))
920
			continue;
921 922
		if (conf_lock)
			*conf_lock = li;
923
		return true;
924 925 926 927
	}
	return false;
}

928
bool
929
cifs_find_lock_conflict(struct cifsFileInfo *cfile, __u64 offset, __u64 length,
930
			__u8 type, struct cifsLockInfo **conf_lock,
931
			int rw_check)
932
{
933
	bool rc = false;
934
	struct cifs_fid_locks *cur;
935
	struct cifsInodeInfo *cinode = CIFS_I(d_inode(cfile->dentry));
936

937 938
	list_for_each_entry(cur, &cinode->llist, llist) {
		rc = cifs_find_fid_lock_conflict(cur, offset, length, type,
939
						 cfile, conf_lock, rw_check);
940 941 942 943 944
		if (rc)
			break;
	}

	return rc;
945 946
}

947 948 949 950 951 952 953
/*
 * Check if there is another lock that prevents us to set the lock (mandatory
 * style). If such a lock exists, update the flock structure with its
 * properties. Otherwise, set the flock type to F_UNLCK if we can cache brlocks
 * or leave it the same if we can't. Returns 0 if we don't need to request to
 * the server or 1 otherwise.
 */
954
static int
955 956
cifs_lock_test(struct cifsFileInfo *cfile, __u64 offset, __u64 length,
	       __u8 type, struct file_lock *flock)
957 958 959
{
	int rc = 0;
	struct cifsLockInfo *conf_lock;
960
	struct cifsInodeInfo *cinode = CIFS_I(d_inode(cfile->dentry));
961
	struct TCP_Server_Info *server = tlink_tcon(cfile->tlink)->ses->server;
962 963
	bool exist;

964
	down_read(&cinode->lock_sem);
965

966
	exist = cifs_find_lock_conflict(cfile, offset, length, type,
967
					&conf_lock, CIFS_LOCK_OP);
968 969 970 971
	if (exist) {
		flock->fl_start = conf_lock->offset;
		flock->fl_end = conf_lock->offset + conf_lock->length - 1;
		flock->fl_pid = conf_lock->pid;
972
		if (conf_lock->type & server->vals->shared_lock_type)
973 974 975 976 977 978 979 980
			flock->fl_type = F_RDLCK;
		else
			flock->fl_type