blob: 429337eb7afec9f0933c72927eedcc7412207c88 [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>
Jeff Layton3bc303c2009-09-21 06:47:50 -040033#include <linux/mount.h>
Linus Torvalds1da177e2005-04-16 15:20:36 -070034#include <asm/div64.h>
35#include "cifsfs.h"
36#include "cifspdu.h"
37#include "cifsglob.h"
38#include "cifsproto.h"
39#include "cifs_unicode.h"
40#include "cifs_debug.h"
41#include "cifs_fs_sb.h"
42
Linus Torvalds1da177e2005-04-16 15:20:36 -070043static inline int cifs_convert_flags(unsigned int flags)
44{
45 if ((flags & O_ACCMODE) == O_RDONLY)
46 return GENERIC_READ;
47 else if ((flags & O_ACCMODE) == O_WRONLY)
48 return GENERIC_WRITE;
49 else if ((flags & O_ACCMODE) == O_RDWR) {
50 /* GENERIC_ALL is too much permission to request
51 can cause unnecessary access denied on create */
52 /* return GENERIC_ALL; */
53 return (GENERIC_READ | GENERIC_WRITE);
54 }
55
Jeff Laytone10f7b52008-05-14 10:21:33 -070056 return (READ_CONTROL | FILE_WRITE_ATTRIBUTES | FILE_READ_ATTRIBUTES |
57 FILE_WRITE_EA | FILE_APPEND_DATA | FILE_WRITE_DATA |
58 FILE_READ_DATA);
Steve French7fc8f4e2009-02-23 20:43:11 +000059}
Jeff Laytone10f7b52008-05-14 10:21:33 -070060
Steve French7fc8f4e2009-02-23 20:43:11 +000061static inline fmode_t cifs_posix_convert_flags(unsigned int flags)
62{
63 fmode_t posix_flags = 0;
Jeff Laytone10f7b52008-05-14 10:21:33 -070064
Steve French7fc8f4e2009-02-23 20:43:11 +000065 if ((flags & O_ACCMODE) == O_RDONLY)
66 posix_flags = FMODE_READ;
67 else if ((flags & O_ACCMODE) == O_WRONLY)
68 posix_flags = FMODE_WRITE;
69 else if ((flags & O_ACCMODE) == O_RDWR) {
70 /* GENERIC_ALL is too much permission to request
71 can cause unnecessary access denied on create */
72 /* return GENERIC_ALL; */
73 posix_flags = FMODE_READ | FMODE_WRITE;
74 }
75 /* can not map O_CREAT or O_EXCL or O_TRUNC flags when
76 reopening a file. They had their effect on the original open */
77 if (flags & O_APPEND)
78 posix_flags |= (fmode_t)O_APPEND;
79 if (flags & O_SYNC)
80 posix_flags |= (fmode_t)O_SYNC;
81 if (flags & O_DIRECTORY)
82 posix_flags |= (fmode_t)O_DIRECTORY;
83 if (flags & O_NOFOLLOW)
84 posix_flags |= (fmode_t)O_NOFOLLOW;
85 if (flags & O_DIRECT)
86 posix_flags |= (fmode_t)O_DIRECT;
87
88 return posix_flags;
Linus Torvalds1da177e2005-04-16 15:20:36 -070089}
90
91static inline int cifs_get_disposition(unsigned int flags)
92{
93 if ((flags & (O_CREAT | O_EXCL)) == (O_CREAT | O_EXCL))
94 return FILE_CREATE;
95 else if ((flags & (O_CREAT | O_TRUNC)) == (O_CREAT | O_TRUNC))
96 return FILE_OVERWRITE_IF;
97 else if ((flags & O_CREAT) == O_CREAT)
98 return FILE_OPEN_IF;
Steve French55aa2e02006-05-30 18:09:31 +000099 else if ((flags & O_TRUNC) == O_TRUNC)
100 return FILE_OVERWRITE;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700101 else
102 return FILE_OPEN;
103}
104
105/* all arguments to this function must be checked for validity in caller */
Jeff Layton590a3fe2009-09-12 11:54:28 -0400106static inline int
107cifs_posix_open_inode_helper(struct inode *inode, struct file *file,
108 struct cifsInodeInfo *pCifsInode,
109 struct cifsFileInfo *pCifsFile, __u32 oplock,
110 u16 netfid)
Steve French276a74a2009-03-03 18:00:34 +0000111{
Steve French276a74a2009-03-03 18:00:34 +0000112
Steve French276a74a2009-03-03 18:00:34 +0000113 write_lock(&GlobalSMBSeslock);
Steve French276a74a2009-03-03 18:00:34 +0000114
115 pCifsInode = CIFS_I(file->f_path.dentry->d_inode);
116 if (pCifsInode == NULL) {
117 write_unlock(&GlobalSMBSeslock);
118 return -EINVAL;
119 }
120
Steve French276a74a2009-03-03 18:00:34 +0000121 if (pCifsInode->clientCanCacheRead) {
122 /* we have the inode open somewhere else
123 no need to discard cache data */
124 goto psx_client_can_cache;
125 }
126
127 /* BB FIXME need to fix this check to move it earlier into posix_open
128 BB fIX following section BB FIXME */
129
130 /* if not oplocked, invalidate inode pages if mtime or file
131 size changed */
132/* temp = cifs_NTtimeToUnix(le64_to_cpu(buf->LastWriteTime));
133 if (timespec_equal(&file->f_path.dentry->d_inode->i_mtime, &temp) &&
134 (file->f_path.dentry->d_inode->i_size ==
135 (loff_t)le64_to_cpu(buf->EndOfFile))) {
136 cFYI(1, ("inode unchanged on server"));
137 } else {
138 if (file->f_path.dentry->d_inode->i_mapping) {
139 rc = filemap_write_and_wait(file->f_path.dentry->d_inode->i_mapping);
140 if (rc != 0)
141 CIFS_I(file->f_path.dentry->d_inode)->write_behind_rc = rc;
142 }
143 cFYI(1, ("invalidating remote inode since open detected it "
144 "changed"));
145 invalidate_remote_inode(file->f_path.dentry->d_inode);
146 } */
147
148psx_client_can_cache:
149 if ((oplock & 0xF) == OPLOCK_EXCLUSIVE) {
150 pCifsInode->clientCanCacheAll = true;
151 pCifsInode->clientCanCacheRead = true;
152 cFYI(1, ("Exclusive Oplock granted on inode %p",
153 file->f_path.dentry->d_inode));
154 } else if ((oplock & 0xF) == OPLOCK_READ)
155 pCifsInode->clientCanCacheRead = true;
156
157 /* will have to change the unlock if we reenable the
158 filemap_fdatawrite (which does not seem necessary */
159 write_unlock(&GlobalSMBSeslock);
160 return 0;
161}
162
Steve French703a3b82009-05-21 22:21:53 +0000163static struct cifsFileInfo *
164cifs_fill_filedata(struct file *file)
165{
166 struct list_head *tmp;
167 struct cifsFileInfo *pCifsFile = NULL;
168 struct cifsInodeInfo *pCifsInode = NULL;
169
170 /* search inode for this file and fill in file->private_data */
171 pCifsInode = CIFS_I(file->f_path.dentry->d_inode);
172 read_lock(&GlobalSMBSeslock);
173 list_for_each(tmp, &pCifsInode->openFileList) {
174 pCifsFile = list_entry(tmp, struct cifsFileInfo, flist);
175 if ((pCifsFile->pfile == NULL) &&
176 (pCifsFile->pid == current->tgid)) {
177 /* mode set in cifs_create */
178
179 /* needed for writepage */
180 pCifsFile->pfile = file;
181 file->private_data = pCifsFile;
182 break;
183 }
184 }
185 read_unlock(&GlobalSMBSeslock);
186
187 if (file->private_data != NULL) {
188 return pCifsFile;
189 } else if ((file->f_flags & O_CREAT) && (file->f_flags & O_EXCL))
190 cERROR(1, ("could not find file instance for "
191 "new file %p", file));
192 return NULL;
193}
194
Steve French276a74a2009-03-03 18:00:34 +0000195/* all arguments to this function must be checked for validity in caller */
Linus Torvalds1da177e2005-04-16 15:20:36 -0700196static inline int cifs_open_inode_helper(struct inode *inode, struct file *file,
197 struct cifsInodeInfo *pCifsInode, struct cifsFileInfo *pCifsFile,
198 struct cifsTconInfo *pTcon, int *oplock, FILE_ALL_INFO *buf,
199 char *full_path, int xid)
200{
201 struct timespec temp;
202 int rc;
203
Linus Torvalds1da177e2005-04-16 15:20:36 -0700204 if (pCifsInode->clientCanCacheRead) {
205 /* we have the inode open somewhere else
206 no need to discard cache data */
207 goto client_can_cache;
208 }
209
210 /* BB need same check in cifs_create too? */
211 /* if not oplocked, invalidate inode pages if mtime or file
212 size changed */
Jeff Layton07119a42009-05-27 09:37:33 -0400213 temp = cifs_NTtimeToUnix(buf->LastWriteTime);
Josef "Jeff" Sipeke6a00292006-12-08 02:36:48 -0800214 if (timespec_equal(&file->f_path.dentry->d_inode->i_mtime, &temp) &&
215 (file->f_path.dentry->d_inode->i_size ==
Linus Torvalds1da177e2005-04-16 15:20:36 -0700216 (loff_t)le64_to_cpu(buf->EndOfFile))) {
217 cFYI(1, ("inode unchanged on server"));
218 } else {
Josef "Jeff" Sipeke6a00292006-12-08 02:36:48 -0800219 if (file->f_path.dentry->d_inode->i_mapping) {
Linus Torvalds1da177e2005-04-16 15:20:36 -0700220 /* BB no need to lock inode until after invalidate
221 since namei code should already have it locked? */
Jeff Laytoncea21802007-11-20 23:19:03 +0000222 rc = filemap_write_and_wait(file->f_path.dentry->d_inode->i_mapping);
223 if (rc != 0)
224 CIFS_I(file->f_path.dentry->d_inode)->write_behind_rc = rc;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700225 }
226 cFYI(1, ("invalidating remote inode since open detected it "
227 "changed"));
Josef "Jeff" Sipeke6a00292006-12-08 02:36:48 -0800228 invalidate_remote_inode(file->f_path.dentry->d_inode);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700229 }
230
231client_can_cache:
Steve Frenchc18c8422007-07-18 23:21:09 +0000232 if (pTcon->unix_ext)
Josef "Jeff" Sipeke6a00292006-12-08 02:36:48 -0800233 rc = cifs_get_inode_info_unix(&file->f_path.dentry->d_inode,
Linus Torvalds1da177e2005-04-16 15:20:36 -0700234 full_path, inode->i_sb, xid);
235 else
Josef "Jeff" Sipeke6a00292006-12-08 02:36:48 -0800236 rc = cifs_get_inode_info(&file->f_path.dentry->d_inode,
Steve French8b1327f2008-03-14 22:37:16 +0000237 full_path, buf, inode->i_sb, xid, NULL);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700238
239 if ((*oplock & 0xF) == OPLOCK_EXCLUSIVE) {
Steve French4b18f2a2008-04-29 00:06:05 +0000240 pCifsInode->clientCanCacheAll = true;
241 pCifsInode->clientCanCacheRead = true;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700242 cFYI(1, ("Exclusive Oplock granted on inode %p",
Josef "Jeff" Sipeke6a00292006-12-08 02:36:48 -0800243 file->f_path.dentry->d_inode));
Linus Torvalds1da177e2005-04-16 15:20:36 -0700244 } else if ((*oplock & 0xF) == OPLOCK_READ)
Steve French4b18f2a2008-04-29 00:06:05 +0000245 pCifsInode->clientCanCacheRead = true;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700246
247 return rc;
248}
249
250int cifs_open(struct inode *inode, struct file *file)
251{
252 int rc = -EACCES;
Jeff Layton590a3fe2009-09-12 11:54:28 -0400253 int xid;
254 __u32 oplock;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700255 struct cifs_sb_info *cifs_sb;
Steve French276a74a2009-03-03 18:00:34 +0000256 struct cifsTconInfo *tcon;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700257 struct cifsFileInfo *pCifsFile;
258 struct cifsInodeInfo *pCifsInode;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700259 char *full_path = NULL;
260 int desiredAccess;
261 int disposition;
262 __u16 netfid;
263 FILE_ALL_INFO *buf = NULL;
264
265 xid = GetXid();
266
267 cifs_sb = CIFS_SB(inode->i_sb);
Steve French276a74a2009-03-03 18:00:34 +0000268 tcon = cifs_sb->tcon;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700269
Steve Frencha6ce4932009-04-09 01:14:32 +0000270 pCifsInode = CIFS_I(file->f_path.dentry->d_inode);
Steve French703a3b82009-05-21 22:21:53 +0000271 pCifsFile = cifs_fill_filedata(file);
272 if (pCifsFile) {
Suresh Jayaraman0f3bc092009-06-25 18:12:34 +0530273 rc = 0;
Steve Frencha6ce4932009-04-09 01:14:32 +0000274 FreeXid(xid);
Suresh Jayaraman0f3bc092009-06-25 18:12:34 +0530275 return rc;
Steve French703a3b82009-05-21 22:21:53 +0000276 }
Linus Torvalds1da177e2005-04-16 15:20:36 -0700277
Josef "Jeff" Sipeke6a00292006-12-08 02:36:48 -0800278 full_path = build_path_from_dentry(file->f_path.dentry);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700279 if (full_path == NULL) {
Suresh Jayaraman0f3bc092009-06-25 18:12:34 +0530280 rc = -ENOMEM;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700281 FreeXid(xid);
Suresh Jayaraman0f3bc092009-06-25 18:12:34 +0530282 return rc;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700283 }
284
Steve French7521a3c2007-07-11 18:30:34 +0000285 cFYI(1, ("inode = 0x%p file flags are 0x%x for %s",
Linus Torvalds1da177e2005-04-16 15:20:36 -0700286 inode, file->f_flags, full_path));
Steve French276a74a2009-03-03 18:00:34 +0000287
288 if (oplockEnabled)
289 oplock = REQ_OPLOCK;
290 else
291 oplock = 0;
292
Steve French64cc2c62009-03-04 19:54:08 +0000293 if (!tcon->broken_posix_open && tcon->unix_ext &&
294 (tcon->ses->capabilities & CAP_UNIX) &&
Steve French276a74a2009-03-03 18:00:34 +0000295 (CIFS_UNIX_POSIX_PATH_OPS_CAP &
296 le64_to_cpu(tcon->fsUnixInfo.Capability))) {
297 int oflags = (int) cifs_posix_convert_flags(file->f_flags);
298 /* can not refresh inode info since size could be stale */
Jeff Layton3bc303c2009-09-21 06:47:50 -0400299 rc = cifs_posix_open(full_path, &inode, file->f_path.mnt,
Steve French276a74a2009-03-03 18:00:34 +0000300 cifs_sb->mnt_file_mode /* ignored */,
301 oflags, &oplock, &netfid, xid);
302 if (rc == 0) {
303 cFYI(1, ("posix open succeeded"));
304 /* no need for special case handling of setting mode
305 on read only files needed here */
306
Steve French703a3b82009-05-21 22:21:53 +0000307 pCifsFile = cifs_fill_filedata(file);
Steve French276a74a2009-03-03 18:00:34 +0000308 cifs_posix_open_inode_helper(inode, file, pCifsInode,
309 pCifsFile, oplock, netfid);
310 goto out;
Steve French64cc2c62009-03-04 19:54:08 +0000311 } else if ((rc == -EINVAL) || (rc == -EOPNOTSUPP)) {
312 if (tcon->ses->serverNOS)
313 cERROR(1, ("server %s of type %s returned"
314 " unexpected error on SMB posix open"
315 ", disabling posix open support."
316 " Check if server update available.",
317 tcon->ses->serverName,
318 tcon->ses->serverNOS));
319 tcon->broken_posix_open = true;
Steve French276a74a2009-03-03 18:00:34 +0000320 } else if ((rc != -EIO) && (rc != -EREMOTE) &&
321 (rc != -EOPNOTSUPP)) /* path not found or net err */
322 goto out;
Steve French64cc2c62009-03-04 19:54:08 +0000323 /* else fallthrough to retry open the old way on network i/o
324 or DFS errors */
Steve French276a74a2009-03-03 18:00:34 +0000325 }
326
Linus Torvalds1da177e2005-04-16 15:20:36 -0700327 desiredAccess = cifs_convert_flags(file->f_flags);
328
329/*********************************************************************
330 * open flag mapping table:
Steve Frenchfb8c4b12007-07-10 01:16:18 +0000331 *
Linus Torvalds1da177e2005-04-16 15:20:36 -0700332 * POSIX Flag CIFS Disposition
Steve Frenchfb8c4b12007-07-10 01:16:18 +0000333 * ---------- ----------------
Linus Torvalds1da177e2005-04-16 15:20:36 -0700334 * O_CREAT FILE_OPEN_IF
335 * O_CREAT | O_EXCL FILE_CREATE
336 * O_CREAT | O_TRUNC FILE_OVERWRITE_IF
337 * O_TRUNC FILE_OVERWRITE
338 * none of the above FILE_OPEN
339 *
340 * Note that there is not a direct match between disposition
Steve Frenchfb8c4b12007-07-10 01:16:18 +0000341 * FILE_SUPERSEDE (ie create whether or not file exists although
Linus Torvalds1da177e2005-04-16 15:20:36 -0700342 * O_CREAT | O_TRUNC is similar but truncates the existing
343 * file rather than creating a new file as FILE_SUPERSEDE does
344 * (which uses the attributes / metadata passed in on open call)
345 *?
Steve Frenchfb8c4b12007-07-10 01:16:18 +0000346 *? O_SYNC is a reasonable match to CIFS writethrough flag
Linus Torvalds1da177e2005-04-16 15:20:36 -0700347 *? and the read write flags match reasonably. O_LARGEFILE
348 *? is irrelevant because largefile support is always used
349 *? by this client. Flags O_APPEND, O_DIRECT, O_DIRECTORY,
350 * O_FASYNC, O_NOFOLLOW, O_NONBLOCK need further investigation
351 *********************************************************************/
352
353 disposition = cifs_get_disposition(file->f_flags);
354
Linus Torvalds1da177e2005-04-16 15:20:36 -0700355 /* BB pass O_SYNC flag through on file attributes .. BB */
356
357 /* Also refresh inode by passing in file_info buf returned by SMBOpen
358 and calling get_inode_info with returned buf (at least helps
359 non-Unix server case) */
360
Steve Frenchfb8c4b12007-07-10 01:16:18 +0000361 /* BB we can not do this if this is the second open of a file
362 and the first handle has writebehind data, we might be
Linus Torvalds1da177e2005-04-16 15:20:36 -0700363 able to simply do a filemap_fdatawrite/filemap_fdatawait first */
364 buf = kmalloc(sizeof(FILE_ALL_INFO), GFP_KERNEL);
365 if (!buf) {
366 rc = -ENOMEM;
367 goto out;
368 }
Steve French5bafd762006-06-07 00:18:43 +0000369
370 if (cifs_sb->tcon->ses->capabilities & CAP_NT_SMBS)
Steve French276a74a2009-03-03 18:00:34 +0000371 rc = CIFSSMBOpen(xid, tcon, full_path, disposition,
Steve French5bafd762006-06-07 00:18:43 +0000372 desiredAccess, CREATE_NOT_DIR, &netfid, &oplock, buf,
Steve French737b7582005-04-28 22:41:06 -0700373 cifs_sb->local_nls, cifs_sb->mnt_cifs_flags
374 & CIFS_MOUNT_MAP_SPECIAL_CHR);
Steve French5bafd762006-06-07 00:18:43 +0000375 else
376 rc = -EIO; /* no NT SMB support fall into legacy open below */
377
Steve Frencha9d02ad2005-08-24 23:06:05 -0700378 if (rc == -EIO) {
379 /* Old server, try legacy style OpenX */
Steve French276a74a2009-03-03 18:00:34 +0000380 rc = SMBLegacyOpen(xid, tcon, full_path, disposition,
Steve Frencha9d02ad2005-08-24 23:06:05 -0700381 desiredAccess, CREATE_NOT_DIR, &netfid, &oplock, buf,
382 cifs_sb->local_nls, cifs_sb->mnt_cifs_flags
383 & CIFS_MOUNT_MAP_SPECIAL_CHR);
384 }
Linus Torvalds1da177e2005-04-16 15:20:36 -0700385 if (rc) {
Steve French26a21b92006-05-31 18:05:34 +0000386 cFYI(1, ("cifs_open returned 0x%x", rc));
Linus Torvalds1da177e2005-04-16 15:20:36 -0700387 goto out;
388 }
Jeff Layton3321b792009-09-25 09:53:37 -0400389
Jeff Layton086f68b2009-09-21 14:08:18 -0400390 pCifsFile = cifs_new_fileinfo(inode, netfid, file, file->f_path.mnt,
391 file->f_flags);
392 file->private_data = pCifsFile;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700393 if (file->private_data == NULL) {
394 rc = -ENOMEM;
395 goto out;
396 }
Linus Torvalds1da177e2005-04-16 15:20:36 -0700397
Jeff Layton3321b792009-09-25 09:53:37 -0400398 rc = cifs_open_inode_helper(inode, file, pCifsInode, pCifsFile, tcon,
399 &oplock, buf, full_path, xid);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700400
Steve Frenchfb8c4b12007-07-10 01:16:18 +0000401 if (oplock & CIFS_CREATE_ACTION) {
Linus Torvalds1da177e2005-04-16 15:20:36 -0700402 /* time to set mode which we can not set earlier due to
403 problems creating new read-only files */
Steve French276a74a2009-03-03 18:00:34 +0000404 if (tcon->unix_ext) {
Jeff Layton4e1e7fb2008-08-02 07:26:12 -0400405 struct cifs_unix_set_info_args args = {
406 .mode = inode->i_mode,
407 .uid = NO_CHANGE_64,
408 .gid = NO_CHANGE_64,
409 .ctime = NO_CHANGE_64,
410 .atime = NO_CHANGE_64,
411 .mtime = NO_CHANGE_64,
412 .device = 0,
413 };
Jeff Layton01ea95e2009-07-09 20:02:49 -0400414 CIFSSMBUnixSetPathInfo(xid, tcon, full_path, &args,
415 cifs_sb->local_nls,
416 cifs_sb->mnt_cifs_flags &
Steve French737b7582005-04-28 22:41:06 -0700417 CIFS_MOUNT_MAP_SPECIAL_CHR);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700418 }
419 }
420
421out:
422 kfree(buf);
423 kfree(full_path);
424 FreeXid(xid);
425 return rc;
426}
427
Adrian Bunk04187262006-06-30 18:23:04 +0200428/* Try to reacquire byte range locks that were released when session */
Linus Torvalds1da177e2005-04-16 15:20:36 -0700429/* to server was lost */
430static int cifs_relock_file(struct cifsFileInfo *cifsFile)
431{
432 int rc = 0;
433
434/* BB list all locks open on this file and relock */
435
436 return rc;
437}
438
Steve French4b18f2a2008-04-29 00:06:05 +0000439static int cifs_reopen_file(struct file *file, bool can_flush)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700440{
441 int rc = -EACCES;
Jeff Layton590a3fe2009-09-12 11:54:28 -0400442 int xid;
443 __u32 oplock;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700444 struct cifs_sb_info *cifs_sb;
Steve French7fc8f4e2009-02-23 20:43:11 +0000445 struct cifsTconInfo *tcon;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700446 struct cifsFileInfo *pCifsFile;
447 struct cifsInodeInfo *pCifsInode;
Steve Frenchfb8c4b12007-07-10 01:16:18 +0000448 struct inode *inode;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700449 char *full_path = NULL;
450 int desiredAccess;
451 int disposition = FILE_OPEN;
452 __u16 netfid;
453
Steve Frenchad7a2922008-02-07 23:25:02 +0000454 if (file->private_data)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700455 pCifsFile = (struct cifsFileInfo *)file->private_data;
Steve Frenchad7a2922008-02-07 23:25:02 +0000456 else
Linus Torvalds1da177e2005-04-16 15:20:36 -0700457 return -EBADF;
458
459 xid = GetXid();
Jeff Laytonf0a71eb2009-06-27 07:04:55 -0400460 mutex_lock(&pCifsFile->fh_mutex);
Steve French4b18f2a2008-04-29 00:06:05 +0000461 if (!pCifsFile->invalidHandle) {
Jeff Laytonf0a71eb2009-06-27 07:04:55 -0400462 mutex_unlock(&pCifsFile->fh_mutex);
Suresh Jayaraman0f3bc092009-06-25 18:12:34 +0530463 rc = 0;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700464 FreeXid(xid);
Suresh Jayaraman0f3bc092009-06-25 18:12:34 +0530465 return rc;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700466 }
467
Josef "Jeff" Sipeke6a00292006-12-08 02:36:48 -0800468 if (file->f_path.dentry == NULL) {
Steve French3a9f4622007-04-04 17:10:24 +0000469 cERROR(1, ("no valid name if dentry freed"));
470 dump_stack();
471 rc = -EBADF;
472 goto reopen_error_exit;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700473 }
Steve French3a9f4622007-04-04 17:10:24 +0000474
475 inode = file->f_path.dentry->d_inode;
Steve Frenchfb8c4b12007-07-10 01:16:18 +0000476 if (inode == NULL) {
Steve French3a9f4622007-04-04 17:10:24 +0000477 cERROR(1, ("inode not valid"));
478 dump_stack();
479 rc = -EBADF;
480 goto reopen_error_exit;
481 }
Steve French50c2f752007-07-13 00:33:32 +0000482
Linus Torvalds1da177e2005-04-16 15:20:36 -0700483 cifs_sb = CIFS_SB(inode->i_sb);
Steve French7fc8f4e2009-02-23 20:43:11 +0000484 tcon = cifs_sb->tcon;
Steve French3a9f4622007-04-04 17:10:24 +0000485
Linus Torvalds1da177e2005-04-16 15:20:36 -0700486/* can not grab rename sem here because various ops, including
487 those that already have the rename sem can end up causing writepage
488 to get called and if the server was down that means we end up here,
489 and we can never tell if the caller already has the rename_sem */
Josef "Jeff" Sipeke6a00292006-12-08 02:36:48 -0800490 full_path = build_path_from_dentry(file->f_path.dentry);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700491 if (full_path == NULL) {
Steve French3a9f4622007-04-04 17:10:24 +0000492 rc = -ENOMEM;
493reopen_error_exit:
Jeff Laytonf0a71eb2009-06-27 07:04:55 -0400494 mutex_unlock(&pCifsFile->fh_mutex);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700495 FreeXid(xid);
Steve French3a9f4622007-04-04 17:10:24 +0000496 return rc;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700497 }
498
Steve French3a9f4622007-04-04 17:10:24 +0000499 cFYI(1, ("inode = 0x%p file flags 0x%x for %s",
Steve Frenchfb8c4b12007-07-10 01:16:18 +0000500 inode, file->f_flags, full_path));
Linus Torvalds1da177e2005-04-16 15:20:36 -0700501
502 if (oplockEnabled)
503 oplock = REQ_OPLOCK;
504 else
Steve French4b18f2a2008-04-29 00:06:05 +0000505 oplock = 0;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700506
Steve French7fc8f4e2009-02-23 20:43:11 +0000507 if (tcon->unix_ext && (tcon->ses->capabilities & CAP_UNIX) &&
508 (CIFS_UNIX_POSIX_PATH_OPS_CAP &
509 le64_to_cpu(tcon->fsUnixInfo.Capability))) {
510 int oflags = (int) cifs_posix_convert_flags(file->f_flags);
511 /* can not refresh inode info since size could be stale */
Jeff Layton3bc303c2009-09-21 06:47:50 -0400512 rc = cifs_posix_open(full_path, NULL, file->f_path.mnt,
Steve French7fc8f4e2009-02-23 20:43:11 +0000513 cifs_sb->mnt_file_mode /* ignored */,
514 oflags, &oplock, &netfid, xid);
515 if (rc == 0) {
516 cFYI(1, ("posix reopen succeeded"));
517 goto reopen_success;
518 }
519 /* fallthrough to retry open the old way on errors, especially
520 in the reconnect path it is important to retry hard */
521 }
522
523 desiredAccess = cifs_convert_flags(file->f_flags);
524
Linus Torvalds1da177e2005-04-16 15:20:36 -0700525 /* Can not refresh inode by passing in file_info buf to be returned
Steve Frenchfb8c4b12007-07-10 01:16:18 +0000526 by SMBOpen and then calling get_inode_info with returned buf
527 since file might have write behind data that needs to be flushed
Linus Torvalds1da177e2005-04-16 15:20:36 -0700528 and server version of file size can be stale. If we knew for sure
529 that inode was not dirty locally we could do this */
530
Steve French7fc8f4e2009-02-23 20:43:11 +0000531 rc = CIFSSMBOpen(xid, tcon, full_path, disposition, desiredAccess,
Linus Torvalds1da177e2005-04-16 15:20:36 -0700532 CREATE_NOT_DIR, &netfid, &oplock, NULL,
Steve Frenchfb8c4b12007-07-10 01:16:18 +0000533 cifs_sb->local_nls, cifs_sb->mnt_cifs_flags &
Steve French737b7582005-04-28 22:41:06 -0700534 CIFS_MOUNT_MAP_SPECIAL_CHR);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700535 if (rc) {
Jeff Laytonf0a71eb2009-06-27 07:04:55 -0400536 mutex_unlock(&pCifsFile->fh_mutex);
Steve French26a21b92006-05-31 18:05:34 +0000537 cFYI(1, ("cifs_open returned 0x%x", rc));
538 cFYI(1, ("oplock: %d", oplock));
Linus Torvalds1da177e2005-04-16 15:20:36 -0700539 } else {
Steve French7fc8f4e2009-02-23 20:43:11 +0000540reopen_success:
Linus Torvalds1da177e2005-04-16 15:20:36 -0700541 pCifsFile->netfid = netfid;
Steve French4b18f2a2008-04-29 00:06:05 +0000542 pCifsFile->invalidHandle = false;
Jeff Laytonf0a71eb2009-06-27 07:04:55 -0400543 mutex_unlock(&pCifsFile->fh_mutex);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700544 pCifsInode = CIFS_I(inode);
545 if (pCifsInode) {
546 if (can_flush) {
Jeff Laytoncea21802007-11-20 23:19:03 +0000547 rc = filemap_write_and_wait(inode->i_mapping);
548 if (rc != 0)
549 CIFS_I(inode)->write_behind_rc = rc;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700550 /* temporarily disable caching while we
551 go to server to get inode info */
Steve French4b18f2a2008-04-29 00:06:05 +0000552 pCifsInode->clientCanCacheAll = false;
553 pCifsInode->clientCanCacheRead = false;
Steve French7fc8f4e2009-02-23 20:43:11 +0000554 if (tcon->unix_ext)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700555 rc = cifs_get_inode_info_unix(&inode,
556 full_path, inode->i_sb, xid);
557 else
558 rc = cifs_get_inode_info(&inode,
559 full_path, NULL, inode->i_sb,
Steve French8b1327f2008-03-14 22:37:16 +0000560 xid, NULL);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700561 } /* else we are writing out data to server already
562 and could deadlock if we tried to flush data, and
563 since we do not know if we have data that would
564 invalidate the current end of file on the server
565 we can not go to the server to get the new inod
566 info */
567 if ((oplock & 0xF) == OPLOCK_EXCLUSIVE) {
Steve French4b18f2a2008-04-29 00:06:05 +0000568 pCifsInode->clientCanCacheAll = true;
569 pCifsInode->clientCanCacheRead = true;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700570 cFYI(1, ("Exclusive Oplock granted on inode %p",
Josef "Jeff" Sipeke6a00292006-12-08 02:36:48 -0800571 file->f_path.dentry->d_inode));
Linus Torvalds1da177e2005-04-16 15:20:36 -0700572 } else if ((oplock & 0xF) == OPLOCK_READ) {
Steve French4b18f2a2008-04-29 00:06:05 +0000573 pCifsInode->clientCanCacheRead = true;
574 pCifsInode->clientCanCacheAll = false;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700575 } else {
Steve French4b18f2a2008-04-29 00:06:05 +0000576 pCifsInode->clientCanCacheRead = false;
577 pCifsInode->clientCanCacheAll = false;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700578 }
579 cifs_relock_file(pCifsFile);
580 }
581 }
Linus Torvalds1da177e2005-04-16 15:20:36 -0700582 kfree(full_path);
583 FreeXid(xid);
584 return rc;
585}
586
587int cifs_close(struct inode *inode, struct file *file)
588{
589 int rc = 0;
Steve French15745322007-09-07 22:23:48 +0000590 int xid, timeout;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700591 struct cifs_sb_info *cifs_sb;
592 struct cifsTconInfo *pTcon;
593 struct cifsFileInfo *pSMBFile =
594 (struct cifsFileInfo *)file->private_data;
595
596 xid = GetXid();
597
598 cifs_sb = CIFS_SB(inode->i_sb);
599 pTcon = cifs_sb->tcon;
600 if (pSMBFile) {
Jeremy Allison7ee1af72006-08-02 21:56:33 +0000601 struct cifsLockInfo *li, *tmp;
Steve Frenchddb4cbf2008-11-20 20:00:44 +0000602 write_lock(&GlobalSMBSeslock);
Steve French4b18f2a2008-04-29 00:06:05 +0000603 pSMBFile->closePend = true;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700604 if (pTcon) {
605 /* no sense reconnecting to close a file that is
606 already closed */
Steve French3b795212008-11-13 19:45:32 +0000607 if (!pTcon->need_reconnect) {
Steve Frenchddb4cbf2008-11-20 20:00:44 +0000608 write_unlock(&GlobalSMBSeslock);
Steve French15745322007-09-07 22:23:48 +0000609 timeout = 2;
Dave Kleikamp6ab409b2009-08-31 11:07:12 -0400610 while ((atomic_read(&pSMBFile->count) != 1)
Steve French15745322007-09-07 22:23:48 +0000611 && (timeout <= 2048)) {
Steve French23e7dd72005-10-20 13:44:56 -0700612 /* Give write a better chance to get to
613 server ahead of the close. We do not
614 want to add a wait_q here as it would
615 increase the memory utilization as
616 the struct would be in each open file,
Steve Frenchfb8c4b12007-07-10 01:16:18 +0000617 but this should give enough time to
Steve French23e7dd72005-10-20 13:44:56 -0700618 clear the socket */
Steve French90c81e02008-02-12 20:32:36 +0000619 cFYI(DBG2,
620 ("close delay, write pending"));
Steve French23e7dd72005-10-20 13:44:56 -0700621 msleep(timeout);
622 timeout *= 4;
Steve French4891d532006-11-07 16:31:16 +0000623 }
Steve Frenchddb4cbf2008-11-20 20:00:44 +0000624 if (!pTcon->need_reconnect &&
625 !pSMBFile->invalidHandle)
626 rc = CIFSSMBClose(xid, pTcon,
Linus Torvalds1da177e2005-04-16 15:20:36 -0700627 pSMBFile->netfid);
Steve Frenchddb4cbf2008-11-20 20:00:44 +0000628 } else
629 write_unlock(&GlobalSMBSeslock);
630 } else
631 write_unlock(&GlobalSMBSeslock);
Jeremy Allison7ee1af72006-08-02 21:56:33 +0000632
633 /* Delete any outstanding lock records.
634 We'll lose them when the file is closed anyway. */
Roland Dreier796e5662007-05-03 04:33:45 +0000635 mutex_lock(&pSMBFile->lock_mutex);
Jeremy Allison7ee1af72006-08-02 21:56:33 +0000636 list_for_each_entry_safe(li, tmp, &pSMBFile->llist, llist) {
637 list_del(&li->llist);
638 kfree(li);
639 }
Roland Dreier796e5662007-05-03 04:33:45 +0000640 mutex_unlock(&pSMBFile->lock_mutex);
Jeremy Allison7ee1af72006-08-02 21:56:33 +0000641
Steve Frenchcbe04762005-04-28 22:41:05 -0700642 write_lock(&GlobalSMBSeslock);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700643 list_del(&pSMBFile->flist);
644 list_del(&pSMBFile->tlist);
Steve Frenchcbe04762005-04-28 22:41:05 -0700645 write_unlock(&GlobalSMBSeslock);
Dave Kleikamp6ab409b2009-08-31 11:07:12 -0400646 cifsFileInfo_put(file->private_data);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700647 file->private_data = NULL;
648 } else
649 rc = -EBADF;
650
Steve French4efa53f2007-09-11 05:50:53 +0000651 read_lock(&GlobalSMBSeslock);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700652 if (list_empty(&(CIFS_I(inode)->openFileList))) {
653 cFYI(1, ("closing last open instance for inode %p", inode));
654 /* if the file is not open we do not know if we can cache info
655 on this inode, much less write behind and read ahead */
Steve French4b18f2a2008-04-29 00:06:05 +0000656 CIFS_I(inode)->clientCanCacheRead = false;
657 CIFS_I(inode)->clientCanCacheAll = false;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700658 }
Steve French4efa53f2007-09-11 05:50:53 +0000659 read_unlock(&GlobalSMBSeslock);
Steve Frenchfb8c4b12007-07-10 01:16:18 +0000660 if ((rc == 0) && CIFS_I(inode)->write_behind_rc)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700661 rc = CIFS_I(inode)->write_behind_rc;
662 FreeXid(xid);
663 return rc;
664}
665
666int cifs_closedir(struct inode *inode, struct file *file)
667{
668 int rc = 0;
669 int xid;
670 struct cifsFileInfo *pCFileStruct =
671 (struct cifsFileInfo *)file->private_data;
672 char *ptmp;
673
Steve French26a21b92006-05-31 18:05:34 +0000674 cFYI(1, ("Closedir inode = 0x%p", inode));
Linus Torvalds1da177e2005-04-16 15:20:36 -0700675
676 xid = GetXid();
677
678 if (pCFileStruct) {
679 struct cifsTconInfo *pTcon;
Steve Frenchfb8c4b12007-07-10 01:16:18 +0000680 struct cifs_sb_info *cifs_sb =
681 CIFS_SB(file->f_path.dentry->d_sb);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700682
683 pTcon = cifs_sb->tcon;
684
685 cFYI(1, ("Freeing private data in close dir"));
Steve Frenchddb4cbf2008-11-20 20:00:44 +0000686 write_lock(&GlobalSMBSeslock);
Steve French4b18f2a2008-04-29 00:06:05 +0000687 if (!pCFileStruct->srch_inf.endOfSearch &&
688 !pCFileStruct->invalidHandle) {
689 pCFileStruct->invalidHandle = true;
Steve Frenchddb4cbf2008-11-20 20:00:44 +0000690 write_unlock(&GlobalSMBSeslock);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700691 rc = CIFSFindClose(xid, pTcon, pCFileStruct->netfid);
692 cFYI(1, ("Closing uncompleted readdir with rc %d",
693 rc));
694 /* not much we can do if it fails anyway, ignore rc */
695 rc = 0;
Steve Frenchddb4cbf2008-11-20 20:00:44 +0000696 } else
697 write_unlock(&GlobalSMBSeslock);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700698 ptmp = pCFileStruct->srch_inf.ntwrk_buf_start;
699 if (ptmp) {
Steve Frenchec637e32005-12-12 20:53:18 -0800700 cFYI(1, ("closedir free smb buf in srch struct"));
Linus Torvalds1da177e2005-04-16 15:20:36 -0700701 pCFileStruct->srch_inf.ntwrk_buf_start = NULL;
Steve Frenchfb8c4b12007-07-10 01:16:18 +0000702 if (pCFileStruct->srch_inf.smallBuf)
Steve Frenchd47d7c12006-02-28 03:45:48 +0000703 cifs_small_buf_release(ptmp);
704 else
705 cifs_buf_release(ptmp);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700706 }
Linus Torvalds1da177e2005-04-16 15:20:36 -0700707 kfree(file->private_data);
708 file->private_data = NULL;
709 }
710 /* BB can we lock the filestruct while this is going on? */
711 FreeXid(xid);
712 return rc;
713}
714
Jeremy Allison7ee1af72006-08-02 21:56:33 +0000715static int store_file_lock(struct cifsFileInfo *fid, __u64 len,
716 __u64 offset, __u8 lockType)
717{
Steve Frenchfb8c4b12007-07-10 01:16:18 +0000718 struct cifsLockInfo *li =
719 kmalloc(sizeof(struct cifsLockInfo), GFP_KERNEL);
Jeremy Allison7ee1af72006-08-02 21:56:33 +0000720 if (li == NULL)
721 return -ENOMEM;
722 li->offset = offset;
723 li->length = len;
724 li->type = lockType;
Roland Dreier796e5662007-05-03 04:33:45 +0000725 mutex_lock(&fid->lock_mutex);
Jeremy Allison7ee1af72006-08-02 21:56:33 +0000726 list_add(&li->llist, &fid->llist);
Roland Dreier796e5662007-05-03 04:33:45 +0000727 mutex_unlock(&fid->lock_mutex);
Jeremy Allison7ee1af72006-08-02 21:56:33 +0000728 return 0;
729}
730
Linus Torvalds1da177e2005-04-16 15:20:36 -0700731int cifs_lock(struct file *file, int cmd, struct file_lock *pfLock)
732{
733 int rc, xid;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700734 __u32 numLock = 0;
735 __u32 numUnlock = 0;
736 __u64 length;
Steve French4b18f2a2008-04-29 00:06:05 +0000737 bool wait_flag = false;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700738 struct cifs_sb_info *cifs_sb;
Steve French13a6e422008-12-02 17:24:33 +0000739 struct cifsTconInfo *tcon;
Steve French08547b02006-02-28 22:39:25 +0000740 __u16 netfid;
741 __u8 lockType = LOCKING_ANDX_LARGE_FILES;
Steve French13a6e422008-12-02 17:24:33 +0000742 bool posix_locking = 0;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700743
744 length = 1 + pfLock->fl_end - pfLock->fl_start;
745 rc = -EACCES;
746 xid = GetXid();
747
748 cFYI(1, ("Lock parm: 0x%x flockflags: "
749 "0x%x flocktype: 0x%x start: %lld end: %lld",
Steve Frenchfb8c4b12007-07-10 01:16:18 +0000750 cmd, pfLock->fl_flags, pfLock->fl_type, pfLock->fl_start,
751 pfLock->fl_end));
Linus Torvalds1da177e2005-04-16 15:20:36 -0700752
753 if (pfLock->fl_flags & FL_POSIX)
Steve Frenchd47d7c12006-02-28 03:45:48 +0000754 cFYI(1, ("Posix"));
Linus Torvalds1da177e2005-04-16 15:20:36 -0700755 if (pfLock->fl_flags & FL_FLOCK)
Steve Frenchd47d7c12006-02-28 03:45:48 +0000756 cFYI(1, ("Flock"));
Linus Torvalds1da177e2005-04-16 15:20:36 -0700757 if (pfLock->fl_flags & FL_SLEEP) {
Steve Frenchd47d7c12006-02-28 03:45:48 +0000758 cFYI(1, ("Blocking lock"));
Steve French4b18f2a2008-04-29 00:06:05 +0000759 wait_flag = true;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700760 }
761 if (pfLock->fl_flags & FL_ACCESS)
762 cFYI(1, ("Process suspended by mandatory locking - "
Steve French26a21b92006-05-31 18:05:34 +0000763 "not implemented yet"));
Linus Torvalds1da177e2005-04-16 15:20:36 -0700764 if (pfLock->fl_flags & FL_LEASE)
765 cFYI(1, ("Lease on file - not implemented yet"));
Steve Frenchfb8c4b12007-07-10 01:16:18 +0000766 if (pfLock->fl_flags &
Linus Torvalds1da177e2005-04-16 15:20:36 -0700767 (~(FL_POSIX | FL_FLOCK | FL_SLEEP | FL_ACCESS | FL_LEASE)))
768 cFYI(1, ("Unknown lock flags 0x%x", pfLock->fl_flags));
769
770 if (pfLock->fl_type == F_WRLCK) {
771 cFYI(1, ("F_WRLCK "));
772 numLock = 1;
773 } else if (pfLock->fl_type == F_UNLCK) {
Steve Frenchd47d7c12006-02-28 03:45:48 +0000774 cFYI(1, ("F_UNLCK"));
Linus Torvalds1da177e2005-04-16 15:20:36 -0700775 numUnlock = 1;
Steve Frenchd47d7c12006-02-28 03:45:48 +0000776 /* Check if unlock includes more than
777 one lock range */
Linus Torvalds1da177e2005-04-16 15:20:36 -0700778 } else if (pfLock->fl_type == F_RDLCK) {
Steve Frenchd47d7c12006-02-28 03:45:48 +0000779 cFYI(1, ("F_RDLCK"));
Linus Torvalds1da177e2005-04-16 15:20:36 -0700780 lockType |= LOCKING_ANDX_SHARED_LOCK;
781 numLock = 1;
782 } else if (pfLock->fl_type == F_EXLCK) {
Steve Frenchd47d7c12006-02-28 03:45:48 +0000783 cFYI(1, ("F_EXLCK"));
Linus Torvalds1da177e2005-04-16 15:20:36 -0700784 numLock = 1;
785 } else if (pfLock->fl_type == F_SHLCK) {
Steve Frenchd47d7c12006-02-28 03:45:48 +0000786 cFYI(1, ("F_SHLCK"));
Linus Torvalds1da177e2005-04-16 15:20:36 -0700787 lockType |= LOCKING_ANDX_SHARED_LOCK;
788 numLock = 1;
789 } else
Steve Frenchd47d7c12006-02-28 03:45:48 +0000790 cFYI(1, ("Unknown type of lock"));
Linus Torvalds1da177e2005-04-16 15:20:36 -0700791
Josef "Jeff" Sipeke6a00292006-12-08 02:36:48 -0800792 cifs_sb = CIFS_SB(file->f_path.dentry->d_sb);
Steve French13a6e422008-12-02 17:24:33 +0000793 tcon = cifs_sb->tcon;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700794
795 if (file->private_data == NULL) {
Suresh Jayaraman0f3bc092009-06-25 18:12:34 +0530796 rc = -EBADF;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700797 FreeXid(xid);
Suresh Jayaraman0f3bc092009-06-25 18:12:34 +0530798 return rc;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700799 }
Steve French08547b02006-02-28 22:39:25 +0000800 netfid = ((struct cifsFileInfo *)file->private_data)->netfid;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700801
Steve French13a6e422008-12-02 17:24:33 +0000802 if ((tcon->ses->capabilities & CAP_UNIX) &&
803 (CIFS_UNIX_FCNTL_CAP & le64_to_cpu(tcon->fsUnixInfo.Capability)) &&
Steve Frenchacc18aa2008-12-02 18:53:55 +0000804 ((cifs_sb->mnt_cifs_flags & CIFS_MOUNT_NOPOSIXBRL) == 0))
Steve French13a6e422008-12-02 17:24:33 +0000805 posix_locking = 1;
Steve French08547b02006-02-28 22:39:25 +0000806 /* BB add code here to normalize offset and length to
807 account for negative length which we can not accept over the
808 wire */
Linus Torvalds1da177e2005-04-16 15:20:36 -0700809 if (IS_GETLK(cmd)) {
Steve Frenchfb8c4b12007-07-10 01:16:18 +0000810 if (posix_locking) {
Steve French08547b02006-02-28 22:39:25 +0000811 int posix_lock_type;
Steve Frenchfb8c4b12007-07-10 01:16:18 +0000812 if (lockType & LOCKING_ANDX_SHARED_LOCK)
Steve French08547b02006-02-28 22:39:25 +0000813 posix_lock_type = CIFS_RDLCK;
814 else
815 posix_lock_type = CIFS_WRLCK;
Steve French13a6e422008-12-02 17:24:33 +0000816 rc = CIFSSMBPosixLock(xid, tcon, netfid, 1 /* get */,
Steve Frenchfc94cdb2006-05-30 18:03:32 +0000817 length, pfLock,
Steve French08547b02006-02-28 22:39:25 +0000818 posix_lock_type, wait_flag);
819 FreeXid(xid);
820 return rc;
821 }
822
823 /* BB we could chain these into one lock request BB */
Steve French13a6e422008-12-02 17:24:33 +0000824 rc = CIFSSMBLock(xid, tcon, netfid, length, pfLock->fl_start,
Steve French08547b02006-02-28 22:39:25 +0000825 0, 1, lockType, 0 /* wait flag */ );
Linus Torvalds1da177e2005-04-16 15:20:36 -0700826 if (rc == 0) {
Steve French13a6e422008-12-02 17:24:33 +0000827 rc = CIFSSMBLock(xid, tcon, netfid, length,
Linus Torvalds1da177e2005-04-16 15:20:36 -0700828 pfLock->fl_start, 1 /* numUnlock */ ,
829 0 /* numLock */ , lockType,
830 0 /* wait flag */ );
831 pfLock->fl_type = F_UNLCK;
832 if (rc != 0)
833 cERROR(1, ("Error unlocking previously locked "
Steve French08547b02006-02-28 22:39:25 +0000834 "range %d during test of lock", rc));
Linus Torvalds1da177e2005-04-16 15:20:36 -0700835 rc = 0;
836
837 } else {
838 /* if rc == ERR_SHARING_VIOLATION ? */
839 rc = 0; /* do not change lock type to unlock
840 since range in use */
841 }
842
843 FreeXid(xid);
844 return rc;
845 }
Jeremy Allison7ee1af72006-08-02 21:56:33 +0000846
847 if (!numLock && !numUnlock) {
848 /* if no lock or unlock then nothing
849 to do since we do not know what it is */
850 FreeXid(xid);
851 return -EOPNOTSUPP;
852 }
853
854 if (posix_locking) {
Steve French08547b02006-02-28 22:39:25 +0000855 int posix_lock_type;
Steve Frenchfb8c4b12007-07-10 01:16:18 +0000856 if (lockType & LOCKING_ANDX_SHARED_LOCK)
Steve French08547b02006-02-28 22:39:25 +0000857 posix_lock_type = CIFS_RDLCK;
858 else
859 posix_lock_type = CIFS_WRLCK;
Steve French50c2f752007-07-13 00:33:32 +0000860
Steve Frenchfb8c4b12007-07-10 01:16:18 +0000861 if (numUnlock == 1)
Steve Frenchbeb84dc2006-03-03 23:36:34 +0000862 posix_lock_type = CIFS_UNLCK;
Jeremy Allison7ee1af72006-08-02 21:56:33 +0000863
Steve French13a6e422008-12-02 17:24:33 +0000864 rc = CIFSSMBPosixLock(xid, tcon, netfid, 0 /* set */,
Steve Frenchfc94cdb2006-05-30 18:03:32 +0000865 length, pfLock,
Steve French08547b02006-02-28 22:39:25 +0000866 posix_lock_type, wait_flag);
Jeremy Allison7ee1af72006-08-02 21:56:33 +0000867 } else {
Steve Frenchfb8c4b12007-07-10 01:16:18 +0000868 struct cifsFileInfo *fid =
869 (struct cifsFileInfo *)file->private_data;
Jeremy Allison7ee1af72006-08-02 21:56:33 +0000870
871 if (numLock) {
Steve French13a6e422008-12-02 17:24:33 +0000872 rc = CIFSSMBLock(xid, tcon, netfid, length,
Steve Frenchfb8c4b12007-07-10 01:16:18 +0000873 pfLock->fl_start,
Jeremy Allison7ee1af72006-08-02 21:56:33 +0000874 0, numLock, lockType, wait_flag);
875
876 if (rc == 0) {
877 /* For Windows locks we must store them. */
878 rc = store_file_lock(fid, length,
879 pfLock->fl_start, lockType);
880 }
881 } else if (numUnlock) {
882 /* For each stored lock that this unlock overlaps
883 completely, unlock it. */
884 int stored_rc = 0;
885 struct cifsLockInfo *li, *tmp;
886
Steve French6b70c952006-09-21 07:35:29 +0000887 rc = 0;
Roland Dreier796e5662007-05-03 04:33:45 +0000888 mutex_lock(&fid->lock_mutex);
Jeremy Allison7ee1af72006-08-02 21:56:33 +0000889 list_for_each_entry_safe(li, tmp, &fid->llist, llist) {
890 if (pfLock->fl_start <= li->offset &&
Steve Frenchc19eb712007-08-24 03:22:48 +0000891 (pfLock->fl_start + length) >=
Jeff Layton39db8102007-08-24 03:16:51 +0000892 (li->offset + li->length)) {
Steve French13a6e422008-12-02 17:24:33 +0000893 stored_rc = CIFSSMBLock(xid, tcon,
Steve Frenchfb8c4b12007-07-10 01:16:18 +0000894 netfid,
Jeremy Allison7ee1af72006-08-02 21:56:33 +0000895 li->length, li->offset,
Steve French4b18f2a2008-04-29 00:06:05 +0000896 1, 0, li->type, false);
Jeremy Allison7ee1af72006-08-02 21:56:33 +0000897 if (stored_rc)
898 rc = stored_rc;
899
900 list_del(&li->llist);
901 kfree(li);
902 }
903 }
Roland Dreier796e5662007-05-03 04:33:45 +0000904 mutex_unlock(&fid->lock_mutex);
Jeremy Allison7ee1af72006-08-02 21:56:33 +0000905 }
906 }
907
Steve Frenchd634cc12005-08-26 14:42:59 -0500908 if (pfLock->fl_flags & FL_POSIX)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700909 posix_lock_file_wait(file, pfLock);
910 FreeXid(xid);
911 return rc;
912}
913
Jeff Laytonfbec9ab2009-04-03 13:44:00 -0400914/*
915 * Set the timeout on write requests past EOF. For some servers (Windows)
916 * these calls can be very long.
917 *
918 * If we're writing >10M past the EOF we give a 180s timeout. Anything less
919 * than that gets a 45s timeout. Writes not past EOF get 15s timeouts.
920 * The 10M cutoff is totally arbitrary. A better scheme for this would be
921 * welcome if someone wants to suggest one.
922 *
923 * We may be able to do a better job with this if there were some way to
924 * declare that a file should be sparse.
925 */
926static int
927cifs_write_timeout(struct cifsInodeInfo *cifsi, loff_t offset)
928{
929 if (offset <= cifsi->server_eof)
930 return CIFS_STD_OP;
931 else if (offset > (cifsi->server_eof + (10 * 1024 * 1024)))
932 return CIFS_VLONG_OP;
933 else
934 return CIFS_LONG_OP;
935}
936
937/* update the file size (if needed) after a write */
938static void
939cifs_update_eof(struct cifsInodeInfo *cifsi, loff_t offset,
940 unsigned int bytes_written)
941{
942 loff_t end_of_write = offset + bytes_written;
943
944 if (end_of_write > cifsi->server_eof)
945 cifsi->server_eof = end_of_write;
946}
947
Linus Torvalds1da177e2005-04-16 15:20:36 -0700948ssize_t cifs_user_write(struct file *file, const char __user *write_data,
949 size_t write_size, loff_t *poffset)
950{
951 int rc = 0;
952 unsigned int bytes_written = 0;
953 unsigned int total_written;
954 struct cifs_sb_info *cifs_sb;
955 struct cifsTconInfo *pTcon;
956 int xid, long_op;
957 struct cifsFileInfo *open_file;
Jeff Laytonfbec9ab2009-04-03 13:44:00 -0400958 struct cifsInodeInfo *cifsi = CIFS_I(file->f_path.dentry->d_inode);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700959
Josef "Jeff" Sipeke6a00292006-12-08 02:36:48 -0800960 cifs_sb = CIFS_SB(file->f_path.dentry->d_sb);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700961
962 pTcon = cifs_sb->tcon;
963
964 /* cFYI(1,
965 (" write %d bytes to offset %lld of %s", write_size,
Josef "Jeff" Sipeke6a00292006-12-08 02:36:48 -0800966 *poffset, file->f_path.dentry->d_name.name)); */
Linus Torvalds1da177e2005-04-16 15:20:36 -0700967
968 if (file->private_data == NULL)
969 return -EBADF;
Christoph Hellwigc33f8d32007-04-02 18:47:20 +0000970 open_file = (struct cifsFileInfo *) file->private_data;
Steve French50c2f752007-07-13 00:33:32 +0000971
Jeff Layton838726c2008-08-28 07:54:59 -0400972 rc = generic_write_checks(file, poffset, &write_size, 0);
973 if (rc)
974 return rc;
975
Linus Torvalds1da177e2005-04-16 15:20:36 -0700976 xid = GetXid();
Linus Torvalds1da177e2005-04-16 15:20:36 -0700977
Jeff Laytonfbec9ab2009-04-03 13:44:00 -0400978 long_op = cifs_write_timeout(cifsi, *poffset);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700979 for (total_written = 0; write_size > total_written;
980 total_written += bytes_written) {
981 rc = -EAGAIN;
982 while (rc == -EAGAIN) {
983 if (file->private_data == NULL) {
984 /* file has been closed on us */
985 FreeXid(xid);
986 /* if we have gotten here we have written some data
987 and blocked, and the file has been freed on us while
988 we blocked so return what we managed to write */
989 return total_written;
Steve Frenchfb8c4b12007-07-10 01:16:18 +0000990 }
Linus Torvalds1da177e2005-04-16 15:20:36 -0700991 if (open_file->closePend) {
992 FreeXid(xid);
993 if (total_written)
994 return total_written;
995 else
996 return -EBADF;
997 }
998 if (open_file->invalidHandle) {
Linus Torvalds1da177e2005-04-16 15:20:36 -0700999 /* we could deadlock if we called
1000 filemap_fdatawait from here so tell
1001 reopen_file not to flush data to server
1002 now */
Steve French4b18f2a2008-04-29 00:06:05 +00001003 rc = cifs_reopen_file(file, false);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001004 if (rc != 0)
1005 break;
1006 }
1007
1008 rc = CIFSSMBWrite(xid, pTcon,
1009 open_file->netfid,
1010 min_t(const int, cifs_sb->wsize,
1011 write_size - total_written),
1012 *poffset, &bytes_written,
1013 NULL, write_data + total_written, long_op);
1014 }
1015 if (rc || (bytes_written == 0)) {
1016 if (total_written)
1017 break;
1018 else {
1019 FreeXid(xid);
1020 return rc;
1021 }
Jeff Laytonfbec9ab2009-04-03 13:44:00 -04001022 } else {
1023 cifs_update_eof(cifsi, *poffset, bytes_written);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001024 *poffset += bytes_written;
Jeff Laytonfbec9ab2009-04-03 13:44:00 -04001025 }
Steve French133672e2007-11-13 22:41:37 +00001026 long_op = CIFS_STD_OP; /* subsequent writes fast -
Linus Torvalds1da177e2005-04-16 15:20:36 -07001027 15 seconds is plenty */
1028 }
1029
Steve Frencha45443472005-08-24 13:59:35 -07001030 cifs_stats_bytes_written(pTcon, total_written);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001031
1032 /* since the write may have blocked check these pointers again */
Steve French3677db12007-02-26 16:46:11 +00001033 if ((file->f_path.dentry) && (file->f_path.dentry->d_inode)) {
1034 struct inode *inode = file->f_path.dentry->d_inode;
Steve Frenchfb8c4b12007-07-10 01:16:18 +00001035/* Do not update local mtime - server will set its actual value on write
1036 * inode->i_ctime = inode->i_mtime =
Steve French3677db12007-02-26 16:46:11 +00001037 * current_fs_time(inode->i_sb);*/
1038 if (total_written > 0) {
1039 spin_lock(&inode->i_lock);
1040 if (*poffset > file->f_path.dentry->d_inode->i_size)
1041 i_size_write(file->f_path.dentry->d_inode,
Linus Torvalds1da177e2005-04-16 15:20:36 -07001042 *poffset);
Steve French3677db12007-02-26 16:46:11 +00001043 spin_unlock(&inode->i_lock);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001044 }
Steve Frenchfb8c4b12007-07-10 01:16:18 +00001045 mark_inode_dirty_sync(file->f_path.dentry->d_inode);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001046 }
1047 FreeXid(xid);
1048 return total_written;
1049}
1050
1051static ssize_t cifs_write(struct file *file, const char *write_data,
Nick Piggind9414772008-09-24 11:32:59 -04001052 size_t write_size, loff_t *poffset)
Linus Torvalds1da177e2005-04-16 15:20:36 -07001053{
1054 int rc = 0;
1055 unsigned int bytes_written = 0;
1056 unsigned int total_written;
1057 struct cifs_sb_info *cifs_sb;
1058 struct cifsTconInfo *pTcon;
1059 int xid, long_op;
1060 struct cifsFileInfo *open_file;
Jeff Laytonfbec9ab2009-04-03 13:44:00 -04001061 struct cifsInodeInfo *cifsi = CIFS_I(file->f_path.dentry->d_inode);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001062
Josef "Jeff" Sipeke6a00292006-12-08 02:36:48 -08001063 cifs_sb = CIFS_SB(file->f_path.dentry->d_sb);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001064
1065 pTcon = cifs_sb->tcon;
1066
Steve Frenchfb8c4b12007-07-10 01:16:18 +00001067 cFYI(1, ("write %zd bytes to offset %lld of %s", write_size,
Josef "Jeff" Sipeke6a00292006-12-08 02:36:48 -08001068 *poffset, file->f_path.dentry->d_name.name));
Linus Torvalds1da177e2005-04-16 15:20:36 -07001069
1070 if (file->private_data == NULL)
1071 return -EBADF;
Christoph Hellwigc33f8d32007-04-02 18:47:20 +00001072 open_file = (struct cifsFileInfo *)file->private_data;
Steve French50c2f752007-07-13 00:33:32 +00001073
Linus Torvalds1da177e2005-04-16 15:20:36 -07001074 xid = GetXid();
Linus Torvalds1da177e2005-04-16 15:20:36 -07001075
Jeff Laytonfbec9ab2009-04-03 13:44:00 -04001076 long_op = cifs_write_timeout(cifsi, *poffset);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001077 for (total_written = 0; write_size > total_written;
1078 total_written += bytes_written) {
1079 rc = -EAGAIN;
1080 while (rc == -EAGAIN) {
1081 if (file->private_data == NULL) {
1082 /* file has been closed on us */
1083 FreeXid(xid);
1084 /* if we have gotten here we have written some data
1085 and blocked, and the file has been freed on us
Steve Frenchfb8c4b12007-07-10 01:16:18 +00001086 while we blocked so return what we managed to
Linus Torvalds1da177e2005-04-16 15:20:36 -07001087 write */
1088 return total_written;
Steve Frenchfb8c4b12007-07-10 01:16:18 +00001089 }
Linus Torvalds1da177e2005-04-16 15:20:36 -07001090 if (open_file->closePend) {
1091 FreeXid(xid);
1092 if (total_written)
1093 return total_written;
1094 else
1095 return -EBADF;
1096 }
1097 if (open_file->invalidHandle) {
Linus Torvalds1da177e2005-04-16 15:20:36 -07001098 /* we could deadlock if we called
1099 filemap_fdatawait from here so tell
Steve Frenchfb8c4b12007-07-10 01:16:18 +00001100 reopen_file not to flush data to
Linus Torvalds1da177e2005-04-16 15:20:36 -07001101 server now */
Steve French4b18f2a2008-04-29 00:06:05 +00001102 rc = cifs_reopen_file(file, false);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001103 if (rc != 0)
1104 break;
1105 }
Steve Frenchfb8c4b12007-07-10 01:16:18 +00001106 if (experimEnabled || (pTcon->ses->server &&
1107 ((pTcon->ses->server->secMode &
Steve French08775832006-05-30 18:08:26 +00001108 (SECMODE_SIGN_REQUIRED | SECMODE_SIGN_ENABLED))
Steve Frenchc01f36a2006-05-30 18:05:10 +00001109 == 0))) {
Steve French3e844692005-10-03 13:37:24 -07001110 struct kvec iov[2];
1111 unsigned int len;
1112
Steve French0ae0efa2005-10-10 10:57:19 -07001113 len = min((size_t)cifs_sb->wsize,
Steve French3e844692005-10-03 13:37:24 -07001114 write_size - total_written);
1115 /* iov[0] is reserved for smb header */
1116 iov[1].iov_base = (char *)write_data +
1117 total_written;
1118 iov[1].iov_len = len;
Steve Frenchd6e04ae2005-06-13 13:24:43 -05001119 rc = CIFSSMBWrite2(xid, pTcon,
Steve French3e844692005-10-03 13:37:24 -07001120 open_file->netfid, len,
Steve Frenchd6e04ae2005-06-13 13:24:43 -05001121 *poffset, &bytes_written,
Steve French3e844692005-10-03 13:37:24 -07001122 iov, 1, long_op);
Steve Frenchd6e04ae2005-06-13 13:24:43 -05001123 } else
Steve French60808232006-04-22 15:53:05 +00001124 rc = CIFSSMBWrite(xid, pTcon,
1125 open_file->netfid,
1126 min_t(const int, cifs_sb->wsize,
1127 write_size - total_written),
1128 *poffset, &bytes_written,
1129 write_data + total_written,
1130 NULL, long_op);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001131 }
1132 if (rc || (bytes_written == 0)) {
1133 if (total_written)
1134 break;
1135 else {
1136 FreeXid(xid);
1137 return rc;
1138 }
Jeff Laytonfbec9ab2009-04-03 13:44:00 -04001139 } else {
1140 cifs_update_eof(cifsi, *poffset, bytes_written);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001141 *poffset += bytes_written;
Jeff Laytonfbec9ab2009-04-03 13:44:00 -04001142 }
Steve French133672e2007-11-13 22:41:37 +00001143 long_op = CIFS_STD_OP; /* subsequent writes fast -
Linus Torvalds1da177e2005-04-16 15:20:36 -07001144 15 seconds is plenty */
1145 }
1146
Steve Frencha45443472005-08-24 13:59:35 -07001147 cifs_stats_bytes_written(pTcon, total_written);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001148
1149 /* since the write may have blocked check these pointers again */
Steve French3677db12007-02-26 16:46:11 +00001150 if ((file->f_path.dentry) && (file->f_path.dentry->d_inode)) {
Steve French004c46b2007-02-17 04:34:13 +00001151/*BB We could make this contingent on superblock ATIME flag too */
Steve French3677db12007-02-26 16:46:11 +00001152/* file->f_path.dentry->d_inode->i_ctime =
1153 file->f_path.dentry->d_inode->i_mtime = CURRENT_TIME;*/
1154 if (total_written > 0) {
1155 spin_lock(&file->f_path.dentry->d_inode->i_lock);
1156 if (*poffset > file->f_path.dentry->d_inode->i_size)
1157 i_size_write(file->f_path.dentry->d_inode,
1158 *poffset);
1159 spin_unlock(&file->f_path.dentry->d_inode->i_lock);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001160 }
Steve French3677db12007-02-26 16:46:11 +00001161 mark_inode_dirty_sync(file->f_path.dentry->d_inode);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001162 }
1163 FreeXid(xid);
1164 return total_written;
1165}
1166
Steve French630f3f0c2007-10-25 21:17:17 +00001167#ifdef CONFIG_CIFS_EXPERIMENTAL
1168struct cifsFileInfo *find_readable_file(struct cifsInodeInfo *cifs_inode)
1169{
1170 struct cifsFileInfo *open_file = NULL;
1171
1172 read_lock(&GlobalSMBSeslock);
1173 /* we could simply get the first_list_entry since write-only entries
1174 are always at the end of the list but since the first entry might
1175 have a close pending, we go through the whole list */
1176 list_for_each_entry(open_file, &cifs_inode->openFileList, flist) {
1177 if (open_file->closePend)
1178 continue;
1179 if (open_file->pfile && ((open_file->pfile->f_flags & O_RDWR) ||
1180 (open_file->pfile->f_flags & O_RDONLY))) {
1181 if (!open_file->invalidHandle) {
1182 /* found a good file */
1183 /* lock it so it will not be closed on us */
Dave Kleikamp6ab409b2009-08-31 11:07:12 -04001184 cifsFileInfo_get(open_file);
Steve French630f3f0c2007-10-25 21:17:17 +00001185 read_unlock(&GlobalSMBSeslock);
1186 return open_file;
1187 } /* else might as well continue, and look for
1188 another, or simply have the caller reopen it
1189 again rather than trying to fix this handle */
1190 } else /* write only file */
1191 break; /* write only files are last so must be done */
1192 }
1193 read_unlock(&GlobalSMBSeslock);
1194 return NULL;
1195}
1196#endif
1197
Steve Frenchdd99cd82005-10-05 19:32:49 -07001198struct cifsFileInfo *find_writable_file(struct cifsInodeInfo *cifs_inode)
Steve French6148a742005-10-05 12:23:19 -07001199{
1200 struct cifsFileInfo *open_file;
Jeff Layton2846d382008-09-22 21:33:33 -04001201 bool any_available = false;
Steve Frenchdd99cd82005-10-05 19:32:49 -07001202 int rc;
Steve French6148a742005-10-05 12:23:19 -07001203
Steve French60808232006-04-22 15:53:05 +00001204 /* Having a null inode here (because mapping->host was set to zero by
1205 the VFS or MM) should not happen but we had reports of on oops (due to
1206 it being zero) during stress testcases so we need to check for it */
1207
Steve Frenchfb8c4b12007-07-10 01:16:18 +00001208 if (cifs_inode == NULL) {
1209 cERROR(1, ("Null inode passed to cifs_writeable_file"));
Steve French60808232006-04-22 15:53:05 +00001210 dump_stack();
1211 return NULL;
1212 }
1213
Steve French6148a742005-10-05 12:23:19 -07001214 read_lock(&GlobalSMBSeslock);
Steve French9b22b0b2007-10-02 01:11:08 +00001215refind_writable:
Steve French6148a742005-10-05 12:23:19 -07001216 list_for_each_entry(open_file, &cifs_inode->openFileList, flist) {
Jeff Layton2846d382008-09-22 21:33:33 -04001217 if (open_file->closePend ||
1218 (!any_available && open_file->pid != current->tgid))
Steve French6148a742005-10-05 12:23:19 -07001219 continue;
Jeff Layton2846d382008-09-22 21:33:33 -04001220
Steve French6148a742005-10-05 12:23:19 -07001221 if (open_file->pfile &&
1222 ((open_file->pfile->f_flags & O_RDWR) ||
1223 (open_file->pfile->f_flags & O_WRONLY))) {
Dave Kleikamp6ab409b2009-08-31 11:07:12 -04001224 cifsFileInfo_get(open_file);
Steve French9b22b0b2007-10-02 01:11:08 +00001225
1226 if (!open_file->invalidHandle) {
1227 /* found a good writable file */
1228 read_unlock(&GlobalSMBSeslock);
1229 return open_file;
1230 }
Steve French8840dee2007-11-16 23:05:52 +00001231
Steve French6148a742005-10-05 12:23:19 -07001232 read_unlock(&GlobalSMBSeslock);
Steve French9b22b0b2007-10-02 01:11:08 +00001233 /* Had to unlock since following call can block */
Steve French4b18f2a2008-04-29 00:06:05 +00001234 rc = cifs_reopen_file(open_file->pfile, false);
Steve French8840dee2007-11-16 23:05:52 +00001235 if (!rc) {
Steve French9b22b0b2007-10-02 01:11:08 +00001236 if (!open_file->closePend)
1237 return open_file;
1238 else { /* start over in case this was deleted */
1239 /* since the list could be modified */
Steve French37c0eb42005-10-05 14:50:29 -07001240 read_lock(&GlobalSMBSeslock);
Dave Kleikamp6ab409b2009-08-31 11:07:12 -04001241 cifsFileInfo_put(open_file);
Steve French9b22b0b2007-10-02 01:11:08 +00001242 goto refind_writable;
Steve French37c0eb42005-10-05 14:50:29 -07001243 }
1244 }
Steve French9b22b0b2007-10-02 01:11:08 +00001245
1246 /* if it fails, try another handle if possible -
1247 (we can not do this if closePending since
1248 loop could be modified - in which case we
1249 have to start at the beginning of the list
1250 again. Note that it would be bad
1251 to hold up writepages here (rather than
1252 in caller) with continuous retries */
1253 cFYI(1, ("wp failed on reopen file"));
1254 read_lock(&GlobalSMBSeslock);
1255 /* can not use this handle, no write
1256 pending on this one after all */
Dave Kleikamp6ab409b2009-08-31 11:07:12 -04001257 cifsFileInfo_put(open_file);
Steve French8840dee2007-11-16 23:05:52 +00001258
Steve French9b22b0b2007-10-02 01:11:08 +00001259 if (open_file->closePend) /* list could have changed */
1260 goto refind_writable;
1261 /* else we simply continue to the next entry. Thus
1262 we do not loop on reopen errors. If we
1263 can not reopen the file, for example if we
1264 reconnected to a server with another client
1265 racing to delete or lock the file we would not
1266 make progress if we restarted before the beginning
1267 of the loop here. */
Steve French6148a742005-10-05 12:23:19 -07001268 }
1269 }
Jeff Layton2846d382008-09-22 21:33:33 -04001270 /* couldn't find useable FH with same pid, try any available */
1271 if (!any_available) {
1272 any_available = true;
1273 goto refind_writable;
1274 }
Steve French6148a742005-10-05 12:23:19 -07001275 read_unlock(&GlobalSMBSeslock);
1276 return NULL;
1277}
1278
Linus Torvalds1da177e2005-04-16 15:20:36 -07001279static int cifs_partialpagewrite(struct page *page, unsigned from, unsigned to)
1280{
1281 struct address_space *mapping = page->mapping;
1282 loff_t offset = (loff_t)page->index << PAGE_CACHE_SHIFT;
1283 char *write_data;
1284 int rc = -EFAULT;
1285 int bytes_written = 0;
1286 struct cifs_sb_info *cifs_sb;
1287 struct cifsTconInfo *pTcon;
1288 struct inode *inode;
Steve French6148a742005-10-05 12:23:19 -07001289 struct cifsFileInfo *open_file;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001290
1291 if (!mapping || !mapping->host)
1292 return -EFAULT;
1293
1294 inode = page->mapping->host;
1295 cifs_sb = CIFS_SB(inode->i_sb);
1296 pTcon = cifs_sb->tcon;
1297
1298 offset += (loff_t)from;
1299 write_data = kmap(page);
1300 write_data += from;
1301
1302 if ((to > PAGE_CACHE_SIZE) || (from > to)) {
1303 kunmap(page);
1304 return -EIO;
1305 }
1306
1307 /* racing with truncate? */
1308 if (offset > mapping->host->i_size) {
1309 kunmap(page);
1310 return 0; /* don't care */
1311 }
1312
1313 /* check to make sure that we are not extending the file */
1314 if (mapping->host->i_size - offset < (loff_t)to)
Steve Frenchfb8c4b12007-07-10 01:16:18 +00001315 to = (unsigned)(mapping->host->i_size - offset);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001316
Steve French6148a742005-10-05 12:23:19 -07001317 open_file = find_writable_file(CIFS_I(mapping->host));
1318 if (open_file) {
1319 bytes_written = cifs_write(open_file->pfile, write_data,
1320 to-from, &offset);
Dave Kleikamp6ab409b2009-08-31 11:07:12 -04001321 cifsFileInfo_put(open_file);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001322 /* Does mm or vfs already set times? */
Steve French6148a742005-10-05 12:23:19 -07001323 inode->i_atime = inode->i_mtime = current_fs_time(inode->i_sb);
Steve Frenchbb5a9a02007-12-31 04:21:29 +00001324 if ((bytes_written > 0) && (offset))
Steve French6148a742005-10-05 12:23:19 -07001325 rc = 0;
Steve Frenchbb5a9a02007-12-31 04:21:29 +00001326 else if (bytes_written < 0)
1327 rc = bytes_written;
Steve French6148a742005-10-05 12:23:19 -07001328 } else {
Linus Torvalds1da177e2005-04-16 15:20:36 -07001329 cFYI(1, ("No writeable filehandles for inode"));
1330 rc = -EIO;
1331 }
1332
1333 kunmap(page);
1334 return rc;
1335}
1336
Linus Torvalds1da177e2005-04-16 15:20:36 -07001337static int cifs_writepages(struct address_space *mapping,
Steve French37c0eb42005-10-05 14:50:29 -07001338 struct writeback_control *wbc)
Linus Torvalds1da177e2005-04-16 15:20:36 -07001339{
Steve French37c0eb42005-10-05 14:50:29 -07001340 struct backing_dev_info *bdi = mapping->backing_dev_info;
1341 unsigned int bytes_to_write;
1342 unsigned int bytes_written;
1343 struct cifs_sb_info *cifs_sb;
1344 int done = 0;
OGAWA Hirofumi111ebb62006-06-23 02:03:26 -07001345 pgoff_t end;
Steve French37c0eb42005-10-05 14:50:29 -07001346 pgoff_t index;
Steve Frenchfb8c4b12007-07-10 01:16:18 +00001347 int range_whole = 0;
1348 struct kvec *iov;
Steve French84d2f072005-10-12 15:32:05 -07001349 int len;
Steve French37c0eb42005-10-05 14:50:29 -07001350 int n_iov = 0;
1351 pgoff_t next;
1352 int nr_pages;
1353 __u64 offset = 0;
Steve French23e7dd72005-10-20 13:44:56 -07001354 struct cifsFileInfo *open_file;
Jeff Laytonfbec9ab2009-04-03 13:44:00 -04001355 struct cifsInodeInfo *cifsi = CIFS_I(mapping->host);
Steve French37c0eb42005-10-05 14:50:29 -07001356 struct page *page;
1357 struct pagevec pvec;
1358 int rc = 0;
1359 int scanned = 0;
Jeff Laytonfbec9ab2009-04-03 13:44:00 -04001360 int xid, long_op;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001361
Steve French37c0eb42005-10-05 14:50:29 -07001362 cifs_sb = CIFS_SB(mapping->host->i_sb);
Steve French50c2f752007-07-13 00:33:32 +00001363
Steve French37c0eb42005-10-05 14:50:29 -07001364 /*
1365 * If wsize is smaller that the page cache size, default to writing
1366 * one page at a time via cifs_writepage
1367 */
1368 if (cifs_sb->wsize < PAGE_CACHE_SIZE)
1369 return generic_writepages(mapping, wbc);
1370
Steve Frenchfb8c4b12007-07-10 01:16:18 +00001371 if ((cifs_sb->tcon->ses) && (cifs_sb->tcon->ses->server))
1372 if (cifs_sb->tcon->ses->server->secMode &
1373 (SECMODE_SIGN_REQUIRED | SECMODE_SIGN_ENABLED))
1374 if (!experimEnabled)
Steve French60808232006-04-22 15:53:05 +00001375 return generic_writepages(mapping, wbc);
Steve French4a771182005-10-05 15:14:33 -07001376
Steve French9a0c8232007-02-02 04:21:57 +00001377 iov = kmalloc(32 * sizeof(struct kvec), GFP_KERNEL);
Steve Frenchfb8c4b12007-07-10 01:16:18 +00001378 if (iov == NULL)
Steve French9a0c8232007-02-02 04:21:57 +00001379 return generic_writepages(mapping, wbc);
1380
1381
Steve French37c0eb42005-10-05 14:50:29 -07001382 /*
1383 * BB: Is this meaningful for a non-block-device file system?
1384 * If it is, we should test it again after we do I/O
1385 */
1386 if (wbc->nonblocking && bdi_write_congested(bdi)) {
1387 wbc->encountered_congestion = 1;
Steve French9a0c8232007-02-02 04:21:57 +00001388 kfree(iov);
Steve French37c0eb42005-10-05 14:50:29 -07001389 return 0;
1390 }
1391
Linus Torvalds1da177e2005-04-16 15:20:36 -07001392 xid = GetXid();
1393
Steve French37c0eb42005-10-05 14:50:29 -07001394 pagevec_init(&pvec, 0);
OGAWA Hirofumi111ebb62006-06-23 02:03:26 -07001395 if (wbc->range_cyclic) {
Steve French37c0eb42005-10-05 14:50:29 -07001396 index = mapping->writeback_index; /* Start from prev offset */
OGAWA Hirofumi111ebb62006-06-23 02:03:26 -07001397 end = -1;
1398 } else {
1399 index = wbc->range_start >> PAGE_CACHE_SHIFT;
1400 end = wbc->range_end >> PAGE_CACHE_SHIFT;
1401 if (wbc->range_start == 0 && wbc->range_end == LLONG_MAX)
1402 range_whole = 1;
Steve French37c0eb42005-10-05 14:50:29 -07001403 scanned = 1;
1404 }
1405retry:
1406 while (!done && (index <= end) &&
1407 (nr_pages = pagevec_lookup_tag(&pvec, mapping, &index,
1408 PAGECACHE_TAG_DIRTY,
1409 min(end - index, (pgoff_t)PAGEVEC_SIZE - 1) + 1))) {
1410 int first;
1411 unsigned int i;
1412
Steve French37c0eb42005-10-05 14:50:29 -07001413 first = -1;
1414 next = 0;
1415 n_iov = 0;
1416 bytes_to_write = 0;
1417
1418 for (i = 0; i < nr_pages; i++) {
1419 page = pvec.pages[i];
1420 /*
1421 * At this point we hold neither mapping->tree_lock nor
1422 * lock on the page itself: the page may be truncated or
1423 * invalidated (changing page->mapping to NULL), or even
1424 * swizzled back from swapper_space to tmpfs file
1425 * mapping
1426 */
1427
1428 if (first < 0)
1429 lock_page(page);
Nick Piggin529ae9a2008-08-02 12:01:03 +02001430 else if (!trylock_page(page))
Steve French37c0eb42005-10-05 14:50:29 -07001431 break;
1432
1433 if (unlikely(page->mapping != mapping)) {
1434 unlock_page(page);
1435 break;
1436 }
1437
OGAWA Hirofumi111ebb62006-06-23 02:03:26 -07001438 if (!wbc->range_cyclic && page->index > end) {
Steve French37c0eb42005-10-05 14:50:29 -07001439 done = 1;
1440 unlock_page(page);
1441 break;
1442 }
1443
1444 if (next && (page->index != next)) {
1445 /* Not next consecutive page */
1446 unlock_page(page);
1447 break;
1448 }
1449
1450 if (wbc->sync_mode != WB_SYNC_NONE)
1451 wait_on_page_writeback(page);
1452
1453 if (PageWriteback(page) ||
Linus Torvaldscb876f42006-12-23 16:19:07 -08001454 !clear_page_dirty_for_io(page)) {
Steve French37c0eb42005-10-05 14:50:29 -07001455 unlock_page(page);
1456 break;
1457 }
Steve French84d2f072005-10-12 15:32:05 -07001458
Linus Torvaldscb876f42006-12-23 16:19:07 -08001459 /*
1460 * This actually clears the dirty bit in the radix tree.
1461 * See cifs_writepage() for more commentary.
1462 */
1463 set_page_writeback(page);
1464
Steve French84d2f072005-10-12 15:32:05 -07001465 if (page_offset(page) >= mapping->host->i_size) {
1466 done = 1;
1467 unlock_page(page);
Linus Torvaldscb876f42006-12-23 16:19:07 -08001468 end_page_writeback(page);
Steve French84d2f072005-10-12 15:32:05 -07001469 break;
1470 }
1471
Steve French37c0eb42005-10-05 14:50:29 -07001472 /*
1473 * BB can we get rid of this? pages are held by pvec
1474 */
1475 page_cache_get(page);
1476
Steve French84d2f072005-10-12 15:32:05 -07001477 len = min(mapping->host->i_size - page_offset(page),
1478 (loff_t)PAGE_CACHE_SIZE);
1479
Steve French37c0eb42005-10-05 14:50:29 -07001480 /* reserve iov[0] for the smb header */
1481 n_iov++;
1482 iov[n_iov].iov_base = kmap(page);
Steve French84d2f072005-10-12 15:32:05 -07001483 iov[n_iov].iov_len = len;
1484 bytes_to_write += len;
Steve French37c0eb42005-10-05 14:50:29 -07001485
1486 if (first < 0) {
1487 first = i;
1488 offset = page_offset(page);
1489 }
1490 next = page->index + 1;
1491 if (bytes_to_write + PAGE_CACHE_SIZE > cifs_sb->wsize)
1492 break;
1493 }
1494 if (n_iov) {
Steve French23e7dd72005-10-20 13:44:56 -07001495 /* Search for a writable handle every time we call
1496 * CIFSSMBWrite2. We can't rely on the last handle
1497 * we used to still be valid
1498 */
1499 open_file = find_writable_file(CIFS_I(mapping->host));
1500 if (!open_file) {
1501 cERROR(1, ("No writable handles for inode"));
1502 rc = -EBADF;
Steve French1047abc2005-10-11 19:58:06 -07001503 } else {
Jeff Laytonfbec9ab2009-04-03 13:44:00 -04001504 long_op = cifs_write_timeout(cifsi, offset);
Steve French23e7dd72005-10-20 13:44:56 -07001505 rc = CIFSSMBWrite2(xid, cifs_sb->tcon,
1506 open_file->netfid,
1507 bytes_to_write, offset,
1508 &bytes_written, iov, n_iov,
Jeff Laytonfbec9ab2009-04-03 13:44:00 -04001509 long_op);
Dave Kleikamp6ab409b2009-08-31 11:07:12 -04001510 cifsFileInfo_put(open_file);
Jeff Laytonfbec9ab2009-04-03 13:44:00 -04001511 cifs_update_eof(cifsi, offset, bytes_written);
1512
Steve French23e7dd72005-10-20 13:44:56 -07001513 if (rc || bytes_written < bytes_to_write) {
Steve French63135e02007-07-17 17:34:02 +00001514 cERROR(1, ("Write2 ret %d, wrote %d",
Steve French23e7dd72005-10-20 13:44:56 -07001515 rc, bytes_written));
1516 /* BB what if continued retry is
1517 requested via mount flags? */
Jeff Laytoncea21802007-11-20 23:19:03 +00001518 if (rc == -ENOSPC)
1519 set_bit(AS_ENOSPC, &mapping->flags);
1520 else
1521 set_bit(AS_EIO, &mapping->flags);
Steve French23e7dd72005-10-20 13:44:56 -07001522 } else {
1523 cifs_stats_bytes_written(cifs_sb->tcon,
1524 bytes_written);
1525 }
Steve French37c0eb42005-10-05 14:50:29 -07001526 }
1527 for (i = 0; i < n_iov; i++) {
1528 page = pvec.pages[first + i];
Steve Frencheb9bdaa2006-01-27 15:11:47 -08001529 /* Should we also set page error on
1530 success rc but too little data written? */
1531 /* BB investigate retry logic on temporary
1532 server crash cases and how recovery works
Steve Frenchfb8c4b12007-07-10 01:16:18 +00001533 when page marked as error */
1534 if (rc)
Steve Frencheb9bdaa2006-01-27 15:11:47 -08001535 SetPageError(page);
Steve French37c0eb42005-10-05 14:50:29 -07001536 kunmap(page);
1537 unlock_page(page);
Linus Torvaldscb876f42006-12-23 16:19:07 -08001538 end_page_writeback(page);
Steve French37c0eb42005-10-05 14:50:29 -07001539 page_cache_release(page);
1540 }
1541 if ((wbc->nr_to_write -= n_iov) <= 0)
1542 done = 1;
1543 index = next;
Dave Kleikampb066a482008-11-18 03:49:05 +00001544 } else
1545 /* Need to re-find the pages we skipped */
1546 index = pvec.pages[0]->index + 1;
1547
Steve French37c0eb42005-10-05 14:50:29 -07001548 pagevec_release(&pvec);
1549 }
1550 if (!scanned && !done) {
1551 /*
1552 * We hit the last page and there is more work to be done: wrap
1553 * back to the start of the file
1554 */
1555 scanned = 1;
1556 index = 0;
1557 goto retry;
1558 }
OGAWA Hirofumi111ebb62006-06-23 02:03:26 -07001559 if (wbc->range_cyclic || (range_whole && wbc->nr_to_write > 0))
Steve French37c0eb42005-10-05 14:50:29 -07001560 mapping->writeback_index = index;
1561
Linus Torvalds1da177e2005-04-16 15:20:36 -07001562 FreeXid(xid);
Steve French9a0c8232007-02-02 04:21:57 +00001563 kfree(iov);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001564 return rc;
1565}
Linus Torvalds1da177e2005-04-16 15:20:36 -07001566
Steve Frenchfb8c4b12007-07-10 01:16:18 +00001567static int cifs_writepage(struct page *page, struct writeback_control *wbc)
Linus Torvalds1da177e2005-04-16 15:20:36 -07001568{
1569 int rc = -EFAULT;
1570 int xid;
1571
1572 xid = GetXid();
1573/* BB add check for wbc flags */
1574 page_cache_get(page);
Steve Frenchad7a2922008-02-07 23:25:02 +00001575 if (!PageUptodate(page))
Linus Torvalds1da177e2005-04-16 15:20:36 -07001576 cFYI(1, ("ppw - page not up to date"));
Linus Torvaldscb876f42006-12-23 16:19:07 -08001577
1578 /*
1579 * Set the "writeback" flag, and clear "dirty" in the radix tree.
1580 *
1581 * A writepage() implementation always needs to do either this,
1582 * or re-dirty the page with "redirty_page_for_writepage()" in
1583 * the case of a failure.
1584 *
1585 * Just unlocking the page will cause the radix tree tag-bits
1586 * to fail to update with the state of the page correctly.
1587 */
Steve Frenchfb8c4b12007-07-10 01:16:18 +00001588 set_page_writeback(page);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001589 rc = cifs_partialpagewrite(page, 0, PAGE_CACHE_SIZE);
1590 SetPageUptodate(page); /* BB add check for error and Clearuptodate? */
1591 unlock_page(page);
Linus Torvaldscb876f42006-12-23 16:19:07 -08001592 end_page_writeback(page);
1593 page_cache_release(page);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001594 FreeXid(xid);
1595 return rc;
1596}
1597
Nick Piggind9414772008-09-24 11:32:59 -04001598static int cifs_write_end(struct file *file, struct address_space *mapping,
1599 loff_t pos, unsigned len, unsigned copied,
1600 struct page *page, void *fsdata)
Linus Torvalds1da177e2005-04-16 15:20:36 -07001601{
Nick Piggind9414772008-09-24 11:32:59 -04001602 int rc;
1603 struct inode *inode = mapping->host;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001604
Nick Piggind9414772008-09-24 11:32:59 -04001605 cFYI(1, ("write_end for page %p from pos %lld with %d bytes",
1606 page, pos, copied));
Steve Frenchad7a2922008-02-07 23:25:02 +00001607
Jeff Laytona98ee8c2008-11-26 19:32:33 +00001608 if (PageChecked(page)) {
1609 if (copied == len)
1610 SetPageUptodate(page);
1611 ClearPageChecked(page);
1612 } else if (!PageUptodate(page) && copied == PAGE_CACHE_SIZE)
Nick Piggind9414772008-09-24 11:32:59 -04001613 SetPageUptodate(page);
1614
Linus Torvalds1da177e2005-04-16 15:20:36 -07001615 if (!PageUptodate(page)) {
Nick Piggind9414772008-09-24 11:32:59 -04001616 char *page_data;
1617 unsigned offset = pos & (PAGE_CACHE_SIZE - 1);
1618 int xid;
1619
1620 xid = GetXid();
Linus Torvalds1da177e2005-04-16 15:20:36 -07001621 /* this is probably better than directly calling
1622 partialpage_write since in this function the file handle is
1623 known which we might as well leverage */
1624 /* BB check if anything else missing out of ppw
1625 such as updating last write time */
1626 page_data = kmap(page);
Nick Piggind9414772008-09-24 11:32:59 -04001627 rc = cifs_write(file, page_data + offset, copied, &pos);
1628 /* if (rc < 0) should we set writebehind rc? */
Linus Torvalds1da177e2005-04-16 15:20:36 -07001629 kunmap(page);
Nick Piggind9414772008-09-24 11:32:59 -04001630
1631 FreeXid(xid);
Steve Frenchfb8c4b12007-07-10 01:16:18 +00001632 } else {
Nick Piggind9414772008-09-24 11:32:59 -04001633 rc = copied;
1634 pos += copied;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001635 set_page_dirty(page);
1636 }
1637
Nick Piggind9414772008-09-24 11:32:59 -04001638 if (rc > 0) {
1639 spin_lock(&inode->i_lock);
1640 if (pos > inode->i_size)
1641 i_size_write(inode, pos);
1642 spin_unlock(&inode->i_lock);
1643 }
1644
1645 unlock_page(page);
1646 page_cache_release(page);
1647
Linus Torvalds1da177e2005-04-16 15:20:36 -07001648 return rc;
1649}
1650
1651int cifs_fsync(struct file *file, struct dentry *dentry, int datasync)
1652{
1653 int xid;
1654 int rc = 0;
Steve Frenchb298f222009-02-21 21:17:43 +00001655 struct cifsTconInfo *tcon;
1656 struct cifsFileInfo *smbfile =
1657 (struct cifsFileInfo *)file->private_data;
Josef "Jeff" Sipeke6a00292006-12-08 02:36:48 -08001658 struct inode *inode = file->f_path.dentry->d_inode;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001659
1660 xid = GetXid();
1661
Steve Frenchfb8c4b12007-07-10 01:16:18 +00001662 cFYI(1, ("Sync file - name: %s datasync: 0x%x",
Linus Torvalds1da177e2005-04-16 15:20:36 -07001663 dentry->d_name.name, datasync));
Steve French50c2f752007-07-13 00:33:32 +00001664
Jeff Laytoncea21802007-11-20 23:19:03 +00001665 rc = filemap_write_and_wait(inode->i_mapping);
1666 if (rc == 0) {
1667 rc = CIFS_I(inode)->write_behind_rc;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001668 CIFS_I(inode)->write_behind_rc = 0;
Steve Frenchb298f222009-02-21 21:17:43 +00001669 tcon = CIFS_SB(inode->i_sb)->tcon;
Steve Frenchbe652442009-02-23 15:21:59 +00001670 if (!rc && tcon && smbfile &&
Steve French4717bed2009-02-24 14:44:19 +00001671 !(CIFS_SB(inode->i_sb)->mnt_cifs_flags & CIFS_MOUNT_NOSSYNC))
Steve Frenchb298f222009-02-21 21:17:43 +00001672 rc = CIFSSMBFlush(xid, tcon, smbfile->netfid);
Jeff Laytoncea21802007-11-20 23:19:03 +00001673 }
Steve Frenchb298f222009-02-21 21:17:43 +00001674
Linus Torvalds1da177e2005-04-16 15:20:36 -07001675 FreeXid(xid);
1676 return rc;
1677}
1678
NeilBrown3978d712006-03-26 01:37:17 -08001679/* static void cifs_sync_page(struct page *page)
Linus Torvalds1da177e2005-04-16 15:20:36 -07001680{
1681 struct address_space *mapping;
1682 struct inode *inode;
1683 unsigned long index = page->index;
1684 unsigned int rpages = 0;
1685 int rc = 0;
1686
1687 cFYI(1, ("sync page %p",page));
1688 mapping = page->mapping;
1689 if (!mapping)
1690 return 0;
1691 inode = mapping->host;
1692 if (!inode)
NeilBrown3978d712006-03-26 01:37:17 -08001693 return; */
Linus Torvalds1da177e2005-04-16 15:20:36 -07001694
Steve Frenchfb8c4b12007-07-10 01:16:18 +00001695/* fill in rpages then
Linus Torvalds1da177e2005-04-16 15:20:36 -07001696 result = cifs_pagein_inode(inode, index, rpages); */ /* BB finish */
1697
Steve French26a21b92006-05-31 18:05:34 +00001698/* cFYI(1, ("rpages is %d for sync page of Index %ld", rpages, index));
Linus Torvalds1da177e2005-04-16 15:20:36 -07001699
NeilBrown3978d712006-03-26 01:37:17 -08001700#if 0
Linus Torvalds1da177e2005-04-16 15:20:36 -07001701 if (rc < 0)
1702 return rc;
1703 return 0;
NeilBrown3978d712006-03-26 01:37:17 -08001704#endif
Linus Torvalds1da177e2005-04-16 15:20:36 -07001705} */
1706
1707/*
1708 * As file closes, flush all cached write data for this inode checking
1709 * for write behind errors.
1710 */
Miklos Szeredi75e1fcc2006-06-23 02:05:12 -07001711int cifs_flush(struct file *file, fl_owner_t id)
Linus Torvalds1da177e2005-04-16 15:20:36 -07001712{
Steve Frenchfb8c4b12007-07-10 01:16:18 +00001713 struct inode *inode = file->f_path.dentry->d_inode;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001714 int rc = 0;
1715
1716 /* Rather than do the steps manually:
1717 lock the inode for writing
1718 loop through pages looking for write behind data (dirty pages)
1719 coalesce into contiguous 16K (or smaller) chunks to write to server
1720 send to server (prefer in parallel)
1721 deal with writebehind errors
1722 unlock inode for writing
1723 filemapfdatawrite appears easier for the time being */
1724
1725 rc = filemap_fdatawrite(inode->i_mapping);
Jeff Laytoncea21802007-11-20 23:19:03 +00001726 /* reset wb rc if we were able to write out dirty pages */
1727 if (!rc) {
1728 rc = CIFS_I(inode)->write_behind_rc;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001729 CIFS_I(inode)->write_behind_rc = 0;
Jeff Laytoncea21802007-11-20 23:19:03 +00001730 }
Steve French50c2f752007-07-13 00:33:32 +00001731
Steve Frenchfb8c4b12007-07-10 01:16:18 +00001732 cFYI(1, ("Flush inode %p file %p rc %d", inode, file, rc));
Linus Torvalds1da177e2005-04-16 15:20:36 -07001733
1734 return rc;
1735}
1736
1737ssize_t cifs_user_read(struct file *file, char __user *read_data,
1738 size_t read_size, loff_t *poffset)
1739{
1740 int rc = -EACCES;
1741 unsigned int bytes_read = 0;
1742 unsigned int total_read = 0;
1743 unsigned int current_read_size;
1744 struct cifs_sb_info *cifs_sb;
1745 struct cifsTconInfo *pTcon;
1746 int xid;
1747 struct cifsFileInfo *open_file;
1748 char *smb_read_data;
1749 char __user *current_offset;
1750 struct smb_com_read_rsp *pSMBr;
1751
1752 xid = GetXid();
Josef "Jeff" Sipeke6a00292006-12-08 02:36:48 -08001753 cifs_sb = CIFS_SB(file->f_path.dentry->d_sb);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001754 pTcon = cifs_sb->tcon;
1755
1756 if (file->private_data == NULL) {
Suresh Jayaraman0f3bc092009-06-25 18:12:34 +05301757 rc = -EBADF;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001758 FreeXid(xid);
Suresh Jayaraman0f3bc092009-06-25 18:12:34 +05301759 return rc;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001760 }
1761 open_file = (struct cifsFileInfo *)file->private_data;
1762
Steve Frenchad7a2922008-02-07 23:25:02 +00001763 if ((file->f_flags & O_ACCMODE) == O_WRONLY)
Linus Torvalds1da177e2005-04-16 15:20:36 -07001764 cFYI(1, ("attempting read on write only file instance"));
Steve Frenchad7a2922008-02-07 23:25:02 +00001765
Linus Torvalds1da177e2005-04-16 15:20:36 -07001766 for (total_read = 0, current_offset = read_data;
1767 read_size > total_read;
1768 total_read += bytes_read, current_offset += bytes_read) {
Steve Frenchfb8c4b12007-07-10 01:16:18 +00001769 current_read_size = min_t(const int, read_size - total_read,
Linus Torvalds1da177e2005-04-16 15:20:36 -07001770 cifs_sb->rsize);
1771 rc = -EAGAIN;
1772 smb_read_data = NULL;
1773 while (rc == -EAGAIN) {
Steve Frenchec637e32005-12-12 20:53:18 -08001774 int buf_type = CIFS_NO_BUFFER;
Steve Frenchfb8c4b12007-07-10 01:16:18 +00001775 if ((open_file->invalidHandle) &&
Linus Torvalds1da177e2005-04-16 15:20:36 -07001776 (!open_file->closePend)) {
Steve French4b18f2a2008-04-29 00:06:05 +00001777 rc = cifs_reopen_file(file, true);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001778 if (rc != 0)
1779 break;
1780 }
Steve Frenchbfa0d752005-08-31 21:50:37 -07001781 rc = CIFSSMBRead(xid, pTcon,
Steve Frenchec637e32005-12-12 20:53:18 -08001782 open_file->netfid,
1783 current_read_size, *poffset,
1784 &bytes_read, &smb_read_data,
1785 &buf_type);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001786 pSMBr = (struct smb_com_read_rsp *)smb_read_data;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001787 if (smb_read_data) {
Steve French93544cc2006-02-14 22:30:52 -06001788 if (copy_to_user(current_offset,
1789 smb_read_data +
1790 4 /* RFC1001 length field */ +
1791 le16_to_cpu(pSMBr->DataOffset),
Steve Frenchad7a2922008-02-07 23:25:02 +00001792 bytes_read))
Steve French93544cc2006-02-14 22:30:52 -06001793 rc = -EFAULT;
Steve French93544cc2006-02-14 22:30:52 -06001794
Steve Frenchfb8c4b12007-07-10 01:16:18 +00001795 if (buf_type == CIFS_SMALL_BUFFER)
Steve Frenchec637e32005-12-12 20:53:18 -08001796 cifs_small_buf_release(smb_read_data);
Steve Frenchfb8c4b12007-07-10 01:16:18 +00001797 else if (buf_type == CIFS_LARGE_BUFFER)
Steve Frenchec637e32005-12-12 20:53:18 -08001798 cifs_buf_release(smb_read_data);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001799 smb_read_data = NULL;
1800 }
1801 }
1802 if (rc || (bytes_read == 0)) {
1803 if (total_read) {
1804 break;
1805 } else {
1806 FreeXid(xid);
1807 return rc;
1808 }
1809 } else {
Steve Frencha45443472005-08-24 13:59:35 -07001810 cifs_stats_bytes_read(pTcon, bytes_read);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001811 *poffset += bytes_read;
1812 }
1813 }
1814 FreeXid(xid);
1815 return total_read;
1816}
1817
1818
1819static ssize_t cifs_read(struct file *file, char *read_data, size_t read_size,
1820 loff_t *poffset)
1821{
1822 int rc = -EACCES;
1823 unsigned int bytes_read = 0;
1824 unsigned int total_read;
1825 unsigned int current_read_size;
1826 struct cifs_sb_info *cifs_sb;
1827 struct cifsTconInfo *pTcon;
1828 int xid;
1829 char *current_offset;
1830 struct cifsFileInfo *open_file;
Steve Frenchec637e32005-12-12 20:53:18 -08001831 int buf_type = CIFS_NO_BUFFER;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001832
1833 xid = GetXid();
Josef "Jeff" Sipeke6a00292006-12-08 02:36:48 -08001834 cifs_sb = CIFS_SB(file->f_path.dentry->d_sb);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001835 pTcon = cifs_sb->tcon;
1836
1837 if (file->private_data == NULL) {
Suresh Jayaraman0f3bc092009-06-25 18:12:34 +05301838 rc = -EBADF;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001839 FreeXid(xid);
Suresh Jayaraman0f3bc092009-06-25 18:12:34 +05301840 return rc;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001841 }
1842 open_file = (struct cifsFileInfo *)file->private_data;
1843
1844 if ((file->f_flags & O_ACCMODE) == O_WRONLY)
1845 cFYI(1, ("attempting read on write only file instance"));
1846
Steve Frenchfb8c4b12007-07-10 01:16:18 +00001847 for (total_read = 0, current_offset = read_data;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001848 read_size > total_read;
1849 total_read += bytes_read, current_offset += bytes_read) {
1850 current_read_size = min_t(const int, read_size - total_read,
1851 cifs_sb->rsize);
Steve Frenchf9f5c8172005-09-15 23:06:38 -07001852 /* For windows me and 9x we do not want to request more
1853 than it negotiated since it will refuse the read then */
Steve Frenchfb8c4b12007-07-10 01:16:18 +00001854 if ((pTcon->ses) &&
Steve Frenchf9f5c8172005-09-15 23:06:38 -07001855 !(pTcon->ses->capabilities & CAP_LARGE_FILES)) {
1856 current_read_size = min_t(const int, current_read_size,
1857 pTcon->ses->server->maxBuf - 128);
1858 }
Linus Torvalds1da177e2005-04-16 15:20:36 -07001859 rc = -EAGAIN;
1860 while (rc == -EAGAIN) {
Steve Frenchfb8c4b12007-07-10 01:16:18 +00001861 if ((open_file->invalidHandle) &&
Linus Torvalds1da177e2005-04-16 15:20:36 -07001862 (!open_file->closePend)) {
Steve French4b18f2a2008-04-29 00:06:05 +00001863 rc = cifs_reopen_file(file, true);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001864 if (rc != 0)
1865 break;
1866 }
Steve Frenchbfa0d752005-08-31 21:50:37 -07001867 rc = CIFSSMBRead(xid, pTcon,
Steve Frenchec637e32005-12-12 20:53:18 -08001868 open_file->netfid,
1869 current_read_size, *poffset,
1870 &bytes_read, &current_offset,
1871 &buf_type);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001872 }
1873 if (rc || (bytes_read == 0)) {
1874 if (total_read) {
1875 break;
1876 } else {
1877 FreeXid(xid);
1878 return rc;
1879 }
1880 } else {
Steve Frencha45443472005-08-24 13:59:35 -07001881 cifs_stats_bytes_read(pTcon, total_read);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001882 *poffset += bytes_read;
1883 }
1884 }
1885 FreeXid(xid);
1886 return total_read;
1887}
1888
1889int cifs_file_mmap(struct file *file, struct vm_area_struct *vma)
1890{
Josef "Jeff" Sipeke6a00292006-12-08 02:36:48 -08001891 struct dentry *dentry = file->f_path.dentry;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001892 int rc, xid;
1893
1894 xid = GetXid();
1895 rc = cifs_revalidate(dentry);
1896 if (rc) {
1897 cFYI(1, ("Validation prior to mmap failed, error=%d", rc));
1898 FreeXid(xid);
1899 return rc;
1900 }
1901 rc = generic_file_mmap(file, vma);
1902 FreeXid(xid);
1903 return rc;
1904}
1905
1906
Steve Frenchfb8c4b12007-07-10 01:16:18 +00001907static void cifs_copy_cache_pages(struct address_space *mapping,
Linus Torvalds1da177e2005-04-16 15:20:36 -07001908 struct list_head *pages, int bytes_read, char *data,
1909 struct pagevec *plru_pvec)
1910{
1911 struct page *page;
1912 char *target;
1913
1914 while (bytes_read > 0) {
1915 if (list_empty(pages))
1916 break;
1917
1918 page = list_entry(pages->prev, struct page, lru);
1919 list_del(&page->lru);
1920
1921 if (add_to_page_cache(page, mapping, page->index,
1922 GFP_KERNEL)) {
1923 page_cache_release(page);
1924 cFYI(1, ("Add page cache failed"));
Steve French3079ca62005-06-09 14:44:07 -07001925 data += PAGE_CACHE_SIZE;
1926 bytes_read -= PAGE_CACHE_SIZE;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001927 continue;
1928 }
1929
Steve Frenchfb8c4b12007-07-10 01:16:18 +00001930 target = kmap_atomic(page, KM_USER0);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001931
1932 if (PAGE_CACHE_SIZE > bytes_read) {
1933 memcpy(target, data, bytes_read);
1934 /* zero the tail end of this partial page */
Steve Frenchfb8c4b12007-07-10 01:16:18 +00001935 memset(target + bytes_read, 0,
Linus Torvalds1da177e2005-04-16 15:20:36 -07001936 PAGE_CACHE_SIZE - bytes_read);
1937 bytes_read = 0;
1938 } else {
1939 memcpy(target, data, PAGE_CACHE_SIZE);
1940 bytes_read -= PAGE_CACHE_SIZE;
1941 }
1942 kunmap_atomic(target, KM_USER0);
1943
1944 flush_dcache_page(page);
1945 SetPageUptodate(page);
1946 unlock_page(page);
1947 if (!pagevec_add(plru_pvec, page))
Rik van Riel4f98a2f2008-10-18 20:26:32 -07001948 __pagevec_lru_add_file(plru_pvec);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001949 data += PAGE_CACHE_SIZE;
1950 }
1951 return;
1952}
1953
1954static int cifs_readpages(struct file *file, struct address_space *mapping,
1955 struct list_head *page_list, unsigned num_pages)
1956{
1957 int rc = -EACCES;
1958 int xid;
1959 loff_t offset;
1960 struct page *page;
1961 struct cifs_sb_info *cifs_sb;
1962 struct cifsTconInfo *pTcon;
Steve French2c2130e2007-10-12 19:10:28 +00001963 unsigned int bytes_read = 0;
Steve Frenchfb8c4b12007-07-10 01:16:18 +00001964 unsigned int read_size, i;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001965 char *smb_read_data = NULL;
1966 struct smb_com_read_rsp *pSMBr;
1967 struct pagevec lru_pvec;
1968 struct cifsFileInfo *open_file;
Steve Frenchec637e32005-12-12 20:53:18 -08001969 int buf_type = CIFS_NO_BUFFER;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001970
1971 xid = GetXid();
1972 if (file->private_data == NULL) {
Suresh Jayaraman0f3bc092009-06-25 18:12:34 +05301973 rc = -EBADF;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001974 FreeXid(xid);
Suresh Jayaraman0f3bc092009-06-25 18:12:34 +05301975 return rc;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001976 }
1977 open_file = (struct cifsFileInfo *)file->private_data;
Josef "Jeff" Sipeke6a00292006-12-08 02:36:48 -08001978 cifs_sb = CIFS_SB(file->f_path.dentry->d_sb);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001979 pTcon = cifs_sb->tcon;
Steve Frenchbfa0d752005-08-31 21:50:37 -07001980
Linus Torvalds1da177e2005-04-16 15:20:36 -07001981 pagevec_init(&lru_pvec, 0);
Steve French61de8002008-10-30 20:15:22 +00001982 cFYI(DBG2, ("rpages: num pages %d", num_pages));
Linus Torvalds1da177e2005-04-16 15:20:36 -07001983 for (i = 0; i < num_pages; ) {
1984 unsigned contig_pages;
1985 struct page *tmp_page;
1986 unsigned long expected_index;
1987
1988 if (list_empty(page_list))
1989 break;
1990
1991 page = list_entry(page_list->prev, struct page, lru);
1992 offset = (loff_t)page->index << PAGE_CACHE_SHIFT;
1993
1994 /* count adjacent pages that we will read into */
1995 contig_pages = 0;
Steve Frenchfb8c4b12007-07-10 01:16:18 +00001996 expected_index =
Linus Torvalds1da177e2005-04-16 15:20:36 -07001997 list_entry(page_list->prev, struct page, lru)->index;
Steve Frenchfb8c4b12007-07-10 01:16:18 +00001998 list_for_each_entry_reverse(tmp_page, page_list, lru) {
Linus Torvalds1da177e2005-04-16 15:20:36 -07001999 if (tmp_page->index == expected_index) {
2000 contig_pages++;
2001 expected_index++;
2002 } else
Steve Frenchfb8c4b12007-07-10 01:16:18 +00002003 break;
Linus Torvalds1da177e2005-04-16 15:20:36 -07002004 }
2005 if (contig_pages + i > num_pages)
2006 contig_pages = num_pages - i;
2007
2008 /* for reads over a certain size could initiate async
2009 read ahead */
2010
2011 read_size = contig_pages * PAGE_CACHE_SIZE;
2012 /* Read size needs to be in multiples of one page */
2013 read_size = min_t(const unsigned int, read_size,
2014 cifs_sb->rsize & PAGE_CACHE_MASK);
Steve French90c81e02008-02-12 20:32:36 +00002015 cFYI(DBG2, ("rpages: read size 0x%x contiguous pages %d",
Steve French75865f8c2007-06-24 18:30:48 +00002016 read_size, contig_pages));
Linus Torvalds1da177e2005-04-16 15:20:36 -07002017 rc = -EAGAIN;
2018 while (rc == -EAGAIN) {
Steve Frenchfb8c4b12007-07-10 01:16:18 +00002019 if ((open_file->invalidHandle) &&
Linus Torvalds1da177e2005-04-16 15:20:36 -07002020 (!open_file->closePend)) {
Steve French4b18f2a2008-04-29 00:06:05 +00002021 rc = cifs_reopen_file(file, true);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002022 if (rc != 0)
2023 break;
2024 }
2025
Steve Frenchbfa0d752005-08-31 21:50:37 -07002026 rc = CIFSSMBRead(xid, pTcon,
Steve Frenchec637e32005-12-12 20:53:18 -08002027 open_file->netfid,
2028 read_size, offset,
2029 &bytes_read, &smb_read_data,
2030 &buf_type);
Steve Frencha9d02ad2005-08-24 23:06:05 -07002031 /* BB more RC checks ? */
Steve Frenchfb8c4b12007-07-10 01:16:18 +00002032 if (rc == -EAGAIN) {
Linus Torvalds1da177e2005-04-16 15:20:36 -07002033 if (smb_read_data) {
Steve Frenchfb8c4b12007-07-10 01:16:18 +00002034 if (buf_type == CIFS_SMALL_BUFFER)
Steve Frenchec637e32005-12-12 20:53:18 -08002035 cifs_small_buf_release(smb_read_data);
Steve Frenchfb8c4b12007-07-10 01:16:18 +00002036 else if (buf_type == CIFS_LARGE_BUFFER)
Steve Frenchec637e32005-12-12 20:53:18 -08002037 cifs_buf_release(smb_read_data);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002038 smb_read_data = NULL;
2039 }
2040 }
2041 }
2042 if ((rc < 0) || (smb_read_data == NULL)) {
2043 cFYI(1, ("Read error in readpages: %d", rc));
Linus Torvalds1da177e2005-04-16 15:20:36 -07002044 break;
2045 } else if (bytes_read > 0) {
Andrew Morton6f88cc22006-12-10 02:19:44 -08002046 task_io_account_read(bytes_read);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002047 pSMBr = (struct smb_com_read_rsp *)smb_read_data;
2048 cifs_copy_cache_pages(mapping, page_list, bytes_read,
2049 smb_read_data + 4 /* RFC1001 hdr */ +
2050 le16_to_cpu(pSMBr->DataOffset), &lru_pvec);
2051
2052 i += bytes_read >> PAGE_CACHE_SHIFT;
Steve Frencha45443472005-08-24 13:59:35 -07002053 cifs_stats_bytes_read(pTcon, bytes_read);
Steve French2c2130e2007-10-12 19:10:28 +00002054 if ((bytes_read & PAGE_CACHE_MASK) != bytes_read) {
Linus Torvalds1da177e2005-04-16 15:20:36 -07002055 i++; /* account for partial page */
2056
Steve Frenchfb8c4b12007-07-10 01:16:18 +00002057 /* server copy of file can have smaller size
Linus Torvalds1da177e2005-04-16 15:20:36 -07002058 than client */
Steve Frenchfb8c4b12007-07-10 01:16:18 +00002059 /* BB do we need to verify this common case ?
2060 this case is ok - if we are at server EOF
Linus Torvalds1da177e2005-04-16 15:20:36 -07002061 we will hit it on next read */
2062
OGAWA Hirofumi05ac9d42006-11-02 22:07:08 -08002063 /* break; */
Linus Torvalds1da177e2005-04-16 15:20:36 -07002064 }
2065 } else {
2066 cFYI(1, ("No bytes read (%d) at offset %lld . "
2067 "Cleaning remaining pages from readahead list",
2068 bytes_read, offset));
Steve Frenchfb8c4b12007-07-10 01:16:18 +00002069 /* BB turn off caching and do new lookup on
Linus Torvalds1da177e2005-04-16 15:20:36 -07002070 file size at server? */
Linus Torvalds1da177e2005-04-16 15:20:36 -07002071 break;
2072 }
2073 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 bytes_read = 0;
2081 }
2082
Rik van Riel4f98a2f2008-10-18 20:26:32 -07002083 pagevec_lru_add_file(&lru_pvec);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002084
2085/* need to free smb_read_data buf before exit */
2086 if (smb_read_data) {
Steve Frenchfb8c4b12007-07-10 01:16:18 +00002087 if (buf_type == CIFS_SMALL_BUFFER)
Steve French47c886b2006-01-18 14:20:39 -08002088 cifs_small_buf_release(smb_read_data);
Steve Frenchfb8c4b12007-07-10 01:16:18 +00002089 else if (buf_type == CIFS_LARGE_BUFFER)
Steve French47c886b2006-01-18 14:20:39 -08002090 cifs_buf_release(smb_read_data);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002091 smb_read_data = NULL;
Steve Frenchfb8c4b12007-07-10 01:16:18 +00002092 }
Linus Torvalds1da177e2005-04-16 15:20:36 -07002093
2094 FreeXid(xid);
2095 return rc;
2096}
2097
2098static int cifs_readpage_worker(struct file *file, struct page *page,
2099 loff_t *poffset)
2100{
2101 char *read_data;
2102 int rc;
2103
2104 page_cache_get(page);
2105 read_data = kmap(page);
2106 /* for reads over a certain size could initiate async read ahead */
Steve Frenchfb8c4b12007-07-10 01:16:18 +00002107
Linus Torvalds1da177e2005-04-16 15:20:36 -07002108 rc = cifs_read(file, read_data, PAGE_CACHE_SIZE, poffset);
Steve Frenchfb8c4b12007-07-10 01:16:18 +00002109
Linus Torvalds1da177e2005-04-16 15:20:36 -07002110 if (rc < 0)
2111 goto io_error;
2112 else
Steve Frenchfb8c4b12007-07-10 01:16:18 +00002113 cFYI(1, ("Bytes read %d", rc));
2114
Josef "Jeff" Sipeke6a00292006-12-08 02:36:48 -08002115 file->f_path.dentry->d_inode->i_atime =
2116 current_fs_time(file->f_path.dentry->d_inode->i_sb);
Steve Frenchfb8c4b12007-07-10 01:16:18 +00002117
Linus Torvalds1da177e2005-04-16 15:20:36 -07002118 if (PAGE_CACHE_SIZE > rc)
2119 memset(read_data + rc, 0, PAGE_CACHE_SIZE - rc);
2120
2121 flush_dcache_page(page);
2122 SetPageUptodate(page);
2123 rc = 0;
Steve Frenchfb8c4b12007-07-10 01:16:18 +00002124
Linus Torvalds1da177e2005-04-16 15:20:36 -07002125io_error:
Steve Frenchfb8c4b12007-07-10 01:16:18 +00002126 kunmap(page);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002127 page_cache_release(page);
2128 return rc;
2129}
2130
2131static int cifs_readpage(struct file *file, struct page *page)
2132{
2133 loff_t offset = (loff_t)page->index << PAGE_CACHE_SHIFT;
2134 int rc = -EACCES;
2135 int xid;
2136
2137 xid = GetXid();
2138
2139 if (file->private_data == NULL) {
Suresh Jayaraman0f3bc092009-06-25 18:12:34 +05302140 rc = -EBADF;
Linus Torvalds1da177e2005-04-16 15:20:36 -07002141 FreeXid(xid);
Suresh Jayaraman0f3bc092009-06-25 18:12:34 +05302142 return rc;
Linus Torvalds1da177e2005-04-16 15:20:36 -07002143 }
2144
Steve Frenchfb8c4b12007-07-10 01:16:18 +00002145 cFYI(1, ("readpage %p at offset %d 0x%x\n",
Linus Torvalds1da177e2005-04-16 15:20:36 -07002146 page, (int)offset, (int)offset));
2147
2148 rc = cifs_readpage_worker(file, page, &offset);
2149
2150 unlock_page(page);
2151
2152 FreeXid(xid);
2153 return rc;
2154}
2155
Steve Frencha403a0a2007-07-26 15:54:16 +00002156static int is_inode_writable(struct cifsInodeInfo *cifs_inode)
2157{
2158 struct cifsFileInfo *open_file;
2159
2160 read_lock(&GlobalSMBSeslock);
2161 list_for_each_entry(open_file, &cifs_inode->openFileList, flist) {
2162 if (open_file->closePend)
2163 continue;
2164 if (open_file->pfile &&
2165 ((open_file->pfile->f_flags & O_RDWR) ||
2166 (open_file->pfile->f_flags & O_WRONLY))) {
2167 read_unlock(&GlobalSMBSeslock);
2168 return 1;
2169 }
2170 }
2171 read_unlock(&GlobalSMBSeslock);
2172 return 0;
2173}
2174
Linus Torvalds1da177e2005-04-16 15:20:36 -07002175/* We do not want to update the file size from server for inodes
2176 open for write - to avoid races with writepage extending
2177 the file - in the future we could consider allowing
Steve Frenchfb8c4b12007-07-10 01:16:18 +00002178 refreshing the inode only on increases in the file size
Linus Torvalds1da177e2005-04-16 15:20:36 -07002179 but this is tricky to do without racing with writebehind
2180 page caching in the current Linux kernel design */
Steve French4b18f2a2008-04-29 00:06:05 +00002181bool is_size_safe_to_change(struct cifsInodeInfo *cifsInode, __u64 end_of_file)
Linus Torvalds1da177e2005-04-16 15:20:36 -07002182{
Steve Frencha403a0a2007-07-26 15:54:16 +00002183 if (!cifsInode)
Steve French4b18f2a2008-04-29 00:06:05 +00002184 return true;
Steve French23e7dd72005-10-20 13:44:56 -07002185
Steve Frencha403a0a2007-07-26 15:54:16 +00002186 if (is_inode_writable(cifsInode)) {
2187 /* This inode is open for write at least once */
Steve Frenchc32a0b62006-01-12 14:41:28 -08002188 struct cifs_sb_info *cifs_sb;
2189
Steve Frenchc32a0b62006-01-12 14:41:28 -08002190 cifs_sb = CIFS_SB(cifsInode->vfs_inode.i_sb);
Steve Frenchad7a2922008-02-07 23:25:02 +00002191 if (cifs_sb->mnt_cifs_flags & CIFS_MOUNT_DIRECT_IO) {
Steve Frenchfb8c4b12007-07-10 01:16:18 +00002192 /* since no page cache to corrupt on directio
Steve Frenchc32a0b62006-01-12 14:41:28 -08002193 we can change size safely */
Steve French4b18f2a2008-04-29 00:06:05 +00002194 return true;
Steve Frenchc32a0b62006-01-12 14:41:28 -08002195 }
2196
Steve Frenchfb8c4b12007-07-10 01:16:18 +00002197 if (i_size_read(&cifsInode->vfs_inode) < end_of_file)
Steve French4b18f2a2008-04-29 00:06:05 +00002198 return true;
Steve French7ba52632007-02-08 18:14:13 +00002199
Steve French4b18f2a2008-04-29 00:06:05 +00002200 return false;
Steve French23e7dd72005-10-20 13:44:56 -07002201 } else
Steve French4b18f2a2008-04-29 00:06:05 +00002202 return true;
Linus Torvalds1da177e2005-04-16 15:20:36 -07002203}
2204
Nick Piggind9414772008-09-24 11:32:59 -04002205static int cifs_write_begin(struct file *file, struct address_space *mapping,
2206 loff_t pos, unsigned len, unsigned flags,
2207 struct page **pagep, void **fsdata)
Linus Torvalds1da177e2005-04-16 15:20:36 -07002208{
Nick Piggind9414772008-09-24 11:32:59 -04002209 pgoff_t index = pos >> PAGE_CACHE_SHIFT;
2210 loff_t offset = pos & (PAGE_CACHE_SIZE - 1);
Jeff Laytona98ee8c2008-11-26 19:32:33 +00002211 loff_t page_start = pos & PAGE_MASK;
2212 loff_t i_size;
2213 struct page *page;
2214 int rc = 0;
Linus Torvalds1da177e2005-04-16 15:20:36 -07002215
Nick Piggind9414772008-09-24 11:32:59 -04002216 cFYI(1, ("write_begin from %lld len %d", (long long)pos, len));
2217
Nick Piggin54566b22009-01-04 12:00:53 -08002218 page = grab_cache_page_write_begin(mapping, index, flags);
Jeff Laytona98ee8c2008-11-26 19:32:33 +00002219 if (!page) {
2220 rc = -ENOMEM;
2221 goto out;
2222 }
Nick Piggind9414772008-09-24 11:32:59 -04002223
Jeff Laytona98ee8c2008-11-26 19:32:33 +00002224 if (PageUptodate(page))
2225 goto out;
Steve French8a236262007-03-06 00:31:00 +00002226
Jeff Laytona98ee8c2008-11-26 19:32:33 +00002227 /*
2228 * If we write a full page it will be up to date, no need to read from
2229 * the server. If the write is short, we'll end up doing a sync write
2230 * instead.
2231 */
2232 if (len == PAGE_CACHE_SIZE)
2233 goto out;
2234
2235 /*
2236 * optimize away the read when we have an oplock, and we're not
2237 * expecting to use any of the data we'd be reading in. That
2238 * is, when the page lies beyond the EOF, or straddles the EOF
2239 * and the write will cover all of the existing data.
2240 */
2241 if (CIFS_I(mapping->host)->clientCanCacheRead) {
2242 i_size = i_size_read(mapping->host);
2243 if (page_start >= i_size ||
2244 (offset == 0 && (pos + len) >= i_size)) {
2245 zero_user_segments(page, 0, offset,
2246 offset + len,
2247 PAGE_CACHE_SIZE);
2248 /*
2249 * PageChecked means that the parts of the page
2250 * to which we're not writing are considered up
2251 * to date. Once the data is copied to the
2252 * page, it can be set uptodate.
2253 */
2254 SetPageChecked(page);
2255 goto out;
2256 }
2257 }
Linus Torvalds1da177e2005-04-16 15:20:36 -07002258
Nick Piggind9414772008-09-24 11:32:59 -04002259 if ((file->f_flags & O_ACCMODE) != O_WRONLY) {
Jeff Laytona98ee8c2008-11-26 19:32:33 +00002260 /*
2261 * might as well read a page, it is fast enough. If we get
2262 * an error, we don't need to return it. cifs_write_end will
2263 * do a sync write instead since PG_uptodate isn't set.
2264 */
2265 cifs_readpage_worker(file, page, &page_start);
Steve French8a236262007-03-06 00:31:00 +00002266 } else {
2267 /* we could try using another file handle if there is one -
2268 but how would we lock it to prevent close of that handle
2269 racing with this read? In any case
Nick Piggind9414772008-09-24 11:32:59 -04002270 this will be written out by write_end so is fine */
Steve French8a236262007-03-06 00:31:00 +00002271 }
Jeff Laytona98ee8c2008-11-26 19:32:33 +00002272out:
2273 *pagep = page;
2274 return rc;
Linus Torvalds1da177e2005-04-16 15:20:36 -07002275}
2276
Jeff Layton3bc303c2009-09-21 06:47:50 -04002277static void
2278cifs_oplock_break(struct slow_work *work)
2279{
2280 struct cifsFileInfo *cfile = container_of(work, struct cifsFileInfo,
2281 oplock_break);
2282 struct inode *inode = cfile->pInode;
2283 struct cifsInodeInfo *cinode = CIFS_I(inode);
2284 struct cifs_sb_info *cifs_sb = CIFS_SB(cfile->mnt->mnt_sb);
2285 int rc, waitrc = 0;
2286
2287 if (inode && S_ISREG(inode->i_mode)) {
2288#ifdef CONFIG_CIFS_EXPERIMENTAL
2289 if (cinode->clientCanCacheAll == 0)
2290 break_lease(inode, FMODE_READ);
2291 else if (cinode->clientCanCacheRead == 0)
2292 break_lease(inode, FMODE_WRITE);
2293#endif
2294 rc = filemap_fdatawrite(inode->i_mapping);
2295 if (cinode->clientCanCacheRead == 0) {
2296 waitrc = filemap_fdatawait(inode->i_mapping);
2297 invalidate_remote_inode(inode);
2298 }
2299 if (!rc)
2300 rc = waitrc;
2301 if (rc)
2302 cinode->write_behind_rc = rc;
2303 cFYI(1, ("Oplock flush inode %p rc %d", inode, rc));
2304 }
2305
2306 /*
2307 * releasing stale oplock after recent reconnect of smb session using
2308 * a now incorrect file handle is not a data integrity issue but do
2309 * not bother sending an oplock release if session to server still is
2310 * disconnected since oplock already released by the server
2311 */
2312 if (!cfile->closePend && !cfile->oplock_break_cancelled) {
2313 rc = CIFSSMBLock(0, cifs_sb->tcon, cfile->netfid, 0, 0, 0, 0,
2314 LOCKING_ANDX_OPLOCK_RELEASE, false);
2315 cFYI(1, ("Oplock release rc = %d", rc));
2316 }
2317}
2318
2319static int
2320cifs_oplock_break_get(struct slow_work *work)
2321{
2322 struct cifsFileInfo *cfile = container_of(work, struct cifsFileInfo,
2323 oplock_break);
2324 mntget(cfile->mnt);
2325 cifsFileInfo_get(cfile);
2326 return 0;
2327}
2328
2329static void
2330cifs_oplock_break_put(struct slow_work *work)
2331{
2332 struct cifsFileInfo *cfile = container_of(work, struct cifsFileInfo,
2333 oplock_break);
2334 mntput(cfile->mnt);
2335 cifsFileInfo_put(cfile);
2336}
2337
2338const struct slow_work_ops cifs_oplock_break_ops = {
2339 .get_ref = cifs_oplock_break_get,
2340 .put_ref = cifs_oplock_break_put,
2341 .execute = cifs_oplock_break,
2342};
2343
Christoph Hellwigf5e54d62006-06-28 04:26:44 -07002344const struct address_space_operations cifs_addr_ops = {
Linus Torvalds1da177e2005-04-16 15:20:36 -07002345 .readpage = cifs_readpage,
2346 .readpages = cifs_readpages,
2347 .writepage = cifs_writepage,
Steve French37c0eb42005-10-05 14:50:29 -07002348 .writepages = cifs_writepages,
Nick Piggind9414772008-09-24 11:32:59 -04002349 .write_begin = cifs_write_begin,
2350 .write_end = cifs_write_end,
Linus Torvalds1da177e2005-04-16 15:20:36 -07002351 .set_page_dirty = __set_page_dirty_nobuffers,
2352 /* .sync_page = cifs_sync_page, */
2353 /* .direct_IO = */
2354};
Dave Kleikamp273d81d2006-06-01 19:41:23 +00002355
2356/*
2357 * cifs_readpages requires the server to support a buffer large enough to
2358 * contain the header plus one complete page of data. Otherwise, we need
2359 * to leave cifs_readpages out of the address space operations.
2360 */
Christoph Hellwigf5e54d62006-06-28 04:26:44 -07002361const struct address_space_operations cifs_addr_ops_smallbuf = {
Dave Kleikamp273d81d2006-06-01 19:41:23 +00002362 .readpage = cifs_readpage,
2363 .writepage = cifs_writepage,
2364 .writepages = cifs_writepages,
Nick Piggind9414772008-09-24 11:32:59 -04002365 .write_begin = cifs_write_begin,
2366 .write_end = cifs_write_end,
Dave Kleikamp273d81d2006-06-01 19:41:23 +00002367 .set_page_dirty = __set_page_dirty_nobuffers,
2368 /* .sync_page = cifs_sync_page, */
2369 /* .direct_IO = */
2370};