Blame view

fs/cifs/file.c 74.4 KB
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
1
2
3
4
  /*
   *   fs/cifs/file.c
   *
   *   vfs operations that deal with files
fb8c4b14d   Steve French   [CIFS] whitespace...
5
   *
f19159dc5   Steve French   [CIFS] Cleanup va...
6
   *   Copyright (C) International Business Machines  Corp., 2002,2010
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
7
   *   Author(s): Steve French (sfrench@us.ibm.com)
7ee1af765   Jeremy Allison   [CIFS]
8
   *              Jeremy Allison (jra@samba.org)
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
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>
37c0eb467   Steve French   CIFS: implement c...
25
  #include <linux/backing-dev.h>
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
26
27
28
29
  #include <linux/stat.h>
  #include <linux/fcntl.h>
  #include <linux/pagemap.h>
  #include <linux/pagevec.h>
37c0eb467   Steve French   CIFS: implement c...
30
  #include <linux/writeback.h>
6f88cc2e9   Andrew Morton   [PATCH] io-accoun...
31
  #include <linux/task_io_accounting_ops.h>
23e7dd7d9   Steve French   [CIFS] Defer clos...
32
  #include <linux/delay.h>
3bc303c25   Jeff Layton   cifs: convert opl...
33
  #include <linux/mount.h>
5a0e3ad6a   Tejun Heo   include cleanup: ...
34
  #include <linux/slab.h>
690c5e316   Jeff Layton   cifs: convert cif...
35
  #include <linux/swap.h>
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
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"
9451a9a52   Suresh Jayaraman   cifs: define inod...
44
  #include "fscache.h"
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
45

1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
46
47
48
49
50
51
52
53
54
55
56
57
  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);
  	}
e10f7b551   Jeff Layton   clarify return va...
58
59
60
  	return (READ_CONTROL | FILE_WRITE_ATTRIBUTES | FILE_READ_ATTRIBUTES |
  		FILE_WRITE_EA | FILE_APPEND_DATA | FILE_WRITE_DATA |
  		FILE_READ_DATA);
7fc8f4e95   Steve French   [CIFS] reopen fil...
61
  }
e10f7b551   Jeff Layton   clarify return va...
62

608712fe8   Jeff Layton   cifs: fix flags h...
63
  static u32 cifs_posix_convert_flags(unsigned int flags)
7fc8f4e95   Steve French   [CIFS] reopen fil...
64
  {
608712fe8   Jeff Layton   cifs: fix flags h...
65
  	u32 posix_flags = 0;
e10f7b551   Jeff Layton   clarify return va...
66

7fc8f4e95   Steve French   [CIFS] reopen fil...
67
  	if ((flags & O_ACCMODE) == O_RDONLY)
608712fe8   Jeff Layton   cifs: fix flags h...
68
  		posix_flags = SMB_O_RDONLY;
7fc8f4e95   Steve French   [CIFS] reopen fil...
69
  	else if ((flags & O_ACCMODE) == O_WRONLY)
608712fe8   Jeff Layton   cifs: fix flags h...
70
71
72
73
74
75
76
77
78
79
80
  		posix_flags = SMB_O_WRONLY;
  	else if ((flags & O_ACCMODE) == O_RDWR)
  		posix_flags = SMB_O_RDWR;
  
  	if (flags & O_CREAT)
  		posix_flags |= SMB_O_CREAT;
  	if (flags & O_EXCL)
  		posix_flags |= SMB_O_EXCL;
  	if (flags & O_TRUNC)
  		posix_flags |= SMB_O_TRUNC;
  	/* be safe and imply O_SYNC for O_DSYNC */
6b2f3d1f7   Christoph Hellwig   vfs: Implement pr...
81
  	if (flags & O_DSYNC)
608712fe8   Jeff Layton   cifs: fix flags h...
82
  		posix_flags |= SMB_O_SYNC;
7fc8f4e95   Steve French   [CIFS] reopen fil...
83
  	if (flags & O_DIRECTORY)
608712fe8   Jeff Layton   cifs: fix flags h...
84
  		posix_flags |= SMB_O_DIRECTORY;
7fc8f4e95   Steve French   [CIFS] reopen fil...
85
  	if (flags & O_NOFOLLOW)
608712fe8   Jeff Layton   cifs: fix flags h...
86
  		posix_flags |= SMB_O_NOFOLLOW;
7fc8f4e95   Steve French   [CIFS] reopen fil...
87
  	if (flags & O_DIRECT)
608712fe8   Jeff Layton   cifs: fix flags h...
88
  		posix_flags |= SMB_O_DIRECT;
7fc8f4e95   Steve French   [CIFS] reopen fil...
89
90
  
  	return posix_flags;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
91
92
93
94
95
96
97
98
99
100
  }
  
  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;
55aa2e097   Steve French   [[CIFS] Pass trun...
101
102
  	else if ((flags & O_TRUNC) == O_TRUNC)
  		return FILE_OVERWRITE;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
103
104
105
  	else
  		return FILE_OPEN;
  }
608712fe8   Jeff Layton   cifs: fix flags h...
106
107
108
109
110
111
112
113
114
115
  int cifs_posix_open(char *full_path, struct inode **pinode,
  			struct super_block *sb, int mode, unsigned int f_flags,
  			__u32 *poplock, __u16 *pnetfid, int xid)
  {
  	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;
96daf2b09   Steve French   [CIFS] Rename thr...
116
  	struct cifs_tcon *tcon;
608712fe8   Jeff Layton   cifs: fix flags h...
117
118
119
120
121
122
123
124
125
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
  
  	cFYI(1, "posix open %s", full_path);
  
  	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;
  }
eeb910a6d   Pavel Shilovsky   CIFS: Simplify no...
167
168
  static int
  cifs_nt_open(char *full_path, struct inode *inode, struct cifs_sb_info *cifs_sb,
96daf2b09   Steve French   [CIFS] Rename thr...
169
  	     struct cifs_tcon *tcon, unsigned int f_flags, __u32 *poplock,
eeb910a6d   Pavel Shilovsky   CIFS: Simplify no...
170
171
172
173
174
  	     __u16 *pnetfid, int xid)
  {
  	int rc;
  	int desiredAccess;
  	int disposition;
3d3ea8e64   Shirish Pargaonkar   cifs: Add mount o...
175
  	int create_options = CREATE_NOT_DIR;
eeb910a6d   Pavel Shilovsky   CIFS: Simplify no...
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
  	FILE_ALL_INFO *buf;
  
  	desiredAccess = cifs_convert_flags(f_flags);
  
  /*********************************************************************
   *  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;
3d3ea8e64   Shirish Pargaonkar   cifs: Add mount o...
211
212
  	if (backup_cred(cifs_sb))
  		create_options |= CREATE_OPEN_BACKUP_INTENT;
eeb910a6d   Pavel Shilovsky   CIFS: Simplify no...
213
214
  	if (tcon->ses->capabilities & CAP_NT_SMBS)
  		rc = CIFSSMBOpen(xid, tcon, full_path, disposition,
3d3ea8e64   Shirish Pargaonkar   cifs: Add mount o...
215
  			 desiredAccess, create_options, pnetfid, poplock, buf,
eeb910a6d   Pavel Shilovsky   CIFS: Simplify no...
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
  			 cifs_sb->local_nls, cifs_sb->mnt_cifs_flags
  				 & CIFS_MOUNT_MAP_SPECIAL_CHR);
  	else
  		rc = SMBLegacyOpen(xid, tcon, full_path, disposition,
  			desiredAccess, CREATE_NOT_DIR, pnetfid, poplock, buf,
  			cifs_sb->local_nls, cifs_sb->mnt_cifs_flags
  				& CIFS_MOUNT_MAP_SPECIAL_CHR);
  
  	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,
  					 xid, pnetfid);
  
  out:
  	kfree(buf);
  	return rc;
  }
15ecb436c   Jeff Layton   cifs: move cifs_n...
238
239
240
241
242
243
244
245
246
247
248
249
  struct cifsFileInfo *
  cifs_new_fileinfo(__u16 fileHandle, struct file *file,
  		  struct tcon_link *tlink, __u32 oplock)
  {
  	struct dentry *dentry = file->f_path.dentry;
  	struct inode *inode = dentry->d_inode;
  	struct cifsInodeInfo *pCifsInode = CIFS_I(inode);
  	struct cifsFileInfo *pCifsFile;
  
  	pCifsFile = kzalloc(sizeof(struct cifsFileInfo), GFP_KERNEL);
  	if (pCifsFile == NULL)
  		return pCifsFile;
5f6dbc9e4   Jeff Layton   cifs: convert cif...
250
  	pCifsFile->count = 1;
15ecb436c   Jeff Layton   cifs: move cifs_n...
251
252
253
254
255
256
  	pCifsFile->netfid = fileHandle;
  	pCifsFile->pid = current->tgid;
  	pCifsFile->uid = current_fsuid();
  	pCifsFile->dentry = dget(dentry);
  	pCifsFile->f_flags = file->f_flags;
  	pCifsFile->invalidHandle = false;
15ecb436c   Jeff Layton   cifs: move cifs_n...
257
258
  	pCifsFile->tlink = cifs_get_tlink(tlink);
  	mutex_init(&pCifsFile->fh_mutex);
15ecb436c   Jeff Layton   cifs: move cifs_n...
259
  	INIT_WORK(&pCifsFile->oplock_break, cifs_oplock_break);
4477288a1   Jeff Layton   cifs: convert Glo...
260
  	spin_lock(&cifs_file_list_lock);
15ecb436c   Jeff Layton   cifs: move cifs_n...
261
262
263
264
265
266
  	list_add(&pCifsFile->tlist, &(tlink_tcon(tlink)->openFileList));
  	/* if readable file instance put first in list*/
  	if (file->f_mode & FMODE_READ)
  		list_add(&pCifsFile->flist, &pCifsInode->openFileList);
  	else
  		list_add_tail(&pCifsFile->flist, &pCifsInode->openFileList);
4477288a1   Jeff Layton   cifs: convert Glo...
267
  	spin_unlock(&cifs_file_list_lock);
15ecb436c   Jeff Layton   cifs: move cifs_n...
268

c67236281   Pavel Shilovsky   cifs: make cifs_s...
269
  	cifs_set_oplock_level(pCifsInode, oplock);
85160e03a   Pavel Shilovsky   CIFS: Implement c...
270
  	pCifsInode->can_cache_brlcks = pCifsInode->clientCanCacheAll;
15ecb436c   Jeff Layton   cifs: move cifs_n...
271
272
273
274
  
  	file->private_data = pCifsFile;
  	return pCifsFile;
  }
85160e03a   Pavel Shilovsky   CIFS: Implement c...
275
  static void cifs_del_lock_waiters(struct cifsLockInfo *lock);
cdff08e76   Steve French   [CIFS] move close...
276
277
  /*
   * Release a reference on the file private data. This may involve closing
5f6dbc9e4   Jeff Layton   cifs: convert cif...
278
279
   * the filehandle out on the server. Must be called without holding
   * cifs_file_list_lock.
cdff08e76   Steve French   [CIFS] move close...
280
   */
b33879aa8   Jeff Layton   cifs: move cifsFi...
281
282
  void cifsFileInfo_put(struct cifsFileInfo *cifs_file)
  {
e66673e39   Pavel Shilovsky   CIFS: Add cifs_se...
283
  	struct inode *inode = cifs_file->dentry->d_inode;
96daf2b09   Steve French   [CIFS] Rename thr...
284
  	struct cifs_tcon *tcon = tlink_tcon(cifs_file->tlink);
e66673e39   Pavel Shilovsky   CIFS: Add cifs_se...
285
  	struct cifsInodeInfo *cifsi = CIFS_I(inode);
4f8ba8a0c   Pavel Shilovsky   CIFS: Make cifsFi...
286
  	struct cifs_sb_info *cifs_sb = CIFS_SB(inode->i_sb);
cdff08e76   Steve French   [CIFS] move close...
287
288
289
  	struct cifsLockInfo *li, *tmp;
  
  	spin_lock(&cifs_file_list_lock);
5f6dbc9e4   Jeff Layton   cifs: convert cif...
290
  	if (--cifs_file->count > 0) {
cdff08e76   Steve French   [CIFS] move close...
291
292
293
294
295
296
297
298
299
300
301
  		spin_unlock(&cifs_file_list_lock);
  		return;
  	}
  
  	/* remove it from the lists */
  	list_del(&cifs_file->flist);
  	list_del(&cifs_file->tlist);
  
  	if (list_empty(&cifsi->openFileList)) {
  		cFYI(1, "closing last open instance for inode %p",
  			cifs_file->dentry->d_inode);
4f8ba8a0c   Pavel Shilovsky   CIFS: Make cifsFi...
302
303
304
305
306
307
  
  		/* 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 */
  		if (cifs_sb->mnt_cifs_flags & CIFS_MOUNT_STRICT_IO)
  			CIFS_I(inode)->invalid_mapping = true;
c67236281   Pavel Shilovsky   cifs: make cifs_s...
308
  		cifs_set_oplock_level(cifsi, 0);
cdff08e76   Steve French   [CIFS] move close...
309
310
  	}
  	spin_unlock(&cifs_file_list_lock);
ad635942c   Jeff Layton   cifs: simplify re...
311
  	cancel_work_sync(&cifs_file->oplock_break);
cdff08e76   Steve French   [CIFS] move close...
312
313
314
315
316
317
318
319
320
321
322
  	if (!tcon->need_reconnect && !cifs_file->invalidHandle) {
  		int xid, rc;
  
  		xid = GetXid();
  		rc = CIFSSMBClose(xid, tcon, cifs_file->netfid);
  		FreeXid(xid);
  	}
  
  	/* Delete any outstanding lock records. We'll lose them when the file
  	 * is closed anyway.
  	 */
d59dad2be   Pavel Shilovsky   CIFS: Move byte r...
323
324
325
326
  	mutex_lock(&cifsi->lock_mutex);
  	list_for_each_entry_safe(li, tmp, &cifsi->llist, llist) {
  		if (li->netfid != cifs_file->netfid)
  			continue;
cdff08e76   Steve French   [CIFS] move close...
327
  		list_del(&li->llist);
85160e03a   Pavel Shilovsky   CIFS: Implement c...
328
  		cifs_del_lock_waiters(li);
cdff08e76   Steve French   [CIFS] move close...
329
  		kfree(li);
b33879aa8   Jeff Layton   cifs: move cifsFi...
330
  	}
d59dad2be   Pavel Shilovsky   CIFS: Move byte r...
331
  	mutex_unlock(&cifsi->lock_mutex);
cdff08e76   Steve French   [CIFS] move close...
332
333
334
335
  
  	cifs_put_tlink(cifs_file->tlink);
  	dput(cifs_file->dentry);
  	kfree(cifs_file);
b33879aa8   Jeff Layton   cifs: move cifsFi...
336
  }
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
337
338
339
  int cifs_open(struct inode *inode, struct file *file)
  {
  	int rc = -EACCES;
590a3fe0e   Jeff Layton   cifs: fix oplock ...
340
341
  	int xid;
  	__u32 oplock;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
342
  	struct cifs_sb_info *cifs_sb;
96daf2b09   Steve French   [CIFS] Rename thr...
343
  	struct cifs_tcon *tcon;
7ffec3724   Jeff Layton   cifs: add refcoun...
344
  	struct tcon_link *tlink;
6ca9f3bae   Jeff Layton   cifs: pass instan...
345
  	struct cifsFileInfo *pCifsFile = NULL;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
346
  	char *full_path = NULL;
7e12eddb7   Pavel Shilovsky   CIFS: Simplify ci...
347
  	bool posix_open_ok = false;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
348
  	__u16 netfid;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
349
350
351
352
  
  	xid = GetXid();
  
  	cifs_sb = CIFS_SB(inode->i_sb);
7ffec3724   Jeff Layton   cifs: add refcoun...
353
354
355
356
357
358
  	tlink = cifs_sb_tlink(cifs_sb);
  	if (IS_ERR(tlink)) {
  		FreeXid(xid);
  		return PTR_ERR(tlink);
  	}
  	tcon = tlink_tcon(tlink);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
359

e6a002964   Josef "Jeff" Sipek   [PATCH] cifs: cha...
360
  	full_path = build_path_from_dentry(file->f_path.dentry);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
361
  	if (full_path == NULL) {
0f3bc09ee   Suresh Jayaraman   cifs: Fix incorre...
362
  		rc = -ENOMEM;
232341ba7   Jeff Layton   cifs: consolidate...
363
  		goto out;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
364
  	}
b6b38f704   Joe Perches   [CIFS] Neaten cER...
365
366
  	cFYI(1, "inode = 0x%p file flags are 0x%x for %s",
  		 inode, file->f_flags, full_path);
276a74a48   Steve French   [CIFS] Use posix ...
367

e75047344   Steve French   add new module pa...
368
  	if (enable_oplocks)
276a74a48   Steve French   [CIFS] Use posix ...
369
370
371
  		oplock = REQ_OPLOCK;
  	else
  		oplock = 0;
64cc2c636   Steve French   [CIFS] work aroun...
372
373
  	if (!tcon->broken_posix_open && tcon->unix_ext &&
  	    (tcon->ses->capabilities & CAP_UNIX) &&
276a74a48   Steve French   [CIFS] Use posix ...
374
375
  	    (CIFS_UNIX_POSIX_PATH_OPS_CAP &
  			le64_to_cpu(tcon->fsUnixInfo.Capability))) {
276a74a48   Steve French   [CIFS] Use posix ...
376
  		/* can not refresh inode info since size could be stale */
2422f676f   Jeff Layton   cifs: move cifs_n...
377
  		rc = cifs_posix_open(full_path, &inode, inode->i_sb,
fa588e0c5   Steve French   [CIFS] Allow null...
378
  				cifs_sb->mnt_file_mode /* ignored */,
608712fe8   Jeff Layton   cifs: fix flags h...
379
  				file->f_flags, &oplock, &netfid, xid);
276a74a48   Steve French   [CIFS] Use posix ...
380
  		if (rc == 0) {
b6b38f704   Joe Perches   [CIFS] Neaten cER...
381
  			cFYI(1, "posix open succeeded");
7e12eddb7   Pavel Shilovsky   CIFS: Simplify ci...
382
  			posix_open_ok = true;
64cc2c636   Steve French   [CIFS] work aroun...
383
384
  		} else if ((rc == -EINVAL) || (rc == -EOPNOTSUPP)) {
  			if (tcon->ses->serverNOS)
b6b38f704   Joe Perches   [CIFS] Neaten cER...
385
  				cERROR(1, "server %s of type %s returned"
64cc2c636   Steve French   [CIFS] work aroun...
386
387
388
389
  					   " unexpected error on SMB posix open"
  					   ", disabling posix open support."
  					   " Check if server update available.",
  					   tcon->ses->serverName,
b6b38f704   Joe Perches   [CIFS] Neaten cER...
390
  					   tcon->ses->serverNOS);
64cc2c636   Steve French   [CIFS] work aroun...
391
  			tcon->broken_posix_open = true;
276a74a48   Steve French   [CIFS] Use posix ...
392
393
394
  		} else if ((rc != -EIO) && (rc != -EREMOTE) &&
  			 (rc != -EOPNOTSUPP)) /* path not found or net err */
  			goto out;
64cc2c636   Steve French   [CIFS] work aroun...
395
396
  		/* else fallthrough to retry open the old way on network i/o
  		   or DFS errors */
276a74a48   Steve French   [CIFS] Use posix ...
397
  	}
7e12eddb7   Pavel Shilovsky   CIFS: Simplify ci...
398
399
400
401
402
403
  	if (!posix_open_ok) {
  		rc = cifs_nt_open(full_path, inode, cifs_sb, tcon,
  				  file->f_flags, &oplock, &netfid, xid);
  		if (rc)
  			goto out;
  	}
47c78b7f4   Jeff Layton   cifs: don't call ...
404

abfe1eedd   Jeff Layton   cifs: eliminate t...
405
  	pCifsFile = cifs_new_fileinfo(netfid, file, tlink, oplock);
6ca9f3bae   Jeff Layton   cifs: pass instan...
406
  	if (pCifsFile == NULL) {
7e12eddb7   Pavel Shilovsky   CIFS: Simplify ci...
407
  		CIFSSMBClose(xid, tcon, netfid);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
408
409
410
  		rc = -ENOMEM;
  		goto out;
  	}
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
411

9451a9a52   Suresh Jayaraman   cifs: define inod...
412
  	cifs_fscache_set_inode_cookie(inode, file);
7e12eddb7   Pavel Shilovsky   CIFS: Simplify ci...
413
  	if ((oplock & CIFS_CREATE_ACTION) && !posix_open_ok && tcon->unix_ext) {
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
414
415
  		/* time to set mode which we can not set earlier due to
  		   problems creating new read-only files */
7e12eddb7   Pavel Shilovsky   CIFS: Simplify ci...
416
417
418
419
420
421
422
423
424
  		struct cifs_unix_set_info_args args = {
  			.mode	= inode->i_mode,
  			.uid	= NO_CHANGE_64,
  			.gid	= NO_CHANGE_64,
  			.ctime	= NO_CHANGE_64,
  			.atime	= NO_CHANGE_64,
  			.mtime	= NO_CHANGE_64,
  			.device	= 0,
  		};
d44a9fe2c   Jeff Layton   cifs: switch cifs...
425
426
  		CIFSSMBUnixSetFileInfo(xid, tcon, &args, netfid,
  					pCifsFile->pid);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
427
428
429
  	}
  
  out:
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
430
431
  	kfree(full_path);
  	FreeXid(xid);
7ffec3724   Jeff Layton   cifs: add refcoun...
432
  	cifs_put_tlink(tlink);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
433
434
  	return rc;
  }
0418726bb   Adrian Bunk   typo fixes: aquir...
435
  /* Try to reacquire byte range locks that were released when session */
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
436
437
438
439
440
441
442
443
444
  /* to server was lost */
  static int cifs_relock_file(struct cifsFileInfo *cifsFile)
  {
  	int rc = 0;
  
  /* BB list all locks open on this file and relock */
  
  	return rc;
  }
15886177e   Jeff Layton   cifs: clean up ci...
445
  static int cifs_reopen_file(struct cifsFileInfo *pCifsFile, bool can_flush)
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
446
447
  {
  	int rc = -EACCES;
590a3fe0e   Jeff Layton   cifs: fix oplock ...
448
449
  	int xid;
  	__u32 oplock;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
450
  	struct cifs_sb_info *cifs_sb;
96daf2b09   Steve French   [CIFS] Rename thr...
451
  	struct cifs_tcon *tcon;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
452
  	struct cifsInodeInfo *pCifsInode;
fb8c4b14d   Steve French   [CIFS] whitespace...
453
  	struct inode *inode;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
454
455
456
  	char *full_path = NULL;
  	int desiredAccess;
  	int disposition = FILE_OPEN;
3d3ea8e64   Shirish Pargaonkar   cifs: Add mount o...
457
  	int create_options = CREATE_NOT_DIR;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
458
  	__u16 netfid;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
459
  	xid = GetXid();
f0a71eb82   Jeff Layton   cifs: fix fh_mute...
460
  	mutex_lock(&pCifsFile->fh_mutex);
4b18f2a9c   Steve French   [CIFS] convert us...
461
  	if (!pCifsFile->invalidHandle) {
f0a71eb82   Jeff Layton   cifs: fix fh_mute...
462
  		mutex_unlock(&pCifsFile->fh_mutex);
0f3bc09ee   Suresh Jayaraman   cifs: Fix incorre...
463
  		rc = 0;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
464
  		FreeXid(xid);
0f3bc09ee   Suresh Jayaraman   cifs: Fix incorre...
465
  		return rc;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
466
  	}
15886177e   Jeff Layton   cifs: clean up ci...
467
  	inode = pCifsFile->dentry->d_inode;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
468
  	cifs_sb = CIFS_SB(inode->i_sb);
13cfb7334   Jeff Layton   cifs: have cifsFi...
469
  	tcon = tlink_tcon(pCifsFile->tlink);
3a9f462f6   Steve French   [CIFS] Remove unn...
470

1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
471
472
473
474
  /* 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 */
15886177e   Jeff Layton   cifs: clean up ci...
475
  	full_path = build_path_from_dentry(pCifsFile->dentry);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
476
  	if (full_path == NULL) {
3a9f462f6   Steve French   [CIFS] Remove unn...
477
  		rc = -ENOMEM;
f0a71eb82   Jeff Layton   cifs: fix fh_mute...
478
  		mutex_unlock(&pCifsFile->fh_mutex);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
479
  		FreeXid(xid);
3a9f462f6   Steve French   [CIFS] Remove unn...
480
  		return rc;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
481
  	}
b6b38f704   Joe Perches   [CIFS] Neaten cER...
482
  	cFYI(1, "inode = 0x%p file flags 0x%x for %s",
15886177e   Jeff Layton   cifs: clean up ci...
483
  		 inode, pCifsFile->f_flags, full_path);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
484

e75047344   Steve French   add new module pa...
485
  	if (enable_oplocks)
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
486
487
  		oplock = REQ_OPLOCK;
  	else
4b18f2a9c   Steve French   [CIFS] convert us...
488
  		oplock = 0;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
489

7fc8f4e95   Steve French   [CIFS] reopen fil...
490
491
492
  	if (tcon->unix_ext && (tcon->ses->capabilities & CAP_UNIX) &&
  	    (CIFS_UNIX_POSIX_PATH_OPS_CAP &
  			le64_to_cpu(tcon->fsUnixInfo.Capability))) {
608712fe8   Jeff Layton   cifs: fix flags h...
493
494
495
496
497
  
  		/*
  		 * O_CREAT, O_EXCL and O_TRUNC already had their effect on the
  		 * original open. Must mask them off for a reopen.
  		 */
15886177e   Jeff Layton   cifs: clean up ci...
498
499
  		unsigned int oflags = pCifsFile->f_flags &
  						~(O_CREAT | O_EXCL | O_TRUNC);
608712fe8   Jeff Layton   cifs: fix flags h...
500

2422f676f   Jeff Layton   cifs: move cifs_n...
501
  		rc = cifs_posix_open(full_path, NULL, inode->i_sb,
fa588e0c5   Steve French   [CIFS] Allow null...
502
503
  				cifs_sb->mnt_file_mode /* ignored */,
  				oflags, &oplock, &netfid, xid);
7fc8f4e95   Steve French   [CIFS] reopen fil...
504
  		if (rc == 0) {
b6b38f704   Joe Perches   [CIFS] Neaten cER...
505
  			cFYI(1, "posix reopen succeeded");
7fc8f4e95   Steve French   [CIFS] reopen fil...
506
507
508
509
510
  			goto reopen_success;
  		}
  		/* fallthrough to retry open the old way on errors, especially
  		   in the reconnect path it is important to retry hard */
  	}
15886177e   Jeff Layton   cifs: clean up ci...
511
  	desiredAccess = cifs_convert_flags(pCifsFile->f_flags);
7fc8f4e95   Steve French   [CIFS] reopen fil...
512

3d3ea8e64   Shirish Pargaonkar   cifs: Add mount o...
513
514
  	if (backup_cred(cifs_sb))
  		create_options |= CREATE_OPEN_BACKUP_INTENT;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
515
  	/* Can not refresh inode by passing in file_info buf to be returned
fb8c4b14d   Steve French   [CIFS] whitespace...
516
517
  	   by SMBOpen and then calling get_inode_info with returned buf
  	   since file might have write behind data that needs to be flushed
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
518
519
  	   and server version of file size can be stale. If we knew for sure
  	   that inode was not dirty locally we could do this */
7fc8f4e95   Steve French   [CIFS] reopen fil...
520
  	rc = CIFSSMBOpen(xid, tcon, full_path, disposition, desiredAccess,
3d3ea8e64   Shirish Pargaonkar   cifs: Add mount o...
521
  			 create_options, &netfid, &oplock, NULL,
fb8c4b14d   Steve French   [CIFS] whitespace...
522
  			 cifs_sb->local_nls, cifs_sb->mnt_cifs_flags &
737b758c9   Steve French   [PATCH] cifs: cha...
523
  				CIFS_MOUNT_MAP_SPECIAL_CHR);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
524
  	if (rc) {
f0a71eb82   Jeff Layton   cifs: fix fh_mute...
525
  		mutex_unlock(&pCifsFile->fh_mutex);
b6b38f704   Joe Perches   [CIFS] Neaten cER...
526
527
  		cFYI(1, "cifs_open returned 0x%x", rc);
  		cFYI(1, "oplock: %d", oplock);
15886177e   Jeff Layton   cifs: clean up ci...
528
529
  		goto reopen_error_exit;
  	}
7fc8f4e95   Steve French   [CIFS] reopen fil...
530
  reopen_success:
15886177e   Jeff Layton   cifs: clean up ci...
531
532
533
534
535
536
537
  	pCifsFile->netfid = netfid;
  	pCifsFile->invalidHandle = false;
  	mutex_unlock(&pCifsFile->fh_mutex);
  	pCifsInode = CIFS_I(inode);
  
  	if (can_flush) {
  		rc = filemap_write_and_wait(inode->i_mapping);
eb4b756b1   Jeff Layton   cifs: eliminate c...
538
  		mapping_set_error(inode->i_mapping, rc);
15886177e   Jeff Layton   cifs: clean up ci...
539

15886177e   Jeff Layton   cifs: clean up ci...
540
541
542
543
544
545
546
547
548
549
550
551
552
  		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, 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 inod
  	     info */
e66673e39   Pavel Shilovsky   CIFS: Add cifs_se...
553

c67236281   Pavel Shilovsky   cifs: make cifs_s...
554
  	cifs_set_oplock_level(pCifsInode, oplock);
e66673e39   Pavel Shilovsky   CIFS: Add cifs_se...
555

15886177e   Jeff Layton   cifs: clean up ci...
556
557
558
  	cifs_relock_file(pCifsFile);
  
  reopen_error_exit:
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
559
560
561
562
563
564
565
  	kfree(full_path);
  	FreeXid(xid);
  	return rc;
  }
  
  int cifs_close(struct inode *inode, struct file *file)
  {
779706930   Jeff Layton   cifs: check for p...
566
567
568
569
  	if (file->private_data != NULL) {
  		cifsFileInfo_put(file->private_data);
  		file->private_data = NULL;
  	}
7ee1af765   Jeremy Allison   [CIFS]
570

cdff08e76   Steve French   [CIFS] move close...
571
572
  	/* return code from the ->release op is always ignored */
  	return 0;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
573
574
575
576
577
578
  }
  
  int cifs_closedir(struct inode *inode, struct file *file)
  {
  	int rc = 0;
  	int xid;
c21dfb699   Joe Perches   fs/cifs: Remove u...
579
  	struct cifsFileInfo *pCFileStruct = file->private_data;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
580
  	char *ptmp;
b6b38f704   Joe Perches   [CIFS] Neaten cER...
581
  	cFYI(1, "Closedir inode = 0x%p", inode);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
582
583
584
585
  
  	xid = GetXid();
  
  	if (pCFileStruct) {
96daf2b09   Steve French   [CIFS] Rename thr...
586
  		struct cifs_tcon *pTcon = tlink_tcon(pCFileStruct->tlink);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
587

b6b38f704   Joe Perches   [CIFS] Neaten cER...
588
  		cFYI(1, "Freeing private data in close dir");
4477288a1   Jeff Layton   cifs: convert Glo...
589
  		spin_lock(&cifs_file_list_lock);
4b18f2a9c   Steve French   [CIFS] convert us...
590
591
592
  		if (!pCFileStruct->srch_inf.endOfSearch &&
  		    !pCFileStruct->invalidHandle) {
  			pCFileStruct->invalidHandle = true;
4477288a1   Jeff Layton   cifs: convert Glo...
593
  			spin_unlock(&cifs_file_list_lock);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
594
  			rc = CIFSFindClose(xid, pTcon, pCFileStruct->netfid);
b6b38f704   Joe Perches   [CIFS] Neaten cER...
595
596
  			cFYI(1, "Closing uncompleted readdir with rc %d",
  				 rc);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
597
598
  			/* not much we can do if it fails anyway, ignore rc */
  			rc = 0;
ddb4cbfc5   Steve French   [CIFS] Do not att...
599
  		} else
4477288a1   Jeff Layton   cifs: convert Glo...
600
  			spin_unlock(&cifs_file_list_lock);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
601
602
  		ptmp = pCFileStruct->srch_inf.ntwrk_buf_start;
  		if (ptmp) {
b6b38f704   Joe Perches   [CIFS] Neaten cER...
603
  			cFYI(1, "closedir free smb buf in srch struct");
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
604
  			pCFileStruct->srch_inf.ntwrk_buf_start = NULL;
fb8c4b14d   Steve French   [CIFS] whitespace...
605
  			if (pCFileStruct->srch_inf.smallBuf)
d47d7c1a8   Steve French   [CIFS] CIFS readd...
606
607
608
  				cifs_small_buf_release(ptmp);
  			else
  				cifs_buf_release(ptmp);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
609
  		}
13cfb7334   Jeff Layton   cifs: have cifsFi...
610
  		cifs_put_tlink(pCFileStruct->tlink);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
611
612
613
614
615
616
617
  		kfree(file->private_data);
  		file->private_data = NULL;
  	}
  	/* BB can we lock the filestruct while this is going on? */
  	FreeXid(xid);
  	return rc;
  }
85160e03a   Pavel Shilovsky   CIFS: Implement c...
618
  static struct cifsLockInfo *
a88b47077   Pavel Shilovsky   CIFS: Cleanup byt...
619
  cifs_lock_init(__u64 offset, __u64 length, __u8 type, __u16 netfid)
7ee1af765   Jeremy Allison   [CIFS]
620
  {
a88b47077   Pavel Shilovsky   CIFS: Cleanup byt...
621
  	struct cifsLockInfo *lock =
fb8c4b14d   Steve French   [CIFS] whitespace...
622
  		kmalloc(sizeof(struct cifsLockInfo), GFP_KERNEL);
a88b47077   Pavel Shilovsky   CIFS: Cleanup byt...
623
624
625
626
627
628
629
630
631
632
  	if (!lock)
  		return lock;
  	lock->offset = offset;
  	lock->length = length;
  	lock->type = type;
  	lock->netfid = netfid;
  	lock->pid = current->tgid;
  	INIT_LIST_HEAD(&lock->blist);
  	init_waitqueue_head(&lock->block_q);
  	return lock;
85160e03a   Pavel Shilovsky   CIFS: Implement c...
633
634
635
636
637
638
639
640
641
642
643
644
645
  }
  
  static void
  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);
  	}
  }
  
  static bool
161ebf9fc   Pavel Shilovsky   CIFS: Simplify se...
646
  __cifs_find_lock_conflict(struct cifsInodeInfo *cinode, __u64 offset,
85160e03a   Pavel Shilovsky   CIFS: Implement c...
647
648
649
650
651
652
653
654
655
656
657
658
659
660
661
662
663
664
665
666
  			__u64 length, __u8 type, __u16 netfid,
  			struct cifsLockInfo **conf_lock)
  {
  	struct cifsLockInfo *li, *tmp;
  
  	list_for_each_entry_safe(li, tmp, &cinode->llist, llist) {
  		if (offset + length <= li->offset ||
  		    offset >= li->offset + li->length)
  			continue;
  		else if ((type & LOCKING_ANDX_SHARED_LOCK) &&
  			 ((netfid == li->netfid && current->tgid == li->pid) ||
  			  type == li->type))
  			continue;
  		else {
  			*conf_lock = li;
  			return true;
  		}
  	}
  	return false;
  }
161ebf9fc   Pavel Shilovsky   CIFS: Simplify se...
667
668
669
670
671
672
673
  static bool
  cifs_find_lock_conflict(struct cifsInodeInfo *cinode, struct cifsLockInfo *lock,
  			struct cifsLockInfo **conf_lock)
  {
  	return __cifs_find_lock_conflict(cinode, lock->offset, lock->length,
  					 lock->type, lock->netfid, conf_lock);
  }
9a5101c89   Pavel Shilovsky   CIFS: Add descrip...
674
675
676
677
678
679
680
  /*
   * 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.
   */
85160e03a   Pavel Shilovsky   CIFS: Implement c...
681
682
683
684
685
686
687
688
689
  static int
  cifs_lock_test(struct cifsInodeInfo *cinode, __u64 offset, __u64 length,
  	       __u8 type, __u16 netfid, struct file_lock *flock)
  {
  	int rc = 0;
  	struct cifsLockInfo *conf_lock;
  	bool exist;
  
  	mutex_lock(&cinode->lock_mutex);
161ebf9fc   Pavel Shilovsky   CIFS: Simplify se...
690
691
  	exist = __cifs_find_lock_conflict(cinode, offset, length, type, netfid,
  					  &conf_lock);
85160e03a   Pavel Shilovsky   CIFS: Implement c...
692
693
694
695
696
697
698
699
700
701
702
703
704
705
706
707
  	if (exist) {
  		flock->fl_start = conf_lock->offset;
  		flock->fl_end = conf_lock->offset + conf_lock->length - 1;
  		flock->fl_pid = conf_lock->pid;
  		if (conf_lock->type & LOCKING_ANDX_SHARED_LOCK)
  			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;
  
  	mutex_unlock(&cinode->lock_mutex);
  	return rc;
  }
161ebf9fc   Pavel Shilovsky   CIFS: Simplify se...
708
709
  static void
  cifs_lock_add(struct cifsInodeInfo *cinode, struct cifsLockInfo *lock)
85160e03a   Pavel Shilovsky   CIFS: Implement c...
710
  {
d59dad2be   Pavel Shilovsky   CIFS: Move byte r...
711
  	mutex_lock(&cinode->lock_mutex);
161ebf9fc   Pavel Shilovsky   CIFS: Simplify se...
712
  	list_add_tail(&lock->llist, &cinode->llist);
d59dad2be   Pavel Shilovsky   CIFS: Move byte r...
713
  	mutex_unlock(&cinode->lock_mutex);
7ee1af765   Jeremy Allison   [CIFS]
714
  }
9a5101c89   Pavel Shilovsky   CIFS: Add descrip...
715
716
717
718
719
720
  /*
   * 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.
   */
85160e03a   Pavel Shilovsky   CIFS: Implement c...
721
  static int
161ebf9fc   Pavel Shilovsky   CIFS: Simplify se...
722
723
  cifs_lock_add_if(struct cifsInodeInfo *cinode, struct cifsLockInfo *lock,
  		 bool wait)
85160e03a   Pavel Shilovsky   CIFS: Implement c...
724
  {
161ebf9fc   Pavel Shilovsky   CIFS: Simplify se...
725
  	struct cifsLockInfo *conf_lock;
85160e03a   Pavel Shilovsky   CIFS: Implement c...
726
727
  	bool exist;
  	int rc = 0;
85160e03a   Pavel Shilovsky   CIFS: Implement c...
728
729
730
  try_again:
  	exist = false;
  	mutex_lock(&cinode->lock_mutex);
161ebf9fc   Pavel Shilovsky   CIFS: Simplify se...
731
  	exist = cifs_find_lock_conflict(cinode, lock, &conf_lock);
85160e03a   Pavel Shilovsky   CIFS: Implement c...
732
733
734
735
736
737
738
739
740
741
742
743
744
745
746
747
748
749
  	if (!exist && cinode->can_cache_brlcks) {
  		list_add_tail(&lock->llist, &cinode->llist);
  		mutex_unlock(&cinode->lock_mutex);
  		return rc;
  	}
  
  	if (!exist)
  		rc = 1;
  	else if (!wait)
  		rc = -EACCES;
  	else {
  		list_add_tail(&lock->blist, &conf_lock->blist);
  		mutex_unlock(&cinode->lock_mutex);
  		rc = wait_event_interruptible(lock->block_q,
  					(lock->blist.prev == &lock->blist) &&
  					(lock->blist.next == &lock->blist));
  		if (!rc)
  			goto try_again;
a88b47077   Pavel Shilovsky   CIFS: Cleanup byt...
750
751
  		mutex_lock(&cinode->lock_mutex);
  		list_del_init(&lock->blist);
85160e03a   Pavel Shilovsky   CIFS: Implement c...
752
  	}
85160e03a   Pavel Shilovsky   CIFS: Implement c...
753
754
755
  	mutex_unlock(&cinode->lock_mutex);
  	return rc;
  }
9a5101c89   Pavel Shilovsky   CIFS: Add descrip...
756
757
758
759
760
761
762
  /*
   * 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.
   */
85160e03a   Pavel Shilovsky   CIFS: Implement c...
763
  static int
4f6bcec91   Pavel Shilovsky   CIFS: Implement c...
764
765
766
767
768
  cifs_posix_lock_test(struct file *file, struct file_lock *flock)
  {
  	int rc = 0;
  	struct cifsInodeInfo *cinode = CIFS_I(file->f_path.dentry->d_inode);
  	unsigned char saved_type = flock->fl_type;
507927606   Pavel Shilovsky   CIFS: Fix the VFS...
769
770
  	if ((flock->fl_flags & FL_POSIX) == 0)
  		return 1;
4f6bcec91   Pavel Shilovsky   CIFS: Implement c...
771
772
773
774
775
776
777
778
779
780
781
  	mutex_lock(&cinode->lock_mutex);
  	posix_test_lock(file, flock);
  
  	if (flock->fl_type == F_UNLCK && !cinode->can_cache_brlcks) {
  		flock->fl_type = saved_type;
  		rc = 1;
  	}
  
  	mutex_unlock(&cinode->lock_mutex);
  	return rc;
  }
9a5101c89   Pavel Shilovsky   CIFS: Add descrip...
782
783
784
785
786
787
  /*
   * 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.
   */
4f6bcec91   Pavel Shilovsky   CIFS: Implement c...
788
789
790
791
  static int
  cifs_posix_lock_set(struct file *file, struct file_lock *flock)
  {
  	struct cifsInodeInfo *cinode = CIFS_I(file->f_path.dentry->d_inode);
507927606   Pavel Shilovsky   CIFS: Fix the VFS...
792
793
794
795
  	int rc = 1;
  
  	if ((flock->fl_flags & FL_POSIX) == 0)
  		return rc;
4f6bcec91   Pavel Shilovsky   CIFS: Implement c...
796
797
798
799
  
  	mutex_lock(&cinode->lock_mutex);
  	if (!cinode->can_cache_brlcks) {
  		mutex_unlock(&cinode->lock_mutex);
507927606   Pavel Shilovsky   CIFS: Fix the VFS...
800
  		return rc;
4f6bcec91   Pavel Shilovsky   CIFS: Implement c...
801
802
803
804
805
806
807
808
  	}
  	rc = posix_lock_file_wait(file, flock);
  	mutex_unlock(&cinode->lock_mutex);
  	return rc;
  }
  
  static int
  cifs_push_mandatory_locks(struct cifsFileInfo *cfile)
85160e03a   Pavel Shilovsky   CIFS: Implement c...
809
810
811
812
813
  {
  	int xid, rc = 0, stored_rc;
  	struct cifsLockInfo *li, *tmp;
  	struct cifs_tcon *tcon;
  	struct cifsInodeInfo *cinode = CIFS_I(cfile->dentry->d_inode);
32b9aaf1a   Pavel Shilovsky   CIFS: Make cifs_p...
814
815
816
817
818
  	unsigned int num, max_num;
  	LOCKING_ANDX_RANGE *buf, *cur;
  	int types[] = {LOCKING_ANDX_LARGE_FILES,
  		       LOCKING_ANDX_SHARED_LOCK | LOCKING_ANDX_LARGE_FILES};
  	int i;
85160e03a   Pavel Shilovsky   CIFS: Implement c...
819
820
821
822
823
824
825
826
827
828
  
  	xid = GetXid();
  	tcon = tlink_tcon(cfile->tlink);
  
  	mutex_lock(&cinode->lock_mutex);
  	if (!cinode->can_cache_brlcks) {
  		mutex_unlock(&cinode->lock_mutex);
  		FreeXid(xid);
  		return rc;
  	}
32b9aaf1a   Pavel Shilovsky   CIFS: Make cifs_p...
829
830
831
832
833
834
835
836
837
838
839
840
841
842
843
844
845
846
847
848
849
850
851
852
853
854
855
856
857
858
859
860
861
862
863
864
865
  	max_num = (tcon->ses->server->maxBuf - sizeof(struct smb_hdr)) /
  		  sizeof(LOCKING_ANDX_RANGE);
  	buf = kzalloc(max_num * sizeof(LOCKING_ANDX_RANGE), GFP_KERNEL);
  	if (!buf) {
  		mutex_unlock(&cinode->lock_mutex);
  		FreeXid(xid);
  		return rc;
  	}
  
  	for (i = 0; i < 2; i++) {
  		cur = buf;
  		num = 0;
  		list_for_each_entry_safe(li, tmp, &cinode->llist, llist) {
  			if (li->type != types[i])
  				continue;
  			cur->Pid = cpu_to_le16(li->pid);
  			cur->LengthLow = cpu_to_le32((u32)li->length);
  			cur->LengthHigh = cpu_to_le32((u32)(li->length>>32));
  			cur->OffsetLow = cpu_to_le32((u32)li->offset);
  			cur->OffsetHigh = cpu_to_le32((u32)(li->offset>>32));
  			if (++num == max_num) {
  				stored_rc = cifs_lockv(xid, tcon, cfile->netfid,
  						       li->type, 0, num, buf);
  				if (stored_rc)
  					rc = stored_rc;
  				cur = buf;
  				num = 0;
  			} else
  				cur++;
  		}
  
  		if (num) {
  			stored_rc = cifs_lockv(xid, tcon, cfile->netfid,
  					       types[i], 0, num, buf);
  			if (stored_rc)
  				rc = stored_rc;
  		}
85160e03a   Pavel Shilovsky   CIFS: Implement c...
866
867
868
869
  	}
  
  	cinode->can_cache_brlcks = false;
  	mutex_unlock(&cinode->lock_mutex);
32b9aaf1a   Pavel Shilovsky   CIFS: Make cifs_p...
870
  	kfree(buf);
85160e03a   Pavel Shilovsky   CIFS: Implement c...
871
872
873
  	FreeXid(xid);
  	return rc;
  }
4f6bcec91   Pavel Shilovsky   CIFS: Implement c...
874
875
876
877
878
879
880
881
882
883
884
885
886
887
888
889
890
891
892
893
894
895
896
897
898
899
900
901
902
903
904
905
906
907
908
  /* copied from fs/locks.c with a name change */
  #define cifs_for_each_lock(inode, lockp) \
  	for (lockp = &inode->i_flock; *lockp != NULL; \
  	     lockp = &(*lockp)->fl_next)
  
  static int
  cifs_push_posix_locks(struct cifsFileInfo *cfile)
  {
  	struct cifsInodeInfo *cinode = CIFS_I(cfile->dentry->d_inode);
  	struct cifs_tcon *tcon = tlink_tcon(cfile->tlink);
  	struct file_lock *flock, **before;
  	struct cifsLockInfo *lck, *tmp;
  	int rc = 0, xid, type;
  	__u64 length;
  	struct list_head locks_to_send;
  
  	xid = GetXid();
  
  	mutex_lock(&cinode->lock_mutex);
  	if (!cinode->can_cache_brlcks) {
  		mutex_unlock(&cinode->lock_mutex);
  		FreeXid(xid);
  		return rc;
  	}
  
  	INIT_LIST_HEAD(&locks_to_send);
  
  	lock_flocks();
  	cifs_for_each_lock(cfile->dentry->d_inode, before) {
  		flock = *before;
  		length = 1 + flock->fl_end - flock->fl_start;
  		if (flock->fl_type == F_RDLCK || flock->fl_type == F_SHLCK)
  			type = CIFS_RDLCK;
  		else
  			type = CIFS_WRLCK;
a88b47077   Pavel Shilovsky   CIFS: Cleanup byt...
909
  		lck = cifs_lock_init(flock->fl_start, length, type,
4f6bcec91   Pavel Shilovsky   CIFS: Implement c...
910
911
912
913
914
915
916
917
918
919
920
921
922
923
924
925
926
927
928
929
930
931
932
933
934
935
936
937
938
939
940
941
942
943
944
945
946
947
948
949
950
951
952
953
954
955
956
  				     cfile->netfid);
  		if (!lck) {
  			rc = -ENOMEM;
  			goto send_locks;
  		}
  		lck->pid = flock->fl_pid;
  
  		list_add_tail(&lck->llist, &locks_to_send);
  	}
  
  send_locks:
  	unlock_flocks();
  
  	list_for_each_entry_safe(lck, tmp, &locks_to_send, llist) {
  		struct file_lock tmp_lock;
  		int stored_rc;
  
  		tmp_lock.fl_start = lck->offset;
  		stored_rc = CIFSSMBPosixLock(xid, tcon, lck->netfid, lck->pid,
  					     0, lck->length, &tmp_lock,
  					     lck->type, 0);
  		if (stored_rc)
  			rc = stored_rc;
  		list_del(&lck->llist);
  		kfree(lck);
  	}
  
  	cinode->can_cache_brlcks = false;
  	mutex_unlock(&cinode->lock_mutex);
  
  	FreeXid(xid);
  	return rc;
  }
  
  static int
  cifs_push_locks(struct cifsFileInfo *cfile)
  {
  	struct cifs_sb_info *cifs_sb = CIFS_SB(cfile->dentry->d_sb);
  	struct cifs_tcon *tcon = tlink_tcon(cfile->tlink);
  
  	if ((tcon->ses->capabilities & CAP_UNIX) &&
  	    (CIFS_UNIX_FCNTL_CAP & le64_to_cpu(tcon->fsUnixInfo.Capability)) &&
  	    ((cifs_sb->mnt_cifs_flags & CIFS_MOUNT_NOPOSIXBRL) == 0))
  		return cifs_push_posix_locks(cfile);
  
  	return cifs_push_mandatory_locks(cfile);
  }
03776f451   Pavel Shilovsky   CIFS: Simplify by...
957
958
959
  static void
  cifs_read_flock(struct file_lock *flock, __u8 *type, int *lock, int *unlock,
  		bool *wait_flag)
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
960
  {
03776f451   Pavel Shilovsky   CIFS: Simplify by...
961
  	if (flock->fl_flags & FL_POSIX)
b6b38f704   Joe Perches   [CIFS] Neaten cER...
962
  		cFYI(1, "Posix");
03776f451   Pavel Shilovsky   CIFS: Simplify by...
963
  	if (flock->fl_flags & FL_FLOCK)
b6b38f704   Joe Perches   [CIFS] Neaten cER...
964
  		cFYI(1, "Flock");
03776f451   Pavel Shilovsky   CIFS: Simplify by...
965
  	if (flock->fl_flags & FL_SLEEP) {
b6b38f704   Joe Perches   [CIFS] Neaten cER...
966
  		cFYI(1, "Blocking lock");
03776f451   Pavel Shilovsky   CIFS: Simplify by...
967
  		*wait_flag = true;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
968
  	}
03776f451   Pavel Shilovsky   CIFS: Simplify by...
969
  	if (flock->fl_flags & FL_ACCESS)
b6b38f704   Joe Perches   [CIFS] Neaten cER...
970
  		cFYI(1, "Process suspended by mandatory locking - "
03776f451   Pavel Shilovsky   CIFS: Simplify by...
971
972
  			"not implemented yet");
  	if (flock->fl_flags & FL_LEASE)
b6b38f704   Joe Perches   [CIFS] Neaten cER...
973
  		cFYI(1, "Lease on file - not implemented yet");
03776f451   Pavel Shilovsky   CIFS: Simplify by...
974
  	if (flock->fl_flags &
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
975
  	    (~(FL_POSIX | FL_FLOCK | FL_SLEEP | FL_ACCESS | FL_LEASE)))
03776f451   Pavel Shilovsky   CIFS: Simplify by...
976
  		cFYI(1, "Unknown lock flags 0x%x", flock->fl_flags);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
977

03776f451   Pavel Shilovsky   CIFS: Simplify by...
978
979
  	*type = LOCKING_ANDX_LARGE_FILES;
  	if (flock->fl_type == F_WRLCK) {
b6b38f704   Joe Perches   [CIFS] Neaten cER...
980
  		cFYI(1, "F_WRLCK ");
03776f451   Pavel Shilovsky   CIFS: Simplify by...
981
982
  		*lock = 1;
  	} else if (flock->fl_type == F_UNLCK) {
b6b38f704   Joe Perches   [CIFS] Neaten cER...
983
  		cFYI(1, "F_UNLCK");
03776f451   Pavel Shilovsky   CIFS: Simplify by...
984
985
986
  		*unlock = 1;
  		/* Check if unlock includes more than one lock range */
  	} else if (flock->fl_type == F_RDLCK) {
b6b38f704   Joe Perches   [CIFS] Neaten cER...
987
  		cFYI(1, "F_RDLCK");
03776f451   Pavel Shilovsky   CIFS: Simplify by...
988
989
990
  		*type |= LOCKING_ANDX_SHARED_LOCK;
  		*lock = 1;
  	} else if (flock->fl_type == F_EXLCK) {
b6b38f704   Joe Perches   [CIFS] Neaten cER...
991
  		cFYI(1, "F_EXLCK");
03776f451   Pavel Shilovsky   CIFS: Simplify by...
992
993
  		*lock = 1;
  	} else if (flock->fl_type == F_SHLCK) {
b6b38f704   Joe Perches   [CIFS] Neaten cER...
994
  		cFYI(1, "F_SHLCK");
03776f451   Pavel Shilovsky   CIFS: Simplify by...
995
996
  		*type |= LOCKING_ANDX_SHARED_LOCK;
  		*lock = 1;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
997
  	} else
b6b38f704   Joe Perches   [CIFS] Neaten cER...
998
  		cFYI(1, "Unknown type of lock");
03776f451   Pavel Shilovsky   CIFS: Simplify by...
999
  }
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
1000

03776f451   Pavel Shilovsky   CIFS: Simplify by...
1001
  static int
4f6bcec91   Pavel Shilovsky   CIFS: Implement c...
1002
  cifs_getlk(struct file *file, struct file_lock *flock, __u8 type,
03776f451   Pavel Shilovsky   CIFS: Simplify by...
1003
1004
1005
1006
  	   bool wait_flag, bool posix_lck, int xid)
  {
  	int rc = 0;
  	__u64 length = 1 + flock->fl_end - flock->fl_start;
4f6bcec91   Pavel Shilovsky   CIFS: Implement c...
1007
1008
  	struct cifsFileInfo *cfile = (struct cifsFileInfo *)file->private_data;
  	struct cifs_tcon *tcon = tlink_tcon(cfile->tlink);
85160e03a   Pavel Shilovsky   CIFS: Implement c...
1009
  	struct cifsInodeInfo *cinode = CIFS_I(cfile->dentry->d_inode);
03776f451   Pavel Shilovsky   CIFS: Simplify by...
1010
  	__u16 netfid = cfile->netfid;
f05337c6a   Pavel Shilovsky   not overwriting f...
1011

03776f451   Pavel Shilovsky   CIFS: Simplify by...
1012
1013
  	if (posix_lck) {
  		int posix_lock_type;
4f6bcec91   Pavel Shilovsky   CIFS: Implement c...
1014
1015
1016
1017
  
  		rc = cifs_posix_lock_test(file, flock);
  		if (!rc)
  			return rc;
03776f451   Pavel Shilovsky   CIFS: Simplify by...
1018
1019
1020
1021
  		if (type & LOCKING_ANDX_SHARED_LOCK)
  			posix_lock_type = CIFS_RDLCK;
  		else
  			posix_lock_type = CIFS_WRLCK;
4f6bcec91   Pavel Shilovsky   CIFS: Implement c...
1022
1023
1024
  		rc = CIFSSMBPosixLock(xid, tcon, netfid, current->tgid,
  				      1 /* get */, length, flock,
  				      posix_lock_type, wait_flag);
03776f451   Pavel Shilovsky   CIFS: Simplify by...
1025
1026
  		return rc;
  	}
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
1027

85160e03a   Pavel Shilovsky   CIFS: Implement c...
1028
1029
1030
1031
  	rc = cifs_lock_test(cinode, flock->fl_start, length, type, netfid,
  			    flock);
  	if (!rc)
  		return rc;
03776f451   Pavel Shilovsky   CIFS: Simplify by...
1032
1033
1034
1035
1036
1037
1038
1039
1040
1041
1042
  	/* BB we could chain these into one lock request BB */
  	rc = CIFSSMBLock(xid, tcon, netfid, current->tgid, length,
  			 flock->fl_start, 0, 1, type, 0, 0);
  	if (rc == 0) {
  		rc = CIFSSMBLock(xid, tcon, netfid, current->tgid,
  				 length, flock->fl_start, 1, 0,
  				 type, 0, 0);
  		flock->fl_type = F_UNLCK;
  		if (rc != 0)
  			cERROR(1, "Error unlocking previously locked "
  				   "range %d during test of lock", rc);
a88b47077   Pavel Shilovsky   CIFS: Cleanup byt...
1043
  		return 0;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
1044
  	}
7ee1af765   Jeremy Allison   [CIFS]
1045

03776f451   Pavel Shilovsky   CIFS: Simplify by...
1046
1047
  	if (type & LOCKING_ANDX_SHARED_LOCK) {
  		flock->fl_type = F_WRLCK;
a88b47077   Pavel Shilovsky   CIFS: Cleanup byt...
1048
  		return 0;
7ee1af765   Jeremy Allison   [CIFS]
1049
  	}
03776f451   Pavel Shilovsky   CIFS: Simplify by...
1050
1051
1052
1053
1054
1055
1056
1057
1058
1059
1060
1061
1062
1063
  	rc = CIFSSMBLock(xid, tcon, netfid, current->tgid, length,
  			 flock->fl_start, 0, 1,
  			 type | LOCKING_ANDX_SHARED_LOCK, 0, 0);
  	if (rc == 0) {
  		rc = CIFSSMBLock(xid, tcon, netfid, current->tgid,
  				 length, flock->fl_start, 1, 0,
  				 type | LOCKING_ANDX_SHARED_LOCK,
  				 0, 0);
  		flock->fl_type = F_RDLCK;
  		if (rc != 0)
  			cERROR(1, "Error unlocking previously locked "
  				  "range %d during test of lock", rc);
  	} else
  		flock->fl_type = F_WRLCK;
a88b47077   Pavel Shilovsky   CIFS: Cleanup byt...
1064
  	return 0;
03776f451   Pavel Shilovsky   CIFS: Simplify by...
1065
  }
9ee305b70   Pavel Shilovsky   CIFS: Send as man...
1066
1067
1068
1069
1070
1071
1072
1073
1074
1075
1076
1077
1078
1079
1080
1081
1082
1083
1084
1085
1086
1087
1088
1089
1090
1091
1092
1093
1094
1095
1096
1097
1098
1099
1100
1101
1102
1103
1104
1105
1106
1107
1108
1109
1110
1111
1112
1113
1114
1115
1116
1117
1118
1119
1120
1121
1122
1123
1124
1125
1126
1127
1128
1129
1130
1131
1132
1133
1134
1135
1136
1137
1138
1139
1140
1141
1142
1143
1144
1145
1146
1147
1148
1149
1150
1151
1152
1153
1154
1155
1156
1157
1158
1159
1160
1161
1162
1163
1164
1165
1166
1167
1168
1169
1170
1171
1172
1173
1174
1175
1176
1177
1178
1179
1180
1181
1182
1183
1184
1185
1186
  static void
  cifs_move_llist(struct list_head *source, struct list_head *dest)
  {
  	struct list_head *li, *tmp;
  	list_for_each_safe(li, tmp, source)
  		list_move(li, dest);
  }
  
  static void
  cifs_free_llist(struct list_head *llist)
  {
  	struct cifsLockInfo *li, *tmp;
  	list_for_each_entry_safe(li, tmp, llist, llist) {
  		cifs_del_lock_waiters(li);
  		list_del(&li->llist);
  		kfree(li);
  	}
  }
  
  static int
  cifs_unlock_range(struct cifsFileInfo *cfile, struct file_lock *flock, int xid)
  {
  	int rc = 0, stored_rc;
  	int types[] = {LOCKING_ANDX_LARGE_FILES,
  		       LOCKING_ANDX_SHARED_LOCK | LOCKING_ANDX_LARGE_FILES};
  	unsigned int i;
  	unsigned int max_num, num;
  	LOCKING_ANDX_RANGE *buf, *cur;
  	struct cifs_tcon *tcon = tlink_tcon(cfile->tlink);
  	struct cifsInodeInfo *cinode = CIFS_I(cfile->dentry->d_inode);
  	struct cifsLockInfo *li, *tmp;
  	__u64 length = 1 + flock->fl_end - flock->fl_start;
  	struct list_head tmp_llist;
  
  	INIT_LIST_HEAD(&tmp_llist);
  
  	max_num = (tcon->ses->server->maxBuf - sizeof(struct smb_hdr)) /
  		  sizeof(LOCKING_ANDX_RANGE);
  	buf = kzalloc(max_num * sizeof(LOCKING_ANDX_RANGE), GFP_KERNEL);
  	if (!buf)
  		return -ENOMEM;
  
  	mutex_lock(&cinode->lock_mutex);
  	for (i = 0; i < 2; i++) {
  		cur = buf;
  		num = 0;
  		list_for_each_entry_safe(li, tmp, &cinode->llist, llist) {
  			if (flock->fl_start > li->offset ||
  			    (flock->fl_start + length) <
  			    (li->offset + li->length))
  				continue;
  			if (current->tgid != li->pid)
  				continue;
  			if (cfile->netfid != li->netfid)
  				continue;
  			if (types[i] != li->type)
  				continue;
  			if (!cinode->can_cache_brlcks) {
  				cur->Pid = cpu_to_le16(li->pid);
  				cur->LengthLow = cpu_to_le32((u32)li->length);
  				cur->LengthHigh =
  					cpu_to_le32((u32)(li->length>>32));
  				cur->OffsetLow = cpu_to_le32((u32)li->offset);
  				cur->OffsetHigh =
  					cpu_to_le32((u32)(li->offset>>32));
  				/*
  				 * We need to save a lock here to let us add
  				 * it again to the inode list if the unlock
  				 * range request fails on the server.
  				 */
  				list_move(&li->llist, &tmp_llist);
  				if (++num == max_num) {
  					stored_rc = cifs_lockv(xid, tcon,
  							       cfile->netfid,
  							       li->type, num,
  							       0, buf);
  					if (stored_rc) {
  						/*
  						 * We failed on the unlock range
  						 * request - add all locks from
  						 * the tmp list to the head of
  						 * the inode list.
  						 */
  						cifs_move_llist(&tmp_llist,
  								&cinode->llist);
  						rc = stored_rc;
  					} else
  						/*
  						 * The unlock range request
  						 * succeed - free the tmp list.
  						 */
  						cifs_free_llist(&tmp_llist);
  					cur = buf;
  					num = 0;
  				} else
  					cur++;
  			} else {
  				/*
  				 * We can cache brlock requests - simply remove
  				 * a lock from the inode list.
  				 */
  				list_del(&li->llist);
  				cifs_del_lock_waiters(li);
  				kfree(li);
  			}
  		}
  		if (num) {
  			stored_rc = cifs_lockv(xid, tcon, cfile->netfid,
  					       types[i], num, 0, buf);
  			if (stored_rc) {
  				cifs_move_llist(&tmp_llist, &cinode->llist);
  				rc = stored_rc;
  			} else
  				cifs_free_llist(&tmp_llist);
  		}
  	}
  
  	mutex_unlock(&cinode->lock_mutex);
  	kfree(buf);
  	return rc;
  }
03776f451   Pavel Shilovsky   CIFS: Simplify by...
1187
1188
1189
1190
1191
1192
1193
1194
  static int
  cifs_setlk(struct file *file,  struct file_lock *flock, __u8 type,
  	   bool wait_flag, bool posix_lck, int lock, int unlock, int xid)
  {
  	int rc = 0;
  	__u64 length = 1 + flock->fl_end - flock->fl_start;
  	struct cifsFileInfo *cfile = (struct cifsFileInfo *)file->private_data;
  	struct cifs_tcon *tcon = tlink_tcon(cfile->tlink);
d59dad2be   Pavel Shilovsky   CIFS: Move byte r...
1195
  	struct cifsInodeInfo *cinode = CIFS_I(file->f_path.dentry->d_inode);
03776f451   Pavel Shilovsky   CIFS: Simplify by...
1196
1197
1198
  	__u16 netfid = cfile->netfid;
  
  	if (posix_lck) {
08547b036   Steve French   [CIFS] Add posix ...
1199
  		int posix_lock_type;
4f6bcec91   Pavel Shilovsky   CIFS: Implement c...
1200
1201
1202
1203
  
  		rc = cifs_posix_lock_set(file, flock);
  		if (!rc || rc < 0)
  			return rc;
03776f451   Pavel Shilovsky   CIFS: Simplify by...
1204
  		if (type & LOCKING_ANDX_SHARED_LOCK)
08547b036   Steve French   [CIFS] Add posix ...
1205
1206
1207
  			posix_lock_type = CIFS_RDLCK;
  		else
  			posix_lock_type = CIFS_WRLCK;
50c2f7538   Steve French   [CIFS] whitespace...
1208

03776f451   Pavel Shilovsky   CIFS: Simplify by...
1209
  		if (unlock == 1)
beb84dc81   Steve French   [CIFS] Set correc...
1210
  			posix_lock_type = CIFS_UNLCK;
7ee1af765   Jeremy Allison   [CIFS]
1211

4f6bcec91   Pavel Shilovsky   CIFS: Implement c...
1212
1213
1214
  		rc = CIFSSMBPosixLock(xid, tcon, netfid, current->tgid,
  				      0 /* set */, length, flock,
  				      posix_lock_type, wait_flag);
03776f451   Pavel Shilovsky   CIFS: Simplify by...
1215
1216
  		goto out;
  	}
7ee1af765   Jeremy Allison   [CIFS]
1217

03776f451   Pavel Shilovsky   CIFS: Simplify by...
1218
  	if (lock) {
161ebf9fc   Pavel Shilovsky   CIFS: Simplify se...
1219
  		struct cifsLockInfo *lock;
a88b47077   Pavel Shilovsky   CIFS: Cleanup byt...
1220
  		lock = cifs_lock_init(flock->fl_start, length, type, netfid);
161ebf9fc   Pavel Shilovsky   CIFS: Simplify se...
1221
1222
1223
1224
  		if (!lock)
  			return -ENOMEM;
  
  		rc = cifs_lock_add_if(cinode, lock, wait_flag);
85160e03a   Pavel Shilovsky   CIFS: Implement c...
1225
  		if (rc < 0)
161ebf9fc   Pavel Shilovsky   CIFS: Simplify se...
1226
1227
  			kfree(lock);
  		if (rc <= 0)
85160e03a   Pavel Shilovsky   CIFS: Implement c...
1228
  			goto out;
03776f451   Pavel Shilovsky   CIFS: Simplify by...
1229
  		rc = CIFSSMBLock(xid, tcon, netfid, current->tgid, length,
85160e03a   Pavel Shilovsky   CIFS: Implement c...
1230
  				 flock->fl_start, 0, 1, type, wait_flag, 0);
161ebf9fc   Pavel Shilovsky   CIFS: Simplify se...
1231
1232
1233
  		if (rc) {
  			kfree(lock);
  			goto out;
03776f451   Pavel Shilovsky   CIFS: Simplify by...
1234
  		}
161ebf9fc   Pavel Shilovsky   CIFS: Simplify se...
1235
1236
  
  		cifs_lock_add(cinode, lock);
9ee305b70   Pavel Shilovsky   CIFS: Send as man...
1237
1238
  	} else if (unlock)
  		rc = cifs_unlock_range(cfile, flock, xid);
03776f451   Pavel Shilovsky   CIFS: Simplify by...
1239

03776f451   Pavel Shilovsky   CIFS: Simplify by...
1240
1241
1242
1243
1244
1245
1246
1247
1248
1249
1250
1251
1252
1253
1254
1255
1256
1257
1258
1259
1260
1261
1262
1263
1264
1265
1266
1267
1268
1269
1270
1271
1272
1273
1274
1275
1276
1277
1278
1279
1280
1281
1282
  out:
  	if (flock->fl_flags & FL_POSIX)
  		posix_lock_file_wait(file, flock);
  	return rc;
  }
  
  int cifs_lock(struct file *file, int cmd, struct file_lock *flock)
  {
  	int rc, xid;
  	int lock = 0, unlock = 0;
  	bool wait_flag = false;
  	bool posix_lck = false;
  	struct cifs_sb_info *cifs_sb;
  	struct cifs_tcon *tcon;
  	struct cifsInodeInfo *cinode;
  	struct cifsFileInfo *cfile;
  	__u16 netfid;
  	__u8 type;
  
  	rc = -EACCES;
  	xid = GetXid();
  
  	cFYI(1, "Lock parm: 0x%x flockflags: 0x%x flocktype: 0x%x start: %lld "
  		"end: %lld", cmd, flock->fl_flags, flock->fl_type,
  		flock->fl_start, flock->fl_end);
  
  	cifs_read_flock(flock, &type, &lock, &unlock, &wait_flag);
  
  	cifs_sb = CIFS_SB(file->f_path.dentry->d_sb);
  	cfile = (struct cifsFileInfo *)file->private_data;
  	tcon = tlink_tcon(cfile->tlink);
  	netfid = cfile->netfid;
  	cinode = CIFS_I(file->f_path.dentry->d_inode);
  
  	if ((tcon->ses->capabilities & CAP_UNIX) &&
  	    (CIFS_UNIX_FCNTL_CAP & le64_to_cpu(tcon->fsUnixInfo.Capability)) &&
  	    ((cifs_sb->mnt_cifs_flags & CIFS_MOUNT_NOPOSIXBRL) == 0))
  		posix_lck = true;
  	/*
  	 * BB add code here to normalize offset and length to account for
  	 * negative length which we can not accept over the wire.
  	 */
  	if (IS_GETLK(cmd)) {
4f6bcec91   Pavel Shilovsky   CIFS: Implement c...
1283
  		rc = cifs_getlk(file, flock, type, wait_flag, posix_lck, xid);
03776f451   Pavel Shilovsky   CIFS: Simplify by...
1284
1285
1286
1287
1288
1289
1290
1291
1292
1293
1294
  		FreeXid(xid);
  		return rc;
  	}
  
  	if (!lock && !unlock) {
  		/*
  		 * if no lock or unlock then nothing to do since we do not
  		 * know what it is
  		 */
  		FreeXid(xid);
  		return -EOPNOTSUPP;
7ee1af765   Jeremy Allison   [CIFS]
1295
  	}
03776f451   Pavel Shilovsky   CIFS: Simplify by...
1296
1297
  	rc = cifs_setlk(file, flock, type, wait_flag, posix_lck, lock, unlock,
  			xid);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
1298
1299
1300
  	FreeXid(xid);
  	return rc;
  }
fbec9ab95   Jeff Layton   cifs: vary timeou...
1301
  /* update the file size (if needed) after a write */
72432ffcf   Pavel Shilovsky   CIFS: Implement c...
1302
  void
fbec9ab95   Jeff Layton   cifs: vary timeou...
1303
1304
1305
1306
1307
1308
1309
1310
  cifs_update_eof(struct cifsInodeInfo *cifsi, loff_t offset,
  		      unsigned int bytes_written)
  {
  	loff_t end_of_write = offset + bytes_written;
  
  	if (end_of_write > cifsi->server_eof)
  		cifsi->server_eof = end_of_write;
  }
fa2989f44   Pavel Shilovsky   CIFS: Use pid sav...
1311
  static ssize_t cifs_write(struct cifsFileInfo *open_file, __u32 pid,
7da4b49a0   Jeff Layton   cifs: cifs_write ...
1312
1313
  			  const char *write_data, size_t write_size,
  			  loff_t *poffset)
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
1314
1315
1316
1317
1318
  {
  	int rc = 0;
  	unsigned int bytes_written = 0;
  	unsigned int total_written;
  	struct cifs_sb_info *cifs_sb;
96daf2b09   Steve French   [CIFS] Rename thr...
1319
  	struct cifs_tcon *pTcon;
7749981ec   Jeff Layton   cifs: remove code...
1320
  	int xid;
7da4b49a0   Jeff Layton   cifs: cifs_write ...
1321
1322
  	struct dentry *dentry = open_file->dentry;
  	struct cifsInodeInfo *cifsi = CIFS_I(dentry->d_inode);
fa2989f44   Pavel Shilovsky   CIFS: Use pid sav...
1323
  	struct cifs_io_parms io_parms;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
1324

7da4b49a0   Jeff Layton   cifs: cifs_write ...
1325
  	cifs_sb = CIFS_SB(dentry->d_sb);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
1326

b6b38f704   Joe Perches   [CIFS] Neaten cER...
1327
  	cFYI(1, "write %zd bytes to offset %lld of %s", write_size,
7da4b49a0   Jeff Layton   cifs: cifs_write ...
1328
  	   *poffset, dentry->d_name.name);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
1329

13cfb7334   Jeff Layton   cifs: have cifsFi...
1330
  	pTcon = tlink_tcon(open_file->tlink);
50c2f7538   Steve French   [CIFS] whitespace...
1331

1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
1332
  	xid = GetXid();
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
1333

1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
1334
1335
1336
1337
  	for (total_written = 0; write_size > total_written;
  	     total_written += bytes_written) {
  		rc = -EAGAIN;
  		while (rc == -EAGAIN) {
ca83ce3d5   Jeff Layton   cifs: don't allow...
1338
1339
  			struct kvec iov[2];
  			unsigned int len;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
1340
  			if (open_file->invalidHandle) {
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
1341
1342
  				/* we could deadlock if we called
  				   filemap_fdatawait from here so tell
fb8c4b14d   Steve French   [CIFS] whitespace...
1343
  				   reopen_file not to flush data to
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
1344
  				   server now */
15886177e   Jeff Layton   cifs: clean up ci...
1345
  				rc = cifs_reopen_file(open_file, false);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
1346
1347
1348
  				if (rc != 0)
  					break;
  			}
ca83ce3d5   Jeff Layton   cifs: don't allow...
1349
1350
1351
1352
1353
1354
  
  			len = min((size_t)cifs_sb->wsize,
  				  write_size - total_written);
  			/* iov[0] is reserved for smb header */
  			iov[1].iov_base = (char *)write_data + total_written;
  			iov[1].iov_len = len;
fa2989f44   Pavel Shilovsky   CIFS: Use pid sav...
1355
1356
1357
1358
1359
1360
1361
  			io_parms.netfid = open_file->netfid;
  			io_parms.pid = pid;
  			io_parms.tcon = pTcon;
  			io_parms.offset = *poffset;
  			io_parms.length = len;
  			rc = CIFSSMBWrite2(xid, &io_parms, &bytes_written, iov,
  					   1, 0);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
1362
1363
1364
1365
1366
1367
1368
1369
  		}
  		if (rc || (bytes_written == 0)) {
  			if (total_written)
  				break;
  			else {
  				FreeXid(xid);
  				return rc;
  			}
fbec9ab95   Jeff Layton   cifs: vary timeou...
1370
1371
  		} else {
  			cifs_update_eof(cifsi, *poffset, bytes_written);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
1372
  			*poffset += bytes_written;
fbec9ab95   Jeff Layton   cifs: vary timeou...
1373
  		}
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
1374
  	}
a45443475   Steve French   CIFS: Reduce CONF...
1375
  	cifs_stats_bytes_written(pTcon, total_written);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
1376

7da4b49a0   Jeff Layton   cifs: cifs_write ...
1377
1378
1379
1380
1381
  	if (total_written > 0) {
  		spin_lock(&dentry->d_inode->i_lock);
  		if (*poffset > dentry->d_inode->i_size)
  			i_size_write(dentry->d_inode, *poffset);
  		spin_unlock(&dentry->d_inode->i_lock);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
1382
  	}
7da4b49a0   Jeff Layton   cifs: cifs_write ...
1383
  	mark_inode_dirty_sync(dentry->d_inode);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
1384
1385
1386
  	FreeXid(xid);
  	return total_written;
  }
6508d904e   Jeff Layton   cifs: have find_r...
1387
1388
  struct cifsFileInfo *find_readable_file(struct cifsInodeInfo *cifs_inode,
  					bool fsuid_only)
630f3f0c4   Steve French   [CIFS] acl suppor...
1389
1390
  {
  	struct cifsFileInfo *open_file = NULL;
6508d904e   Jeff Layton   cifs: have find_r...
1391
1392
1393
1394
1395
  	struct cifs_sb_info *cifs_sb = CIFS_SB(cifs_inode->vfs_inode.i_sb);
  
  	/* only filter by fsuid on multiuser mounts */
  	if (!(cifs_sb->mnt_cifs_flags & CIFS_MOUNT_MULTIUSER))
  		fsuid_only = false;
630f3f0c4   Steve French   [CIFS] acl suppor...
1396

4477288a1   Jeff Layton   cifs: convert Glo...
1397
  	spin_lock(&cifs_file_list_lock);
630f3f0c4   Steve French   [CIFS] acl suppor...
1398
1399
1400
1401
  	/* we could simply get the first_list_entry since write-only entries
  	   are always at the end of the list but since the first entry might
  	   have a close pending, we go through the whole list */
  	list_for_each_entry(open_file, &cifs_inode->openFileList, flist) {
6508d904e   Jeff Layton   cifs: have find_r...
1402
1403
  		if (fsuid_only && open_file->uid != current_fsuid())
  			continue;
2e396b83f   Jeff Layton   cifs: eliminate p...
1404
  		if (OPEN_FMODE(open_file->f_flags) & FMODE_READ) {
630f3f0c4   Steve French   [CIFS] acl suppor...
1405
1406
1407
  			if (!open_file->invalidHandle) {
  				/* found a good file */
  				/* lock it so it will not be closed on us */
6ab409b53   Dave Kleikamp   cifs: Replace wrt...
1408
  				cifsFileInfo_get(open_file);
4477288a1   Jeff Layton   cifs: convert Glo...
1409
  				spin_unlock(&cifs_file_list_lock);
630f3f0c4   Steve French   [CIFS] acl suppor...
1410
1411
1412
1413
1414
1415
1416
  				return open_file;
  			} /* else might as well continue, and look for
  			     another, or simply have the caller reopen it
  			     again rather than trying to fix this handle */
  		} else /* write only file */
  			break; /* write only files are last so must be done */
  	}
4477288a1   Jeff Layton   cifs: convert Glo...
1417
  	spin_unlock(&cifs_file_list_lock);
630f3f0c4   Steve French   [CIFS] acl suppor...
1418
1419
  	return NULL;
  }
630f3f0c4   Steve French   [CIFS] acl suppor...
1420

6508d904e   Jeff Layton   cifs: have find_r...
1421
1422
  struct cifsFileInfo *find_writable_file(struct cifsInodeInfo *cifs_inode,
  					bool fsuid_only)
6148a742b   Steve French   CIFS: Create rout...
1423
1424
  {
  	struct cifsFileInfo *open_file;
d38922949   Jeff Layton   cifs: dereferenci...
1425
  	struct cifs_sb_info *cifs_sb;
2846d3864   Jeff Layton   cifs: have find_w...
1426
  	bool any_available = false;
dd99cd803   Steve French   [CIFS] cleanup sp...
1427
  	int rc;
6148a742b   Steve French   CIFS: Create rout...
1428

60808233f   Steve French   [CIFS] Readdir fi...
1429
1430
1431
  	/* Having a null inode here (because mapping->host was set to zero by
  	the VFS or MM) should not happen but we had reports of on oops (due to
  	it being zero) during stress testcases so we need to check for it */
fb8c4b14d   Steve French   [CIFS] whitespace...
1432
  	if (cifs_inode == NULL) {
b6b38f704   Joe Perches   [CIFS] Neaten cER...
1433
  		cERROR(1, "Null inode passed to cifs_writeable_file");
60808233f   Steve French   [CIFS] Readdir fi...
1434
1435
1436
  		dump_stack();
  		return NULL;
  	}
d38922949   Jeff Layton   cifs: dereferenci...
1437
  	cifs_sb = CIFS_SB(cifs_inode->vfs_inode.i_sb);
6508d904e   Jeff Layton   cifs: have find_r...
1438
1439
1440
  	/* only filter by fsuid on multiuser mounts */
  	if (!(cifs_sb->mnt_cifs_flags & CIFS_MOUNT_MULTIUSER))
  		fsuid_only = false;
4477288a1   Jeff Layton   cifs: convert Glo...
1441
  	spin_lock(&cifs_file_list_lock);
9b22b0b72   Steve French   [CIFS] Reduce cha...
1442
  refind_writable:
6148a742b   Steve French   CIFS: Create rout...
1443
  	list_for_each_entry(open_file, &cifs_inode->openFileList, flist) {
6508d904e   Jeff Layton   cifs: have find_r...
1444
1445
1446
  		if (!any_available && open_file->pid != current->tgid)
  			continue;
  		if (fsuid_only && open_file->uid != current_fsuid())
6148a742b   Steve French   CIFS: Create rout...
1447
  			continue;
2e396b83f   Jeff Layton   cifs: eliminate p...
1448
  		if (OPEN_FMODE(open_file->f_flags) & FMODE_WRITE) {
6ab409b53   Dave Kleikamp   cifs: Replace wrt...
1449
  			cifsFileInfo_get(open_file);
9b22b0b72   Steve French   [CIFS] Reduce cha...
1450
1451
1452
  
  			if (!open_file->invalidHandle) {
  				/* found a good writable file */
4477288a1   Jeff Layton   cifs: convert Glo...
1453
  				spin_unlock(&cifs_file_list_lock);
9b22b0b72   Steve French   [CIFS] Reduce cha...
1454
1455
  				return open_file;
  			}
8840dee9d   Steve French   [CIFS] minor chec...
1456

4477288a1   Jeff Layton   cifs: convert Glo...
1457
  			spin_unlock(&cifs_file_list_lock);
cdff08e76   Steve French   [CIFS] move close...
1458

9b22b0b72   Steve French   [CIFS] Reduce cha...
1459
  			/* Had to unlock since following call can block */
15886177e   Jeff Layton   cifs: clean up ci...
1460
  			rc = cifs_reopen_file(open_file, false);
cdff08e76   Steve French   [CIFS] move close...
1461
1462
  			if (!rc)
  				return open_file;
9b22b0b72   Steve French   [CIFS] Reduce cha...
1463

cdff08e76   Steve French   [CIFS] move close...
1464
  			/* if it fails, try another handle if possible */
b6b38f704   Joe Perches   [CIFS] Neaten cER...
1465
  			cFYI(1, "wp failed on reopen file");
6ab409b53   Dave Kleikamp   cifs: Replace wrt...
1466
  			cifsFileInfo_put(open_file);
8840dee9d   Steve French   [CIFS] minor chec...
1467

cdff08e76   Steve French   [CIFS] move close...
1468
  			spin_lock(&cifs_file_list_lock);
9b22b0b72   Steve French   [CIFS] Reduce cha...
1469
1470
1471
1472
1473
1474
1475
  			/* else we simply continue to the next entry. Thus
  			   we do not loop on reopen errors.  If we
  			   can not reopen the file, for example if we
  			   reconnected to a server with another client
  			   racing to delete or lock the file we would not
  			   make progress if we restarted before the beginning
  			   of the loop here. */
6148a742b   Steve French   CIFS: Create rout...
1476
1477
  		}
  	}
2846d3864   Jeff Layton   cifs: have find_w...
1478
1479
1480
1481
1482
  	/* couldn't find useable FH with same pid, try any available */
  	if (!any_available) {
  		any_available = true;
  		goto refind_writable;
  	}
4477288a1   Jeff Layton   cifs: convert Glo...
1483
  	spin_unlock(&cifs_file_list_lock);
6148a742b   Steve French   CIFS: Create rout...
1484
1485
  	return NULL;
  }
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
1486
1487
1488
1489
1490
1491
1492
  static int cifs_partialpagewrite(struct page *page, unsigned from, unsigned to)
  {
  	struct address_space *mapping = page->mapping;
  	loff_t offset = (loff_t)page->index << PAGE_CACHE_SHIFT;
  	char *write_data;
  	int rc = -EFAULT;
  	int bytes_written = 0;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
1493
  	struct inode *inode;
6148a742b   Steve French   CIFS: Create rout...
1494
  	struct cifsFileInfo *open_file;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
1495
1496
1497
1498
1499
  
  	if (!mapping || !mapping->host)
  		return -EFAULT;
  
  	inode = page->mapping->host;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
1500
1501
1502
1503
1504
1505
1506
1507
1508
1509
1510
1511
1512
1513
1514
1515
1516
1517
  
  	offset += (loff_t)from;
  	write_data = kmap(page);
  	write_data += from;
  
  	if ((to > PAGE_CACHE_SIZE) || (from > to)) {
  		kunmap(page);
  		return -EIO;
  	}
  
  	/* racing with truncate? */
  	if (offset > mapping->host->i_size) {
  		kunmap(page);
  		return 0; /* don't care */
  	}
  
  	/* check to make sure that we are not extending the file */
  	if (mapping->host->i_size - offset < (loff_t)to)
fb8c4b14d   Steve French   [CIFS] whitespace...
1518
  		to = (unsigned)(mapping->host->i_size - offset);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
1519

6508d904e   Jeff Layton   cifs: have find_r...
1520
  	open_file = find_writable_file(CIFS_I(mapping->host), false);
6148a742b   Steve French   CIFS: Create rout...
1521
  	if (open_file) {
fa2989f44   Pavel Shilovsky   CIFS: Use pid sav...
1522
1523
  		bytes_written = cifs_write(open_file, open_file->pid,
  					   write_data, to - from, &offset);
6ab409b53   Dave Kleikamp   cifs: Replace wrt...
1524
  		cifsFileInfo_put(open_file);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
1525
  		/* Does mm or vfs already set times? */
6148a742b   Steve French   CIFS: Create rout...
1526
  		inode->i_atime = inode->i_mtime = current_fs_time(inode->i_sb);
bb5a9a04d   Steve French   [CIFS] cifs_parti...
1527
  		if ((bytes_written > 0) && (offset))
6148a742b   Steve French   CIFS: Create rout...
1528
  			rc = 0;
bb5a9a04d   Steve French   [CIFS] cifs_parti...
1529
1530
  		else if (bytes_written < 0)
  			rc = bytes_written;
6148a742b   Steve French   CIFS: Create rout...
1531
  	} else {
b6b38f704   Joe Perches   [CIFS] Neaten cER...
1532
  		cFYI(1, "No writeable filehandles for inode");
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
1533
1534
1535
1536
1537
1538
  		rc = -EIO;
  	}
  
  	kunmap(page);
  	return rc;
  }
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
1539
  static int cifs_writepages(struct address_space *mapping,
37c0eb467   Steve French   CIFS: implement c...
1540
  			   struct writeback_control *wbc)
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
1541
  {
c3d17b63e   Jeff Layton   cifs: convert cif...
1542
1543
1544
1545
  	struct cifs_sb_info *cifs_sb = CIFS_SB(mapping->host->i_sb);
  	bool done = false, scanned = false, range_whole = false;
  	pgoff_t end, index;
  	struct cifs_writedata *wdata;
37c0eb467   Steve French   CIFS: implement c...
1546
  	struct page *page;
37c0eb467   Steve French   CIFS: implement c...
1547
  	int rc = 0;
50c2f7538   Steve French   [CIFS] whitespace...
1548

37c0eb467   Steve French   CIFS: implement c...
1549
  	/*
c3d17b63e   Jeff Layton   cifs: convert cif...
1550
  	 * If wsize is smaller than the page cache size, default to writing
37c0eb467   Steve French   CIFS: implement c...
1551
1552
1553
1554
  	 * one page at a time via cifs_writepage
  	 */
  	if (cifs_sb->wsize < PAGE_CACHE_SIZE)
  		return generic_writepages(mapping, wbc);
111ebb6e6   OGAWA Hirofumi   [PATCH] writeback...
1555
  	if (wbc->range_cyclic) {
37c0eb467   Steve French   CIFS: implement c...
1556
  		index = mapping->writeback_index; /* Start from prev offset */
111ebb6e6   OGAWA Hirofumi   [PATCH] writeback...
1557
1558
1559
1560
1561
  		end = -1;
  	} else {
  		index = wbc->range_start >> PAGE_CACHE_SHIFT;
  		end = wbc->range_end >> PAGE_CACHE_SHIFT;
  		if (wbc->range_start == 0 && wbc->range_end == LLONG_MAX)
c3d17b63e   Jeff Layton   cifs: convert cif...
1562
1563
  			range_whole = true;
  		scanned = true;
37c0eb467   Steve French   CIFS: implement c...
1564
1565
  	}
  retry:
c3d17b63e   Jeff Layton   cifs: convert cif...
1566
1567
1568
1569
1570
1571
1572
1573
1574
1575
1576
1577
1578
1579
1580
1581
1582
1583
1584
1585
1586
1587
1588
1589
1590
1591
1592
1593
1594
1595
1596
1597
1598
1599
1600
1601
1602
1603
1604
  	while (!done && index <= end) {
  		unsigned int i, nr_pages, found_pages;
  		pgoff_t next = 0, tofind;
  		struct page **pages;
  
  		tofind = min((cifs_sb->wsize / PAGE_CACHE_SIZE) - 1,
  				end - index) + 1;
  
  		wdata = cifs_writedata_alloc((unsigned int)tofind);
  		if (!wdata) {
  			rc = -ENOMEM;
  			break;
  		}
  
  		/*
  		 * find_get_pages_tag seems to return a max of 256 on each
  		 * iteration, so we must call it several times in order to
  		 * fill the array or the wsize is effectively limited to
  		 * 256 * PAGE_CACHE_SIZE.
  		 */
  		found_pages = 0;
  		pages = wdata->pages;
  		do {
  			nr_pages = find_get_pages_tag(mapping, &index,
  							PAGECACHE_TAG_DIRTY,
  							tofind, pages);
  			found_pages += nr_pages;
  			tofind -= nr_pages;
  			pages += nr_pages;
  		} while (nr_pages && tofind && index <= end);
  
  		if (found_pages == 0) {
  			kref_put(&wdata->refcount, cifs_writedata_release);
  			break;
  		}
  
  		nr_pages = 0;
  		for (i = 0; i < found_pages; i++) {
  			page = wdata->pages[i];
37c0eb467   Steve French   CIFS: implement c...
1605
1606
1607
1608
1609
1610
1611
  			/*
  			 * At this point we hold neither mapping->tree_lock nor
  			 * lock on the page itself: the page may be truncated or
  			 * invalidated (changing page->mapping to NULL), or even
  			 * swizzled back from swapper_space to tmpfs file
  			 * mapping
  			 */
c3d17b63e   Jeff Layton   cifs: convert cif...
1612
  			if (nr_pages == 0)
37c0eb467   Steve French   CIFS: implement c...
1613
  				lock_page(page);
529ae9aaa   Nick Piggin   mm: rename page t...
1614
  			else if (!trylock_page(page))
37c0eb467   Steve French   CIFS: implement c...
1615
1616
1617
1618
1619
1620
  				break;
  
  			if (unlikely(page->mapping != mapping)) {
  				unlock_page(page);
  				break;
  			}
111ebb6e6   OGAWA Hirofumi   [PATCH] writeback...
1621
  			if (!wbc->range_cyclic && page->index > end) {
c3d17b63e   Jeff Layton   cifs: convert cif...
1622
  				done = true;
37c0eb467   Steve French   CIFS: implement c...
1623
1624
1625
1626
1627
1628
1629
1630
1631
1632
1633
1634
1635
1636
  				unlock_page(page);
  				break;
  			}
  
  			if (next && (page->index != next)) {
  				/* Not next consecutive page */
  				unlock_page(page);
  				break;
  			}
  
  			if (wbc->sync_mode != WB_SYNC_NONE)
  				wait_on_page_writeback(page);
  
  			if (PageWriteback(page) ||
cb876f451   Linus Torvalds   Fix up CIFS for "...
1637
  					!clear_page_dirty_for_io(page)) {
37c0eb467   Steve French   CIFS: implement c...
1638
1639
1640
  				unlock_page(page);
  				break;
  			}
84d2f07e8   Steve French   CIFS: cifs_writep...
1641

cb876f451   Linus Torvalds   Fix up CIFS for "...
1642
1643
1644
1645
1646
  			/*
  			 * This actually clears the dirty bit in the radix tree.
  			 * See cifs_writepage() for more commentary.
  			 */
  			set_page_writeback(page);
84d2f07e8   Steve French   CIFS: cifs_writep...
1647
  			if (page_offset(page) >= mapping->host->i_size) {
c3d17b63e   Jeff Layton   cifs: convert cif...
1648
  				done = true;
84d2f07e8   Steve French   CIFS: cifs_writep...
1649
  				unlock_page(page);
cb876f451   Linus Torvalds   Fix up CIFS for "...
1650
  				end_page_writeback(page);
84d2f07e8   Steve French   CIFS: cifs_writep...
1651
1652
  				break;
  			}
c3d17b63e   Jeff Layton   cifs: convert cif...
1653
1654
1655
1656
  			wdata->pages[i] = page;
  			next = page->index + 1;
  			++nr_pages;
  		}
37c0eb467   Steve French   CIFS: implement c...
1657

c3d17b63e   Jeff Layton   cifs: convert cif...
1658
1659
1660
  		/* reset index to refind any pages skipped */
  		if (nr_pages == 0)
  			index = wdata->pages[0]->index + 1;
84d2f07e8   Steve French   CIFS: cifs_writep...
1661

c3d17b63e   Jeff Layton   cifs: convert cif...
1662
1663
1664
1665
1666
  		/* put any pages we aren't going to use */
  		for (i = nr_pages; i < found_pages; i++) {
  			page_cache_release(wdata->pages[i]);
  			wdata->pages[i] = NULL;
  		}
37c0eb467   Steve French   CIFS: implement c...
1667

c3d17b63e   Jeff Layton   cifs: convert cif...
1668
1669
1670
1671
  		/* nothing to write? */
  		if (nr_pages == 0) {
  			kref_put(&wdata->refcount, cifs_writedata_release);
  			continue;
37c0eb467   Steve French   CIFS: implement c...
1672
  		}
fbec9ab95   Jeff Layton   cifs: vary timeou...
1673

c3d17b63e   Jeff Layton   cifs: convert cif...
1674
1675
1676
  		wdata->sync_mode = wbc->sync_mode;
  		wdata->nr_pages = nr_pages;
  		wdata->offset = page_offset(wdata->pages[0]);
941b853d7   Jeff Layton   cifs: don't fail ...
1677

c3d17b63e   Jeff Layton   cifs: convert cif...
1678
1679
1680
1681
1682
1683
1684
1685
1686
  		do {
  			if (wdata->cfile != NULL)
  				cifsFileInfo_put(wdata->cfile);
  			wdata->cfile = find_writable_file(CIFS_I(mapping->host),
  							  false);
  			if (!wdata->cfile) {
  				cERROR(1, "No writable handles for inode");
  				rc = -EBADF;
  				break;
941b853d7   Jeff Layton   cifs: don't fail ...
1687
  			}
c3d17b63e   Jeff Layton   cifs: convert cif...
1688
1689
  			rc = cifs_async_writev(wdata);
  		} while (wbc->sync_mode == WB_SYNC_ALL && rc == -EAGAIN);
941b853d7   Jeff Layton   cifs: don't fail ...
1690

c3d17b63e   Jeff Layton   cifs: convert cif...
1691
1692
  		for (i = 0; i < nr_pages; ++i)
  			unlock_page(wdata->pages[i]);
f3983c213   Jeff Layton   cifs: fix handlin...
1693

c3d17b63e   Jeff Layton   cifs: convert cif...
1694
1695
1696
  		/* send failure -- clean up the mess */
  		if (rc != 0) {
  			for (i = 0; i < nr_pages; ++i) {
941b853d7   Jeff Layton   cifs: don't fail ...
1697
  				if (rc == -EAGAIN)
c3d17b63e   Jeff Layton   cifs: convert cif...
1698
1699
1700
1701
1702
1703
  					redirty_page_for_writepage(wbc,
  							   wdata->pages[i]);
  				else
  					SetPageError(wdata->pages[i]);
  				end_page_writeback(wdata->pages[i]);
  				page_cache_release(wdata->pages[i]);
37c0eb467   Steve French   CIFS: implement c...
1704
  			}
941b853d7   Jeff Layton   cifs: don't fail ...
1705
1706
  			if (rc != -EAGAIN)
  				mapping_set_error(mapping, rc);
c3d17b63e   Jeff Layton   cifs: convert cif...
1707
1708
  		}
  		kref_put(&wdata->refcount, cifs_writedata_release);
941b853d7   Jeff Layton   cifs: don't fail ...
1709

c3d17b63e   Jeff Layton   cifs: convert cif...
1710
1711
1712
  		wbc->nr_to_write -= nr_pages;
  		if (wbc->nr_to_write <= 0)
  			done = true;
b066a48c9   Dave Kleikamp   prevent cifs_writ...
1713

c3d17b63e   Jeff Layton   cifs: convert cif...
1714
  		index = next;
37c0eb467   Steve French   CIFS: implement c...
1715
  	}
c3d17b63e   Jeff Layton   cifs: convert cif...
1716

37c0eb467   Steve French   CIFS: implement c...
1717
1718
1719
1720
1721
  	if (!scanned && !done) {
  		/*
  		 * We hit the last page and there is more work to be done: wrap
  		 * back to the start of the file
  		 */
c3d17b63e   Jeff Layton   cifs: convert cif...
1722
  		scanned = true;
37c0eb467   Steve French   CIFS: implement c...
1723
1724
1725
  		index = 0;
  		goto retry;
  	}
c3d17b63e   Jeff Layton   cifs: convert cif...
1726

111ebb6e6   OGAWA Hirofumi   [PATCH] writeback...
1727
  	if (wbc->range_cyclic || (range_whole && wbc->nr_to_write > 0))
37c0eb467   Steve French   CIFS: implement c...
1728
  		mapping->writeback_index = index;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
1729
1730
  	return rc;
  }
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
1731

9ad1506b4   Pavel Shilovsky   CIFS: Add launder...
1732
1733
  static int
  cifs_writepage_locked(struct page *page, struct writeback_control *wbc)
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
1734
  {
9ad1506b4   Pavel Shilovsky   CIFS: Add launder...
1735
  	int rc;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
1736
1737
1738
1739
1740
  	int xid;
  
  	xid = GetXid();
  /* BB add check for wbc flags */
  	page_cache_get(page);
ad7a2926b   Steve French   [CIFS] reduce che...
1741
  	if (!PageUptodate(page))
b6b38f704   Joe Perches   [CIFS] Neaten cER...
1742
  		cFYI(1, "ppw - page not up to date");
cb876f451   Linus Torvalds   Fix up CIFS for "...
1743
1744
1745
1746
1747
1748
1749
1750
1751
1752
1753
  
  	/*
  	 * Set the "writeback" flag, and clear "dirty" in the radix tree.
  	 *
  	 * A writepage() implementation always needs to do either this,
  	 * or re-dirty the page with "redirty_page_for_writepage()" in
  	 * the case of a failure.
  	 *
  	 * Just unlocking the page will cause the radix tree tag-bits
  	 * to fail to update with the state of the page correctly.
  	 */
fb8c4b14d   Steve French   [CIFS] whitespace...
1754
  	set_page_writeback(page);
9ad1506b4   Pavel Shilovsky   CIFS: Add launder...
1755
  retry_write:
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
1756
  	rc = cifs_partialpagewrite(page, 0, PAGE_CACHE_SIZE);
9ad1506b4   Pavel Shilovsky   CIFS: Add launder...
1757
1758
1759
1760
1761
1762
1763
1764
  	if (rc == -EAGAIN && wbc->sync_mode == WB_SYNC_ALL)
  		goto retry_write;
  	else if (rc == -EAGAIN)
  		redirty_page_for_writepage(wbc, page);
  	else if (rc != 0)
  		SetPageError(page);
  	else
  		SetPageUptodate(page);
cb876f451   Linus Torvalds   Fix up CIFS for "...
1765
1766
  	end_page_writeback(page);
  	page_cache_release(page);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
1767
1768
1769
  	FreeXid(xid);
  	return rc;
  }
9ad1506b4   Pavel Shilovsky   CIFS: Add launder...
1770
1771
1772
1773
1774
1775
  static int cifs_writepage(struct page *page, struct writeback_control *wbc)
  {
  	int rc = cifs_writepage_locked(page, wbc);
  	unlock_page(page);
  	return rc;
  }
d9414774d   Nick Piggin   cifs: Convert cif...
1776
1777
1778
  static int cifs_write_end(struct file *file, struct address_space *mapping,
  			loff_t pos, unsigned len, unsigned copied,
  			struct page *page, void *fsdata)
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
1779
  {
d9414774d   Nick Piggin   cifs: Convert cif...
1780
1781
  	int rc;
  	struct inode *inode = mapping->host;
d4ffff1fa   Pavel Shilovsky   CIFS: Add rwpidfo...
1782
1783
1784
1785
1786
1787
1788
1789
  	struct cifsFileInfo *cfile = file->private_data;
  	struct cifs_sb_info *cifs_sb = CIFS_SB(cfile->dentry->d_sb);
  	__u32 pid;
  
  	if (cifs_sb->mnt_cifs_flags & CIFS_MOUNT_RWPIDFORWARD)
  		pid = cfile->pid;
  	else
  		pid = current->tgid;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
1790

b6b38f704   Joe Perches   [CIFS] Neaten cER...
1791
1792
  	cFYI(1, "write_end for page %p from pos %lld with %d bytes",
  		 page, pos, copied);
d9414774d   Nick Piggin   cifs: Convert cif...
1793

a98ee8c1c   Jeff Layton   [CIFS] fix regres...
1794
1795
1796
1797
1798
  	if (PageChecked(page)) {
  		if (copied == len)
  			SetPageUptodate(page);
  		ClearPageChecked(page);
  	} else if (!PageUptodate(page) && copied == PAGE_CACHE_SIZE)
d9414774d   Nick Piggin   cifs: Convert cif...
1799
  		SetPageUptodate(page);
ad7a2926b   Steve French   [CIFS] reduce che...
1800

1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
1801
  	if (!PageUptodate(page)) {
d9414774d   Nick Piggin   cifs: Convert cif...
1802
1803
1804
1805
1806
  		char *page_data;
  		unsigned offset = pos & (PAGE_CACHE_SIZE - 1);
  		int xid;
  
  		xid = GetXid();
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
1807
1808
1809
1810
1811
1812
  		/* this is probably better than directly calling
  		   partialpage_write since in this function the file handle is
  		   known which we might as well	leverage */
  		/* BB check if anything else missing out of ppw
  		   such as updating last write time */
  		page_data = kmap(page);
d4ffff1fa   Pavel Shilovsky   CIFS: Add rwpidfo...
1813
  		rc = cifs_write(cfile, pid, page_data + offset, copied, &pos);
d9414774d   Nick Piggin   cifs: Convert cif...
1814
  		/* if (rc < 0) should we set writebehind rc? */
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
1815
  		kunmap(page);
d9414774d   Nick Piggin   cifs: Convert cif...
1816
1817
  
  		FreeXid(xid);
fb8c4b14d   Steve French   [CIFS] whitespace...
1818
  	} else {
d9414774d   Nick Piggin   cifs: Convert cif...
1819
1820
  		rc = copied;
  		pos += copied;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
1821
1822
  		set_page_dirty(page);
  	}
d9414774d   Nick Piggin   cifs: Convert cif...
1823
1824
1825
1826
1827
1828
1829
1830
1831
  	if (rc > 0) {
  		spin_lock(&inode->i_lock);
  		if (pos > inode->i_size)
  			i_size_write(inode, pos);
  		spin_unlock(&inode->i_lock);
  	}
  
  	unlock_page(page);
  	page_cache_release(page);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
1832
1833
  	return rc;
  }
02c24a821   Josef Bacik   fs: push i_mutex ...
1834
1835
  int cifs_strict_fsync(struct file *file, loff_t start, loff_t end,
  		      int datasync)
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
1836
1837
1838
  {
  	int xid;
  	int rc = 0;
96daf2b09   Steve French   [CIFS] Rename thr...
1839
  	struct cifs_tcon *tcon;
c21dfb699   Joe Perches   fs/cifs: Remove u...
1840
  	struct cifsFileInfo *smbfile = file->private_data;
e6a002964   Josef "Jeff" Sipek   [PATCH] cifs: cha...
1841
  	struct inode *inode = file->f_path.dentry->d_inode;
8be7e6ba1   Pavel Shilovsky   CIFS: Implement c...
1842
  	struct cifs_sb_info *cifs_sb = CIFS_SB(inode->i_sb);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
1843

02c24a821   Josef Bacik   fs: push i_mutex ...
1844
1845
1846
1847
  	rc = filemap_write_and_wait_range(inode->i_mapping, start, end);
  	if (rc)
  		return rc;
  	mutex_lock(&inode->i_mutex);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
1848
  	xid = GetXid();
b6b38f704   Joe Perches   [CIFS] Neaten cER...
1849
  	cFYI(1, "Sync file - name: %s datasync: 0x%x",
7ea808591   Christoph Hellwig   drop unused dentr...
1850
  		file->f_path.dentry->d_name.name, datasync);
50c2f7538   Steve French   [CIFS] whitespace...
1851

6feb9891d   Pavel Shilovsky   CIFS: Simplify in...
1852
1853
1854
1855
1856
1857
1858
  	if (!CIFS_I(inode)->clientCanCacheRead) {
  		rc = cifs_invalidate_mapping(inode);
  		if (rc) {
  			cFYI(1, "rc: %d during invalidate phase", rc);
  			rc = 0; /* don't care about it in fsync */
  		}
  	}
eb4b756b1   Jeff Layton   cifs: eliminate c...
1859

8be7e6ba1   Pavel Shilovsky   CIFS: Implement c...
1860
1861
1862
1863
1864
  	tcon = tlink_tcon(smbfile->tlink);
  	if (!(cifs_sb->mnt_cifs_flags & CIFS_MOUNT_NOSSYNC))
  		rc = CIFSSMBFlush(xid, tcon, smbfile->netfid);
  
  	FreeXid(xid);
02c24a821   Josef Bacik   fs: push i_mutex ...
1865
  	mutex_unlock(&inode->i_mutex);
8be7e6ba1   Pavel Shilovsky   CIFS: Implement c...
1866
1867
  	return rc;
  }
02c24a821   Josef Bacik   fs: push i_mutex ...
1868
  int cifs_fsync(struct file *file, loff_t start, loff_t end, int datasync)
8be7e6ba1   Pavel Shilovsky   CIFS: Implement c...
1869
1870
1871
  {
  	int xid;
  	int rc = 0;
96daf2b09   Steve French   [CIFS] Rename thr...
1872
  	struct cifs_tcon *tcon;
8be7e6ba1   Pavel Shilovsky   CIFS: Implement c...
1873
1874
  	struct cifsFileInfo *smbfile = file->private_data;
  	struct cifs_sb_info *cifs_sb = CIFS_SB(file->f_path.dentry->d_sb);
02c24a821   Josef Bacik   fs: push i_mutex ...
1875
1876
1877
1878
1879
1880
  	struct inode *inode = file->f_mapping->host;
  
  	rc = filemap_write_and_wait_range(inode->i_mapping, start, end);
  	if (rc)
  		return rc;
  	mutex_lock(&inode->i_mutex);
8be7e6ba1   Pavel Shilovsky   CIFS: Implement c...
1881
1882
1883
1884
1885
1886
1887
1888
1889
  
  	xid = GetXid();
  
  	cFYI(1, "Sync file - name: %s datasync: 0x%x",
  		file->f_path.dentry->d_name.name, datasync);
  
  	tcon = tlink_tcon(smbfile->tlink);
  	if (!(cifs_sb->mnt_cifs_flags & CIFS_MOUNT_NOSSYNC))
  		rc = CIFSSMBFlush(xid, tcon, smbfile->netfid);
b298f2235   Steve French   [CIFS] Send SMB f...
1890

1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
1891
  	FreeXid(xid);
02c24a821   Josef Bacik   fs: push i_mutex ...
1892
  	mutex_unlock(&inode->i_mutex);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
1893
1894
  	return rc;
  }
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
1895
1896
1897
1898
  /*
   * As file closes, flush all cached write data for this inode checking
   * for write behind errors.
   */
75e1fcc0b   Miklos Szeredi   [PATCH] vfs: add ...
1899
  int cifs_flush(struct file *file, fl_owner_t id)
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
1900
  {
fb8c4b14d   Steve French   [CIFS] whitespace...
1901
  	struct inode *inode = file->f_path.dentry->d_inode;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
1902
  	int rc = 0;
eb4b756b1   Jeff Layton   cifs: eliminate c...
1903
  	if (file->f_mode & FMODE_WRITE)
d3f1322af   Jeff Layton   cifs: wait for wr...
1904
  		rc = filemap_write_and_wait(inode->i_mapping);
50c2f7538   Steve French   [CIFS] whitespace...
1905

b6b38f704   Joe Perches   [CIFS] Neaten cER...
1906
  	cFYI(1, "Flush inode %p file %p rc %d", inode, file, rc);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
1907
1908
1909
  
  	return rc;
  }
72432ffcf   Pavel Shilovsky   CIFS: Implement c...
1910
1911
1912
1913
1914
1915
1916
1917
1918
1919
1920
1921
1922
1923
1924
1925
1926
1927
1928
1929
1930
1931
1932
1933
1934
1935
1936
1937
1938
1939
1940
1941
1942
1943
1944
1945
1946
1947
1948
1949
1950
1951
1952
1953
1954
1955
1956
1957
  static int
  cifs_write_allocate_pages(struct page **pages, unsigned long num_pages)
  {
  	int rc = 0;
  	unsigned long i;
  
  	for (i = 0; i < num_pages; i++) {
  		pages[i] = alloc_page(__GFP_HIGHMEM);
  		if (!pages[i]) {
  			/*
  			 * save number of pages we have already allocated and
  			 * return with ENOMEM error
  			 */
  			num_pages = i;
  			rc = -ENOMEM;
  			goto error;
  		}
  	}
  
  	return rc;
  
  error:
  	for (i = 0; i < num_pages; i++)
  		put_page(pages[i]);
  	return rc;
  }
  
  static inline
  size_t get_numpages(const size_t wsize, const size_t len, size_t *cur_len)
  {
  	size_t num_pages;
  	size_t clen;
  
  	clen = min_t(const size_t, len, wsize);
  	num_pages = clen / PAGE_CACHE_SIZE;
  	if (clen % PAGE_CACHE_SIZE)
  		num_pages++;
  
  	if (cur_len)
  		*cur_len = clen;
  
  	return num_pages;
  }
  
  static ssize_t
  cifs_iovec_write(struct file *file, const struct iovec *iov,
  		 unsigned long nr_segs, loff_t *poffset)
  {
76429c148   Pavel Shilovsky   CIFS: Fix variabl...
1958
1959
1960
1961
  	unsigned int written;
  	unsigned long num_pages, npages, i;
  	size_t copied, len, cur_len;
  	ssize_t total_written = 0;
72432ffcf   Pavel Shilovsky   CIFS: Implement c...
1962
1963
1964
1965
1966
  	struct kvec *to_send;
  	struct page **pages;
  	struct iov_iter it;
  	struct inode *inode;
  	struct cifsFileInfo *open_file;
96daf2b09   Steve French   [CIFS] Rename thr...
1967
  	struct cifs_tcon *pTcon;
72432ffcf   Pavel Shilovsky   CIFS: Implement c...
1968
  	struct cifs_sb_info *cifs_sb;
fa2989f44   Pavel Shilovsky   CIFS: Use pid sav...
1969
  	struct cifs_io_parms io_parms;
72432ffcf   Pavel Shilovsky   CIFS: Implement c...
1970
  	int xid, rc;
d4ffff1fa   Pavel Shilovsky   CIFS: Add rwpidfo...
1971
  	__u32 pid;
72432ffcf   Pavel Shilovsky   CIFS: Implement c...
1972
1973
1974
1975
1976
1977
1978
1979
1980
1981
1982
1983
1984
1985
1986
1987
1988
1989
1990
1991
1992
1993
1994
1995
1996
1997
1998
1999
2000
2001
2002
  
  	len = iov_length(iov, nr_segs);
  	if (!len)
  		return 0;
  
  	rc = generic_write_checks(file, poffset, &len, 0);
  	if (rc)
  		return rc;
  
  	cifs_sb = CIFS_SB(file->f_path.dentry->d_sb);
  	num_pages = get_numpages(cifs_sb->wsize, len, &cur_len);
  
  	pages = kmalloc(sizeof(struct pages *)*num_pages, GFP_KERNEL);
  	if (!pages)
  		return -ENOMEM;
  
  	to_send = kmalloc(sizeof(struct kvec)*(num_pages + 1), GFP_KERNEL);
  	if (!to_send) {
  		kfree(pages);
  		return -ENOMEM;
  	}
  
  	rc = cifs_write_allocate_pages(pages, num_pages);
  	if (rc) {
  		kfree(pages);
  		kfree(to_send);
  		return rc;
  	}
  
  	xid = GetXid();
  	open_file = file->private_data;
d4ffff1fa   Pavel Shilovsky   CIFS: Add rwpidfo...
2003
2004
2005
2006
2007
  
  	if (cifs_sb->mnt_cifs_flags & CIFS_MOUNT_RWPIDFORWARD)
  		pid = open_file->pid;
  	else
  		pid = current->tgid;
72432ffcf   Pavel Shilovsky   CIFS: Implement c...
2008
2009
2010
2011
2012
2013
2014
2015
2016
2017
2018
2019
2020
2021
2022
2023
2024
2025
2026
2027
2028
2029
2030
2031
2032
2033
  	pTcon = tlink_tcon(open_file->tlink);
  	inode = file->f_path.dentry->d_inode;
  
  	iov_iter_init(&it, iov, nr_segs, len, 0);
  	npages = num_pages;
  
  	do {
  		size_t save_len = cur_len;
  		for (i = 0; i < npages; i++) {
  			copied = min_t(const size_t, cur_len, PAGE_CACHE_SIZE);
  			copied = iov_iter_copy_from_user(pages[i], &it, 0,
  							 copied);
  			cur_len -= copied;
  			iov_iter_advance(&it, copied);
  			to_send[i+1].iov_base = kmap(pages[i]);
  			to_send[i+1].iov_len = copied;
  		}
  
  		cur_len = save_len - cur_len;
  
  		do {
  			if (open_file->invalidHandle) {
  				rc = cifs_reopen_file(open_file, false);
  				if (rc != 0)
  					break;
  			}
fa2989f44   Pavel Shilovsky   CIFS: Use pid sav...
2034
  			io_parms.netfid = open_file->netfid;
d4ffff1fa   Pavel Shilovsky   CIFS: Add rwpidfo...
2035
  			io_parms.pid = pid;
fa2989f44   Pavel Shilovsky   CIFS: Use pid sav...
2036
2037
2038
2039
2040
  			io_parms.tcon = pTcon;
  			io_parms.offset = *poffset;
  			io_parms.length = cur_len;
  			rc = CIFSSMBWrite2(xid, &io_parms, &written, to_send,
  					   npages, 0);
72432ffcf   Pavel Shilovsky   CIFS: Implement c...
2041
2042
2043
2044
2045
2046
2047
2048
2049
2050
2051
2052
2053
2054
2055
2056
2057
2058
2059
2060
2061
2062
2063
2064
2065
2066
2067
2068
2069
2070
2071
2072
2073
2074
2075
2076
2077
  		} while (rc == -EAGAIN);
  
  		for (i = 0; i < npages; i++)
  			kunmap(pages[i]);
  
  		if (written) {
  			len -= written;
  			total_written += written;
  			cifs_update_eof(CIFS_I(inode), *poffset, written);
  			*poffset += written;
  		} else if (rc < 0) {
  			if (!total_written)
  				total_written = rc;
  			break;
  		}
  
  		/* get length and number of kvecs of the next write */
  		npages = get_numpages(cifs_sb->wsize, len, &cur_len);
  	} while (len > 0);
  
  	if (total_written > 0) {
  		spin_lock(&inode->i_lock);
  		if (*poffset > inode->i_size)
  			i_size_write(inode, *poffset);
  		spin_unlock(&inode->i_lock);
  	}
  
  	cifs_stats_bytes_written(pTcon, total_written);
  	mark_inode_dirty_sync(inode);
  
  	for (i = 0; i < num_pages; i++)
  		put_page(pages[i]);
  	kfree(to_send);
  	kfree(pages);
  	FreeXid(xid);
  	return total_written;
  }
0b81c1c40   Pavel Shilovsky   CIFS: directio re...
2078
  ssize_t cifs_user_writev(struct kiocb *iocb, const struct iovec *iov,
72432ffcf   Pavel Shilovsky   CIFS: Implement c...
2079
2080
2081
2082
2083
2084
2085
2086
2087
2088
2089
2090
2091
2092
2093
2094
2095
2096
2097
2098
2099
2100
2101
2102
2103
2104
2105
2106
2107
2108
2109
2110
2111
2112
2113
2114
2115
2116
2117
2118
2119
  				unsigned long nr_segs, loff_t pos)
  {
  	ssize_t written;
  	struct inode *inode;
  
  	inode = iocb->ki_filp->f_path.dentry->d_inode;
  
  	/*
  	 * BB - optimize the way when signing is disabled. We can drop this
  	 * extra memory-to-memory copying and use iovec buffers for constructing
  	 * write request.
  	 */
  
  	written = cifs_iovec_write(iocb->ki_filp, iov, nr_segs, &pos);
  	if (written > 0) {
  		CIFS_I(inode)->invalid_mapping = true;
  		iocb->ki_pos = pos;
  	}
  
  	return written;
  }
  
  ssize_t cifs_strict_writev(struct kiocb *iocb, const struct iovec *iov,
  			   unsigned long nr_segs, loff_t pos)
  {
  	struct inode *inode;
  
  	inode = iocb->ki_filp->f_path.dentry->d_inode;
  
  	if (CIFS_I(inode)->clientCanCacheAll)
  		return generic_file_aio_write(iocb, iov, nr_segs, pos);
  
  	/*
  	 * In strict cache mode we need to write the data to the server exactly
  	 * from the pos to pos+len-1 rather than flush all affected pages
  	 * because it may cause a error with mandatory locks on these pages but
  	 * not on the region from pos to ppos+len-1.
  	 */
  
  	return cifs_user_writev(iocb, iov, nr_segs, pos);
  }
a70307eee   Pavel Shilovsky   CIFS: Implement c...
2120
2121
2122
  static ssize_t
  cifs_iovec_read(struct file *file, const struct iovec *iov,
  		 unsigned long nr_segs, loff_t *poffset)
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
2123
  {
a70307eee   Pavel Shilovsky   CIFS: Implement c...
2124
2125
  	int rc;
  	int xid;
76429c148   Pavel Shilovsky   CIFS: Fix variabl...
2126
2127
  	ssize_t total_read;
  	unsigned int bytes_read = 0;
a70307eee   Pavel Shilovsky   CIFS: Implement c...
2128
2129
  	size_t len, cur_len;
  	int iov_offset = 0;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
2130
  	struct cifs_sb_info *cifs_sb;
96daf2b09   Steve French   [CIFS] Rename thr...
2131
  	struct cifs_tcon *pTcon;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
2132
  	struct cifsFileInfo *open_file;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
2133
  	struct smb_com_read_rsp *pSMBr;
d4ffff1fa   Pavel Shilovsky   CIFS: Add rwpidfo...
2134
  	struct cifs_io_parms io_parms;
a70307eee   Pavel Shilovsky   CIFS: Implement c...
2135
  	char *read_data;
5eba8ab36   Jeff Layton   cifs: allow for l...
2136
  	unsigned int rsize;
d4ffff1fa   Pavel Shilovsky   CIFS: Add rwpidfo...
2137
  	__u32 pid;
a70307eee   Pavel Shilovsky   CIFS: Implement c...
2138
2139
2140
2141
2142
2143
2144
  
  	if (!nr_segs)
  		return 0;
  
  	len = iov_length(iov, nr_segs);
  	if (!len)
  		return 0;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
2145
2146
  
  	xid = GetXid();
e6a002964   Josef "Jeff" Sipek   [PATCH] cifs: cha...
2147
  	cifs_sb = CIFS_SB(file->f_path.dentry->d_sb);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
2148

5eba8ab36   Jeff Layton   cifs: allow for l...
2149
2150
  	/* FIXME: set up handlers for larger reads and/or convert to async */
  	rsize = min_t(unsigned int, cifs_sb->rsize, CIFSMaxBufSize);
c21dfb699   Joe Perches   fs/cifs: Remove u...
2151
  	open_file = file->private_data;
13cfb7334   Jeff Layton   cifs: have cifsFi...
2152
  	pTcon = tlink_tcon(open_file->tlink);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
2153

d4ffff1fa   Pavel Shilovsky   CIFS: Add rwpidfo...
2154
2155
2156
2157
  	if (cifs_sb->mnt_cifs_flags & CIFS_MOUNT_RWPIDFORWARD)
  		pid = open_file->pid;
  	else
  		pid = current->tgid;
ad7a2926b   Steve French   [CIFS] reduce che...
2158
  	if ((file->f_flags & O_ACCMODE) == O_WRONLY)
b6b38f704   Joe Perches   [CIFS] Neaten cER...
2159
  		cFYI(1, "attempting read on write only file instance");
ad7a2926b   Steve French   [CIFS] reduce che...
2160

a70307eee   Pavel Shilovsky   CIFS: Implement c...
2161
  	for (total_read = 0; total_read < len; total_read += bytes_read) {
5eba8ab36   Jeff Layton   cifs: allow for l...
2162
  		cur_len = min_t(const size_t, len - total_read, rsize);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
2163
  		rc = -EAGAIN;
a70307eee   Pavel Shilovsky   CIFS: Implement c...
2164
  		read_data = NULL;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
2165
  		while (rc == -EAGAIN) {
ec637e3ff   Steve French   [CIFS] Avoid extr...
2166
  			int buf_type = CIFS_NO_BUFFER;
cdff08e76   Steve French   [CIFS] move close...
2167
  			if (open_file->invalidHandle) {
15886177e   Jeff Layton   cifs: clean up ci...
2168
  				rc = cifs_reopen_file(open_file, true);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
2169
2170
2171
  				if (rc != 0)
  					break;
  			}
d4ffff1fa   Pavel Shilovsky   CIFS: Add rwpidfo...
2172
2173
2174
2175
  			io_parms.netfid = open_file->netfid;
  			io_parms.pid = pid;
  			io_parms.tcon = pTcon;
  			io_parms.offset = *poffset;
2cebaa58b   Pavel Shilovsky   CIFS: Fix wrong l...
2176
  			io_parms.length = cur_len;
d4ffff1fa   Pavel Shilovsky   CIFS: Add rwpidfo...
2177
  			rc = CIFSSMBRead(xid, &io_parms, &bytes_read,
a70307eee   Pavel Shilovsky   CIFS: Implement c...
2178
2179
2180
2181
2182
2183
2184
  					 &read_data, &buf_type);
  			pSMBr = (struct smb_com_read_rsp *)read_data;
  			if (read_data) {
  				char *data_offset = read_data + 4 +
  						le16_to_cpu(pSMBr->DataOffset);
  				if (memcpy_toiovecend(iov, data_offset,
  						      iov_offset, bytes_read))
93544cc64   Steve French   [PATCH] CIFS: fix...
2185
  					rc = -EFAULT;
fb8c4b14d   Steve French   [CIFS] whitespace...
2186
  				if (buf_type == CIFS_SMALL_BUFFER)
a70307eee   Pavel Shilovsky   CIFS: Implement c...
2187
  					cifs_small_buf_release(read_data);
fb8c4b14d   Steve French   [CIFS] whitespace...
2188
  				else if (buf_type == CIFS_LARGE_BUFFER)
a70307eee   Pavel Shilovsky   CIFS: Implement c...
2189
2190
2191
  					cifs_buf_release(read_data);
  				read_data = NULL;
  				iov_offset += bytes_read;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
2192
2193
  			}
  		}
a70307eee   Pavel Shilovsky   CIFS: Implement c...
2194

1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
2195
2196
2197
2198
2199
2200
2201
2202
  		if (rc || (bytes_read == 0)) {
  			if (total_read) {
  				break;
  			} else {
  				FreeXid(xid);
  				return rc;
  			}
  		} else {
a45443475   Steve French   CIFS: Reduce CONF...
2203
  			cifs_stats_bytes_read(pTcon, bytes_read);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
2204
2205
2206
  			*poffset += bytes_read;
  		}
  	}
a70307eee   Pavel Shilovsky   CIFS: Implement c...
2207

1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
2208
2209
2210
  	FreeXid(xid);
  	return total_read;
  }
0b81c1c40   Pavel Shilovsky   CIFS: directio re...
2211
  ssize_t cifs_user_readv(struct kiocb *iocb, const struct iovec *iov,
a70307eee   Pavel Shilovsky   CIFS: Implement c...
2212
2213
2214
2215
2216
2217
2218
2219
2220
2221
2222
2223
2224
2225
2226
2227
2228
2229
2230
2231
2232
2233
2234
2235
2236
2237
2238
2239
2240
2241
2242
2243
  			       unsigned long nr_segs, loff_t pos)
  {
  	ssize_t read;
  
  	read = cifs_iovec_read(iocb->ki_filp, iov, nr_segs, &pos);
  	if (read > 0)
  		iocb->ki_pos = pos;
  
  	return read;
  }
  
  ssize_t cifs_strict_readv(struct kiocb *iocb, const struct iovec *iov,
  			  unsigned long nr_segs, loff_t pos)
  {
  	struct inode *inode;
  
  	inode = iocb->ki_filp->f_path.dentry->d_inode;
  
  	if (CIFS_I(inode)->clientCanCacheRead)
  		return generic_file_aio_read(iocb, iov, nr_segs, pos);
  
  	/*
  	 * In strict cache mode we need to read from the server all the time
  	 * if we don't have level II oplock because the server can delay mtime
  	 * change - so we can't make a decision about inode invalidating.
  	 * And we can also fail with pagereading if there are mandatory locks
  	 * on pages affected by this read but not on the region from pos to
  	 * pos+len-1.
  	 */
  
  	return cifs_user_readv(iocb, iov, nr_segs, pos);
  }
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
2244
2245
  
  static ssize_t cifs_read(struct file *file, char *read_data, size_t read_size,
a70307eee   Pavel Shilovsky   CIFS: Implement c...
2246
  			 loff_t *poffset)
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
2247
2248
2249
2250
2251
  {
  	int rc = -EACCES;
  	unsigned int bytes_read = 0;
  	unsigned int total_read;
  	unsigned int current_read_size;
5eba8ab36   Jeff Layton   cifs: allow for l...
2252
  	unsigned int rsize;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
2253
  	struct cifs_sb_info *cifs_sb;
96daf2b09   Steve French   [CIFS] Rename thr...
2254
  	struct cifs_tcon *pTcon;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
2255
2256
2257
  	int xid;
  	char *current_offset;
  	struct cifsFileInfo *open_file;
d4ffff1fa   Pavel Shilovsky   CIFS: Add rwpidfo...
2258
  	struct cifs_io_parms io_parms;
ec637e3ff   Steve French   [CIFS] Avoid extr...
2259
  	int buf_type = CIFS_NO_BUFFER;
d4ffff1fa   Pavel Shilovsky   CIFS: Add rwpidfo...
2260
  	__u32 pid;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
2261
2262
  
  	xid = GetXid();
e6a002964   Josef "Jeff" Sipek   [PATCH] cifs: cha...
2263
  	cifs_sb = CIFS_SB(file->f_path.dentry->d_sb);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
2264

5eba8ab36   Jeff Layton   cifs: allow for l...
2265
2266
  	/* FIXME: set up handlers for larger reads and/or convert to async */
  	rsize = min_t(unsigned int, cifs_sb->rsize, CIFSMaxBufSize);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
2267
  	if (file->private_data == NULL) {
0f3bc09ee   Suresh Jayaraman   cifs: Fix incorre...
2268
  		rc = -EBADF;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
2269
  		FreeXid(xid);
0f3bc09ee   Suresh Jayaraman   cifs: Fix incorre...
2270
  		return rc;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
2271
  	}
c21dfb699   Joe Perches   fs/cifs: Remove u...
2272
  	open_file = file->private_data;
13cfb7334   Jeff Layton   cifs: have cifsFi...
2273
  	pTcon = tlink_tcon(open_file->tlink);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
2274

d4ffff1fa   Pavel Shilovsky   CIFS: Add rwpidfo...
2275
2276
2277
2278
  	if (cifs_sb->mnt_cifs_flags & CIFS_MOUNT_RWPIDFORWARD)
  		pid = open_file->pid;
  	else
  		pid = current->tgid;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
2279
  	if ((file->f_flags & O_ACCMODE) == O_WRONLY)
b6b38f704   Joe Perches   [CIFS] Neaten cER...
2280
  		cFYI(1, "attempting read on write only file instance");
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
2281

fb8c4b14d   Steve French   [CIFS] whitespace...
2282
  	for (total_read = 0, current_offset = read_data;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
2283
2284
  	     read_size > total_read;
  	     total_read += bytes_read, current_offset += bytes_read) {
5eba8ab36   Jeff Layton   cifs: allow for l...
2285
  		current_read_size = min_t(uint, read_size - total_read, rsize);
f9f5c8176   Steve French   [CIFS] Add suppor...
2286
2287
  		/* For windows me and 9x we do not want to request more
  		than it negotiated since it will refuse the read then */
fb8c4b14d   Steve French   [CIFS] whitespace...
2288
  		if ((pTcon->ses) &&
f9f5c8176   Steve French   [CIFS] Add suppor...
2289
  			!(pTcon->ses->capabilities & CAP_LARGE_FILES)) {
7748dd6ea   Dan Carpenter   CIFS: cleanup min...
2290
  			current_read_size = min_t(uint, current_read_size,
c974befa4   Jeff Layton   cifs: untangle se...
2291
  					CIFSMaxBufSize);
f9f5c8176   Steve French   [CIFS] Add suppor...
2292
  		}
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
2293
2294
  		rc = -EAGAIN;
  		while (rc == -EAGAIN) {
cdff08e76   Steve French   [CIFS] move close...
2295
  			if (open_file->invalidHandle) {
15886177e   Jeff Layton   cifs: clean up ci...
2296
  				rc = cifs_reopen_file(open_file, true);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
2297
2298
2299
  				if (rc != 0)
  					break;
  			}
d4ffff1fa   Pavel Shilovsky   CIFS: Add rwpidfo...
2300
2301
2302
2303
2304
2305
2306
  			io_parms.netfid = open_file->netfid;
  			io_parms.pid = pid;
  			io_parms.tcon = pTcon;
  			io_parms.offset = *poffset;
  			io_parms.length = current_read_size;
  			rc = CIFSSMBRead(xid, &io_parms, &bytes_read,
  					 &current_offset, &buf_type);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
2307
2308
2309
2310
2311
2312
2313
2314
2315
  		}
  		if (rc || (bytes_read == 0)) {
  			if (total_read) {
  				break;
  			} else {
  				FreeXid(xid);
  				return rc;
  			}
  		} else {
a45443475   Steve French   CIFS: Reduce CONF...
2316
  			cifs_stats_bytes_read(pTcon, total_read);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
2317
2318
2319
2320
2321
2322
  			*poffset += bytes_read;
  		}
  	}
  	FreeXid(xid);
  	return total_read;
  }
ca83ce3d5   Jeff Layton   cifs: don't allow...
2323
2324
2325
2326
2327
2328
2329
2330
2331
2332
2333
2334
2335
2336
2337
2338
2339
  /*
   * If the page is mmap'ed into a process' page tables, then we need to make
   * sure that it doesn't change while being written back.
   */
  static int
  cifs_page_mkwrite(struct vm_area_struct *vma, struct vm_fault *vmf)
  {
  	struct page *page = vmf->page;
  
  	lock_page(page);
  	return VM_FAULT_LOCKED;
  }
  
  static struct vm_operations_struct cifs_file_vm_ops = {
  	.fault = filemap_fault,
  	.page_mkwrite = cifs_page_mkwrite,
  };
7a6a19b17   Pavel Shilovsky   CIFS: Implement c...
2340
2341
2342
2343
2344
2345
  int cifs_file_strict_mmap(struct file *file, struct vm_area_struct *vma)
  {
  	int rc, xid;
  	struct inode *inode = file->f_path.dentry->d_inode;
  
  	xid = GetXid();
6feb9891d   Pavel Shilovsky   CIFS: Simplify in...
2346
2347
2348
2349
2350
  	if (!CIFS_I(inode)->clientCanCacheRead) {
  		rc = cifs_invalidate_mapping(inode);
  		if (rc)
  			return rc;
  	}
7a6a19b17   Pavel Shilovsky   CIFS: Implement c...
2351
2352
  
  	rc = generic_file_mmap(file, vma);
ca83ce3d5   Jeff Layton   cifs: don't allow...
2353
2354
  	if (rc == 0)
  		vma->vm_ops = &cifs_file_vm_ops;
7a6a19b17   Pavel Shilovsky   CIFS: Implement c...
2355
2356
2357
  	FreeXid(xid);
  	return rc;
  }
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
2358
2359
  int cifs_file_mmap(struct file *file, struct vm_area_struct *vma)
  {
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
2360
2361
2362
  	int rc, xid;
  
  	xid = GetXid();
abab095d1   Jeff Layton   cifs: add cifs_re...
2363
  	rc = cifs_revalidate_file(file);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
2364
  	if (rc) {
b6b38f704   Joe Perches   [CIFS] Neaten cER...
2365
  		cFYI(1, "Validation prior to mmap failed, error=%d", rc);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
2366
2367
2368
2369
  		FreeXid(xid);
  		return rc;
  	}
  	rc = generic_file_mmap(file, vma);
ca83ce3d5   Jeff Layton   cifs: don't allow...
2370
2371
  	if (rc == 0)
  		vma->vm_ops = &cifs_file_vm_ops;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
2372
2373
2374
  	FreeXid(xid);
  	return rc;
  }
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
2375
2376
2377
  static int cifs_readpages(struct file *file, struct address_space *mapping,
  	struct list_head *page_list, unsigned num_pages)
  {
690c5e316   Jeff Layton   cifs: convert cif...
2378
2379
2380
2381
2382
2383
  	int rc;
  	struct list_head tmplist;
  	struct cifsFileInfo *open_file = file->private_data;
  	struct cifs_sb_info *cifs_sb = CIFS_SB(file->f_path.dentry->d_sb);
  	unsigned int rsize = cifs_sb->rsize;
  	pid_t pid;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
2384

690c5e316   Jeff Layton   cifs: convert cif...
2385
2386
2387
2388
2389
2390
2391
2392
  	/*
  	 * Give up immediately if rsize is too small to read an entire page.
  	 * The VFS will fall back to readpage. We should never reach this
  	 * point however since we set ra_pages to 0 when the rsize is smaller
  	 * than a cache page.
  	 */
  	if (unlikely(rsize < PAGE_CACHE_SIZE))
  		return 0;
bfa0d75a1   Steve French   [CIFS] Add suppor...
2393

56698236e   Suresh Jayaraman   cifs: read pages ...
2394
2395
2396
2397
2398
2399
2400
  	/*
  	 * Reads as many pages as possible from fscache. Returns -ENOBUFS
  	 * immediately if the cookie is negative
  	 */
  	rc = cifs_readpages_from_fscache(mapping->host, mapping, page_list,
  					 &num_pages);
  	if (rc == 0)
690c5e316   Jeff Layton   cifs: convert cif...
2401
  		return rc;
56698236e   Suresh Jayaraman   cifs: read pages ...
2402

d4ffff1fa   Pavel Shilovsky   CIFS: Add rwpidfo...
2403
2404
2405
2406
  	if (cifs_sb->mnt_cifs_flags & CIFS_MOUNT_RWPIDFORWARD)
  		pid = open_file->pid;
  	else
  		pid = current->tgid;
690c5e316   Jeff Layton   cifs: convert cif...
2407
2408
  	rc = 0;
  	INIT_LIST_HEAD(&tmplist);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
2409

690c5e316   Jeff Layton   cifs: convert cif...
2410
2411
2412
2413
2414
2415
2416
2417
2418
2419
2420
2421
2422
2423
2424
2425
2426
2427
2428
2429
2430
  	cFYI(1, "%s: file=%p mapping=%p num_pages=%u", __func__, file,
  		mapping, num_pages);
  
  	/*
  	 * Start with the page at end of list and move it to private
  	 * list. Do the same with any following pages until we hit
  	 * the rsize limit, hit an index discontinuity, or run out of
  	 * pages. Issue the async read and then start the loop again
  	 * until the list is empty.
  	 *
  	 * Note that list order is important. The page_list is in
  	 * the order of declining indexes. When we put the pages in
  	 * the rdata->pages, then we want them in increasing order.
  	 */
  	while (!list_empty(page_list)) {
  		unsigned int bytes = PAGE_CACHE_SIZE;
  		unsigned int expected_index;
  		unsigned int nr_pages = 1;
  		loff_t offset;
  		struct page *page, *tpage;
  		struct cifs_readdata *rdata;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
2431
2432
  
  		page = list_entry(page_list->prev, struct page, lru);
690c5e316   Jeff Layton   cifs: convert cif...
2433
2434
2435
2436
2437
2438
2439
2440
2441
2442
2443
2444
2445
2446
2447
2448
2449
  
  		/*
  		 * Lock the page and put it in the cache. Since no one else
  		 * should have access to this page, we're safe to simply set
  		 * PG_locked without checking it first.
  		 */
  		__set_page_locked(page);
  		rc = add_to_page_cache_locked(page, mapping,
  					      page->index, GFP_KERNEL);
  
  		/* give up if we can't stick it in the cache */
  		if (rc) {
  			__clear_page_locked(page);
  			break;
  		}
  
  		/* move first page to the tmplist */
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
2450
  		offset = (loff_t)page->index << PAGE_CACHE_SHIFT;
690c5e316   Jeff Layton   cifs: convert cif...
2451
  		list_move_tail(&page->lru, &tmplist);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
2452

690c5e316   Jeff Layton   cifs: convert cif...
2453
2454
2455
2456
2457
  		/* now try and add more pages onto the request */
  		expected_index = page->index + 1;
  		list_for_each_entry_safe_reverse(page, tpage, page_list, lru) {
  			/* discontinuity ? */
  			if (page->index != expected_index)
fb8c4b14d   Steve French   [CIFS] whitespace...
2458
  				break;
690c5e316   Jeff Layton   cifs: convert cif...
2459
2460
2461
2462
2463
2464
2465
2466
2467
2468
2469
2470
2471
2472
2473
  
  			/* would this page push the read over the rsize? */
  			if (bytes + PAGE_CACHE_SIZE > rsize)
  				break;
  
  			__set_page_locked(page);
  			if (add_to_page_cache_locked(page, mapping,
  						page->index, GFP_KERNEL)) {
  				__clear_page_locked(page);
  				break;
  			}
  			list_move_tail(&page->lru, &tmplist);
  			bytes += PAGE_CACHE_SIZE;
  			expected_index++;
  			nr_pages++;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
2474
  		}
690c5e316   Jeff Layton   cifs: convert cif...
2475
2476
2477
2478
2479
2480
2481
2482
2483
2484
2485
2486
2487
2488
2489
2490
2491
2492
2493
2494
2495
2496
2497
2498
2499
  
  		rdata = cifs_readdata_alloc(nr_pages);
  		if (!rdata) {
  			/* best to give up if we're out of mem */
  			list_for_each_entry_safe(page, tpage, &tmplist, lru) {
  				list_del(&page->lru);
  				lru_cache_add_file(page);
  				unlock_page(page);
  				page_cache_release(page);
  			}
  			rc = -ENOMEM;
  			break;
  		}
  
  		spin_lock(&cifs_file_list_lock);
  		cifsFileInfo_get(open_file);
  		spin_unlock(&cifs_file_list_lock);
  		rdata->cfile = open_file;
  		rdata->mapping = mapping;
  		rdata->offset = offset;
  		rdata->bytes = bytes;
  		rdata->pid = pid;
  		list_splice_init(&tmplist, &rdata->pages);
  
  		do {
cdff08e76   Steve French   [CIFS] move close...
2500
  			if (open_file->invalidHandle) {
15886177e   Jeff Layton   cifs: clean up ci...
2501
  				rc = cifs_reopen_file(open_file, true);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
2502
  				if (rc != 0)
690c5e316   Jeff Layton   cifs: convert cif...
2503
  					continue;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
2504
  			}
690c5e316   Jeff Layton   cifs: convert cif...
2505
2506
  			rc = cifs_async_readv(rdata);
  		} while (rc == -EAGAIN);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
2507

690c5e316   Jeff Layton   cifs: convert cif...
2508
2509
2510
2511
2512
2513
2514
  		if (rc != 0) {
  			list_for_each_entry_safe(page, tpage, &rdata->pages,
  						 lru) {
  				list_del(&page->lru);
  				lru_cache_add_file(page);
  				unlock_page(page);
  				page_cache_release(page);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
2515
  			}
690c5e316   Jeff Layton   cifs: convert cif...
2516
  			cifs_readdata_free(rdata);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
2517
2518
  			break;
  		}
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
2519
  	}
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
2520
2521
2522
2523
2524
2525
2526
2527
  	return rc;
  }
  
  static int cifs_readpage_worker(struct file *file, struct page *page,
  	loff_t *poffset)
  {
  	char *read_data;
  	int rc;
56698236e   Suresh Jayaraman   cifs: read pages ...
2528
2529
2530
2531
  	/* Is the page cached? */
  	rc = cifs_readpage_from_fscache(file->f_path.dentry->d_inode, page);
  	if (rc == 0)
  		goto read_complete;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
2532
2533
2534
  	page_cache_get(page);
  	read_data = kmap(page);
  	/* for reads over a certain size could initiate async read ahead */
fb8c4b14d   Steve French   [CIFS] whitespace...
2535

1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
2536
  	rc = cifs_read(file, read_data, PAGE_CACHE_SIZE, poffset);
fb8c4b14d   Steve French   [CIFS] whitespace...
2537

1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
2538
2539
2540
  	if (rc < 0)
  		goto io_error;
  	else
b6b38f704   Joe Perches   [CIFS] Neaten cER...
2541
  		cFYI(1, "Bytes read %d", rc);
fb8c4b14d   Steve French   [CIFS] whitespace...
2542

e6a002964   Josef "Jeff" Sipek   [PATCH] cifs: cha...
2543
2544
  	file->f_path.dentry->d_inode->i_atime =
  		current_fs_time(file->f_path.dentry->d_inode->i_sb);
fb8c4b14d   Steve French   [CIFS] whitespace...
2545

1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
2546
2547
2548
2549
2550
  	if (PAGE_CACHE_SIZE > rc)
  		memset(read_data + rc, 0, PAGE_CACHE_SIZE - rc);
  
  	flush_dcache_page(page);
  	SetPageUptodate(page);
9dc06558c   Suresh Jayaraman   cifs: store pages...
2551
2552
2553
  
  	/* send this page to the cache */
  	cifs_readpage_to_fscache(file->f_path.dentry->d_inode, page);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
2554
  	rc = 0;
fb8c4b14d   Steve French   [CIFS] whitespace...
2555

1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
2556
  io_error:
fb8c4b14d   Steve French   [CIFS] whitespace...
2557
  	kunmap(page);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
2558
  	page_cache_release(page);
56698236e   Suresh Jayaraman   cifs: read pages ...
2559
2560
  
  read_complete:
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
2561
2562
2563
2564
2565
2566
2567
2568
2569
2570
2571
2572
  	return rc;
  }
  
  static int cifs_readpage(struct file *file, struct page *page)
  {
  	loff_t offset = (loff_t)page->index << PAGE_CACHE_SHIFT;
  	int rc = -EACCES;
  	int xid;
  
  	xid = GetXid();
  
  	if (file->private_data == NULL) {
0f3bc09ee   Suresh Jayaraman   cifs: Fix incorre...
2573
  		rc = -EBADF;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
2574
  		FreeXid(xid);
0f3bc09ee   Suresh Jayaraman   cifs: Fix incorre...
2575
  		return rc;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
2576
  	}
b6b38f704   Joe Perches   [CIFS] Neaten cER...
2577
2578
2579
  	cFYI(1, "readpage %p at offset %d 0x%x
  ",
  		 page, (int)offset, (int)offset);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
2580
2581
2582
2583
2584
2585
2586
2587
  
  	rc = cifs_readpage_worker(file, page, &offset);
  
  	unlock_page(page);
  
  	FreeXid(xid);
  	return rc;
  }
a403a0a37   Steve French   [CIFS] Fix hang i...
2588
2589
2590
  static int is_inode_writable(struct cifsInodeInfo *cifs_inode)
  {
  	struct cifsFileInfo *open_file;
4477288a1   Jeff Layton   cifs: convert Glo...
2591
  	spin_lock(&cifs_file_list_lock);
a403a0a37   Steve French   [CIFS] Fix hang i...
2592
  	list_for_each_entry(open_file, &cifs_inode->openFileList, flist) {
2e396b83f   Jeff Layton   cifs: eliminate p...
2593
  		if (OPEN_FMODE(open_file->f_flags) & FMODE_WRITE) {
4477288a1   Jeff Layton   cifs: convert Glo...
2594
  			spin_unlock(&cifs_file_list_lock);
a403a0a37   Steve French   [CIFS] Fix hang i...
2595
2596
2597
  			return 1;
  		}
  	}
4477288a1   Jeff Layton   cifs: convert Glo...
2598
  	spin_unlock(&cifs_file_list_lock);
a403a0a37   Steve French   [CIFS] Fix hang i...
2599
2600
  	return 0;
  }
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
2601
2602
2603
  /* We do not want to update the file size from server for inodes
     open for write - to avoid races with writepage extending
     the file - in the future we could consider allowing
fb8c4b14d   Steve French   [CIFS] whitespace...
2604
     refreshing the inode only on increases in the file size
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
2605
2606
     but this is tricky to do without racing with writebehind
     page caching in the current Linux kernel design */
4b18f2a9c   Steve French   [CIFS] convert us...
2607
  bool is_size_safe_to_change(struct cifsInodeInfo *cifsInode, __u64 end_of_file)
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
2608
  {
a403a0a37   Steve French   [CIFS] Fix hang i...
2609
  	if (!cifsInode)
4b18f2a9c   Steve French   [CIFS] convert us...
2610
  		return true;
50c2f7538   Steve French   [CIFS] whitespace...
2611

a403a0a37   Steve French   [CIFS] Fix hang i...
2612
2613
  	if (is_inode_writable(cifsInode)) {
  		/* This inode is open for write at least once */
c32a0b689   Steve French   [CIFS] Allow loca...
2614
  		struct cifs_sb_info *cifs_sb;
c32a0b689   Steve French   [CIFS] Allow loca...
2615
  		cifs_sb = CIFS_SB(cifsInode->vfs_inode.i_sb);
ad7a2926b   Steve French   [CIFS] reduce che...
2616
  		if (cifs_sb->mnt_cifs_flags & CIFS_MOUNT_DIRECT_IO) {
fb8c4b14d   Steve French   [CIFS] whitespace...
2617
  			/* since no page cache to corrupt on directio
c32a0b689   Steve French   [CIFS] Allow loca...
2618
  			we can change size safely */
4b18f2a9c   Steve French   [CIFS] convert us...
2619
  			return true;
c32a0b689   Steve French   [CIFS] Allow loca...
2620
  		}
fb8c4b14d   Steve French   [CIFS] whitespace...
2621
  		if (i_size_read(&cifsInode->vfs_inode) < end_of_file)
4b18f2a9c   Steve French   [CIFS] convert us...
2622
  			return true;
7ba526316   Steve French   [CIFS] Allow upda...
2623

4b18f2a9c   Steve French   [CIFS] convert us...
2624
  		return false;
23e7dd7d9   Steve French   [CIFS] Defer clos...
2625
  	} else
4b18f2a9c   Steve French   [CIFS] convert us...
2626
  		return true;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
2627
  }
d9414774d   Nick Piggin   cifs: Convert cif...
2628
2629
2630
  static int cifs_write_begin(struct file *file, struct address_space *mapping,
  			loff_t pos, unsigned len, unsigned flags,
  			struct page **pagep, void **fsdata)
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
2631
  {
d9414774d   Nick Piggin   cifs: Convert cif...
2632
2633
  	pgoff_t index = pos >> PAGE_CACHE_SHIFT;
  	loff_t offset = pos & (PAGE_CACHE_SIZE - 1);
a98ee8c1c   Jeff Layton   [CIFS] fix regres...
2634
2635
2636
2637
  	loff_t page_start = pos & PAGE_MASK;
  	loff_t i_size;
  	struct page *page;
  	int rc = 0;
d9414774d   Nick Piggin   cifs: Convert cif...
2638

b6b38f704   Joe Perches   [CIFS] Neaten cER...
2639
  	cFYI(1, "write_begin from %lld len %d", (long long)pos, len);
d9414774d   Nick Piggin   cifs: Convert cif...
2640

54566b2c1   Nick Piggin   fs: symlink write...
2641
  	page = grab_cache_page_write_begin(mapping, index, flags);
a98ee8c1c   Jeff Layton   [CIFS] fix regres...
2642
2643
2644
2645
  	if (!page) {
  		rc = -ENOMEM;
  		goto out;
  	}
8a236264f   Steve French   [CIFS] cifs_prepa...
2646

a98ee8c1c   Jeff Layton   [CIFS] fix regres...
2647
2648
  	if (PageUptodate(page))
  		goto out;
8a236264f   Steve French   [CIFS] cifs_prepa...
2649

a98ee8c1c   Jeff Layton   [CIFS] fix regres...
2650
2651
2652
2653
2654
2655
2656
  	/*
  	 * If we write a full page it will be up to date, no need to read from
  	 * the server. If the write is short, we'll end up doing a sync write
  	 * instead.
  	 */
  	if (len == PAGE_CACHE_SIZE)
  		goto out;
8a236264f   Steve French   [CIFS] cifs_prepa...
2657

a98ee8c1c   Jeff Layton   [CIFS] fix regres...
2658
2659
2660
2661
2662
2663
2664
2665
2666
2667
2668
2669
2670
2671
2672
2673
2674
2675
2676
2677
2678
2679
2680
  	/*
  	 * optimize away the read when we have an oplock, and we're not
  	 * expecting to use any of the data we'd be reading in. That
  	 * is, when the page lies beyond the EOF, or straddles the EOF
  	 * and the write will cover all of the existing data.
  	 */
  	if (CIFS_I(mapping->host)->clientCanCacheRead) {
  		i_size = i_size_read(mapping->host);
  		if (page_start >= i_size ||
  		    (offset == 0 && (pos + len) >= i_size)) {
  			zero_user_segments(page, 0, offset,
  					   offset + len,
  					   PAGE_CACHE_SIZE);
  			/*
  			 * PageChecked means that the parts of the page
  			 * to which we're not writing are considered up
  			 * to date. Once the data is copied to the
  			 * page, it can be set uptodate.
  			 */
  			SetPageChecked(page);
  			goto out;
  		}
  	}
d9414774d   Nick Piggin   cifs: Convert cif...
2681

a98ee8c1c   Jeff Layton   [CIFS] fix regres...
2682
2683
2684
2685
2686
2687
2688
  	if ((file->f_flags & O_ACCMODE) != O_WRONLY) {
  		/*
  		 * might as well read a page, it is fast enough. If we get
  		 * an error, we don't need to return it. cifs_write_end will
  		 * do a sync write instead since PG_uptodate isn't set.
  		 */
  		cifs_readpage_worker(file, page, &page_start);
8a236264f   Steve French   [CIFS] cifs_prepa...
2689
2690
2691
2692
  	} else {
  		/* we could try using another file handle if there is one -
  		   but how would we lock it to prevent close of that handle
  		   racing with this read? In any case
d9414774d   Nick Piggin   cifs: Convert cif...
2693
  		   this will be written out by write_end so is fine */
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
2694
  	}
a98ee8c1c   Jeff Layton   [CIFS] fix regres...
2695
2696
2697
  out:
  	*pagep = page;
  	return rc;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
2698
  }
85f2d6b44   Suresh Jayaraman   cifs: FS-Cache pa...
2699
2700
2701
2702
2703
2704
2705
2706
2707
2708
2709
2710
2711
2712
2713
  static int cifs_release_page(struct page *page, gfp_t gfp)
  {
  	if (PagePrivate(page))
  		return 0;
  
  	return cifs_fscache_release_page(page, gfp);
  }
  
  static void cifs_invalidate_page(struct page *page, unsigned long offset)
  {
  	struct cifsInodeInfo *cifsi = CIFS_I(page->mapping->host);
  
  	if (offset == 0)
  		cifs_fscache_invalidate_page(page, &cifsi->vfs_inode);
  }
9ad1506b4   Pavel Shilovsky   CIFS: Add launder...
2714
2715
2716
2717
2718
2719
2720
2721
2722
2723
2724
2725
2726
2727
2728
2729
2730
2731
2732
2733
  static int cifs_launder_page(struct page *page)
  {
  	int rc = 0;
  	loff_t range_start = page_offset(page);
  	loff_t range_end = range_start + (loff_t)(PAGE_CACHE_SIZE - 1);
  	struct writeback_control wbc = {
  		.sync_mode = WB_SYNC_ALL,
  		.nr_to_write = 0,
  		.range_start = range_start,
  		.range_end = range_end,
  	};
  
  	cFYI(1, "Launder page: %p", page);
  
  	if (clear_page_dirty_for_io(page))
  		rc = cifs_writepage_locked(page, &wbc);
  
  	cifs_fscache_invalidate_page(page, page->mapping->host);
  	return rc;
  }
9b6469724   Tejun Heo   cifs: use workque...
2734
  void cifs_oplock_break(struct work_struct *work)
3bc303c25   Jeff Layton   cifs: convert opl...
2735
2736
2737
  {
  	struct cifsFileInfo *cfile = container_of(work, struct cifsFileInfo,
  						  oplock_break);
a5e18bc36   Jeff Layton   cifs: keep dentry...
2738
  	struct inode *inode = cfile->dentry->d_inode;
3bc303c25   Jeff Layton   cifs: convert opl...
2739
  	struct cifsInodeInfo *cinode = CIFS_I(inode);
eb4b756b1   Jeff Layton   cifs: eliminate c...
2740
  	int rc = 0;
3bc303c25   Jeff Layton   cifs: convert opl...
2741
2742
  
  	if (inode && S_ISREG(inode->i_mode)) {
d54ff7325   Steve French   [CIFS] Fix lease ...
2743
  		if (cinode->clientCanCacheRead)
8737c9305   Al Viro   Switch may_open()...
2744
  			break_lease(inode, O_RDONLY);
d54ff7325   Steve French   [CIFS] Fix lease ...
2745
  		else
8737c9305   Al Viro   Switch may_open()...
2746
  			break_lease(inode, O_WRONLY);
3bc303c25   Jeff Layton   cifs: convert opl...
2747
2748
  		rc = filemap_fdatawrite(inode->i_mapping);
  		if (cinode->clientCanCacheRead == 0) {
eb4b756b1   Jeff Layton   cifs: eliminate c...
2749
2750
  			rc = filemap_fdatawait(inode->i_mapping);
  			mapping_set_error(inode->i_mapping, rc);
3bc303c25   Jeff Layton   cifs: convert opl...
2751
2752
  			invalidate_remote_inode(inode);
  		}
b6b38f704   Joe Perches   [CIFS] Neaten cER...
2753
  		cFYI(1, "Oplock flush inode %p rc %d", inode, rc);
3bc303c25   Jeff Layton   cifs: convert opl...
2754
  	}
85160e03a   Pavel Shilovsky   CIFS: Implement c...
2755
2756
2757
  	rc = cifs_push_locks(cfile);
  	if (rc)
  		cERROR(1, "Push locks rc = %d", rc);
3bc303c25   Jeff Layton   cifs: convert opl...
2758
2759
2760
2761
2762
2763
  	/*
  	 * releasing stale oplock after recent reconnect of smb session using
  	 * a now incorrect file handle is not a data integrity issue but do
  	 * not bother sending an oplock release if session to server still is
  	 * disconnected since oplock already released by the server
  	 */
cdff08e76   Steve French   [CIFS] move close...
2764
  	if (!cfile->oplock_break_cancelled) {
03776f451   Pavel Shilovsky   CIFS: Simplify by...
2765
2766
2767
  		rc = CIFSSMBLock(0, tlink_tcon(cfile->tlink), cfile->netfid,
  				 current->tgid, 0, 0, 0, 0,
  				 LOCKING_ANDX_OPLOCK_RELEASE, false,
12fed00de   Pavel Shilovsky   CIFS: Fix oplock ...
2768
  				 cinode->clientCanCacheRead ? 1 : 0);
b6b38f704   Joe Perches   [CIFS] Neaten cER...
2769
  		cFYI(1, "Oplock release rc = %d", rc);
3bc303c25   Jeff Layton   cifs: convert opl...
2770
  	}
3bc303c25   Jeff Layton   cifs: convert opl...
2771
  }
f5e54d6e5   Christoph Hellwig   [PATCH] mark addr...
2772
  const struct address_space_operations cifs_addr_ops = {
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
2773
2774
2775
  	.readpage = cifs_readpage,
  	.readpages = cifs_readpages,
  	.writepage = cifs_writepage,
37c0eb467   Steve French   CIFS: implement c...
2776
  	.writepages = cifs_writepages,
d9414774d   Nick Piggin   cifs: Convert cif...
2777
2778
  	.write_begin = cifs_write_begin,
  	.write_end = cifs_write_end,
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
2779
  	.set_page_dirty = __set_page_dirty_nobuffers,
85f2d6b44   Suresh Jayaraman   cifs: FS-Cache pa...
2780
2781
  	.releasepage = cifs_release_page,
  	.invalidatepage = cifs_invalidate_page,
9ad1506b4   Pavel Shilovsky   CIFS: Add launder...
2782
  	.launder_page = cifs_launder_page,
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
2783
  };
273d81d6a   Dave Kleikamp   [CIFS] Do not ove...
2784
2785
2786
2787
2788
2789
  
  /*
   * cifs_readpages requires the server to support a buffer large enough to
   * contain the header plus one complete page of data.  Otherwise, we need
   * to leave cifs_readpages out of the address space operations.
   */
f5e54d6e5   Christoph Hellwig   [PATCH] mark addr...
2790
  const struct address_space_operations cifs_addr_ops_smallbuf = {
273d81d6a   Dave Kleikamp   [CIFS] Do not ove...
2791
2792
2793
  	.readpage = cifs_readpage,
  	.writepage = cifs_writepage,
  	.writepages = cifs_writepages,
d9414774d   Nick Piggin   cifs: Convert cif...
2794
2795
  	.write_begin = cifs_write_begin,
  	.write_end = cifs_write_end,
273d81d6a   Dave Kleikamp   [CIFS] Do not ove...
2796
  	.set_page_dirty = __set_page_dirty_nobuffers,
85f2d6b44   Suresh Jayaraman   cifs: FS-Cache pa...
2797
2798
  	.releasepage = cifs_release_page,
  	.invalidatepage = cifs_invalidate_page,
9ad1506b4   Pavel Shilovsky   CIFS: Add launder...
2799
  	.launder_page = cifs_launder_page,
273d81d6a   Dave Kleikamp   [CIFS] Do not ove...
2800
  };