blob: 1361d67f68f3f66874b57a551404ebaef3d85edb [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>
Tejun Heo5a0e3ad2010-03-24 17:04:11 +090034#include <linux/slab.h>
Linus Torvalds1da177e2005-04-16 15:20:36 -070035#include <asm/div64.h>
36#include "cifsfs.h"
37#include "cifspdu.h"
38#include "cifsglob.h"
39#include "cifsproto.h"
40#include "cifs_unicode.h"
41#include "cifs_debug.h"
42#include "cifs_fs_sb.h"
43
Linus Torvalds1da177e2005-04-16 15:20:36 -070044static inline int cifs_convert_flags(unsigned int flags)
45{
46 if ((flags & O_ACCMODE) == O_RDONLY)
47 return GENERIC_READ;
48 else if ((flags & O_ACCMODE) == O_WRONLY)
49 return GENERIC_WRITE;
50 else if ((flags & O_ACCMODE) == O_RDWR) {
51 /* GENERIC_ALL is too much permission to request
52 can cause unnecessary access denied on create */
53 /* return GENERIC_ALL; */
54 return (GENERIC_READ | GENERIC_WRITE);
55 }
56
Jeff Laytone10f7b52008-05-14 10:21:33 -070057 return (READ_CONTROL | FILE_WRITE_ATTRIBUTES | FILE_READ_ATTRIBUTES |
58 FILE_WRITE_EA | FILE_APPEND_DATA | FILE_WRITE_DATA |
59 FILE_READ_DATA);
Steve French7fc8f4e2009-02-23 20:43:11 +000060}
Jeff Laytone10f7b52008-05-14 10:21:33 -070061
Steve French7fc8f4e2009-02-23 20:43:11 +000062static inline fmode_t cifs_posix_convert_flags(unsigned int flags)
63{
64 fmode_t posix_flags = 0;
Jeff Laytone10f7b52008-05-14 10:21:33 -070065
Steve French7fc8f4e2009-02-23 20:43:11 +000066 if ((flags & O_ACCMODE) == O_RDONLY)
67 posix_flags = FMODE_READ;
68 else if ((flags & O_ACCMODE) == O_WRONLY)
69 posix_flags = FMODE_WRITE;
70 else if ((flags & O_ACCMODE) == O_RDWR) {
71 /* GENERIC_ALL is too much permission to request
72 can cause unnecessary access denied on create */
73 /* return GENERIC_ALL; */
74 posix_flags = FMODE_READ | FMODE_WRITE;
75 }
76 /* can not map O_CREAT or O_EXCL or O_TRUNC flags when
77 reopening a file. They had their effect on the original open */
78 if (flags & O_APPEND)
79 posix_flags |= (fmode_t)O_APPEND;
Christoph Hellwig6b2f3d12009-10-27 11:05:28 +010080 if (flags & O_DSYNC)
81 posix_flags |= (fmode_t)O_DSYNC;
82 if (flags & __O_SYNC)
83 posix_flags |= (fmode_t)__O_SYNC;
Steve French7fc8f4e2009-02-23 20:43:11 +000084 if (flags & O_DIRECTORY)
85 posix_flags |= (fmode_t)O_DIRECTORY;
86 if (flags & O_NOFOLLOW)
87 posix_flags |= (fmode_t)O_NOFOLLOW;
88 if (flags & O_DIRECT)
89 posix_flags |= (fmode_t)O_DIRECT;
90
91 return posix_flags;
Linus Torvalds1da177e2005-04-16 15:20:36 -070092}
93
94static inline int cifs_get_disposition(unsigned int flags)
95{
96 if ((flags & (O_CREAT | O_EXCL)) == (O_CREAT | O_EXCL))
97 return FILE_CREATE;
98 else if ((flags & (O_CREAT | O_TRUNC)) == (O_CREAT | O_TRUNC))
99 return FILE_OVERWRITE_IF;
100 else if ((flags & O_CREAT) == O_CREAT)
101 return FILE_OPEN_IF;
Steve French55aa2e02006-05-30 18:09:31 +0000102 else if ((flags & O_TRUNC) == O_TRUNC)
103 return FILE_OVERWRITE;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700104 else
105 return FILE_OPEN;
106}
107
108/* all arguments to this function must be checked for validity in caller */
Jeff Layton590a3fe2009-09-12 11:54:28 -0400109static inline int
110cifs_posix_open_inode_helper(struct inode *inode, struct file *file,
111 struct cifsInodeInfo *pCifsInode,
112 struct cifsFileInfo *pCifsFile, __u32 oplock,
113 u16 netfid)
Steve French276a74a2009-03-03 18:00:34 +0000114{
Steve French276a74a2009-03-03 18:00:34 +0000115
Steve French276a74a2009-03-03 18:00:34 +0000116 write_lock(&GlobalSMBSeslock);
Steve French276a74a2009-03-03 18:00:34 +0000117
118 pCifsInode = CIFS_I(file->f_path.dentry->d_inode);
119 if (pCifsInode == NULL) {
120 write_unlock(&GlobalSMBSeslock);
121 return -EINVAL;
122 }
123
Steve French276a74a2009-03-03 18:00:34 +0000124 if (pCifsInode->clientCanCacheRead) {
125 /* we have the inode open somewhere else
126 no need to discard cache data */
127 goto psx_client_can_cache;
128 }
129
130 /* BB FIXME need to fix this check to move it earlier into posix_open
131 BB fIX following section BB FIXME */
132
133 /* if not oplocked, invalidate inode pages if mtime or file
134 size changed */
135/* temp = cifs_NTtimeToUnix(le64_to_cpu(buf->LastWriteTime));
136 if (timespec_equal(&file->f_path.dentry->d_inode->i_mtime, &temp) &&
137 (file->f_path.dentry->d_inode->i_size ==
138 (loff_t)le64_to_cpu(buf->EndOfFile))) {
139 cFYI(1, ("inode unchanged on server"));
140 } else {
141 if (file->f_path.dentry->d_inode->i_mapping) {
142 rc = filemap_write_and_wait(file->f_path.dentry->d_inode->i_mapping);
143 if (rc != 0)
144 CIFS_I(file->f_path.dentry->d_inode)->write_behind_rc = rc;
145 }
146 cFYI(1, ("invalidating remote inode since open detected it "
147 "changed"));
148 invalidate_remote_inode(file->f_path.dentry->d_inode);
149 } */
150
151psx_client_can_cache:
152 if ((oplock & 0xF) == OPLOCK_EXCLUSIVE) {
153 pCifsInode->clientCanCacheAll = true;
154 pCifsInode->clientCanCacheRead = true;
155 cFYI(1, ("Exclusive Oplock granted on inode %p",
156 file->f_path.dentry->d_inode));
157 } else if ((oplock & 0xF) == OPLOCK_READ)
158 pCifsInode->clientCanCacheRead = true;
159
160 /* will have to change the unlock if we reenable the
161 filemap_fdatawrite (which does not seem necessary */
162 write_unlock(&GlobalSMBSeslock);
163 return 0;
164}
165
Steve French703a3b82009-05-21 22:21:53 +0000166static struct cifsFileInfo *
167cifs_fill_filedata(struct file *file)
168{
169 struct list_head *tmp;
170 struct cifsFileInfo *pCifsFile = NULL;
171 struct cifsInodeInfo *pCifsInode = NULL;
172
173 /* search inode for this file and fill in file->private_data */
174 pCifsInode = CIFS_I(file->f_path.dentry->d_inode);
175 read_lock(&GlobalSMBSeslock);
176 list_for_each(tmp, &pCifsInode->openFileList) {
177 pCifsFile = list_entry(tmp, struct cifsFileInfo, flist);
178 if ((pCifsFile->pfile == NULL) &&
179 (pCifsFile->pid == current->tgid)) {
180 /* mode set in cifs_create */
181
182 /* needed for writepage */
183 pCifsFile->pfile = file;
184 file->private_data = pCifsFile;
185 break;
186 }
187 }
188 read_unlock(&GlobalSMBSeslock);
189
190 if (file->private_data != NULL) {
191 return pCifsFile;
192 } else if ((file->f_flags & O_CREAT) && (file->f_flags & O_EXCL))
193 cERROR(1, ("could not find file instance for "
194 "new file %p", file));
195 return NULL;
196}
197
Steve French276a74a2009-03-03 18:00:34 +0000198/* all arguments to this function must be checked for validity in caller */
Linus Torvalds1da177e2005-04-16 15:20:36 -0700199static inline int cifs_open_inode_helper(struct inode *inode, struct file *file,
200 struct cifsInodeInfo *pCifsInode, struct cifsFileInfo *pCifsFile,
201 struct cifsTconInfo *pTcon, int *oplock, FILE_ALL_INFO *buf,
202 char *full_path, int xid)
203{
204 struct timespec temp;
205 int rc;
206
Linus Torvalds1da177e2005-04-16 15:20:36 -0700207 if (pCifsInode->clientCanCacheRead) {
208 /* we have the inode open somewhere else
209 no need to discard cache data */
210 goto client_can_cache;
211 }
212
213 /* BB need same check in cifs_create too? */
214 /* if not oplocked, invalidate inode pages if mtime or file
215 size changed */
Jeff Layton07119a42009-05-27 09:37:33 -0400216 temp = cifs_NTtimeToUnix(buf->LastWriteTime);
Josef "Jeff" Sipeke6a00292006-12-08 02:36:48 -0800217 if (timespec_equal(&file->f_path.dentry->d_inode->i_mtime, &temp) &&
218 (file->f_path.dentry->d_inode->i_size ==
Linus Torvalds1da177e2005-04-16 15:20:36 -0700219 (loff_t)le64_to_cpu(buf->EndOfFile))) {
220 cFYI(1, ("inode unchanged on server"));
221 } else {
Josef "Jeff" Sipeke6a00292006-12-08 02:36:48 -0800222 if (file->f_path.dentry->d_inode->i_mapping) {
Steve Frenchff2157132010-03-09 20:30:42 +0000223 /* BB no need to lock inode until after invalidate
224 since namei code should already have it locked? */
Jeff Laytoncea21802007-11-20 23:19:03 +0000225 rc = filemap_write_and_wait(file->f_path.dentry->d_inode->i_mapping);
226 if (rc != 0)
227 CIFS_I(file->f_path.dentry->d_inode)->write_behind_rc = rc;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700228 }
229 cFYI(1, ("invalidating remote inode since open detected it "
230 "changed"));
Josef "Jeff" Sipeke6a00292006-12-08 02:36:48 -0800231 invalidate_remote_inode(file->f_path.dentry->d_inode);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700232 }
233
234client_can_cache:
Steve Frenchc18c8422007-07-18 23:21:09 +0000235 if (pTcon->unix_ext)
Josef "Jeff" Sipeke6a00292006-12-08 02:36:48 -0800236 rc = cifs_get_inode_info_unix(&file->f_path.dentry->d_inode,
Linus Torvalds1da177e2005-04-16 15:20:36 -0700237 full_path, inode->i_sb, xid);
238 else
Josef "Jeff" Sipeke6a00292006-12-08 02:36:48 -0800239 rc = cifs_get_inode_info(&file->f_path.dentry->d_inode,
Steve French8b1327f2008-03-14 22:37:16 +0000240 full_path, buf, inode->i_sb, xid, NULL);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700241
242 if ((*oplock & 0xF) == OPLOCK_EXCLUSIVE) {
Steve French4b18f2a2008-04-29 00:06:05 +0000243 pCifsInode->clientCanCacheAll = true;
244 pCifsInode->clientCanCacheRead = true;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700245 cFYI(1, ("Exclusive Oplock granted on inode %p",
Josef "Jeff" Sipeke6a00292006-12-08 02:36:48 -0800246 file->f_path.dentry->d_inode));
Linus Torvalds1da177e2005-04-16 15:20:36 -0700247 } else if ((*oplock & 0xF) == OPLOCK_READ)
Steve French4b18f2a2008-04-29 00:06:05 +0000248 pCifsInode->clientCanCacheRead = true;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700249
250 return rc;
251}
252
253int cifs_open(struct inode *inode, struct file *file)
254{
255 int rc = -EACCES;
Jeff Layton590a3fe2009-09-12 11:54:28 -0400256 int xid;
257 __u32 oplock;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700258 struct cifs_sb_info *cifs_sb;
Steve French276a74a2009-03-03 18:00:34 +0000259 struct cifsTconInfo *tcon;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700260 struct cifsFileInfo *pCifsFile;
261 struct cifsInodeInfo *pCifsInode;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700262 char *full_path = NULL;
263 int desiredAccess;
264 int disposition;
265 __u16 netfid;
266 FILE_ALL_INFO *buf = NULL;
267
268 xid = GetXid();
269
270 cifs_sb = CIFS_SB(inode->i_sb);
Steve French276a74a2009-03-03 18:00:34 +0000271 tcon = cifs_sb->tcon;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700272
Steve Frencha6ce4932009-04-09 01:14:32 +0000273 pCifsInode = CIFS_I(file->f_path.dentry->d_inode);
Steve French703a3b82009-05-21 22:21:53 +0000274 pCifsFile = cifs_fill_filedata(file);
275 if (pCifsFile) {
Suresh Jayaraman0f3bc092009-06-25 18:12:34 +0530276 rc = 0;
Steve Frencha6ce4932009-04-09 01:14:32 +0000277 FreeXid(xid);
Suresh Jayaraman0f3bc092009-06-25 18:12:34 +0530278 return rc;
Steve French703a3b82009-05-21 22:21:53 +0000279 }
Linus Torvalds1da177e2005-04-16 15:20:36 -0700280
Josef "Jeff" Sipeke6a00292006-12-08 02:36:48 -0800281 full_path = build_path_from_dentry(file->f_path.dentry);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700282 if (full_path == NULL) {
Suresh Jayaraman0f3bc092009-06-25 18:12:34 +0530283 rc = -ENOMEM;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700284 FreeXid(xid);
Suresh Jayaraman0f3bc092009-06-25 18:12:34 +0530285 return rc;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700286 }
287
Steve French7521a3c2007-07-11 18:30:34 +0000288 cFYI(1, ("inode = 0x%p file flags are 0x%x for %s",
Linus Torvalds1da177e2005-04-16 15:20:36 -0700289 inode, file->f_flags, full_path));
Steve French276a74a2009-03-03 18:00:34 +0000290
291 if (oplockEnabled)
292 oplock = REQ_OPLOCK;
293 else
294 oplock = 0;
295
Steve French64cc2c62009-03-04 19:54:08 +0000296 if (!tcon->broken_posix_open && tcon->unix_ext &&
297 (tcon->ses->capabilities & CAP_UNIX) &&
Steve French276a74a2009-03-03 18:00:34 +0000298 (CIFS_UNIX_POSIX_PATH_OPS_CAP &
299 le64_to_cpu(tcon->fsUnixInfo.Capability))) {
300 int oflags = (int) cifs_posix_convert_flags(file->f_flags);
301 /* can not refresh inode info since size could be stale */
Jeff Layton3bc303c2009-09-21 06:47:50 -0400302 rc = cifs_posix_open(full_path, &inode, file->f_path.mnt,
Steve French276a74a2009-03-03 18:00:34 +0000303 cifs_sb->mnt_file_mode /* ignored */,
304 oflags, &oplock, &netfid, xid);
305 if (rc == 0) {
306 cFYI(1, ("posix open succeeded"));
307 /* no need for special case handling of setting mode
308 on read only files needed here */
309
Steve French703a3b82009-05-21 22:21:53 +0000310 pCifsFile = cifs_fill_filedata(file);
Steve French276a74a2009-03-03 18:00:34 +0000311 cifs_posix_open_inode_helper(inode, file, pCifsInode,
312 pCifsFile, oplock, netfid);
313 goto out;
Steve French64cc2c62009-03-04 19:54:08 +0000314 } else if ((rc == -EINVAL) || (rc == -EOPNOTSUPP)) {
315 if (tcon->ses->serverNOS)
316 cERROR(1, ("server %s of type %s returned"
317 " unexpected error on SMB posix open"
318 ", disabling posix open support."
319 " Check if server update available.",
320 tcon->ses->serverName,
321 tcon->ses->serverNOS));
322 tcon->broken_posix_open = true;
Steve French276a74a2009-03-03 18:00:34 +0000323 } else if ((rc != -EIO) && (rc != -EREMOTE) &&
324 (rc != -EOPNOTSUPP)) /* path not found or net err */
325 goto out;
Steve French64cc2c62009-03-04 19:54:08 +0000326 /* else fallthrough to retry open the old way on network i/o
327 or DFS errors */
Steve French276a74a2009-03-03 18:00:34 +0000328 }
329
Linus Torvalds1da177e2005-04-16 15:20:36 -0700330 desiredAccess = cifs_convert_flags(file->f_flags);
331
332/*********************************************************************
333 * open flag mapping table:
Steve Frenchfb8c4b12007-07-10 01:16:18 +0000334 *
Linus Torvalds1da177e2005-04-16 15:20:36 -0700335 * POSIX Flag CIFS Disposition
Steve Frenchfb8c4b12007-07-10 01:16:18 +0000336 * ---------- ----------------
Linus Torvalds1da177e2005-04-16 15:20:36 -0700337 * O_CREAT FILE_OPEN_IF
338 * O_CREAT | O_EXCL FILE_CREATE
339 * O_CREAT | O_TRUNC FILE_OVERWRITE_IF
340 * O_TRUNC FILE_OVERWRITE
341 * none of the above FILE_OPEN
342 *
343 * Note that there is not a direct match between disposition
Steve Frenchfb8c4b12007-07-10 01:16:18 +0000344 * FILE_SUPERSEDE (ie create whether or not file exists although
Linus Torvalds1da177e2005-04-16 15:20:36 -0700345 * O_CREAT | O_TRUNC is similar but truncates the existing
346 * file rather than creating a new file as FILE_SUPERSEDE does
347 * (which uses the attributes / metadata passed in on open call)
348 *?
Steve Frenchfb8c4b12007-07-10 01:16:18 +0000349 *? O_SYNC is a reasonable match to CIFS writethrough flag
Linus Torvalds1da177e2005-04-16 15:20:36 -0700350 *? and the read write flags match reasonably. O_LARGEFILE
351 *? is irrelevant because largefile support is always used
352 *? by this client. Flags O_APPEND, O_DIRECT, O_DIRECTORY,
353 * O_FASYNC, O_NOFOLLOW, O_NONBLOCK need further investigation
354 *********************************************************************/
355
356 disposition = cifs_get_disposition(file->f_flags);
357
Linus Torvalds1da177e2005-04-16 15:20:36 -0700358 /* BB pass O_SYNC flag through on file attributes .. BB */
359
360 /* Also refresh inode by passing in file_info buf returned by SMBOpen
361 and calling get_inode_info with returned buf (at least helps
362 non-Unix server case) */
363
Steve Frenchfb8c4b12007-07-10 01:16:18 +0000364 /* BB we can not do this if this is the second open of a file
365 and the first handle has writebehind data, we might be
Linus Torvalds1da177e2005-04-16 15:20:36 -0700366 able to simply do a filemap_fdatawrite/filemap_fdatawait first */
367 buf = kmalloc(sizeof(FILE_ALL_INFO), GFP_KERNEL);
368 if (!buf) {
369 rc = -ENOMEM;
370 goto out;
371 }
Steve French5bafd762006-06-07 00:18:43 +0000372
373 if (cifs_sb->tcon->ses->capabilities & CAP_NT_SMBS)
Steve French276a74a2009-03-03 18:00:34 +0000374 rc = CIFSSMBOpen(xid, tcon, full_path, disposition,
Steve French5bafd762006-06-07 00:18:43 +0000375 desiredAccess, CREATE_NOT_DIR, &netfid, &oplock, buf,
Steve French737b7582005-04-28 22:41:06 -0700376 cifs_sb->local_nls, cifs_sb->mnt_cifs_flags
377 & CIFS_MOUNT_MAP_SPECIAL_CHR);
Steve French5bafd762006-06-07 00:18:43 +0000378 else
379 rc = -EIO; /* no NT SMB support fall into legacy open below */
380
Steve Frencha9d02ad2005-08-24 23:06:05 -0700381 if (rc == -EIO) {
382 /* Old server, try legacy style OpenX */
Steve French276a74a2009-03-03 18:00:34 +0000383 rc = SMBLegacyOpen(xid, tcon, full_path, disposition,
Steve Frencha9d02ad2005-08-24 23:06:05 -0700384 desiredAccess, CREATE_NOT_DIR, &netfid, &oplock, buf,
385 cifs_sb->local_nls, cifs_sb->mnt_cifs_flags
386 & CIFS_MOUNT_MAP_SPECIAL_CHR);
387 }
Linus Torvalds1da177e2005-04-16 15:20:36 -0700388 if (rc) {
Steve French26a21b92006-05-31 18:05:34 +0000389 cFYI(1, ("cifs_open returned 0x%x", rc));
Linus Torvalds1da177e2005-04-16 15:20:36 -0700390 goto out;
391 }
Jeff Layton3321b792009-09-25 09:53:37 -0400392
Jeff Layton086f68b2009-09-21 14:08:18 -0400393 pCifsFile = cifs_new_fileinfo(inode, netfid, file, file->f_path.mnt,
394 file->f_flags);
395 file->private_data = pCifsFile;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700396 if (file->private_data == NULL) {
397 rc = -ENOMEM;
398 goto out;
399 }
Linus Torvalds1da177e2005-04-16 15:20:36 -0700400
Jeff Layton3321b792009-09-25 09:53:37 -0400401 rc = cifs_open_inode_helper(inode, file, pCifsInode, pCifsFile, tcon,
402 &oplock, buf, full_path, xid);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700403
Steve Frenchfb8c4b12007-07-10 01:16:18 +0000404 if (oplock & CIFS_CREATE_ACTION) {
Linus Torvalds1da177e2005-04-16 15:20:36 -0700405 /* time to set mode which we can not set earlier due to
406 problems creating new read-only files */
Steve French276a74a2009-03-03 18:00:34 +0000407 if (tcon->unix_ext) {
Jeff Layton4e1e7fb2008-08-02 07:26:12 -0400408 struct cifs_unix_set_info_args args = {
409 .mode = inode->i_mode,
410 .uid = NO_CHANGE_64,
411 .gid = NO_CHANGE_64,
412 .ctime = NO_CHANGE_64,
413 .atime = NO_CHANGE_64,
414 .mtime = NO_CHANGE_64,
415 .device = 0,
416 };
Jeff Layton01ea95e2009-07-09 20:02:49 -0400417 CIFSSMBUnixSetPathInfo(xid, tcon, full_path, &args,
418 cifs_sb->local_nls,
419 cifs_sb->mnt_cifs_flags &
Steve French737b7582005-04-28 22:41:06 -0700420 CIFS_MOUNT_MAP_SPECIAL_CHR);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700421 }
422 }
423
424out:
425 kfree(buf);
426 kfree(full_path);
427 FreeXid(xid);
428 return rc;
429}
430
Adrian Bunk04187262006-06-30 18:23:04 +0200431/* Try to reacquire byte range locks that were released when session */
Linus Torvalds1da177e2005-04-16 15:20:36 -0700432/* to server was lost */
433static int cifs_relock_file(struct cifsFileInfo *cifsFile)
434{
435 int rc = 0;
436
437/* BB list all locks open on this file and relock */
438
439 return rc;
440}
441
Steve French4b18f2a2008-04-29 00:06:05 +0000442static int cifs_reopen_file(struct file *file, bool can_flush)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700443{
444 int rc = -EACCES;
Jeff Layton590a3fe2009-09-12 11:54:28 -0400445 int xid;
446 __u32 oplock;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700447 struct cifs_sb_info *cifs_sb;
Steve French7fc8f4e2009-02-23 20:43:11 +0000448 struct cifsTconInfo *tcon;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700449 struct cifsFileInfo *pCifsFile;
450 struct cifsInodeInfo *pCifsInode;
Steve Frenchfb8c4b12007-07-10 01:16:18 +0000451 struct inode *inode;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700452 char *full_path = NULL;
453 int desiredAccess;
454 int disposition = FILE_OPEN;
455 __u16 netfid;
456
Steve Frenchad7a2922008-02-07 23:25:02 +0000457 if (file->private_data)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700458 pCifsFile = (struct cifsFileInfo *)file->private_data;
Steve Frenchad7a2922008-02-07 23:25:02 +0000459 else
Linus Torvalds1da177e2005-04-16 15:20:36 -0700460 return -EBADF;
461
462 xid = GetXid();
Jeff Laytonf0a71eb2009-06-27 07:04:55 -0400463 mutex_lock(&pCifsFile->fh_mutex);
Steve French4b18f2a2008-04-29 00:06:05 +0000464 if (!pCifsFile->invalidHandle) {
Jeff Laytonf0a71eb2009-06-27 07:04:55 -0400465 mutex_unlock(&pCifsFile->fh_mutex);
Suresh Jayaraman0f3bc092009-06-25 18:12:34 +0530466 rc = 0;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700467 FreeXid(xid);
Suresh Jayaraman0f3bc092009-06-25 18:12:34 +0530468 return rc;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700469 }
470
Josef "Jeff" Sipeke6a00292006-12-08 02:36:48 -0800471 if (file->f_path.dentry == NULL) {
Steve French3a9f4622007-04-04 17:10:24 +0000472 cERROR(1, ("no valid name if dentry freed"));
473 dump_stack();
474 rc = -EBADF;
475 goto reopen_error_exit;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700476 }
Steve French3a9f4622007-04-04 17:10:24 +0000477
478 inode = file->f_path.dentry->d_inode;
Steve Frenchfb8c4b12007-07-10 01:16:18 +0000479 if (inode == NULL) {
Steve French3a9f4622007-04-04 17:10:24 +0000480 cERROR(1, ("inode not valid"));
481 dump_stack();
482 rc = -EBADF;
483 goto reopen_error_exit;
484 }
Steve French50c2f752007-07-13 00:33:32 +0000485
Linus Torvalds1da177e2005-04-16 15:20:36 -0700486 cifs_sb = CIFS_SB(inode->i_sb);
Steve French7fc8f4e2009-02-23 20:43:11 +0000487 tcon = cifs_sb->tcon;
Steve French3a9f4622007-04-04 17:10:24 +0000488
Linus Torvalds1da177e2005-04-16 15:20:36 -0700489/* can not grab rename sem here because various ops, including
490 those that already have the rename sem can end up causing writepage
491 to get called and if the server was down that means we end up here,
492 and we can never tell if the caller already has the rename_sem */
Josef "Jeff" Sipeke6a00292006-12-08 02:36:48 -0800493 full_path = build_path_from_dentry(file->f_path.dentry);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700494 if (full_path == NULL) {
Steve French3a9f4622007-04-04 17:10:24 +0000495 rc = -ENOMEM;
496reopen_error_exit:
Jeff Laytonf0a71eb2009-06-27 07:04:55 -0400497 mutex_unlock(&pCifsFile->fh_mutex);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700498 FreeXid(xid);
Steve French3a9f4622007-04-04 17:10:24 +0000499 return rc;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700500 }
501
Steve French3a9f4622007-04-04 17:10:24 +0000502 cFYI(1, ("inode = 0x%p file flags 0x%x for %s",
Steve Frenchfb8c4b12007-07-10 01:16:18 +0000503 inode, file->f_flags, full_path));
Linus Torvalds1da177e2005-04-16 15:20:36 -0700504
505 if (oplockEnabled)
506 oplock = REQ_OPLOCK;
507 else
Steve French4b18f2a2008-04-29 00:06:05 +0000508 oplock = 0;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700509
Steve French7fc8f4e2009-02-23 20:43:11 +0000510 if (tcon->unix_ext && (tcon->ses->capabilities & CAP_UNIX) &&
511 (CIFS_UNIX_POSIX_PATH_OPS_CAP &
512 le64_to_cpu(tcon->fsUnixInfo.Capability))) {
513 int oflags = (int) cifs_posix_convert_flags(file->f_flags);
514 /* can not refresh inode info since size could be stale */
Jeff Layton3bc303c2009-09-21 06:47:50 -0400515 rc = cifs_posix_open(full_path, NULL, file->f_path.mnt,
Steve French7fc8f4e2009-02-23 20:43:11 +0000516 cifs_sb->mnt_file_mode /* ignored */,
517 oflags, &oplock, &netfid, xid);
518 if (rc == 0) {
519 cFYI(1, ("posix reopen succeeded"));
520 goto reopen_success;
521 }
522 /* fallthrough to retry open the old way on errors, especially
523 in the reconnect path it is important to retry hard */
524 }
525
526 desiredAccess = cifs_convert_flags(file->f_flags);
527
Linus Torvalds1da177e2005-04-16 15:20:36 -0700528 /* Can not refresh inode by passing in file_info buf to be returned
Steve Frenchfb8c4b12007-07-10 01:16:18 +0000529 by SMBOpen and then calling get_inode_info with returned buf
530 since file might have write behind data that needs to be flushed
Linus Torvalds1da177e2005-04-16 15:20:36 -0700531 and server version of file size can be stale. If we knew for sure
532 that inode was not dirty locally we could do this */
533
Steve French7fc8f4e2009-02-23 20:43:11 +0000534 rc = CIFSSMBOpen(xid, tcon, full_path, disposition, desiredAccess,
Linus Torvalds1da177e2005-04-16 15:20:36 -0700535 CREATE_NOT_DIR, &netfid, &oplock, NULL,
Steve Frenchfb8c4b12007-07-10 01:16:18 +0000536 cifs_sb->local_nls, cifs_sb->mnt_cifs_flags &
Steve French737b7582005-04-28 22:41:06 -0700537 CIFS_MOUNT_MAP_SPECIAL_CHR);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700538 if (rc) {
Jeff Laytonf0a71eb2009-06-27 07:04:55 -0400539 mutex_unlock(&pCifsFile->fh_mutex);
Steve French26a21b92006-05-31 18:05:34 +0000540 cFYI(1, ("cifs_open returned 0x%x", rc));
541 cFYI(1, ("oplock: %d", oplock));
Linus Torvalds1da177e2005-04-16 15:20:36 -0700542 } else {
Steve French7fc8f4e2009-02-23 20:43:11 +0000543reopen_success:
Linus Torvalds1da177e2005-04-16 15:20:36 -0700544 pCifsFile->netfid = netfid;
Steve French4b18f2a2008-04-29 00:06:05 +0000545 pCifsFile->invalidHandle = false;
Jeff Laytonf0a71eb2009-06-27 07:04:55 -0400546 mutex_unlock(&pCifsFile->fh_mutex);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700547 pCifsInode = CIFS_I(inode);
548 if (pCifsInode) {
549 if (can_flush) {
Jeff Laytoncea21802007-11-20 23:19:03 +0000550 rc = filemap_write_and_wait(inode->i_mapping);
551 if (rc != 0)
552 CIFS_I(inode)->write_behind_rc = rc;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700553 /* temporarily disable caching while we
554 go to server to get inode info */
Steve French4b18f2a2008-04-29 00:06:05 +0000555 pCifsInode->clientCanCacheAll = false;
556 pCifsInode->clientCanCacheRead = false;
Steve French7fc8f4e2009-02-23 20:43:11 +0000557 if (tcon->unix_ext)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700558 rc = cifs_get_inode_info_unix(&inode,
559 full_path, inode->i_sb, xid);
560 else
561 rc = cifs_get_inode_info(&inode,
562 full_path, NULL, inode->i_sb,
Steve French8b1327f2008-03-14 22:37:16 +0000563 xid, NULL);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700564 } /* else we are writing out data to server already
565 and could deadlock if we tried to flush data, and
566 since we do not know if we have data that would
567 invalidate the current end of file on the server
568 we can not go to the server to get the new inod
569 info */
570 if ((oplock & 0xF) == OPLOCK_EXCLUSIVE) {
Steve French4b18f2a2008-04-29 00:06:05 +0000571 pCifsInode->clientCanCacheAll = true;
572 pCifsInode->clientCanCacheRead = true;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700573 cFYI(1, ("Exclusive Oplock granted on inode %p",
Josef "Jeff" Sipeke6a00292006-12-08 02:36:48 -0800574 file->f_path.dentry->d_inode));
Linus Torvalds1da177e2005-04-16 15:20:36 -0700575 } else if ((oplock & 0xF) == OPLOCK_READ) {
Steve French4b18f2a2008-04-29 00:06:05 +0000576 pCifsInode->clientCanCacheRead = true;
577 pCifsInode->clientCanCacheAll = false;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700578 } else {
Steve French4b18f2a2008-04-29 00:06:05 +0000579 pCifsInode->clientCanCacheRead = false;
580 pCifsInode->clientCanCacheAll = false;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700581 }
582 cifs_relock_file(pCifsFile);
583 }
584 }
Linus Torvalds1da177e2005-04-16 15:20:36 -0700585 kfree(full_path);
586 FreeXid(xid);
587 return rc;
588}
589
590int cifs_close(struct inode *inode, struct file *file)
591{
592 int rc = 0;
Steve French15745322007-09-07 22:23:48 +0000593 int xid, timeout;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700594 struct cifs_sb_info *cifs_sb;
595 struct cifsTconInfo *pTcon;
596 struct cifsFileInfo *pSMBFile =
597 (struct cifsFileInfo *)file->private_data;
598
599 xid = GetXid();
600
601 cifs_sb = CIFS_SB(inode->i_sb);
602 pTcon = cifs_sb->tcon;
603 if (pSMBFile) {
Jeremy Allison7ee1af72006-08-02 21:56:33 +0000604 struct cifsLockInfo *li, *tmp;
Steve Frenchddb4cbf2008-11-20 20:00:44 +0000605 write_lock(&GlobalSMBSeslock);
Steve French4b18f2a2008-04-29 00:06:05 +0000606 pSMBFile->closePend = true;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700607 if (pTcon) {
608 /* no sense reconnecting to close a file that is
609 already closed */
Steve French3b795212008-11-13 19:45:32 +0000610 if (!pTcon->need_reconnect) {
Steve Frenchddb4cbf2008-11-20 20:00:44 +0000611 write_unlock(&GlobalSMBSeslock);
Steve French15745322007-09-07 22:23:48 +0000612 timeout = 2;
Dave Kleikamp6ab409b2009-08-31 11:07:12 -0400613 while ((atomic_read(&pSMBFile->count) != 1)
Steve French15745322007-09-07 22:23:48 +0000614 && (timeout <= 2048)) {
Steve French23e7dd72005-10-20 13:44:56 -0700615 /* Give write a better chance to get to
616 server ahead of the close. We do not
617 want to add a wait_q here as it would
618 increase the memory utilization as
619 the struct would be in each open file,
Steve Frenchfb8c4b12007-07-10 01:16:18 +0000620 but this should give enough time to
Steve French23e7dd72005-10-20 13:44:56 -0700621 clear the socket */
Steve French90c81e02008-02-12 20:32:36 +0000622 cFYI(DBG2,
623 ("close delay, write pending"));
Steve French23e7dd72005-10-20 13:44:56 -0700624 msleep(timeout);
625 timeout *= 4;
Steve French4891d532006-11-07 16:31:16 +0000626 }
Steve Frenchddb4cbf2008-11-20 20:00:44 +0000627 if (!pTcon->need_reconnect &&
628 !pSMBFile->invalidHandle)
629 rc = CIFSSMBClose(xid, pTcon,
Linus Torvalds1da177e2005-04-16 15:20:36 -0700630 pSMBFile->netfid);
Steve Frenchddb4cbf2008-11-20 20:00:44 +0000631 } else
632 write_unlock(&GlobalSMBSeslock);
633 } else
634 write_unlock(&GlobalSMBSeslock);
Jeremy Allison7ee1af72006-08-02 21:56:33 +0000635
636 /* Delete any outstanding lock records.
637 We'll lose them when the file is closed anyway. */
Roland Dreier796e5662007-05-03 04:33:45 +0000638 mutex_lock(&pSMBFile->lock_mutex);
Jeremy Allison7ee1af72006-08-02 21:56:33 +0000639 list_for_each_entry_safe(li, tmp, &pSMBFile->llist, llist) {
640 list_del(&li->llist);
641 kfree(li);
642 }
Roland Dreier796e5662007-05-03 04:33:45 +0000643 mutex_unlock(&pSMBFile->lock_mutex);
Jeremy Allison7ee1af72006-08-02 21:56:33 +0000644
Steve Frenchcbe04762005-04-28 22:41:05 -0700645 write_lock(&GlobalSMBSeslock);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700646 list_del(&pSMBFile->flist);
647 list_del(&pSMBFile->tlist);
Steve Frenchcbe04762005-04-28 22:41:05 -0700648 write_unlock(&GlobalSMBSeslock);
Dave Kleikamp6ab409b2009-08-31 11:07:12 -0400649 cifsFileInfo_put(file->private_data);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700650 file->private_data = NULL;
651 } else
652 rc = -EBADF;
653
Steve French4efa53f2007-09-11 05:50:53 +0000654 read_lock(&GlobalSMBSeslock);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700655 if (list_empty(&(CIFS_I(inode)->openFileList))) {
656 cFYI(1, ("closing last open instance for inode %p", inode));
657 /* if the file is not open we do not know if we can cache info
658 on this inode, much less write behind and read ahead */
Steve French4b18f2a2008-04-29 00:06:05 +0000659 CIFS_I(inode)->clientCanCacheRead = false;
660 CIFS_I(inode)->clientCanCacheAll = false;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700661 }
Steve French4efa53f2007-09-11 05:50:53 +0000662 read_unlock(&GlobalSMBSeslock);
Steve Frenchfb8c4b12007-07-10 01:16:18 +0000663 if ((rc == 0) && CIFS_I(inode)->write_behind_rc)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700664 rc = CIFS_I(inode)->write_behind_rc;
665 FreeXid(xid);
666 return rc;
667}
668
669int cifs_closedir(struct inode *inode, struct file *file)
670{
671 int rc = 0;
672 int xid;
673 struct cifsFileInfo *pCFileStruct =
674 (struct cifsFileInfo *)file->private_data;
675 char *ptmp;
676
Steve French26a21b92006-05-31 18:05:34 +0000677 cFYI(1, ("Closedir inode = 0x%p", inode));
Linus Torvalds1da177e2005-04-16 15:20:36 -0700678
679 xid = GetXid();
680
681 if (pCFileStruct) {
682 struct cifsTconInfo *pTcon;
Steve Frenchfb8c4b12007-07-10 01:16:18 +0000683 struct cifs_sb_info *cifs_sb =
684 CIFS_SB(file->f_path.dentry->d_sb);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700685
686 pTcon = cifs_sb->tcon;
687
688 cFYI(1, ("Freeing private data in close dir"));
Steve Frenchddb4cbf2008-11-20 20:00:44 +0000689 write_lock(&GlobalSMBSeslock);
Steve French4b18f2a2008-04-29 00:06:05 +0000690 if (!pCFileStruct->srch_inf.endOfSearch &&
691 !pCFileStruct->invalidHandle) {
692 pCFileStruct->invalidHandle = true;
Steve Frenchddb4cbf2008-11-20 20:00:44 +0000693 write_unlock(&GlobalSMBSeslock);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700694 rc = CIFSFindClose(xid, pTcon, pCFileStruct->netfid);
695 cFYI(1, ("Closing uncompleted readdir with rc %d",
696 rc));
697 /* not much we can do if it fails anyway, ignore rc */
698 rc = 0;
Steve Frenchddb4cbf2008-11-20 20:00:44 +0000699 } else
700 write_unlock(&GlobalSMBSeslock);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700701 ptmp = pCFileStruct->srch_inf.ntwrk_buf_start;
702 if (ptmp) {
Steve Frenchec637e32005-12-12 20:53:18 -0800703 cFYI(1, ("closedir free smb buf in srch struct"));
Linus Torvalds1da177e2005-04-16 15:20:36 -0700704 pCFileStruct->srch_inf.ntwrk_buf_start = NULL;
Steve Frenchfb8c4b12007-07-10 01:16:18 +0000705 if (pCFileStruct->srch_inf.smallBuf)
Steve Frenchd47d7c12006-02-28 03:45:48 +0000706 cifs_small_buf_release(ptmp);
707 else
708 cifs_buf_release(ptmp);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700709 }
Linus Torvalds1da177e2005-04-16 15:20:36 -0700710 kfree(file->private_data);
711 file->private_data = NULL;
712 }
713 /* BB can we lock the filestruct while this is going on? */
714 FreeXid(xid);
715 return rc;
716}
717
Jeremy Allison7ee1af72006-08-02 21:56:33 +0000718static int store_file_lock(struct cifsFileInfo *fid, __u64 len,
719 __u64 offset, __u8 lockType)
720{
Steve Frenchfb8c4b12007-07-10 01:16:18 +0000721 struct cifsLockInfo *li =
722 kmalloc(sizeof(struct cifsLockInfo), GFP_KERNEL);
Jeremy Allison7ee1af72006-08-02 21:56:33 +0000723 if (li == NULL)
724 return -ENOMEM;
725 li->offset = offset;
726 li->length = len;
727 li->type = lockType;
Roland Dreier796e5662007-05-03 04:33:45 +0000728 mutex_lock(&fid->lock_mutex);
Jeremy Allison7ee1af72006-08-02 21:56:33 +0000729 list_add(&li->llist, &fid->llist);
Roland Dreier796e5662007-05-03 04:33:45 +0000730 mutex_unlock(&fid->lock_mutex);
Jeremy Allison7ee1af72006-08-02 21:56:33 +0000731 return 0;
732}
733
Linus Torvalds1da177e2005-04-16 15:20:36 -0700734int cifs_lock(struct file *file, int cmd, struct file_lock *pfLock)
735{
736 int rc, xid;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700737 __u32 numLock = 0;
738 __u32 numUnlock = 0;
739 __u64 length;
Steve French4b18f2a2008-04-29 00:06:05 +0000740 bool wait_flag = false;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700741 struct cifs_sb_info *cifs_sb;
Steve French13a6e422008-12-02 17:24:33 +0000742 struct cifsTconInfo *tcon;
Steve French08547b02006-02-28 22:39:25 +0000743 __u16 netfid;
744 __u8 lockType = LOCKING_ANDX_LARGE_FILES;
Steve French13a6e422008-12-02 17:24:33 +0000745 bool posix_locking = 0;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700746
747 length = 1 + pfLock->fl_end - pfLock->fl_start;
748 rc = -EACCES;
749 xid = GetXid();
750
751 cFYI(1, ("Lock parm: 0x%x flockflags: "
752 "0x%x flocktype: 0x%x start: %lld end: %lld",
Steve Frenchfb8c4b12007-07-10 01:16:18 +0000753 cmd, pfLock->fl_flags, pfLock->fl_type, pfLock->fl_start,
754 pfLock->fl_end));
Linus Torvalds1da177e2005-04-16 15:20:36 -0700755
756 if (pfLock->fl_flags & FL_POSIX)
Steve Frenchd47d7c12006-02-28 03:45:48 +0000757 cFYI(1, ("Posix"));
Linus Torvalds1da177e2005-04-16 15:20:36 -0700758 if (pfLock->fl_flags & FL_FLOCK)
Steve Frenchd47d7c12006-02-28 03:45:48 +0000759 cFYI(1, ("Flock"));
Linus Torvalds1da177e2005-04-16 15:20:36 -0700760 if (pfLock->fl_flags & FL_SLEEP) {
Steve Frenchd47d7c12006-02-28 03:45:48 +0000761 cFYI(1, ("Blocking lock"));
Steve French4b18f2a2008-04-29 00:06:05 +0000762 wait_flag = true;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700763 }
764 if (pfLock->fl_flags & FL_ACCESS)
765 cFYI(1, ("Process suspended by mandatory locking - "
Steve French26a21b92006-05-31 18:05:34 +0000766 "not implemented yet"));
Linus Torvalds1da177e2005-04-16 15:20:36 -0700767 if (pfLock->fl_flags & FL_LEASE)
768 cFYI(1, ("Lease on file - not implemented yet"));
Steve Frenchfb8c4b12007-07-10 01:16:18 +0000769 if (pfLock->fl_flags &
Linus Torvalds1da177e2005-04-16 15:20:36 -0700770 (~(FL_POSIX | FL_FLOCK | FL_SLEEP | FL_ACCESS | FL_LEASE)))
771 cFYI(1, ("Unknown lock flags 0x%x", pfLock->fl_flags));
772
773 if (pfLock->fl_type == F_WRLCK) {
774 cFYI(1, ("F_WRLCK "));
775 numLock = 1;
776 } else if (pfLock->fl_type == F_UNLCK) {
Steve Frenchd47d7c12006-02-28 03:45:48 +0000777 cFYI(1, ("F_UNLCK"));
Linus Torvalds1da177e2005-04-16 15:20:36 -0700778 numUnlock = 1;
Steve Frenchd47d7c12006-02-28 03:45:48 +0000779 /* Check if unlock includes more than
780 one lock range */
Linus Torvalds1da177e2005-04-16 15:20:36 -0700781 } else if (pfLock->fl_type == F_RDLCK) {
Steve Frenchd47d7c12006-02-28 03:45:48 +0000782 cFYI(1, ("F_RDLCK"));
Linus Torvalds1da177e2005-04-16 15:20:36 -0700783 lockType |= LOCKING_ANDX_SHARED_LOCK;
784 numLock = 1;
785 } else if (pfLock->fl_type == F_EXLCK) {
Steve Frenchd47d7c12006-02-28 03:45:48 +0000786 cFYI(1, ("F_EXLCK"));
Linus Torvalds1da177e2005-04-16 15:20:36 -0700787 numLock = 1;
788 } else if (pfLock->fl_type == F_SHLCK) {
Steve Frenchd47d7c12006-02-28 03:45:48 +0000789 cFYI(1, ("F_SHLCK"));
Linus Torvalds1da177e2005-04-16 15:20:36 -0700790 lockType |= LOCKING_ANDX_SHARED_LOCK;
791 numLock = 1;
792 } else
Steve Frenchd47d7c12006-02-28 03:45:48 +0000793 cFYI(1, ("Unknown type of lock"));
Linus Torvalds1da177e2005-04-16 15:20:36 -0700794
Josef "Jeff" Sipeke6a00292006-12-08 02:36:48 -0800795 cifs_sb = CIFS_SB(file->f_path.dentry->d_sb);
Steve French13a6e422008-12-02 17:24:33 +0000796 tcon = cifs_sb->tcon;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700797
798 if (file->private_data == NULL) {
Suresh Jayaraman0f3bc092009-06-25 18:12:34 +0530799 rc = -EBADF;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700800 FreeXid(xid);
Suresh Jayaraman0f3bc092009-06-25 18:12:34 +0530801 return rc;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700802 }
Steve French08547b02006-02-28 22:39:25 +0000803 netfid = ((struct cifsFileInfo *)file->private_data)->netfid;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700804
Steve French13a6e422008-12-02 17:24:33 +0000805 if ((tcon->ses->capabilities & CAP_UNIX) &&
806 (CIFS_UNIX_FCNTL_CAP & le64_to_cpu(tcon->fsUnixInfo.Capability)) &&
Steve Frenchacc18aa2008-12-02 18:53:55 +0000807 ((cifs_sb->mnt_cifs_flags & CIFS_MOUNT_NOPOSIXBRL) == 0))
Steve French13a6e422008-12-02 17:24:33 +0000808 posix_locking = 1;
Steve French08547b02006-02-28 22:39:25 +0000809 /* BB add code here to normalize offset and length to
810 account for negative length which we can not accept over the
811 wire */
Linus Torvalds1da177e2005-04-16 15:20:36 -0700812 if (IS_GETLK(cmd)) {
Steve Frenchfb8c4b12007-07-10 01:16:18 +0000813 if (posix_locking) {
Steve French08547b02006-02-28 22:39:25 +0000814 int posix_lock_type;
Steve Frenchfb8c4b12007-07-10 01:16:18 +0000815 if (lockType & LOCKING_ANDX_SHARED_LOCK)
Steve French08547b02006-02-28 22:39:25 +0000816 posix_lock_type = CIFS_RDLCK;
817 else
818 posix_lock_type = CIFS_WRLCK;
Steve French13a6e422008-12-02 17:24:33 +0000819 rc = CIFSSMBPosixLock(xid, tcon, netfid, 1 /* get */,
Steve Frenchfc94cdb2006-05-30 18:03:32 +0000820 length, pfLock,
Steve French08547b02006-02-28 22:39:25 +0000821 posix_lock_type, wait_flag);
822 FreeXid(xid);
823 return rc;
824 }
825
826 /* BB we could chain these into one lock request BB */
Steve French13a6e422008-12-02 17:24:33 +0000827 rc = CIFSSMBLock(xid, tcon, netfid, length, pfLock->fl_start,
Steve French08547b02006-02-28 22:39:25 +0000828 0, 1, lockType, 0 /* wait flag */ );
Linus Torvalds1da177e2005-04-16 15:20:36 -0700829 if (rc == 0) {
Steve French13a6e422008-12-02 17:24:33 +0000830 rc = CIFSSMBLock(xid, tcon, netfid, length,
Linus Torvalds1da177e2005-04-16 15:20:36 -0700831 pfLock->fl_start, 1 /* numUnlock */ ,
832 0 /* numLock */ , lockType,
833 0 /* wait flag */ );
834 pfLock->fl_type = F_UNLCK;
835 if (rc != 0)
836 cERROR(1, ("Error unlocking previously locked "
Steve French08547b02006-02-28 22:39:25 +0000837 "range %d during test of lock", rc));
Linus Torvalds1da177e2005-04-16 15:20:36 -0700838 rc = 0;
839
840 } else {
841 /* if rc == ERR_SHARING_VIOLATION ? */
Pavel Shilovskyf05337c2010-04-05 09:59:14 +0400842 rc = 0;
843
844 if (lockType & LOCKING_ANDX_SHARED_LOCK) {
845 pfLock->fl_type = F_WRLCK;
846 } else {
847 rc = CIFSSMBLock(xid, tcon, netfid, length,
848 pfLock->fl_start, 0, 1,
849 lockType | LOCKING_ANDX_SHARED_LOCK,
850 0 /* wait flag */);
851 if (rc == 0) {
852 rc = CIFSSMBLock(xid, tcon, netfid,
853 length, pfLock->fl_start, 1, 0,
854 lockType |
855 LOCKING_ANDX_SHARED_LOCK,
856 0 /* wait flag */);
857 pfLock->fl_type = F_RDLCK;
858 if (rc != 0)
859 cERROR(1, ("Error unlocking "
860 "previously locked range %d "
861 "during test of lock", rc));
862 rc = 0;
863 } else {
864 pfLock->fl_type = F_WRLCK;
865 rc = 0;
866 }
867 }
Linus Torvalds1da177e2005-04-16 15:20:36 -0700868 }
869
870 FreeXid(xid);
871 return rc;
872 }
Jeremy Allison7ee1af72006-08-02 21:56:33 +0000873
874 if (!numLock && !numUnlock) {
875 /* if no lock or unlock then nothing
876 to do since we do not know what it is */
877 FreeXid(xid);
878 return -EOPNOTSUPP;
879 }
880
881 if (posix_locking) {
Steve French08547b02006-02-28 22:39:25 +0000882 int posix_lock_type;
Steve Frenchfb8c4b12007-07-10 01:16:18 +0000883 if (lockType & LOCKING_ANDX_SHARED_LOCK)
Steve French08547b02006-02-28 22:39:25 +0000884 posix_lock_type = CIFS_RDLCK;
885 else
886 posix_lock_type = CIFS_WRLCK;
Steve French50c2f752007-07-13 00:33:32 +0000887
Steve Frenchfb8c4b12007-07-10 01:16:18 +0000888 if (numUnlock == 1)
Steve Frenchbeb84dc2006-03-03 23:36:34 +0000889 posix_lock_type = CIFS_UNLCK;
Jeremy Allison7ee1af72006-08-02 21:56:33 +0000890
Steve French13a6e422008-12-02 17:24:33 +0000891 rc = CIFSSMBPosixLock(xid, tcon, netfid, 0 /* set */,
Steve Frenchfc94cdb2006-05-30 18:03:32 +0000892 length, pfLock,
Steve French08547b02006-02-28 22:39:25 +0000893 posix_lock_type, wait_flag);
Jeremy Allison7ee1af72006-08-02 21:56:33 +0000894 } else {
Steve Frenchfb8c4b12007-07-10 01:16:18 +0000895 struct cifsFileInfo *fid =
896 (struct cifsFileInfo *)file->private_data;
Jeremy Allison7ee1af72006-08-02 21:56:33 +0000897
898 if (numLock) {
Steve French13a6e422008-12-02 17:24:33 +0000899 rc = CIFSSMBLock(xid, tcon, netfid, length,
Steve Frenchfb8c4b12007-07-10 01:16:18 +0000900 pfLock->fl_start,
Jeremy Allison7ee1af72006-08-02 21:56:33 +0000901 0, numLock, lockType, wait_flag);
902
903 if (rc == 0) {
904 /* For Windows locks we must store them. */
905 rc = store_file_lock(fid, length,
906 pfLock->fl_start, lockType);
907 }
908 } else if (numUnlock) {
909 /* For each stored lock that this unlock overlaps
910 completely, unlock it. */
911 int stored_rc = 0;
912 struct cifsLockInfo *li, *tmp;
913
Steve French6b70c952006-09-21 07:35:29 +0000914 rc = 0;
Roland Dreier796e5662007-05-03 04:33:45 +0000915 mutex_lock(&fid->lock_mutex);
Jeremy Allison7ee1af72006-08-02 21:56:33 +0000916 list_for_each_entry_safe(li, tmp, &fid->llist, llist) {
917 if (pfLock->fl_start <= li->offset &&
Steve Frenchc19eb712007-08-24 03:22:48 +0000918 (pfLock->fl_start + length) >=
Jeff Layton39db8102007-08-24 03:16:51 +0000919 (li->offset + li->length)) {
Steve French13a6e422008-12-02 17:24:33 +0000920 stored_rc = CIFSSMBLock(xid, tcon,
Steve Frenchfb8c4b12007-07-10 01:16:18 +0000921 netfid,
Jeremy Allison7ee1af72006-08-02 21:56:33 +0000922 li->length, li->offset,
Steve French4b18f2a2008-04-29 00:06:05 +0000923 1, 0, li->type, false);
Jeremy Allison7ee1af72006-08-02 21:56:33 +0000924 if (stored_rc)
925 rc = stored_rc;
926
927 list_del(&li->llist);
928 kfree(li);
929 }
930 }
Roland Dreier796e5662007-05-03 04:33:45 +0000931 mutex_unlock(&fid->lock_mutex);
Jeremy Allison7ee1af72006-08-02 21:56:33 +0000932 }
933 }
934
Steve Frenchd634cc12005-08-26 14:42:59 -0500935 if (pfLock->fl_flags & FL_POSIX)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700936 posix_lock_file_wait(file, pfLock);
937 FreeXid(xid);
938 return rc;
939}
940
Jeff Laytonfbec9ab2009-04-03 13:44:00 -0400941/*
942 * Set the timeout on write requests past EOF. For some servers (Windows)
943 * these calls can be very long.
944 *
945 * If we're writing >10M past the EOF we give a 180s timeout. Anything less
946 * than that gets a 45s timeout. Writes not past EOF get 15s timeouts.
947 * The 10M cutoff is totally arbitrary. A better scheme for this would be
948 * welcome if someone wants to suggest one.
949 *
950 * We may be able to do a better job with this if there were some way to
951 * declare that a file should be sparse.
952 */
953static int
954cifs_write_timeout(struct cifsInodeInfo *cifsi, loff_t offset)
955{
956 if (offset <= cifsi->server_eof)
957 return CIFS_STD_OP;
958 else if (offset > (cifsi->server_eof + (10 * 1024 * 1024)))
959 return CIFS_VLONG_OP;
960 else
961 return CIFS_LONG_OP;
962}
963
964/* update the file size (if needed) after a write */
965static void
966cifs_update_eof(struct cifsInodeInfo *cifsi, loff_t offset,
967 unsigned int bytes_written)
968{
969 loff_t end_of_write = offset + bytes_written;
970
971 if (end_of_write > cifsi->server_eof)
972 cifsi->server_eof = end_of_write;
973}
974
Linus Torvalds1da177e2005-04-16 15:20:36 -0700975ssize_t cifs_user_write(struct file *file, const char __user *write_data,
976 size_t write_size, loff_t *poffset)
977{
978 int rc = 0;
979 unsigned int bytes_written = 0;
980 unsigned int total_written;
981 struct cifs_sb_info *cifs_sb;
982 struct cifsTconInfo *pTcon;
983 int xid, long_op;
984 struct cifsFileInfo *open_file;
Jeff Laytonfbec9ab2009-04-03 13:44:00 -0400985 struct cifsInodeInfo *cifsi = CIFS_I(file->f_path.dentry->d_inode);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700986
Josef "Jeff" Sipeke6a00292006-12-08 02:36:48 -0800987 cifs_sb = CIFS_SB(file->f_path.dentry->d_sb);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700988
989 pTcon = cifs_sb->tcon;
990
991 /* cFYI(1,
992 (" write %d bytes to offset %lld of %s", write_size,
Josef "Jeff" Sipeke6a00292006-12-08 02:36:48 -0800993 *poffset, file->f_path.dentry->d_name.name)); */
Linus Torvalds1da177e2005-04-16 15:20:36 -0700994
995 if (file->private_data == NULL)
996 return -EBADF;
Christoph Hellwigc33f8d32007-04-02 18:47:20 +0000997 open_file = (struct cifsFileInfo *) file->private_data;
Steve French50c2f752007-07-13 00:33:32 +0000998
Jeff Layton838726c2008-08-28 07:54:59 -0400999 rc = generic_write_checks(file, poffset, &write_size, 0);
1000 if (rc)
1001 return rc;
1002
Linus Torvalds1da177e2005-04-16 15:20:36 -07001003 xid = GetXid();
Linus Torvalds1da177e2005-04-16 15:20:36 -07001004
Jeff Laytonfbec9ab2009-04-03 13:44:00 -04001005 long_op = cifs_write_timeout(cifsi, *poffset);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001006 for (total_written = 0; write_size > total_written;
1007 total_written += bytes_written) {
1008 rc = -EAGAIN;
1009 while (rc == -EAGAIN) {
1010 if (file->private_data == NULL) {
1011 /* file has been closed on us */
1012 FreeXid(xid);
1013 /* if we have gotten here we have written some data
1014 and blocked, and the file has been freed on us while
1015 we blocked so return what we managed to write */
1016 return total_written;
Steve Frenchfb8c4b12007-07-10 01:16:18 +00001017 }
Linus Torvalds1da177e2005-04-16 15:20:36 -07001018 if (open_file->closePend) {
1019 FreeXid(xid);
1020 if (total_written)
1021 return total_written;
1022 else
1023 return -EBADF;
1024 }
1025 if (open_file->invalidHandle) {
Linus Torvalds1da177e2005-04-16 15:20:36 -07001026 /* we could deadlock if we called
1027 filemap_fdatawait from here so tell
1028 reopen_file not to flush data to server
1029 now */
Steve French4b18f2a2008-04-29 00:06:05 +00001030 rc = cifs_reopen_file(file, false);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001031 if (rc != 0)
1032 break;
1033 }
1034
1035 rc = CIFSSMBWrite(xid, pTcon,
1036 open_file->netfid,
1037 min_t(const int, cifs_sb->wsize,
1038 write_size - total_written),
1039 *poffset, &bytes_written,
1040 NULL, write_data + total_written, long_op);
1041 }
1042 if (rc || (bytes_written == 0)) {
1043 if (total_written)
1044 break;
1045 else {
1046 FreeXid(xid);
1047 return rc;
1048 }
Jeff Laytonfbec9ab2009-04-03 13:44:00 -04001049 } else {
1050 cifs_update_eof(cifsi, *poffset, bytes_written);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001051 *poffset += bytes_written;
Jeff Laytonfbec9ab2009-04-03 13:44:00 -04001052 }
Steve French133672e2007-11-13 22:41:37 +00001053 long_op = CIFS_STD_OP; /* subsequent writes fast -
Linus Torvalds1da177e2005-04-16 15:20:36 -07001054 15 seconds is plenty */
1055 }
1056
Steve Frencha4544342005-08-24 13:59:35 -07001057 cifs_stats_bytes_written(pTcon, total_written);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001058
1059 /* since the write may have blocked check these pointers again */
Steve French3677db12007-02-26 16:46:11 +00001060 if ((file->f_path.dentry) && (file->f_path.dentry->d_inode)) {
1061 struct inode *inode = file->f_path.dentry->d_inode;
Steve Frenchfb8c4b12007-07-10 01:16:18 +00001062/* Do not update local mtime - server will set its actual value on write
1063 * inode->i_ctime = inode->i_mtime =
Steve French3677db12007-02-26 16:46:11 +00001064 * current_fs_time(inode->i_sb);*/
1065 if (total_written > 0) {
1066 spin_lock(&inode->i_lock);
1067 if (*poffset > file->f_path.dentry->d_inode->i_size)
1068 i_size_write(file->f_path.dentry->d_inode,
Linus Torvalds1da177e2005-04-16 15:20:36 -07001069 *poffset);
Steve French3677db12007-02-26 16:46:11 +00001070 spin_unlock(&inode->i_lock);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001071 }
Steve Frenchfb8c4b12007-07-10 01:16:18 +00001072 mark_inode_dirty_sync(file->f_path.dentry->d_inode);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001073 }
1074 FreeXid(xid);
1075 return total_written;
1076}
1077
1078static ssize_t cifs_write(struct file *file, const char *write_data,
Nick Piggind9414772008-09-24 11:32:59 -04001079 size_t write_size, loff_t *poffset)
Linus Torvalds1da177e2005-04-16 15:20:36 -07001080{
1081 int rc = 0;
1082 unsigned int bytes_written = 0;
1083 unsigned int total_written;
1084 struct cifs_sb_info *cifs_sb;
1085 struct cifsTconInfo *pTcon;
1086 int xid, long_op;
1087 struct cifsFileInfo *open_file;
Jeff Laytonfbec9ab2009-04-03 13:44:00 -04001088 struct cifsInodeInfo *cifsi = CIFS_I(file->f_path.dentry->d_inode);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001089
Josef "Jeff" Sipeke6a00292006-12-08 02:36:48 -08001090 cifs_sb = CIFS_SB(file->f_path.dentry->d_sb);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001091
1092 pTcon = cifs_sb->tcon;
1093
Steve Frenchfb8c4b12007-07-10 01:16:18 +00001094 cFYI(1, ("write %zd bytes to offset %lld of %s", write_size,
Josef "Jeff" Sipeke6a00292006-12-08 02:36:48 -08001095 *poffset, file->f_path.dentry->d_name.name));
Linus Torvalds1da177e2005-04-16 15:20:36 -07001096
1097 if (file->private_data == NULL)
1098 return -EBADF;
Christoph Hellwigc33f8d32007-04-02 18:47:20 +00001099 open_file = (struct cifsFileInfo *)file->private_data;
Steve French50c2f752007-07-13 00:33:32 +00001100
Linus Torvalds1da177e2005-04-16 15:20:36 -07001101 xid = GetXid();
Linus Torvalds1da177e2005-04-16 15:20:36 -07001102
Jeff Laytonfbec9ab2009-04-03 13:44:00 -04001103 long_op = cifs_write_timeout(cifsi, *poffset);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001104 for (total_written = 0; write_size > total_written;
1105 total_written += bytes_written) {
1106 rc = -EAGAIN;
1107 while (rc == -EAGAIN) {
1108 if (file->private_data == NULL) {
1109 /* file has been closed on us */
1110 FreeXid(xid);
1111 /* if we have gotten here we have written some data
1112 and blocked, and the file has been freed on us
Steve Frenchfb8c4b12007-07-10 01:16:18 +00001113 while we blocked so return what we managed to
Linus Torvalds1da177e2005-04-16 15:20:36 -07001114 write */
1115 return total_written;
Steve Frenchfb8c4b12007-07-10 01:16:18 +00001116 }
Linus Torvalds1da177e2005-04-16 15:20:36 -07001117 if (open_file->closePend) {
1118 FreeXid(xid);
1119 if (total_written)
1120 return total_written;
1121 else
1122 return -EBADF;
1123 }
1124 if (open_file->invalidHandle) {
Linus Torvalds1da177e2005-04-16 15:20:36 -07001125 /* we could deadlock if we called
1126 filemap_fdatawait from here so tell
Steve Frenchfb8c4b12007-07-10 01:16:18 +00001127 reopen_file not to flush data to
Linus Torvalds1da177e2005-04-16 15:20:36 -07001128 server now */
Steve French4b18f2a2008-04-29 00:06:05 +00001129 rc = cifs_reopen_file(file, false);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001130 if (rc != 0)
1131 break;
1132 }
Steve Frenchfb8c4b12007-07-10 01:16:18 +00001133 if (experimEnabled || (pTcon->ses->server &&
1134 ((pTcon->ses->server->secMode &
Steve French08775832006-05-30 18:08:26 +00001135 (SECMODE_SIGN_REQUIRED | SECMODE_SIGN_ENABLED))
Steve Frenchc01f36a2006-05-30 18:05:10 +00001136 == 0))) {
Steve French3e844692005-10-03 13:37:24 -07001137 struct kvec iov[2];
1138 unsigned int len;
1139
Steve French0ae0efa2005-10-10 10:57:19 -07001140 len = min((size_t)cifs_sb->wsize,
Steve French3e844692005-10-03 13:37:24 -07001141 write_size - total_written);
1142 /* iov[0] is reserved for smb header */
1143 iov[1].iov_base = (char *)write_data +
1144 total_written;
1145 iov[1].iov_len = len;
Steve Frenchd6e04ae2005-06-13 13:24:43 -05001146 rc = CIFSSMBWrite2(xid, pTcon,
Steve French3e844692005-10-03 13:37:24 -07001147 open_file->netfid, len,
Steve Frenchd6e04ae2005-06-13 13:24:43 -05001148 *poffset, &bytes_written,
Steve French3e844692005-10-03 13:37:24 -07001149 iov, 1, long_op);
Steve Frenchd6e04ae2005-06-13 13:24:43 -05001150 } else
Steve French60808232006-04-22 15:53:05 +00001151 rc = CIFSSMBWrite(xid, pTcon,
1152 open_file->netfid,
1153 min_t(const int, cifs_sb->wsize,
1154 write_size - total_written),
1155 *poffset, &bytes_written,
1156 write_data + total_written,
1157 NULL, long_op);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001158 }
1159 if (rc || (bytes_written == 0)) {
1160 if (total_written)
1161 break;
1162 else {
1163 FreeXid(xid);
1164 return rc;
1165 }
Jeff Laytonfbec9ab2009-04-03 13:44:00 -04001166 } else {
1167 cifs_update_eof(cifsi, *poffset, bytes_written);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001168 *poffset += bytes_written;
Jeff Laytonfbec9ab2009-04-03 13:44:00 -04001169 }
Steve French133672e2007-11-13 22:41:37 +00001170 long_op = CIFS_STD_OP; /* subsequent writes fast -
Linus Torvalds1da177e2005-04-16 15:20:36 -07001171 15 seconds is plenty */
1172 }
1173
Steve Frencha4544342005-08-24 13:59:35 -07001174 cifs_stats_bytes_written(pTcon, total_written);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001175
1176 /* since the write may have blocked check these pointers again */
Steve French3677db12007-02-26 16:46:11 +00001177 if ((file->f_path.dentry) && (file->f_path.dentry->d_inode)) {
Steve French004c46b2007-02-17 04:34:13 +00001178/*BB We could make this contingent on superblock ATIME flag too */
Steve French3677db12007-02-26 16:46:11 +00001179/* file->f_path.dentry->d_inode->i_ctime =
1180 file->f_path.dentry->d_inode->i_mtime = CURRENT_TIME;*/
1181 if (total_written > 0) {
1182 spin_lock(&file->f_path.dentry->d_inode->i_lock);
1183 if (*poffset > file->f_path.dentry->d_inode->i_size)
1184 i_size_write(file->f_path.dentry->d_inode,
1185 *poffset);
1186 spin_unlock(&file->f_path.dentry->d_inode->i_lock);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001187 }
Steve French3677db12007-02-26 16:46:11 +00001188 mark_inode_dirty_sync(file->f_path.dentry->d_inode);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001189 }
1190 FreeXid(xid);
1191 return total_written;
1192}
1193
Steve French630f3f0c2007-10-25 21:17:17 +00001194#ifdef CONFIG_CIFS_EXPERIMENTAL
1195struct cifsFileInfo *find_readable_file(struct cifsInodeInfo *cifs_inode)
1196{
1197 struct cifsFileInfo *open_file = NULL;
1198
1199 read_lock(&GlobalSMBSeslock);
1200 /* we could simply get the first_list_entry since write-only entries
1201 are always at the end of the list but since the first entry might
1202 have a close pending, we go through the whole list */
1203 list_for_each_entry(open_file, &cifs_inode->openFileList, flist) {
1204 if (open_file->closePend)
1205 continue;
1206 if (open_file->pfile && ((open_file->pfile->f_flags & O_RDWR) ||
1207 (open_file->pfile->f_flags & O_RDONLY))) {
1208 if (!open_file->invalidHandle) {
1209 /* found a good file */
1210 /* lock it so it will not be closed on us */
Dave Kleikamp6ab409b2009-08-31 11:07:12 -04001211 cifsFileInfo_get(open_file);
Steve French630f3f0c2007-10-25 21:17:17 +00001212 read_unlock(&GlobalSMBSeslock);
1213 return open_file;
1214 } /* else might as well continue, and look for
1215 another, or simply have the caller reopen it
1216 again rather than trying to fix this handle */
1217 } else /* write only file */
1218 break; /* write only files are last so must be done */
1219 }
1220 read_unlock(&GlobalSMBSeslock);
1221 return NULL;
1222}
1223#endif
1224
Steve Frenchdd99cd82005-10-05 19:32:49 -07001225struct cifsFileInfo *find_writable_file(struct cifsInodeInfo *cifs_inode)
Steve French6148a742005-10-05 12:23:19 -07001226{
1227 struct cifsFileInfo *open_file;
Jeff Layton2846d382008-09-22 21:33:33 -04001228 bool any_available = false;
Steve Frenchdd99cd82005-10-05 19:32:49 -07001229 int rc;
Steve French6148a742005-10-05 12:23:19 -07001230
Steve French60808232006-04-22 15:53:05 +00001231 /* Having a null inode here (because mapping->host was set to zero by
1232 the VFS or MM) should not happen but we had reports of on oops (due to
1233 it being zero) during stress testcases so we need to check for it */
1234
Steve Frenchfb8c4b12007-07-10 01:16:18 +00001235 if (cifs_inode == NULL) {
1236 cERROR(1, ("Null inode passed to cifs_writeable_file"));
Steve French60808232006-04-22 15:53:05 +00001237 dump_stack();
1238 return NULL;
1239 }
1240
Steve French6148a742005-10-05 12:23:19 -07001241 read_lock(&GlobalSMBSeslock);
Steve French9b22b0b2007-10-02 01:11:08 +00001242refind_writable:
Steve French6148a742005-10-05 12:23:19 -07001243 list_for_each_entry(open_file, &cifs_inode->openFileList, flist) {
Jeff Layton2846d382008-09-22 21:33:33 -04001244 if (open_file->closePend ||
1245 (!any_available && open_file->pid != current->tgid))
Steve French6148a742005-10-05 12:23:19 -07001246 continue;
Jeff Layton2846d382008-09-22 21:33:33 -04001247
Steve French6148a742005-10-05 12:23:19 -07001248 if (open_file->pfile &&
1249 ((open_file->pfile->f_flags & O_RDWR) ||
1250 (open_file->pfile->f_flags & O_WRONLY))) {
Dave Kleikamp6ab409b2009-08-31 11:07:12 -04001251 cifsFileInfo_get(open_file);
Steve French9b22b0b2007-10-02 01:11:08 +00001252
1253 if (!open_file->invalidHandle) {
1254 /* found a good writable file */
1255 read_unlock(&GlobalSMBSeslock);
1256 return open_file;
1257 }
Steve French8840dee2007-11-16 23:05:52 +00001258
Steve French6148a742005-10-05 12:23:19 -07001259 read_unlock(&GlobalSMBSeslock);
Steve French9b22b0b2007-10-02 01:11:08 +00001260 /* Had to unlock since following call can block */
Steve French4b18f2a2008-04-29 00:06:05 +00001261 rc = cifs_reopen_file(open_file->pfile, false);
Steve French8840dee2007-11-16 23:05:52 +00001262 if (!rc) {
Steve French9b22b0b2007-10-02 01:11:08 +00001263 if (!open_file->closePend)
1264 return open_file;
1265 else { /* start over in case this was deleted */
1266 /* since the list could be modified */
Steve French37c0eb42005-10-05 14:50:29 -07001267 read_lock(&GlobalSMBSeslock);
Dave Kleikamp6ab409b2009-08-31 11:07:12 -04001268 cifsFileInfo_put(open_file);
Steve French9b22b0b2007-10-02 01:11:08 +00001269 goto refind_writable;
Steve French37c0eb42005-10-05 14:50:29 -07001270 }
1271 }
Steve French9b22b0b2007-10-02 01:11:08 +00001272
1273 /* if it fails, try another handle if possible -
1274 (we can not do this if closePending since
1275 loop could be modified - in which case we
1276 have to start at the beginning of the list
1277 again. Note that it would be bad
1278 to hold up writepages here (rather than
1279 in caller) with continuous retries */
1280 cFYI(1, ("wp failed on reopen file"));
1281 read_lock(&GlobalSMBSeslock);
1282 /* can not use this handle, no write
1283 pending on this one after all */
Dave Kleikamp6ab409b2009-08-31 11:07:12 -04001284 cifsFileInfo_put(open_file);
Steve French8840dee2007-11-16 23:05:52 +00001285
Steve French9b22b0b2007-10-02 01:11:08 +00001286 if (open_file->closePend) /* list could have changed */
1287 goto refind_writable;
1288 /* else we simply continue to the next entry. Thus
1289 we do not loop on reopen errors. If we
1290 can not reopen the file, for example if we
1291 reconnected to a server with another client
1292 racing to delete or lock the file we would not
1293 make progress if we restarted before the beginning
1294 of the loop here. */
Steve French6148a742005-10-05 12:23:19 -07001295 }
1296 }
Jeff Layton2846d382008-09-22 21:33:33 -04001297 /* couldn't find useable FH with same pid, try any available */
1298 if (!any_available) {
1299 any_available = true;
1300 goto refind_writable;
1301 }
Steve French6148a742005-10-05 12:23:19 -07001302 read_unlock(&GlobalSMBSeslock);
1303 return NULL;
1304}
1305
Linus Torvalds1da177e2005-04-16 15:20:36 -07001306static int cifs_partialpagewrite(struct page *page, unsigned from, unsigned to)
1307{
1308 struct address_space *mapping = page->mapping;
1309 loff_t offset = (loff_t)page->index << PAGE_CACHE_SHIFT;
1310 char *write_data;
1311 int rc = -EFAULT;
1312 int bytes_written = 0;
1313 struct cifs_sb_info *cifs_sb;
1314 struct cifsTconInfo *pTcon;
1315 struct inode *inode;
Steve French6148a742005-10-05 12:23:19 -07001316 struct cifsFileInfo *open_file;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001317
1318 if (!mapping || !mapping->host)
1319 return -EFAULT;
1320
1321 inode = page->mapping->host;
1322 cifs_sb = CIFS_SB(inode->i_sb);
1323 pTcon = cifs_sb->tcon;
1324
1325 offset += (loff_t)from;
1326 write_data = kmap(page);
1327 write_data += from;
1328
1329 if ((to > PAGE_CACHE_SIZE) || (from > to)) {
1330 kunmap(page);
1331 return -EIO;
1332 }
1333
1334 /* racing with truncate? */
1335 if (offset > mapping->host->i_size) {
1336 kunmap(page);
1337 return 0; /* don't care */
1338 }
1339
1340 /* check to make sure that we are not extending the file */
1341 if (mapping->host->i_size - offset < (loff_t)to)
Steve Frenchfb8c4b12007-07-10 01:16:18 +00001342 to = (unsigned)(mapping->host->i_size - offset);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001343
Steve French6148a742005-10-05 12:23:19 -07001344 open_file = find_writable_file(CIFS_I(mapping->host));
1345 if (open_file) {
1346 bytes_written = cifs_write(open_file->pfile, write_data,
1347 to-from, &offset);
Dave Kleikamp6ab409b2009-08-31 11:07:12 -04001348 cifsFileInfo_put(open_file);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001349 /* Does mm or vfs already set times? */
Steve French6148a742005-10-05 12:23:19 -07001350 inode->i_atime = inode->i_mtime = current_fs_time(inode->i_sb);
Steve Frenchbb5a9a02007-12-31 04:21:29 +00001351 if ((bytes_written > 0) && (offset))
Steve French6148a742005-10-05 12:23:19 -07001352 rc = 0;
Steve Frenchbb5a9a02007-12-31 04:21:29 +00001353 else if (bytes_written < 0)
1354 rc = bytes_written;
Steve French6148a742005-10-05 12:23:19 -07001355 } else {
Linus Torvalds1da177e2005-04-16 15:20:36 -07001356 cFYI(1, ("No writeable filehandles for inode"));
1357 rc = -EIO;
1358 }
1359
1360 kunmap(page);
1361 return rc;
1362}
1363
Linus Torvalds1da177e2005-04-16 15:20:36 -07001364static int cifs_writepages(struct address_space *mapping,
Steve French37c0eb42005-10-05 14:50:29 -07001365 struct writeback_control *wbc)
Linus Torvalds1da177e2005-04-16 15:20:36 -07001366{
Steve French37c0eb42005-10-05 14:50:29 -07001367 struct backing_dev_info *bdi = mapping->backing_dev_info;
1368 unsigned int bytes_to_write;
1369 unsigned int bytes_written;
1370 struct cifs_sb_info *cifs_sb;
1371 int done = 0;
OGAWA Hirofumi111ebb62006-06-23 02:03:26 -07001372 pgoff_t end;
Steve French37c0eb42005-10-05 14:50:29 -07001373 pgoff_t index;
Steve Frenchfb8c4b12007-07-10 01:16:18 +00001374 int range_whole = 0;
1375 struct kvec *iov;
Steve French84d2f072005-10-12 15:32:05 -07001376 int len;
Steve French37c0eb42005-10-05 14:50:29 -07001377 int n_iov = 0;
1378 pgoff_t next;
1379 int nr_pages;
1380 __u64 offset = 0;
Steve French23e7dd72005-10-20 13:44:56 -07001381 struct cifsFileInfo *open_file;
Jeff Laytonfbec9ab2009-04-03 13:44:00 -04001382 struct cifsInodeInfo *cifsi = CIFS_I(mapping->host);
Steve French37c0eb42005-10-05 14:50:29 -07001383 struct page *page;
1384 struct pagevec pvec;
1385 int rc = 0;
1386 int scanned = 0;
Jeff Laytonfbec9ab2009-04-03 13:44:00 -04001387 int xid, long_op;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001388
Steve French37c0eb42005-10-05 14:50:29 -07001389 cifs_sb = CIFS_SB(mapping->host->i_sb);
Steve French50c2f752007-07-13 00:33:32 +00001390
Steve French37c0eb42005-10-05 14:50:29 -07001391 /*
1392 * If wsize is smaller that the page cache size, default to writing
1393 * one page at a time via cifs_writepage
1394 */
1395 if (cifs_sb->wsize < PAGE_CACHE_SIZE)
1396 return generic_writepages(mapping, wbc);
1397
Steve Frenchfb8c4b12007-07-10 01:16:18 +00001398 if ((cifs_sb->tcon->ses) && (cifs_sb->tcon->ses->server))
1399 if (cifs_sb->tcon->ses->server->secMode &
1400 (SECMODE_SIGN_REQUIRED | SECMODE_SIGN_ENABLED))
1401 if (!experimEnabled)
Steve French60808232006-04-22 15:53:05 +00001402 return generic_writepages(mapping, wbc);
Steve French4a771182005-10-05 15:14:33 -07001403
Steve French9a0c8232007-02-02 04:21:57 +00001404 iov = kmalloc(32 * sizeof(struct kvec), GFP_KERNEL);
Steve Frenchfb8c4b12007-07-10 01:16:18 +00001405 if (iov == NULL)
Steve French9a0c8232007-02-02 04:21:57 +00001406 return generic_writepages(mapping, wbc);
1407
1408
Steve French37c0eb42005-10-05 14:50:29 -07001409 /*
1410 * BB: Is this meaningful for a non-block-device file system?
1411 * If it is, we should test it again after we do I/O
1412 */
1413 if (wbc->nonblocking && bdi_write_congested(bdi)) {
1414 wbc->encountered_congestion = 1;
Steve French9a0c8232007-02-02 04:21:57 +00001415 kfree(iov);
Steve French37c0eb42005-10-05 14:50:29 -07001416 return 0;
1417 }
1418
Linus Torvalds1da177e2005-04-16 15:20:36 -07001419 xid = GetXid();
1420
Steve French37c0eb42005-10-05 14:50:29 -07001421 pagevec_init(&pvec, 0);
OGAWA Hirofumi111ebb62006-06-23 02:03:26 -07001422 if (wbc->range_cyclic) {
Steve French37c0eb42005-10-05 14:50:29 -07001423 index = mapping->writeback_index; /* Start from prev offset */
OGAWA Hirofumi111ebb62006-06-23 02:03:26 -07001424 end = -1;
1425 } else {
1426 index = wbc->range_start >> PAGE_CACHE_SHIFT;
1427 end = wbc->range_end >> PAGE_CACHE_SHIFT;
1428 if (wbc->range_start == 0 && wbc->range_end == LLONG_MAX)
1429 range_whole = 1;
Steve French37c0eb42005-10-05 14:50:29 -07001430 scanned = 1;
1431 }
1432retry:
1433 while (!done && (index <= end) &&
1434 (nr_pages = pagevec_lookup_tag(&pvec, mapping, &index,
1435 PAGECACHE_TAG_DIRTY,
1436 min(end - index, (pgoff_t)PAGEVEC_SIZE - 1) + 1))) {
1437 int first;
1438 unsigned int i;
1439
Steve French37c0eb42005-10-05 14:50:29 -07001440 first = -1;
1441 next = 0;
1442 n_iov = 0;
1443 bytes_to_write = 0;
1444
1445 for (i = 0; i < nr_pages; i++) {
1446 page = pvec.pages[i];
1447 /*
1448 * At this point we hold neither mapping->tree_lock nor
1449 * lock on the page itself: the page may be truncated or
1450 * invalidated (changing page->mapping to NULL), or even
1451 * swizzled back from swapper_space to tmpfs file
1452 * mapping
1453 */
1454
1455 if (first < 0)
1456 lock_page(page);
Nick Piggin529ae9a2008-08-02 12:01:03 +02001457 else if (!trylock_page(page))
Steve French37c0eb42005-10-05 14:50:29 -07001458 break;
1459
1460 if (unlikely(page->mapping != mapping)) {
1461 unlock_page(page);
1462 break;
1463 }
1464
OGAWA Hirofumi111ebb62006-06-23 02:03:26 -07001465 if (!wbc->range_cyclic && page->index > end) {
Steve French37c0eb42005-10-05 14:50:29 -07001466 done = 1;
1467 unlock_page(page);
1468 break;
1469 }
1470
1471 if (next && (page->index != next)) {
1472 /* Not next consecutive page */
1473 unlock_page(page);
1474 break;
1475 }
1476
1477 if (wbc->sync_mode != WB_SYNC_NONE)
1478 wait_on_page_writeback(page);
1479
1480 if (PageWriteback(page) ||
Linus Torvaldscb876f42006-12-23 16:19:07 -08001481 !clear_page_dirty_for_io(page)) {
Steve French37c0eb42005-10-05 14:50:29 -07001482 unlock_page(page);
1483 break;
1484 }
Steve French84d2f072005-10-12 15:32:05 -07001485
Linus Torvaldscb876f42006-12-23 16:19:07 -08001486 /*
1487 * This actually clears the dirty bit in the radix tree.
1488 * See cifs_writepage() for more commentary.
1489 */
1490 set_page_writeback(page);
1491
Steve French84d2f072005-10-12 15:32:05 -07001492 if (page_offset(page) >= mapping->host->i_size) {
1493 done = 1;
1494 unlock_page(page);
Linus Torvaldscb876f42006-12-23 16:19:07 -08001495 end_page_writeback(page);
Steve French84d2f072005-10-12 15:32:05 -07001496 break;
1497 }
1498
Steve French37c0eb42005-10-05 14:50:29 -07001499 /*
1500 * BB can we get rid of this? pages are held by pvec
1501 */
1502 page_cache_get(page);
1503
Steve French84d2f072005-10-12 15:32:05 -07001504 len = min(mapping->host->i_size - page_offset(page),
1505 (loff_t)PAGE_CACHE_SIZE);
1506
Steve French37c0eb42005-10-05 14:50:29 -07001507 /* reserve iov[0] for the smb header */
1508 n_iov++;
1509 iov[n_iov].iov_base = kmap(page);
Steve French84d2f072005-10-12 15:32:05 -07001510 iov[n_iov].iov_len = len;
1511 bytes_to_write += len;
Steve French37c0eb42005-10-05 14:50:29 -07001512
1513 if (first < 0) {
1514 first = i;
1515 offset = page_offset(page);
1516 }
1517 next = page->index + 1;
1518 if (bytes_to_write + PAGE_CACHE_SIZE > cifs_sb->wsize)
1519 break;
1520 }
1521 if (n_iov) {
Steve French23e7dd72005-10-20 13:44:56 -07001522 /* Search for a writable handle every time we call
1523 * CIFSSMBWrite2. We can't rely on the last handle
1524 * we used to still be valid
1525 */
1526 open_file = find_writable_file(CIFS_I(mapping->host));
1527 if (!open_file) {
1528 cERROR(1, ("No writable handles for inode"));
1529 rc = -EBADF;
Steve French1047abc2005-10-11 19:58:06 -07001530 } else {
Jeff Laytonfbec9ab2009-04-03 13:44:00 -04001531 long_op = cifs_write_timeout(cifsi, offset);
Steve French23e7dd72005-10-20 13:44:56 -07001532 rc = CIFSSMBWrite2(xid, cifs_sb->tcon,
1533 open_file->netfid,
1534 bytes_to_write, offset,
1535 &bytes_written, iov, n_iov,
Jeff Laytonfbec9ab2009-04-03 13:44:00 -04001536 long_op);
Dave Kleikamp6ab409b2009-08-31 11:07:12 -04001537 cifsFileInfo_put(open_file);
Jeff Laytonfbec9ab2009-04-03 13:44:00 -04001538 cifs_update_eof(cifsi, offset, bytes_written);
1539
Steve French23e7dd72005-10-20 13:44:56 -07001540 if (rc || bytes_written < bytes_to_write) {
Steve French63135e02007-07-17 17:34:02 +00001541 cERROR(1, ("Write2 ret %d, wrote %d",
Steve French23e7dd72005-10-20 13:44:56 -07001542 rc, bytes_written));
1543 /* BB what if continued retry is
1544 requested via mount flags? */
Jeff Laytoncea21802007-11-20 23:19:03 +00001545 if (rc == -ENOSPC)
1546 set_bit(AS_ENOSPC, &mapping->flags);
1547 else
1548 set_bit(AS_EIO, &mapping->flags);
Steve French23e7dd72005-10-20 13:44:56 -07001549 } else {
1550 cifs_stats_bytes_written(cifs_sb->tcon,
1551 bytes_written);
1552 }
Steve French37c0eb42005-10-05 14:50:29 -07001553 }
1554 for (i = 0; i < n_iov; i++) {
1555 page = pvec.pages[first + i];
Steve Frencheb9bdaa2006-01-27 15:11:47 -08001556 /* Should we also set page error on
1557 success rc but too little data written? */
1558 /* BB investigate retry logic on temporary
1559 server crash cases and how recovery works
Steve Frenchfb8c4b12007-07-10 01:16:18 +00001560 when page marked as error */
1561 if (rc)
Steve Frencheb9bdaa2006-01-27 15:11:47 -08001562 SetPageError(page);
Steve French37c0eb42005-10-05 14:50:29 -07001563 kunmap(page);
1564 unlock_page(page);
Linus Torvaldscb876f42006-12-23 16:19:07 -08001565 end_page_writeback(page);
Steve French37c0eb42005-10-05 14:50:29 -07001566 page_cache_release(page);
1567 }
1568 if ((wbc->nr_to_write -= n_iov) <= 0)
1569 done = 1;
1570 index = next;
Dave Kleikampb066a482008-11-18 03:49:05 +00001571 } else
1572 /* Need to re-find the pages we skipped */
1573 index = pvec.pages[0]->index + 1;
1574
Steve French37c0eb42005-10-05 14:50:29 -07001575 pagevec_release(&pvec);
1576 }
1577 if (!scanned && !done) {
1578 /*
1579 * We hit the last page and there is more work to be done: wrap
1580 * back to the start of the file
1581 */
1582 scanned = 1;
1583 index = 0;
1584 goto retry;
1585 }
OGAWA Hirofumi111ebb62006-06-23 02:03:26 -07001586 if (wbc->range_cyclic || (range_whole && wbc->nr_to_write > 0))
Steve French37c0eb42005-10-05 14:50:29 -07001587 mapping->writeback_index = index;
1588
Linus Torvalds1da177e2005-04-16 15:20:36 -07001589 FreeXid(xid);
Steve French9a0c8232007-02-02 04:21:57 +00001590 kfree(iov);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001591 return rc;
1592}
Linus Torvalds1da177e2005-04-16 15:20:36 -07001593
Steve Frenchfb8c4b12007-07-10 01:16:18 +00001594static int cifs_writepage(struct page *page, struct writeback_control *wbc)
Linus Torvalds1da177e2005-04-16 15:20:36 -07001595{
1596 int rc = -EFAULT;
1597 int xid;
1598
1599 xid = GetXid();
1600/* BB add check for wbc flags */
1601 page_cache_get(page);
Steve Frenchad7a2922008-02-07 23:25:02 +00001602 if (!PageUptodate(page))
Linus Torvalds1da177e2005-04-16 15:20:36 -07001603 cFYI(1, ("ppw - page not up to date"));
Linus Torvaldscb876f42006-12-23 16:19:07 -08001604
1605 /*
1606 * Set the "writeback" flag, and clear "dirty" in the radix tree.
1607 *
1608 * A writepage() implementation always needs to do either this,
1609 * or re-dirty the page with "redirty_page_for_writepage()" in
1610 * the case of a failure.
1611 *
1612 * Just unlocking the page will cause the radix tree tag-bits
1613 * to fail to update with the state of the page correctly.
1614 */
Steve Frenchfb8c4b12007-07-10 01:16:18 +00001615 set_page_writeback(page);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001616 rc = cifs_partialpagewrite(page, 0, PAGE_CACHE_SIZE);
1617 SetPageUptodate(page); /* BB add check for error and Clearuptodate? */
1618 unlock_page(page);
Linus Torvaldscb876f42006-12-23 16:19:07 -08001619 end_page_writeback(page);
1620 page_cache_release(page);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001621 FreeXid(xid);
1622 return rc;
1623}
1624
Nick Piggind9414772008-09-24 11:32:59 -04001625static int cifs_write_end(struct file *file, struct address_space *mapping,
1626 loff_t pos, unsigned len, unsigned copied,
1627 struct page *page, void *fsdata)
Linus Torvalds1da177e2005-04-16 15:20:36 -07001628{
Nick Piggind9414772008-09-24 11:32:59 -04001629 int rc;
1630 struct inode *inode = mapping->host;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001631
Nick Piggind9414772008-09-24 11:32:59 -04001632 cFYI(1, ("write_end for page %p from pos %lld with %d bytes",
1633 page, pos, copied));
Steve Frenchad7a2922008-02-07 23:25:02 +00001634
Jeff Laytona98ee8c2008-11-26 19:32:33 +00001635 if (PageChecked(page)) {
1636 if (copied == len)
1637 SetPageUptodate(page);
1638 ClearPageChecked(page);
1639 } else if (!PageUptodate(page) && copied == PAGE_CACHE_SIZE)
Nick Piggind9414772008-09-24 11:32:59 -04001640 SetPageUptodate(page);
1641
Linus Torvalds1da177e2005-04-16 15:20:36 -07001642 if (!PageUptodate(page)) {
Nick Piggind9414772008-09-24 11:32:59 -04001643 char *page_data;
1644 unsigned offset = pos & (PAGE_CACHE_SIZE - 1);
1645 int xid;
1646
1647 xid = GetXid();
Linus Torvalds1da177e2005-04-16 15:20:36 -07001648 /* this is probably better than directly calling
1649 partialpage_write since in this function the file handle is
1650 known which we might as well leverage */
1651 /* BB check if anything else missing out of ppw
1652 such as updating last write time */
1653 page_data = kmap(page);
Nick Piggind9414772008-09-24 11:32:59 -04001654 rc = cifs_write(file, page_data + offset, copied, &pos);
1655 /* if (rc < 0) should we set writebehind rc? */
Linus Torvalds1da177e2005-04-16 15:20:36 -07001656 kunmap(page);
Nick Piggind9414772008-09-24 11:32:59 -04001657
1658 FreeXid(xid);
Steve Frenchfb8c4b12007-07-10 01:16:18 +00001659 } else {
Nick Piggind9414772008-09-24 11:32:59 -04001660 rc = copied;
1661 pos += copied;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001662 set_page_dirty(page);
1663 }
1664
Nick Piggind9414772008-09-24 11:32:59 -04001665 if (rc > 0) {
1666 spin_lock(&inode->i_lock);
1667 if (pos > inode->i_size)
1668 i_size_write(inode, pos);
1669 spin_unlock(&inode->i_lock);
1670 }
1671
1672 unlock_page(page);
1673 page_cache_release(page);
1674
Linus Torvalds1da177e2005-04-16 15:20:36 -07001675 return rc;
1676}
1677
1678int cifs_fsync(struct file *file, struct dentry *dentry, int datasync)
1679{
1680 int xid;
1681 int rc = 0;
Steve Frenchb298f222009-02-21 21:17:43 +00001682 struct cifsTconInfo *tcon;
1683 struct cifsFileInfo *smbfile =
1684 (struct cifsFileInfo *)file->private_data;
Josef "Jeff" Sipeke6a00292006-12-08 02:36:48 -08001685 struct inode *inode = file->f_path.dentry->d_inode;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001686
1687 xid = GetXid();
1688
Steve Frenchfb8c4b12007-07-10 01:16:18 +00001689 cFYI(1, ("Sync file - name: %s datasync: 0x%x",
Linus Torvalds1da177e2005-04-16 15:20:36 -07001690 dentry->d_name.name, datasync));
Steve French50c2f752007-07-13 00:33:32 +00001691
Jeff Laytoncea21802007-11-20 23:19:03 +00001692 rc = filemap_write_and_wait(inode->i_mapping);
1693 if (rc == 0) {
1694 rc = CIFS_I(inode)->write_behind_rc;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001695 CIFS_I(inode)->write_behind_rc = 0;
Steve Frenchb298f222009-02-21 21:17:43 +00001696 tcon = CIFS_SB(inode->i_sb)->tcon;
Steve Frenchbe652442009-02-23 15:21:59 +00001697 if (!rc && tcon && smbfile &&
Steve French4717bed2009-02-24 14:44:19 +00001698 !(CIFS_SB(inode->i_sb)->mnt_cifs_flags & CIFS_MOUNT_NOSSYNC))
Steve Frenchb298f222009-02-21 21:17:43 +00001699 rc = CIFSSMBFlush(xid, tcon, smbfile->netfid);
Jeff Laytoncea21802007-11-20 23:19:03 +00001700 }
Steve Frenchb298f222009-02-21 21:17:43 +00001701
Linus Torvalds1da177e2005-04-16 15:20:36 -07001702 FreeXid(xid);
1703 return rc;
1704}
1705
NeilBrown3978d7172006-03-26 01:37:17 -08001706/* static void cifs_sync_page(struct page *page)
Linus Torvalds1da177e2005-04-16 15:20:36 -07001707{
1708 struct address_space *mapping;
1709 struct inode *inode;
1710 unsigned long index = page->index;
1711 unsigned int rpages = 0;
1712 int rc = 0;
1713
1714 cFYI(1, ("sync page %p",page));
1715 mapping = page->mapping;
1716 if (!mapping)
1717 return 0;
1718 inode = mapping->host;
1719 if (!inode)
NeilBrown3978d7172006-03-26 01:37:17 -08001720 return; */
Linus Torvalds1da177e2005-04-16 15:20:36 -07001721
Steve Frenchfb8c4b12007-07-10 01:16:18 +00001722/* fill in rpages then
Linus Torvalds1da177e2005-04-16 15:20:36 -07001723 result = cifs_pagein_inode(inode, index, rpages); */ /* BB finish */
1724
Steve French26a21b92006-05-31 18:05:34 +00001725/* cFYI(1, ("rpages is %d for sync page of Index %ld", rpages, index));
Linus Torvalds1da177e2005-04-16 15:20:36 -07001726
NeilBrown3978d7172006-03-26 01:37:17 -08001727#if 0
Linus Torvalds1da177e2005-04-16 15:20:36 -07001728 if (rc < 0)
1729 return rc;
1730 return 0;
NeilBrown3978d7172006-03-26 01:37:17 -08001731#endif
Linus Torvalds1da177e2005-04-16 15:20:36 -07001732} */
1733
1734/*
1735 * As file closes, flush all cached write data for this inode checking
1736 * for write behind errors.
1737 */
Miklos Szeredi75e1fcc2006-06-23 02:05:12 -07001738int cifs_flush(struct file *file, fl_owner_t id)
Linus Torvalds1da177e2005-04-16 15:20:36 -07001739{
Steve Frenchfb8c4b12007-07-10 01:16:18 +00001740 struct inode *inode = file->f_path.dentry->d_inode;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001741 int rc = 0;
1742
1743 /* Rather than do the steps manually:
1744 lock the inode for writing
1745 loop through pages looking for write behind data (dirty pages)
1746 coalesce into contiguous 16K (or smaller) chunks to write to server
1747 send to server (prefer in parallel)
1748 deal with writebehind errors
1749 unlock inode for writing
1750 filemapfdatawrite appears easier for the time being */
1751
1752 rc = filemap_fdatawrite(inode->i_mapping);
Jeff Laytoncea21802007-11-20 23:19:03 +00001753 /* reset wb rc if we were able to write out dirty pages */
1754 if (!rc) {
1755 rc = CIFS_I(inode)->write_behind_rc;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001756 CIFS_I(inode)->write_behind_rc = 0;
Jeff Laytoncea21802007-11-20 23:19:03 +00001757 }
Steve French50c2f752007-07-13 00:33:32 +00001758
Steve Frenchfb8c4b12007-07-10 01:16:18 +00001759 cFYI(1, ("Flush inode %p file %p rc %d", inode, file, rc));
Linus Torvalds1da177e2005-04-16 15:20:36 -07001760
1761 return rc;
1762}
1763
1764ssize_t cifs_user_read(struct file *file, char __user *read_data,
1765 size_t read_size, loff_t *poffset)
1766{
1767 int rc = -EACCES;
1768 unsigned int bytes_read = 0;
1769 unsigned int total_read = 0;
1770 unsigned int current_read_size;
1771 struct cifs_sb_info *cifs_sb;
1772 struct cifsTconInfo *pTcon;
1773 int xid;
1774 struct cifsFileInfo *open_file;
1775 char *smb_read_data;
1776 char __user *current_offset;
1777 struct smb_com_read_rsp *pSMBr;
1778
1779 xid = GetXid();
Josef "Jeff" Sipeke6a00292006-12-08 02:36:48 -08001780 cifs_sb = CIFS_SB(file->f_path.dentry->d_sb);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001781 pTcon = cifs_sb->tcon;
1782
1783 if (file->private_data == NULL) {
Suresh Jayaraman0f3bc092009-06-25 18:12:34 +05301784 rc = -EBADF;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001785 FreeXid(xid);
Suresh Jayaraman0f3bc092009-06-25 18:12:34 +05301786 return rc;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001787 }
1788 open_file = (struct cifsFileInfo *)file->private_data;
1789
Steve Frenchad7a2922008-02-07 23:25:02 +00001790 if ((file->f_flags & O_ACCMODE) == O_WRONLY)
Linus Torvalds1da177e2005-04-16 15:20:36 -07001791 cFYI(1, ("attempting read on write only file instance"));
Steve Frenchad7a2922008-02-07 23:25:02 +00001792
Linus Torvalds1da177e2005-04-16 15:20:36 -07001793 for (total_read = 0, current_offset = read_data;
1794 read_size > total_read;
1795 total_read += bytes_read, current_offset += bytes_read) {
Steve Frenchfb8c4b12007-07-10 01:16:18 +00001796 current_read_size = min_t(const int, read_size - total_read,
Linus Torvalds1da177e2005-04-16 15:20:36 -07001797 cifs_sb->rsize);
1798 rc = -EAGAIN;
1799 smb_read_data = NULL;
1800 while (rc == -EAGAIN) {
Steve Frenchec637e32005-12-12 20:53:18 -08001801 int buf_type = CIFS_NO_BUFFER;
Steve Frenchfb8c4b12007-07-10 01:16:18 +00001802 if ((open_file->invalidHandle) &&
Linus Torvalds1da177e2005-04-16 15:20:36 -07001803 (!open_file->closePend)) {
Steve French4b18f2a2008-04-29 00:06:05 +00001804 rc = cifs_reopen_file(file, true);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001805 if (rc != 0)
1806 break;
1807 }
Steve Frenchbfa0d752005-08-31 21:50:37 -07001808 rc = CIFSSMBRead(xid, pTcon,
Steve Frenchec637e32005-12-12 20:53:18 -08001809 open_file->netfid,
1810 current_read_size, *poffset,
1811 &bytes_read, &smb_read_data,
1812 &buf_type);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001813 pSMBr = (struct smb_com_read_rsp *)smb_read_data;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001814 if (smb_read_data) {
Steve French93544cc2006-02-14 22:30:52 -06001815 if (copy_to_user(current_offset,
1816 smb_read_data +
1817 4 /* RFC1001 length field */ +
1818 le16_to_cpu(pSMBr->DataOffset),
Steve Frenchad7a2922008-02-07 23:25:02 +00001819 bytes_read))
Steve French93544cc2006-02-14 22:30:52 -06001820 rc = -EFAULT;
Steve French93544cc2006-02-14 22:30:52 -06001821
Steve Frenchfb8c4b12007-07-10 01:16:18 +00001822 if (buf_type == CIFS_SMALL_BUFFER)
Steve Frenchec637e32005-12-12 20:53:18 -08001823 cifs_small_buf_release(smb_read_data);
Steve Frenchfb8c4b12007-07-10 01:16:18 +00001824 else if (buf_type == CIFS_LARGE_BUFFER)
Steve Frenchec637e32005-12-12 20:53:18 -08001825 cifs_buf_release(smb_read_data);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001826 smb_read_data = NULL;
1827 }
1828 }
1829 if (rc || (bytes_read == 0)) {
1830 if (total_read) {
1831 break;
1832 } else {
1833 FreeXid(xid);
1834 return rc;
1835 }
1836 } else {
Steve Frencha4544342005-08-24 13:59:35 -07001837 cifs_stats_bytes_read(pTcon, bytes_read);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001838 *poffset += bytes_read;
1839 }
1840 }
1841 FreeXid(xid);
1842 return total_read;
1843}
1844
1845
1846static ssize_t cifs_read(struct file *file, char *read_data, size_t read_size,
1847 loff_t *poffset)
1848{
1849 int rc = -EACCES;
1850 unsigned int bytes_read = 0;
1851 unsigned int total_read;
1852 unsigned int current_read_size;
1853 struct cifs_sb_info *cifs_sb;
1854 struct cifsTconInfo *pTcon;
1855 int xid;
1856 char *current_offset;
1857 struct cifsFileInfo *open_file;
Steve Frenchec637e32005-12-12 20:53:18 -08001858 int buf_type = CIFS_NO_BUFFER;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001859
1860 xid = GetXid();
Josef "Jeff" Sipeke6a00292006-12-08 02:36:48 -08001861 cifs_sb = CIFS_SB(file->f_path.dentry->d_sb);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001862 pTcon = cifs_sb->tcon;
1863
1864 if (file->private_data == NULL) {
Suresh Jayaraman0f3bc092009-06-25 18:12:34 +05301865 rc = -EBADF;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001866 FreeXid(xid);
Suresh Jayaraman0f3bc092009-06-25 18:12:34 +05301867 return rc;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001868 }
1869 open_file = (struct cifsFileInfo *)file->private_data;
1870
1871 if ((file->f_flags & O_ACCMODE) == O_WRONLY)
1872 cFYI(1, ("attempting read on write only file instance"));
1873
Steve Frenchfb8c4b12007-07-10 01:16:18 +00001874 for (total_read = 0, current_offset = read_data;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001875 read_size > total_read;
1876 total_read += bytes_read, current_offset += bytes_read) {
1877 current_read_size = min_t(const int, read_size - total_read,
1878 cifs_sb->rsize);
Steve Frenchf9f5c8172005-09-15 23:06:38 -07001879 /* For windows me and 9x we do not want to request more
1880 than it negotiated since it will refuse the read then */
Steve Frenchfb8c4b12007-07-10 01:16:18 +00001881 if ((pTcon->ses) &&
Steve Frenchf9f5c8172005-09-15 23:06:38 -07001882 !(pTcon->ses->capabilities & CAP_LARGE_FILES)) {
1883 current_read_size = min_t(const int, current_read_size,
1884 pTcon->ses->server->maxBuf - 128);
1885 }
Linus Torvalds1da177e2005-04-16 15:20:36 -07001886 rc = -EAGAIN;
1887 while (rc == -EAGAIN) {
Steve Frenchfb8c4b12007-07-10 01:16:18 +00001888 if ((open_file->invalidHandle) &&
Linus Torvalds1da177e2005-04-16 15:20:36 -07001889 (!open_file->closePend)) {
Steve French4b18f2a2008-04-29 00:06:05 +00001890 rc = cifs_reopen_file(file, true);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001891 if (rc != 0)
1892 break;
1893 }
Steve Frenchbfa0d752005-08-31 21:50:37 -07001894 rc = CIFSSMBRead(xid, pTcon,
Steve Frenchec637e32005-12-12 20:53:18 -08001895 open_file->netfid,
1896 current_read_size, *poffset,
1897 &bytes_read, &current_offset,
1898 &buf_type);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001899 }
1900 if (rc || (bytes_read == 0)) {
1901 if (total_read) {
1902 break;
1903 } else {
1904 FreeXid(xid);
1905 return rc;
1906 }
1907 } else {
Steve Frencha4544342005-08-24 13:59:35 -07001908 cifs_stats_bytes_read(pTcon, total_read);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001909 *poffset += bytes_read;
1910 }
1911 }
1912 FreeXid(xid);
1913 return total_read;
1914}
1915
1916int cifs_file_mmap(struct file *file, struct vm_area_struct *vma)
1917{
Linus Torvalds1da177e2005-04-16 15:20:36 -07001918 int rc, xid;
1919
1920 xid = GetXid();
Jeff Laytonabab0952010-02-12 07:44:18 -05001921 rc = cifs_revalidate_file(file);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001922 if (rc) {
1923 cFYI(1, ("Validation prior to mmap failed, error=%d", rc));
1924 FreeXid(xid);
1925 return rc;
1926 }
1927 rc = generic_file_mmap(file, vma);
1928 FreeXid(xid);
1929 return rc;
1930}
1931
1932
Steve Frenchfb8c4b12007-07-10 01:16:18 +00001933static void cifs_copy_cache_pages(struct address_space *mapping,
Nick Piggin315e9952010-04-21 03:18:28 +00001934 struct list_head *pages, int bytes_read, char *data)
Linus Torvalds1da177e2005-04-16 15:20:36 -07001935{
1936 struct page *page;
1937 char *target;
1938
1939 while (bytes_read > 0) {
1940 if (list_empty(pages))
1941 break;
1942
1943 page = list_entry(pages->prev, struct page, lru);
1944 list_del(&page->lru);
1945
Nick Piggin315e9952010-04-21 03:18:28 +00001946 if (add_to_page_cache_lru(page, mapping, page->index,
Linus Torvalds1da177e2005-04-16 15:20:36 -07001947 GFP_KERNEL)) {
1948 page_cache_release(page);
1949 cFYI(1, ("Add page cache failed"));
Steve French3079ca62005-06-09 14:44:07 -07001950 data += PAGE_CACHE_SIZE;
1951 bytes_read -= PAGE_CACHE_SIZE;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001952 continue;
1953 }
1954
Steve Frenchfb8c4b12007-07-10 01:16:18 +00001955 target = kmap_atomic(page, KM_USER0);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001956
1957 if (PAGE_CACHE_SIZE > bytes_read) {
1958 memcpy(target, data, bytes_read);
1959 /* zero the tail end of this partial page */
Steve Frenchfb8c4b12007-07-10 01:16:18 +00001960 memset(target + bytes_read, 0,
Linus Torvalds1da177e2005-04-16 15:20:36 -07001961 PAGE_CACHE_SIZE - bytes_read);
1962 bytes_read = 0;
1963 } else {
1964 memcpy(target, data, PAGE_CACHE_SIZE);
1965 bytes_read -= PAGE_CACHE_SIZE;
1966 }
1967 kunmap_atomic(target, KM_USER0);
1968
1969 flush_dcache_page(page);
1970 SetPageUptodate(page);
1971 unlock_page(page);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001972 data += PAGE_CACHE_SIZE;
1973 }
1974 return;
1975}
1976
1977static int cifs_readpages(struct file *file, struct address_space *mapping,
1978 struct list_head *page_list, unsigned num_pages)
1979{
1980 int rc = -EACCES;
1981 int xid;
1982 loff_t offset;
1983 struct page *page;
1984 struct cifs_sb_info *cifs_sb;
1985 struct cifsTconInfo *pTcon;
Steve French2c2130e2007-10-12 19:10:28 +00001986 unsigned int bytes_read = 0;
Steve Frenchfb8c4b12007-07-10 01:16:18 +00001987 unsigned int read_size, i;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001988 char *smb_read_data = NULL;
1989 struct smb_com_read_rsp *pSMBr;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001990 struct cifsFileInfo *open_file;
Steve Frenchec637e32005-12-12 20:53:18 -08001991 int buf_type = CIFS_NO_BUFFER;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001992
1993 xid = GetXid();
1994 if (file->private_data == NULL) {
Suresh Jayaraman0f3bc092009-06-25 18:12:34 +05301995 rc = -EBADF;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001996 FreeXid(xid);
Suresh Jayaraman0f3bc092009-06-25 18:12:34 +05301997 return rc;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001998 }
1999 open_file = (struct cifsFileInfo *)file->private_data;
Josef "Jeff" Sipeke6a00292006-12-08 02:36:48 -08002000 cifs_sb = CIFS_SB(file->f_path.dentry->d_sb);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002001 pTcon = cifs_sb->tcon;
Steve Frenchbfa0d752005-08-31 21:50:37 -07002002
Steve French61de8002008-10-30 20:15:22 +00002003 cFYI(DBG2, ("rpages: num pages %d", num_pages));
Linus Torvalds1da177e2005-04-16 15:20:36 -07002004 for (i = 0; i < num_pages; ) {
2005 unsigned contig_pages;
2006 struct page *tmp_page;
2007 unsigned long expected_index;
2008
2009 if (list_empty(page_list))
2010 break;
2011
2012 page = list_entry(page_list->prev, struct page, lru);
2013 offset = (loff_t)page->index << PAGE_CACHE_SHIFT;
2014
2015 /* count adjacent pages that we will read into */
2016 contig_pages = 0;
Steve Frenchfb8c4b12007-07-10 01:16:18 +00002017 expected_index =
Linus Torvalds1da177e2005-04-16 15:20:36 -07002018 list_entry(page_list->prev, struct page, lru)->index;
Steve Frenchfb8c4b12007-07-10 01:16:18 +00002019 list_for_each_entry_reverse(tmp_page, page_list, lru) {
Linus Torvalds1da177e2005-04-16 15:20:36 -07002020 if (tmp_page->index == expected_index) {
2021 contig_pages++;
2022 expected_index++;
2023 } else
Steve Frenchfb8c4b12007-07-10 01:16:18 +00002024 break;
Linus Torvalds1da177e2005-04-16 15:20:36 -07002025 }
2026 if (contig_pages + i > num_pages)
2027 contig_pages = num_pages - i;
2028
2029 /* for reads over a certain size could initiate async
2030 read ahead */
2031
2032 read_size = contig_pages * PAGE_CACHE_SIZE;
2033 /* Read size needs to be in multiples of one page */
2034 read_size = min_t(const unsigned int, read_size,
2035 cifs_sb->rsize & PAGE_CACHE_MASK);
Steve French90c81e02008-02-12 20:32:36 +00002036 cFYI(DBG2, ("rpages: read size 0x%x contiguous pages %d",
Steve French75865f8c2007-06-24 18:30:48 +00002037 read_size, contig_pages));
Linus Torvalds1da177e2005-04-16 15:20:36 -07002038 rc = -EAGAIN;
2039 while (rc == -EAGAIN) {
Steve Frenchfb8c4b12007-07-10 01:16:18 +00002040 if ((open_file->invalidHandle) &&
Linus Torvalds1da177e2005-04-16 15:20:36 -07002041 (!open_file->closePend)) {
Steve French4b18f2a2008-04-29 00:06:05 +00002042 rc = cifs_reopen_file(file, true);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002043 if (rc != 0)
2044 break;
2045 }
2046
Steve Frenchbfa0d752005-08-31 21:50:37 -07002047 rc = CIFSSMBRead(xid, pTcon,
Steve Frenchec637e32005-12-12 20:53:18 -08002048 open_file->netfid,
2049 read_size, offset,
2050 &bytes_read, &smb_read_data,
2051 &buf_type);
Steve Frencha9d02ad2005-08-24 23:06:05 -07002052 /* BB more RC checks ? */
Steve Frenchfb8c4b12007-07-10 01:16:18 +00002053 if (rc == -EAGAIN) {
Linus Torvalds1da177e2005-04-16 15:20:36 -07002054 if (smb_read_data) {
Steve Frenchfb8c4b12007-07-10 01:16:18 +00002055 if (buf_type == CIFS_SMALL_BUFFER)
Steve Frenchec637e32005-12-12 20:53:18 -08002056 cifs_small_buf_release(smb_read_data);
Steve Frenchfb8c4b12007-07-10 01:16:18 +00002057 else if (buf_type == CIFS_LARGE_BUFFER)
Steve Frenchec637e32005-12-12 20:53:18 -08002058 cifs_buf_release(smb_read_data);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002059 smb_read_data = NULL;
2060 }
2061 }
2062 }
2063 if ((rc < 0) || (smb_read_data == NULL)) {
2064 cFYI(1, ("Read error in readpages: %d", rc));
Linus Torvalds1da177e2005-04-16 15:20:36 -07002065 break;
2066 } else if (bytes_read > 0) {
Andrew Morton6f88cc22006-12-10 02:19:44 -08002067 task_io_account_read(bytes_read);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002068 pSMBr = (struct smb_com_read_rsp *)smb_read_data;
2069 cifs_copy_cache_pages(mapping, page_list, bytes_read,
2070 smb_read_data + 4 /* RFC1001 hdr */ +
Nick Piggin315e9952010-04-21 03:18:28 +00002071 le16_to_cpu(pSMBr->DataOffset));
Linus Torvalds1da177e2005-04-16 15:20:36 -07002072
2073 i += bytes_read >> PAGE_CACHE_SHIFT;
Steve Frencha4544342005-08-24 13:59:35 -07002074 cifs_stats_bytes_read(pTcon, bytes_read);
Steve French2c2130e2007-10-12 19:10:28 +00002075 if ((bytes_read & PAGE_CACHE_MASK) != bytes_read) {
Linus Torvalds1da177e2005-04-16 15:20:36 -07002076 i++; /* account for partial page */
2077
Steve Frenchfb8c4b12007-07-10 01:16:18 +00002078 /* server copy of file can have smaller size
Linus Torvalds1da177e2005-04-16 15:20:36 -07002079 than client */
Steve Frenchfb8c4b12007-07-10 01:16:18 +00002080 /* BB do we need to verify this common case ?
2081 this case is ok - if we are at server EOF
Linus Torvalds1da177e2005-04-16 15:20:36 -07002082 we will hit it on next read */
2083
OGAWA Hirofumi05ac9d42006-11-02 22:07:08 -08002084 /* break; */
Linus Torvalds1da177e2005-04-16 15:20:36 -07002085 }
2086 } else {
2087 cFYI(1, ("No bytes read (%d) at offset %lld . "
2088 "Cleaning remaining pages from readahead list",
2089 bytes_read, offset));
Steve Frenchfb8c4b12007-07-10 01:16:18 +00002090 /* BB turn off caching and do new lookup on
Linus Torvalds1da177e2005-04-16 15:20:36 -07002091 file size at server? */
Linus Torvalds1da177e2005-04-16 15:20:36 -07002092 break;
2093 }
2094 if (smb_read_data) {
Steve Frenchfb8c4b12007-07-10 01:16:18 +00002095 if (buf_type == CIFS_SMALL_BUFFER)
Steve Frenchec637e32005-12-12 20:53:18 -08002096 cifs_small_buf_release(smb_read_data);
Steve Frenchfb8c4b12007-07-10 01:16:18 +00002097 else if (buf_type == CIFS_LARGE_BUFFER)
Steve Frenchec637e32005-12-12 20:53:18 -08002098 cifs_buf_release(smb_read_data);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002099 smb_read_data = NULL;
2100 }
2101 bytes_read = 0;
2102 }
2103
Linus Torvalds1da177e2005-04-16 15:20:36 -07002104/* need to free smb_read_data buf before exit */
2105 if (smb_read_data) {
Steve Frenchfb8c4b12007-07-10 01:16:18 +00002106 if (buf_type == CIFS_SMALL_BUFFER)
Steve French47c886b2006-01-18 14:20:39 -08002107 cifs_small_buf_release(smb_read_data);
Steve Frenchfb8c4b12007-07-10 01:16:18 +00002108 else if (buf_type == CIFS_LARGE_BUFFER)
Steve French47c886b2006-01-18 14:20:39 -08002109 cifs_buf_release(smb_read_data);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002110 smb_read_data = NULL;
Steve Frenchfb8c4b12007-07-10 01:16:18 +00002111 }
Linus Torvalds1da177e2005-04-16 15:20:36 -07002112
2113 FreeXid(xid);
2114 return rc;
2115}
2116
2117static int cifs_readpage_worker(struct file *file, struct page *page,
2118 loff_t *poffset)
2119{
2120 char *read_data;
2121 int rc;
2122
2123 page_cache_get(page);
2124 read_data = kmap(page);
2125 /* for reads over a certain size could initiate async read ahead */
Steve Frenchfb8c4b12007-07-10 01:16:18 +00002126
Linus Torvalds1da177e2005-04-16 15:20:36 -07002127 rc = cifs_read(file, read_data, PAGE_CACHE_SIZE, poffset);
Steve Frenchfb8c4b12007-07-10 01:16:18 +00002128
Linus Torvalds1da177e2005-04-16 15:20:36 -07002129 if (rc < 0)
2130 goto io_error;
2131 else
Steve Frenchfb8c4b12007-07-10 01:16:18 +00002132 cFYI(1, ("Bytes read %d", rc));
2133
Josef "Jeff" Sipeke6a00292006-12-08 02:36:48 -08002134 file->f_path.dentry->d_inode->i_atime =
2135 current_fs_time(file->f_path.dentry->d_inode->i_sb);
Steve Frenchfb8c4b12007-07-10 01:16:18 +00002136
Linus Torvalds1da177e2005-04-16 15:20:36 -07002137 if (PAGE_CACHE_SIZE > rc)
2138 memset(read_data + rc, 0, PAGE_CACHE_SIZE - rc);
2139
2140 flush_dcache_page(page);
2141 SetPageUptodate(page);
2142 rc = 0;
Steve Frenchfb8c4b12007-07-10 01:16:18 +00002143
Linus Torvalds1da177e2005-04-16 15:20:36 -07002144io_error:
Steve Frenchfb8c4b12007-07-10 01:16:18 +00002145 kunmap(page);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002146 page_cache_release(page);
2147 return rc;
2148}
2149
2150static int cifs_readpage(struct file *file, struct page *page)
2151{
2152 loff_t offset = (loff_t)page->index << PAGE_CACHE_SHIFT;
2153 int rc = -EACCES;
2154 int xid;
2155
2156 xid = GetXid();
2157
2158 if (file->private_data == NULL) {
Suresh Jayaraman0f3bc092009-06-25 18:12:34 +05302159 rc = -EBADF;
Linus Torvalds1da177e2005-04-16 15:20:36 -07002160 FreeXid(xid);
Suresh Jayaraman0f3bc092009-06-25 18:12:34 +05302161 return rc;
Linus Torvalds1da177e2005-04-16 15:20:36 -07002162 }
2163
Steve Frenchfb8c4b12007-07-10 01:16:18 +00002164 cFYI(1, ("readpage %p at offset %d 0x%x\n",
Linus Torvalds1da177e2005-04-16 15:20:36 -07002165 page, (int)offset, (int)offset));
2166
2167 rc = cifs_readpage_worker(file, page, &offset);
2168
2169 unlock_page(page);
2170
2171 FreeXid(xid);
2172 return rc;
2173}
2174
Steve Frencha403a0a2007-07-26 15:54:16 +00002175static int is_inode_writable(struct cifsInodeInfo *cifs_inode)
2176{
2177 struct cifsFileInfo *open_file;
2178
2179 read_lock(&GlobalSMBSeslock);
2180 list_for_each_entry(open_file, &cifs_inode->openFileList, flist) {
2181 if (open_file->closePend)
2182 continue;
2183 if (open_file->pfile &&
2184 ((open_file->pfile->f_flags & O_RDWR) ||
2185 (open_file->pfile->f_flags & O_WRONLY))) {
2186 read_unlock(&GlobalSMBSeslock);
2187 return 1;
2188 }
2189 }
2190 read_unlock(&GlobalSMBSeslock);
2191 return 0;
2192}
2193
Linus Torvalds1da177e2005-04-16 15:20:36 -07002194/* We do not want to update the file size from server for inodes
2195 open for write - to avoid races with writepage extending
2196 the file - in the future we could consider allowing
Steve Frenchfb8c4b12007-07-10 01:16:18 +00002197 refreshing the inode only on increases in the file size
Linus Torvalds1da177e2005-04-16 15:20:36 -07002198 but this is tricky to do without racing with writebehind
2199 page caching in the current Linux kernel design */
Steve French4b18f2a2008-04-29 00:06:05 +00002200bool is_size_safe_to_change(struct cifsInodeInfo *cifsInode, __u64 end_of_file)
Linus Torvalds1da177e2005-04-16 15:20:36 -07002201{
Steve Frencha403a0a2007-07-26 15:54:16 +00002202 if (!cifsInode)
Steve French4b18f2a2008-04-29 00:06:05 +00002203 return true;
Steve French23e7dd72005-10-20 13:44:56 -07002204
Steve Frencha403a0a2007-07-26 15:54:16 +00002205 if (is_inode_writable(cifsInode)) {
2206 /* This inode is open for write at least once */
Steve Frenchc32a0b62006-01-12 14:41:28 -08002207 struct cifs_sb_info *cifs_sb;
2208
Steve Frenchc32a0b62006-01-12 14:41:28 -08002209 cifs_sb = CIFS_SB(cifsInode->vfs_inode.i_sb);
Steve Frenchad7a2922008-02-07 23:25:02 +00002210 if (cifs_sb->mnt_cifs_flags & CIFS_MOUNT_DIRECT_IO) {
Steve Frenchfb8c4b12007-07-10 01:16:18 +00002211 /* since no page cache to corrupt on directio
Steve Frenchc32a0b62006-01-12 14:41:28 -08002212 we can change size safely */
Steve French4b18f2a2008-04-29 00:06:05 +00002213 return true;
Steve Frenchc32a0b62006-01-12 14:41:28 -08002214 }
2215
Steve Frenchfb8c4b12007-07-10 01:16:18 +00002216 if (i_size_read(&cifsInode->vfs_inode) < end_of_file)
Steve French4b18f2a2008-04-29 00:06:05 +00002217 return true;
Steve French7ba52632007-02-08 18:14:13 +00002218
Steve French4b18f2a2008-04-29 00:06:05 +00002219 return false;
Steve French23e7dd72005-10-20 13:44:56 -07002220 } else
Steve French4b18f2a2008-04-29 00:06:05 +00002221 return true;
Linus Torvalds1da177e2005-04-16 15:20:36 -07002222}
2223
Nick Piggind9414772008-09-24 11:32:59 -04002224static int cifs_write_begin(struct file *file, struct address_space *mapping,
2225 loff_t pos, unsigned len, unsigned flags,
2226 struct page **pagep, void **fsdata)
Linus Torvalds1da177e2005-04-16 15:20:36 -07002227{
Nick Piggind9414772008-09-24 11:32:59 -04002228 pgoff_t index = pos >> PAGE_CACHE_SHIFT;
2229 loff_t offset = pos & (PAGE_CACHE_SIZE - 1);
Jeff Laytona98ee8c2008-11-26 19:32:33 +00002230 loff_t page_start = pos & PAGE_MASK;
2231 loff_t i_size;
2232 struct page *page;
2233 int rc = 0;
Linus Torvalds1da177e2005-04-16 15:20:36 -07002234
Nick Piggind9414772008-09-24 11:32:59 -04002235 cFYI(1, ("write_begin from %lld len %d", (long long)pos, len));
2236
Nick Piggin54566b22009-01-04 12:00:53 -08002237 page = grab_cache_page_write_begin(mapping, index, flags);
Jeff Laytona98ee8c2008-11-26 19:32:33 +00002238 if (!page) {
2239 rc = -ENOMEM;
2240 goto out;
2241 }
Nick Piggind9414772008-09-24 11:32:59 -04002242
Jeff Laytona98ee8c2008-11-26 19:32:33 +00002243 if (PageUptodate(page))
2244 goto out;
Steve French8a236262007-03-06 00:31:00 +00002245
Jeff Laytona98ee8c2008-11-26 19:32:33 +00002246 /*
2247 * If we write a full page it will be up to date, no need to read from
2248 * the server. If the write is short, we'll end up doing a sync write
2249 * instead.
2250 */
2251 if (len == PAGE_CACHE_SIZE)
2252 goto out;
2253
2254 /*
2255 * optimize away the read when we have an oplock, and we're not
2256 * expecting to use any of the data we'd be reading in. That
2257 * is, when the page lies beyond the EOF, or straddles the EOF
2258 * and the write will cover all of the existing data.
2259 */
2260 if (CIFS_I(mapping->host)->clientCanCacheRead) {
2261 i_size = i_size_read(mapping->host);
2262 if (page_start >= i_size ||
2263 (offset == 0 && (pos + len) >= i_size)) {
2264 zero_user_segments(page, 0, offset,
2265 offset + len,
2266 PAGE_CACHE_SIZE);
2267 /*
2268 * PageChecked means that the parts of the page
2269 * to which we're not writing are considered up
2270 * to date. Once the data is copied to the
2271 * page, it can be set uptodate.
2272 */
2273 SetPageChecked(page);
2274 goto out;
2275 }
2276 }
Linus Torvalds1da177e2005-04-16 15:20:36 -07002277
Nick Piggind9414772008-09-24 11:32:59 -04002278 if ((file->f_flags & O_ACCMODE) != O_WRONLY) {
Jeff Laytona98ee8c2008-11-26 19:32:33 +00002279 /*
2280 * might as well read a page, it is fast enough. If we get
2281 * an error, we don't need to return it. cifs_write_end will
2282 * do a sync write instead since PG_uptodate isn't set.
2283 */
2284 cifs_readpage_worker(file, page, &page_start);
Steve French8a236262007-03-06 00:31:00 +00002285 } else {
2286 /* we could try using another file handle if there is one -
2287 but how would we lock it to prevent close of that handle
2288 racing with this read? In any case
Nick Piggind9414772008-09-24 11:32:59 -04002289 this will be written out by write_end so is fine */
Steve French8a236262007-03-06 00:31:00 +00002290 }
Jeff Laytona98ee8c2008-11-26 19:32:33 +00002291out:
2292 *pagep = page;
2293 return rc;
Linus Torvalds1da177e2005-04-16 15:20:36 -07002294}
2295
Jeff Layton3bc303c2009-09-21 06:47:50 -04002296static void
2297cifs_oplock_break(struct slow_work *work)
2298{
2299 struct cifsFileInfo *cfile = container_of(work, struct cifsFileInfo,
2300 oplock_break);
2301 struct inode *inode = cfile->pInode;
2302 struct cifsInodeInfo *cinode = CIFS_I(inode);
2303 struct cifs_sb_info *cifs_sb = CIFS_SB(cfile->mnt->mnt_sb);
2304 int rc, waitrc = 0;
2305
2306 if (inode && S_ISREG(inode->i_mode)) {
2307#ifdef CONFIG_CIFS_EXPERIMENTAL
2308 if (cinode->clientCanCacheAll == 0)
Al Viro8737c932009-12-24 06:47:55 -05002309 break_lease(inode, O_RDONLY);
Jeff Layton3bc303c2009-09-21 06:47:50 -04002310 else if (cinode->clientCanCacheRead == 0)
Al Viro8737c932009-12-24 06:47:55 -05002311 break_lease(inode, O_WRONLY);
Jeff Layton3bc303c2009-09-21 06:47:50 -04002312#endif
2313 rc = filemap_fdatawrite(inode->i_mapping);
2314 if (cinode->clientCanCacheRead == 0) {
2315 waitrc = filemap_fdatawait(inode->i_mapping);
2316 invalidate_remote_inode(inode);
2317 }
2318 if (!rc)
2319 rc = waitrc;
2320 if (rc)
2321 cinode->write_behind_rc = rc;
2322 cFYI(1, ("Oplock flush inode %p rc %d", inode, rc));
2323 }
2324
2325 /*
2326 * releasing stale oplock after recent reconnect of smb session using
2327 * a now incorrect file handle is not a data integrity issue but do
2328 * not bother sending an oplock release if session to server still is
2329 * disconnected since oplock already released by the server
2330 */
2331 if (!cfile->closePend && !cfile->oplock_break_cancelled) {
2332 rc = CIFSSMBLock(0, cifs_sb->tcon, cfile->netfid, 0, 0, 0, 0,
2333 LOCKING_ANDX_OPLOCK_RELEASE, false);
2334 cFYI(1, ("Oplock release rc = %d", rc));
2335 }
2336}
2337
2338static int
2339cifs_oplock_break_get(struct slow_work *work)
2340{
2341 struct cifsFileInfo *cfile = container_of(work, struct cifsFileInfo,
2342 oplock_break);
2343 mntget(cfile->mnt);
2344 cifsFileInfo_get(cfile);
2345 return 0;
2346}
2347
2348static void
2349cifs_oplock_break_put(struct slow_work *work)
2350{
2351 struct cifsFileInfo *cfile = container_of(work, struct cifsFileInfo,
2352 oplock_break);
2353 mntput(cfile->mnt);
2354 cifsFileInfo_put(cfile);
2355}
2356
2357const struct slow_work_ops cifs_oplock_break_ops = {
2358 .get_ref = cifs_oplock_break_get,
2359 .put_ref = cifs_oplock_break_put,
2360 .execute = cifs_oplock_break,
2361};
2362
Christoph Hellwigf5e54d62006-06-28 04:26:44 -07002363const struct address_space_operations cifs_addr_ops = {
Linus Torvalds1da177e2005-04-16 15:20:36 -07002364 .readpage = cifs_readpage,
2365 .readpages = cifs_readpages,
2366 .writepage = cifs_writepage,
Steve French37c0eb42005-10-05 14:50:29 -07002367 .writepages = cifs_writepages,
Nick Piggind9414772008-09-24 11:32:59 -04002368 .write_begin = cifs_write_begin,
2369 .write_end = cifs_write_end,
Linus Torvalds1da177e2005-04-16 15:20:36 -07002370 .set_page_dirty = __set_page_dirty_nobuffers,
2371 /* .sync_page = cifs_sync_page, */
2372 /* .direct_IO = */
2373};
Dave Kleikamp273d81d2006-06-01 19:41:23 +00002374
2375/*
2376 * cifs_readpages requires the server to support a buffer large enough to
2377 * contain the header plus one complete page of data. Otherwise, we need
2378 * to leave cifs_readpages out of the address space operations.
2379 */
Christoph Hellwigf5e54d62006-06-28 04:26:44 -07002380const struct address_space_operations cifs_addr_ops_smallbuf = {
Dave Kleikamp273d81d2006-06-01 19:41:23 +00002381 .readpage = cifs_readpage,
2382 .writepage = cifs_writepage,
2383 .writepages = cifs_writepages,
Nick Piggind9414772008-09-24 11:32:59 -04002384 .write_begin = cifs_write_begin,
2385 .write_end = cifs_write_end,
Dave Kleikamp273d81d2006-06-01 19:41:23 +00002386 .set_page_dirty = __set_page_dirty_nobuffers,
2387 /* .sync_page = cifs_sync_page, */
2388 /* .direct_IO = */
2389};