blob: 38c06f826575b4c8c94e0c9924dbd040b247f7f5 [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;
Steve Frencha6ce4932009-04-09 01:14:32 +000049 mutex_init(&private_data->fh_mutex);
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{
Steve French276a74a2009-03-03 18:00:34 +0000132
133 file->private_data = kmalloc(sizeof(struct cifsFileInfo), GFP_KERNEL);
134 if (file->private_data == NULL)
135 return -ENOMEM;
136 pCifsFile = cifs_init_private(file->private_data, inode, file, netfid);
137 write_lock(&GlobalSMBSeslock);
Steve French276a74a2009-03-03 18:00:34 +0000138
139 pCifsInode = CIFS_I(file->f_path.dentry->d_inode);
140 if (pCifsInode == NULL) {
141 write_unlock(&GlobalSMBSeslock);
142 return -EINVAL;
143 }
144
Steve French276a74a2009-03-03 18:00:34 +0000145 if (pCifsInode->clientCanCacheRead) {
146 /* we have the inode open somewhere else
147 no need to discard cache data */
148 goto psx_client_can_cache;
149 }
150
151 /* BB FIXME need to fix this check to move it earlier into posix_open
152 BB fIX following section BB FIXME */
153
154 /* if not oplocked, invalidate inode pages if mtime or file
155 size changed */
156/* temp = cifs_NTtimeToUnix(le64_to_cpu(buf->LastWriteTime));
157 if (timespec_equal(&file->f_path.dentry->d_inode->i_mtime, &temp) &&
158 (file->f_path.dentry->d_inode->i_size ==
159 (loff_t)le64_to_cpu(buf->EndOfFile))) {
160 cFYI(1, ("inode unchanged on server"));
161 } else {
162 if (file->f_path.dentry->d_inode->i_mapping) {
163 rc = filemap_write_and_wait(file->f_path.dentry->d_inode->i_mapping);
164 if (rc != 0)
165 CIFS_I(file->f_path.dentry->d_inode)->write_behind_rc = rc;
166 }
167 cFYI(1, ("invalidating remote inode since open detected it "
168 "changed"));
169 invalidate_remote_inode(file->f_path.dentry->d_inode);
170 } */
171
172psx_client_can_cache:
173 if ((oplock & 0xF) == OPLOCK_EXCLUSIVE) {
174 pCifsInode->clientCanCacheAll = true;
175 pCifsInode->clientCanCacheRead = true;
176 cFYI(1, ("Exclusive Oplock granted on inode %p",
177 file->f_path.dentry->d_inode));
178 } else if ((oplock & 0xF) == OPLOCK_READ)
179 pCifsInode->clientCanCacheRead = true;
180
181 /* will have to change the unlock if we reenable the
182 filemap_fdatawrite (which does not seem necessary */
183 write_unlock(&GlobalSMBSeslock);
184 return 0;
185}
186
187/* all arguments to this function must be checked for validity in caller */
Linus Torvalds1da177e2005-04-16 15:20:36 -0700188static inline int cifs_open_inode_helper(struct inode *inode, struct file *file,
189 struct cifsInodeInfo *pCifsInode, struct cifsFileInfo *pCifsFile,
190 struct cifsTconInfo *pTcon, int *oplock, FILE_ALL_INFO *buf,
191 char *full_path, int xid)
192{
193 struct timespec temp;
194 int rc;
195
196 /* want handles we can use to read with first
197 in the list so we do not have to walk the
Nick Piggind9414772008-09-24 11:32:59 -0400198 list to search for one in write_begin */
Linus Torvalds1da177e2005-04-16 15:20:36 -0700199 if ((file->f_flags & O_ACCMODE) == O_WRONLY) {
Steve Frenchfb8c4b12007-07-10 01:16:18 +0000200 list_add_tail(&pCifsFile->flist,
Linus Torvalds1da177e2005-04-16 15:20:36 -0700201 &pCifsInode->openFileList);
202 } else {
203 list_add(&pCifsFile->flist,
204 &pCifsInode->openFileList);
205 }
206 write_unlock(&GlobalSMBSeslock);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700207 if (pCifsInode->clientCanCacheRead) {
208 /* we have the inode open somewhere else
209 no need to discard cache data */
210 goto client_can_cache;
211 }
212
213 /* BB need same check in cifs_create too? */
214 /* if not oplocked, invalidate inode pages if mtime or file
215 size changed */
216 temp = cifs_NTtimeToUnix(le64_to_cpu(buf->LastWriteTime));
Josef "Jeff" Sipeke6a00292006-12-08 02:36:48 -0800217 if (timespec_equal(&file->f_path.dentry->d_inode->i_mtime, &temp) &&
218 (file->f_path.dentry->d_inode->i_size ==
Linus Torvalds1da177e2005-04-16 15:20:36 -0700219 (loff_t)le64_to_cpu(buf->EndOfFile))) {
220 cFYI(1, ("inode unchanged on server"));
221 } else {
Josef "Jeff" Sipeke6a00292006-12-08 02:36:48 -0800222 if (file->f_path.dentry->d_inode->i_mapping) {
Linus Torvalds1da177e2005-04-16 15:20:36 -0700223 /* BB no need to lock inode until after invalidate
224 since namei code should already have it locked? */
Jeff Laytoncea21802007-11-20 23:19:03 +0000225 rc = filemap_write_and_wait(file->f_path.dentry->d_inode->i_mapping);
226 if (rc != 0)
227 CIFS_I(file->f_path.dentry->d_inode)->write_behind_rc = rc;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700228 }
229 cFYI(1, ("invalidating remote inode since open detected it "
230 "changed"));
Josef "Jeff" Sipeke6a00292006-12-08 02:36:48 -0800231 invalidate_remote_inode(file->f_path.dentry->d_inode);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700232 }
233
234client_can_cache:
Steve Frenchc18c8422007-07-18 23:21:09 +0000235 if (pTcon->unix_ext)
Josef "Jeff" Sipeke6a00292006-12-08 02:36:48 -0800236 rc = cifs_get_inode_info_unix(&file->f_path.dentry->d_inode,
Linus Torvalds1da177e2005-04-16 15:20:36 -0700237 full_path, inode->i_sb, xid);
238 else
Josef "Jeff" Sipeke6a00292006-12-08 02:36:48 -0800239 rc = cifs_get_inode_info(&file->f_path.dentry->d_inode,
Steve French8b1327f2008-03-14 22:37:16 +0000240 full_path, buf, inode->i_sb, xid, NULL);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700241
242 if ((*oplock & 0xF) == OPLOCK_EXCLUSIVE) {
Steve French4b18f2a2008-04-29 00:06:05 +0000243 pCifsInode->clientCanCacheAll = true;
244 pCifsInode->clientCanCacheRead = true;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700245 cFYI(1, ("Exclusive Oplock granted on inode %p",
Josef "Jeff" Sipeke6a00292006-12-08 02:36:48 -0800246 file->f_path.dentry->d_inode));
Linus Torvalds1da177e2005-04-16 15:20:36 -0700247 } else if ((*oplock & 0xF) == OPLOCK_READ)
Steve French4b18f2a2008-04-29 00:06:05 +0000248 pCifsInode->clientCanCacheRead = true;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700249
250 return rc;
251}
252
253int cifs_open(struct inode *inode, struct file *file)
254{
255 int rc = -EACCES;
256 int xid, oplock;
257 struct cifs_sb_info *cifs_sb;
Steve French276a74a2009-03-03 18:00:34 +0000258 struct cifsTconInfo *tcon;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700259 struct cifsFileInfo *pCifsFile;
260 struct cifsInodeInfo *pCifsInode;
261 struct list_head *tmp;
262 char *full_path = NULL;
263 int desiredAccess;
264 int disposition;
265 __u16 netfid;
266 FILE_ALL_INFO *buf = NULL;
267
268 xid = GetXid();
269
270 cifs_sb = CIFS_SB(inode->i_sb);
Steve French276a74a2009-03-03 18:00:34 +0000271 tcon = cifs_sb->tcon;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700272
Steve Frencha6ce4932009-04-09 01:14:32 +0000273 /* search inode for this file and fill in file->private_data */
274 pCifsInode = CIFS_I(file->f_path.dentry->d_inode);
275 read_lock(&GlobalSMBSeslock);
276 list_for_each(tmp, &pCifsInode->openFileList) {
277 pCifsFile = list_entry(tmp, struct cifsFileInfo,
278 flist);
279 if ((pCifsFile->pfile == NULL) &&
280 (pCifsFile->pid == current->tgid)) {
281 /* mode set in cifs_create */
Linus Torvalds1da177e2005-04-16 15:20:36 -0700282
Steve Frencha6ce4932009-04-09 01:14:32 +0000283 /* needed for writepage */
284 pCifsFile->pfile = file;
Steve French50c2f752007-07-13 00:33:32 +0000285
Steve Frencha6ce4932009-04-09 01:14:32 +0000286 file->private_data = pCifsFile;
287 break;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700288 }
Steve Frencha6ce4932009-04-09 01:14:32 +0000289 }
290 read_unlock(&GlobalSMBSeslock);
291
292 if (file->private_data != NULL) {
293 rc = 0;
294 FreeXid(xid);
295 return rc;
Steve Frenchbc8cd432009-04-12 18:18:40 +0000296 } else if ((file->f_flags & O_CREAT) && (file->f_flags & O_EXCL))
Steve Frencha6ce4932009-04-09 01:14:32 +0000297 cERROR(1, ("could not find file instance for "
298 "new file %p", file));
Linus Torvalds1da177e2005-04-16 15:20:36 -0700299
Josef "Jeff" Sipeke6a00292006-12-08 02:36:48 -0800300 full_path = build_path_from_dentry(file->f_path.dentry);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700301 if (full_path == NULL) {
302 FreeXid(xid);
303 return -ENOMEM;
304 }
305
Steve French7521a3c2007-07-11 18:30:34 +0000306 cFYI(1, ("inode = 0x%p file flags are 0x%x for %s",
Linus Torvalds1da177e2005-04-16 15:20:36 -0700307 inode, file->f_flags, full_path));
Steve French276a74a2009-03-03 18:00:34 +0000308
309 if (oplockEnabled)
310 oplock = REQ_OPLOCK;
311 else
312 oplock = 0;
313
Steve French64cc2c62009-03-04 19:54:08 +0000314 if (!tcon->broken_posix_open && tcon->unix_ext &&
315 (tcon->ses->capabilities & CAP_UNIX) &&
Steve French276a74a2009-03-03 18:00:34 +0000316 (CIFS_UNIX_POSIX_PATH_OPS_CAP &
317 le64_to_cpu(tcon->fsUnixInfo.Capability))) {
318 int oflags = (int) cifs_posix_convert_flags(file->f_flags);
319 /* can not refresh inode info since size could be stale */
320 rc = cifs_posix_open(full_path, &inode, inode->i_sb,
321 cifs_sb->mnt_file_mode /* ignored */,
322 oflags, &oplock, &netfid, xid);
323 if (rc == 0) {
324 cFYI(1, ("posix open succeeded"));
325 /* no need for special case handling of setting mode
326 on read only files needed here */
327
328 cifs_posix_open_inode_helper(inode, file, pCifsInode,
329 pCifsFile, oplock, netfid);
330 goto out;
Steve French64cc2c62009-03-04 19:54:08 +0000331 } else if ((rc == -EINVAL) || (rc == -EOPNOTSUPP)) {
332 if (tcon->ses->serverNOS)
333 cERROR(1, ("server %s of type %s returned"
334 " unexpected error on SMB posix open"
335 ", disabling posix open support."
336 " Check if server update available.",
337 tcon->ses->serverName,
338 tcon->ses->serverNOS));
339 tcon->broken_posix_open = true;
Steve French276a74a2009-03-03 18:00:34 +0000340 } else if ((rc != -EIO) && (rc != -EREMOTE) &&
341 (rc != -EOPNOTSUPP)) /* path not found or net err */
342 goto out;
Steve French64cc2c62009-03-04 19:54:08 +0000343 /* else fallthrough to retry open the old way on network i/o
344 or DFS errors */
Steve French276a74a2009-03-03 18:00:34 +0000345 }
346
Linus Torvalds1da177e2005-04-16 15:20:36 -0700347 desiredAccess = cifs_convert_flags(file->f_flags);
348
349/*********************************************************************
350 * open flag mapping table:
Steve Frenchfb8c4b12007-07-10 01:16:18 +0000351 *
Linus Torvalds1da177e2005-04-16 15:20:36 -0700352 * POSIX Flag CIFS Disposition
Steve Frenchfb8c4b12007-07-10 01:16:18 +0000353 * ---------- ----------------
Linus Torvalds1da177e2005-04-16 15:20:36 -0700354 * O_CREAT FILE_OPEN_IF
355 * O_CREAT | O_EXCL FILE_CREATE
356 * O_CREAT | O_TRUNC FILE_OVERWRITE_IF
357 * O_TRUNC FILE_OVERWRITE
358 * none of the above FILE_OPEN
359 *
360 * Note that there is not a direct match between disposition
Steve Frenchfb8c4b12007-07-10 01:16:18 +0000361 * FILE_SUPERSEDE (ie create whether or not file exists although
Linus Torvalds1da177e2005-04-16 15:20:36 -0700362 * O_CREAT | O_TRUNC is similar but truncates the existing
363 * file rather than creating a new file as FILE_SUPERSEDE does
364 * (which uses the attributes / metadata passed in on open call)
365 *?
Steve Frenchfb8c4b12007-07-10 01:16:18 +0000366 *? O_SYNC is a reasonable match to CIFS writethrough flag
Linus Torvalds1da177e2005-04-16 15:20:36 -0700367 *? and the read write flags match reasonably. O_LARGEFILE
368 *? is irrelevant because largefile support is always used
369 *? by this client. Flags O_APPEND, O_DIRECT, O_DIRECTORY,
370 * O_FASYNC, O_NOFOLLOW, O_NONBLOCK need further investigation
371 *********************************************************************/
372
373 disposition = cifs_get_disposition(file->f_flags);
374
Linus Torvalds1da177e2005-04-16 15:20:36 -0700375 /* BB pass O_SYNC flag through on file attributes .. BB */
376
377 /* Also refresh inode by passing in file_info buf returned by SMBOpen
378 and calling get_inode_info with returned buf (at least helps
379 non-Unix server case) */
380
Steve Frenchfb8c4b12007-07-10 01:16:18 +0000381 /* BB we can not do this if this is the second open of a file
382 and the first handle has writebehind data, we might be
Linus Torvalds1da177e2005-04-16 15:20:36 -0700383 able to simply do a filemap_fdatawrite/filemap_fdatawait first */
384 buf = kmalloc(sizeof(FILE_ALL_INFO), GFP_KERNEL);
385 if (!buf) {
386 rc = -ENOMEM;
387 goto out;
388 }
Steve French5bafd762006-06-07 00:18:43 +0000389
390 if (cifs_sb->tcon->ses->capabilities & CAP_NT_SMBS)
Steve French276a74a2009-03-03 18:00:34 +0000391 rc = CIFSSMBOpen(xid, tcon, full_path, disposition,
Steve French5bafd762006-06-07 00:18:43 +0000392 desiredAccess, CREATE_NOT_DIR, &netfid, &oplock, buf,
Steve French737b7582005-04-28 22:41:06 -0700393 cifs_sb->local_nls, cifs_sb->mnt_cifs_flags
394 & CIFS_MOUNT_MAP_SPECIAL_CHR);
Steve French5bafd762006-06-07 00:18:43 +0000395 else
396 rc = -EIO; /* no NT SMB support fall into legacy open below */
397
Steve Frencha9d02ad2005-08-24 23:06:05 -0700398 if (rc == -EIO) {
399 /* Old server, try legacy style OpenX */
Steve French276a74a2009-03-03 18:00:34 +0000400 rc = SMBLegacyOpen(xid, tcon, full_path, disposition,
Steve Frencha9d02ad2005-08-24 23:06:05 -0700401 desiredAccess, CREATE_NOT_DIR, &netfid, &oplock, buf,
402 cifs_sb->local_nls, cifs_sb->mnt_cifs_flags
403 & CIFS_MOUNT_MAP_SPECIAL_CHR);
404 }
Linus Torvalds1da177e2005-04-16 15:20:36 -0700405 if (rc) {
Steve French26a21b92006-05-31 18:05:34 +0000406 cFYI(1, ("cifs_open returned 0x%x", rc));
Linus Torvalds1da177e2005-04-16 15:20:36 -0700407 goto out;
408 }
409 file->private_data =
410 kmalloc(sizeof(struct cifsFileInfo), GFP_KERNEL);
411 if (file->private_data == NULL) {
412 rc = -ENOMEM;
413 goto out;
414 }
415 pCifsFile = cifs_init_private(file->private_data, inode, file, netfid);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700416 write_lock(&GlobalSMBSeslock);
Steve French276a74a2009-03-03 18:00:34 +0000417 list_add(&pCifsFile->tlist, &tcon->openFileList);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700418
Josef "Jeff" Sipeke6a00292006-12-08 02:36:48 -0800419 pCifsInode = CIFS_I(file->f_path.dentry->d_inode);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700420 if (pCifsInode) {
421 rc = cifs_open_inode_helper(inode, file, pCifsInode,
Steve French276a74a2009-03-03 18:00:34 +0000422 pCifsFile, tcon,
Linus Torvalds1da177e2005-04-16 15:20:36 -0700423 &oplock, buf, full_path, xid);
424 } else {
425 write_unlock(&GlobalSMBSeslock);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700426 }
427
Steve Frenchfb8c4b12007-07-10 01:16:18 +0000428 if (oplock & CIFS_CREATE_ACTION) {
Linus Torvalds1da177e2005-04-16 15:20:36 -0700429 /* time to set mode which we can not set earlier due to
430 problems creating new read-only files */
Steve French276a74a2009-03-03 18:00:34 +0000431 if (tcon->unix_ext) {
Jeff Layton4e1e7fb2008-08-02 07:26:12 -0400432 struct cifs_unix_set_info_args args = {
433 .mode = inode->i_mode,
434 .uid = NO_CHANGE_64,
435 .gid = NO_CHANGE_64,
436 .ctime = NO_CHANGE_64,
437 .atime = NO_CHANGE_64,
438 .mtime = NO_CHANGE_64,
439 .device = 0,
440 };
Steve French276a74a2009-03-03 18:00:34 +0000441 CIFSSMBUnixSetInfo(xid, tcon, full_path, &args,
Steve French737b7582005-04-28 22:41:06 -0700442 cifs_sb->local_nls,
Steve Frenchfb8c4b12007-07-10 01:16:18 +0000443 cifs_sb->mnt_cifs_flags &
Steve French737b7582005-04-28 22:41:06 -0700444 CIFS_MOUNT_MAP_SPECIAL_CHR);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700445 }
446 }
447
448out:
449 kfree(buf);
450 kfree(full_path);
451 FreeXid(xid);
452 return rc;
453}
454
Adrian Bunk04187262006-06-30 18:23:04 +0200455/* Try to reacquire byte range locks that were released when session */
Linus Torvalds1da177e2005-04-16 15:20:36 -0700456/* to server was lost */
457static int cifs_relock_file(struct cifsFileInfo *cifsFile)
458{
459 int rc = 0;
460
461/* BB list all locks open on this file and relock */
462
463 return rc;
464}
465
Steve French4b18f2a2008-04-29 00:06:05 +0000466static int cifs_reopen_file(struct file *file, bool can_flush)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700467{
468 int rc = -EACCES;
469 int xid, oplock;
470 struct cifs_sb_info *cifs_sb;
Steve French7fc8f4e2009-02-23 20:43:11 +0000471 struct cifsTconInfo *tcon;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700472 struct cifsFileInfo *pCifsFile;
473 struct cifsInodeInfo *pCifsInode;
Steve Frenchfb8c4b12007-07-10 01:16:18 +0000474 struct inode *inode;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700475 char *full_path = NULL;
476 int desiredAccess;
477 int disposition = FILE_OPEN;
478 __u16 netfid;
479
Steve Frenchad7a2922008-02-07 23:25:02 +0000480 if (file->private_data)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700481 pCifsFile = (struct cifsFileInfo *)file->private_data;
Steve Frenchad7a2922008-02-07 23:25:02 +0000482 else
Linus Torvalds1da177e2005-04-16 15:20:36 -0700483 return -EBADF;
484
485 xid = GetXid();
Steve Frencha6ce4932009-04-09 01:14:32 +0000486 mutex_unlock(&pCifsFile->fh_mutex);
Steve French4b18f2a2008-04-29 00:06:05 +0000487 if (!pCifsFile->invalidHandle) {
Steve Frencha6ce4932009-04-09 01:14:32 +0000488 mutex_lock(&pCifsFile->fh_mutex);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700489 FreeXid(xid);
490 return 0;
491 }
492
Josef "Jeff" Sipeke6a00292006-12-08 02:36:48 -0800493 if (file->f_path.dentry == NULL) {
Steve French3a9f4622007-04-04 17:10:24 +0000494 cERROR(1, ("no valid name if dentry freed"));
495 dump_stack();
496 rc = -EBADF;
497 goto reopen_error_exit;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700498 }
Steve French3a9f4622007-04-04 17:10:24 +0000499
500 inode = file->f_path.dentry->d_inode;
Steve Frenchfb8c4b12007-07-10 01:16:18 +0000501 if (inode == NULL) {
Steve French3a9f4622007-04-04 17:10:24 +0000502 cERROR(1, ("inode not valid"));
503 dump_stack();
504 rc = -EBADF;
505 goto reopen_error_exit;
506 }
Steve French50c2f752007-07-13 00:33:32 +0000507
Linus Torvalds1da177e2005-04-16 15:20:36 -0700508 cifs_sb = CIFS_SB(inode->i_sb);
Steve French7fc8f4e2009-02-23 20:43:11 +0000509 tcon = cifs_sb->tcon;
Steve French3a9f4622007-04-04 17:10:24 +0000510
Linus Torvalds1da177e2005-04-16 15:20:36 -0700511/* can not grab rename sem here because various ops, including
512 those that already have the rename sem can end up causing writepage
513 to get called and if the server was down that means we end up here,
514 and we can never tell if the caller already has the rename_sem */
Josef "Jeff" Sipeke6a00292006-12-08 02:36:48 -0800515 full_path = build_path_from_dentry(file->f_path.dentry);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700516 if (full_path == NULL) {
Steve French3a9f4622007-04-04 17:10:24 +0000517 rc = -ENOMEM;
518reopen_error_exit:
Steve Frencha6ce4932009-04-09 01:14:32 +0000519 mutex_lock(&pCifsFile->fh_mutex);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700520 FreeXid(xid);
Steve French3a9f4622007-04-04 17:10:24 +0000521 return rc;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700522 }
523
Steve French3a9f4622007-04-04 17:10:24 +0000524 cFYI(1, ("inode = 0x%p file flags 0x%x for %s",
Steve Frenchfb8c4b12007-07-10 01:16:18 +0000525 inode, file->f_flags, full_path));
Linus Torvalds1da177e2005-04-16 15:20:36 -0700526
527 if (oplockEnabled)
528 oplock = REQ_OPLOCK;
529 else
Steve French4b18f2a2008-04-29 00:06:05 +0000530 oplock = 0;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700531
Steve French7fc8f4e2009-02-23 20:43:11 +0000532 if (tcon->unix_ext && (tcon->ses->capabilities & CAP_UNIX) &&
533 (CIFS_UNIX_POSIX_PATH_OPS_CAP &
534 le64_to_cpu(tcon->fsUnixInfo.Capability))) {
535 int oflags = (int) cifs_posix_convert_flags(file->f_flags);
536 /* can not refresh inode info since size could be stale */
537 rc = cifs_posix_open(full_path, NULL, inode->i_sb,
538 cifs_sb->mnt_file_mode /* ignored */,
539 oflags, &oplock, &netfid, xid);
540 if (rc == 0) {
541 cFYI(1, ("posix reopen succeeded"));
542 goto reopen_success;
543 }
544 /* fallthrough to retry open the old way on errors, especially
545 in the reconnect path it is important to retry hard */
546 }
547
548 desiredAccess = cifs_convert_flags(file->f_flags);
549
Linus Torvalds1da177e2005-04-16 15:20:36 -0700550 /* Can not refresh inode by passing in file_info buf to be returned
Steve Frenchfb8c4b12007-07-10 01:16:18 +0000551 by SMBOpen and then calling get_inode_info with returned buf
552 since file might have write behind data that needs to be flushed
Linus Torvalds1da177e2005-04-16 15:20:36 -0700553 and server version of file size can be stale. If we knew for sure
554 that inode was not dirty locally we could do this */
555
Steve French7fc8f4e2009-02-23 20:43:11 +0000556 rc = CIFSSMBOpen(xid, tcon, full_path, disposition, desiredAccess,
Linus Torvalds1da177e2005-04-16 15:20:36 -0700557 CREATE_NOT_DIR, &netfid, &oplock, NULL,
Steve Frenchfb8c4b12007-07-10 01:16:18 +0000558 cifs_sb->local_nls, cifs_sb->mnt_cifs_flags &
Steve French737b7582005-04-28 22:41:06 -0700559 CIFS_MOUNT_MAP_SPECIAL_CHR);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700560 if (rc) {
Steve Frencha6ce4932009-04-09 01:14:32 +0000561 mutex_lock(&pCifsFile->fh_mutex);
Steve French26a21b92006-05-31 18:05:34 +0000562 cFYI(1, ("cifs_open returned 0x%x", rc));
563 cFYI(1, ("oplock: %d", oplock));
Linus Torvalds1da177e2005-04-16 15:20:36 -0700564 } else {
Steve French7fc8f4e2009-02-23 20:43:11 +0000565reopen_success:
Linus Torvalds1da177e2005-04-16 15:20:36 -0700566 pCifsFile->netfid = netfid;
Steve French4b18f2a2008-04-29 00:06:05 +0000567 pCifsFile->invalidHandle = false;
Steve Frencha6ce4932009-04-09 01:14:32 +0000568 mutex_lock(&pCifsFile->fh_mutex);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700569 pCifsInode = CIFS_I(inode);
570 if (pCifsInode) {
571 if (can_flush) {
Jeff Laytoncea21802007-11-20 23:19:03 +0000572 rc = filemap_write_and_wait(inode->i_mapping);
573 if (rc != 0)
574 CIFS_I(inode)->write_behind_rc = rc;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700575 /* temporarily disable caching while we
576 go to server to get inode info */
Steve French4b18f2a2008-04-29 00:06:05 +0000577 pCifsInode->clientCanCacheAll = false;
578 pCifsInode->clientCanCacheRead = false;
Steve French7fc8f4e2009-02-23 20:43:11 +0000579 if (tcon->unix_ext)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700580 rc = cifs_get_inode_info_unix(&inode,
581 full_path, inode->i_sb, xid);
582 else
583 rc = cifs_get_inode_info(&inode,
584 full_path, NULL, inode->i_sb,
Steve French8b1327f2008-03-14 22:37:16 +0000585 xid, NULL);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700586 } /* else we are writing out data to server already
587 and could deadlock if we tried to flush data, and
588 since we do not know if we have data that would
589 invalidate the current end of file on the server
590 we can not go to the server to get the new inod
591 info */
592 if ((oplock & 0xF) == OPLOCK_EXCLUSIVE) {
Steve French4b18f2a2008-04-29 00:06:05 +0000593 pCifsInode->clientCanCacheAll = true;
594 pCifsInode->clientCanCacheRead = true;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700595 cFYI(1, ("Exclusive Oplock granted on inode %p",
Josef "Jeff" Sipeke6a00292006-12-08 02:36:48 -0800596 file->f_path.dentry->d_inode));
Linus Torvalds1da177e2005-04-16 15:20:36 -0700597 } else if ((oplock & 0xF) == OPLOCK_READ) {
Steve French4b18f2a2008-04-29 00:06:05 +0000598 pCifsInode->clientCanCacheRead = true;
599 pCifsInode->clientCanCacheAll = false;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700600 } else {
Steve French4b18f2a2008-04-29 00:06:05 +0000601 pCifsInode->clientCanCacheRead = false;
602 pCifsInode->clientCanCacheAll = false;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700603 }
604 cifs_relock_file(pCifsFile);
605 }
606 }
Linus Torvalds1da177e2005-04-16 15:20:36 -0700607 kfree(full_path);
608 FreeXid(xid);
609 return rc;
610}
611
612int cifs_close(struct inode *inode, struct file *file)
613{
614 int rc = 0;
Steve French15745322007-09-07 22:23:48 +0000615 int xid, timeout;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700616 struct cifs_sb_info *cifs_sb;
617 struct cifsTconInfo *pTcon;
618 struct cifsFileInfo *pSMBFile =
619 (struct cifsFileInfo *)file->private_data;
620
621 xid = GetXid();
622
623 cifs_sb = CIFS_SB(inode->i_sb);
624 pTcon = cifs_sb->tcon;
625 if (pSMBFile) {
Jeremy Allison7ee1af72006-08-02 21:56:33 +0000626 struct cifsLockInfo *li, *tmp;
Steve Frenchddb4cbf2008-11-20 20:00:44 +0000627 write_lock(&GlobalSMBSeslock);
Steve French4b18f2a2008-04-29 00:06:05 +0000628 pSMBFile->closePend = true;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700629 if (pTcon) {
630 /* no sense reconnecting to close a file that is
631 already closed */
Steve French3b795212008-11-13 19:45:32 +0000632 if (!pTcon->need_reconnect) {
Steve Frenchddb4cbf2008-11-20 20:00:44 +0000633 write_unlock(&GlobalSMBSeslock);
Steve French15745322007-09-07 22:23:48 +0000634 timeout = 2;
Steve Frenchfb8c4b12007-07-10 01:16:18 +0000635 while ((atomic_read(&pSMBFile->wrtPending) != 0)
Steve French15745322007-09-07 22:23:48 +0000636 && (timeout <= 2048)) {
Steve French23e7dd72005-10-20 13:44:56 -0700637 /* Give write a better chance to get to
638 server ahead of the close. We do not
639 want to add a wait_q here as it would
640 increase the memory utilization as
641 the struct would be in each open file,
Steve Frenchfb8c4b12007-07-10 01:16:18 +0000642 but this should give enough time to
Steve French23e7dd72005-10-20 13:44:56 -0700643 clear the socket */
Steve French90c81e02008-02-12 20:32:36 +0000644 cFYI(DBG2,
645 ("close delay, write pending"));
Steve French23e7dd72005-10-20 13:44:56 -0700646 msleep(timeout);
647 timeout *= 4;
Steve French4891d532006-11-07 16:31:16 +0000648 }
Steve Frenchfb8c4b12007-07-10 01:16:18 +0000649 if (atomic_read(&pSMBFile->wrtPending))
Steve Frenchddb4cbf2008-11-20 20:00:44 +0000650 cERROR(1, ("close with pending write"));
651 if (!pTcon->need_reconnect &&
652 !pSMBFile->invalidHandle)
653 rc = CIFSSMBClose(xid, pTcon,
Linus Torvalds1da177e2005-04-16 15:20:36 -0700654 pSMBFile->netfid);
Steve Frenchddb4cbf2008-11-20 20:00:44 +0000655 } else
656 write_unlock(&GlobalSMBSeslock);
657 } else
658 write_unlock(&GlobalSMBSeslock);
Jeremy Allison7ee1af72006-08-02 21:56:33 +0000659
660 /* Delete any outstanding lock records.
661 We'll lose them when the file is closed anyway. */
Roland Dreier796e5662007-05-03 04:33:45 +0000662 mutex_lock(&pSMBFile->lock_mutex);
Jeremy Allison7ee1af72006-08-02 21:56:33 +0000663 list_for_each_entry_safe(li, tmp, &pSMBFile->llist, llist) {
664 list_del(&li->llist);
665 kfree(li);
666 }
Roland Dreier796e5662007-05-03 04:33:45 +0000667 mutex_unlock(&pSMBFile->lock_mutex);
Jeremy Allison7ee1af72006-08-02 21:56:33 +0000668
Steve Frenchcbe04762005-04-28 22:41:05 -0700669 write_lock(&GlobalSMBSeslock);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700670 list_del(&pSMBFile->flist);
671 list_del(&pSMBFile->tlist);
Steve Frenchcbe04762005-04-28 22:41:05 -0700672 write_unlock(&GlobalSMBSeslock);
Steve French15745322007-09-07 22:23:48 +0000673 timeout = 10;
674 /* We waited above to give the SMBWrite a chance to issue
675 on the wire (so we do not get SMBWrite returning EBADF
676 if writepages is racing with close. Note that writepages
677 does not specify a file handle, so it is possible for a file
678 to be opened twice, and the application close the "wrong"
679 file handle - in these cases we delay long enough to allow
680 the SMBWrite to get on the wire before the SMB Close.
681 We allow total wait here over 45 seconds, more than
682 oplock break time, and more than enough to allow any write
683 to complete on the server, or to time out on the client */
684 while ((atomic_read(&pSMBFile->wrtPending) != 0)
685 && (timeout <= 50000)) {
686 cERROR(1, ("writes pending, delay free of handle"));
687 msleep(timeout);
688 timeout *= 8;
689 }
Linus Torvalds1da177e2005-04-16 15:20:36 -0700690 kfree(file->private_data);
691 file->private_data = NULL;
692 } else
693 rc = -EBADF;
694
Steve French4efa53f2007-09-11 05:50:53 +0000695 read_lock(&GlobalSMBSeslock);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700696 if (list_empty(&(CIFS_I(inode)->openFileList))) {
697 cFYI(1, ("closing last open instance for inode %p", inode));
698 /* if the file is not open we do not know if we can cache info
699 on this inode, much less write behind and read ahead */
Steve French4b18f2a2008-04-29 00:06:05 +0000700 CIFS_I(inode)->clientCanCacheRead = false;
701 CIFS_I(inode)->clientCanCacheAll = false;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700702 }
Steve French4efa53f2007-09-11 05:50:53 +0000703 read_unlock(&GlobalSMBSeslock);
Steve Frenchfb8c4b12007-07-10 01:16:18 +0000704 if ((rc == 0) && CIFS_I(inode)->write_behind_rc)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700705 rc = CIFS_I(inode)->write_behind_rc;
706 FreeXid(xid);
707 return rc;
708}
709
710int cifs_closedir(struct inode *inode, struct file *file)
711{
712 int rc = 0;
713 int xid;
714 struct cifsFileInfo *pCFileStruct =
715 (struct cifsFileInfo *)file->private_data;
716 char *ptmp;
717
Steve French26a21b92006-05-31 18:05:34 +0000718 cFYI(1, ("Closedir inode = 0x%p", inode));
Linus Torvalds1da177e2005-04-16 15:20:36 -0700719
720 xid = GetXid();
721
722 if (pCFileStruct) {
723 struct cifsTconInfo *pTcon;
Steve Frenchfb8c4b12007-07-10 01:16:18 +0000724 struct cifs_sb_info *cifs_sb =
725 CIFS_SB(file->f_path.dentry->d_sb);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700726
727 pTcon = cifs_sb->tcon;
728
729 cFYI(1, ("Freeing private data in close dir"));
Steve Frenchddb4cbf2008-11-20 20:00:44 +0000730 write_lock(&GlobalSMBSeslock);
Steve French4b18f2a2008-04-29 00:06:05 +0000731 if (!pCFileStruct->srch_inf.endOfSearch &&
732 !pCFileStruct->invalidHandle) {
733 pCFileStruct->invalidHandle = true;
Steve Frenchddb4cbf2008-11-20 20:00:44 +0000734 write_unlock(&GlobalSMBSeslock);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700735 rc = CIFSFindClose(xid, pTcon, pCFileStruct->netfid);
736 cFYI(1, ("Closing uncompleted readdir with rc %d",
737 rc));
738 /* not much we can do if it fails anyway, ignore rc */
739 rc = 0;
Steve Frenchddb4cbf2008-11-20 20:00:44 +0000740 } else
741 write_unlock(&GlobalSMBSeslock);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700742 ptmp = pCFileStruct->srch_inf.ntwrk_buf_start;
743 if (ptmp) {
Steve Frenchec637e32005-12-12 20:53:18 -0800744 cFYI(1, ("closedir free smb buf in srch struct"));
Linus Torvalds1da177e2005-04-16 15:20:36 -0700745 pCFileStruct->srch_inf.ntwrk_buf_start = NULL;
Steve Frenchfb8c4b12007-07-10 01:16:18 +0000746 if (pCFileStruct->srch_inf.smallBuf)
Steve Frenchd47d7c12006-02-28 03:45:48 +0000747 cifs_small_buf_release(ptmp);
748 else
749 cifs_buf_release(ptmp);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700750 }
Linus Torvalds1da177e2005-04-16 15:20:36 -0700751 kfree(file->private_data);
752 file->private_data = NULL;
753 }
754 /* BB can we lock the filestruct while this is going on? */
755 FreeXid(xid);
756 return rc;
757}
758
Jeremy Allison7ee1af72006-08-02 21:56:33 +0000759static int store_file_lock(struct cifsFileInfo *fid, __u64 len,
760 __u64 offset, __u8 lockType)
761{
Steve Frenchfb8c4b12007-07-10 01:16:18 +0000762 struct cifsLockInfo *li =
763 kmalloc(sizeof(struct cifsLockInfo), GFP_KERNEL);
Jeremy Allison7ee1af72006-08-02 21:56:33 +0000764 if (li == NULL)
765 return -ENOMEM;
766 li->offset = offset;
767 li->length = len;
768 li->type = lockType;
Roland Dreier796e5662007-05-03 04:33:45 +0000769 mutex_lock(&fid->lock_mutex);
Jeremy Allison7ee1af72006-08-02 21:56:33 +0000770 list_add(&li->llist, &fid->llist);
Roland Dreier796e5662007-05-03 04:33:45 +0000771 mutex_unlock(&fid->lock_mutex);
Jeremy Allison7ee1af72006-08-02 21:56:33 +0000772 return 0;
773}
774
Linus Torvalds1da177e2005-04-16 15:20:36 -0700775int cifs_lock(struct file *file, int cmd, struct file_lock *pfLock)
776{
777 int rc, xid;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700778 __u32 numLock = 0;
779 __u32 numUnlock = 0;
780 __u64 length;
Steve French4b18f2a2008-04-29 00:06:05 +0000781 bool wait_flag = false;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700782 struct cifs_sb_info *cifs_sb;
Steve French13a6e422008-12-02 17:24:33 +0000783 struct cifsTconInfo *tcon;
Steve French08547b02006-02-28 22:39:25 +0000784 __u16 netfid;
785 __u8 lockType = LOCKING_ANDX_LARGE_FILES;
Steve French13a6e422008-12-02 17:24:33 +0000786 bool posix_locking = 0;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700787
788 length = 1 + pfLock->fl_end - pfLock->fl_start;
789 rc = -EACCES;
790 xid = GetXid();
791
792 cFYI(1, ("Lock parm: 0x%x flockflags: "
793 "0x%x flocktype: 0x%x start: %lld end: %lld",
Steve Frenchfb8c4b12007-07-10 01:16:18 +0000794 cmd, pfLock->fl_flags, pfLock->fl_type, pfLock->fl_start,
795 pfLock->fl_end));
Linus Torvalds1da177e2005-04-16 15:20:36 -0700796
797 if (pfLock->fl_flags & FL_POSIX)
Steve Frenchd47d7c12006-02-28 03:45:48 +0000798 cFYI(1, ("Posix"));
Linus Torvalds1da177e2005-04-16 15:20:36 -0700799 if (pfLock->fl_flags & FL_FLOCK)
Steve Frenchd47d7c12006-02-28 03:45:48 +0000800 cFYI(1, ("Flock"));
Linus Torvalds1da177e2005-04-16 15:20:36 -0700801 if (pfLock->fl_flags & FL_SLEEP) {
Steve Frenchd47d7c12006-02-28 03:45:48 +0000802 cFYI(1, ("Blocking lock"));
Steve French4b18f2a2008-04-29 00:06:05 +0000803 wait_flag = true;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700804 }
805 if (pfLock->fl_flags & FL_ACCESS)
806 cFYI(1, ("Process suspended by mandatory locking - "
Steve French26a21b92006-05-31 18:05:34 +0000807 "not implemented yet"));
Linus Torvalds1da177e2005-04-16 15:20:36 -0700808 if (pfLock->fl_flags & FL_LEASE)
809 cFYI(1, ("Lease on file - not implemented yet"));
Steve Frenchfb8c4b12007-07-10 01:16:18 +0000810 if (pfLock->fl_flags &
Linus Torvalds1da177e2005-04-16 15:20:36 -0700811 (~(FL_POSIX | FL_FLOCK | FL_SLEEP | FL_ACCESS | FL_LEASE)))
812 cFYI(1, ("Unknown lock flags 0x%x", pfLock->fl_flags));
813
814 if (pfLock->fl_type == F_WRLCK) {
815 cFYI(1, ("F_WRLCK "));
816 numLock = 1;
817 } else if (pfLock->fl_type == F_UNLCK) {
Steve Frenchd47d7c12006-02-28 03:45:48 +0000818 cFYI(1, ("F_UNLCK"));
Linus Torvalds1da177e2005-04-16 15:20:36 -0700819 numUnlock = 1;
Steve Frenchd47d7c12006-02-28 03:45:48 +0000820 /* Check if unlock includes more than
821 one lock range */
Linus Torvalds1da177e2005-04-16 15:20:36 -0700822 } else if (pfLock->fl_type == F_RDLCK) {
Steve Frenchd47d7c12006-02-28 03:45:48 +0000823 cFYI(1, ("F_RDLCK"));
Linus Torvalds1da177e2005-04-16 15:20:36 -0700824 lockType |= LOCKING_ANDX_SHARED_LOCK;
825 numLock = 1;
826 } else if (pfLock->fl_type == F_EXLCK) {
Steve Frenchd47d7c12006-02-28 03:45:48 +0000827 cFYI(1, ("F_EXLCK"));
Linus Torvalds1da177e2005-04-16 15:20:36 -0700828 numLock = 1;
829 } else if (pfLock->fl_type == F_SHLCK) {
Steve Frenchd47d7c12006-02-28 03:45:48 +0000830 cFYI(1, ("F_SHLCK"));
Linus Torvalds1da177e2005-04-16 15:20:36 -0700831 lockType |= LOCKING_ANDX_SHARED_LOCK;
832 numLock = 1;
833 } else
Steve Frenchd47d7c12006-02-28 03:45:48 +0000834 cFYI(1, ("Unknown type of lock"));
Linus Torvalds1da177e2005-04-16 15:20:36 -0700835
Josef "Jeff" Sipeke6a00292006-12-08 02:36:48 -0800836 cifs_sb = CIFS_SB(file->f_path.dentry->d_sb);
Steve French13a6e422008-12-02 17:24:33 +0000837 tcon = cifs_sb->tcon;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700838
839 if (file->private_data == NULL) {
840 FreeXid(xid);
841 return -EBADF;
842 }
Steve French08547b02006-02-28 22:39:25 +0000843 netfid = ((struct cifsFileInfo *)file->private_data)->netfid;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700844
Steve French13a6e422008-12-02 17:24:33 +0000845 if ((tcon->ses->capabilities & CAP_UNIX) &&
846 (CIFS_UNIX_FCNTL_CAP & le64_to_cpu(tcon->fsUnixInfo.Capability)) &&
Steve Frenchacc18aa2008-12-02 18:53:55 +0000847 ((cifs_sb->mnt_cifs_flags & CIFS_MOUNT_NOPOSIXBRL) == 0))
Steve French13a6e422008-12-02 17:24:33 +0000848 posix_locking = 1;
Steve French08547b02006-02-28 22:39:25 +0000849 /* BB add code here to normalize offset and length to
850 account for negative length which we can not accept over the
851 wire */
Linus Torvalds1da177e2005-04-16 15:20:36 -0700852 if (IS_GETLK(cmd)) {
Steve Frenchfb8c4b12007-07-10 01:16:18 +0000853 if (posix_locking) {
Steve French08547b02006-02-28 22:39:25 +0000854 int posix_lock_type;
Steve Frenchfb8c4b12007-07-10 01:16:18 +0000855 if (lockType & LOCKING_ANDX_SHARED_LOCK)
Steve French08547b02006-02-28 22:39:25 +0000856 posix_lock_type = CIFS_RDLCK;
857 else
858 posix_lock_type = CIFS_WRLCK;
Steve French13a6e422008-12-02 17:24:33 +0000859 rc = CIFSSMBPosixLock(xid, tcon, netfid, 1 /* get */,
Steve Frenchfc94cdb2006-05-30 18:03:32 +0000860 length, pfLock,
Steve French08547b02006-02-28 22:39:25 +0000861 posix_lock_type, wait_flag);
862 FreeXid(xid);
863 return rc;
864 }
865
866 /* BB we could chain these into one lock request BB */
Steve French13a6e422008-12-02 17:24:33 +0000867 rc = CIFSSMBLock(xid, tcon, netfid, length, pfLock->fl_start,
Steve French08547b02006-02-28 22:39:25 +0000868 0, 1, lockType, 0 /* wait flag */ );
Linus Torvalds1da177e2005-04-16 15:20:36 -0700869 if (rc == 0) {
Steve French13a6e422008-12-02 17:24:33 +0000870 rc = CIFSSMBLock(xid, tcon, netfid, length,
Linus Torvalds1da177e2005-04-16 15:20:36 -0700871 pfLock->fl_start, 1 /* numUnlock */ ,
872 0 /* numLock */ , lockType,
873 0 /* wait flag */ );
874 pfLock->fl_type = F_UNLCK;
875 if (rc != 0)
876 cERROR(1, ("Error unlocking previously locked "
Steve French08547b02006-02-28 22:39:25 +0000877 "range %d during test of lock", rc));
Linus Torvalds1da177e2005-04-16 15:20:36 -0700878 rc = 0;
879
880 } else {
881 /* if rc == ERR_SHARING_VIOLATION ? */
882 rc = 0; /* do not change lock type to unlock
883 since range in use */
884 }
885
886 FreeXid(xid);
887 return rc;
888 }
Jeremy Allison7ee1af72006-08-02 21:56:33 +0000889
890 if (!numLock && !numUnlock) {
891 /* if no lock or unlock then nothing
892 to do since we do not know what it is */
893 FreeXid(xid);
894 return -EOPNOTSUPP;
895 }
896
897 if (posix_locking) {
Steve French08547b02006-02-28 22:39:25 +0000898 int posix_lock_type;
Steve Frenchfb8c4b12007-07-10 01:16:18 +0000899 if (lockType & LOCKING_ANDX_SHARED_LOCK)
Steve French08547b02006-02-28 22:39:25 +0000900 posix_lock_type = CIFS_RDLCK;
901 else
902 posix_lock_type = CIFS_WRLCK;
Steve French50c2f752007-07-13 00:33:32 +0000903
Steve Frenchfb8c4b12007-07-10 01:16:18 +0000904 if (numUnlock == 1)
Steve Frenchbeb84dc2006-03-03 23:36:34 +0000905 posix_lock_type = CIFS_UNLCK;
Jeremy Allison7ee1af72006-08-02 21:56:33 +0000906
Steve French13a6e422008-12-02 17:24:33 +0000907 rc = CIFSSMBPosixLock(xid, tcon, netfid, 0 /* set */,
Steve Frenchfc94cdb2006-05-30 18:03:32 +0000908 length, pfLock,
Steve French08547b02006-02-28 22:39:25 +0000909 posix_lock_type, wait_flag);
Jeremy Allison7ee1af72006-08-02 21:56:33 +0000910 } else {
Steve Frenchfb8c4b12007-07-10 01:16:18 +0000911 struct cifsFileInfo *fid =
912 (struct cifsFileInfo *)file->private_data;
Jeremy Allison7ee1af72006-08-02 21:56:33 +0000913
914 if (numLock) {
Steve French13a6e422008-12-02 17:24:33 +0000915 rc = CIFSSMBLock(xid, tcon, netfid, length,
Steve Frenchfb8c4b12007-07-10 01:16:18 +0000916 pfLock->fl_start,
Jeremy Allison7ee1af72006-08-02 21:56:33 +0000917 0, numLock, lockType, wait_flag);
918
919 if (rc == 0) {
920 /* For Windows locks we must store them. */
921 rc = store_file_lock(fid, length,
922 pfLock->fl_start, lockType);
923 }
924 } else if (numUnlock) {
925 /* For each stored lock that this unlock overlaps
926 completely, unlock it. */
927 int stored_rc = 0;
928 struct cifsLockInfo *li, *tmp;
929
Steve French6b70c952006-09-21 07:35:29 +0000930 rc = 0;
Roland Dreier796e5662007-05-03 04:33:45 +0000931 mutex_lock(&fid->lock_mutex);
Jeremy Allison7ee1af72006-08-02 21:56:33 +0000932 list_for_each_entry_safe(li, tmp, &fid->llist, llist) {
933 if (pfLock->fl_start <= li->offset &&
Steve Frenchc19eb712007-08-24 03:22:48 +0000934 (pfLock->fl_start + length) >=
Jeff Layton39db8102007-08-24 03:16:51 +0000935 (li->offset + li->length)) {
Steve French13a6e422008-12-02 17:24:33 +0000936 stored_rc = CIFSSMBLock(xid, tcon,
Steve Frenchfb8c4b12007-07-10 01:16:18 +0000937 netfid,
Jeremy Allison7ee1af72006-08-02 21:56:33 +0000938 li->length, li->offset,
Steve French4b18f2a2008-04-29 00:06:05 +0000939 1, 0, li->type, false);
Jeremy Allison7ee1af72006-08-02 21:56:33 +0000940 if (stored_rc)
941 rc = stored_rc;
942
943 list_del(&li->llist);
944 kfree(li);
945 }
946 }
Roland Dreier796e5662007-05-03 04:33:45 +0000947 mutex_unlock(&fid->lock_mutex);
Jeremy Allison7ee1af72006-08-02 21:56:33 +0000948 }
949 }
950
Steve Frenchd634cc12005-08-26 14:42:59 -0500951 if (pfLock->fl_flags & FL_POSIX)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700952 posix_lock_file_wait(file, pfLock);
953 FreeXid(xid);
954 return rc;
955}
956
Jeff Laytonfbec9ab2009-04-03 13:44:00 -0400957/*
958 * Set the timeout on write requests past EOF. For some servers (Windows)
959 * these calls can be very long.
960 *
961 * If we're writing >10M past the EOF we give a 180s timeout. Anything less
962 * than that gets a 45s timeout. Writes not past EOF get 15s timeouts.
963 * The 10M cutoff is totally arbitrary. A better scheme for this would be
964 * welcome if someone wants to suggest one.
965 *
966 * We may be able to do a better job with this if there were some way to
967 * declare that a file should be sparse.
968 */
969static int
970cifs_write_timeout(struct cifsInodeInfo *cifsi, loff_t offset)
971{
972 if (offset <= cifsi->server_eof)
973 return CIFS_STD_OP;
974 else if (offset > (cifsi->server_eof + (10 * 1024 * 1024)))
975 return CIFS_VLONG_OP;
976 else
977 return CIFS_LONG_OP;
978}
979
980/* update the file size (if needed) after a write */
981static void
982cifs_update_eof(struct cifsInodeInfo *cifsi, loff_t offset,
983 unsigned int bytes_written)
984{
985 loff_t end_of_write = offset + bytes_written;
986
987 if (end_of_write > cifsi->server_eof)
988 cifsi->server_eof = end_of_write;
989}
990
Linus Torvalds1da177e2005-04-16 15:20:36 -0700991ssize_t cifs_user_write(struct file *file, const char __user *write_data,
992 size_t write_size, loff_t *poffset)
993{
994 int rc = 0;
995 unsigned int bytes_written = 0;
996 unsigned int total_written;
997 struct cifs_sb_info *cifs_sb;
998 struct cifsTconInfo *pTcon;
999 int xid, long_op;
1000 struct cifsFileInfo *open_file;
Jeff Laytonfbec9ab2009-04-03 13:44:00 -04001001 struct cifsInodeInfo *cifsi = CIFS_I(file->f_path.dentry->d_inode);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001002
Josef "Jeff" Sipeke6a00292006-12-08 02:36:48 -08001003 cifs_sb = CIFS_SB(file->f_path.dentry->d_sb);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001004
1005 pTcon = cifs_sb->tcon;
1006
1007 /* cFYI(1,
1008 (" write %d bytes to offset %lld of %s", write_size,
Josef "Jeff" Sipeke6a00292006-12-08 02:36:48 -08001009 *poffset, file->f_path.dentry->d_name.name)); */
Linus Torvalds1da177e2005-04-16 15:20:36 -07001010
1011 if (file->private_data == NULL)
1012 return -EBADF;
Christoph Hellwigc33f8d32007-04-02 18:47:20 +00001013 open_file = (struct cifsFileInfo *) file->private_data;
Steve French50c2f752007-07-13 00:33:32 +00001014
Jeff Layton838726c2008-08-28 07:54:59 -04001015 rc = generic_write_checks(file, poffset, &write_size, 0);
1016 if (rc)
1017 return rc;
1018
Linus Torvalds1da177e2005-04-16 15:20:36 -07001019 xid = GetXid();
Linus Torvalds1da177e2005-04-16 15:20:36 -07001020
Jeff Laytonfbec9ab2009-04-03 13:44:00 -04001021 long_op = cifs_write_timeout(cifsi, *poffset);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001022 for (total_written = 0; write_size > total_written;
1023 total_written += bytes_written) {
1024 rc = -EAGAIN;
1025 while (rc == -EAGAIN) {
1026 if (file->private_data == NULL) {
1027 /* file has been closed on us */
1028 FreeXid(xid);
1029 /* if we have gotten here we have written some data
1030 and blocked, and the file has been freed on us while
1031 we blocked so return what we managed to write */
1032 return total_written;
Steve Frenchfb8c4b12007-07-10 01:16:18 +00001033 }
Linus Torvalds1da177e2005-04-16 15:20:36 -07001034 if (open_file->closePend) {
1035 FreeXid(xid);
1036 if (total_written)
1037 return total_written;
1038 else
1039 return -EBADF;
1040 }
1041 if (open_file->invalidHandle) {
Linus Torvalds1da177e2005-04-16 15:20:36 -07001042 /* we could deadlock if we called
1043 filemap_fdatawait from here so tell
1044 reopen_file not to flush data to server
1045 now */
Steve French4b18f2a2008-04-29 00:06:05 +00001046 rc = cifs_reopen_file(file, false);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001047 if (rc != 0)
1048 break;
1049 }
1050
1051 rc = CIFSSMBWrite(xid, pTcon,
1052 open_file->netfid,
1053 min_t(const int, cifs_sb->wsize,
1054 write_size - total_written),
1055 *poffset, &bytes_written,
1056 NULL, write_data + total_written, long_op);
1057 }
1058 if (rc || (bytes_written == 0)) {
1059 if (total_written)
1060 break;
1061 else {
1062 FreeXid(xid);
1063 return rc;
1064 }
Jeff Laytonfbec9ab2009-04-03 13:44:00 -04001065 } else {
1066 cifs_update_eof(cifsi, *poffset, bytes_written);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001067 *poffset += bytes_written;
Jeff Laytonfbec9ab2009-04-03 13:44:00 -04001068 }
Steve French133672e2007-11-13 22:41:37 +00001069 long_op = CIFS_STD_OP; /* subsequent writes fast -
Linus Torvalds1da177e2005-04-16 15:20:36 -07001070 15 seconds is plenty */
1071 }
1072
Steve Frencha4544342005-08-24 13:59:35 -07001073 cifs_stats_bytes_written(pTcon, total_written);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001074
1075 /* since the write may have blocked check these pointers again */
Steve French3677db12007-02-26 16:46:11 +00001076 if ((file->f_path.dentry) && (file->f_path.dentry->d_inode)) {
1077 struct inode *inode = file->f_path.dentry->d_inode;
Steve Frenchfb8c4b12007-07-10 01:16:18 +00001078/* Do not update local mtime - server will set its actual value on write
1079 * inode->i_ctime = inode->i_mtime =
Steve French3677db12007-02-26 16:46:11 +00001080 * current_fs_time(inode->i_sb);*/
1081 if (total_written > 0) {
1082 spin_lock(&inode->i_lock);
1083 if (*poffset > file->f_path.dentry->d_inode->i_size)
1084 i_size_write(file->f_path.dentry->d_inode,
Linus Torvalds1da177e2005-04-16 15:20:36 -07001085 *poffset);
Steve French3677db12007-02-26 16:46:11 +00001086 spin_unlock(&inode->i_lock);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001087 }
Steve Frenchfb8c4b12007-07-10 01:16:18 +00001088 mark_inode_dirty_sync(file->f_path.dentry->d_inode);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001089 }
1090 FreeXid(xid);
1091 return total_written;
1092}
1093
1094static ssize_t cifs_write(struct file *file, const char *write_data,
Nick Piggind9414772008-09-24 11:32:59 -04001095 size_t write_size, loff_t *poffset)
Linus Torvalds1da177e2005-04-16 15:20:36 -07001096{
1097 int rc = 0;
1098 unsigned int bytes_written = 0;
1099 unsigned int total_written;
1100 struct cifs_sb_info *cifs_sb;
1101 struct cifsTconInfo *pTcon;
1102 int xid, long_op;
1103 struct cifsFileInfo *open_file;
Jeff Laytonfbec9ab2009-04-03 13:44:00 -04001104 struct cifsInodeInfo *cifsi = CIFS_I(file->f_path.dentry->d_inode);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001105
Josef "Jeff" Sipeke6a00292006-12-08 02:36:48 -08001106 cifs_sb = CIFS_SB(file->f_path.dentry->d_sb);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001107
1108 pTcon = cifs_sb->tcon;
1109
Steve Frenchfb8c4b12007-07-10 01:16:18 +00001110 cFYI(1, ("write %zd bytes to offset %lld of %s", write_size,
Josef "Jeff" Sipeke6a00292006-12-08 02:36:48 -08001111 *poffset, file->f_path.dentry->d_name.name));
Linus Torvalds1da177e2005-04-16 15:20:36 -07001112
1113 if (file->private_data == NULL)
1114 return -EBADF;
Christoph Hellwigc33f8d32007-04-02 18:47:20 +00001115 open_file = (struct cifsFileInfo *)file->private_data;
Steve French50c2f752007-07-13 00:33:32 +00001116
Linus Torvalds1da177e2005-04-16 15:20:36 -07001117 xid = GetXid();
Linus Torvalds1da177e2005-04-16 15:20:36 -07001118
Jeff Laytonfbec9ab2009-04-03 13:44:00 -04001119 long_op = cifs_write_timeout(cifsi, *poffset);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001120 for (total_written = 0; write_size > total_written;
1121 total_written += bytes_written) {
1122 rc = -EAGAIN;
1123 while (rc == -EAGAIN) {
1124 if (file->private_data == NULL) {
1125 /* file has been closed on us */
1126 FreeXid(xid);
1127 /* if we have gotten here we have written some data
1128 and blocked, and the file has been freed on us
Steve Frenchfb8c4b12007-07-10 01:16:18 +00001129 while we blocked so return what we managed to
Linus Torvalds1da177e2005-04-16 15:20:36 -07001130 write */
1131 return total_written;
Steve Frenchfb8c4b12007-07-10 01:16:18 +00001132 }
Linus Torvalds1da177e2005-04-16 15:20:36 -07001133 if (open_file->closePend) {
1134 FreeXid(xid);
1135 if (total_written)
1136 return total_written;
1137 else
1138 return -EBADF;
1139 }
1140 if (open_file->invalidHandle) {
Linus Torvalds1da177e2005-04-16 15:20:36 -07001141 /* we could deadlock if we called
1142 filemap_fdatawait from here so tell
Steve Frenchfb8c4b12007-07-10 01:16:18 +00001143 reopen_file not to flush data to
Linus Torvalds1da177e2005-04-16 15:20:36 -07001144 server now */
Steve French4b18f2a2008-04-29 00:06:05 +00001145 rc = cifs_reopen_file(file, false);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001146 if (rc != 0)
1147 break;
1148 }
Steve Frenchfb8c4b12007-07-10 01:16:18 +00001149 if (experimEnabled || (pTcon->ses->server &&
1150 ((pTcon->ses->server->secMode &
Steve French08775832006-05-30 18:08:26 +00001151 (SECMODE_SIGN_REQUIRED | SECMODE_SIGN_ENABLED))
Steve Frenchc01f36a2006-05-30 18:05:10 +00001152 == 0))) {
Steve French3e844692005-10-03 13:37:24 -07001153 struct kvec iov[2];
1154 unsigned int len;
1155
Steve French0ae0efa2005-10-10 10:57:19 -07001156 len = min((size_t)cifs_sb->wsize,
Steve French3e844692005-10-03 13:37:24 -07001157 write_size - total_written);
1158 /* iov[0] is reserved for smb header */
1159 iov[1].iov_base = (char *)write_data +
1160 total_written;
1161 iov[1].iov_len = len;
Steve Frenchd6e04ae2005-06-13 13:24:43 -05001162 rc = CIFSSMBWrite2(xid, pTcon,
Steve French3e844692005-10-03 13:37:24 -07001163 open_file->netfid, len,
Steve Frenchd6e04ae2005-06-13 13:24:43 -05001164 *poffset, &bytes_written,
Steve French3e844692005-10-03 13:37:24 -07001165 iov, 1, long_op);
Steve Frenchd6e04ae2005-06-13 13:24:43 -05001166 } else
Steve French60808232006-04-22 15:53:05 +00001167 rc = CIFSSMBWrite(xid, pTcon,
1168 open_file->netfid,
1169 min_t(const int, cifs_sb->wsize,
1170 write_size - total_written),
1171 *poffset, &bytes_written,
1172 write_data + total_written,
1173 NULL, long_op);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001174 }
1175 if (rc || (bytes_written == 0)) {
1176 if (total_written)
1177 break;
1178 else {
1179 FreeXid(xid);
1180 return rc;
1181 }
Jeff Laytonfbec9ab2009-04-03 13:44:00 -04001182 } else {
1183 cifs_update_eof(cifsi, *poffset, bytes_written);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001184 *poffset += bytes_written;
Jeff Laytonfbec9ab2009-04-03 13:44:00 -04001185 }
Steve French133672e2007-11-13 22:41:37 +00001186 long_op = CIFS_STD_OP; /* subsequent writes fast -
Linus Torvalds1da177e2005-04-16 15:20:36 -07001187 15 seconds is plenty */
1188 }
1189
Steve Frencha4544342005-08-24 13:59:35 -07001190 cifs_stats_bytes_written(pTcon, total_written);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001191
1192 /* since the write may have blocked check these pointers again */
Steve French3677db12007-02-26 16:46:11 +00001193 if ((file->f_path.dentry) && (file->f_path.dentry->d_inode)) {
Steve French004c46b2007-02-17 04:34:13 +00001194/*BB We could make this contingent on superblock ATIME flag too */
Steve French3677db12007-02-26 16:46:11 +00001195/* file->f_path.dentry->d_inode->i_ctime =
1196 file->f_path.dentry->d_inode->i_mtime = CURRENT_TIME;*/
1197 if (total_written > 0) {
1198 spin_lock(&file->f_path.dentry->d_inode->i_lock);
1199 if (*poffset > file->f_path.dentry->d_inode->i_size)
1200 i_size_write(file->f_path.dentry->d_inode,
1201 *poffset);
1202 spin_unlock(&file->f_path.dentry->d_inode->i_lock);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001203 }
Steve French3677db12007-02-26 16:46:11 +00001204 mark_inode_dirty_sync(file->f_path.dentry->d_inode);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001205 }
1206 FreeXid(xid);
1207 return total_written;
1208}
1209
Steve French630f3f0c2007-10-25 21:17:17 +00001210#ifdef CONFIG_CIFS_EXPERIMENTAL
1211struct cifsFileInfo *find_readable_file(struct cifsInodeInfo *cifs_inode)
1212{
1213 struct cifsFileInfo *open_file = NULL;
1214
1215 read_lock(&GlobalSMBSeslock);
1216 /* we could simply get the first_list_entry since write-only entries
1217 are always at the end of the list but since the first entry might
1218 have a close pending, we go through the whole list */
1219 list_for_each_entry(open_file, &cifs_inode->openFileList, flist) {
1220 if (open_file->closePend)
1221 continue;
1222 if (open_file->pfile && ((open_file->pfile->f_flags & O_RDWR) ||
1223 (open_file->pfile->f_flags & O_RDONLY))) {
1224 if (!open_file->invalidHandle) {
1225 /* found a good file */
1226 /* lock it so it will not be closed on us */
1227 atomic_inc(&open_file->wrtPending);
1228 read_unlock(&GlobalSMBSeslock);
1229 return open_file;
1230 } /* else might as well continue, and look for
1231 another, or simply have the caller reopen it
1232 again rather than trying to fix this handle */
1233 } else /* write only file */
1234 break; /* write only files are last so must be done */
1235 }
1236 read_unlock(&GlobalSMBSeslock);
1237 return NULL;
1238}
1239#endif
1240
Steve Frenchdd99cd82005-10-05 19:32:49 -07001241struct cifsFileInfo *find_writable_file(struct cifsInodeInfo *cifs_inode)
Steve French6148a742005-10-05 12:23:19 -07001242{
1243 struct cifsFileInfo *open_file;
Jeff Layton2846d382008-09-22 21:33:33 -04001244 bool any_available = false;
Steve Frenchdd99cd82005-10-05 19:32:49 -07001245 int rc;
Steve French6148a742005-10-05 12:23:19 -07001246
Steve French60808232006-04-22 15:53:05 +00001247 /* Having a null inode here (because mapping->host was set to zero by
1248 the VFS or MM) should not happen but we had reports of on oops (due to
1249 it being zero) during stress testcases so we need to check for it */
1250
Steve Frenchfb8c4b12007-07-10 01:16:18 +00001251 if (cifs_inode == NULL) {
1252 cERROR(1, ("Null inode passed to cifs_writeable_file"));
Steve French60808232006-04-22 15:53:05 +00001253 dump_stack();
1254 return NULL;
1255 }
1256
Steve French6148a742005-10-05 12:23:19 -07001257 read_lock(&GlobalSMBSeslock);
Steve French9b22b0b2007-10-02 01:11:08 +00001258refind_writable:
Steve French6148a742005-10-05 12:23:19 -07001259 list_for_each_entry(open_file, &cifs_inode->openFileList, flist) {
Jeff Layton2846d382008-09-22 21:33:33 -04001260 if (open_file->closePend ||
1261 (!any_available && open_file->pid != current->tgid))
Steve French6148a742005-10-05 12:23:19 -07001262 continue;
Jeff Layton2846d382008-09-22 21:33:33 -04001263
Steve French6148a742005-10-05 12:23:19 -07001264 if (open_file->pfile &&
1265 ((open_file->pfile->f_flags & O_RDWR) ||
1266 (open_file->pfile->f_flags & O_WRONLY))) {
Steve French23e7dd72005-10-20 13:44:56 -07001267 atomic_inc(&open_file->wrtPending);
Steve French9b22b0b2007-10-02 01:11:08 +00001268
1269 if (!open_file->invalidHandle) {
1270 /* found a good writable file */
1271 read_unlock(&GlobalSMBSeslock);
1272 return open_file;
1273 }
Steve French8840dee2007-11-16 23:05:52 +00001274
Steve French6148a742005-10-05 12:23:19 -07001275 read_unlock(&GlobalSMBSeslock);
Steve French9b22b0b2007-10-02 01:11:08 +00001276 /* Had to unlock since following call can block */
Steve French4b18f2a2008-04-29 00:06:05 +00001277 rc = cifs_reopen_file(open_file->pfile, false);
Steve French8840dee2007-11-16 23:05:52 +00001278 if (!rc) {
Steve French9b22b0b2007-10-02 01:11:08 +00001279 if (!open_file->closePend)
1280 return open_file;
1281 else { /* start over in case this was deleted */
1282 /* since the list could be modified */
Steve French37c0eb42005-10-05 14:50:29 -07001283 read_lock(&GlobalSMBSeslock);
Steve French15745322007-09-07 22:23:48 +00001284 atomic_dec(&open_file->wrtPending);
Steve French9b22b0b2007-10-02 01:11:08 +00001285 goto refind_writable;
Steve French37c0eb42005-10-05 14:50:29 -07001286 }
1287 }
Steve French9b22b0b2007-10-02 01:11:08 +00001288
1289 /* if it fails, try another handle if possible -
1290 (we can not do this if closePending since
1291 loop could be modified - in which case we
1292 have to start at the beginning of the list
1293 again. Note that it would be bad
1294 to hold up writepages here (rather than
1295 in caller) with continuous retries */
1296 cFYI(1, ("wp failed on reopen file"));
1297 read_lock(&GlobalSMBSeslock);
1298 /* can not use this handle, no write
1299 pending on this one after all */
1300 atomic_dec(&open_file->wrtPending);
Steve French8840dee2007-11-16 23:05:52 +00001301
Steve French9b22b0b2007-10-02 01:11:08 +00001302 if (open_file->closePend) /* list could have changed */
1303 goto refind_writable;
1304 /* else we simply continue to the next entry. Thus
1305 we do not loop on reopen errors. If we
1306 can not reopen the file, for example if we
1307 reconnected to a server with another client
1308 racing to delete or lock the file we would not
1309 make progress if we restarted before the beginning
1310 of the loop here. */
Steve French6148a742005-10-05 12:23:19 -07001311 }
1312 }
Jeff Layton2846d382008-09-22 21:33:33 -04001313 /* couldn't find useable FH with same pid, try any available */
1314 if (!any_available) {
1315 any_available = true;
1316 goto refind_writable;
1317 }
Steve French6148a742005-10-05 12:23:19 -07001318 read_unlock(&GlobalSMBSeslock);
1319 return NULL;
1320}
1321
Linus Torvalds1da177e2005-04-16 15:20:36 -07001322static int cifs_partialpagewrite(struct page *page, unsigned from, unsigned to)
1323{
1324 struct address_space *mapping = page->mapping;
1325 loff_t offset = (loff_t)page->index << PAGE_CACHE_SHIFT;
1326 char *write_data;
1327 int rc = -EFAULT;
1328 int bytes_written = 0;
1329 struct cifs_sb_info *cifs_sb;
1330 struct cifsTconInfo *pTcon;
1331 struct inode *inode;
Steve French6148a742005-10-05 12:23:19 -07001332 struct cifsFileInfo *open_file;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001333
1334 if (!mapping || !mapping->host)
1335 return -EFAULT;
1336
1337 inode = page->mapping->host;
1338 cifs_sb = CIFS_SB(inode->i_sb);
1339 pTcon = cifs_sb->tcon;
1340
1341 offset += (loff_t)from;
1342 write_data = kmap(page);
1343 write_data += from;
1344
1345 if ((to > PAGE_CACHE_SIZE) || (from > to)) {
1346 kunmap(page);
1347 return -EIO;
1348 }
1349
1350 /* racing with truncate? */
1351 if (offset > mapping->host->i_size) {
1352 kunmap(page);
1353 return 0; /* don't care */
1354 }
1355
1356 /* check to make sure that we are not extending the file */
1357 if (mapping->host->i_size - offset < (loff_t)to)
Steve Frenchfb8c4b12007-07-10 01:16:18 +00001358 to = (unsigned)(mapping->host->i_size - offset);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001359
Steve French6148a742005-10-05 12:23:19 -07001360 open_file = find_writable_file(CIFS_I(mapping->host));
1361 if (open_file) {
1362 bytes_written = cifs_write(open_file->pfile, write_data,
1363 to-from, &offset);
Steve French23e7dd72005-10-20 13:44:56 -07001364 atomic_dec(&open_file->wrtPending);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001365 /* Does mm or vfs already set times? */
Steve French6148a742005-10-05 12:23:19 -07001366 inode->i_atime = inode->i_mtime = current_fs_time(inode->i_sb);
Steve Frenchbb5a9a02007-12-31 04:21:29 +00001367 if ((bytes_written > 0) && (offset))
Steve French6148a742005-10-05 12:23:19 -07001368 rc = 0;
Steve Frenchbb5a9a02007-12-31 04:21:29 +00001369 else if (bytes_written < 0)
1370 rc = bytes_written;
Steve French6148a742005-10-05 12:23:19 -07001371 } else {
Linus Torvalds1da177e2005-04-16 15:20:36 -07001372 cFYI(1, ("No writeable filehandles for inode"));
1373 rc = -EIO;
1374 }
1375
1376 kunmap(page);
1377 return rc;
1378}
1379
Linus Torvalds1da177e2005-04-16 15:20:36 -07001380static int cifs_writepages(struct address_space *mapping,
Steve French37c0eb42005-10-05 14:50:29 -07001381 struct writeback_control *wbc)
Linus Torvalds1da177e2005-04-16 15:20:36 -07001382{
Steve French37c0eb42005-10-05 14:50:29 -07001383 struct backing_dev_info *bdi = mapping->backing_dev_info;
1384 unsigned int bytes_to_write;
1385 unsigned int bytes_written;
1386 struct cifs_sb_info *cifs_sb;
1387 int done = 0;
OGAWA Hirofumi111ebb62006-06-23 02:03:26 -07001388 pgoff_t end;
Steve French37c0eb42005-10-05 14:50:29 -07001389 pgoff_t index;
Steve Frenchfb8c4b12007-07-10 01:16:18 +00001390 int range_whole = 0;
1391 struct kvec *iov;
Steve French84d2f072005-10-12 15:32:05 -07001392 int len;
Steve French37c0eb42005-10-05 14:50:29 -07001393 int n_iov = 0;
1394 pgoff_t next;
1395 int nr_pages;
1396 __u64 offset = 0;
Steve French23e7dd72005-10-20 13:44:56 -07001397 struct cifsFileInfo *open_file;
Jeff Laytonfbec9ab2009-04-03 13:44:00 -04001398 struct cifsInodeInfo *cifsi = CIFS_I(mapping->host);
Steve French37c0eb42005-10-05 14:50:29 -07001399 struct page *page;
1400 struct pagevec pvec;
1401 int rc = 0;
1402 int scanned = 0;
Jeff Laytonfbec9ab2009-04-03 13:44:00 -04001403 int xid, long_op;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001404
Steve French37c0eb42005-10-05 14:50:29 -07001405 cifs_sb = CIFS_SB(mapping->host->i_sb);
Steve French50c2f752007-07-13 00:33:32 +00001406
Steve French37c0eb42005-10-05 14:50:29 -07001407 /*
1408 * If wsize is smaller that the page cache size, default to writing
1409 * one page at a time via cifs_writepage
1410 */
1411 if (cifs_sb->wsize < PAGE_CACHE_SIZE)
1412 return generic_writepages(mapping, wbc);
1413
Steve Frenchfb8c4b12007-07-10 01:16:18 +00001414 if ((cifs_sb->tcon->ses) && (cifs_sb->tcon->ses->server))
1415 if (cifs_sb->tcon->ses->server->secMode &
1416 (SECMODE_SIGN_REQUIRED | SECMODE_SIGN_ENABLED))
1417 if (!experimEnabled)
Steve French60808232006-04-22 15:53:05 +00001418 return generic_writepages(mapping, wbc);
Steve French4a771182005-10-05 15:14:33 -07001419
Steve French9a0c8232007-02-02 04:21:57 +00001420 iov = kmalloc(32 * sizeof(struct kvec), GFP_KERNEL);
Steve Frenchfb8c4b12007-07-10 01:16:18 +00001421 if (iov == NULL)
Steve French9a0c8232007-02-02 04:21:57 +00001422 return generic_writepages(mapping, wbc);
1423
1424
Steve French37c0eb42005-10-05 14:50:29 -07001425 /*
1426 * BB: Is this meaningful for a non-block-device file system?
1427 * If it is, we should test it again after we do I/O
1428 */
1429 if (wbc->nonblocking && bdi_write_congested(bdi)) {
1430 wbc->encountered_congestion = 1;
Steve French9a0c8232007-02-02 04:21:57 +00001431 kfree(iov);
Steve French37c0eb42005-10-05 14:50:29 -07001432 return 0;
1433 }
1434
Linus Torvalds1da177e2005-04-16 15:20:36 -07001435 xid = GetXid();
1436
Steve French37c0eb42005-10-05 14:50:29 -07001437 pagevec_init(&pvec, 0);
OGAWA Hirofumi111ebb62006-06-23 02:03:26 -07001438 if (wbc->range_cyclic) {
Steve French37c0eb42005-10-05 14:50:29 -07001439 index = mapping->writeback_index; /* Start from prev offset */
OGAWA Hirofumi111ebb62006-06-23 02:03:26 -07001440 end = -1;
1441 } else {
1442 index = wbc->range_start >> PAGE_CACHE_SHIFT;
1443 end = wbc->range_end >> PAGE_CACHE_SHIFT;
1444 if (wbc->range_start == 0 && wbc->range_end == LLONG_MAX)
1445 range_whole = 1;
Steve French37c0eb42005-10-05 14:50:29 -07001446 scanned = 1;
1447 }
1448retry:
1449 while (!done && (index <= end) &&
1450 (nr_pages = pagevec_lookup_tag(&pvec, mapping, &index,
1451 PAGECACHE_TAG_DIRTY,
1452 min(end - index, (pgoff_t)PAGEVEC_SIZE - 1) + 1))) {
1453 int first;
1454 unsigned int i;
1455
Steve French37c0eb42005-10-05 14:50:29 -07001456 first = -1;
1457 next = 0;
1458 n_iov = 0;
1459 bytes_to_write = 0;
1460
1461 for (i = 0; i < nr_pages; i++) {
1462 page = pvec.pages[i];
1463 /*
1464 * At this point we hold neither mapping->tree_lock nor
1465 * lock on the page itself: the page may be truncated or
1466 * invalidated (changing page->mapping to NULL), or even
1467 * swizzled back from swapper_space to tmpfs file
1468 * mapping
1469 */
1470
1471 if (first < 0)
1472 lock_page(page);
Nick Piggin529ae9a2008-08-02 12:01:03 +02001473 else if (!trylock_page(page))
Steve French37c0eb42005-10-05 14:50:29 -07001474 break;
1475
1476 if (unlikely(page->mapping != mapping)) {
1477 unlock_page(page);
1478 break;
1479 }
1480
OGAWA Hirofumi111ebb62006-06-23 02:03:26 -07001481 if (!wbc->range_cyclic && page->index > end) {
Steve French37c0eb42005-10-05 14:50:29 -07001482 done = 1;
1483 unlock_page(page);
1484 break;
1485 }
1486
1487 if (next && (page->index != next)) {
1488 /* Not next consecutive page */
1489 unlock_page(page);
1490 break;
1491 }
1492
1493 if (wbc->sync_mode != WB_SYNC_NONE)
1494 wait_on_page_writeback(page);
1495
1496 if (PageWriteback(page) ||
Linus Torvaldscb876f42006-12-23 16:19:07 -08001497 !clear_page_dirty_for_io(page)) {
Steve French37c0eb42005-10-05 14:50:29 -07001498 unlock_page(page);
1499 break;
1500 }
Steve French84d2f072005-10-12 15:32:05 -07001501
Linus Torvaldscb876f42006-12-23 16:19:07 -08001502 /*
1503 * This actually clears the dirty bit in the radix tree.
1504 * See cifs_writepage() for more commentary.
1505 */
1506 set_page_writeback(page);
1507
Steve French84d2f072005-10-12 15:32:05 -07001508 if (page_offset(page) >= mapping->host->i_size) {
1509 done = 1;
1510 unlock_page(page);
Linus Torvaldscb876f42006-12-23 16:19:07 -08001511 end_page_writeback(page);
Steve French84d2f072005-10-12 15:32:05 -07001512 break;
1513 }
1514
Steve French37c0eb42005-10-05 14:50:29 -07001515 /*
1516 * BB can we get rid of this? pages are held by pvec
1517 */
1518 page_cache_get(page);
1519
Steve French84d2f072005-10-12 15:32:05 -07001520 len = min(mapping->host->i_size - page_offset(page),
1521 (loff_t)PAGE_CACHE_SIZE);
1522
Steve French37c0eb42005-10-05 14:50:29 -07001523 /* reserve iov[0] for the smb header */
1524 n_iov++;
1525 iov[n_iov].iov_base = kmap(page);
Steve French84d2f072005-10-12 15:32:05 -07001526 iov[n_iov].iov_len = len;
1527 bytes_to_write += len;
Steve French37c0eb42005-10-05 14:50:29 -07001528
1529 if (first < 0) {
1530 first = i;
1531 offset = page_offset(page);
1532 }
1533 next = page->index + 1;
1534 if (bytes_to_write + PAGE_CACHE_SIZE > cifs_sb->wsize)
1535 break;
1536 }
1537 if (n_iov) {
Steve French23e7dd72005-10-20 13:44:56 -07001538 /* Search for a writable handle every time we call
1539 * CIFSSMBWrite2. We can't rely on the last handle
1540 * we used to still be valid
1541 */
1542 open_file = find_writable_file(CIFS_I(mapping->host));
1543 if (!open_file) {
1544 cERROR(1, ("No writable handles for inode"));
1545 rc = -EBADF;
Steve French1047abc2005-10-11 19:58:06 -07001546 } else {
Jeff Laytonfbec9ab2009-04-03 13:44:00 -04001547 long_op = cifs_write_timeout(cifsi, offset);
Steve French23e7dd72005-10-20 13:44:56 -07001548 rc = CIFSSMBWrite2(xid, cifs_sb->tcon,
1549 open_file->netfid,
1550 bytes_to_write, offset,
1551 &bytes_written, iov, n_iov,
Jeff Laytonfbec9ab2009-04-03 13:44:00 -04001552 long_op);
Steve French23e7dd72005-10-20 13:44:56 -07001553 atomic_dec(&open_file->wrtPending);
Jeff Laytonfbec9ab2009-04-03 13:44:00 -04001554 cifs_update_eof(cifsi, offset, bytes_written);
1555
Steve French23e7dd72005-10-20 13:44:56 -07001556 if (rc || bytes_written < bytes_to_write) {
Steve French63135e02007-07-17 17:34:02 +00001557 cERROR(1, ("Write2 ret %d, wrote %d",
Steve French23e7dd72005-10-20 13:44:56 -07001558 rc, bytes_written));
1559 /* BB what if continued retry is
1560 requested via mount flags? */
Jeff Laytoncea21802007-11-20 23:19:03 +00001561 if (rc == -ENOSPC)
1562 set_bit(AS_ENOSPC, &mapping->flags);
1563 else
1564 set_bit(AS_EIO, &mapping->flags);
Steve French23e7dd72005-10-20 13:44:56 -07001565 } else {
1566 cifs_stats_bytes_written(cifs_sb->tcon,
1567 bytes_written);
1568 }
Steve French37c0eb42005-10-05 14:50:29 -07001569 }
1570 for (i = 0; i < n_iov; i++) {
1571 page = pvec.pages[first + i];
Steve Frencheb9bdaa2006-01-27 15:11:47 -08001572 /* Should we also set page error on
1573 success rc but too little data written? */
1574 /* BB investigate retry logic on temporary
1575 server crash cases and how recovery works
Steve Frenchfb8c4b12007-07-10 01:16:18 +00001576 when page marked as error */
1577 if (rc)
Steve Frencheb9bdaa2006-01-27 15:11:47 -08001578 SetPageError(page);
Steve French37c0eb42005-10-05 14:50:29 -07001579 kunmap(page);
1580 unlock_page(page);
Linus Torvaldscb876f42006-12-23 16:19:07 -08001581 end_page_writeback(page);
Steve French37c0eb42005-10-05 14:50:29 -07001582 page_cache_release(page);
1583 }
1584 if ((wbc->nr_to_write -= n_iov) <= 0)
1585 done = 1;
1586 index = next;
Dave Kleikampb066a482008-11-18 03:49:05 +00001587 } else
1588 /* Need to re-find the pages we skipped */
1589 index = pvec.pages[0]->index + 1;
1590
Steve French37c0eb42005-10-05 14:50:29 -07001591 pagevec_release(&pvec);
1592 }
1593 if (!scanned && !done) {
1594 /*
1595 * We hit the last page and there is more work to be done: wrap
1596 * back to the start of the file
1597 */
1598 scanned = 1;
1599 index = 0;
1600 goto retry;
1601 }
OGAWA Hirofumi111ebb62006-06-23 02:03:26 -07001602 if (wbc->range_cyclic || (range_whole && wbc->nr_to_write > 0))
Steve French37c0eb42005-10-05 14:50:29 -07001603 mapping->writeback_index = index;
1604
Linus Torvalds1da177e2005-04-16 15:20:36 -07001605 FreeXid(xid);
Steve French9a0c8232007-02-02 04:21:57 +00001606 kfree(iov);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001607 return rc;
1608}
Linus Torvalds1da177e2005-04-16 15:20:36 -07001609
Steve Frenchfb8c4b12007-07-10 01:16:18 +00001610static int cifs_writepage(struct page *page, struct writeback_control *wbc)
Linus Torvalds1da177e2005-04-16 15:20:36 -07001611{
1612 int rc = -EFAULT;
1613 int xid;
1614
1615 xid = GetXid();
1616/* BB add check for wbc flags */
1617 page_cache_get(page);
Steve Frenchad7a2922008-02-07 23:25:02 +00001618 if (!PageUptodate(page))
Linus Torvalds1da177e2005-04-16 15:20:36 -07001619 cFYI(1, ("ppw - page not up to date"));
Linus Torvaldscb876f42006-12-23 16:19:07 -08001620
1621 /*
1622 * Set the "writeback" flag, and clear "dirty" in the radix tree.
1623 *
1624 * A writepage() implementation always needs to do either this,
1625 * or re-dirty the page with "redirty_page_for_writepage()" in
1626 * the case of a failure.
1627 *
1628 * Just unlocking the page will cause the radix tree tag-bits
1629 * to fail to update with the state of the page correctly.
1630 */
Steve Frenchfb8c4b12007-07-10 01:16:18 +00001631 set_page_writeback(page);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001632 rc = cifs_partialpagewrite(page, 0, PAGE_CACHE_SIZE);
1633 SetPageUptodate(page); /* BB add check for error and Clearuptodate? */
1634 unlock_page(page);
Linus Torvaldscb876f42006-12-23 16:19:07 -08001635 end_page_writeback(page);
1636 page_cache_release(page);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001637 FreeXid(xid);
1638 return rc;
1639}
1640
Nick Piggind9414772008-09-24 11:32:59 -04001641static int cifs_write_end(struct file *file, struct address_space *mapping,
1642 loff_t pos, unsigned len, unsigned copied,
1643 struct page *page, void *fsdata)
Linus Torvalds1da177e2005-04-16 15:20:36 -07001644{
Nick Piggind9414772008-09-24 11:32:59 -04001645 int rc;
1646 struct inode *inode = mapping->host;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001647
Nick Piggind9414772008-09-24 11:32:59 -04001648 cFYI(1, ("write_end for page %p from pos %lld with %d bytes",
1649 page, pos, copied));
Steve Frenchad7a2922008-02-07 23:25:02 +00001650
Jeff Laytona98ee8c2008-11-26 19:32:33 +00001651 if (PageChecked(page)) {
1652 if (copied == len)
1653 SetPageUptodate(page);
1654 ClearPageChecked(page);
1655 } else if (!PageUptodate(page) && copied == PAGE_CACHE_SIZE)
Nick Piggind9414772008-09-24 11:32:59 -04001656 SetPageUptodate(page);
1657
Linus Torvalds1da177e2005-04-16 15:20:36 -07001658 if (!PageUptodate(page)) {
Nick Piggind9414772008-09-24 11:32:59 -04001659 char *page_data;
1660 unsigned offset = pos & (PAGE_CACHE_SIZE - 1);
1661 int xid;
1662
1663 xid = GetXid();
Linus Torvalds1da177e2005-04-16 15:20:36 -07001664 /* this is probably better than directly calling
1665 partialpage_write since in this function the file handle is
1666 known which we might as well leverage */
1667 /* BB check if anything else missing out of ppw
1668 such as updating last write time */
1669 page_data = kmap(page);
Nick Piggind9414772008-09-24 11:32:59 -04001670 rc = cifs_write(file, page_data + offset, copied, &pos);
1671 /* if (rc < 0) should we set writebehind rc? */
Linus Torvalds1da177e2005-04-16 15:20:36 -07001672 kunmap(page);
Nick Piggind9414772008-09-24 11:32:59 -04001673
1674 FreeXid(xid);
Steve Frenchfb8c4b12007-07-10 01:16:18 +00001675 } else {
Nick Piggind9414772008-09-24 11:32:59 -04001676 rc = copied;
1677 pos += copied;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001678 set_page_dirty(page);
1679 }
1680
Nick Piggind9414772008-09-24 11:32:59 -04001681 if (rc > 0) {
1682 spin_lock(&inode->i_lock);
1683 if (pos > inode->i_size)
1684 i_size_write(inode, pos);
1685 spin_unlock(&inode->i_lock);
1686 }
1687
1688 unlock_page(page);
1689 page_cache_release(page);
1690
Linus Torvalds1da177e2005-04-16 15:20:36 -07001691 return rc;
1692}
1693
1694int cifs_fsync(struct file *file, struct dentry *dentry, int datasync)
1695{
1696 int xid;
1697 int rc = 0;
Steve Frenchb298f222009-02-21 21:17:43 +00001698 struct cifsTconInfo *tcon;
1699 struct cifsFileInfo *smbfile =
1700 (struct cifsFileInfo *)file->private_data;
Josef "Jeff" Sipeke6a00292006-12-08 02:36:48 -08001701 struct inode *inode = file->f_path.dentry->d_inode;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001702
1703 xid = GetXid();
1704
Steve Frenchfb8c4b12007-07-10 01:16:18 +00001705 cFYI(1, ("Sync file - name: %s datasync: 0x%x",
Linus Torvalds1da177e2005-04-16 15:20:36 -07001706 dentry->d_name.name, datasync));
Steve French50c2f752007-07-13 00:33:32 +00001707
Jeff Laytoncea21802007-11-20 23:19:03 +00001708 rc = filemap_write_and_wait(inode->i_mapping);
1709 if (rc == 0) {
1710 rc = CIFS_I(inode)->write_behind_rc;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001711 CIFS_I(inode)->write_behind_rc = 0;
Steve Frenchb298f222009-02-21 21:17:43 +00001712 tcon = CIFS_SB(inode->i_sb)->tcon;
Steve Frenchbe652442009-02-23 15:21:59 +00001713 if (!rc && tcon && smbfile &&
Steve French4717bed2009-02-24 14:44:19 +00001714 !(CIFS_SB(inode->i_sb)->mnt_cifs_flags & CIFS_MOUNT_NOSSYNC))
Steve Frenchb298f222009-02-21 21:17:43 +00001715 rc = CIFSSMBFlush(xid, tcon, smbfile->netfid);
Jeff Laytoncea21802007-11-20 23:19:03 +00001716 }
Steve Frenchb298f222009-02-21 21:17:43 +00001717
Linus Torvalds1da177e2005-04-16 15:20:36 -07001718 FreeXid(xid);
1719 return rc;
1720}
1721
NeilBrown3978d7172006-03-26 01:37:17 -08001722/* static void cifs_sync_page(struct page *page)
Linus Torvalds1da177e2005-04-16 15:20:36 -07001723{
1724 struct address_space *mapping;
1725 struct inode *inode;
1726 unsigned long index = page->index;
1727 unsigned int rpages = 0;
1728 int rc = 0;
1729
1730 cFYI(1, ("sync page %p",page));
1731 mapping = page->mapping;
1732 if (!mapping)
1733 return 0;
1734 inode = mapping->host;
1735 if (!inode)
NeilBrown3978d7172006-03-26 01:37:17 -08001736 return; */
Linus Torvalds1da177e2005-04-16 15:20:36 -07001737
Steve Frenchfb8c4b12007-07-10 01:16:18 +00001738/* fill in rpages then
Linus Torvalds1da177e2005-04-16 15:20:36 -07001739 result = cifs_pagein_inode(inode, index, rpages); */ /* BB finish */
1740
Steve French26a21b92006-05-31 18:05:34 +00001741/* cFYI(1, ("rpages is %d for sync page of Index %ld", rpages, index));
Linus Torvalds1da177e2005-04-16 15:20:36 -07001742
NeilBrown3978d7172006-03-26 01:37:17 -08001743#if 0
Linus Torvalds1da177e2005-04-16 15:20:36 -07001744 if (rc < 0)
1745 return rc;
1746 return 0;
NeilBrown3978d7172006-03-26 01:37:17 -08001747#endif
Linus Torvalds1da177e2005-04-16 15:20:36 -07001748} */
1749
1750/*
1751 * As file closes, flush all cached write data for this inode checking
1752 * for write behind errors.
1753 */
Miklos Szeredi75e1fcc2006-06-23 02:05:12 -07001754int cifs_flush(struct file *file, fl_owner_t id)
Linus Torvalds1da177e2005-04-16 15:20:36 -07001755{
Steve Frenchfb8c4b12007-07-10 01:16:18 +00001756 struct inode *inode = file->f_path.dentry->d_inode;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001757 int rc = 0;
1758
1759 /* Rather than do the steps manually:
1760 lock the inode for writing
1761 loop through pages looking for write behind data (dirty pages)
1762 coalesce into contiguous 16K (or smaller) chunks to write to server
1763 send to server (prefer in parallel)
1764 deal with writebehind errors
1765 unlock inode for writing
1766 filemapfdatawrite appears easier for the time being */
1767
1768 rc = filemap_fdatawrite(inode->i_mapping);
Jeff Laytoncea21802007-11-20 23:19:03 +00001769 /* reset wb rc if we were able to write out dirty pages */
1770 if (!rc) {
1771 rc = CIFS_I(inode)->write_behind_rc;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001772 CIFS_I(inode)->write_behind_rc = 0;
Jeff Laytoncea21802007-11-20 23:19:03 +00001773 }
Steve French50c2f752007-07-13 00:33:32 +00001774
Steve Frenchfb8c4b12007-07-10 01:16:18 +00001775 cFYI(1, ("Flush inode %p file %p rc %d", inode, file, rc));
Linus Torvalds1da177e2005-04-16 15:20:36 -07001776
1777 return rc;
1778}
1779
1780ssize_t cifs_user_read(struct file *file, char __user *read_data,
1781 size_t read_size, loff_t *poffset)
1782{
1783 int rc = -EACCES;
1784 unsigned int bytes_read = 0;
1785 unsigned int total_read = 0;
1786 unsigned int current_read_size;
1787 struct cifs_sb_info *cifs_sb;
1788 struct cifsTconInfo *pTcon;
1789 int xid;
1790 struct cifsFileInfo *open_file;
1791 char *smb_read_data;
1792 char __user *current_offset;
1793 struct smb_com_read_rsp *pSMBr;
1794
1795 xid = GetXid();
Josef "Jeff" Sipeke6a00292006-12-08 02:36:48 -08001796 cifs_sb = CIFS_SB(file->f_path.dentry->d_sb);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001797 pTcon = cifs_sb->tcon;
1798
1799 if (file->private_data == NULL) {
1800 FreeXid(xid);
1801 return -EBADF;
1802 }
1803 open_file = (struct cifsFileInfo *)file->private_data;
1804
Steve Frenchad7a2922008-02-07 23:25:02 +00001805 if ((file->f_flags & O_ACCMODE) == O_WRONLY)
Linus Torvalds1da177e2005-04-16 15:20:36 -07001806 cFYI(1, ("attempting read on write only file instance"));
Steve Frenchad7a2922008-02-07 23:25:02 +00001807
Linus Torvalds1da177e2005-04-16 15:20:36 -07001808 for (total_read = 0, current_offset = read_data;
1809 read_size > total_read;
1810 total_read += bytes_read, current_offset += bytes_read) {
Steve Frenchfb8c4b12007-07-10 01:16:18 +00001811 current_read_size = min_t(const int, read_size - total_read,
Linus Torvalds1da177e2005-04-16 15:20:36 -07001812 cifs_sb->rsize);
1813 rc = -EAGAIN;
1814 smb_read_data = NULL;
1815 while (rc == -EAGAIN) {
Steve Frenchec637e32005-12-12 20:53:18 -08001816 int buf_type = CIFS_NO_BUFFER;
Steve Frenchfb8c4b12007-07-10 01:16:18 +00001817 if ((open_file->invalidHandle) &&
Linus Torvalds1da177e2005-04-16 15:20:36 -07001818 (!open_file->closePend)) {
Steve French4b18f2a2008-04-29 00:06:05 +00001819 rc = cifs_reopen_file(file, true);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001820 if (rc != 0)
1821 break;
1822 }
Steve Frenchbfa0d752005-08-31 21:50:37 -07001823 rc = CIFSSMBRead(xid, pTcon,
Steve Frenchec637e32005-12-12 20:53:18 -08001824 open_file->netfid,
1825 current_read_size, *poffset,
1826 &bytes_read, &smb_read_data,
1827 &buf_type);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001828 pSMBr = (struct smb_com_read_rsp *)smb_read_data;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001829 if (smb_read_data) {
Steve French93544cc2006-02-14 22:30:52 -06001830 if (copy_to_user(current_offset,
1831 smb_read_data +
1832 4 /* RFC1001 length field */ +
1833 le16_to_cpu(pSMBr->DataOffset),
Steve Frenchad7a2922008-02-07 23:25:02 +00001834 bytes_read))
Steve French93544cc2006-02-14 22:30:52 -06001835 rc = -EFAULT;
Steve French93544cc2006-02-14 22:30:52 -06001836
Steve Frenchfb8c4b12007-07-10 01:16:18 +00001837 if (buf_type == CIFS_SMALL_BUFFER)
Steve Frenchec637e32005-12-12 20:53:18 -08001838 cifs_small_buf_release(smb_read_data);
Steve Frenchfb8c4b12007-07-10 01:16:18 +00001839 else if (buf_type == CIFS_LARGE_BUFFER)
Steve Frenchec637e32005-12-12 20:53:18 -08001840 cifs_buf_release(smb_read_data);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001841 smb_read_data = NULL;
1842 }
1843 }
1844 if (rc || (bytes_read == 0)) {
1845 if (total_read) {
1846 break;
1847 } else {
1848 FreeXid(xid);
1849 return rc;
1850 }
1851 } else {
Steve Frencha4544342005-08-24 13:59:35 -07001852 cifs_stats_bytes_read(pTcon, bytes_read);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001853 *poffset += bytes_read;
1854 }
1855 }
1856 FreeXid(xid);
1857 return total_read;
1858}
1859
1860
1861static ssize_t cifs_read(struct file *file, char *read_data, size_t read_size,
1862 loff_t *poffset)
1863{
1864 int rc = -EACCES;
1865 unsigned int bytes_read = 0;
1866 unsigned int total_read;
1867 unsigned int current_read_size;
1868 struct cifs_sb_info *cifs_sb;
1869 struct cifsTconInfo *pTcon;
1870 int xid;
1871 char *current_offset;
1872 struct cifsFileInfo *open_file;
Steve Frenchec637e32005-12-12 20:53:18 -08001873 int buf_type = CIFS_NO_BUFFER;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001874
1875 xid = GetXid();
Josef "Jeff" Sipeke6a00292006-12-08 02:36:48 -08001876 cifs_sb = CIFS_SB(file->f_path.dentry->d_sb);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001877 pTcon = cifs_sb->tcon;
1878
1879 if (file->private_data == NULL) {
1880 FreeXid(xid);
1881 return -EBADF;
1882 }
1883 open_file = (struct cifsFileInfo *)file->private_data;
1884
1885 if ((file->f_flags & O_ACCMODE) == O_WRONLY)
1886 cFYI(1, ("attempting read on write only file instance"));
1887
Steve Frenchfb8c4b12007-07-10 01:16:18 +00001888 for (total_read = 0, current_offset = read_data;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001889 read_size > total_read;
1890 total_read += bytes_read, current_offset += bytes_read) {
1891 current_read_size = min_t(const int, read_size - total_read,
1892 cifs_sb->rsize);
Steve Frenchf9f5c8172005-09-15 23:06:38 -07001893 /* For windows me and 9x we do not want to request more
1894 than it negotiated since it will refuse the read then */
Steve Frenchfb8c4b12007-07-10 01:16:18 +00001895 if ((pTcon->ses) &&
Steve Frenchf9f5c8172005-09-15 23:06:38 -07001896 !(pTcon->ses->capabilities & CAP_LARGE_FILES)) {
1897 current_read_size = min_t(const int, current_read_size,
1898 pTcon->ses->server->maxBuf - 128);
1899 }
Linus Torvalds1da177e2005-04-16 15:20:36 -07001900 rc = -EAGAIN;
1901 while (rc == -EAGAIN) {
Steve Frenchfb8c4b12007-07-10 01:16:18 +00001902 if ((open_file->invalidHandle) &&
Linus Torvalds1da177e2005-04-16 15:20:36 -07001903 (!open_file->closePend)) {
Steve French4b18f2a2008-04-29 00:06:05 +00001904 rc = cifs_reopen_file(file, true);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001905 if (rc != 0)
1906 break;
1907 }
Steve Frenchbfa0d752005-08-31 21:50:37 -07001908 rc = CIFSSMBRead(xid, pTcon,
Steve Frenchec637e32005-12-12 20:53:18 -08001909 open_file->netfid,
1910 current_read_size, *poffset,
1911 &bytes_read, &current_offset,
1912 &buf_type);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001913 }
1914 if (rc || (bytes_read == 0)) {
1915 if (total_read) {
1916 break;
1917 } else {
1918 FreeXid(xid);
1919 return rc;
1920 }
1921 } else {
Steve Frencha4544342005-08-24 13:59:35 -07001922 cifs_stats_bytes_read(pTcon, total_read);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001923 *poffset += bytes_read;
1924 }
1925 }
1926 FreeXid(xid);
1927 return total_read;
1928}
1929
1930int cifs_file_mmap(struct file *file, struct vm_area_struct *vma)
1931{
Josef "Jeff" Sipeke6a00292006-12-08 02:36:48 -08001932 struct dentry *dentry = file->f_path.dentry;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001933 int rc, xid;
1934
1935 xid = GetXid();
1936 rc = cifs_revalidate(dentry);
1937 if (rc) {
1938 cFYI(1, ("Validation prior to mmap failed, error=%d", rc));
1939 FreeXid(xid);
1940 return rc;
1941 }
1942 rc = generic_file_mmap(file, vma);
1943 FreeXid(xid);
1944 return rc;
1945}
1946
1947
Steve Frenchfb8c4b12007-07-10 01:16:18 +00001948static void cifs_copy_cache_pages(struct address_space *mapping,
Linus Torvalds1da177e2005-04-16 15:20:36 -07001949 struct list_head *pages, int bytes_read, char *data,
1950 struct pagevec *plru_pvec)
1951{
1952 struct page *page;
1953 char *target;
1954
1955 while (bytes_read > 0) {
1956 if (list_empty(pages))
1957 break;
1958
1959 page = list_entry(pages->prev, struct page, lru);
1960 list_del(&page->lru);
1961
1962 if (add_to_page_cache(page, mapping, page->index,
1963 GFP_KERNEL)) {
1964 page_cache_release(page);
1965 cFYI(1, ("Add page cache failed"));
Steve French3079ca62005-06-09 14:44:07 -07001966 data += PAGE_CACHE_SIZE;
1967 bytes_read -= PAGE_CACHE_SIZE;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001968 continue;
1969 }
1970
Steve Frenchfb8c4b12007-07-10 01:16:18 +00001971 target = kmap_atomic(page, KM_USER0);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001972
1973 if (PAGE_CACHE_SIZE > bytes_read) {
1974 memcpy(target, data, bytes_read);
1975 /* zero the tail end of this partial page */
Steve Frenchfb8c4b12007-07-10 01:16:18 +00001976 memset(target + bytes_read, 0,
Linus Torvalds1da177e2005-04-16 15:20:36 -07001977 PAGE_CACHE_SIZE - bytes_read);
1978 bytes_read = 0;
1979 } else {
1980 memcpy(target, data, PAGE_CACHE_SIZE);
1981 bytes_read -= PAGE_CACHE_SIZE;
1982 }
1983 kunmap_atomic(target, KM_USER0);
1984
1985 flush_dcache_page(page);
1986 SetPageUptodate(page);
1987 unlock_page(page);
1988 if (!pagevec_add(plru_pvec, page))
Rik van Riel4f98a2f2008-10-18 20:26:32 -07001989 __pagevec_lru_add_file(plru_pvec);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001990 data += PAGE_CACHE_SIZE;
1991 }
1992 return;
1993}
1994
1995static int cifs_readpages(struct file *file, struct address_space *mapping,
1996 struct list_head *page_list, unsigned num_pages)
1997{
1998 int rc = -EACCES;
1999 int xid;
2000 loff_t offset;
2001 struct page *page;
2002 struct cifs_sb_info *cifs_sb;
2003 struct cifsTconInfo *pTcon;
Steve French2c2130e2007-10-12 19:10:28 +00002004 unsigned int bytes_read = 0;
Steve Frenchfb8c4b12007-07-10 01:16:18 +00002005 unsigned int read_size, i;
Linus Torvalds1da177e2005-04-16 15:20:36 -07002006 char *smb_read_data = NULL;
2007 struct smb_com_read_rsp *pSMBr;
2008 struct pagevec lru_pvec;
2009 struct cifsFileInfo *open_file;
Steve Frenchec637e32005-12-12 20:53:18 -08002010 int buf_type = CIFS_NO_BUFFER;
Linus Torvalds1da177e2005-04-16 15:20:36 -07002011
2012 xid = GetXid();
2013 if (file->private_data == NULL) {
2014 FreeXid(xid);
2015 return -EBADF;
2016 }
2017 open_file = (struct cifsFileInfo *)file->private_data;
Josef "Jeff" Sipeke6a00292006-12-08 02:36:48 -08002018 cifs_sb = CIFS_SB(file->f_path.dentry->d_sb);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002019 pTcon = cifs_sb->tcon;
Steve Frenchbfa0d752005-08-31 21:50:37 -07002020
Linus Torvalds1da177e2005-04-16 15:20:36 -07002021 pagevec_init(&lru_pvec, 0);
Steve French61de8002008-10-30 20:15:22 +00002022 cFYI(DBG2, ("rpages: num pages %d", num_pages));
Linus Torvalds1da177e2005-04-16 15:20:36 -07002023 for (i = 0; i < num_pages; ) {
2024 unsigned contig_pages;
2025 struct page *tmp_page;
2026 unsigned long expected_index;
2027
2028 if (list_empty(page_list))
2029 break;
2030
2031 page = list_entry(page_list->prev, struct page, lru);
2032 offset = (loff_t)page->index << PAGE_CACHE_SHIFT;
2033
2034 /* count adjacent pages that we will read into */
2035 contig_pages = 0;
Steve Frenchfb8c4b12007-07-10 01:16:18 +00002036 expected_index =
Linus Torvalds1da177e2005-04-16 15:20:36 -07002037 list_entry(page_list->prev, struct page, lru)->index;
Steve Frenchfb8c4b12007-07-10 01:16:18 +00002038 list_for_each_entry_reverse(tmp_page, page_list, lru) {
Linus Torvalds1da177e2005-04-16 15:20:36 -07002039 if (tmp_page->index == expected_index) {
2040 contig_pages++;
2041 expected_index++;
2042 } else
Steve Frenchfb8c4b12007-07-10 01:16:18 +00002043 break;
Linus Torvalds1da177e2005-04-16 15:20:36 -07002044 }
2045 if (contig_pages + i > num_pages)
2046 contig_pages = num_pages - i;
2047
2048 /* for reads over a certain size could initiate async
2049 read ahead */
2050
2051 read_size = contig_pages * PAGE_CACHE_SIZE;
2052 /* Read size needs to be in multiples of one page */
2053 read_size = min_t(const unsigned int, read_size,
2054 cifs_sb->rsize & PAGE_CACHE_MASK);
Steve French90c81e02008-02-12 20:32:36 +00002055 cFYI(DBG2, ("rpages: read size 0x%x contiguous pages %d",
Steve French75865f8c2007-06-24 18:30:48 +00002056 read_size, contig_pages));
Linus Torvalds1da177e2005-04-16 15:20:36 -07002057 rc = -EAGAIN;
2058 while (rc == -EAGAIN) {
Steve Frenchfb8c4b12007-07-10 01:16:18 +00002059 if ((open_file->invalidHandle) &&
Linus Torvalds1da177e2005-04-16 15:20:36 -07002060 (!open_file->closePend)) {
Steve French4b18f2a2008-04-29 00:06:05 +00002061 rc = cifs_reopen_file(file, true);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002062 if (rc != 0)
2063 break;
2064 }
2065
Steve Frenchbfa0d752005-08-31 21:50:37 -07002066 rc = CIFSSMBRead(xid, pTcon,
Steve Frenchec637e32005-12-12 20:53:18 -08002067 open_file->netfid,
2068 read_size, offset,
2069 &bytes_read, &smb_read_data,
2070 &buf_type);
Steve Frencha9d02ad2005-08-24 23:06:05 -07002071 /* BB more RC checks ? */
Steve Frenchfb8c4b12007-07-10 01:16:18 +00002072 if (rc == -EAGAIN) {
Linus Torvalds1da177e2005-04-16 15:20:36 -07002073 if (smb_read_data) {
Steve Frenchfb8c4b12007-07-10 01:16:18 +00002074 if (buf_type == CIFS_SMALL_BUFFER)
Steve Frenchec637e32005-12-12 20:53:18 -08002075 cifs_small_buf_release(smb_read_data);
Steve Frenchfb8c4b12007-07-10 01:16:18 +00002076 else if (buf_type == CIFS_LARGE_BUFFER)
Steve Frenchec637e32005-12-12 20:53:18 -08002077 cifs_buf_release(smb_read_data);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002078 smb_read_data = NULL;
2079 }
2080 }
2081 }
2082 if ((rc < 0) || (smb_read_data == NULL)) {
2083 cFYI(1, ("Read error in readpages: %d", rc));
Linus Torvalds1da177e2005-04-16 15:20:36 -07002084 break;
2085 } else if (bytes_read > 0) {
Andrew Morton6f88cc22006-12-10 02:19:44 -08002086 task_io_account_read(bytes_read);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002087 pSMBr = (struct smb_com_read_rsp *)smb_read_data;
2088 cifs_copy_cache_pages(mapping, page_list, bytes_read,
2089 smb_read_data + 4 /* RFC1001 hdr */ +
2090 le16_to_cpu(pSMBr->DataOffset), &lru_pvec);
2091
2092 i += bytes_read >> PAGE_CACHE_SHIFT;
Steve Frencha4544342005-08-24 13:59:35 -07002093 cifs_stats_bytes_read(pTcon, bytes_read);
Steve French2c2130e2007-10-12 19:10:28 +00002094 if ((bytes_read & PAGE_CACHE_MASK) != bytes_read) {
Linus Torvalds1da177e2005-04-16 15:20:36 -07002095 i++; /* account for partial page */
2096
Steve Frenchfb8c4b12007-07-10 01:16:18 +00002097 /* server copy of file can have smaller size
Linus Torvalds1da177e2005-04-16 15:20:36 -07002098 than client */
Steve Frenchfb8c4b12007-07-10 01:16:18 +00002099 /* BB do we need to verify this common case ?
2100 this case is ok - if we are at server EOF
Linus Torvalds1da177e2005-04-16 15:20:36 -07002101 we will hit it on next read */
2102
OGAWA Hirofumi05ac9d42006-11-02 22:07:08 -08002103 /* break; */
Linus Torvalds1da177e2005-04-16 15:20:36 -07002104 }
2105 } else {
2106 cFYI(1, ("No bytes read (%d) at offset %lld . "
2107 "Cleaning remaining pages from readahead list",
2108 bytes_read, offset));
Steve Frenchfb8c4b12007-07-10 01:16:18 +00002109 /* BB turn off caching and do new lookup on
Linus Torvalds1da177e2005-04-16 15:20:36 -07002110 file size at server? */
Linus Torvalds1da177e2005-04-16 15:20:36 -07002111 break;
2112 }
2113 if (smb_read_data) {
Steve Frenchfb8c4b12007-07-10 01:16:18 +00002114 if (buf_type == CIFS_SMALL_BUFFER)
Steve Frenchec637e32005-12-12 20:53:18 -08002115 cifs_small_buf_release(smb_read_data);
Steve Frenchfb8c4b12007-07-10 01:16:18 +00002116 else if (buf_type == CIFS_LARGE_BUFFER)
Steve Frenchec637e32005-12-12 20:53:18 -08002117 cifs_buf_release(smb_read_data);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002118 smb_read_data = NULL;
2119 }
2120 bytes_read = 0;
2121 }
2122
Rik van Riel4f98a2f2008-10-18 20:26:32 -07002123 pagevec_lru_add_file(&lru_pvec);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002124
2125/* need to free smb_read_data buf before exit */
2126 if (smb_read_data) {
Steve Frenchfb8c4b12007-07-10 01:16:18 +00002127 if (buf_type == CIFS_SMALL_BUFFER)
Steve French47c886b2006-01-18 14:20:39 -08002128 cifs_small_buf_release(smb_read_data);
Steve Frenchfb8c4b12007-07-10 01:16:18 +00002129 else if (buf_type == CIFS_LARGE_BUFFER)
Steve French47c886b2006-01-18 14:20:39 -08002130 cifs_buf_release(smb_read_data);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002131 smb_read_data = NULL;
Steve Frenchfb8c4b12007-07-10 01:16:18 +00002132 }
Linus Torvalds1da177e2005-04-16 15:20:36 -07002133
2134 FreeXid(xid);
2135 return rc;
2136}
2137
2138static int cifs_readpage_worker(struct file *file, struct page *page,
2139 loff_t *poffset)
2140{
2141 char *read_data;
2142 int rc;
2143
2144 page_cache_get(page);
2145 read_data = kmap(page);
2146 /* for reads over a certain size could initiate async read ahead */
Steve Frenchfb8c4b12007-07-10 01:16:18 +00002147
Linus Torvalds1da177e2005-04-16 15:20:36 -07002148 rc = cifs_read(file, read_data, PAGE_CACHE_SIZE, poffset);
Steve Frenchfb8c4b12007-07-10 01:16:18 +00002149
Linus Torvalds1da177e2005-04-16 15:20:36 -07002150 if (rc < 0)
2151 goto io_error;
2152 else
Steve Frenchfb8c4b12007-07-10 01:16:18 +00002153 cFYI(1, ("Bytes read %d", rc));
2154
Josef "Jeff" Sipeke6a00292006-12-08 02:36:48 -08002155 file->f_path.dentry->d_inode->i_atime =
2156 current_fs_time(file->f_path.dentry->d_inode->i_sb);
Steve Frenchfb8c4b12007-07-10 01:16:18 +00002157
Linus Torvalds1da177e2005-04-16 15:20:36 -07002158 if (PAGE_CACHE_SIZE > rc)
2159 memset(read_data + rc, 0, PAGE_CACHE_SIZE - rc);
2160
2161 flush_dcache_page(page);
2162 SetPageUptodate(page);
2163 rc = 0;
Steve Frenchfb8c4b12007-07-10 01:16:18 +00002164
Linus Torvalds1da177e2005-04-16 15:20:36 -07002165io_error:
Steve Frenchfb8c4b12007-07-10 01:16:18 +00002166 kunmap(page);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002167 page_cache_release(page);
2168 return rc;
2169}
2170
2171static int cifs_readpage(struct file *file, struct page *page)
2172{
2173 loff_t offset = (loff_t)page->index << PAGE_CACHE_SHIFT;
2174 int rc = -EACCES;
2175 int xid;
2176
2177 xid = GetXid();
2178
2179 if (file->private_data == NULL) {
2180 FreeXid(xid);
2181 return -EBADF;
2182 }
2183
Steve Frenchfb8c4b12007-07-10 01:16:18 +00002184 cFYI(1, ("readpage %p at offset %d 0x%x\n",
Linus Torvalds1da177e2005-04-16 15:20:36 -07002185 page, (int)offset, (int)offset));
2186
2187 rc = cifs_readpage_worker(file, page, &offset);
2188
2189 unlock_page(page);
2190
2191 FreeXid(xid);
2192 return rc;
2193}
2194
Steve Frencha403a0a2007-07-26 15:54:16 +00002195static int is_inode_writable(struct cifsInodeInfo *cifs_inode)
2196{
2197 struct cifsFileInfo *open_file;
2198
2199 read_lock(&GlobalSMBSeslock);
2200 list_for_each_entry(open_file, &cifs_inode->openFileList, flist) {
2201 if (open_file->closePend)
2202 continue;
2203 if (open_file->pfile &&
2204 ((open_file->pfile->f_flags & O_RDWR) ||
2205 (open_file->pfile->f_flags & O_WRONLY))) {
2206 read_unlock(&GlobalSMBSeslock);
2207 return 1;
2208 }
2209 }
2210 read_unlock(&GlobalSMBSeslock);
2211 return 0;
2212}
2213
Linus Torvalds1da177e2005-04-16 15:20:36 -07002214/* We do not want to update the file size from server for inodes
2215 open for write - to avoid races with writepage extending
2216 the file - in the future we could consider allowing
Steve Frenchfb8c4b12007-07-10 01:16:18 +00002217 refreshing the inode only on increases in the file size
Linus Torvalds1da177e2005-04-16 15:20:36 -07002218 but this is tricky to do without racing with writebehind
2219 page caching in the current Linux kernel design */
Steve French4b18f2a2008-04-29 00:06:05 +00002220bool is_size_safe_to_change(struct cifsInodeInfo *cifsInode, __u64 end_of_file)
Linus Torvalds1da177e2005-04-16 15:20:36 -07002221{
Steve Frencha403a0a2007-07-26 15:54:16 +00002222 if (!cifsInode)
Steve French4b18f2a2008-04-29 00:06:05 +00002223 return true;
Steve French23e7dd72005-10-20 13:44:56 -07002224
Steve Frencha403a0a2007-07-26 15:54:16 +00002225 if (is_inode_writable(cifsInode)) {
2226 /* This inode is open for write at least once */
Steve Frenchc32a0b62006-01-12 14:41:28 -08002227 struct cifs_sb_info *cifs_sb;
2228
Steve Frenchc32a0b62006-01-12 14:41:28 -08002229 cifs_sb = CIFS_SB(cifsInode->vfs_inode.i_sb);
Steve Frenchad7a2922008-02-07 23:25:02 +00002230 if (cifs_sb->mnt_cifs_flags & CIFS_MOUNT_DIRECT_IO) {
Steve Frenchfb8c4b12007-07-10 01:16:18 +00002231 /* since no page cache to corrupt on directio
Steve Frenchc32a0b62006-01-12 14:41:28 -08002232 we can change size safely */
Steve French4b18f2a2008-04-29 00:06:05 +00002233 return true;
Steve Frenchc32a0b62006-01-12 14:41:28 -08002234 }
2235
Steve Frenchfb8c4b12007-07-10 01:16:18 +00002236 if (i_size_read(&cifsInode->vfs_inode) < end_of_file)
Steve French4b18f2a2008-04-29 00:06:05 +00002237 return true;
Steve French7ba52632007-02-08 18:14:13 +00002238
Steve French4b18f2a2008-04-29 00:06:05 +00002239 return false;
Steve French23e7dd72005-10-20 13:44:56 -07002240 } else
Steve French4b18f2a2008-04-29 00:06:05 +00002241 return true;
Linus Torvalds1da177e2005-04-16 15:20:36 -07002242}
2243
Nick Piggind9414772008-09-24 11:32:59 -04002244static int cifs_write_begin(struct file *file, struct address_space *mapping,
2245 loff_t pos, unsigned len, unsigned flags,
2246 struct page **pagep, void **fsdata)
Linus Torvalds1da177e2005-04-16 15:20:36 -07002247{
Nick Piggind9414772008-09-24 11:32:59 -04002248 pgoff_t index = pos >> PAGE_CACHE_SHIFT;
2249 loff_t offset = pos & (PAGE_CACHE_SIZE - 1);
Jeff Laytona98ee8c2008-11-26 19:32:33 +00002250 loff_t page_start = pos & PAGE_MASK;
2251 loff_t i_size;
2252 struct page *page;
2253 int rc = 0;
Linus Torvalds1da177e2005-04-16 15:20:36 -07002254
Nick Piggind9414772008-09-24 11:32:59 -04002255 cFYI(1, ("write_begin from %lld len %d", (long long)pos, len));
2256
Nick Piggin54566b22009-01-04 12:00:53 -08002257 page = grab_cache_page_write_begin(mapping, index, flags);
Jeff Laytona98ee8c2008-11-26 19:32:33 +00002258 if (!page) {
2259 rc = -ENOMEM;
2260 goto out;
2261 }
Nick Piggind9414772008-09-24 11:32:59 -04002262
Jeff Laytona98ee8c2008-11-26 19:32:33 +00002263 if (PageUptodate(page))
2264 goto out;
Steve French8a236262007-03-06 00:31:00 +00002265
Jeff Laytona98ee8c2008-11-26 19:32:33 +00002266 /*
2267 * If we write a full page it will be up to date, no need to read from
2268 * the server. If the write is short, we'll end up doing a sync write
2269 * instead.
2270 */
2271 if (len == PAGE_CACHE_SIZE)
2272 goto out;
2273
2274 /*
2275 * optimize away the read when we have an oplock, and we're not
2276 * expecting to use any of the data we'd be reading in. That
2277 * is, when the page lies beyond the EOF, or straddles the EOF
2278 * and the write will cover all of the existing data.
2279 */
2280 if (CIFS_I(mapping->host)->clientCanCacheRead) {
2281 i_size = i_size_read(mapping->host);
2282 if (page_start >= i_size ||
2283 (offset == 0 && (pos + len) >= i_size)) {
2284 zero_user_segments(page, 0, offset,
2285 offset + len,
2286 PAGE_CACHE_SIZE);
2287 /*
2288 * PageChecked means that the parts of the page
2289 * to which we're not writing are considered up
2290 * to date. Once the data is copied to the
2291 * page, it can be set uptodate.
2292 */
2293 SetPageChecked(page);
2294 goto out;
2295 }
2296 }
Linus Torvalds1da177e2005-04-16 15:20:36 -07002297
Nick Piggind9414772008-09-24 11:32:59 -04002298 if ((file->f_flags & O_ACCMODE) != O_WRONLY) {
Jeff Laytona98ee8c2008-11-26 19:32:33 +00002299 /*
2300 * might as well read a page, it is fast enough. If we get
2301 * an error, we don't need to return it. cifs_write_end will
2302 * do a sync write instead since PG_uptodate isn't set.
2303 */
2304 cifs_readpage_worker(file, page, &page_start);
Steve French8a236262007-03-06 00:31:00 +00002305 } else {
2306 /* we could try using another file handle if there is one -
2307 but how would we lock it to prevent close of that handle
2308 racing with this read? In any case
Nick Piggind9414772008-09-24 11:32:59 -04002309 this will be written out by write_end so is fine */
Steve French8a236262007-03-06 00:31:00 +00002310 }
Jeff Laytona98ee8c2008-11-26 19:32:33 +00002311out:
2312 *pagep = page;
2313 return rc;
Linus Torvalds1da177e2005-04-16 15:20:36 -07002314}
2315
Christoph Hellwigf5e54d62006-06-28 04:26:44 -07002316const struct address_space_operations cifs_addr_ops = {
Linus Torvalds1da177e2005-04-16 15:20:36 -07002317 .readpage = cifs_readpage,
2318 .readpages = cifs_readpages,
2319 .writepage = cifs_writepage,
Steve French37c0eb42005-10-05 14:50:29 -07002320 .writepages = cifs_writepages,
Nick Piggind9414772008-09-24 11:32:59 -04002321 .write_begin = cifs_write_begin,
2322 .write_end = cifs_write_end,
Linus Torvalds1da177e2005-04-16 15:20:36 -07002323 .set_page_dirty = __set_page_dirty_nobuffers,
2324 /* .sync_page = cifs_sync_page, */
2325 /* .direct_IO = */
2326};
Dave Kleikamp273d81d2006-06-01 19:41:23 +00002327
2328/*
2329 * cifs_readpages requires the server to support a buffer large enough to
2330 * contain the header plus one complete page of data. Otherwise, we need
2331 * to leave cifs_readpages out of the address space operations.
2332 */
Christoph Hellwigf5e54d62006-06-28 04:26:44 -07002333const struct address_space_operations cifs_addr_ops_smallbuf = {
Dave Kleikamp273d81d2006-06-01 19:41:23 +00002334 .readpage = cifs_readpage,
2335 .writepage = cifs_writepage,
2336 .writepages = cifs_writepages,
Nick Piggind9414772008-09-24 11:32:59 -04002337 .write_begin = cifs_write_begin,
2338 .write_end = cifs_write_end,
Dave Kleikamp273d81d2006-06-01 19:41:23 +00002339 .set_page_dirty = __set_page_dirty_nobuffers,
2340 /* .sync_page = cifs_sync_page, */
2341 /* .direct_IO = */
2342};