blob: 7bef4cce572a6e3785c8eafa5b1f1e17ac819095 [file] [log] [blame]
Linus Torvalds1da177e2005-04-16 15:20:36 -07001/*
2 * fs/cifs/file.c
3 *
4 * vfs operations that deal with files
Steve Frenchfb8c4b12007-07-10 01:16:18 +00005 *
6 * Copyright (C) International Business Machines Corp., 2002,2007
Linus Torvalds1da177e2005-04-16 15:20:36 -07007 * Author(s): Steve French (sfrench@us.ibm.com)
Jeremy Allison7ee1af72006-08-02 21:56:33 +00008 * Jeremy Allison (jra@samba.org)
Linus Torvalds1da177e2005-04-16 15:20:36 -07009 *
10 * This library is free software; you can redistribute it and/or modify
11 * it under the terms of the GNU Lesser General Public License as published
12 * by the Free Software Foundation; either version 2.1 of the License, or
13 * (at your option) any later version.
14 *
15 * This library is distributed in the hope that it will be useful,
16 * but WITHOUT ANY WARRANTY; without even the implied warranty of
17 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See
18 * the GNU Lesser General Public License for more details.
19 *
20 * You should have received a copy of the GNU Lesser General Public License
21 * along with this library; if not, write to the Free Software
22 * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
23 */
24#include <linux/fs.h>
Steve French37c0eb42005-10-05 14:50:29 -070025#include <linux/backing-dev.h>
Linus Torvalds1da177e2005-04-16 15:20:36 -070026#include <linux/stat.h>
27#include <linux/fcntl.h>
28#include <linux/pagemap.h>
29#include <linux/pagevec.h>
Steve French37c0eb42005-10-05 14:50:29 -070030#include <linux/writeback.h>
Andrew Morton6f88cc22006-12-10 02:19:44 -080031#include <linux/task_io_accounting_ops.h>
Steve French23e7dd72005-10-20 13:44:56 -070032#include <linux/delay.h>
Linus Torvalds1da177e2005-04-16 15:20:36 -070033#include <asm/div64.h>
34#include "cifsfs.h"
35#include "cifspdu.h"
36#include "cifsglob.h"
37#include "cifsproto.h"
38#include "cifs_unicode.h"
39#include "cifs_debug.h"
40#include "cifs_fs_sb.h"
41
42static inline struct cifsFileInfo *cifs_init_private(
43 struct cifsFileInfo *private_data, struct inode *inode,
44 struct file *file, __u16 netfid)
45{
46 memset(private_data, 0, sizeof(struct cifsFileInfo));
47 private_data->netfid = netfid;
Steve Frenchfb8c4b12007-07-10 01:16:18 +000048 private_data->pid = current->tgid;
Linus Torvalds1da177e2005-04-16 15:20:36 -070049 init_MUTEX(&private_data->fh_sem);
Roland Dreier796e5662007-05-03 04:33:45 +000050 mutex_init(&private_data->lock_mutex);
Jeremy Allison7ee1af72006-08-02 21:56:33 +000051 INIT_LIST_HEAD(&private_data->llist);
Linus Torvalds1da177e2005-04-16 15:20:36 -070052 private_data->pfile = file; /* needed for writepage */
53 private_data->pInode = inode;
Steve French4b18f2a2008-04-29 00:06:05 +000054 private_data->invalidHandle = false;
55 private_data->closePend = false;
Steve French23e7dd72005-10-20 13:44:56 -070056 /* we have to track num writers to the inode, since writepages
57 does not tell us which handle the write is for so there can
58 be a close (overlapping with write) of the filehandle that
59 cifs_writepages chose to use */
Steve Frenchfb8c4b12007-07-10 01:16:18 +000060 atomic_set(&private_data->wrtPending, 0);
Linus Torvalds1da177e2005-04-16 15:20:36 -070061
62 return private_data;
63}
64
65static inline int cifs_convert_flags(unsigned int flags)
66{
67 if ((flags & O_ACCMODE) == O_RDONLY)
68 return GENERIC_READ;
69 else if ((flags & O_ACCMODE) == O_WRONLY)
70 return GENERIC_WRITE;
71 else if ((flags & O_ACCMODE) == O_RDWR) {
72 /* GENERIC_ALL is too much permission to request
73 can cause unnecessary access denied on create */
74 /* return GENERIC_ALL; */
75 return (GENERIC_READ | GENERIC_WRITE);
76 }
77
Jeff Laytone10f7b52008-05-14 10:21:33 -070078 return (READ_CONTROL | FILE_WRITE_ATTRIBUTES | FILE_READ_ATTRIBUTES |
79 FILE_WRITE_EA | FILE_APPEND_DATA | FILE_WRITE_DATA |
80 FILE_READ_DATA);
Steve French7fc8f4e2009-02-23 20:43:11 +000081}
Jeff Laytone10f7b52008-05-14 10:21:33 -070082
Steve French7fc8f4e2009-02-23 20:43:11 +000083static inline fmode_t cifs_posix_convert_flags(unsigned int flags)
84{
85 fmode_t posix_flags = 0;
Jeff Laytone10f7b52008-05-14 10:21:33 -070086
Steve French7fc8f4e2009-02-23 20:43:11 +000087 if ((flags & O_ACCMODE) == O_RDONLY)
88 posix_flags = FMODE_READ;
89 else if ((flags & O_ACCMODE) == O_WRONLY)
90 posix_flags = FMODE_WRITE;
91 else if ((flags & O_ACCMODE) == O_RDWR) {
92 /* GENERIC_ALL is too much permission to request
93 can cause unnecessary access denied on create */
94 /* return GENERIC_ALL; */
95 posix_flags = FMODE_READ | FMODE_WRITE;
96 }
97 /* can not map O_CREAT or O_EXCL or O_TRUNC flags when
98 reopening a file. They had their effect on the original open */
99 if (flags & O_APPEND)
100 posix_flags |= (fmode_t)O_APPEND;
101 if (flags & O_SYNC)
102 posix_flags |= (fmode_t)O_SYNC;
103 if (flags & O_DIRECTORY)
104 posix_flags |= (fmode_t)O_DIRECTORY;
105 if (flags & O_NOFOLLOW)
106 posix_flags |= (fmode_t)O_NOFOLLOW;
107 if (flags & O_DIRECT)
108 posix_flags |= (fmode_t)O_DIRECT;
109
110 return posix_flags;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700111}
112
113static inline int cifs_get_disposition(unsigned int flags)
114{
115 if ((flags & (O_CREAT | O_EXCL)) == (O_CREAT | O_EXCL))
116 return FILE_CREATE;
117 else if ((flags & (O_CREAT | O_TRUNC)) == (O_CREAT | O_TRUNC))
118 return FILE_OVERWRITE_IF;
119 else if ((flags & O_CREAT) == O_CREAT)
120 return FILE_OPEN_IF;
Steve French55aa2e02006-05-30 18:09:31 +0000121 else if ((flags & O_TRUNC) == O_TRUNC)
122 return FILE_OVERWRITE;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700123 else
124 return FILE_OPEN;
125}
126
127/* all arguments to this function must be checked for validity in caller */
Steve French276a74a2009-03-03 18:00:34 +0000128static inline int cifs_posix_open_inode_helper(struct inode *inode,
129 struct file *file, struct cifsInodeInfo *pCifsInode,
130 struct cifsFileInfo *pCifsFile, int oplock, u16 netfid)
131{
132 struct cifs_sb_info *cifs_sb = CIFS_SB(inode->i_sb);
133/* struct timespec temp; */ /* BB REMOVEME BB */
134
135 file->private_data = kmalloc(sizeof(struct cifsFileInfo), GFP_KERNEL);
136 if (file->private_data == NULL)
137 return -ENOMEM;
138 pCifsFile = cifs_init_private(file->private_data, inode, file, netfid);
139 write_lock(&GlobalSMBSeslock);
140 list_add(&pCifsFile->tlist, &cifs_sb->tcon->openFileList);
141
142 pCifsInode = CIFS_I(file->f_path.dentry->d_inode);
143 if (pCifsInode == NULL) {
144 write_unlock(&GlobalSMBSeslock);
145 return -EINVAL;
146 }
147
148 /* want handles we can use to read with first
149 in the list so we do not have to walk the
150 list to search for one in write_begin */
151 if ((file->f_flags & O_ACCMODE) == O_WRONLY) {
152 list_add_tail(&pCifsFile->flist,
153 &pCifsInode->openFileList);
154 } else {
155 list_add(&pCifsFile->flist,
156 &pCifsInode->openFileList);
157 }
158
159 if (pCifsInode->clientCanCacheRead) {
160 /* we have the inode open somewhere else
161 no need to discard cache data */
162 goto psx_client_can_cache;
163 }
164
165 /* BB FIXME need to fix this check to move it earlier into posix_open
166 BB fIX following section BB FIXME */
167
168 /* if not oplocked, invalidate inode pages if mtime or file
169 size changed */
170/* temp = cifs_NTtimeToUnix(le64_to_cpu(buf->LastWriteTime));
171 if (timespec_equal(&file->f_path.dentry->d_inode->i_mtime, &temp) &&
172 (file->f_path.dentry->d_inode->i_size ==
173 (loff_t)le64_to_cpu(buf->EndOfFile))) {
174 cFYI(1, ("inode unchanged on server"));
175 } else {
176 if (file->f_path.dentry->d_inode->i_mapping) {
177 rc = filemap_write_and_wait(file->f_path.dentry->d_inode->i_mapping);
178 if (rc != 0)
179 CIFS_I(file->f_path.dentry->d_inode)->write_behind_rc = rc;
180 }
181 cFYI(1, ("invalidating remote inode since open detected it "
182 "changed"));
183 invalidate_remote_inode(file->f_path.dentry->d_inode);
184 } */
185
186psx_client_can_cache:
187 if ((oplock & 0xF) == OPLOCK_EXCLUSIVE) {
188 pCifsInode->clientCanCacheAll = true;
189 pCifsInode->clientCanCacheRead = true;
190 cFYI(1, ("Exclusive Oplock granted on inode %p",
191 file->f_path.dentry->d_inode));
192 } else if ((oplock & 0xF) == OPLOCK_READ)
193 pCifsInode->clientCanCacheRead = true;
194
195 /* will have to change the unlock if we reenable the
196 filemap_fdatawrite (which does not seem necessary */
197 write_unlock(&GlobalSMBSeslock);
198 return 0;
199}
200
201/* all arguments to this function must be checked for validity in caller */
Linus Torvalds1da177e2005-04-16 15:20:36 -0700202static inline int cifs_open_inode_helper(struct inode *inode, struct file *file,
203 struct cifsInodeInfo *pCifsInode, struct cifsFileInfo *pCifsFile,
204 struct cifsTconInfo *pTcon, int *oplock, FILE_ALL_INFO *buf,
205 char *full_path, int xid)
206{
207 struct timespec temp;
208 int rc;
209
210 /* want handles we can use to read with first
211 in the list so we do not have to walk the
Nick Piggind9414772008-09-24 11:32:59 -0400212 list to search for one in write_begin */
Linus Torvalds1da177e2005-04-16 15:20:36 -0700213 if ((file->f_flags & O_ACCMODE) == O_WRONLY) {
Steve Frenchfb8c4b12007-07-10 01:16:18 +0000214 list_add_tail(&pCifsFile->flist,
Linus Torvalds1da177e2005-04-16 15:20:36 -0700215 &pCifsInode->openFileList);
216 } else {
217 list_add(&pCifsFile->flist,
218 &pCifsInode->openFileList);
219 }
220 write_unlock(&GlobalSMBSeslock);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700221 if (pCifsInode->clientCanCacheRead) {
222 /* we have the inode open somewhere else
223 no need to discard cache data */
224 goto client_can_cache;
225 }
226
227 /* BB need same check in cifs_create too? */
228 /* if not oplocked, invalidate inode pages if mtime or file
229 size changed */
230 temp = cifs_NTtimeToUnix(le64_to_cpu(buf->LastWriteTime));
Josef "Jeff" Sipeke6a00292006-12-08 02:36:48 -0800231 if (timespec_equal(&file->f_path.dentry->d_inode->i_mtime, &temp) &&
232 (file->f_path.dentry->d_inode->i_size ==
Linus Torvalds1da177e2005-04-16 15:20:36 -0700233 (loff_t)le64_to_cpu(buf->EndOfFile))) {
234 cFYI(1, ("inode unchanged on server"));
235 } else {
Josef "Jeff" Sipeke6a00292006-12-08 02:36:48 -0800236 if (file->f_path.dentry->d_inode->i_mapping) {
Linus Torvalds1da177e2005-04-16 15:20:36 -0700237 /* BB no need to lock inode until after invalidate
238 since namei code should already have it locked? */
Jeff Laytoncea21802007-11-20 23:19:03 +0000239 rc = filemap_write_and_wait(file->f_path.dentry->d_inode->i_mapping);
240 if (rc != 0)
241 CIFS_I(file->f_path.dentry->d_inode)->write_behind_rc = rc;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700242 }
243 cFYI(1, ("invalidating remote inode since open detected it "
244 "changed"));
Josef "Jeff" Sipeke6a00292006-12-08 02:36:48 -0800245 invalidate_remote_inode(file->f_path.dentry->d_inode);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700246 }
247
248client_can_cache:
Steve Frenchc18c8422007-07-18 23:21:09 +0000249 if (pTcon->unix_ext)
Josef "Jeff" Sipeke6a00292006-12-08 02:36:48 -0800250 rc = cifs_get_inode_info_unix(&file->f_path.dentry->d_inode,
Linus Torvalds1da177e2005-04-16 15:20:36 -0700251 full_path, inode->i_sb, xid);
252 else
Josef "Jeff" Sipeke6a00292006-12-08 02:36:48 -0800253 rc = cifs_get_inode_info(&file->f_path.dentry->d_inode,
Steve French8b1327f2008-03-14 22:37:16 +0000254 full_path, buf, inode->i_sb, xid, NULL);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700255
256 if ((*oplock & 0xF) == OPLOCK_EXCLUSIVE) {
Steve French4b18f2a2008-04-29 00:06:05 +0000257 pCifsInode->clientCanCacheAll = true;
258 pCifsInode->clientCanCacheRead = true;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700259 cFYI(1, ("Exclusive Oplock granted on inode %p",
Josef "Jeff" Sipeke6a00292006-12-08 02:36:48 -0800260 file->f_path.dentry->d_inode));
Linus Torvalds1da177e2005-04-16 15:20:36 -0700261 } else if ((*oplock & 0xF) == OPLOCK_READ)
Steve French4b18f2a2008-04-29 00:06:05 +0000262 pCifsInode->clientCanCacheRead = true;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700263
264 return rc;
265}
266
267int cifs_open(struct inode *inode, struct file *file)
268{
269 int rc = -EACCES;
270 int xid, oplock;
271 struct cifs_sb_info *cifs_sb;
Steve French276a74a2009-03-03 18:00:34 +0000272 struct cifsTconInfo *tcon;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700273 struct cifsFileInfo *pCifsFile;
274 struct cifsInodeInfo *pCifsInode;
275 struct list_head *tmp;
276 char *full_path = NULL;
277 int desiredAccess;
278 int disposition;
279 __u16 netfid;
280 FILE_ALL_INFO *buf = NULL;
281
282 xid = GetXid();
283
284 cifs_sb = CIFS_SB(inode->i_sb);
Steve French276a74a2009-03-03 18:00:34 +0000285 tcon = cifs_sb->tcon;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700286
287 if (file->f_flags & O_CREAT) {
288 /* search inode for this file and fill in file->private_data */
Josef "Jeff" Sipeke6a00292006-12-08 02:36:48 -0800289 pCifsInode = CIFS_I(file->f_path.dentry->d_inode);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700290 read_lock(&GlobalSMBSeslock);
291 list_for_each(tmp, &pCifsInode->openFileList) {
292 pCifsFile = list_entry(tmp, struct cifsFileInfo,
293 flist);
294 if ((pCifsFile->pfile == NULL) &&
295 (pCifsFile->pid == current->tgid)) {
296 /* mode set in cifs_create */
297
298 /* needed for writepage */
299 pCifsFile->pfile = file;
Steve French50c2f752007-07-13 00:33:32 +0000300
Linus Torvalds1da177e2005-04-16 15:20:36 -0700301 file->private_data = pCifsFile;
302 break;
303 }
304 }
305 read_unlock(&GlobalSMBSeslock);
306 if (file->private_data != NULL) {
307 rc = 0;
308 FreeXid(xid);
309 return rc;
310 } else {
311 if (file->f_flags & O_EXCL)
312 cERROR(1, ("could not find file instance for "
Steve French26a21b92006-05-31 18:05:34 +0000313 "new file %p", file));
Linus Torvalds1da177e2005-04-16 15:20:36 -0700314 }
315 }
316
Josef "Jeff" Sipeke6a00292006-12-08 02:36:48 -0800317 full_path = build_path_from_dentry(file->f_path.dentry);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700318 if (full_path == NULL) {
319 FreeXid(xid);
320 return -ENOMEM;
321 }
322
Steve French7521a3c2007-07-11 18:30:34 +0000323 cFYI(1, ("inode = 0x%p file flags are 0x%x for %s",
Linus Torvalds1da177e2005-04-16 15:20:36 -0700324 inode, file->f_flags, full_path));
Steve French276a74a2009-03-03 18:00:34 +0000325
326 if (oplockEnabled)
327 oplock = REQ_OPLOCK;
328 else
329 oplock = 0;
330
331 if (tcon->unix_ext && (tcon->ses->capabilities & CAP_UNIX) &&
332 (CIFS_UNIX_POSIX_PATH_OPS_CAP &
333 le64_to_cpu(tcon->fsUnixInfo.Capability))) {
334 int oflags = (int) cifs_posix_convert_flags(file->f_flags);
335 /* can not refresh inode info since size could be stale */
336 rc = cifs_posix_open(full_path, &inode, inode->i_sb,
337 cifs_sb->mnt_file_mode /* ignored */,
338 oflags, &oplock, &netfid, xid);
339 if (rc == 0) {
340 cFYI(1, ("posix open succeeded"));
341 /* no need for special case handling of setting mode
342 on read only files needed here */
343
344 cifs_posix_open_inode_helper(inode, file, pCifsInode,
345 pCifsFile, oplock, netfid);
346 goto out;
347 } else if ((rc != -EIO) && (rc != -EREMOTE) &&
348 (rc != -EOPNOTSUPP)) /* path not found or net err */
349 goto out;
350 /* fallthrough to retry open the old way on operation
351 not supported or DFS errors */
352 }
353
Linus Torvalds1da177e2005-04-16 15:20:36 -0700354 desiredAccess = cifs_convert_flags(file->f_flags);
355
356/*********************************************************************
357 * open flag mapping table:
Steve Frenchfb8c4b12007-07-10 01:16:18 +0000358 *
Linus Torvalds1da177e2005-04-16 15:20:36 -0700359 * POSIX Flag CIFS Disposition
Steve Frenchfb8c4b12007-07-10 01:16:18 +0000360 * ---------- ----------------
Linus Torvalds1da177e2005-04-16 15:20:36 -0700361 * O_CREAT FILE_OPEN_IF
362 * O_CREAT | O_EXCL FILE_CREATE
363 * O_CREAT | O_TRUNC FILE_OVERWRITE_IF
364 * O_TRUNC FILE_OVERWRITE
365 * none of the above FILE_OPEN
366 *
367 * Note that there is not a direct match between disposition
Steve Frenchfb8c4b12007-07-10 01:16:18 +0000368 * FILE_SUPERSEDE (ie create whether or not file exists although
Linus Torvalds1da177e2005-04-16 15:20:36 -0700369 * O_CREAT | O_TRUNC is similar but truncates the existing
370 * file rather than creating a new file as FILE_SUPERSEDE does
371 * (which uses the attributes / metadata passed in on open call)
372 *?
Steve Frenchfb8c4b12007-07-10 01:16:18 +0000373 *? O_SYNC is a reasonable match to CIFS writethrough flag
Linus Torvalds1da177e2005-04-16 15:20:36 -0700374 *? and the read write flags match reasonably. O_LARGEFILE
375 *? is irrelevant because largefile support is always used
376 *? by this client. Flags O_APPEND, O_DIRECT, O_DIRECTORY,
377 * O_FASYNC, O_NOFOLLOW, O_NONBLOCK need further investigation
378 *********************************************************************/
379
380 disposition = cifs_get_disposition(file->f_flags);
381
Linus Torvalds1da177e2005-04-16 15:20:36 -0700382 /* BB pass O_SYNC flag through on file attributes .. BB */
383
384 /* Also refresh inode by passing in file_info buf returned by SMBOpen
385 and calling get_inode_info with returned buf (at least helps
386 non-Unix server case) */
387
Steve Frenchfb8c4b12007-07-10 01:16:18 +0000388 /* BB we can not do this if this is the second open of a file
389 and the first handle has writebehind data, we might be
Linus Torvalds1da177e2005-04-16 15:20:36 -0700390 able to simply do a filemap_fdatawrite/filemap_fdatawait first */
391 buf = kmalloc(sizeof(FILE_ALL_INFO), GFP_KERNEL);
392 if (!buf) {
393 rc = -ENOMEM;
394 goto out;
395 }
Steve French5bafd762006-06-07 00:18:43 +0000396
397 if (cifs_sb->tcon->ses->capabilities & CAP_NT_SMBS)
Steve French276a74a2009-03-03 18:00:34 +0000398 rc = CIFSSMBOpen(xid, tcon, full_path, disposition,
Steve French5bafd762006-06-07 00:18:43 +0000399 desiredAccess, CREATE_NOT_DIR, &netfid, &oplock, buf,
Steve French737b7582005-04-28 22:41:06 -0700400 cifs_sb->local_nls, cifs_sb->mnt_cifs_flags
401 & CIFS_MOUNT_MAP_SPECIAL_CHR);
Steve French5bafd762006-06-07 00:18:43 +0000402 else
403 rc = -EIO; /* no NT SMB support fall into legacy open below */
404
Steve Frencha9d02ad2005-08-24 23:06:05 -0700405 if (rc == -EIO) {
406 /* Old server, try legacy style OpenX */
Steve French276a74a2009-03-03 18:00:34 +0000407 rc = SMBLegacyOpen(xid, tcon, full_path, disposition,
Steve Frencha9d02ad2005-08-24 23:06:05 -0700408 desiredAccess, CREATE_NOT_DIR, &netfid, &oplock, buf,
409 cifs_sb->local_nls, cifs_sb->mnt_cifs_flags
410 & CIFS_MOUNT_MAP_SPECIAL_CHR);
411 }
Linus Torvalds1da177e2005-04-16 15:20:36 -0700412 if (rc) {
Steve French26a21b92006-05-31 18:05:34 +0000413 cFYI(1, ("cifs_open returned 0x%x", rc));
Linus Torvalds1da177e2005-04-16 15:20:36 -0700414 goto out;
415 }
416 file->private_data =
417 kmalloc(sizeof(struct cifsFileInfo), GFP_KERNEL);
418 if (file->private_data == NULL) {
419 rc = -ENOMEM;
420 goto out;
421 }
422 pCifsFile = cifs_init_private(file->private_data, inode, file, netfid);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700423 write_lock(&GlobalSMBSeslock);
Steve French276a74a2009-03-03 18:00:34 +0000424 list_add(&pCifsFile->tlist, &tcon->openFileList);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700425
Josef "Jeff" Sipeke6a00292006-12-08 02:36:48 -0800426 pCifsInode = CIFS_I(file->f_path.dentry->d_inode);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700427 if (pCifsInode) {
428 rc = cifs_open_inode_helper(inode, file, pCifsInode,
Steve French276a74a2009-03-03 18:00:34 +0000429 pCifsFile, tcon,
Linus Torvalds1da177e2005-04-16 15:20:36 -0700430 &oplock, buf, full_path, xid);
431 } else {
432 write_unlock(&GlobalSMBSeslock);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700433 }
434
Steve Frenchfb8c4b12007-07-10 01:16:18 +0000435 if (oplock & CIFS_CREATE_ACTION) {
Linus Torvalds1da177e2005-04-16 15:20:36 -0700436 /* time to set mode which we can not set earlier due to
437 problems creating new read-only files */
Steve French276a74a2009-03-03 18:00:34 +0000438 if (tcon->unix_ext) {
Jeff Layton4e1e7fb2008-08-02 07:26:12 -0400439 struct cifs_unix_set_info_args args = {
440 .mode = inode->i_mode,
441 .uid = NO_CHANGE_64,
442 .gid = NO_CHANGE_64,
443 .ctime = NO_CHANGE_64,
444 .atime = NO_CHANGE_64,
445 .mtime = NO_CHANGE_64,
446 .device = 0,
447 };
Steve French276a74a2009-03-03 18:00:34 +0000448 CIFSSMBUnixSetInfo(xid, tcon, full_path, &args,
Steve French737b7582005-04-28 22:41:06 -0700449 cifs_sb->local_nls,
Steve Frenchfb8c4b12007-07-10 01:16:18 +0000450 cifs_sb->mnt_cifs_flags &
Steve French737b7582005-04-28 22:41:06 -0700451 CIFS_MOUNT_MAP_SPECIAL_CHR);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700452 }
453 }
454
455out:
456 kfree(buf);
457 kfree(full_path);
458 FreeXid(xid);
459 return rc;
460}
461
Adrian Bunk04187262006-06-30 18:23:04 +0200462/* Try to reacquire byte range locks that were released when session */
Linus Torvalds1da177e2005-04-16 15:20:36 -0700463/* to server was lost */
464static int cifs_relock_file(struct cifsFileInfo *cifsFile)
465{
466 int rc = 0;
467
468/* BB list all locks open on this file and relock */
469
470 return rc;
471}
472
Steve French4b18f2a2008-04-29 00:06:05 +0000473static int cifs_reopen_file(struct file *file, bool can_flush)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700474{
475 int rc = -EACCES;
476 int xid, oplock;
477 struct cifs_sb_info *cifs_sb;
Steve French7fc8f4e2009-02-23 20:43:11 +0000478 struct cifsTconInfo *tcon;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700479 struct cifsFileInfo *pCifsFile;
480 struct cifsInodeInfo *pCifsInode;
Steve Frenchfb8c4b12007-07-10 01:16:18 +0000481 struct inode *inode;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700482 char *full_path = NULL;
483 int desiredAccess;
484 int disposition = FILE_OPEN;
485 __u16 netfid;
486
Steve Frenchad7a2922008-02-07 23:25:02 +0000487 if (file->private_data)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700488 pCifsFile = (struct cifsFileInfo *)file->private_data;
Steve Frenchad7a2922008-02-07 23:25:02 +0000489 else
Linus Torvalds1da177e2005-04-16 15:20:36 -0700490 return -EBADF;
491
492 xid = GetXid();
493 down(&pCifsFile->fh_sem);
Steve French4b18f2a2008-04-29 00:06:05 +0000494 if (!pCifsFile->invalidHandle) {
Linus Torvalds1da177e2005-04-16 15:20:36 -0700495 up(&pCifsFile->fh_sem);
496 FreeXid(xid);
497 return 0;
498 }
499
Josef "Jeff" Sipeke6a00292006-12-08 02:36:48 -0800500 if (file->f_path.dentry == NULL) {
Steve French3a9f4622007-04-04 17:10:24 +0000501 cERROR(1, ("no valid name if dentry freed"));
502 dump_stack();
503 rc = -EBADF;
504 goto reopen_error_exit;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700505 }
Steve French3a9f4622007-04-04 17:10:24 +0000506
507 inode = file->f_path.dentry->d_inode;
Steve Frenchfb8c4b12007-07-10 01:16:18 +0000508 if (inode == NULL) {
Steve French3a9f4622007-04-04 17:10:24 +0000509 cERROR(1, ("inode not valid"));
510 dump_stack();
511 rc = -EBADF;
512 goto reopen_error_exit;
513 }
Steve French50c2f752007-07-13 00:33:32 +0000514
Linus Torvalds1da177e2005-04-16 15:20:36 -0700515 cifs_sb = CIFS_SB(inode->i_sb);
Steve French7fc8f4e2009-02-23 20:43:11 +0000516 tcon = cifs_sb->tcon;
Steve French3a9f4622007-04-04 17:10:24 +0000517
Linus Torvalds1da177e2005-04-16 15:20:36 -0700518/* can not grab rename sem here because various ops, including
519 those that already have the rename sem can end up causing writepage
520 to get called and if the server was down that means we end up here,
521 and we can never tell if the caller already has the rename_sem */
Josef "Jeff" Sipeke6a00292006-12-08 02:36:48 -0800522 full_path = build_path_from_dentry(file->f_path.dentry);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700523 if (full_path == NULL) {
Steve French3a9f4622007-04-04 17:10:24 +0000524 rc = -ENOMEM;
525reopen_error_exit:
Linus Torvalds1da177e2005-04-16 15:20:36 -0700526 up(&pCifsFile->fh_sem);
527 FreeXid(xid);
Steve French3a9f4622007-04-04 17:10:24 +0000528 return rc;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700529 }
530
Steve French3a9f4622007-04-04 17:10:24 +0000531 cFYI(1, ("inode = 0x%p file flags 0x%x for %s",
Steve Frenchfb8c4b12007-07-10 01:16:18 +0000532 inode, file->f_flags, full_path));
Linus Torvalds1da177e2005-04-16 15:20:36 -0700533
534 if (oplockEnabled)
535 oplock = REQ_OPLOCK;
536 else
Steve French4b18f2a2008-04-29 00:06:05 +0000537 oplock = 0;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700538
Steve French7fc8f4e2009-02-23 20:43:11 +0000539 if (tcon->unix_ext && (tcon->ses->capabilities & CAP_UNIX) &&
540 (CIFS_UNIX_POSIX_PATH_OPS_CAP &
541 le64_to_cpu(tcon->fsUnixInfo.Capability))) {
542 int oflags = (int) cifs_posix_convert_flags(file->f_flags);
543 /* can not refresh inode info since size could be stale */
544 rc = cifs_posix_open(full_path, NULL, inode->i_sb,
545 cifs_sb->mnt_file_mode /* ignored */,
546 oflags, &oplock, &netfid, xid);
547 if (rc == 0) {
548 cFYI(1, ("posix reopen succeeded"));
549 goto reopen_success;
550 }
551 /* fallthrough to retry open the old way on errors, especially
552 in the reconnect path it is important to retry hard */
553 }
554
555 desiredAccess = cifs_convert_flags(file->f_flags);
556
Linus Torvalds1da177e2005-04-16 15:20:36 -0700557 /* Can not refresh inode by passing in file_info buf to be returned
Steve Frenchfb8c4b12007-07-10 01:16:18 +0000558 by SMBOpen and then calling get_inode_info with returned buf
559 since file might have write behind data that needs to be flushed
Linus Torvalds1da177e2005-04-16 15:20:36 -0700560 and server version of file size can be stale. If we knew for sure
561 that inode was not dirty locally we could do this */
562
Steve French7fc8f4e2009-02-23 20:43:11 +0000563 rc = CIFSSMBOpen(xid, tcon, full_path, disposition, desiredAccess,
Linus Torvalds1da177e2005-04-16 15:20:36 -0700564 CREATE_NOT_DIR, &netfid, &oplock, NULL,
Steve Frenchfb8c4b12007-07-10 01:16:18 +0000565 cifs_sb->local_nls, cifs_sb->mnt_cifs_flags &
Steve French737b7582005-04-28 22:41:06 -0700566 CIFS_MOUNT_MAP_SPECIAL_CHR);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700567 if (rc) {
568 up(&pCifsFile->fh_sem);
Steve French26a21b92006-05-31 18:05:34 +0000569 cFYI(1, ("cifs_open returned 0x%x", rc));
570 cFYI(1, ("oplock: %d", oplock));
Linus Torvalds1da177e2005-04-16 15:20:36 -0700571 } else {
Steve French7fc8f4e2009-02-23 20:43:11 +0000572reopen_success:
Linus Torvalds1da177e2005-04-16 15:20:36 -0700573 pCifsFile->netfid = netfid;
Steve French4b18f2a2008-04-29 00:06:05 +0000574 pCifsFile->invalidHandle = false;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700575 up(&pCifsFile->fh_sem);
576 pCifsInode = CIFS_I(inode);
577 if (pCifsInode) {
578 if (can_flush) {
Jeff Laytoncea21802007-11-20 23:19:03 +0000579 rc = filemap_write_and_wait(inode->i_mapping);
580 if (rc != 0)
581 CIFS_I(inode)->write_behind_rc = rc;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700582 /* temporarily disable caching while we
583 go to server to get inode info */
Steve French4b18f2a2008-04-29 00:06:05 +0000584 pCifsInode->clientCanCacheAll = false;
585 pCifsInode->clientCanCacheRead = false;
Steve French7fc8f4e2009-02-23 20:43:11 +0000586 if (tcon->unix_ext)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700587 rc = cifs_get_inode_info_unix(&inode,
588 full_path, inode->i_sb, xid);
589 else
590 rc = cifs_get_inode_info(&inode,
591 full_path, NULL, inode->i_sb,
Steve French8b1327f2008-03-14 22:37:16 +0000592 xid, NULL);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700593 } /* else we are writing out data to server already
594 and could deadlock if we tried to flush data, and
595 since we do not know if we have data that would
596 invalidate the current end of file on the server
597 we can not go to the server to get the new inod
598 info */
599 if ((oplock & 0xF) == OPLOCK_EXCLUSIVE) {
Steve French4b18f2a2008-04-29 00:06:05 +0000600 pCifsInode->clientCanCacheAll = true;
601 pCifsInode->clientCanCacheRead = true;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700602 cFYI(1, ("Exclusive Oplock granted on inode %p",
Josef "Jeff" Sipeke6a00292006-12-08 02:36:48 -0800603 file->f_path.dentry->d_inode));
Linus Torvalds1da177e2005-04-16 15:20:36 -0700604 } else if ((oplock & 0xF) == OPLOCK_READ) {
Steve French4b18f2a2008-04-29 00:06:05 +0000605 pCifsInode->clientCanCacheRead = true;
606 pCifsInode->clientCanCacheAll = false;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700607 } else {
Steve French4b18f2a2008-04-29 00:06:05 +0000608 pCifsInode->clientCanCacheRead = false;
609 pCifsInode->clientCanCacheAll = false;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700610 }
611 cifs_relock_file(pCifsFile);
612 }
613 }
Linus Torvalds1da177e2005-04-16 15:20:36 -0700614 kfree(full_path);
615 FreeXid(xid);
616 return rc;
617}
618
619int cifs_close(struct inode *inode, struct file *file)
620{
621 int rc = 0;
Steve French15745322007-09-07 22:23:48 +0000622 int xid, timeout;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700623 struct cifs_sb_info *cifs_sb;
624 struct cifsTconInfo *pTcon;
625 struct cifsFileInfo *pSMBFile =
626 (struct cifsFileInfo *)file->private_data;
627
628 xid = GetXid();
629
630 cifs_sb = CIFS_SB(inode->i_sb);
631 pTcon = cifs_sb->tcon;
632 if (pSMBFile) {
Jeremy Allison7ee1af72006-08-02 21:56:33 +0000633 struct cifsLockInfo *li, *tmp;
Steve Frenchddb4cbf2008-11-20 20:00:44 +0000634 write_lock(&GlobalSMBSeslock);
Steve French4b18f2a2008-04-29 00:06:05 +0000635 pSMBFile->closePend = true;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700636 if (pTcon) {
637 /* no sense reconnecting to close a file that is
638 already closed */
Steve French3b795212008-11-13 19:45:32 +0000639 if (!pTcon->need_reconnect) {
Steve Frenchddb4cbf2008-11-20 20:00:44 +0000640 write_unlock(&GlobalSMBSeslock);
Steve French15745322007-09-07 22:23:48 +0000641 timeout = 2;
Steve Frenchfb8c4b12007-07-10 01:16:18 +0000642 while ((atomic_read(&pSMBFile->wrtPending) != 0)
Steve French15745322007-09-07 22:23:48 +0000643 && (timeout <= 2048)) {
Steve French23e7dd72005-10-20 13:44:56 -0700644 /* Give write a better chance to get to
645 server ahead of the close. We do not
646 want to add a wait_q here as it would
647 increase the memory utilization as
648 the struct would be in each open file,
Steve Frenchfb8c4b12007-07-10 01:16:18 +0000649 but this should give enough time to
Steve French23e7dd72005-10-20 13:44:56 -0700650 clear the socket */
Steve French90c81e02008-02-12 20:32:36 +0000651 cFYI(DBG2,
652 ("close delay, write pending"));
Steve French23e7dd72005-10-20 13:44:56 -0700653 msleep(timeout);
654 timeout *= 4;
Steve French4891d532006-11-07 16:31:16 +0000655 }
Steve Frenchfb8c4b12007-07-10 01:16:18 +0000656 if (atomic_read(&pSMBFile->wrtPending))
Steve Frenchddb4cbf2008-11-20 20:00:44 +0000657 cERROR(1, ("close with pending write"));
658 if (!pTcon->need_reconnect &&
659 !pSMBFile->invalidHandle)
660 rc = CIFSSMBClose(xid, pTcon,
Linus Torvalds1da177e2005-04-16 15:20:36 -0700661 pSMBFile->netfid);
Steve Frenchddb4cbf2008-11-20 20:00:44 +0000662 } else
663 write_unlock(&GlobalSMBSeslock);
664 } else
665 write_unlock(&GlobalSMBSeslock);
Jeremy Allison7ee1af72006-08-02 21:56:33 +0000666
667 /* Delete any outstanding lock records.
668 We'll lose them when the file is closed anyway. */
Roland Dreier796e5662007-05-03 04:33:45 +0000669 mutex_lock(&pSMBFile->lock_mutex);
Jeremy Allison7ee1af72006-08-02 21:56:33 +0000670 list_for_each_entry_safe(li, tmp, &pSMBFile->llist, llist) {
671 list_del(&li->llist);
672 kfree(li);
673 }
Roland Dreier796e5662007-05-03 04:33:45 +0000674 mutex_unlock(&pSMBFile->lock_mutex);
Jeremy Allison7ee1af72006-08-02 21:56:33 +0000675
Steve Frenchcbe04762005-04-28 22:41:05 -0700676 write_lock(&GlobalSMBSeslock);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700677 list_del(&pSMBFile->flist);
678 list_del(&pSMBFile->tlist);
Steve Frenchcbe04762005-04-28 22:41:05 -0700679 write_unlock(&GlobalSMBSeslock);
Steve French15745322007-09-07 22:23:48 +0000680 timeout = 10;
681 /* We waited above to give the SMBWrite a chance to issue
682 on the wire (so we do not get SMBWrite returning EBADF
683 if writepages is racing with close. Note that writepages
684 does not specify a file handle, so it is possible for a file
685 to be opened twice, and the application close the "wrong"
686 file handle - in these cases we delay long enough to allow
687 the SMBWrite to get on the wire before the SMB Close.
688 We allow total wait here over 45 seconds, more than
689 oplock break time, and more than enough to allow any write
690 to complete on the server, or to time out on the client */
691 while ((atomic_read(&pSMBFile->wrtPending) != 0)
692 && (timeout <= 50000)) {
693 cERROR(1, ("writes pending, delay free of handle"));
694 msleep(timeout);
695 timeout *= 8;
696 }
Linus Torvalds1da177e2005-04-16 15:20:36 -0700697 kfree(file->private_data);
698 file->private_data = NULL;
699 } else
700 rc = -EBADF;
701
Steve French4efa53f2007-09-11 05:50:53 +0000702 read_lock(&GlobalSMBSeslock);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700703 if (list_empty(&(CIFS_I(inode)->openFileList))) {
704 cFYI(1, ("closing last open instance for inode %p", inode));
705 /* if the file is not open we do not know if we can cache info
706 on this inode, much less write behind and read ahead */
Steve French4b18f2a2008-04-29 00:06:05 +0000707 CIFS_I(inode)->clientCanCacheRead = false;
708 CIFS_I(inode)->clientCanCacheAll = false;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700709 }
Steve French4efa53f2007-09-11 05:50:53 +0000710 read_unlock(&GlobalSMBSeslock);
Steve Frenchfb8c4b12007-07-10 01:16:18 +0000711 if ((rc == 0) && CIFS_I(inode)->write_behind_rc)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700712 rc = CIFS_I(inode)->write_behind_rc;
713 FreeXid(xid);
714 return rc;
715}
716
717int cifs_closedir(struct inode *inode, struct file *file)
718{
719 int rc = 0;
720 int xid;
721 struct cifsFileInfo *pCFileStruct =
722 (struct cifsFileInfo *)file->private_data;
723 char *ptmp;
724
Steve French26a21b92006-05-31 18:05:34 +0000725 cFYI(1, ("Closedir inode = 0x%p", inode));
Linus Torvalds1da177e2005-04-16 15:20:36 -0700726
727 xid = GetXid();
728
729 if (pCFileStruct) {
730 struct cifsTconInfo *pTcon;
Steve Frenchfb8c4b12007-07-10 01:16:18 +0000731 struct cifs_sb_info *cifs_sb =
732 CIFS_SB(file->f_path.dentry->d_sb);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700733
734 pTcon = cifs_sb->tcon;
735
736 cFYI(1, ("Freeing private data in close dir"));
Steve Frenchddb4cbf2008-11-20 20:00:44 +0000737 write_lock(&GlobalSMBSeslock);
Steve French4b18f2a2008-04-29 00:06:05 +0000738 if (!pCFileStruct->srch_inf.endOfSearch &&
739 !pCFileStruct->invalidHandle) {
740 pCFileStruct->invalidHandle = true;
Steve Frenchddb4cbf2008-11-20 20:00:44 +0000741 write_unlock(&GlobalSMBSeslock);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700742 rc = CIFSFindClose(xid, pTcon, pCFileStruct->netfid);
743 cFYI(1, ("Closing uncompleted readdir with rc %d",
744 rc));
745 /* not much we can do if it fails anyway, ignore rc */
746 rc = 0;
Steve Frenchddb4cbf2008-11-20 20:00:44 +0000747 } else
748 write_unlock(&GlobalSMBSeslock);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700749 ptmp = pCFileStruct->srch_inf.ntwrk_buf_start;
750 if (ptmp) {
Steve Frenchec637e32005-12-12 20:53:18 -0800751 cFYI(1, ("closedir free smb buf in srch struct"));
Linus Torvalds1da177e2005-04-16 15:20:36 -0700752 pCFileStruct->srch_inf.ntwrk_buf_start = NULL;
Steve Frenchfb8c4b12007-07-10 01:16:18 +0000753 if (pCFileStruct->srch_inf.smallBuf)
Steve Frenchd47d7c12006-02-28 03:45:48 +0000754 cifs_small_buf_release(ptmp);
755 else
756 cifs_buf_release(ptmp);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700757 }
Linus Torvalds1da177e2005-04-16 15:20:36 -0700758 kfree(file->private_data);
759 file->private_data = NULL;
760 }
761 /* BB can we lock the filestruct while this is going on? */
762 FreeXid(xid);
763 return rc;
764}
765
Jeremy Allison7ee1af72006-08-02 21:56:33 +0000766static int store_file_lock(struct cifsFileInfo *fid, __u64 len,
767 __u64 offset, __u8 lockType)
768{
Steve Frenchfb8c4b12007-07-10 01:16:18 +0000769 struct cifsLockInfo *li =
770 kmalloc(sizeof(struct cifsLockInfo), GFP_KERNEL);
Jeremy Allison7ee1af72006-08-02 21:56:33 +0000771 if (li == NULL)
772 return -ENOMEM;
773 li->offset = offset;
774 li->length = len;
775 li->type = lockType;
Roland Dreier796e5662007-05-03 04:33:45 +0000776 mutex_lock(&fid->lock_mutex);
Jeremy Allison7ee1af72006-08-02 21:56:33 +0000777 list_add(&li->llist, &fid->llist);
Roland Dreier796e5662007-05-03 04:33:45 +0000778 mutex_unlock(&fid->lock_mutex);
Jeremy Allison7ee1af72006-08-02 21:56:33 +0000779 return 0;
780}
781
Linus Torvalds1da177e2005-04-16 15:20:36 -0700782int cifs_lock(struct file *file, int cmd, struct file_lock *pfLock)
783{
784 int rc, xid;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700785 __u32 numLock = 0;
786 __u32 numUnlock = 0;
787 __u64 length;
Steve French4b18f2a2008-04-29 00:06:05 +0000788 bool wait_flag = false;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700789 struct cifs_sb_info *cifs_sb;
Steve French13a6e422008-12-02 17:24:33 +0000790 struct cifsTconInfo *tcon;
Steve French08547b02006-02-28 22:39:25 +0000791 __u16 netfid;
792 __u8 lockType = LOCKING_ANDX_LARGE_FILES;
Steve French13a6e422008-12-02 17:24:33 +0000793 bool posix_locking = 0;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700794
795 length = 1 + pfLock->fl_end - pfLock->fl_start;
796 rc = -EACCES;
797 xid = GetXid();
798
799 cFYI(1, ("Lock parm: 0x%x flockflags: "
800 "0x%x flocktype: 0x%x start: %lld end: %lld",
Steve Frenchfb8c4b12007-07-10 01:16:18 +0000801 cmd, pfLock->fl_flags, pfLock->fl_type, pfLock->fl_start,
802 pfLock->fl_end));
Linus Torvalds1da177e2005-04-16 15:20:36 -0700803
804 if (pfLock->fl_flags & FL_POSIX)
Steve Frenchd47d7c12006-02-28 03:45:48 +0000805 cFYI(1, ("Posix"));
Linus Torvalds1da177e2005-04-16 15:20:36 -0700806 if (pfLock->fl_flags & FL_FLOCK)
Steve Frenchd47d7c12006-02-28 03:45:48 +0000807 cFYI(1, ("Flock"));
Linus Torvalds1da177e2005-04-16 15:20:36 -0700808 if (pfLock->fl_flags & FL_SLEEP) {
Steve Frenchd47d7c12006-02-28 03:45:48 +0000809 cFYI(1, ("Blocking lock"));
Steve French4b18f2a2008-04-29 00:06:05 +0000810 wait_flag = true;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700811 }
812 if (pfLock->fl_flags & FL_ACCESS)
813 cFYI(1, ("Process suspended by mandatory locking - "
Steve French26a21b92006-05-31 18:05:34 +0000814 "not implemented yet"));
Linus Torvalds1da177e2005-04-16 15:20:36 -0700815 if (pfLock->fl_flags & FL_LEASE)
816 cFYI(1, ("Lease on file - not implemented yet"));
Steve Frenchfb8c4b12007-07-10 01:16:18 +0000817 if (pfLock->fl_flags &
Linus Torvalds1da177e2005-04-16 15:20:36 -0700818 (~(FL_POSIX | FL_FLOCK | FL_SLEEP | FL_ACCESS | FL_LEASE)))
819 cFYI(1, ("Unknown lock flags 0x%x", pfLock->fl_flags));
820
821 if (pfLock->fl_type == F_WRLCK) {
822 cFYI(1, ("F_WRLCK "));
823 numLock = 1;
824 } else if (pfLock->fl_type == F_UNLCK) {
Steve Frenchd47d7c12006-02-28 03:45:48 +0000825 cFYI(1, ("F_UNLCK"));
Linus Torvalds1da177e2005-04-16 15:20:36 -0700826 numUnlock = 1;
Steve Frenchd47d7c12006-02-28 03:45:48 +0000827 /* Check if unlock includes more than
828 one lock range */
Linus Torvalds1da177e2005-04-16 15:20:36 -0700829 } else if (pfLock->fl_type == F_RDLCK) {
Steve Frenchd47d7c12006-02-28 03:45:48 +0000830 cFYI(1, ("F_RDLCK"));
Linus Torvalds1da177e2005-04-16 15:20:36 -0700831 lockType |= LOCKING_ANDX_SHARED_LOCK;
832 numLock = 1;
833 } else if (pfLock->fl_type == F_EXLCK) {
Steve Frenchd47d7c12006-02-28 03:45:48 +0000834 cFYI(1, ("F_EXLCK"));
Linus Torvalds1da177e2005-04-16 15:20:36 -0700835 numLock = 1;
836 } else if (pfLock->fl_type == F_SHLCK) {
Steve Frenchd47d7c12006-02-28 03:45:48 +0000837 cFYI(1, ("F_SHLCK"));
Linus Torvalds1da177e2005-04-16 15:20:36 -0700838 lockType |= LOCKING_ANDX_SHARED_LOCK;
839 numLock = 1;
840 } else
Steve Frenchd47d7c12006-02-28 03:45:48 +0000841 cFYI(1, ("Unknown type of lock"));
Linus Torvalds1da177e2005-04-16 15:20:36 -0700842
Josef "Jeff" Sipeke6a00292006-12-08 02:36:48 -0800843 cifs_sb = CIFS_SB(file->f_path.dentry->d_sb);
Steve French13a6e422008-12-02 17:24:33 +0000844 tcon = cifs_sb->tcon;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700845
846 if (file->private_data == NULL) {
847 FreeXid(xid);
848 return -EBADF;
849 }
Steve French08547b02006-02-28 22:39:25 +0000850 netfid = ((struct cifsFileInfo *)file->private_data)->netfid;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700851
Steve French13a6e422008-12-02 17:24:33 +0000852 if ((tcon->ses->capabilities & CAP_UNIX) &&
853 (CIFS_UNIX_FCNTL_CAP & le64_to_cpu(tcon->fsUnixInfo.Capability)) &&
Steve Frenchacc18aa2008-12-02 18:53:55 +0000854 ((cifs_sb->mnt_cifs_flags & CIFS_MOUNT_NOPOSIXBRL) == 0))
Steve French13a6e422008-12-02 17:24:33 +0000855 posix_locking = 1;
Steve French08547b02006-02-28 22:39:25 +0000856 /* BB add code here to normalize offset and length to
857 account for negative length which we can not accept over the
858 wire */
Linus Torvalds1da177e2005-04-16 15:20:36 -0700859 if (IS_GETLK(cmd)) {
Steve Frenchfb8c4b12007-07-10 01:16:18 +0000860 if (posix_locking) {
Steve French08547b02006-02-28 22:39:25 +0000861 int posix_lock_type;
Steve Frenchfb8c4b12007-07-10 01:16:18 +0000862 if (lockType & LOCKING_ANDX_SHARED_LOCK)
Steve French08547b02006-02-28 22:39:25 +0000863 posix_lock_type = CIFS_RDLCK;
864 else
865 posix_lock_type = CIFS_WRLCK;
Steve French13a6e422008-12-02 17:24:33 +0000866 rc = CIFSSMBPosixLock(xid, tcon, netfid, 1 /* get */,
Steve Frenchfc94cdb2006-05-30 18:03:32 +0000867 length, pfLock,
Steve French08547b02006-02-28 22:39:25 +0000868 posix_lock_type, wait_flag);
869 FreeXid(xid);
870 return rc;
871 }
872
873 /* BB we could chain these into one lock request BB */
Steve French13a6e422008-12-02 17:24:33 +0000874 rc = CIFSSMBLock(xid, tcon, netfid, length, pfLock->fl_start,
Steve French08547b02006-02-28 22:39:25 +0000875 0, 1, lockType, 0 /* wait flag */ );
Linus Torvalds1da177e2005-04-16 15:20:36 -0700876 if (rc == 0) {
Steve French13a6e422008-12-02 17:24:33 +0000877 rc = CIFSSMBLock(xid, tcon, netfid, length,
Linus Torvalds1da177e2005-04-16 15:20:36 -0700878 pfLock->fl_start, 1 /* numUnlock */ ,
879 0 /* numLock */ , lockType,
880 0 /* wait flag */ );
881 pfLock->fl_type = F_UNLCK;
882 if (rc != 0)
883 cERROR(1, ("Error unlocking previously locked "
Steve French08547b02006-02-28 22:39:25 +0000884 "range %d during test of lock", rc));
Linus Torvalds1da177e2005-04-16 15:20:36 -0700885 rc = 0;
886
887 } else {
888 /* if rc == ERR_SHARING_VIOLATION ? */
889 rc = 0; /* do not change lock type to unlock
890 since range in use */
891 }
892
893 FreeXid(xid);
894 return rc;
895 }
Jeremy Allison7ee1af72006-08-02 21:56:33 +0000896
897 if (!numLock && !numUnlock) {
898 /* if no lock or unlock then nothing
899 to do since we do not know what it is */
900 FreeXid(xid);
901 return -EOPNOTSUPP;
902 }
903
904 if (posix_locking) {
Steve French08547b02006-02-28 22:39:25 +0000905 int posix_lock_type;
Steve Frenchfb8c4b12007-07-10 01:16:18 +0000906 if (lockType & LOCKING_ANDX_SHARED_LOCK)
Steve French08547b02006-02-28 22:39:25 +0000907 posix_lock_type = CIFS_RDLCK;
908 else
909 posix_lock_type = CIFS_WRLCK;
Steve French50c2f752007-07-13 00:33:32 +0000910
Steve Frenchfb8c4b12007-07-10 01:16:18 +0000911 if (numUnlock == 1)
Steve Frenchbeb84dc2006-03-03 23:36:34 +0000912 posix_lock_type = CIFS_UNLCK;
Jeremy Allison7ee1af72006-08-02 21:56:33 +0000913
Steve French13a6e422008-12-02 17:24:33 +0000914 rc = CIFSSMBPosixLock(xid, tcon, netfid, 0 /* set */,
Steve Frenchfc94cdb2006-05-30 18:03:32 +0000915 length, pfLock,
Steve French08547b02006-02-28 22:39:25 +0000916 posix_lock_type, wait_flag);
Jeremy Allison7ee1af72006-08-02 21:56:33 +0000917 } else {
Steve Frenchfb8c4b12007-07-10 01:16:18 +0000918 struct cifsFileInfo *fid =
919 (struct cifsFileInfo *)file->private_data;
Jeremy Allison7ee1af72006-08-02 21:56:33 +0000920
921 if (numLock) {
Steve French13a6e422008-12-02 17:24:33 +0000922 rc = CIFSSMBLock(xid, tcon, netfid, length,
Steve Frenchfb8c4b12007-07-10 01:16:18 +0000923 pfLock->fl_start,
Jeremy Allison7ee1af72006-08-02 21:56:33 +0000924 0, numLock, lockType, wait_flag);
925
926 if (rc == 0) {
927 /* For Windows locks we must store them. */
928 rc = store_file_lock(fid, length,
929 pfLock->fl_start, lockType);
930 }
931 } else if (numUnlock) {
932 /* For each stored lock that this unlock overlaps
933 completely, unlock it. */
934 int stored_rc = 0;
935 struct cifsLockInfo *li, *tmp;
936
Steve French6b70c952006-09-21 07:35:29 +0000937 rc = 0;
Roland Dreier796e5662007-05-03 04:33:45 +0000938 mutex_lock(&fid->lock_mutex);
Jeremy Allison7ee1af72006-08-02 21:56:33 +0000939 list_for_each_entry_safe(li, tmp, &fid->llist, llist) {
940 if (pfLock->fl_start <= li->offset &&
Steve Frenchc19eb712007-08-24 03:22:48 +0000941 (pfLock->fl_start + length) >=
Jeff Layton39db8102007-08-24 03:16:51 +0000942 (li->offset + li->length)) {
Steve French13a6e422008-12-02 17:24:33 +0000943 stored_rc = CIFSSMBLock(xid, tcon,
Steve Frenchfb8c4b12007-07-10 01:16:18 +0000944 netfid,
Jeremy Allison7ee1af72006-08-02 21:56:33 +0000945 li->length, li->offset,
Steve French4b18f2a2008-04-29 00:06:05 +0000946 1, 0, li->type, false);
Jeremy Allison7ee1af72006-08-02 21:56:33 +0000947 if (stored_rc)
948 rc = stored_rc;
949
950 list_del(&li->llist);
951 kfree(li);
952 }
953 }
Roland Dreier796e5662007-05-03 04:33:45 +0000954 mutex_unlock(&fid->lock_mutex);
Jeremy Allison7ee1af72006-08-02 21:56:33 +0000955 }
956 }
957
Steve Frenchd634cc12005-08-26 14:42:59 -0500958 if (pfLock->fl_flags & FL_POSIX)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700959 posix_lock_file_wait(file, pfLock);
960 FreeXid(xid);
961 return rc;
962}
963
964ssize_t cifs_user_write(struct file *file, const char __user *write_data,
965 size_t write_size, loff_t *poffset)
966{
967 int rc = 0;
968 unsigned int bytes_written = 0;
969 unsigned int total_written;
970 struct cifs_sb_info *cifs_sb;
971 struct cifsTconInfo *pTcon;
972 int xid, long_op;
973 struct cifsFileInfo *open_file;
974
Josef "Jeff" Sipeke6a00292006-12-08 02:36:48 -0800975 cifs_sb = CIFS_SB(file->f_path.dentry->d_sb);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700976
977 pTcon = cifs_sb->tcon;
978
979 /* cFYI(1,
980 (" write %d bytes to offset %lld of %s", write_size,
Josef "Jeff" Sipeke6a00292006-12-08 02:36:48 -0800981 *poffset, file->f_path.dentry->d_name.name)); */
Linus Torvalds1da177e2005-04-16 15:20:36 -0700982
983 if (file->private_data == NULL)
984 return -EBADF;
Christoph Hellwigc33f8d32007-04-02 18:47:20 +0000985 open_file = (struct cifsFileInfo *) file->private_data;
Steve French50c2f752007-07-13 00:33:32 +0000986
Jeff Layton838726c2008-08-28 07:54:59 -0400987 rc = generic_write_checks(file, poffset, &write_size, 0);
988 if (rc)
989 return rc;
990
Linus Torvalds1da177e2005-04-16 15:20:36 -0700991 xid = GetXid();
Linus Torvalds1da177e2005-04-16 15:20:36 -0700992
Josef "Jeff" Sipeke6a00292006-12-08 02:36:48 -0800993 if (*poffset > file->f_path.dentry->d_inode->i_size)
Steve French133672e2007-11-13 22:41:37 +0000994 long_op = CIFS_VLONG_OP; /* writes past EOF take long time */
Linus Torvalds1da177e2005-04-16 15:20:36 -0700995 else
Steve French133672e2007-11-13 22:41:37 +0000996 long_op = CIFS_LONG_OP;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700997
998 for (total_written = 0; write_size > total_written;
999 total_written += bytes_written) {
1000 rc = -EAGAIN;
1001 while (rc == -EAGAIN) {
1002 if (file->private_data == NULL) {
1003 /* file has been closed on us */
1004 FreeXid(xid);
1005 /* if we have gotten here we have written some data
1006 and blocked, and the file has been freed on us while
1007 we blocked so return what we managed to write */
1008 return total_written;
Steve Frenchfb8c4b12007-07-10 01:16:18 +00001009 }
Linus Torvalds1da177e2005-04-16 15:20:36 -07001010 if (open_file->closePend) {
1011 FreeXid(xid);
1012 if (total_written)
1013 return total_written;
1014 else
1015 return -EBADF;
1016 }
1017 if (open_file->invalidHandle) {
Linus Torvalds1da177e2005-04-16 15:20:36 -07001018 /* we could deadlock if we called
1019 filemap_fdatawait from here so tell
1020 reopen_file not to flush data to server
1021 now */
Steve French4b18f2a2008-04-29 00:06:05 +00001022 rc = cifs_reopen_file(file, false);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001023 if (rc != 0)
1024 break;
1025 }
1026
1027 rc = CIFSSMBWrite(xid, pTcon,
1028 open_file->netfid,
1029 min_t(const int, cifs_sb->wsize,
1030 write_size - total_written),
1031 *poffset, &bytes_written,
1032 NULL, write_data + total_written, long_op);
1033 }
1034 if (rc || (bytes_written == 0)) {
1035 if (total_written)
1036 break;
1037 else {
1038 FreeXid(xid);
1039 return rc;
1040 }
1041 } else
1042 *poffset += bytes_written;
Steve French133672e2007-11-13 22:41:37 +00001043 long_op = CIFS_STD_OP; /* subsequent writes fast -
Linus Torvalds1da177e2005-04-16 15:20:36 -07001044 15 seconds is plenty */
1045 }
1046
Steve Frencha4544342005-08-24 13:59:35 -07001047 cifs_stats_bytes_written(pTcon, total_written);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001048
1049 /* since the write may have blocked check these pointers again */
Steve French3677db12007-02-26 16:46:11 +00001050 if ((file->f_path.dentry) && (file->f_path.dentry->d_inode)) {
1051 struct inode *inode = file->f_path.dentry->d_inode;
Steve Frenchfb8c4b12007-07-10 01:16:18 +00001052/* Do not update local mtime - server will set its actual value on write
1053 * inode->i_ctime = inode->i_mtime =
Steve French3677db12007-02-26 16:46:11 +00001054 * current_fs_time(inode->i_sb);*/
1055 if (total_written > 0) {
1056 spin_lock(&inode->i_lock);
1057 if (*poffset > file->f_path.dentry->d_inode->i_size)
1058 i_size_write(file->f_path.dentry->d_inode,
Linus Torvalds1da177e2005-04-16 15:20:36 -07001059 *poffset);
Steve French3677db12007-02-26 16:46:11 +00001060 spin_unlock(&inode->i_lock);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001061 }
Steve Frenchfb8c4b12007-07-10 01:16:18 +00001062 mark_inode_dirty_sync(file->f_path.dentry->d_inode);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001063 }
1064 FreeXid(xid);
1065 return total_written;
1066}
1067
1068static ssize_t cifs_write(struct file *file, const char *write_data,
Nick Piggind9414772008-09-24 11:32:59 -04001069 size_t write_size, loff_t *poffset)
Linus Torvalds1da177e2005-04-16 15:20:36 -07001070{
1071 int rc = 0;
1072 unsigned int bytes_written = 0;
1073 unsigned int total_written;
1074 struct cifs_sb_info *cifs_sb;
1075 struct cifsTconInfo *pTcon;
1076 int xid, long_op;
1077 struct cifsFileInfo *open_file;
1078
Josef "Jeff" Sipeke6a00292006-12-08 02:36:48 -08001079 cifs_sb = CIFS_SB(file->f_path.dentry->d_sb);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001080
1081 pTcon = cifs_sb->tcon;
1082
Steve Frenchfb8c4b12007-07-10 01:16:18 +00001083 cFYI(1, ("write %zd bytes to offset %lld of %s", write_size,
Josef "Jeff" Sipeke6a00292006-12-08 02:36:48 -08001084 *poffset, file->f_path.dentry->d_name.name));
Linus Torvalds1da177e2005-04-16 15:20:36 -07001085
1086 if (file->private_data == NULL)
1087 return -EBADF;
Christoph Hellwigc33f8d32007-04-02 18:47:20 +00001088 open_file = (struct cifsFileInfo *)file->private_data;
Steve French50c2f752007-07-13 00:33:32 +00001089
Linus Torvalds1da177e2005-04-16 15:20:36 -07001090 xid = GetXid();
Linus Torvalds1da177e2005-04-16 15:20:36 -07001091
Josef "Jeff" Sipeke6a00292006-12-08 02:36:48 -08001092 if (*poffset > file->f_path.dentry->d_inode->i_size)
Steve French133672e2007-11-13 22:41:37 +00001093 long_op = CIFS_VLONG_OP; /* writes past EOF can be slow */
Linus Torvalds1da177e2005-04-16 15:20:36 -07001094 else
Steve French133672e2007-11-13 22:41:37 +00001095 long_op = CIFS_LONG_OP;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001096
1097 for (total_written = 0; write_size > total_written;
1098 total_written += bytes_written) {
1099 rc = -EAGAIN;
1100 while (rc == -EAGAIN) {
1101 if (file->private_data == NULL) {
1102 /* file has been closed on us */
1103 FreeXid(xid);
1104 /* if we have gotten here we have written some data
1105 and blocked, and the file has been freed on us
Steve Frenchfb8c4b12007-07-10 01:16:18 +00001106 while we blocked so return what we managed to
Linus Torvalds1da177e2005-04-16 15:20:36 -07001107 write */
1108 return total_written;
Steve Frenchfb8c4b12007-07-10 01:16:18 +00001109 }
Linus Torvalds1da177e2005-04-16 15:20:36 -07001110 if (open_file->closePend) {
1111 FreeXid(xid);
1112 if (total_written)
1113 return total_written;
1114 else
1115 return -EBADF;
1116 }
1117 if (open_file->invalidHandle) {
Linus Torvalds1da177e2005-04-16 15:20:36 -07001118 /* we could deadlock if we called
1119 filemap_fdatawait from here so tell
Steve Frenchfb8c4b12007-07-10 01:16:18 +00001120 reopen_file not to flush data to
Linus Torvalds1da177e2005-04-16 15:20:36 -07001121 server now */
Steve French4b18f2a2008-04-29 00:06:05 +00001122 rc = cifs_reopen_file(file, false);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001123 if (rc != 0)
1124 break;
1125 }
Steve Frenchfb8c4b12007-07-10 01:16:18 +00001126 if (experimEnabled || (pTcon->ses->server &&
1127 ((pTcon->ses->server->secMode &
Steve French08775832006-05-30 18:08:26 +00001128 (SECMODE_SIGN_REQUIRED | SECMODE_SIGN_ENABLED))
Steve Frenchc01f36a2006-05-30 18:05:10 +00001129 == 0))) {
Steve French3e844692005-10-03 13:37:24 -07001130 struct kvec iov[2];
1131 unsigned int len;
1132
Steve French0ae0efa2005-10-10 10:57:19 -07001133 len = min((size_t)cifs_sb->wsize,
Steve French3e844692005-10-03 13:37:24 -07001134 write_size - total_written);
1135 /* iov[0] is reserved for smb header */
1136 iov[1].iov_base = (char *)write_data +
1137 total_written;
1138 iov[1].iov_len = len;
Steve Frenchd6e04ae2005-06-13 13:24:43 -05001139 rc = CIFSSMBWrite2(xid, pTcon,
Steve French3e844692005-10-03 13:37:24 -07001140 open_file->netfid, len,
Steve Frenchd6e04ae2005-06-13 13:24:43 -05001141 *poffset, &bytes_written,
Steve French3e844692005-10-03 13:37:24 -07001142 iov, 1, long_op);
Steve Frenchd6e04ae2005-06-13 13:24:43 -05001143 } else
Steve French60808232006-04-22 15:53:05 +00001144 rc = CIFSSMBWrite(xid, pTcon,
1145 open_file->netfid,
1146 min_t(const int, cifs_sb->wsize,
1147 write_size - total_written),
1148 *poffset, &bytes_written,
1149 write_data + total_written,
1150 NULL, long_op);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001151 }
1152 if (rc || (bytes_written == 0)) {
1153 if (total_written)
1154 break;
1155 else {
1156 FreeXid(xid);
1157 return rc;
1158 }
1159 } else
1160 *poffset += bytes_written;
Steve French133672e2007-11-13 22:41:37 +00001161 long_op = CIFS_STD_OP; /* subsequent writes fast -
Linus Torvalds1da177e2005-04-16 15:20:36 -07001162 15 seconds is plenty */
1163 }
1164
Steve Frencha4544342005-08-24 13:59:35 -07001165 cifs_stats_bytes_written(pTcon, total_written);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001166
1167 /* since the write may have blocked check these pointers again */
Steve French3677db12007-02-26 16:46:11 +00001168 if ((file->f_path.dentry) && (file->f_path.dentry->d_inode)) {
Steve French004c46b2007-02-17 04:34:13 +00001169/*BB We could make this contingent on superblock ATIME flag too */
Steve French3677db12007-02-26 16:46:11 +00001170/* file->f_path.dentry->d_inode->i_ctime =
1171 file->f_path.dentry->d_inode->i_mtime = CURRENT_TIME;*/
1172 if (total_written > 0) {
1173 spin_lock(&file->f_path.dentry->d_inode->i_lock);
1174 if (*poffset > file->f_path.dentry->d_inode->i_size)
1175 i_size_write(file->f_path.dentry->d_inode,
1176 *poffset);
1177 spin_unlock(&file->f_path.dentry->d_inode->i_lock);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001178 }
Steve French3677db12007-02-26 16:46:11 +00001179 mark_inode_dirty_sync(file->f_path.dentry->d_inode);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001180 }
1181 FreeXid(xid);
1182 return total_written;
1183}
1184
Steve French630f3f0c2007-10-25 21:17:17 +00001185#ifdef CONFIG_CIFS_EXPERIMENTAL
1186struct cifsFileInfo *find_readable_file(struct cifsInodeInfo *cifs_inode)
1187{
1188 struct cifsFileInfo *open_file = NULL;
1189
1190 read_lock(&GlobalSMBSeslock);
1191 /* we could simply get the first_list_entry since write-only entries
1192 are always at the end of the list but since the first entry might
1193 have a close pending, we go through the whole list */
1194 list_for_each_entry(open_file, &cifs_inode->openFileList, flist) {
1195 if (open_file->closePend)
1196 continue;
1197 if (open_file->pfile && ((open_file->pfile->f_flags & O_RDWR) ||
1198 (open_file->pfile->f_flags & O_RDONLY))) {
1199 if (!open_file->invalidHandle) {
1200 /* found a good file */
1201 /* lock it so it will not be closed on us */
1202 atomic_inc(&open_file->wrtPending);
1203 read_unlock(&GlobalSMBSeslock);
1204 return open_file;
1205 } /* else might as well continue, and look for
1206 another, or simply have the caller reopen it
1207 again rather than trying to fix this handle */
1208 } else /* write only file */
1209 break; /* write only files are last so must be done */
1210 }
1211 read_unlock(&GlobalSMBSeslock);
1212 return NULL;
1213}
1214#endif
1215
Steve Frenchdd99cd82005-10-05 19:32:49 -07001216struct cifsFileInfo *find_writable_file(struct cifsInodeInfo *cifs_inode)
Steve French6148a742005-10-05 12:23:19 -07001217{
1218 struct cifsFileInfo *open_file;
Jeff Layton2846d382008-09-22 21:33:33 -04001219 bool any_available = false;
Steve Frenchdd99cd82005-10-05 19:32:49 -07001220 int rc;
Steve French6148a742005-10-05 12:23:19 -07001221
Steve French60808232006-04-22 15:53:05 +00001222 /* Having a null inode here (because mapping->host was set to zero by
1223 the VFS or MM) should not happen but we had reports of on oops (due to
1224 it being zero) during stress testcases so we need to check for it */
1225
Steve Frenchfb8c4b12007-07-10 01:16:18 +00001226 if (cifs_inode == NULL) {
1227 cERROR(1, ("Null inode passed to cifs_writeable_file"));
Steve French60808232006-04-22 15:53:05 +00001228 dump_stack();
1229 return NULL;
1230 }
1231
Steve French6148a742005-10-05 12:23:19 -07001232 read_lock(&GlobalSMBSeslock);
Steve French9b22b0b2007-10-02 01:11:08 +00001233refind_writable:
Steve French6148a742005-10-05 12:23:19 -07001234 list_for_each_entry(open_file, &cifs_inode->openFileList, flist) {
Jeff Layton2846d382008-09-22 21:33:33 -04001235 if (open_file->closePend ||
1236 (!any_available && open_file->pid != current->tgid))
Steve French6148a742005-10-05 12:23:19 -07001237 continue;
Jeff Layton2846d382008-09-22 21:33:33 -04001238
Steve French6148a742005-10-05 12:23:19 -07001239 if (open_file->pfile &&
1240 ((open_file->pfile->f_flags & O_RDWR) ||
1241 (open_file->pfile->f_flags & O_WRONLY))) {
Steve French23e7dd72005-10-20 13:44:56 -07001242 atomic_inc(&open_file->wrtPending);
Steve French9b22b0b2007-10-02 01:11:08 +00001243
1244 if (!open_file->invalidHandle) {
1245 /* found a good writable file */
1246 read_unlock(&GlobalSMBSeslock);
1247 return open_file;
1248 }
Steve French8840dee2007-11-16 23:05:52 +00001249
Steve French6148a742005-10-05 12:23:19 -07001250 read_unlock(&GlobalSMBSeslock);
Steve French9b22b0b2007-10-02 01:11:08 +00001251 /* Had to unlock since following call can block */
Steve French4b18f2a2008-04-29 00:06:05 +00001252 rc = cifs_reopen_file(open_file->pfile, false);
Steve French8840dee2007-11-16 23:05:52 +00001253 if (!rc) {
Steve French9b22b0b2007-10-02 01:11:08 +00001254 if (!open_file->closePend)
1255 return open_file;
1256 else { /* start over in case this was deleted */
1257 /* since the list could be modified */
Steve French37c0eb42005-10-05 14:50:29 -07001258 read_lock(&GlobalSMBSeslock);
Steve French15745322007-09-07 22:23:48 +00001259 atomic_dec(&open_file->wrtPending);
Steve French9b22b0b2007-10-02 01:11:08 +00001260 goto refind_writable;
Steve French37c0eb42005-10-05 14:50:29 -07001261 }
1262 }
Steve French9b22b0b2007-10-02 01:11:08 +00001263
1264 /* if it fails, try another handle if possible -
1265 (we can not do this if closePending since
1266 loop could be modified - in which case we
1267 have to start at the beginning of the list
1268 again. Note that it would be bad
1269 to hold up writepages here (rather than
1270 in caller) with continuous retries */
1271 cFYI(1, ("wp failed on reopen file"));
1272 read_lock(&GlobalSMBSeslock);
1273 /* can not use this handle, no write
1274 pending on this one after all */
1275 atomic_dec(&open_file->wrtPending);
Steve French8840dee2007-11-16 23:05:52 +00001276
Steve French9b22b0b2007-10-02 01:11:08 +00001277 if (open_file->closePend) /* list could have changed */
1278 goto refind_writable;
1279 /* else we simply continue to the next entry. Thus
1280 we do not loop on reopen errors. If we
1281 can not reopen the file, for example if we
1282 reconnected to a server with another client
1283 racing to delete or lock the file we would not
1284 make progress if we restarted before the beginning
1285 of the loop here. */
Steve French6148a742005-10-05 12:23:19 -07001286 }
1287 }
Jeff Layton2846d382008-09-22 21:33:33 -04001288 /* couldn't find useable FH with same pid, try any available */
1289 if (!any_available) {
1290 any_available = true;
1291 goto refind_writable;
1292 }
Steve French6148a742005-10-05 12:23:19 -07001293 read_unlock(&GlobalSMBSeslock);
1294 return NULL;
1295}
1296
Linus Torvalds1da177e2005-04-16 15:20:36 -07001297static int cifs_partialpagewrite(struct page *page, unsigned from, unsigned to)
1298{
1299 struct address_space *mapping = page->mapping;
1300 loff_t offset = (loff_t)page->index << PAGE_CACHE_SHIFT;
1301 char *write_data;
1302 int rc = -EFAULT;
1303 int bytes_written = 0;
1304 struct cifs_sb_info *cifs_sb;
1305 struct cifsTconInfo *pTcon;
1306 struct inode *inode;
Steve French6148a742005-10-05 12:23:19 -07001307 struct cifsFileInfo *open_file;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001308
1309 if (!mapping || !mapping->host)
1310 return -EFAULT;
1311
1312 inode = page->mapping->host;
1313 cifs_sb = CIFS_SB(inode->i_sb);
1314 pTcon = cifs_sb->tcon;
1315
1316 offset += (loff_t)from;
1317 write_data = kmap(page);
1318 write_data += from;
1319
1320 if ((to > PAGE_CACHE_SIZE) || (from > to)) {
1321 kunmap(page);
1322 return -EIO;
1323 }
1324
1325 /* racing with truncate? */
1326 if (offset > mapping->host->i_size) {
1327 kunmap(page);
1328 return 0; /* don't care */
1329 }
1330
1331 /* check to make sure that we are not extending the file */
1332 if (mapping->host->i_size - offset < (loff_t)to)
Steve Frenchfb8c4b12007-07-10 01:16:18 +00001333 to = (unsigned)(mapping->host->i_size - offset);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001334
Steve French6148a742005-10-05 12:23:19 -07001335 open_file = find_writable_file(CIFS_I(mapping->host));
1336 if (open_file) {
1337 bytes_written = cifs_write(open_file->pfile, write_data,
1338 to-from, &offset);
Steve French23e7dd72005-10-20 13:44:56 -07001339 atomic_dec(&open_file->wrtPending);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001340 /* Does mm or vfs already set times? */
Steve French6148a742005-10-05 12:23:19 -07001341 inode->i_atime = inode->i_mtime = current_fs_time(inode->i_sb);
Steve Frenchbb5a9a02007-12-31 04:21:29 +00001342 if ((bytes_written > 0) && (offset))
Steve French6148a742005-10-05 12:23:19 -07001343 rc = 0;
Steve Frenchbb5a9a02007-12-31 04:21:29 +00001344 else if (bytes_written < 0)
1345 rc = bytes_written;
Steve French6148a742005-10-05 12:23:19 -07001346 } else {
Linus Torvalds1da177e2005-04-16 15:20:36 -07001347 cFYI(1, ("No writeable filehandles for inode"));
1348 rc = -EIO;
1349 }
1350
1351 kunmap(page);
1352 return rc;
1353}
1354
Linus Torvalds1da177e2005-04-16 15:20:36 -07001355static int cifs_writepages(struct address_space *mapping,
Steve French37c0eb42005-10-05 14:50:29 -07001356 struct writeback_control *wbc)
Linus Torvalds1da177e2005-04-16 15:20:36 -07001357{
Steve French37c0eb42005-10-05 14:50:29 -07001358 struct backing_dev_info *bdi = mapping->backing_dev_info;
1359 unsigned int bytes_to_write;
1360 unsigned int bytes_written;
1361 struct cifs_sb_info *cifs_sb;
1362 int done = 0;
OGAWA Hirofumi111ebb62006-06-23 02:03:26 -07001363 pgoff_t end;
Steve French37c0eb42005-10-05 14:50:29 -07001364 pgoff_t index;
Steve Frenchfb8c4b12007-07-10 01:16:18 +00001365 int range_whole = 0;
1366 struct kvec *iov;
Steve French84d2f072005-10-12 15:32:05 -07001367 int len;
Steve French37c0eb42005-10-05 14:50:29 -07001368 int n_iov = 0;
1369 pgoff_t next;
1370 int nr_pages;
1371 __u64 offset = 0;
Steve French23e7dd72005-10-20 13:44:56 -07001372 struct cifsFileInfo *open_file;
Steve French37c0eb42005-10-05 14:50:29 -07001373 struct page *page;
1374 struct pagevec pvec;
1375 int rc = 0;
1376 int scanned = 0;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001377 int xid;
1378
Steve French37c0eb42005-10-05 14:50:29 -07001379 cifs_sb = CIFS_SB(mapping->host->i_sb);
Steve French50c2f752007-07-13 00:33:32 +00001380
Steve French37c0eb42005-10-05 14:50:29 -07001381 /*
1382 * If wsize is smaller that the page cache size, default to writing
1383 * one page at a time via cifs_writepage
1384 */
1385 if (cifs_sb->wsize < PAGE_CACHE_SIZE)
1386 return generic_writepages(mapping, wbc);
1387
Steve Frenchfb8c4b12007-07-10 01:16:18 +00001388 if ((cifs_sb->tcon->ses) && (cifs_sb->tcon->ses->server))
1389 if (cifs_sb->tcon->ses->server->secMode &
1390 (SECMODE_SIGN_REQUIRED | SECMODE_SIGN_ENABLED))
1391 if (!experimEnabled)
Steve French60808232006-04-22 15:53:05 +00001392 return generic_writepages(mapping, wbc);
Steve French4a771182005-10-05 15:14:33 -07001393
Steve French9a0c8232007-02-02 04:21:57 +00001394 iov = kmalloc(32 * sizeof(struct kvec), GFP_KERNEL);
Steve Frenchfb8c4b12007-07-10 01:16:18 +00001395 if (iov == NULL)
Steve French9a0c8232007-02-02 04:21:57 +00001396 return generic_writepages(mapping, wbc);
1397
1398
Steve French37c0eb42005-10-05 14:50:29 -07001399 /*
1400 * BB: Is this meaningful for a non-block-device file system?
1401 * If it is, we should test it again after we do I/O
1402 */
1403 if (wbc->nonblocking && bdi_write_congested(bdi)) {
1404 wbc->encountered_congestion = 1;
Steve French9a0c8232007-02-02 04:21:57 +00001405 kfree(iov);
Steve French37c0eb42005-10-05 14:50:29 -07001406 return 0;
1407 }
1408
Linus Torvalds1da177e2005-04-16 15:20:36 -07001409 xid = GetXid();
1410
Steve French37c0eb42005-10-05 14:50:29 -07001411 pagevec_init(&pvec, 0);
OGAWA Hirofumi111ebb62006-06-23 02:03:26 -07001412 if (wbc->range_cyclic) {
Steve French37c0eb42005-10-05 14:50:29 -07001413 index = mapping->writeback_index; /* Start from prev offset */
OGAWA Hirofumi111ebb62006-06-23 02:03:26 -07001414 end = -1;
1415 } else {
1416 index = wbc->range_start >> PAGE_CACHE_SHIFT;
1417 end = wbc->range_end >> PAGE_CACHE_SHIFT;
1418 if (wbc->range_start == 0 && wbc->range_end == LLONG_MAX)
1419 range_whole = 1;
Steve French37c0eb42005-10-05 14:50:29 -07001420 scanned = 1;
1421 }
1422retry:
1423 while (!done && (index <= end) &&
1424 (nr_pages = pagevec_lookup_tag(&pvec, mapping, &index,
1425 PAGECACHE_TAG_DIRTY,
1426 min(end - index, (pgoff_t)PAGEVEC_SIZE - 1) + 1))) {
1427 int first;
1428 unsigned int i;
1429
Steve French37c0eb42005-10-05 14:50:29 -07001430 first = -1;
1431 next = 0;
1432 n_iov = 0;
1433 bytes_to_write = 0;
1434
1435 for (i = 0; i < nr_pages; i++) {
1436 page = pvec.pages[i];
1437 /*
1438 * At this point we hold neither mapping->tree_lock nor
1439 * lock on the page itself: the page may be truncated or
1440 * invalidated (changing page->mapping to NULL), or even
1441 * swizzled back from swapper_space to tmpfs file
1442 * mapping
1443 */
1444
1445 if (first < 0)
1446 lock_page(page);
Nick Piggin529ae9a2008-08-02 12:01:03 +02001447 else if (!trylock_page(page))
Steve French37c0eb42005-10-05 14:50:29 -07001448 break;
1449
1450 if (unlikely(page->mapping != mapping)) {
1451 unlock_page(page);
1452 break;
1453 }
1454
OGAWA Hirofumi111ebb62006-06-23 02:03:26 -07001455 if (!wbc->range_cyclic && page->index > end) {
Steve French37c0eb42005-10-05 14:50:29 -07001456 done = 1;
1457 unlock_page(page);
1458 break;
1459 }
1460
1461 if (next && (page->index != next)) {
1462 /* Not next consecutive page */
1463 unlock_page(page);
1464 break;
1465 }
1466
1467 if (wbc->sync_mode != WB_SYNC_NONE)
1468 wait_on_page_writeback(page);
1469
1470 if (PageWriteback(page) ||
Linus Torvaldscb876f42006-12-23 16:19:07 -08001471 !clear_page_dirty_for_io(page)) {
Steve French37c0eb42005-10-05 14:50:29 -07001472 unlock_page(page);
1473 break;
1474 }
Steve French84d2f072005-10-12 15:32:05 -07001475
Linus Torvaldscb876f42006-12-23 16:19:07 -08001476 /*
1477 * This actually clears the dirty bit in the radix tree.
1478 * See cifs_writepage() for more commentary.
1479 */
1480 set_page_writeback(page);
1481
Steve French84d2f072005-10-12 15:32:05 -07001482 if (page_offset(page) >= mapping->host->i_size) {
1483 done = 1;
1484 unlock_page(page);
Linus Torvaldscb876f42006-12-23 16:19:07 -08001485 end_page_writeback(page);
Steve French84d2f072005-10-12 15:32:05 -07001486 break;
1487 }
1488
Steve French37c0eb42005-10-05 14:50:29 -07001489 /*
1490 * BB can we get rid of this? pages are held by pvec
1491 */
1492 page_cache_get(page);
1493
Steve French84d2f072005-10-12 15:32:05 -07001494 len = min(mapping->host->i_size - page_offset(page),
1495 (loff_t)PAGE_CACHE_SIZE);
1496
Steve French37c0eb42005-10-05 14:50:29 -07001497 /* reserve iov[0] for the smb header */
1498 n_iov++;
1499 iov[n_iov].iov_base = kmap(page);
Steve French84d2f072005-10-12 15:32:05 -07001500 iov[n_iov].iov_len = len;
1501 bytes_to_write += len;
Steve French37c0eb42005-10-05 14:50:29 -07001502
1503 if (first < 0) {
1504 first = i;
1505 offset = page_offset(page);
1506 }
1507 next = page->index + 1;
1508 if (bytes_to_write + PAGE_CACHE_SIZE > cifs_sb->wsize)
1509 break;
1510 }
1511 if (n_iov) {
Steve French23e7dd72005-10-20 13:44:56 -07001512 /* Search for a writable handle every time we call
1513 * CIFSSMBWrite2. We can't rely on the last handle
1514 * we used to still be valid
1515 */
1516 open_file = find_writable_file(CIFS_I(mapping->host));
1517 if (!open_file) {
1518 cERROR(1, ("No writable handles for inode"));
1519 rc = -EBADF;
Steve French1047abc2005-10-11 19:58:06 -07001520 } else {
Steve French23e7dd72005-10-20 13:44:56 -07001521 rc = CIFSSMBWrite2(xid, cifs_sb->tcon,
1522 open_file->netfid,
1523 bytes_to_write, offset,
1524 &bytes_written, iov, n_iov,
Steve French133672e2007-11-13 22:41:37 +00001525 CIFS_LONG_OP);
Steve French23e7dd72005-10-20 13:44:56 -07001526 atomic_dec(&open_file->wrtPending);
1527 if (rc || bytes_written < bytes_to_write) {
Steve French63135e02007-07-17 17:34:02 +00001528 cERROR(1, ("Write2 ret %d, wrote %d",
Steve French23e7dd72005-10-20 13:44:56 -07001529 rc, bytes_written));
1530 /* BB what if continued retry is
1531 requested via mount flags? */
Jeff Laytoncea21802007-11-20 23:19:03 +00001532 if (rc == -ENOSPC)
1533 set_bit(AS_ENOSPC, &mapping->flags);
1534 else
1535 set_bit(AS_EIO, &mapping->flags);
Steve French23e7dd72005-10-20 13:44:56 -07001536 } else {
1537 cifs_stats_bytes_written(cifs_sb->tcon,
1538 bytes_written);
1539 }
Steve French37c0eb42005-10-05 14:50:29 -07001540 }
1541 for (i = 0; i < n_iov; i++) {
1542 page = pvec.pages[first + i];
Steve Frencheb9bdaa2006-01-27 15:11:47 -08001543 /* Should we also set page error on
1544 success rc but too little data written? */
1545 /* BB investigate retry logic on temporary
1546 server crash cases and how recovery works
Steve Frenchfb8c4b12007-07-10 01:16:18 +00001547 when page marked as error */
1548 if (rc)
Steve Frencheb9bdaa2006-01-27 15:11:47 -08001549 SetPageError(page);
Steve French37c0eb42005-10-05 14:50:29 -07001550 kunmap(page);
1551 unlock_page(page);
Linus Torvaldscb876f42006-12-23 16:19:07 -08001552 end_page_writeback(page);
Steve French37c0eb42005-10-05 14:50:29 -07001553 page_cache_release(page);
1554 }
1555 if ((wbc->nr_to_write -= n_iov) <= 0)
1556 done = 1;
1557 index = next;
Dave Kleikampb066a482008-11-18 03:49:05 +00001558 } else
1559 /* Need to re-find the pages we skipped */
1560 index = pvec.pages[0]->index + 1;
1561
Steve French37c0eb42005-10-05 14:50:29 -07001562 pagevec_release(&pvec);
1563 }
1564 if (!scanned && !done) {
1565 /*
1566 * We hit the last page and there is more work to be done: wrap
1567 * back to the start of the file
1568 */
1569 scanned = 1;
1570 index = 0;
1571 goto retry;
1572 }
OGAWA Hirofumi111ebb62006-06-23 02:03:26 -07001573 if (wbc->range_cyclic || (range_whole && wbc->nr_to_write > 0))
Steve French37c0eb42005-10-05 14:50:29 -07001574 mapping->writeback_index = index;
1575
Linus Torvalds1da177e2005-04-16 15:20:36 -07001576 FreeXid(xid);
Steve French9a0c8232007-02-02 04:21:57 +00001577 kfree(iov);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001578 return rc;
1579}
Linus Torvalds1da177e2005-04-16 15:20:36 -07001580
Steve Frenchfb8c4b12007-07-10 01:16:18 +00001581static int cifs_writepage(struct page *page, struct writeback_control *wbc)
Linus Torvalds1da177e2005-04-16 15:20:36 -07001582{
1583 int rc = -EFAULT;
1584 int xid;
1585
1586 xid = GetXid();
1587/* BB add check for wbc flags */
1588 page_cache_get(page);
Steve Frenchad7a2922008-02-07 23:25:02 +00001589 if (!PageUptodate(page))
Linus Torvalds1da177e2005-04-16 15:20:36 -07001590 cFYI(1, ("ppw - page not up to date"));
Linus Torvaldscb876f42006-12-23 16:19:07 -08001591
1592 /*
1593 * Set the "writeback" flag, and clear "dirty" in the radix tree.
1594 *
1595 * A writepage() implementation always needs to do either this,
1596 * or re-dirty the page with "redirty_page_for_writepage()" in
1597 * the case of a failure.
1598 *
1599 * Just unlocking the page will cause the radix tree tag-bits
1600 * to fail to update with the state of the page correctly.
1601 */
Steve Frenchfb8c4b12007-07-10 01:16:18 +00001602 set_page_writeback(page);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001603 rc = cifs_partialpagewrite(page, 0, PAGE_CACHE_SIZE);
1604 SetPageUptodate(page); /* BB add check for error and Clearuptodate? */
1605 unlock_page(page);
Linus Torvaldscb876f42006-12-23 16:19:07 -08001606 end_page_writeback(page);
1607 page_cache_release(page);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001608 FreeXid(xid);
1609 return rc;
1610}
1611
Nick Piggind9414772008-09-24 11:32:59 -04001612static int cifs_write_end(struct file *file, struct address_space *mapping,
1613 loff_t pos, unsigned len, unsigned copied,
1614 struct page *page, void *fsdata)
Linus Torvalds1da177e2005-04-16 15:20:36 -07001615{
Nick Piggind9414772008-09-24 11:32:59 -04001616 int rc;
1617 struct inode *inode = mapping->host;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001618
Nick Piggind9414772008-09-24 11:32:59 -04001619 cFYI(1, ("write_end for page %p from pos %lld with %d bytes",
1620 page, pos, copied));
Steve Frenchad7a2922008-02-07 23:25:02 +00001621
Jeff Laytona98ee8c2008-11-26 19:32:33 +00001622 if (PageChecked(page)) {
1623 if (copied == len)
1624 SetPageUptodate(page);
1625 ClearPageChecked(page);
1626 } else if (!PageUptodate(page) && copied == PAGE_CACHE_SIZE)
Nick Piggind9414772008-09-24 11:32:59 -04001627 SetPageUptodate(page);
1628
Linus Torvalds1da177e2005-04-16 15:20:36 -07001629 if (!PageUptodate(page)) {
Nick Piggind9414772008-09-24 11:32:59 -04001630 char *page_data;
1631 unsigned offset = pos & (PAGE_CACHE_SIZE - 1);
1632 int xid;
1633
1634 xid = GetXid();
Linus Torvalds1da177e2005-04-16 15:20:36 -07001635 /* this is probably better than directly calling
1636 partialpage_write since in this function the file handle is
1637 known which we might as well leverage */
1638 /* BB check if anything else missing out of ppw
1639 such as updating last write time */
1640 page_data = kmap(page);
Nick Piggind9414772008-09-24 11:32:59 -04001641 rc = cifs_write(file, page_data + offset, copied, &pos);
1642 /* if (rc < 0) should we set writebehind rc? */
Linus Torvalds1da177e2005-04-16 15:20:36 -07001643 kunmap(page);
Nick Piggind9414772008-09-24 11:32:59 -04001644
1645 FreeXid(xid);
Steve Frenchfb8c4b12007-07-10 01:16:18 +00001646 } else {
Nick Piggind9414772008-09-24 11:32:59 -04001647 rc = copied;
1648 pos += copied;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001649 set_page_dirty(page);
1650 }
1651
Nick Piggind9414772008-09-24 11:32:59 -04001652 if (rc > 0) {
1653 spin_lock(&inode->i_lock);
1654 if (pos > inode->i_size)
1655 i_size_write(inode, pos);
1656 spin_unlock(&inode->i_lock);
1657 }
1658
1659 unlock_page(page);
1660 page_cache_release(page);
1661
Linus Torvalds1da177e2005-04-16 15:20:36 -07001662 return rc;
1663}
1664
1665int cifs_fsync(struct file *file, struct dentry *dentry, int datasync)
1666{
1667 int xid;
1668 int rc = 0;
Steve Frenchb298f222009-02-21 21:17:43 +00001669 struct cifsTconInfo *tcon;
1670 struct cifsFileInfo *smbfile =
1671 (struct cifsFileInfo *)file->private_data;
Josef "Jeff" Sipeke6a00292006-12-08 02:36:48 -08001672 struct inode *inode = file->f_path.dentry->d_inode;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001673
1674 xid = GetXid();
1675
Steve Frenchfb8c4b12007-07-10 01:16:18 +00001676 cFYI(1, ("Sync file - name: %s datasync: 0x%x",
Linus Torvalds1da177e2005-04-16 15:20:36 -07001677 dentry->d_name.name, datasync));
Steve French50c2f752007-07-13 00:33:32 +00001678
Jeff Laytoncea21802007-11-20 23:19:03 +00001679 rc = filemap_write_and_wait(inode->i_mapping);
1680 if (rc == 0) {
1681 rc = CIFS_I(inode)->write_behind_rc;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001682 CIFS_I(inode)->write_behind_rc = 0;
Steve Frenchb298f222009-02-21 21:17:43 +00001683 tcon = CIFS_SB(inode->i_sb)->tcon;
Steve Frenchbe652442009-02-23 15:21:59 +00001684 if (!rc && tcon && smbfile &&
Steve French4717bed2009-02-24 14:44:19 +00001685 !(CIFS_SB(inode->i_sb)->mnt_cifs_flags & CIFS_MOUNT_NOSSYNC))
Steve Frenchb298f222009-02-21 21:17:43 +00001686 rc = CIFSSMBFlush(xid, tcon, smbfile->netfid);
Jeff Laytoncea21802007-11-20 23:19:03 +00001687 }
Steve Frenchb298f222009-02-21 21:17:43 +00001688
Linus Torvalds1da177e2005-04-16 15:20:36 -07001689 FreeXid(xid);
1690 return rc;
1691}
1692
NeilBrown3978d7172006-03-26 01:37:17 -08001693/* static void cifs_sync_page(struct page *page)
Linus Torvalds1da177e2005-04-16 15:20:36 -07001694{
1695 struct address_space *mapping;
1696 struct inode *inode;
1697 unsigned long index = page->index;
1698 unsigned int rpages = 0;
1699 int rc = 0;
1700
1701 cFYI(1, ("sync page %p",page));
1702 mapping = page->mapping;
1703 if (!mapping)
1704 return 0;
1705 inode = mapping->host;
1706 if (!inode)
NeilBrown3978d7172006-03-26 01:37:17 -08001707 return; */
Linus Torvalds1da177e2005-04-16 15:20:36 -07001708
Steve Frenchfb8c4b12007-07-10 01:16:18 +00001709/* fill in rpages then
Linus Torvalds1da177e2005-04-16 15:20:36 -07001710 result = cifs_pagein_inode(inode, index, rpages); */ /* BB finish */
1711
Steve French26a21b92006-05-31 18:05:34 +00001712/* cFYI(1, ("rpages is %d for sync page of Index %ld", rpages, index));
Linus Torvalds1da177e2005-04-16 15:20:36 -07001713
NeilBrown3978d7172006-03-26 01:37:17 -08001714#if 0
Linus Torvalds1da177e2005-04-16 15:20:36 -07001715 if (rc < 0)
1716 return rc;
1717 return 0;
NeilBrown3978d7172006-03-26 01:37:17 -08001718#endif
Linus Torvalds1da177e2005-04-16 15:20:36 -07001719} */
1720
1721/*
1722 * As file closes, flush all cached write data for this inode checking
1723 * for write behind errors.
1724 */
Miklos Szeredi75e1fcc2006-06-23 02:05:12 -07001725int cifs_flush(struct file *file, fl_owner_t id)
Linus Torvalds1da177e2005-04-16 15:20:36 -07001726{
Steve Frenchfb8c4b12007-07-10 01:16:18 +00001727 struct inode *inode = file->f_path.dentry->d_inode;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001728 int rc = 0;
1729
1730 /* Rather than do the steps manually:
1731 lock the inode for writing
1732 loop through pages looking for write behind data (dirty pages)
1733 coalesce into contiguous 16K (or smaller) chunks to write to server
1734 send to server (prefer in parallel)
1735 deal with writebehind errors
1736 unlock inode for writing
1737 filemapfdatawrite appears easier for the time being */
1738
1739 rc = filemap_fdatawrite(inode->i_mapping);
Jeff Laytoncea21802007-11-20 23:19:03 +00001740 /* reset wb rc if we were able to write out dirty pages */
1741 if (!rc) {
1742 rc = CIFS_I(inode)->write_behind_rc;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001743 CIFS_I(inode)->write_behind_rc = 0;
Jeff Laytoncea21802007-11-20 23:19:03 +00001744 }
Steve French50c2f752007-07-13 00:33:32 +00001745
Steve Frenchfb8c4b12007-07-10 01:16:18 +00001746 cFYI(1, ("Flush inode %p file %p rc %d", inode, file, rc));
Linus Torvalds1da177e2005-04-16 15:20:36 -07001747
1748 return rc;
1749}
1750
1751ssize_t cifs_user_read(struct file *file, char __user *read_data,
1752 size_t read_size, loff_t *poffset)
1753{
1754 int rc = -EACCES;
1755 unsigned int bytes_read = 0;
1756 unsigned int total_read = 0;
1757 unsigned int current_read_size;
1758 struct cifs_sb_info *cifs_sb;
1759 struct cifsTconInfo *pTcon;
1760 int xid;
1761 struct cifsFileInfo *open_file;
1762 char *smb_read_data;
1763 char __user *current_offset;
1764 struct smb_com_read_rsp *pSMBr;
1765
1766 xid = GetXid();
Josef "Jeff" Sipeke6a00292006-12-08 02:36:48 -08001767 cifs_sb = CIFS_SB(file->f_path.dentry->d_sb);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001768 pTcon = cifs_sb->tcon;
1769
1770 if (file->private_data == NULL) {
1771 FreeXid(xid);
1772 return -EBADF;
1773 }
1774 open_file = (struct cifsFileInfo *)file->private_data;
1775
Steve Frenchad7a2922008-02-07 23:25:02 +00001776 if ((file->f_flags & O_ACCMODE) == O_WRONLY)
Linus Torvalds1da177e2005-04-16 15:20:36 -07001777 cFYI(1, ("attempting read on write only file instance"));
Steve Frenchad7a2922008-02-07 23:25:02 +00001778
Linus Torvalds1da177e2005-04-16 15:20:36 -07001779 for (total_read = 0, current_offset = read_data;
1780 read_size > total_read;
1781 total_read += bytes_read, current_offset += bytes_read) {
Steve Frenchfb8c4b12007-07-10 01:16:18 +00001782 current_read_size = min_t(const int, read_size - total_read,
Linus Torvalds1da177e2005-04-16 15:20:36 -07001783 cifs_sb->rsize);
1784 rc = -EAGAIN;
1785 smb_read_data = NULL;
1786 while (rc == -EAGAIN) {
Steve Frenchec637e32005-12-12 20:53:18 -08001787 int buf_type = CIFS_NO_BUFFER;
Steve Frenchfb8c4b12007-07-10 01:16:18 +00001788 if ((open_file->invalidHandle) &&
Linus Torvalds1da177e2005-04-16 15:20:36 -07001789 (!open_file->closePend)) {
Steve French4b18f2a2008-04-29 00:06:05 +00001790 rc = cifs_reopen_file(file, true);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001791 if (rc != 0)
1792 break;
1793 }
Steve Frenchbfa0d752005-08-31 21:50:37 -07001794 rc = CIFSSMBRead(xid, pTcon,
Steve Frenchec637e32005-12-12 20:53:18 -08001795 open_file->netfid,
1796 current_read_size, *poffset,
1797 &bytes_read, &smb_read_data,
1798 &buf_type);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001799 pSMBr = (struct smb_com_read_rsp *)smb_read_data;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001800 if (smb_read_data) {
Steve French93544cc2006-02-14 22:30:52 -06001801 if (copy_to_user(current_offset,
1802 smb_read_data +
1803 4 /* RFC1001 length field */ +
1804 le16_to_cpu(pSMBr->DataOffset),
Steve Frenchad7a2922008-02-07 23:25:02 +00001805 bytes_read))
Steve French93544cc2006-02-14 22:30:52 -06001806 rc = -EFAULT;
Steve French93544cc2006-02-14 22:30:52 -06001807
Steve Frenchfb8c4b12007-07-10 01:16:18 +00001808 if (buf_type == CIFS_SMALL_BUFFER)
Steve Frenchec637e32005-12-12 20:53:18 -08001809 cifs_small_buf_release(smb_read_data);
Steve Frenchfb8c4b12007-07-10 01:16:18 +00001810 else if (buf_type == CIFS_LARGE_BUFFER)
Steve Frenchec637e32005-12-12 20:53:18 -08001811 cifs_buf_release(smb_read_data);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001812 smb_read_data = NULL;
1813 }
1814 }
1815 if (rc || (bytes_read == 0)) {
1816 if (total_read) {
1817 break;
1818 } else {
1819 FreeXid(xid);
1820 return rc;
1821 }
1822 } else {
Steve Frencha4544342005-08-24 13:59:35 -07001823 cifs_stats_bytes_read(pTcon, bytes_read);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001824 *poffset += bytes_read;
1825 }
1826 }
1827 FreeXid(xid);
1828 return total_read;
1829}
1830
1831
1832static ssize_t cifs_read(struct file *file, char *read_data, size_t read_size,
1833 loff_t *poffset)
1834{
1835 int rc = -EACCES;
1836 unsigned int bytes_read = 0;
1837 unsigned int total_read;
1838 unsigned int current_read_size;
1839 struct cifs_sb_info *cifs_sb;
1840 struct cifsTconInfo *pTcon;
1841 int xid;
1842 char *current_offset;
1843 struct cifsFileInfo *open_file;
Steve Frenchec637e32005-12-12 20:53:18 -08001844 int buf_type = CIFS_NO_BUFFER;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001845
1846 xid = GetXid();
Josef "Jeff" Sipeke6a00292006-12-08 02:36:48 -08001847 cifs_sb = CIFS_SB(file->f_path.dentry->d_sb);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001848 pTcon = cifs_sb->tcon;
1849
1850 if (file->private_data == NULL) {
1851 FreeXid(xid);
1852 return -EBADF;
1853 }
1854 open_file = (struct cifsFileInfo *)file->private_data;
1855
1856 if ((file->f_flags & O_ACCMODE) == O_WRONLY)
1857 cFYI(1, ("attempting read on write only file instance"));
1858
Steve Frenchfb8c4b12007-07-10 01:16:18 +00001859 for (total_read = 0, current_offset = read_data;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001860 read_size > total_read;
1861 total_read += bytes_read, current_offset += bytes_read) {
1862 current_read_size = min_t(const int, read_size - total_read,
1863 cifs_sb->rsize);
Steve Frenchf9f5c8172005-09-15 23:06:38 -07001864 /* For windows me and 9x we do not want to request more
1865 than it negotiated since it will refuse the read then */
Steve Frenchfb8c4b12007-07-10 01:16:18 +00001866 if ((pTcon->ses) &&
Steve Frenchf9f5c8172005-09-15 23:06:38 -07001867 !(pTcon->ses->capabilities & CAP_LARGE_FILES)) {
1868 current_read_size = min_t(const int, current_read_size,
1869 pTcon->ses->server->maxBuf - 128);
1870 }
Linus Torvalds1da177e2005-04-16 15:20:36 -07001871 rc = -EAGAIN;
1872 while (rc == -EAGAIN) {
Steve Frenchfb8c4b12007-07-10 01:16:18 +00001873 if ((open_file->invalidHandle) &&
Linus Torvalds1da177e2005-04-16 15:20:36 -07001874 (!open_file->closePend)) {
Steve French4b18f2a2008-04-29 00:06:05 +00001875 rc = cifs_reopen_file(file, true);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001876 if (rc != 0)
1877 break;
1878 }
Steve Frenchbfa0d752005-08-31 21:50:37 -07001879 rc = CIFSSMBRead(xid, pTcon,
Steve Frenchec637e32005-12-12 20:53:18 -08001880 open_file->netfid,
1881 current_read_size, *poffset,
1882 &bytes_read, &current_offset,
1883 &buf_type);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001884 }
1885 if (rc || (bytes_read == 0)) {
1886 if (total_read) {
1887 break;
1888 } else {
1889 FreeXid(xid);
1890 return rc;
1891 }
1892 } else {
Steve Frencha4544342005-08-24 13:59:35 -07001893 cifs_stats_bytes_read(pTcon, total_read);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001894 *poffset += bytes_read;
1895 }
1896 }
1897 FreeXid(xid);
1898 return total_read;
1899}
1900
1901int cifs_file_mmap(struct file *file, struct vm_area_struct *vma)
1902{
Josef "Jeff" Sipeke6a00292006-12-08 02:36:48 -08001903 struct dentry *dentry = file->f_path.dentry;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001904 int rc, xid;
1905
1906 xid = GetXid();
1907 rc = cifs_revalidate(dentry);
1908 if (rc) {
1909 cFYI(1, ("Validation prior to mmap failed, error=%d", rc));
1910 FreeXid(xid);
1911 return rc;
1912 }
1913 rc = generic_file_mmap(file, vma);
1914 FreeXid(xid);
1915 return rc;
1916}
1917
1918
Steve Frenchfb8c4b12007-07-10 01:16:18 +00001919static void cifs_copy_cache_pages(struct address_space *mapping,
Linus Torvalds1da177e2005-04-16 15:20:36 -07001920 struct list_head *pages, int bytes_read, char *data,
1921 struct pagevec *plru_pvec)
1922{
1923 struct page *page;
1924 char *target;
1925
1926 while (bytes_read > 0) {
1927 if (list_empty(pages))
1928 break;
1929
1930 page = list_entry(pages->prev, struct page, lru);
1931 list_del(&page->lru);
1932
1933 if (add_to_page_cache(page, mapping, page->index,
1934 GFP_KERNEL)) {
1935 page_cache_release(page);
1936 cFYI(1, ("Add page cache failed"));
Steve French3079ca62005-06-09 14:44:07 -07001937 data += PAGE_CACHE_SIZE;
1938 bytes_read -= PAGE_CACHE_SIZE;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001939 continue;
1940 }
1941
Steve Frenchfb8c4b12007-07-10 01:16:18 +00001942 target = kmap_atomic(page, KM_USER0);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001943
1944 if (PAGE_CACHE_SIZE > bytes_read) {
1945 memcpy(target, data, bytes_read);
1946 /* zero the tail end of this partial page */
Steve Frenchfb8c4b12007-07-10 01:16:18 +00001947 memset(target + bytes_read, 0,
Linus Torvalds1da177e2005-04-16 15:20:36 -07001948 PAGE_CACHE_SIZE - bytes_read);
1949 bytes_read = 0;
1950 } else {
1951 memcpy(target, data, PAGE_CACHE_SIZE);
1952 bytes_read -= PAGE_CACHE_SIZE;
1953 }
1954 kunmap_atomic(target, KM_USER0);
1955
1956 flush_dcache_page(page);
1957 SetPageUptodate(page);
1958 unlock_page(page);
1959 if (!pagevec_add(plru_pvec, page))
Rik van Riel4f98a2f2008-10-18 20:26:32 -07001960 __pagevec_lru_add_file(plru_pvec);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001961 data += PAGE_CACHE_SIZE;
1962 }
1963 return;
1964}
1965
1966static int cifs_readpages(struct file *file, struct address_space *mapping,
1967 struct list_head *page_list, unsigned num_pages)
1968{
1969 int rc = -EACCES;
1970 int xid;
1971 loff_t offset;
1972 struct page *page;
1973 struct cifs_sb_info *cifs_sb;
1974 struct cifsTconInfo *pTcon;
Steve French2c2130e2007-10-12 19:10:28 +00001975 unsigned int bytes_read = 0;
Steve Frenchfb8c4b12007-07-10 01:16:18 +00001976 unsigned int read_size, i;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001977 char *smb_read_data = NULL;
1978 struct smb_com_read_rsp *pSMBr;
1979 struct pagevec lru_pvec;
1980 struct cifsFileInfo *open_file;
Steve Frenchec637e32005-12-12 20:53:18 -08001981 int buf_type = CIFS_NO_BUFFER;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001982
1983 xid = GetXid();
1984 if (file->private_data == NULL) {
1985 FreeXid(xid);
1986 return -EBADF;
1987 }
1988 open_file = (struct cifsFileInfo *)file->private_data;
Josef "Jeff" Sipeke6a00292006-12-08 02:36:48 -08001989 cifs_sb = CIFS_SB(file->f_path.dentry->d_sb);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001990 pTcon = cifs_sb->tcon;
Steve Frenchbfa0d752005-08-31 21:50:37 -07001991
Linus Torvalds1da177e2005-04-16 15:20:36 -07001992 pagevec_init(&lru_pvec, 0);
Steve French61de8002008-10-30 20:15:22 +00001993 cFYI(DBG2, ("rpages: num pages %d", num_pages));
Linus Torvalds1da177e2005-04-16 15:20:36 -07001994 for (i = 0; i < num_pages; ) {
1995 unsigned contig_pages;
1996 struct page *tmp_page;
1997 unsigned long expected_index;
1998
1999 if (list_empty(page_list))
2000 break;
2001
2002 page = list_entry(page_list->prev, struct page, lru);
2003 offset = (loff_t)page->index << PAGE_CACHE_SHIFT;
2004
2005 /* count adjacent pages that we will read into */
2006 contig_pages = 0;
Steve Frenchfb8c4b12007-07-10 01:16:18 +00002007 expected_index =
Linus Torvalds1da177e2005-04-16 15:20:36 -07002008 list_entry(page_list->prev, struct page, lru)->index;
Steve Frenchfb8c4b12007-07-10 01:16:18 +00002009 list_for_each_entry_reverse(tmp_page, page_list, lru) {
Linus Torvalds1da177e2005-04-16 15:20:36 -07002010 if (tmp_page->index == expected_index) {
2011 contig_pages++;
2012 expected_index++;
2013 } else
Steve Frenchfb8c4b12007-07-10 01:16:18 +00002014 break;
Linus Torvalds1da177e2005-04-16 15:20:36 -07002015 }
2016 if (contig_pages + i > num_pages)
2017 contig_pages = num_pages - i;
2018
2019 /* for reads over a certain size could initiate async
2020 read ahead */
2021
2022 read_size = contig_pages * PAGE_CACHE_SIZE;
2023 /* Read size needs to be in multiples of one page */
2024 read_size = min_t(const unsigned int, read_size,
2025 cifs_sb->rsize & PAGE_CACHE_MASK);
Steve French90c81e02008-02-12 20:32:36 +00002026 cFYI(DBG2, ("rpages: read size 0x%x contiguous pages %d",
Steve French75865f8c2007-06-24 18:30:48 +00002027 read_size, contig_pages));
Linus Torvalds1da177e2005-04-16 15:20:36 -07002028 rc = -EAGAIN;
2029 while (rc == -EAGAIN) {
Steve Frenchfb8c4b12007-07-10 01:16:18 +00002030 if ((open_file->invalidHandle) &&
Linus Torvalds1da177e2005-04-16 15:20:36 -07002031 (!open_file->closePend)) {
Steve French4b18f2a2008-04-29 00:06:05 +00002032 rc = cifs_reopen_file(file, true);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002033 if (rc != 0)
2034 break;
2035 }
2036
Steve Frenchbfa0d752005-08-31 21:50:37 -07002037 rc = CIFSSMBRead(xid, pTcon,
Steve Frenchec637e32005-12-12 20:53:18 -08002038 open_file->netfid,
2039 read_size, offset,
2040 &bytes_read, &smb_read_data,
2041 &buf_type);
Steve Frencha9d02ad2005-08-24 23:06:05 -07002042 /* BB more RC checks ? */
Steve Frenchfb8c4b12007-07-10 01:16:18 +00002043 if (rc == -EAGAIN) {
Linus Torvalds1da177e2005-04-16 15:20:36 -07002044 if (smb_read_data) {
Steve Frenchfb8c4b12007-07-10 01:16:18 +00002045 if (buf_type == CIFS_SMALL_BUFFER)
Steve Frenchec637e32005-12-12 20:53:18 -08002046 cifs_small_buf_release(smb_read_data);
Steve Frenchfb8c4b12007-07-10 01:16:18 +00002047 else if (buf_type == CIFS_LARGE_BUFFER)
Steve Frenchec637e32005-12-12 20:53:18 -08002048 cifs_buf_release(smb_read_data);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002049 smb_read_data = NULL;
2050 }
2051 }
2052 }
2053 if ((rc < 0) || (smb_read_data == NULL)) {
2054 cFYI(1, ("Read error in readpages: %d", rc));
Linus Torvalds1da177e2005-04-16 15:20:36 -07002055 break;
2056 } else if (bytes_read > 0) {
Andrew Morton6f88cc22006-12-10 02:19:44 -08002057 task_io_account_read(bytes_read);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002058 pSMBr = (struct smb_com_read_rsp *)smb_read_data;
2059 cifs_copy_cache_pages(mapping, page_list, bytes_read,
2060 smb_read_data + 4 /* RFC1001 hdr */ +
2061 le16_to_cpu(pSMBr->DataOffset), &lru_pvec);
2062
2063 i += bytes_read >> PAGE_CACHE_SHIFT;
Steve Frencha4544342005-08-24 13:59:35 -07002064 cifs_stats_bytes_read(pTcon, bytes_read);
Steve French2c2130e2007-10-12 19:10:28 +00002065 if ((bytes_read & PAGE_CACHE_MASK) != bytes_read) {
Linus Torvalds1da177e2005-04-16 15:20:36 -07002066 i++; /* account for partial page */
2067
Steve Frenchfb8c4b12007-07-10 01:16:18 +00002068 /* server copy of file can have smaller size
Linus Torvalds1da177e2005-04-16 15:20:36 -07002069 than client */
Steve Frenchfb8c4b12007-07-10 01:16:18 +00002070 /* BB do we need to verify this common case ?
2071 this case is ok - if we are at server EOF
Linus Torvalds1da177e2005-04-16 15:20:36 -07002072 we will hit it on next read */
2073
OGAWA Hirofumi05ac9d42006-11-02 22:07:08 -08002074 /* break; */
Linus Torvalds1da177e2005-04-16 15:20:36 -07002075 }
2076 } else {
2077 cFYI(1, ("No bytes read (%d) at offset %lld . "
2078 "Cleaning remaining pages from readahead list",
2079 bytes_read, offset));
Steve Frenchfb8c4b12007-07-10 01:16:18 +00002080 /* BB turn off caching and do new lookup on
Linus Torvalds1da177e2005-04-16 15:20:36 -07002081 file size at server? */
Linus Torvalds1da177e2005-04-16 15:20:36 -07002082 break;
2083 }
2084 if (smb_read_data) {
Steve Frenchfb8c4b12007-07-10 01:16:18 +00002085 if (buf_type == CIFS_SMALL_BUFFER)
Steve Frenchec637e32005-12-12 20:53:18 -08002086 cifs_small_buf_release(smb_read_data);
Steve Frenchfb8c4b12007-07-10 01:16:18 +00002087 else if (buf_type == CIFS_LARGE_BUFFER)
Steve Frenchec637e32005-12-12 20:53:18 -08002088 cifs_buf_release(smb_read_data);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002089 smb_read_data = NULL;
2090 }
2091 bytes_read = 0;
2092 }
2093
Rik van Riel4f98a2f2008-10-18 20:26:32 -07002094 pagevec_lru_add_file(&lru_pvec);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002095
2096/* need to free smb_read_data buf before exit */
2097 if (smb_read_data) {
Steve Frenchfb8c4b12007-07-10 01:16:18 +00002098 if (buf_type == CIFS_SMALL_BUFFER)
Steve French47c886b2006-01-18 14:20:39 -08002099 cifs_small_buf_release(smb_read_data);
Steve Frenchfb8c4b12007-07-10 01:16:18 +00002100 else if (buf_type == CIFS_LARGE_BUFFER)
Steve French47c886b2006-01-18 14:20:39 -08002101 cifs_buf_release(smb_read_data);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002102 smb_read_data = NULL;
Steve Frenchfb8c4b12007-07-10 01:16:18 +00002103 }
Linus Torvalds1da177e2005-04-16 15:20:36 -07002104
2105 FreeXid(xid);
2106 return rc;
2107}
2108
2109static int cifs_readpage_worker(struct file *file, struct page *page,
2110 loff_t *poffset)
2111{
2112 char *read_data;
2113 int rc;
2114
2115 page_cache_get(page);
2116 read_data = kmap(page);
2117 /* for reads over a certain size could initiate async read ahead */
Steve Frenchfb8c4b12007-07-10 01:16:18 +00002118
Linus Torvalds1da177e2005-04-16 15:20:36 -07002119 rc = cifs_read(file, read_data, PAGE_CACHE_SIZE, poffset);
Steve Frenchfb8c4b12007-07-10 01:16:18 +00002120
Linus Torvalds1da177e2005-04-16 15:20:36 -07002121 if (rc < 0)
2122 goto io_error;
2123 else
Steve Frenchfb8c4b12007-07-10 01:16:18 +00002124 cFYI(1, ("Bytes read %d", rc));
2125
Josef "Jeff" Sipeke6a00292006-12-08 02:36:48 -08002126 file->f_path.dentry->d_inode->i_atime =
2127 current_fs_time(file->f_path.dentry->d_inode->i_sb);
Steve Frenchfb8c4b12007-07-10 01:16:18 +00002128
Linus Torvalds1da177e2005-04-16 15:20:36 -07002129 if (PAGE_CACHE_SIZE > rc)
2130 memset(read_data + rc, 0, PAGE_CACHE_SIZE - rc);
2131
2132 flush_dcache_page(page);
2133 SetPageUptodate(page);
2134 rc = 0;
Steve Frenchfb8c4b12007-07-10 01:16:18 +00002135
Linus Torvalds1da177e2005-04-16 15:20:36 -07002136io_error:
Steve Frenchfb8c4b12007-07-10 01:16:18 +00002137 kunmap(page);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002138 page_cache_release(page);
2139 return rc;
2140}
2141
2142static int cifs_readpage(struct file *file, struct page *page)
2143{
2144 loff_t offset = (loff_t)page->index << PAGE_CACHE_SHIFT;
2145 int rc = -EACCES;
2146 int xid;
2147
2148 xid = GetXid();
2149
2150 if (file->private_data == NULL) {
2151 FreeXid(xid);
2152 return -EBADF;
2153 }
2154
Steve Frenchfb8c4b12007-07-10 01:16:18 +00002155 cFYI(1, ("readpage %p at offset %d 0x%x\n",
Linus Torvalds1da177e2005-04-16 15:20:36 -07002156 page, (int)offset, (int)offset));
2157
2158 rc = cifs_readpage_worker(file, page, &offset);
2159
2160 unlock_page(page);
2161
2162 FreeXid(xid);
2163 return rc;
2164}
2165
Steve Frencha403a0a2007-07-26 15:54:16 +00002166static int is_inode_writable(struct cifsInodeInfo *cifs_inode)
2167{
2168 struct cifsFileInfo *open_file;
2169
2170 read_lock(&GlobalSMBSeslock);
2171 list_for_each_entry(open_file, &cifs_inode->openFileList, flist) {
2172 if (open_file->closePend)
2173 continue;
2174 if (open_file->pfile &&
2175 ((open_file->pfile->f_flags & O_RDWR) ||
2176 (open_file->pfile->f_flags & O_WRONLY))) {
2177 read_unlock(&GlobalSMBSeslock);
2178 return 1;
2179 }
2180 }
2181 read_unlock(&GlobalSMBSeslock);
2182 return 0;
2183}
2184
Linus Torvalds1da177e2005-04-16 15:20:36 -07002185/* We do not want to update the file size from server for inodes
2186 open for write - to avoid races with writepage extending
2187 the file - in the future we could consider allowing
Steve Frenchfb8c4b12007-07-10 01:16:18 +00002188 refreshing the inode only on increases in the file size
Linus Torvalds1da177e2005-04-16 15:20:36 -07002189 but this is tricky to do without racing with writebehind
2190 page caching in the current Linux kernel design */
Steve French4b18f2a2008-04-29 00:06:05 +00002191bool is_size_safe_to_change(struct cifsInodeInfo *cifsInode, __u64 end_of_file)
Linus Torvalds1da177e2005-04-16 15:20:36 -07002192{
Steve Frencha403a0a2007-07-26 15:54:16 +00002193 if (!cifsInode)
Steve French4b18f2a2008-04-29 00:06:05 +00002194 return true;
Steve French23e7dd72005-10-20 13:44:56 -07002195
Steve Frencha403a0a2007-07-26 15:54:16 +00002196 if (is_inode_writable(cifsInode)) {
2197 /* This inode is open for write at least once */
Steve Frenchc32a0b62006-01-12 14:41:28 -08002198 struct cifs_sb_info *cifs_sb;
2199
Steve Frenchc32a0b62006-01-12 14:41:28 -08002200 cifs_sb = CIFS_SB(cifsInode->vfs_inode.i_sb);
Steve Frenchad7a2922008-02-07 23:25:02 +00002201 if (cifs_sb->mnt_cifs_flags & CIFS_MOUNT_DIRECT_IO) {
Steve Frenchfb8c4b12007-07-10 01:16:18 +00002202 /* since no page cache to corrupt on directio
Steve Frenchc32a0b62006-01-12 14:41:28 -08002203 we can change size safely */
Steve French4b18f2a2008-04-29 00:06:05 +00002204 return true;
Steve Frenchc32a0b62006-01-12 14:41:28 -08002205 }
2206
Steve Frenchfb8c4b12007-07-10 01:16:18 +00002207 if (i_size_read(&cifsInode->vfs_inode) < end_of_file)
Steve French4b18f2a2008-04-29 00:06:05 +00002208 return true;
Steve French7ba52632007-02-08 18:14:13 +00002209
Steve French4b18f2a2008-04-29 00:06:05 +00002210 return false;
Steve French23e7dd72005-10-20 13:44:56 -07002211 } else
Steve French4b18f2a2008-04-29 00:06:05 +00002212 return true;
Linus Torvalds1da177e2005-04-16 15:20:36 -07002213}
2214
Nick Piggind9414772008-09-24 11:32:59 -04002215static int cifs_write_begin(struct file *file, struct address_space *mapping,
2216 loff_t pos, unsigned len, unsigned flags,
2217 struct page **pagep, void **fsdata)
Linus Torvalds1da177e2005-04-16 15:20:36 -07002218{
Nick Piggind9414772008-09-24 11:32:59 -04002219 pgoff_t index = pos >> PAGE_CACHE_SHIFT;
2220 loff_t offset = pos & (PAGE_CACHE_SIZE - 1);
Jeff Laytona98ee8c2008-11-26 19:32:33 +00002221 loff_t page_start = pos & PAGE_MASK;
2222 loff_t i_size;
2223 struct page *page;
2224 int rc = 0;
Linus Torvalds1da177e2005-04-16 15:20:36 -07002225
Nick Piggind9414772008-09-24 11:32:59 -04002226 cFYI(1, ("write_begin from %lld len %d", (long long)pos, len));
2227
Nick Piggin54566b22009-01-04 12:00:53 -08002228 page = grab_cache_page_write_begin(mapping, index, flags);
Jeff Laytona98ee8c2008-11-26 19:32:33 +00002229 if (!page) {
2230 rc = -ENOMEM;
2231 goto out;
2232 }
Nick Piggind9414772008-09-24 11:32:59 -04002233
Jeff Laytona98ee8c2008-11-26 19:32:33 +00002234 if (PageUptodate(page))
2235 goto out;
Steve French8a236262007-03-06 00:31:00 +00002236
Jeff Laytona98ee8c2008-11-26 19:32:33 +00002237 /*
2238 * If we write a full page it will be up to date, no need to read from
2239 * the server. If the write is short, we'll end up doing a sync write
2240 * instead.
2241 */
2242 if (len == PAGE_CACHE_SIZE)
2243 goto out;
2244
2245 /*
2246 * optimize away the read when we have an oplock, and we're not
2247 * expecting to use any of the data we'd be reading in. That
2248 * is, when the page lies beyond the EOF, or straddles the EOF
2249 * and the write will cover all of the existing data.
2250 */
2251 if (CIFS_I(mapping->host)->clientCanCacheRead) {
2252 i_size = i_size_read(mapping->host);
2253 if (page_start >= i_size ||
2254 (offset == 0 && (pos + len) >= i_size)) {
2255 zero_user_segments(page, 0, offset,
2256 offset + len,
2257 PAGE_CACHE_SIZE);
2258 /*
2259 * PageChecked means that the parts of the page
2260 * to which we're not writing are considered up
2261 * to date. Once the data is copied to the
2262 * page, it can be set uptodate.
2263 */
2264 SetPageChecked(page);
2265 goto out;
2266 }
2267 }
Linus Torvalds1da177e2005-04-16 15:20:36 -07002268
Nick Piggind9414772008-09-24 11:32:59 -04002269 if ((file->f_flags & O_ACCMODE) != O_WRONLY) {
Jeff Laytona98ee8c2008-11-26 19:32:33 +00002270 /*
2271 * might as well read a page, it is fast enough. If we get
2272 * an error, we don't need to return it. cifs_write_end will
2273 * do a sync write instead since PG_uptodate isn't set.
2274 */
2275 cifs_readpage_worker(file, page, &page_start);
Steve French8a236262007-03-06 00:31:00 +00002276 } else {
2277 /* we could try using another file handle if there is one -
2278 but how would we lock it to prevent close of that handle
2279 racing with this read? In any case
Nick Piggind9414772008-09-24 11:32:59 -04002280 this will be written out by write_end so is fine */
Steve French8a236262007-03-06 00:31:00 +00002281 }
Jeff Laytona98ee8c2008-11-26 19:32:33 +00002282out:
2283 *pagep = page;
2284 return rc;
Linus Torvalds1da177e2005-04-16 15:20:36 -07002285}
2286
Christoph Hellwigf5e54d62006-06-28 04:26:44 -07002287const struct address_space_operations cifs_addr_ops = {
Linus Torvalds1da177e2005-04-16 15:20:36 -07002288 .readpage = cifs_readpage,
2289 .readpages = cifs_readpages,
2290 .writepage = cifs_writepage,
Steve French37c0eb42005-10-05 14:50:29 -07002291 .writepages = cifs_writepages,
Nick Piggind9414772008-09-24 11:32:59 -04002292 .write_begin = cifs_write_begin,
2293 .write_end = cifs_write_end,
Linus Torvalds1da177e2005-04-16 15:20:36 -07002294 .set_page_dirty = __set_page_dirty_nobuffers,
2295 /* .sync_page = cifs_sync_page, */
2296 /* .direct_IO = */
2297};
Dave Kleikamp273d81d2006-06-01 19:41:23 +00002298
2299/*
2300 * cifs_readpages requires the server to support a buffer large enough to
2301 * contain the header plus one complete page of data. Otherwise, we need
2302 * to leave cifs_readpages out of the address space operations.
2303 */
Christoph Hellwigf5e54d62006-06-28 04:26:44 -07002304const struct address_space_operations cifs_addr_ops_smallbuf = {
Dave Kleikamp273d81d2006-06-01 19:41:23 +00002305 .readpage = cifs_readpage,
2306 .writepage = cifs_writepage,
2307 .writepages = cifs_writepages,
Nick Piggind9414772008-09-24 11:32:59 -04002308 .write_begin = cifs_write_begin,
2309 .write_end = cifs_write_end,
Dave Kleikamp273d81d2006-06-01 19:41:23 +00002310 .set_page_dirty = __set_page_dirty_nobuffers,
2311 /* .sync_page = cifs_sync_page, */
2312 /* .direct_IO = */
2313};