file.c 101 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 (sfrench@us.ibm.com)
Jeremy Allison's avatar
[CIFS]    
Jeremy Allison committed
8
 *              Jeremy Allison (jra@samba.org)
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"
Linus Torvalds's avatar
Linus Torvalds committed
45

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
143
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
174

	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,
			     cifs_sb->mnt_cifs_flags &
					CIFS_MOUNT_MAP_SPECIAL_CHR);
	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;
}

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

Pavel Shilovsky's avatar
Pavel Shilovsky committed
188
	if (!server->ops->open)
189
190
191
		return -ENOSYS;

	desired_access = cifs_convert_flags(f_flags);
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
224

/*********************************************************************
 *  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;

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

228
229
230
231
232
233
234
	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;
235
	oparms.reconnect = false;
236
237

	rc = server->ops->open(xid, &oparms, oplock, buf);
238
239
240
241
242
243
244
245
246

	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,
247
					 xid, fid);
248
249
250
251
252
253

out:
	kfree(buf);
	return rc;
}

254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
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;
}

271
struct cifsFileInfo *
272
cifs_new_fileinfo(struct cifs_fid *fid, struct file *file,
273
274
275
276
		  struct tcon_link *tlink, __u32 oplock)
{
	struct dentry *dentry = file->f_path.dentry;
	struct inode *inode = dentry->d_inode;
277
278
	struct cifsInodeInfo *cinode = CIFS_I(inode);
	struct cifsFileInfo *cfile;
279
	struct cifs_fid_locks *fdlocks;
280
	struct cifs_tcon *tcon = tlink_tcon(tlink);
281
	struct TCP_Server_Info *server = tcon->ses->server;
282
283
284
285
286

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

287
288
289
290
291
292
293
294
295
	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;
296
	down_write(&cinode->lock_sem);
297
	list_add(&fdlocks->llist, &cinode->llist);
298
	up_write(&cinode->lock_sem);
299

300
301
302
303
304
305
306
307
	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);
308
	mutex_init(&cfile->fh_mutex);
309

310
311
	cifs_sb_active(inode->i_sb);

312
313
314
315
	/*
	 * If the server returned a read oplock and we have mandatory brlocks,
	 * set oplock level to None.
	 */
316
	if (server->ops->is_read_op(oplock) && cifs_has_mand_locks(cinode)) {
317
		cifs_dbg(FYI, "Reset oplock val from read to None due to mand locks\n");
318
319
320
		oplock = 0;
	}

321
	spin_lock(&cifs_file_list_lock);
322
	if (fid->pending_open->oplock != CIFS_OPLOCK_NO_CHANGE && oplock)
323
324
325
		oplock = fid->pending_open->oplock;
	list_del(&fid->pending_open->olist);

326
	fid->purge_cache = false;
327
	server->ops->set_fid(cfile, fid, oplock);
328
329

	list_add(&cfile->tlist, &tcon->openFileList);
330
331
	/* if readable file instance put first in list*/
	if (file->f_mode & FMODE_READ)
332
		list_add(&cfile->flist, &cinode->openFileList);
333
	else
334
		list_add_tail(&cfile->flist, &cinode->openFileList);
335
	spin_unlock(&cifs_file_list_lock);
336

337
	if (fid->purge_cache)
338
		cifs_zap_mapping(inode);
339

340
341
	file->private_data = cfile;
	return cfile;
342
343
}

344
345
346
347
348
349
350
351
352
struct cifsFileInfo *
cifsFileInfo_get(struct cifsFileInfo *cifs_file)
{
	spin_lock(&cifs_file_list_lock);
	cifsFileInfo_get_locked(cifs_file);
	spin_unlock(&cifs_file_list_lock);
	return cifs_file;
}

353
354
/*
 * Release a reference on the file private data. This may involve closing
355
356
 * the filehandle out on the server. Must be called without holding
 * cifs_file_list_lock.
357
 */
358
359
void cifsFileInfo_put(struct cifsFileInfo *cifs_file)
{
360
	struct inode *inode = cifs_file->dentry->d_inode;
361
	struct cifs_tcon *tcon = tlink_tcon(cifs_file->tlink);
362
	struct TCP_Server_Info *server = tcon->ses->server;
363
	struct cifsInodeInfo *cifsi = CIFS_I(inode);
364
365
	struct super_block *sb = inode->i_sb;
	struct cifs_sb_info *cifs_sb = CIFS_SB(sb);
366
	struct cifsLockInfo *li, *tmp;
367
368
	struct cifs_fid fid;
	struct cifs_pending_open open;
369
	bool oplock_break_cancelled;
370
371

	spin_lock(&cifs_file_list_lock);
372
	if (--cifs_file->count > 0) {
373
374
375
376
		spin_unlock(&cifs_file_list_lock);
		return;
	}

377
378
379
380
381
382
	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);

383
384
385
386
387
	/* remove it from the lists */
	list_del(&cifs_file->flist);
	list_del(&cifs_file->tlist);

	if (list_empty(&cifsi->openFileList)) {
388
389
		cifs_dbg(FYI, "closing last open instance for inode %p\n",
			 cifs_file->dentry->d_inode);
390
391
392
393
394
		/*
		 * 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.
		 */
395
		if (cifs_sb->mnt_cifs_flags & CIFS_MOUNT_STRICT_IO)
396
			set_bit(CIFS_INO_INVALID_MAPPING, &cifsi->flags);
397
		cifs_set_oplock_level(cifsi, 0);
398
399
400
	}
	spin_unlock(&cifs_file_list_lock);

401
	oplock_break_cancelled = cancel_work_sync(&cifs_file->oplock_break);
402

403
	if (!tcon->need_reconnect && !cifs_file->invalidHandle) {
404
		struct TCP_Server_Info *server = tcon->ses->server;
405
		unsigned int xid;
406

407
		xid = get_xid();
408
		if (server->ops->close)
409
410
			server->ops->close(xid, tcon, &cifs_file->fid);
		_free_xid(xid);
411
412
	}

413
414
415
	if (oplock_break_cancelled)
		cifs_done_oplock_break(cifsi);

416
417
	cifs_del_pending_open(&open);

418
419
	/*
	 * Delete any outstanding lock records. We'll lose them when the file
420
421
	 * is closed anyway.
	 */
422
	down_write(&cifsi->lock_sem);
423
	list_for_each_entry_safe(li, tmp, &cifs_file->llist->locks, llist) {
424
		list_del(&li->llist);
425
		cifs_del_lock_waiters(li);
426
		kfree(li);
427
	}
428
429
	list_del(&cifs_file->llist->llist);
	kfree(cifs_file->llist);
430
	up_write(&cifsi->lock_sem);
431
432
433

	cifs_put_tlink(cifs_file->tlink);
	dput(cifs_file->dentry);
434
	cifs_sb_deactive(sb);
435
	kfree(cifs_file);
436
437
}

Linus Torvalds's avatar
Linus Torvalds committed
438
int cifs_open(struct inode *inode, struct file *file)
439

Linus Torvalds's avatar
Linus Torvalds committed
440
441
{
	int rc = -EACCES;
442
	unsigned int xid;
443
	__u32 oplock;
Linus Torvalds's avatar
Linus Torvalds committed
444
	struct cifs_sb_info *cifs_sb;
Pavel Shilovsky's avatar
Pavel Shilovsky committed
445
	struct TCP_Server_Info *server;
446
	struct cifs_tcon *tcon;
447
	struct tcon_link *tlink;
448
	struct cifsFileInfo *cfile = NULL;
Linus Torvalds's avatar
Linus Torvalds committed
449
	char *full_path = NULL;
450
	bool posix_open_ok = false;
451
	struct cifs_fid fid;
452
	struct cifs_pending_open open;
Linus Torvalds's avatar
Linus Torvalds committed
453

454
	xid = get_xid();
Linus Torvalds's avatar
Linus Torvalds committed
455
456

	cifs_sb = CIFS_SB(inode->i_sb);
457
458
	tlink = cifs_sb_tlink(cifs_sb);
	if (IS_ERR(tlink)) {
459
		free_xid(xid);
460
461
462
		return PTR_ERR(tlink);
	}
	tcon = tlink_tcon(tlink);
Pavel Shilovsky's avatar
Pavel Shilovsky committed
463
	server = tcon->ses->server;
Linus Torvalds's avatar
Linus Torvalds committed
464

465
	full_path = build_path_from_dentry(file->f_path.dentry);
Linus Torvalds's avatar
Linus Torvalds committed
466
	if (full_path == NULL) {
467
		rc = -ENOMEM;
468
		goto out;
Linus Torvalds's avatar
Linus Torvalds committed
469
470
	}

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

474
475
476
477
478
479
480
481
	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;
	}

482
	if (server->oplocks)
483
484
485
486
		oplock = REQ_OPLOCK;
	else
		oplock = 0;

487
	if (!tcon->broken_posix_open && tcon->unix_ext &&
488
489
	    cap_unix(tcon->ses) && (CIFS_UNIX_POSIX_PATH_OPS_CAP &
				le64_to_cpu(tcon->fsUnixInfo.Capability))) {
490
		/* can not refresh inode info since size could be stale */
491
		rc = cifs_posix_open(full_path, &inode, inode->i_sb,
492
				cifs_sb->mnt_file_mode /* ignored */,
493
				file->f_flags, &oplock, &fid.netfid, xid);
494
		if (rc == 0) {
495
			cifs_dbg(FYI, "posix open succeeded\n");
496
			posix_open_ok = true;
497
498
		} else if ((rc == -EINVAL) || (rc == -EOPNOTSUPP)) {
			if (tcon->ses->serverNOS)
499
500
501
				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);
502
			tcon->broken_posix_open = true;
503
504
505
		} else if ((rc != -EIO) && (rc != -EREMOTE) &&
			 (rc != -EOPNOTSUPP)) /* path not found or net err */
			goto out;
506
507
508
509
		/*
		 * Else fallthrough to retry open the old way on network i/o
		 * or DFS errors.
		 */
510
511
	}

512
513
514
515
516
	if (server->ops->get_lease_key)
		server->ops->get_lease_key(inode, &fid);

	cifs_add_pending_open(&fid, tlink, &open);

517
	if (!posix_open_ok) {
Pavel Shilovsky's avatar
Pavel Shilovsky committed
518
519
520
		if (server->ops->get_lease_key)
			server->ops->get_lease_key(inode, &fid);

521
		rc = cifs_nt_open(full_path, inode, cifs_sb, tcon,
522
				  file->f_flags, &oplock, &fid, xid);
523
524
		if (rc) {
			cifs_del_pending_open(&open);
525
			goto out;
526
		}
527
	}
528

529
530
	cfile = cifs_new_fileinfo(&fid, file, tlink, oplock);
	if (cfile == NULL) {
Pavel Shilovsky's avatar
Pavel Shilovsky committed
531
532
		if (server->ops->close)
			server->ops->close(xid, tcon, &fid);
533
		cifs_del_pending_open(&open);
Linus Torvalds's avatar
Linus Torvalds committed
534
535
536
537
		rc = -ENOMEM;
		goto out;
	}

538
539
	cifs_fscache_set_inode_cookie(inode, file);

540
	if ((oplock & CIFS_CREATE_ACTION) && !posix_open_ok && tcon->unix_ext) {
541
542
543
544
		/*
		 * Time to set mode which we can not set earlier due to
		 * problems creating new read-only files.
		 */
545
546
		struct cifs_unix_set_info_args args = {
			.mode	= inode->i_mode,
547
548
			.uid	= INVALID_UID, /* no change */
			.gid	= INVALID_GID, /* no change */
549
550
551
552
553
			.ctime	= NO_CHANGE_64,
			.atime	= NO_CHANGE_64,
			.mtime	= NO_CHANGE_64,
			.device	= 0,
		};
554
555
		CIFSSMBUnixSetFileInfo(xid, tcon, &args, fid.netfid,
				       cfile->pid);
Linus Torvalds's avatar
Linus Torvalds committed
556
557
558
559
	}

out:
	kfree(full_path);
560
	free_xid(xid);
561
	cifs_put_tlink(tlink);
Linus Torvalds's avatar
Linus Torvalds committed
562
563
564
	return rc;
}

565
566
static int cifs_push_posix_locks(struct cifsFileInfo *cfile);

567
568
/*
 * Try to reacquire byte range locks that were released when session
569
 * to server was lost.
570
 */
571
572
static int
cifs_relock_file(struct cifsFileInfo *cfile)
Linus Torvalds's avatar
Linus Torvalds committed
573
{
574
575
576
	struct cifs_sb_info *cifs_sb = CIFS_SB(cfile->dentry->d_sb);
	struct cifsInodeInfo *cinode = CIFS_I(cfile->dentry->d_inode);
	struct cifs_tcon *tcon = tlink_tcon(cfile->tlink);
Linus Torvalds's avatar
Linus Torvalds committed
577
578
	int rc = 0;

579
	down_read(&cinode->lock_sem);
580
	if (cinode->can_cache_brlcks) {
581
582
		/* can cache locks - no need to relock */
		up_read(&cinode->lock_sem);
583
584
585
586
587
588
589
590
591
		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
592

593
	up_read(&cinode->lock_sem);
Linus Torvalds's avatar
Linus Torvalds committed
594
595
596
	return rc;
}

597
598
static int
cifs_reopen_file(struct cifsFileInfo *cfile, bool can_flush)
Linus Torvalds's avatar
Linus Torvalds committed
599
600
{
	int rc = -EACCES;
601
	unsigned int xid;
602
	__u32 oplock;
Linus Torvalds's avatar
Linus Torvalds committed
603
	struct cifs_sb_info *cifs_sb;
604
	struct cifs_tcon *tcon;
605
606
	struct TCP_Server_Info *server;
	struct cifsInodeInfo *cinode;
Steve French's avatar
Steve French committed
607
	struct inode *inode;
Linus Torvalds's avatar
Linus Torvalds committed
608
	char *full_path = NULL;
609
	int desired_access;
Linus Torvalds's avatar
Linus Torvalds committed
610
	int disposition = FILE_OPEN;
611
	int create_options = CREATE_NOT_DIR;
612
	struct cifs_open_parms oparms;
Linus Torvalds's avatar
Linus Torvalds committed
613

614
	xid = get_xid();
615
616
617
	mutex_lock(&cfile->fh_mutex);
	if (!cfile->invalidHandle) {
		mutex_unlock(&cfile->fh_mutex);
618
		rc = 0;
619
		free_xid(xid);
620
		return rc;
Linus Torvalds's avatar
Linus Torvalds committed
621
622
	}

623
	inode = cfile->dentry->d_inode;
Linus Torvalds's avatar
Linus Torvalds committed
624
	cifs_sb = CIFS_SB(inode->i_sb);
625
626
627
628
629
630
631
632
633
634
	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
635
	if (full_path == NULL) {
636
		rc = -ENOMEM;
637
		mutex_unlock(&cfile->fh_mutex);
638
		free_xid(xid);
639
		return rc;
Linus Torvalds's avatar
Linus Torvalds committed
640
641
	}

642
643
	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
644

645
	if (tcon->ses->server->oplocks)
Linus Torvalds's avatar
Linus Torvalds committed
646
647
		oplock = REQ_OPLOCK;
	else
648
		oplock = 0;
Linus Torvalds's avatar
Linus Torvalds committed
649

650
	if (tcon->unix_ext && cap_unix(tcon->ses) &&
651
	    (CIFS_UNIX_POSIX_PATH_OPS_CAP &
652
				le64_to_cpu(tcon->fsUnixInfo.Capability))) {
653
654
655
656
		/*
		 * O_CREAT, O_EXCL and O_TRUNC already had their effect on the
		 * original open. Must mask them off for a reopen.
		 */
657
		unsigned int oflags = cfile->f_flags &
Jeff Layton's avatar
Jeff Layton committed
658
						~(O_CREAT | O_EXCL | O_TRUNC);
659

660
		rc = cifs_posix_open(full_path, NULL, inode->i_sb,
661
				     cifs_sb->mnt_file_mode /* ignored */,
662
				     oflags, &oplock, &cfile->fid.netfid, xid);
663
		if (rc == 0) {
664
			cifs_dbg(FYI, "posix reopen succeeded\n");
665
			oparms.reconnect = true;
666
667
			goto reopen_success;
		}
668
669
670
671
		/*
		 * fallthrough to retry open the old way on errors, especially
		 * in the reconnect path it is important to retry hard
		 */
672
673
	}

674
	desired_access = cifs_convert_flags(cfile->f_flags);
675

676
677
678
	if (backup_cred(cifs_sb))
		create_options |= CREATE_OPEN_BACKUP_INTENT;

Pavel Shilovsky's avatar
Pavel Shilovsky committed
679
	if (server->ops->get_lease_key)
680
		server->ops->get_lease_key(inode, &cfile->fid);
Pavel Shilovsky's avatar
Pavel Shilovsky committed
681

682
683
684
685
686
687
	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;
688
689
	oparms.fid = &cfile->fid;
	oparms.reconnect = true;
690

691
692
	/*
	 * Can not refresh inode by passing in file_info buf to be returned by
693
	 * ops->open and then calling get_inode_info with returned buf since
694
695
696
697
	 * 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.
	 */
698
	rc = server->ops->open(xid, &oparms, &oplock, NULL);
699
700
701
702
703
704
705
	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
706
	if (rc) {
707
		mutex_unlock(&cfile->fh_mutex);
708
709
		cifs_dbg(FYI, "cifs_reopen returned 0x%x\n", rc);
		cifs_dbg(FYI, "oplock: %d\n", oplock);
Jeff Layton's avatar
Jeff Layton committed
710
711
712
		goto reopen_error_exit;
	}

713
reopen_success:
714
715
716
	cfile->invalidHandle = false;
	mutex_unlock(&cfile->fh_mutex);
	cinode = CIFS_I(inode);
Jeff Layton's avatar
Jeff Layton committed
717
718
719

	if (can_flush) {
		rc = filemap_write_and_wait(inode->i_mapping);
720
		mapping_set_error(inode->i_mapping, rc);
Jeff Layton's avatar
Jeff Layton committed
721
722

		if (tcon->unix_ext)
723
724
			rc = cifs_get_inode_info_unix(&inode, full_path,
						      inode->i_sb, xid);
Jeff Layton's avatar
Jeff Layton committed
725
		else
726
727
728
729
730
731
732
733
734
735
			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.
	 */

736
737
738
	server->ops->set_fid(cfile, &cfile->fid, oplock);
	if (oparms.reconnect)
		cifs_relock_file(cfile);
Jeff Layton's avatar
Jeff Layton committed
739
740

reopen_error_exit:
Linus Torvalds's avatar
Linus Torvalds committed
741
	kfree(full_path);
742
	free_xid(xid);
Linus Torvalds's avatar
Linus Torvalds committed
743
744
745
746
747
	return rc;
}

int cifs_close(struct inode *inode, struct file *file)
{
748
749
750
751
	if (file->private_data != NULL) {
		cifsFileInfo_put(file->private_data);
		file->private_data = NULL;
	}
Jeremy Allison's avatar
[CIFS]    
Jeremy Allison committed
752

753
754
	/* return code from the ->release op is always ignored */
	return 0;
Linus Torvalds's avatar
Linus Torvalds committed
755
756
757
758
759
}

int cifs_closedir(struct inode *inode, struct file *file)
{
	int rc = 0;
760
	unsigned int xid;
761
	struct cifsFileInfo *cfile = file->private_data;
762
763
764
	struct cifs_tcon *tcon;
	struct TCP_Server_Info *server;
	char *buf;
Linus Torvalds's avatar
Linus Torvalds committed
765

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

768
769
770
	if (cfile == NULL)
		return rc;

771
	xid = get_xid();
772
773
	tcon = tlink_tcon(cfile->tlink);
	server = tcon->ses->server;
Linus Torvalds's avatar
Linus Torvalds committed
774

775
	cifs_dbg(FYI, "Freeing private data in close dir\n");
776
	spin_lock(&cifs_file_list_lock);
777
	if (server->ops->dir_needs_close(cfile)) {
778
779
780
781
782
783
		cfile->invalidHandle = true;
		spin_unlock(&cifs_file_list_lock);
		if (server->ops->close_dir)
			rc = server->ops->close_dir(xid, tcon, &cfile->fid);
		else
			rc = -ENOSYS;
784
		cifs_dbg(FYI, "Closing uncompleted readdir with rc %d\n", rc);
785
786
787
788
789
790
791
		/* not much we can do if it fails anyway, ignore rc */
		rc = 0;
	} else
		spin_unlock(&cifs_file_list_lock);

	buf = cfile->srch_inf.ntwrk_buf_start;
	if (buf) {
792
		cifs_dbg(FYI, "closedir free smb buf in srch struct\n");
793
794
795
796
797
		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
798
	}
799
800
801
802

	cifs_put_tlink(cfile->tlink);
	kfree(file->private_data);
	file->private_data = NULL;
Linus Torvalds's avatar
Linus Torvalds committed
803
	/* BB can we lock the filestruct while this is going on? */
804
	free_xid(xid);
Linus Torvalds's avatar
Linus Torvalds committed
805
806
807
	return rc;
}

808
static struct cifsLockInfo *
809
cifs_lock_init(__u64 offset, __u64 length, __u8 type)
Jeremy Allison's avatar
[CIFS]    
Jeremy Allison committed
810
{
811
	struct cifsLockInfo *lock =
Steve French's avatar
Steve French committed
812
		kmalloc(sizeof(struct cifsLockInfo), GFP_KERNEL);
813
814
815
816
817
818
819
820
821
	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;
822
823
}

824
void
825
826
827
828
829
830
831
832
833
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);
	}
}

834
835
836
837
838
#define CIFS_LOCK_OP	0
#define CIFS_READ_OP	1
#define CIFS_WRITE_OP	2

/* @rw_check : 0 - no op, 1 - read, 2 - write */
839
static bool
840
841
cifs_find_fid_lock_conflict(struct cifs_fid_locks *fdlocks, __u64 offset,
			    __u64 length, __u8 type, struct cifsFileInfo *cfile,
842
			    struct cifsLockInfo **conf_lock, int rw_check)
843
{
844
	struct cifsLockInfo *li;
845
	struct cifsFileInfo *cur_cfile = fdlocks->cfile;
846
	struct TCP_Server_Info *server = tlink_tcon(cfile->tlink)->ses->server;
847

848
	list_for_each_entry(li, &fdlocks->locks, llist) {
849
850
851
		if (offset + length <= li->offset ||
		    offset >= li->offset + li->length)
			continue;
852
853
854
855
856
857
858
		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;
		}
859
860
861
		if ((type & server->vals->shared_lock_type) &&
		    ((server->ops->compare_fids(cfile, cur_cfile) &&
		     current->tgid == li->pid) || type == li->type))
862
			continue;
863
864
		if (conf_lock)
			*conf_lock = li;
865
		return true;
866
867
868
869
	}
	return false;
}

870
bool
871
cifs_find_lock_conflict(struct cifsFileInfo *cfile, __u64 offset, __u64 length,
872
			__u8 type, struct cifsLockInfo **conf_lock,
873
			int rw_check)
874
{
875
	bool rc = false;
876
	struct cifs_fid_locks *cur;
877
	struct cifsInodeInfo *cinode = CIFS_I(cfile->dentry->d_inode);
878

879
880
	list_for_each_entry(cur, &cinode->llist, llist) {
		rc = cifs_find_fid_lock_conflict(cur, offset, length, type,
881
						 cfile, conf_lock, rw_check);
882
883
884
885
886
		if (rc)
			break;
	}

	return rc;
887
888
}

889
890
891
892
893
894
895
/*
 * 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.
 */
896
static int
897
898
cifs_lock_test(struct cifsFileInfo *cfile, __u64 offset, __u64 length,
	       __u8 type, struct file_lock *flock)
899
900
901
{
	int rc = 0;
	struct cifsLockInfo *conf_lock;
902
	struct cifsInodeInfo *cinode = CIFS_I(cfile->dentry->d_inode);
903
	struct TCP_Server_Info *server = tlink_tcon(cfile->tlink)->ses->server;
904
905
	bool exist;

906
	down_read(&cinode->lock_sem);
907

908
	exist = cifs_find_lock_conflict(cfile, offset, length, type,
909
					&conf_lock, CIFS_LOCK_OP);
910
911
912
913
	if (exist) {
		flock->fl_start = conf_lock->offset;
		flock->fl_end = conf_lock->offset + conf_lock->length - 1;
		flock->fl_pid = conf_lock->pid;
914
		if (conf_lock->type & server->vals->shared_lock_type)
915
916
917
918
919
920
921
922
			flock->fl_type = F_RDLCK;
		else
			flock->fl_type = F_WRLCK;
	} else if (!cinode->can_cache_brlcks)
		rc = 1;
	else
		flock->fl_type = F_UNLCK;

923
	up_read(&cinode->lock_sem);
924
925
926
	return rc;
}

927
static void
928
cifs_lock_add(struct cifsFileInfo *cfile, struct cifsLockInfo *lock)
929
{
930
	struct cifsInodeInfo *cinode = CIFS_I(cfile->dentry->d_inode);
931
	down_write(&cinode->lock_sem);
932
	list_add_tail(&lock->llist, &cfile->llist->locks);
933
	up_write(&cinode->lock_sem);
Jeremy Allison's avatar
[CIFS]    
Jeremy Allison committed
934
935
}

936
937
938
939
940
941
/*
 * Set the byte-range lock (mandatory style). Returns:
 * 1) 0, if we set the lock and don't need to request to the server;
 * 2) 1, if no locks prevent us but we need to request to the server;
 * 3) -EACCESS, if there is a lock that prevents us and wait is false.
 */
942
static int
943
cifs_lock_add_if(struct cifsFileInfo *cfile, struct cifsLockInfo *lock,
944
		 bool wait)
945
{
946
	struct cifsLockInfo *conf_lock;
947
	struct cifsInodeInfo *cinode = CIFS_I(cfile->dentry->d_inode);
948
949
950
951
952
	bool exist;
	int rc = 0;

try_again:
	exist = false;
953
	down_write(&cinode->lock_sem);
954

955
	exist = cifs_find_lock_conflict(cfile, lock->offset, lock->length,
956
					lock->type, &conf_lock, CIFS_LOCK_OP);
957
	if (!exist && cinode->can_cache_brlcks) {
958
		list_add_tail(&lock->llist, &cfile->llist->locks);
959
		up_write(&cinode->lock_sem);
960
961
962
963
964
965
966
967
968
		return rc;
	}

	if (!exist)
		rc = 1;
	else if (!wait)
		rc = -EACCES;
	else {
		list_add_tail(&lock->blist, &conf_lock->blist);
969
		up_write(&cinode->lock_sem);
970
971
972
973
974
		rc = wait_event_interruptible(lock->block_q,
					(lock->blist.prev == &lock->blist) &&
					(lock->blist.next == &lock->blist));
		if (!rc)
			goto try_again;
975
		down_write(&cinode->lock_sem);
976
		list_del_init(&lock->blist);
977
978
	}

979
	up_write(&cinode->lock_sem);
980
981
982
	return rc;
}

983
984
985
986
987
988
989
/*
 * Check if there is another lock that prevents us to set the lock (posix
 * 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.
 */
990
static int
991
992
993
cifs_posix_lock_test(struct file *file, struct file_lock *flock)
{
	int rc = 0;
Al Viro's avatar
Al Viro committed
994
	struct cifsInodeInfo *cinode = CIFS_I(file_inode(file));
995
996
	unsigned char saved_type = flock->fl_type;

997
998
999
	if ((flock->fl_flags & FL_POSIX) == 0)
		return 1;

1000
	down_read(&cinode->lock_sem);
1001
1002
1003
1004
1005
1006
1007
	posix_test_lock(file, flock);

	if (flock->fl_type == F_UNLCK && !cinode->can_cache_brlcks) {
		flock->fl_type = saved_type;
		rc = 1;
	}

1008
	up_read(&cinode->lock_sem);
1009
1010
1011
	return rc;
}

1012
1013
1014
1015
1016
1017
/*
 * Set the byte-range lock (posix style). Returns:
 * 1) 0, if we set the lock and don't need to request to the server;
 * 2) 1, if we need to request to the server;
 * 3) <0, if the error occurs while setting the lock.
 */
1018
1019
1020
static int
cifs_posix_lock_set(struct file *file, struct file_lock *flock)
{
Al Viro's avatar
Al Viro committed
1021
	struct cifsInodeInfo *cinode = CIFS_I(file_inode(file));