blob: 5b9d1f25aaec3f396bbf7ab7d12fff9436ac6f38 [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 *
Steve Frenchf19159d2010-04-21 04:12:10 +00006 * Copyright (C) International Business Machines Corp., 2002,2010
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,
Suresh Jayaraman51c81762010-05-10 15:15:24 +0530111 struct cifsInodeInfo *pCifsInode, __u32 oplock,
Jeff Layton590a3fe2009-09-12 11:54:28 -0400112 u16 netfid)
Steve French276a74a2009-03-03 18:00:34 +0000113{
Steve French276a74a2009-03-03 18:00:34 +0000114
Steve French276a74a2009-03-03 18:00:34 +0000115 write_lock(&GlobalSMBSeslock);
Steve French276a74a2009-03-03 18:00:34 +0000116
117 pCifsInode = CIFS_I(file->f_path.dentry->d_inode);
118 if (pCifsInode == NULL) {
119 write_unlock(&GlobalSMBSeslock);
120 return -EINVAL;
121 }
122
Steve French276a74a2009-03-03 18:00:34 +0000123 if (pCifsInode->clientCanCacheRead) {
124 /* we have the inode open somewhere else
125 no need to discard cache data */
126 goto psx_client_can_cache;
127 }
128
129 /* BB FIXME need to fix this check to move it earlier into posix_open
130 BB fIX following section BB FIXME */
131
132 /* if not oplocked, invalidate inode pages if mtime or file
133 size changed */
134/* temp = cifs_NTtimeToUnix(le64_to_cpu(buf->LastWriteTime));
135 if (timespec_equal(&file->f_path.dentry->d_inode->i_mtime, &temp) &&
136 (file->f_path.dentry->d_inode->i_size ==
137 (loff_t)le64_to_cpu(buf->EndOfFile))) {
Joe Perchesb6b38f72010-04-21 03:50:45 +0000138 cFYI(1, "inode unchanged on server");
Steve French276a74a2009-03-03 18:00:34 +0000139 } else {
140 if (file->f_path.dentry->d_inode->i_mapping) {
141 rc = filemap_write_and_wait(file->f_path.dentry->d_inode->i_mapping);
142 if (rc != 0)
143 CIFS_I(file->f_path.dentry->d_inode)->write_behind_rc = rc;
144 }
Joe Perchesb6b38f72010-04-21 03:50:45 +0000145 cFYI(1, "invalidating remote inode since open detected it "
146 "changed");
Steve French276a74a2009-03-03 18:00:34 +0000147 invalidate_remote_inode(file->f_path.dentry->d_inode);
148 } */
149
150psx_client_can_cache:
151 if ((oplock & 0xF) == OPLOCK_EXCLUSIVE) {
152 pCifsInode->clientCanCacheAll = true;
153 pCifsInode->clientCanCacheRead = true;
Joe Perchesb6b38f72010-04-21 03:50:45 +0000154 cFYI(1, "Exclusive Oplock granted on inode %p",
155 file->f_path.dentry->d_inode);
Steve French276a74a2009-03-03 18:00:34 +0000156 } else if ((oplock & 0xF) == OPLOCK_READ)
157 pCifsInode->clientCanCacheRead = true;
158
159 /* will have to change the unlock if we reenable the
160 filemap_fdatawrite (which does not seem necessary */
161 write_unlock(&GlobalSMBSeslock);
162 return 0;
163}
164
165/* all arguments to this function must be checked for validity in caller */
Jeff Laytondb460242010-06-16 13:40:17 -0400166static inline int cifs_open_inode_helper(struct inode *inode,
Linus Torvalds1da177e2005-04-16 15:20:36 -0700167 struct cifsTconInfo *pTcon, int *oplock, FILE_ALL_INFO *buf,
168 char *full_path, int xid)
169{
Jeff Laytondb460242010-06-16 13:40:17 -0400170 struct cifsInodeInfo *pCifsInode = CIFS_I(inode);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700171 struct timespec temp;
172 int rc;
173
Linus Torvalds1da177e2005-04-16 15:20:36 -0700174 if (pCifsInode->clientCanCacheRead) {
175 /* we have the inode open somewhere else
176 no need to discard cache data */
177 goto client_can_cache;
178 }
179
180 /* BB need same check in cifs_create too? */
181 /* if not oplocked, invalidate inode pages if mtime or file
182 size changed */
Jeff Layton07119a42009-05-27 09:37:33 -0400183 temp = cifs_NTtimeToUnix(buf->LastWriteTime);
Jeff Laytondb460242010-06-16 13:40:17 -0400184 if (timespec_equal(&inode->i_mtime, &temp) &&
185 (inode->i_size ==
Linus Torvalds1da177e2005-04-16 15:20:36 -0700186 (loff_t)le64_to_cpu(buf->EndOfFile))) {
Joe Perchesb6b38f72010-04-21 03:50:45 +0000187 cFYI(1, "inode unchanged on server");
Linus Torvalds1da177e2005-04-16 15:20:36 -0700188 } else {
Jeff Laytondb460242010-06-16 13:40:17 -0400189 if (inode->i_mapping) {
Steve Frenchff2157132010-03-09 20:30:42 +0000190 /* BB no need to lock inode until after invalidate
191 since namei code should already have it locked? */
Jeff Laytondb460242010-06-16 13:40:17 -0400192 rc = filemap_write_and_wait(inode->i_mapping);
Jeff Laytoncea21802007-11-20 23:19:03 +0000193 if (rc != 0)
Jeff Laytondb460242010-06-16 13:40:17 -0400194 pCifsInode->write_behind_rc = rc;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700195 }
Joe Perchesb6b38f72010-04-21 03:50:45 +0000196 cFYI(1, "invalidating remote inode since open detected it "
197 "changed");
Jeff Laytondb460242010-06-16 13:40:17 -0400198 invalidate_remote_inode(inode);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700199 }
200
201client_can_cache:
Steve Frenchc18c8422007-07-18 23:21:09 +0000202 if (pTcon->unix_ext)
Jeff Laytondb460242010-06-16 13:40:17 -0400203 rc = cifs_get_inode_info_unix(&inode, full_path, inode->i_sb,
204 xid);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700205 else
Jeff Laytondb460242010-06-16 13:40:17 -0400206 rc = cifs_get_inode_info(&inode, full_path, buf, inode->i_sb,
207 xid, NULL);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700208
209 if ((*oplock & 0xF) == OPLOCK_EXCLUSIVE) {
Steve French4b18f2a2008-04-29 00:06:05 +0000210 pCifsInode->clientCanCacheAll = true;
211 pCifsInode->clientCanCacheRead = true;
Jeff Laytondb460242010-06-16 13:40:17 -0400212 cFYI(1, "Exclusive Oplock granted on inode %p", inode);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700213 } else if ((*oplock & 0xF) == OPLOCK_READ)
Steve French4b18f2a2008-04-29 00:06:05 +0000214 pCifsInode->clientCanCacheRead = true;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700215
216 return rc;
217}
218
219int cifs_open(struct inode *inode, struct file *file)
220{
221 int rc = -EACCES;
Jeff Layton590a3fe2009-09-12 11:54:28 -0400222 int xid;
223 __u32 oplock;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700224 struct cifs_sb_info *cifs_sb;
Steve French276a74a2009-03-03 18:00:34 +0000225 struct cifsTconInfo *tcon;
Jeff Layton6ca9f3b2010-06-16 13:40:16 -0400226 struct cifsFileInfo *pCifsFile = NULL;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700227 struct cifsInodeInfo *pCifsInode;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700228 char *full_path = NULL;
229 int desiredAccess;
230 int disposition;
231 __u16 netfid;
232 FILE_ALL_INFO *buf = NULL;
233
234 xid = GetXid();
235
236 cifs_sb = CIFS_SB(inode->i_sb);
Steve French276a74a2009-03-03 18:00:34 +0000237 tcon = cifs_sb->tcon;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700238
Steve Frencha6ce4932009-04-09 01:14:32 +0000239 pCifsInode = CIFS_I(file->f_path.dentry->d_inode);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700240
Josef "Jeff" Sipeke6a00292006-12-08 02:36:48 -0800241 full_path = build_path_from_dentry(file->f_path.dentry);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700242 if (full_path == NULL) {
Suresh Jayaraman0f3bc092009-06-25 18:12:34 +0530243 rc = -ENOMEM;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700244 FreeXid(xid);
Suresh Jayaraman0f3bc092009-06-25 18:12:34 +0530245 return rc;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700246 }
247
Joe Perchesb6b38f72010-04-21 03:50:45 +0000248 cFYI(1, "inode = 0x%p file flags are 0x%x for %s",
249 inode, file->f_flags, full_path);
Steve French276a74a2009-03-03 18:00:34 +0000250
251 if (oplockEnabled)
252 oplock = REQ_OPLOCK;
253 else
254 oplock = 0;
255
Steve French64cc2c62009-03-04 19:54:08 +0000256 if (!tcon->broken_posix_open && tcon->unix_ext &&
257 (tcon->ses->capabilities & CAP_UNIX) &&
Steve French276a74a2009-03-03 18:00:34 +0000258 (CIFS_UNIX_POSIX_PATH_OPS_CAP &
259 le64_to_cpu(tcon->fsUnixInfo.Capability))) {
260 int oflags = (int) cifs_posix_convert_flags(file->f_flags);
Steve Frenchfa588e02010-04-22 19:21:55 +0000261 oflags |= SMB_O_CREAT;
Steve French276a74a2009-03-03 18:00:34 +0000262 /* can not refresh inode info since size could be stale */
Jeff Layton2422f672010-06-16 13:40:16 -0400263 rc = cifs_posix_open(full_path, &inode, inode->i_sb,
Steve Frenchfa588e02010-04-22 19:21:55 +0000264 cifs_sb->mnt_file_mode /* ignored */,
265 oflags, &oplock, &netfid, xid);
Steve French276a74a2009-03-03 18:00:34 +0000266 if (rc == 0) {
Joe Perchesb6b38f72010-04-21 03:50:45 +0000267 cFYI(1, "posix open succeeded");
Steve French276a74a2009-03-03 18:00:34 +0000268 /* no need for special case handling of setting mode
269 on read only files needed here */
270
Jeff Layton2422f672010-06-16 13:40:16 -0400271 pCifsFile = cifs_new_fileinfo(inode, netfid, file,
272 file->f_path.mnt,
273 oflags);
274 if (pCifsFile == NULL) {
275 CIFSSMBClose(xid, tcon, netfid);
276 rc = -ENOMEM;
277 goto out;
278 }
Jeff Layton2422f672010-06-16 13:40:16 -0400279
Steve French276a74a2009-03-03 18:00:34 +0000280 cifs_posix_open_inode_helper(inode, file, pCifsInode,
Suresh Jayaraman51c81762010-05-10 15:15:24 +0530281 oplock, netfid);
Steve French276a74a2009-03-03 18:00:34 +0000282 goto out;
Steve French64cc2c62009-03-04 19:54:08 +0000283 } else if ((rc == -EINVAL) || (rc == -EOPNOTSUPP)) {
284 if (tcon->ses->serverNOS)
Joe Perchesb6b38f72010-04-21 03:50:45 +0000285 cERROR(1, "server %s of type %s returned"
Steve French64cc2c62009-03-04 19:54:08 +0000286 " unexpected error on SMB posix open"
287 ", disabling posix open support."
288 " Check if server update available.",
289 tcon->ses->serverName,
Joe Perchesb6b38f72010-04-21 03:50:45 +0000290 tcon->ses->serverNOS);
Steve French64cc2c62009-03-04 19:54:08 +0000291 tcon->broken_posix_open = true;
Steve French276a74a2009-03-03 18:00:34 +0000292 } else if ((rc != -EIO) && (rc != -EREMOTE) &&
293 (rc != -EOPNOTSUPP)) /* path not found or net err */
294 goto out;
Steve French64cc2c62009-03-04 19:54:08 +0000295 /* else fallthrough to retry open the old way on network i/o
296 or DFS errors */
Steve French276a74a2009-03-03 18:00:34 +0000297 }
298
Linus Torvalds1da177e2005-04-16 15:20:36 -0700299 desiredAccess = cifs_convert_flags(file->f_flags);
300
301/*********************************************************************
302 * open flag mapping table:
Steve Frenchfb8c4b12007-07-10 01:16:18 +0000303 *
Linus Torvalds1da177e2005-04-16 15:20:36 -0700304 * POSIX Flag CIFS Disposition
Steve Frenchfb8c4b12007-07-10 01:16:18 +0000305 * ---------- ----------------
Linus Torvalds1da177e2005-04-16 15:20:36 -0700306 * O_CREAT FILE_OPEN_IF
307 * O_CREAT | O_EXCL FILE_CREATE
308 * O_CREAT | O_TRUNC FILE_OVERWRITE_IF
309 * O_TRUNC FILE_OVERWRITE
310 * none of the above FILE_OPEN
311 *
312 * Note that there is not a direct match between disposition
Steve Frenchfb8c4b12007-07-10 01:16:18 +0000313 * FILE_SUPERSEDE (ie create whether or not file exists although
Linus Torvalds1da177e2005-04-16 15:20:36 -0700314 * O_CREAT | O_TRUNC is similar but truncates the existing
315 * file rather than creating a new file as FILE_SUPERSEDE does
316 * (which uses the attributes / metadata passed in on open call)
317 *?
Steve Frenchfb8c4b12007-07-10 01:16:18 +0000318 *? O_SYNC is a reasonable match to CIFS writethrough flag
Linus Torvalds1da177e2005-04-16 15:20:36 -0700319 *? and the read write flags match reasonably. O_LARGEFILE
320 *? is irrelevant because largefile support is always used
321 *? by this client. Flags O_APPEND, O_DIRECT, O_DIRECTORY,
322 * O_FASYNC, O_NOFOLLOW, O_NONBLOCK need further investigation
323 *********************************************************************/
324
325 disposition = cifs_get_disposition(file->f_flags);
326
Linus Torvalds1da177e2005-04-16 15:20:36 -0700327 /* BB pass O_SYNC flag through on file attributes .. BB */
328
329 /* Also refresh inode by passing in file_info buf returned by SMBOpen
330 and calling get_inode_info with returned buf (at least helps
331 non-Unix server case) */
332
Steve Frenchfb8c4b12007-07-10 01:16:18 +0000333 /* BB we can not do this if this is the second open of a file
334 and the first handle has writebehind data, we might be
Linus Torvalds1da177e2005-04-16 15:20:36 -0700335 able to simply do a filemap_fdatawrite/filemap_fdatawait first */
336 buf = kmalloc(sizeof(FILE_ALL_INFO), GFP_KERNEL);
337 if (!buf) {
338 rc = -ENOMEM;
339 goto out;
340 }
Steve French5bafd762006-06-07 00:18:43 +0000341
342 if (cifs_sb->tcon->ses->capabilities & CAP_NT_SMBS)
Steve French276a74a2009-03-03 18:00:34 +0000343 rc = CIFSSMBOpen(xid, tcon, full_path, disposition,
Steve French5bafd762006-06-07 00:18:43 +0000344 desiredAccess, CREATE_NOT_DIR, &netfid, &oplock, buf,
Steve French737b7582005-04-28 22:41:06 -0700345 cifs_sb->local_nls, cifs_sb->mnt_cifs_flags
346 & CIFS_MOUNT_MAP_SPECIAL_CHR);
Steve French5bafd762006-06-07 00:18:43 +0000347 else
348 rc = -EIO; /* no NT SMB support fall into legacy open below */
349
Steve Frencha9d02ad2005-08-24 23:06:05 -0700350 if (rc == -EIO) {
351 /* Old server, try legacy style OpenX */
Steve French276a74a2009-03-03 18:00:34 +0000352 rc = SMBLegacyOpen(xid, tcon, full_path, disposition,
Steve Frencha9d02ad2005-08-24 23:06:05 -0700353 desiredAccess, CREATE_NOT_DIR, &netfid, &oplock, buf,
354 cifs_sb->local_nls, cifs_sb->mnt_cifs_flags
355 & CIFS_MOUNT_MAP_SPECIAL_CHR);
356 }
Linus Torvalds1da177e2005-04-16 15:20:36 -0700357 if (rc) {
Joe Perchesb6b38f72010-04-21 03:50:45 +0000358 cFYI(1, "cifs_open returned 0x%x", rc);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700359 goto out;
360 }
Jeff Layton3321b792009-09-25 09:53:37 -0400361
Jeff Layton086f68b2009-09-21 14:08:18 -0400362 pCifsFile = cifs_new_fileinfo(inode, netfid, file, file->f_path.mnt,
363 file->f_flags);
Jeff Layton6ca9f3b2010-06-16 13:40:16 -0400364 if (pCifsFile == NULL) {
Linus Torvalds1da177e2005-04-16 15:20:36 -0700365 rc = -ENOMEM;
366 goto out;
367 }
Linus Torvalds1da177e2005-04-16 15:20:36 -0700368
Jeff Laytondb460242010-06-16 13:40:17 -0400369 rc = cifs_open_inode_helper(inode, tcon, &oplock, buf, full_path, xid);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700370
Steve Frenchfb8c4b12007-07-10 01:16:18 +0000371 if (oplock & CIFS_CREATE_ACTION) {
Linus Torvalds1da177e2005-04-16 15:20:36 -0700372 /* time to set mode which we can not set earlier due to
373 problems creating new read-only files */
Steve French276a74a2009-03-03 18:00:34 +0000374 if (tcon->unix_ext) {
Jeff Layton4e1e7fb2008-08-02 07:26:12 -0400375 struct cifs_unix_set_info_args args = {
376 .mode = inode->i_mode,
377 .uid = NO_CHANGE_64,
378 .gid = NO_CHANGE_64,
379 .ctime = NO_CHANGE_64,
380 .atime = NO_CHANGE_64,
381 .mtime = NO_CHANGE_64,
382 .device = 0,
383 };
Jeff Layton01ea95e2009-07-09 20:02:49 -0400384 CIFSSMBUnixSetPathInfo(xid, tcon, full_path, &args,
385 cifs_sb->local_nls,
386 cifs_sb->mnt_cifs_flags &
Steve French737b7582005-04-28 22:41:06 -0700387 CIFS_MOUNT_MAP_SPECIAL_CHR);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700388 }
389 }
390
391out:
392 kfree(buf);
393 kfree(full_path);
394 FreeXid(xid);
395 return rc;
396}
397
Adrian Bunk04187262006-06-30 18:23:04 +0200398/* Try to reacquire byte range locks that were released when session */
Linus Torvalds1da177e2005-04-16 15:20:36 -0700399/* to server was lost */
400static int cifs_relock_file(struct cifsFileInfo *cifsFile)
401{
402 int rc = 0;
403
404/* BB list all locks open on this file and relock */
405
406 return rc;
407}
408
Steve French4b18f2a2008-04-29 00:06:05 +0000409static int cifs_reopen_file(struct file *file, bool can_flush)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700410{
411 int rc = -EACCES;
Jeff Layton590a3fe2009-09-12 11:54:28 -0400412 int xid;
413 __u32 oplock;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700414 struct cifs_sb_info *cifs_sb;
Steve French7fc8f4e2009-02-23 20:43:11 +0000415 struct cifsTconInfo *tcon;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700416 struct cifsFileInfo *pCifsFile;
417 struct cifsInodeInfo *pCifsInode;
Steve Frenchfb8c4b12007-07-10 01:16:18 +0000418 struct inode *inode;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700419 char *full_path = NULL;
420 int desiredAccess;
421 int disposition = FILE_OPEN;
422 __u16 netfid;
423
Steve Frenchad7a2922008-02-07 23:25:02 +0000424 if (file->private_data)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700425 pCifsFile = (struct cifsFileInfo *)file->private_data;
Steve Frenchad7a2922008-02-07 23:25:02 +0000426 else
Linus Torvalds1da177e2005-04-16 15:20:36 -0700427 return -EBADF;
428
429 xid = GetXid();
Jeff Laytonf0a71eb2009-06-27 07:04:55 -0400430 mutex_lock(&pCifsFile->fh_mutex);
Steve French4b18f2a2008-04-29 00:06:05 +0000431 if (!pCifsFile->invalidHandle) {
Jeff Laytonf0a71eb2009-06-27 07:04:55 -0400432 mutex_unlock(&pCifsFile->fh_mutex);
Suresh Jayaraman0f3bc092009-06-25 18:12:34 +0530433 rc = 0;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700434 FreeXid(xid);
Suresh Jayaraman0f3bc092009-06-25 18:12:34 +0530435 return rc;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700436 }
437
Josef "Jeff" Sipeke6a00292006-12-08 02:36:48 -0800438 if (file->f_path.dentry == NULL) {
Joe Perchesb6b38f72010-04-21 03:50:45 +0000439 cERROR(1, "no valid name if dentry freed");
Steve French3a9f4622007-04-04 17:10:24 +0000440 dump_stack();
441 rc = -EBADF;
442 goto reopen_error_exit;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700443 }
Steve French3a9f4622007-04-04 17:10:24 +0000444
445 inode = file->f_path.dentry->d_inode;
Steve Frenchfb8c4b12007-07-10 01:16:18 +0000446 if (inode == NULL) {
Joe Perchesb6b38f72010-04-21 03:50:45 +0000447 cERROR(1, "inode not valid");
Steve French3a9f4622007-04-04 17:10:24 +0000448 dump_stack();
449 rc = -EBADF;
450 goto reopen_error_exit;
451 }
Steve French50c2f752007-07-13 00:33:32 +0000452
Linus Torvalds1da177e2005-04-16 15:20:36 -0700453 cifs_sb = CIFS_SB(inode->i_sb);
Steve French7fc8f4e2009-02-23 20:43:11 +0000454 tcon = cifs_sb->tcon;
Steve French3a9f4622007-04-04 17:10:24 +0000455
Linus Torvalds1da177e2005-04-16 15:20:36 -0700456/* can not grab rename sem here because various ops, including
457 those that already have the rename sem can end up causing writepage
458 to get called and if the server was down that means we end up here,
459 and we can never tell if the caller already has the rename_sem */
Josef "Jeff" Sipeke6a00292006-12-08 02:36:48 -0800460 full_path = build_path_from_dentry(file->f_path.dentry);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700461 if (full_path == NULL) {
Steve French3a9f4622007-04-04 17:10:24 +0000462 rc = -ENOMEM;
463reopen_error_exit:
Jeff Laytonf0a71eb2009-06-27 07:04:55 -0400464 mutex_unlock(&pCifsFile->fh_mutex);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700465 FreeXid(xid);
Steve French3a9f4622007-04-04 17:10:24 +0000466 return rc;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700467 }
468
Joe Perchesb6b38f72010-04-21 03:50:45 +0000469 cFYI(1, "inode = 0x%p file flags 0x%x for %s",
470 inode, file->f_flags, full_path);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700471
472 if (oplockEnabled)
473 oplock = REQ_OPLOCK;
474 else
Steve French4b18f2a2008-04-29 00:06:05 +0000475 oplock = 0;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700476
Steve French7fc8f4e2009-02-23 20:43:11 +0000477 if (tcon->unix_ext && (tcon->ses->capabilities & CAP_UNIX) &&
478 (CIFS_UNIX_POSIX_PATH_OPS_CAP &
479 le64_to_cpu(tcon->fsUnixInfo.Capability))) {
480 int oflags = (int) cifs_posix_convert_flags(file->f_flags);
481 /* can not refresh inode info since size could be stale */
Jeff Layton2422f672010-06-16 13:40:16 -0400482 rc = cifs_posix_open(full_path, NULL, inode->i_sb,
Steve Frenchfa588e02010-04-22 19:21:55 +0000483 cifs_sb->mnt_file_mode /* ignored */,
484 oflags, &oplock, &netfid, xid);
Steve French7fc8f4e2009-02-23 20:43:11 +0000485 if (rc == 0) {
Joe Perchesb6b38f72010-04-21 03:50:45 +0000486 cFYI(1, "posix reopen succeeded");
Steve French7fc8f4e2009-02-23 20:43:11 +0000487 goto reopen_success;
488 }
489 /* fallthrough to retry open the old way on errors, especially
490 in the reconnect path it is important to retry hard */
491 }
492
493 desiredAccess = cifs_convert_flags(file->f_flags);
494
Linus Torvalds1da177e2005-04-16 15:20:36 -0700495 /* Can not refresh inode by passing in file_info buf to be returned
Steve Frenchfb8c4b12007-07-10 01:16:18 +0000496 by SMBOpen and then calling get_inode_info with returned buf
497 since file might have write behind data that needs to be flushed
Linus Torvalds1da177e2005-04-16 15:20:36 -0700498 and server version of file size can be stale. If we knew for sure
499 that inode was not dirty locally we could do this */
500
Steve French7fc8f4e2009-02-23 20:43:11 +0000501 rc = CIFSSMBOpen(xid, tcon, full_path, disposition, desiredAccess,
Linus Torvalds1da177e2005-04-16 15:20:36 -0700502 CREATE_NOT_DIR, &netfid, &oplock, NULL,
Steve Frenchfb8c4b12007-07-10 01:16:18 +0000503 cifs_sb->local_nls, cifs_sb->mnt_cifs_flags &
Steve French737b7582005-04-28 22:41:06 -0700504 CIFS_MOUNT_MAP_SPECIAL_CHR);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700505 if (rc) {
Jeff Laytonf0a71eb2009-06-27 07:04:55 -0400506 mutex_unlock(&pCifsFile->fh_mutex);
Joe Perchesb6b38f72010-04-21 03:50:45 +0000507 cFYI(1, "cifs_open returned 0x%x", rc);
508 cFYI(1, "oplock: %d", oplock);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700509 } else {
Steve French7fc8f4e2009-02-23 20:43:11 +0000510reopen_success:
Linus Torvalds1da177e2005-04-16 15:20:36 -0700511 pCifsFile->netfid = netfid;
Steve French4b18f2a2008-04-29 00:06:05 +0000512 pCifsFile->invalidHandle = false;
Jeff Laytonf0a71eb2009-06-27 07:04:55 -0400513 mutex_unlock(&pCifsFile->fh_mutex);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700514 pCifsInode = CIFS_I(inode);
515 if (pCifsInode) {
516 if (can_flush) {
Jeff Laytoncea21802007-11-20 23:19:03 +0000517 rc = filemap_write_and_wait(inode->i_mapping);
518 if (rc != 0)
519 CIFS_I(inode)->write_behind_rc = rc;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700520 /* temporarily disable caching while we
521 go to server to get inode info */
Steve French4b18f2a2008-04-29 00:06:05 +0000522 pCifsInode->clientCanCacheAll = false;
523 pCifsInode->clientCanCacheRead = false;
Steve French7fc8f4e2009-02-23 20:43:11 +0000524 if (tcon->unix_ext)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700525 rc = cifs_get_inode_info_unix(&inode,
526 full_path, inode->i_sb, xid);
527 else
528 rc = cifs_get_inode_info(&inode,
529 full_path, NULL, inode->i_sb,
Steve French8b1327f2008-03-14 22:37:16 +0000530 xid, NULL);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700531 } /* else we are writing out data to server already
532 and could deadlock if we tried to flush data, and
533 since we do not know if we have data that would
534 invalidate the current end of file on the server
535 we can not go to the server to get the new inod
536 info */
537 if ((oplock & 0xF) == OPLOCK_EXCLUSIVE) {
Steve French4b18f2a2008-04-29 00:06:05 +0000538 pCifsInode->clientCanCacheAll = true;
539 pCifsInode->clientCanCacheRead = true;
Joe Perchesb6b38f72010-04-21 03:50:45 +0000540 cFYI(1, "Exclusive Oplock granted on inode %p",
541 file->f_path.dentry->d_inode);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700542 } else if ((oplock & 0xF) == OPLOCK_READ) {
Steve French4b18f2a2008-04-29 00:06:05 +0000543 pCifsInode->clientCanCacheRead = true;
544 pCifsInode->clientCanCacheAll = false;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700545 } else {
Steve French4b18f2a2008-04-29 00:06:05 +0000546 pCifsInode->clientCanCacheRead = false;
547 pCifsInode->clientCanCacheAll = false;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700548 }
549 cifs_relock_file(pCifsFile);
550 }
551 }
Linus Torvalds1da177e2005-04-16 15:20:36 -0700552 kfree(full_path);
553 FreeXid(xid);
554 return rc;
555}
556
557int cifs_close(struct inode *inode, struct file *file)
558{
559 int rc = 0;
Steve French15745322007-09-07 22:23:48 +0000560 int xid, timeout;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700561 struct cifs_sb_info *cifs_sb;
562 struct cifsTconInfo *pTcon;
563 struct cifsFileInfo *pSMBFile =
564 (struct cifsFileInfo *)file->private_data;
565
566 xid = GetXid();
567
568 cifs_sb = CIFS_SB(inode->i_sb);
569 pTcon = cifs_sb->tcon;
570 if (pSMBFile) {
Jeremy Allison7ee1af72006-08-02 21:56:33 +0000571 struct cifsLockInfo *li, *tmp;
Steve Frenchddb4cbf2008-11-20 20:00:44 +0000572 write_lock(&GlobalSMBSeslock);
Steve French4b18f2a2008-04-29 00:06:05 +0000573 pSMBFile->closePend = true;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700574 if (pTcon) {
575 /* no sense reconnecting to close a file that is
576 already closed */
Steve French3b795212008-11-13 19:45:32 +0000577 if (!pTcon->need_reconnect) {
Steve Frenchddb4cbf2008-11-20 20:00:44 +0000578 write_unlock(&GlobalSMBSeslock);
Steve French15745322007-09-07 22:23:48 +0000579 timeout = 2;
Dave Kleikamp6ab409b2009-08-31 11:07:12 -0400580 while ((atomic_read(&pSMBFile->count) != 1)
Steve French15745322007-09-07 22:23:48 +0000581 && (timeout <= 2048)) {
Steve French23e7dd72005-10-20 13:44:56 -0700582 /* Give write a better chance to get to
583 server ahead of the close. We do not
584 want to add a wait_q here as it would
585 increase the memory utilization as
586 the struct would be in each open file,
Steve Frenchfb8c4b12007-07-10 01:16:18 +0000587 but this should give enough time to
Steve French23e7dd72005-10-20 13:44:56 -0700588 clear the socket */
Joe Perchesb6b38f72010-04-21 03:50:45 +0000589 cFYI(DBG2, "close delay, write pending");
Steve French23e7dd72005-10-20 13:44:56 -0700590 msleep(timeout);
591 timeout *= 4;
Steve French4891d532006-11-07 16:31:16 +0000592 }
Steve Frenchddb4cbf2008-11-20 20:00:44 +0000593 if (!pTcon->need_reconnect &&
594 !pSMBFile->invalidHandle)
595 rc = CIFSSMBClose(xid, pTcon,
Linus Torvalds1da177e2005-04-16 15:20:36 -0700596 pSMBFile->netfid);
Steve Frenchddb4cbf2008-11-20 20:00:44 +0000597 } else
598 write_unlock(&GlobalSMBSeslock);
599 } else
600 write_unlock(&GlobalSMBSeslock);
Jeremy Allison7ee1af72006-08-02 21:56:33 +0000601
602 /* Delete any outstanding lock records.
603 We'll lose them when the file is closed anyway. */
Roland Dreier796e5662007-05-03 04:33:45 +0000604 mutex_lock(&pSMBFile->lock_mutex);
Jeremy Allison7ee1af72006-08-02 21:56:33 +0000605 list_for_each_entry_safe(li, tmp, &pSMBFile->llist, llist) {
606 list_del(&li->llist);
607 kfree(li);
608 }
Roland Dreier796e5662007-05-03 04:33:45 +0000609 mutex_unlock(&pSMBFile->lock_mutex);
Jeremy Allison7ee1af72006-08-02 21:56:33 +0000610
Steve Frenchcbe04762005-04-28 22:41:05 -0700611 write_lock(&GlobalSMBSeslock);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700612 list_del(&pSMBFile->flist);
613 list_del(&pSMBFile->tlist);
Steve Frenchcbe04762005-04-28 22:41:05 -0700614 write_unlock(&GlobalSMBSeslock);
Dave Kleikamp6ab409b2009-08-31 11:07:12 -0400615 cifsFileInfo_put(file->private_data);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700616 file->private_data = NULL;
617 } else
618 rc = -EBADF;
619
Steve French4efa53f2007-09-11 05:50:53 +0000620 read_lock(&GlobalSMBSeslock);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700621 if (list_empty(&(CIFS_I(inode)->openFileList))) {
Joe Perchesb6b38f72010-04-21 03:50:45 +0000622 cFYI(1, "closing last open instance for inode %p", inode);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700623 /* if the file is not open we do not know if we can cache info
624 on this inode, much less write behind and read ahead */
Steve French4b18f2a2008-04-29 00:06:05 +0000625 CIFS_I(inode)->clientCanCacheRead = false;
626 CIFS_I(inode)->clientCanCacheAll = false;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700627 }
Steve French4efa53f2007-09-11 05:50:53 +0000628 read_unlock(&GlobalSMBSeslock);
Steve Frenchfb8c4b12007-07-10 01:16:18 +0000629 if ((rc == 0) && CIFS_I(inode)->write_behind_rc)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700630 rc = CIFS_I(inode)->write_behind_rc;
631 FreeXid(xid);
632 return rc;
633}
634
635int cifs_closedir(struct inode *inode, struct file *file)
636{
637 int rc = 0;
638 int xid;
639 struct cifsFileInfo *pCFileStruct =
640 (struct cifsFileInfo *)file->private_data;
641 char *ptmp;
642
Joe Perchesb6b38f72010-04-21 03:50:45 +0000643 cFYI(1, "Closedir inode = 0x%p", inode);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700644
645 xid = GetXid();
646
647 if (pCFileStruct) {
648 struct cifsTconInfo *pTcon;
Steve Frenchfb8c4b12007-07-10 01:16:18 +0000649 struct cifs_sb_info *cifs_sb =
650 CIFS_SB(file->f_path.dentry->d_sb);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700651
652 pTcon = cifs_sb->tcon;
653
Joe Perchesb6b38f72010-04-21 03:50:45 +0000654 cFYI(1, "Freeing private data in close dir");
Steve Frenchddb4cbf2008-11-20 20:00:44 +0000655 write_lock(&GlobalSMBSeslock);
Steve French4b18f2a2008-04-29 00:06:05 +0000656 if (!pCFileStruct->srch_inf.endOfSearch &&
657 !pCFileStruct->invalidHandle) {
658 pCFileStruct->invalidHandle = true;
Steve Frenchddb4cbf2008-11-20 20:00:44 +0000659 write_unlock(&GlobalSMBSeslock);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700660 rc = CIFSFindClose(xid, pTcon, pCFileStruct->netfid);
Joe Perchesb6b38f72010-04-21 03:50:45 +0000661 cFYI(1, "Closing uncompleted readdir with rc %d",
662 rc);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700663 /* not much we can do if it fails anyway, ignore rc */
664 rc = 0;
Steve Frenchddb4cbf2008-11-20 20:00:44 +0000665 } else
666 write_unlock(&GlobalSMBSeslock);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700667 ptmp = pCFileStruct->srch_inf.ntwrk_buf_start;
668 if (ptmp) {
Joe Perchesb6b38f72010-04-21 03:50:45 +0000669 cFYI(1, "closedir free smb buf in srch struct");
Linus Torvalds1da177e2005-04-16 15:20:36 -0700670 pCFileStruct->srch_inf.ntwrk_buf_start = NULL;
Steve Frenchfb8c4b12007-07-10 01:16:18 +0000671 if (pCFileStruct->srch_inf.smallBuf)
Steve Frenchd47d7c12006-02-28 03:45:48 +0000672 cifs_small_buf_release(ptmp);
673 else
674 cifs_buf_release(ptmp);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700675 }
Linus Torvalds1da177e2005-04-16 15:20:36 -0700676 kfree(file->private_data);
677 file->private_data = NULL;
678 }
679 /* BB can we lock the filestruct while this is going on? */
680 FreeXid(xid);
681 return rc;
682}
683
Jeremy Allison7ee1af72006-08-02 21:56:33 +0000684static int store_file_lock(struct cifsFileInfo *fid, __u64 len,
685 __u64 offset, __u8 lockType)
686{
Steve Frenchfb8c4b12007-07-10 01:16:18 +0000687 struct cifsLockInfo *li =
688 kmalloc(sizeof(struct cifsLockInfo), GFP_KERNEL);
Jeremy Allison7ee1af72006-08-02 21:56:33 +0000689 if (li == NULL)
690 return -ENOMEM;
691 li->offset = offset;
692 li->length = len;
693 li->type = lockType;
Roland Dreier796e5662007-05-03 04:33:45 +0000694 mutex_lock(&fid->lock_mutex);
Jeremy Allison7ee1af72006-08-02 21:56:33 +0000695 list_add(&li->llist, &fid->llist);
Roland Dreier796e5662007-05-03 04:33:45 +0000696 mutex_unlock(&fid->lock_mutex);
Jeremy Allison7ee1af72006-08-02 21:56:33 +0000697 return 0;
698}
699
Linus Torvalds1da177e2005-04-16 15:20:36 -0700700int cifs_lock(struct file *file, int cmd, struct file_lock *pfLock)
701{
702 int rc, xid;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700703 __u32 numLock = 0;
704 __u32 numUnlock = 0;
705 __u64 length;
Steve French4b18f2a2008-04-29 00:06:05 +0000706 bool wait_flag = false;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700707 struct cifs_sb_info *cifs_sb;
Steve French13a6e422008-12-02 17:24:33 +0000708 struct cifsTconInfo *tcon;
Steve French08547b02006-02-28 22:39:25 +0000709 __u16 netfid;
710 __u8 lockType = LOCKING_ANDX_LARGE_FILES;
Steve French13a6e422008-12-02 17:24:33 +0000711 bool posix_locking = 0;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700712
713 length = 1 + pfLock->fl_end - pfLock->fl_start;
714 rc = -EACCES;
715 xid = GetXid();
716
Joe Perchesb6b38f72010-04-21 03:50:45 +0000717 cFYI(1, "Lock parm: 0x%x flockflags: "
Linus Torvalds1da177e2005-04-16 15:20:36 -0700718 "0x%x flocktype: 0x%x start: %lld end: %lld",
Steve Frenchfb8c4b12007-07-10 01:16:18 +0000719 cmd, pfLock->fl_flags, pfLock->fl_type, pfLock->fl_start,
Joe Perchesb6b38f72010-04-21 03:50:45 +0000720 pfLock->fl_end);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700721
722 if (pfLock->fl_flags & FL_POSIX)
Joe Perchesb6b38f72010-04-21 03:50:45 +0000723 cFYI(1, "Posix");
Linus Torvalds1da177e2005-04-16 15:20:36 -0700724 if (pfLock->fl_flags & FL_FLOCK)
Joe Perchesb6b38f72010-04-21 03:50:45 +0000725 cFYI(1, "Flock");
Linus Torvalds1da177e2005-04-16 15:20:36 -0700726 if (pfLock->fl_flags & FL_SLEEP) {
Joe Perchesb6b38f72010-04-21 03:50:45 +0000727 cFYI(1, "Blocking lock");
Steve French4b18f2a2008-04-29 00:06:05 +0000728 wait_flag = true;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700729 }
730 if (pfLock->fl_flags & FL_ACCESS)
Joe Perchesb6b38f72010-04-21 03:50:45 +0000731 cFYI(1, "Process suspended by mandatory locking - "
732 "not implemented yet");
Linus Torvalds1da177e2005-04-16 15:20:36 -0700733 if (pfLock->fl_flags & FL_LEASE)
Joe Perchesb6b38f72010-04-21 03:50:45 +0000734 cFYI(1, "Lease on file - not implemented yet");
Steve Frenchfb8c4b12007-07-10 01:16:18 +0000735 if (pfLock->fl_flags &
Linus Torvalds1da177e2005-04-16 15:20:36 -0700736 (~(FL_POSIX | FL_FLOCK | FL_SLEEP | FL_ACCESS | FL_LEASE)))
Joe Perchesb6b38f72010-04-21 03:50:45 +0000737 cFYI(1, "Unknown lock flags 0x%x", pfLock->fl_flags);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700738
739 if (pfLock->fl_type == F_WRLCK) {
Joe Perchesb6b38f72010-04-21 03:50:45 +0000740 cFYI(1, "F_WRLCK ");
Linus Torvalds1da177e2005-04-16 15:20:36 -0700741 numLock = 1;
742 } else if (pfLock->fl_type == F_UNLCK) {
Joe Perchesb6b38f72010-04-21 03:50:45 +0000743 cFYI(1, "F_UNLCK");
Linus Torvalds1da177e2005-04-16 15:20:36 -0700744 numUnlock = 1;
Steve Frenchd47d7c12006-02-28 03:45:48 +0000745 /* Check if unlock includes more than
746 one lock range */
Linus Torvalds1da177e2005-04-16 15:20:36 -0700747 } else if (pfLock->fl_type == F_RDLCK) {
Joe Perchesb6b38f72010-04-21 03:50:45 +0000748 cFYI(1, "F_RDLCK");
Linus Torvalds1da177e2005-04-16 15:20:36 -0700749 lockType |= LOCKING_ANDX_SHARED_LOCK;
750 numLock = 1;
751 } else if (pfLock->fl_type == F_EXLCK) {
Joe Perchesb6b38f72010-04-21 03:50:45 +0000752 cFYI(1, "F_EXLCK");
Linus Torvalds1da177e2005-04-16 15:20:36 -0700753 numLock = 1;
754 } else if (pfLock->fl_type == F_SHLCK) {
Joe Perchesb6b38f72010-04-21 03:50:45 +0000755 cFYI(1, "F_SHLCK");
Linus Torvalds1da177e2005-04-16 15:20:36 -0700756 lockType |= LOCKING_ANDX_SHARED_LOCK;
757 numLock = 1;
758 } else
Joe Perchesb6b38f72010-04-21 03:50:45 +0000759 cFYI(1, "Unknown type of lock");
Linus Torvalds1da177e2005-04-16 15:20:36 -0700760
Josef "Jeff" Sipeke6a00292006-12-08 02:36:48 -0800761 cifs_sb = CIFS_SB(file->f_path.dentry->d_sb);
Steve French13a6e422008-12-02 17:24:33 +0000762 tcon = cifs_sb->tcon;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700763
764 if (file->private_data == NULL) {
Suresh Jayaraman0f3bc092009-06-25 18:12:34 +0530765 rc = -EBADF;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700766 FreeXid(xid);
Suresh Jayaraman0f3bc092009-06-25 18:12:34 +0530767 return rc;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700768 }
Steve French08547b02006-02-28 22:39:25 +0000769 netfid = ((struct cifsFileInfo *)file->private_data)->netfid;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700770
Steve French13a6e422008-12-02 17:24:33 +0000771 if ((tcon->ses->capabilities & CAP_UNIX) &&
772 (CIFS_UNIX_FCNTL_CAP & le64_to_cpu(tcon->fsUnixInfo.Capability)) &&
Steve Frenchacc18aa2008-12-02 18:53:55 +0000773 ((cifs_sb->mnt_cifs_flags & CIFS_MOUNT_NOPOSIXBRL) == 0))
Steve French13a6e422008-12-02 17:24:33 +0000774 posix_locking = 1;
Steve French08547b02006-02-28 22:39:25 +0000775 /* BB add code here to normalize offset and length to
776 account for negative length which we can not accept over the
777 wire */
Linus Torvalds1da177e2005-04-16 15:20:36 -0700778 if (IS_GETLK(cmd)) {
Steve Frenchfb8c4b12007-07-10 01:16:18 +0000779 if (posix_locking) {
Steve French08547b02006-02-28 22:39:25 +0000780 int posix_lock_type;
Steve Frenchfb8c4b12007-07-10 01:16:18 +0000781 if (lockType & LOCKING_ANDX_SHARED_LOCK)
Steve French08547b02006-02-28 22:39:25 +0000782 posix_lock_type = CIFS_RDLCK;
783 else
784 posix_lock_type = CIFS_WRLCK;
Steve French13a6e422008-12-02 17:24:33 +0000785 rc = CIFSSMBPosixLock(xid, tcon, netfid, 1 /* get */,
Steve Frenchfc94cdb2006-05-30 18:03:32 +0000786 length, pfLock,
Steve French08547b02006-02-28 22:39:25 +0000787 posix_lock_type, wait_flag);
788 FreeXid(xid);
789 return rc;
790 }
791
792 /* BB we could chain these into one lock request BB */
Steve French13a6e422008-12-02 17:24:33 +0000793 rc = CIFSSMBLock(xid, tcon, netfid, length, pfLock->fl_start,
Steve French08547b02006-02-28 22:39:25 +0000794 0, 1, lockType, 0 /* wait flag */ );
Linus Torvalds1da177e2005-04-16 15:20:36 -0700795 if (rc == 0) {
Steve French13a6e422008-12-02 17:24:33 +0000796 rc = CIFSSMBLock(xid, tcon, netfid, length,
Linus Torvalds1da177e2005-04-16 15:20:36 -0700797 pfLock->fl_start, 1 /* numUnlock */ ,
798 0 /* numLock */ , lockType,
799 0 /* wait flag */ );
800 pfLock->fl_type = F_UNLCK;
801 if (rc != 0)
Joe Perchesb6b38f72010-04-21 03:50:45 +0000802 cERROR(1, "Error unlocking previously locked "
803 "range %d during test of lock", rc);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700804 rc = 0;
805
806 } else {
807 /* if rc == ERR_SHARING_VIOLATION ? */
Pavel Shilovskyf05337c2010-04-05 09:59:14 +0400808 rc = 0;
809
810 if (lockType & LOCKING_ANDX_SHARED_LOCK) {
811 pfLock->fl_type = F_WRLCK;
812 } else {
813 rc = CIFSSMBLock(xid, tcon, netfid, length,
814 pfLock->fl_start, 0, 1,
815 lockType | LOCKING_ANDX_SHARED_LOCK,
816 0 /* wait flag */);
817 if (rc == 0) {
818 rc = CIFSSMBLock(xid, tcon, netfid,
819 length, pfLock->fl_start, 1, 0,
820 lockType |
821 LOCKING_ANDX_SHARED_LOCK,
822 0 /* wait flag */);
823 pfLock->fl_type = F_RDLCK;
824 if (rc != 0)
Steve Frenchf19159d2010-04-21 04:12:10 +0000825 cERROR(1, "Error unlocking "
Pavel Shilovskyf05337c2010-04-05 09:59:14 +0400826 "previously locked range %d "
Steve Frenchf19159d2010-04-21 04:12:10 +0000827 "during test of lock", rc);
Pavel Shilovskyf05337c2010-04-05 09:59:14 +0400828 rc = 0;
829 } else {
830 pfLock->fl_type = F_WRLCK;
831 rc = 0;
832 }
833 }
Linus Torvalds1da177e2005-04-16 15:20:36 -0700834 }
835
836 FreeXid(xid);
837 return rc;
838 }
Jeremy Allison7ee1af72006-08-02 21:56:33 +0000839
840 if (!numLock && !numUnlock) {
841 /* if no lock or unlock then nothing
842 to do since we do not know what it is */
843 FreeXid(xid);
844 return -EOPNOTSUPP;
845 }
846
847 if (posix_locking) {
Steve French08547b02006-02-28 22:39:25 +0000848 int posix_lock_type;
Steve Frenchfb8c4b12007-07-10 01:16:18 +0000849 if (lockType & LOCKING_ANDX_SHARED_LOCK)
Steve French08547b02006-02-28 22:39:25 +0000850 posix_lock_type = CIFS_RDLCK;
851 else
852 posix_lock_type = CIFS_WRLCK;
Steve French50c2f752007-07-13 00:33:32 +0000853
Steve Frenchfb8c4b12007-07-10 01:16:18 +0000854 if (numUnlock == 1)
Steve Frenchbeb84dc2006-03-03 23:36:34 +0000855 posix_lock_type = CIFS_UNLCK;
Jeremy Allison7ee1af72006-08-02 21:56:33 +0000856
Steve French13a6e422008-12-02 17:24:33 +0000857 rc = CIFSSMBPosixLock(xid, tcon, netfid, 0 /* set */,
Steve Frenchfc94cdb2006-05-30 18:03:32 +0000858 length, pfLock,
Steve French08547b02006-02-28 22:39:25 +0000859 posix_lock_type, wait_flag);
Jeremy Allison7ee1af72006-08-02 21:56:33 +0000860 } else {
Steve Frenchfb8c4b12007-07-10 01:16:18 +0000861 struct cifsFileInfo *fid =
862 (struct cifsFileInfo *)file->private_data;
Jeremy Allison7ee1af72006-08-02 21:56:33 +0000863
864 if (numLock) {
Steve French13a6e422008-12-02 17:24:33 +0000865 rc = CIFSSMBLock(xid, tcon, netfid, length,
Steve Frenchfb8c4b12007-07-10 01:16:18 +0000866 pfLock->fl_start,
Jeremy Allison7ee1af72006-08-02 21:56:33 +0000867 0, numLock, lockType, wait_flag);
868
869 if (rc == 0) {
870 /* For Windows locks we must store them. */
871 rc = store_file_lock(fid, length,
872 pfLock->fl_start, lockType);
873 }
874 } else if (numUnlock) {
875 /* For each stored lock that this unlock overlaps
876 completely, unlock it. */
877 int stored_rc = 0;
878 struct cifsLockInfo *li, *tmp;
879
Steve French6b70c952006-09-21 07:35:29 +0000880 rc = 0;
Roland Dreier796e5662007-05-03 04:33:45 +0000881 mutex_lock(&fid->lock_mutex);
Jeremy Allison7ee1af72006-08-02 21:56:33 +0000882 list_for_each_entry_safe(li, tmp, &fid->llist, llist) {
883 if (pfLock->fl_start <= li->offset &&
Steve Frenchc19eb712007-08-24 03:22:48 +0000884 (pfLock->fl_start + length) >=
Jeff Layton39db8102007-08-24 03:16:51 +0000885 (li->offset + li->length)) {
Steve French13a6e422008-12-02 17:24:33 +0000886 stored_rc = CIFSSMBLock(xid, tcon,
Steve Frenchfb8c4b12007-07-10 01:16:18 +0000887 netfid,
Jeremy Allison7ee1af72006-08-02 21:56:33 +0000888 li->length, li->offset,
Steve French4b18f2a2008-04-29 00:06:05 +0000889 1, 0, li->type, false);
Jeremy Allison7ee1af72006-08-02 21:56:33 +0000890 if (stored_rc)
891 rc = stored_rc;
Pavel Shilovsky2c964d12010-04-21 19:44:24 +0000892 else {
893 list_del(&li->llist);
894 kfree(li);
895 }
Jeremy Allison7ee1af72006-08-02 21:56:33 +0000896 }
897 }
Roland Dreier796e5662007-05-03 04:33:45 +0000898 mutex_unlock(&fid->lock_mutex);
Jeremy Allison7ee1af72006-08-02 21:56:33 +0000899 }
900 }
901
Steve Frenchd634cc12005-08-26 14:42:59 -0500902 if (pfLock->fl_flags & FL_POSIX)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700903 posix_lock_file_wait(file, pfLock);
904 FreeXid(xid);
905 return rc;
906}
907
Jeff Laytonfbec9ab2009-04-03 13:44:00 -0400908/*
909 * Set the timeout on write requests past EOF. For some servers (Windows)
910 * these calls can be very long.
911 *
912 * If we're writing >10M past the EOF we give a 180s timeout. Anything less
913 * than that gets a 45s timeout. Writes not past EOF get 15s timeouts.
914 * The 10M cutoff is totally arbitrary. A better scheme for this would be
915 * welcome if someone wants to suggest one.
916 *
917 * We may be able to do a better job with this if there were some way to
918 * declare that a file should be sparse.
919 */
920static int
921cifs_write_timeout(struct cifsInodeInfo *cifsi, loff_t offset)
922{
923 if (offset <= cifsi->server_eof)
924 return CIFS_STD_OP;
925 else if (offset > (cifsi->server_eof + (10 * 1024 * 1024)))
926 return CIFS_VLONG_OP;
927 else
928 return CIFS_LONG_OP;
929}
930
931/* update the file size (if needed) after a write */
932static void
933cifs_update_eof(struct cifsInodeInfo *cifsi, loff_t offset,
934 unsigned int bytes_written)
935{
936 loff_t end_of_write = offset + bytes_written;
937
938 if (end_of_write > cifsi->server_eof)
939 cifsi->server_eof = end_of_write;
940}
941
Linus Torvalds1da177e2005-04-16 15:20:36 -0700942ssize_t cifs_user_write(struct file *file, const char __user *write_data,
943 size_t write_size, loff_t *poffset)
944{
945 int rc = 0;
946 unsigned int bytes_written = 0;
947 unsigned int total_written;
948 struct cifs_sb_info *cifs_sb;
949 struct cifsTconInfo *pTcon;
950 int xid, long_op;
951 struct cifsFileInfo *open_file;
Jeff Laytonfbec9ab2009-04-03 13:44:00 -0400952 struct cifsInodeInfo *cifsi = CIFS_I(file->f_path.dentry->d_inode);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700953
Josef "Jeff" Sipeke6a00292006-12-08 02:36:48 -0800954 cifs_sb = CIFS_SB(file->f_path.dentry->d_sb);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700955
956 pTcon = cifs_sb->tcon;
957
Joe Perchesb6b38f72010-04-21 03:50:45 +0000958 /* cFYI(1, " write %d bytes to offset %lld of %s", write_size,
959 *poffset, file->f_path.dentry->d_name.name); */
Linus Torvalds1da177e2005-04-16 15:20:36 -0700960
961 if (file->private_data == NULL)
962 return -EBADF;
Christoph Hellwigc33f8d32007-04-02 18:47:20 +0000963 open_file = (struct cifsFileInfo *) file->private_data;
Steve French50c2f752007-07-13 00:33:32 +0000964
Jeff Layton838726c2008-08-28 07:54:59 -0400965 rc = generic_write_checks(file, poffset, &write_size, 0);
966 if (rc)
967 return rc;
968
Linus Torvalds1da177e2005-04-16 15:20:36 -0700969 xid = GetXid();
Linus Torvalds1da177e2005-04-16 15:20:36 -0700970
Jeff Laytonfbec9ab2009-04-03 13:44:00 -0400971 long_op = cifs_write_timeout(cifsi, *poffset);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700972 for (total_written = 0; write_size > total_written;
973 total_written += bytes_written) {
974 rc = -EAGAIN;
975 while (rc == -EAGAIN) {
976 if (file->private_data == NULL) {
977 /* file has been closed on us */
978 FreeXid(xid);
979 /* if we have gotten here we have written some data
980 and blocked, and the file has been freed on us while
981 we blocked so return what we managed to write */
982 return total_written;
Steve Frenchfb8c4b12007-07-10 01:16:18 +0000983 }
Linus Torvalds1da177e2005-04-16 15:20:36 -0700984 if (open_file->closePend) {
985 FreeXid(xid);
986 if (total_written)
987 return total_written;
988 else
989 return -EBADF;
990 }
991 if (open_file->invalidHandle) {
Linus Torvalds1da177e2005-04-16 15:20:36 -0700992 /* we could deadlock if we called
993 filemap_fdatawait from here so tell
994 reopen_file not to flush data to server
995 now */
Steve French4b18f2a2008-04-29 00:06:05 +0000996 rc = cifs_reopen_file(file, false);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700997 if (rc != 0)
998 break;
999 }
1000
1001 rc = CIFSSMBWrite(xid, pTcon,
1002 open_file->netfid,
1003 min_t(const int, cifs_sb->wsize,
1004 write_size - total_written),
1005 *poffset, &bytes_written,
1006 NULL, write_data + total_written, long_op);
1007 }
1008 if (rc || (bytes_written == 0)) {
1009 if (total_written)
1010 break;
1011 else {
1012 FreeXid(xid);
1013 return rc;
1014 }
Jeff Laytonfbec9ab2009-04-03 13:44:00 -04001015 } else {
1016 cifs_update_eof(cifsi, *poffset, bytes_written);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001017 *poffset += bytes_written;
Jeff Laytonfbec9ab2009-04-03 13:44:00 -04001018 }
Steve French133672e2007-11-13 22:41:37 +00001019 long_op = CIFS_STD_OP; /* subsequent writes fast -
Linus Torvalds1da177e2005-04-16 15:20:36 -07001020 15 seconds is plenty */
1021 }
1022
Steve Frencha4544342005-08-24 13:59:35 -07001023 cifs_stats_bytes_written(pTcon, total_written);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001024
1025 /* since the write may have blocked check these pointers again */
Steve French3677db12007-02-26 16:46:11 +00001026 if ((file->f_path.dentry) && (file->f_path.dentry->d_inode)) {
1027 struct inode *inode = file->f_path.dentry->d_inode;
Steve Frenchfb8c4b12007-07-10 01:16:18 +00001028/* Do not update local mtime - server will set its actual value on write
1029 * inode->i_ctime = inode->i_mtime =
Steve French3677db12007-02-26 16:46:11 +00001030 * current_fs_time(inode->i_sb);*/
1031 if (total_written > 0) {
1032 spin_lock(&inode->i_lock);
1033 if (*poffset > file->f_path.dentry->d_inode->i_size)
1034 i_size_write(file->f_path.dentry->d_inode,
Linus Torvalds1da177e2005-04-16 15:20:36 -07001035 *poffset);
Steve French3677db12007-02-26 16:46:11 +00001036 spin_unlock(&inode->i_lock);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001037 }
Steve Frenchfb8c4b12007-07-10 01:16:18 +00001038 mark_inode_dirty_sync(file->f_path.dentry->d_inode);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001039 }
1040 FreeXid(xid);
1041 return total_written;
1042}
1043
1044static ssize_t cifs_write(struct file *file, const char *write_data,
Nick Piggind9414772008-09-24 11:32:59 -04001045 size_t write_size, loff_t *poffset)
Linus Torvalds1da177e2005-04-16 15:20:36 -07001046{
1047 int rc = 0;
1048 unsigned int bytes_written = 0;
1049 unsigned int total_written;
1050 struct cifs_sb_info *cifs_sb;
1051 struct cifsTconInfo *pTcon;
1052 int xid, long_op;
1053 struct cifsFileInfo *open_file;
Jeff Laytonfbec9ab2009-04-03 13:44:00 -04001054 struct cifsInodeInfo *cifsi = CIFS_I(file->f_path.dentry->d_inode);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001055
Josef "Jeff" Sipeke6a00292006-12-08 02:36:48 -08001056 cifs_sb = CIFS_SB(file->f_path.dentry->d_sb);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001057
1058 pTcon = cifs_sb->tcon;
1059
Joe Perchesb6b38f72010-04-21 03:50:45 +00001060 cFYI(1, "write %zd bytes to offset %lld of %s", write_size,
1061 *poffset, file->f_path.dentry->d_name.name);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001062
1063 if (file->private_data == NULL)
1064 return -EBADF;
Christoph Hellwigc33f8d32007-04-02 18:47:20 +00001065 open_file = (struct cifsFileInfo *)file->private_data;
Steve French50c2f752007-07-13 00:33:32 +00001066
Linus Torvalds1da177e2005-04-16 15:20:36 -07001067 xid = GetXid();
Linus Torvalds1da177e2005-04-16 15:20:36 -07001068
Jeff Laytonfbec9ab2009-04-03 13:44:00 -04001069 long_op = cifs_write_timeout(cifsi, *poffset);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001070 for (total_written = 0; write_size > total_written;
1071 total_written += bytes_written) {
1072 rc = -EAGAIN;
1073 while (rc == -EAGAIN) {
1074 if (file->private_data == NULL) {
1075 /* file has been closed on us */
1076 FreeXid(xid);
1077 /* if we have gotten here we have written some data
1078 and blocked, and the file has been freed on us
Steve Frenchfb8c4b12007-07-10 01:16:18 +00001079 while we blocked so return what we managed to
Linus Torvalds1da177e2005-04-16 15:20:36 -07001080 write */
1081 return total_written;
Steve Frenchfb8c4b12007-07-10 01:16:18 +00001082 }
Linus Torvalds1da177e2005-04-16 15:20:36 -07001083 if (open_file->closePend) {
1084 FreeXid(xid);
1085 if (total_written)
1086 return total_written;
1087 else
1088 return -EBADF;
1089 }
1090 if (open_file->invalidHandle) {
Linus Torvalds1da177e2005-04-16 15:20:36 -07001091 /* we could deadlock if we called
1092 filemap_fdatawait from here so tell
Steve Frenchfb8c4b12007-07-10 01:16:18 +00001093 reopen_file not to flush data to
Linus Torvalds1da177e2005-04-16 15:20:36 -07001094 server now */
Steve French4b18f2a2008-04-29 00:06:05 +00001095 rc = cifs_reopen_file(file, false);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001096 if (rc != 0)
1097 break;
1098 }
Steve Frenchfb8c4b12007-07-10 01:16:18 +00001099 if (experimEnabled || (pTcon->ses->server &&
1100 ((pTcon->ses->server->secMode &
Steve French08775832006-05-30 18:08:26 +00001101 (SECMODE_SIGN_REQUIRED | SECMODE_SIGN_ENABLED))
Steve Frenchc01f36a2006-05-30 18:05:10 +00001102 == 0))) {
Steve French3e844692005-10-03 13:37:24 -07001103 struct kvec iov[2];
1104 unsigned int len;
1105
Steve French0ae0efa2005-10-10 10:57:19 -07001106 len = min((size_t)cifs_sb->wsize,
Steve French3e844692005-10-03 13:37:24 -07001107 write_size - total_written);
1108 /* iov[0] is reserved for smb header */
1109 iov[1].iov_base = (char *)write_data +
1110 total_written;
1111 iov[1].iov_len = len;
Steve Frenchd6e04ae2005-06-13 13:24:43 -05001112 rc = CIFSSMBWrite2(xid, pTcon,
Steve French3e844692005-10-03 13:37:24 -07001113 open_file->netfid, len,
Steve Frenchd6e04ae2005-06-13 13:24:43 -05001114 *poffset, &bytes_written,
Steve French3e844692005-10-03 13:37:24 -07001115 iov, 1, long_op);
Steve Frenchd6e04ae2005-06-13 13:24:43 -05001116 } else
Steve French60808232006-04-22 15:53:05 +00001117 rc = CIFSSMBWrite(xid, pTcon,
1118 open_file->netfid,
1119 min_t(const int, cifs_sb->wsize,
1120 write_size - total_written),
1121 *poffset, &bytes_written,
1122 write_data + total_written,
1123 NULL, long_op);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001124 }
1125 if (rc || (bytes_written == 0)) {
1126 if (total_written)
1127 break;
1128 else {
1129 FreeXid(xid);
1130 return rc;
1131 }
Jeff Laytonfbec9ab2009-04-03 13:44:00 -04001132 } else {
1133 cifs_update_eof(cifsi, *poffset, bytes_written);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001134 *poffset += bytes_written;
Jeff Laytonfbec9ab2009-04-03 13:44:00 -04001135 }
Steve French133672e2007-11-13 22:41:37 +00001136 long_op = CIFS_STD_OP; /* subsequent writes fast -
Linus Torvalds1da177e2005-04-16 15:20:36 -07001137 15 seconds is plenty */
1138 }
1139
Steve Frencha4544342005-08-24 13:59:35 -07001140 cifs_stats_bytes_written(pTcon, total_written);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001141
1142 /* since the write may have blocked check these pointers again */
Steve French3677db12007-02-26 16:46:11 +00001143 if ((file->f_path.dentry) && (file->f_path.dentry->d_inode)) {
Steve French004c46b2007-02-17 04:34:13 +00001144/*BB We could make this contingent on superblock ATIME flag too */
Steve French3677db12007-02-26 16:46:11 +00001145/* file->f_path.dentry->d_inode->i_ctime =
1146 file->f_path.dentry->d_inode->i_mtime = CURRENT_TIME;*/
1147 if (total_written > 0) {
1148 spin_lock(&file->f_path.dentry->d_inode->i_lock);
1149 if (*poffset > file->f_path.dentry->d_inode->i_size)
1150 i_size_write(file->f_path.dentry->d_inode,
1151 *poffset);
1152 spin_unlock(&file->f_path.dentry->d_inode->i_lock);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001153 }
Steve French3677db12007-02-26 16:46:11 +00001154 mark_inode_dirty_sync(file->f_path.dentry->d_inode);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001155 }
1156 FreeXid(xid);
1157 return total_written;
1158}
1159
Steve French630f3f0c2007-10-25 21:17:17 +00001160#ifdef CONFIG_CIFS_EXPERIMENTAL
1161struct cifsFileInfo *find_readable_file(struct cifsInodeInfo *cifs_inode)
1162{
1163 struct cifsFileInfo *open_file = NULL;
1164
1165 read_lock(&GlobalSMBSeslock);
1166 /* we could simply get the first_list_entry since write-only entries
1167 are always at the end of the list but since the first entry might
1168 have a close pending, we go through the whole list */
1169 list_for_each_entry(open_file, &cifs_inode->openFileList, flist) {
1170 if (open_file->closePend)
1171 continue;
1172 if (open_file->pfile && ((open_file->pfile->f_flags & O_RDWR) ||
1173 (open_file->pfile->f_flags & O_RDONLY))) {
1174 if (!open_file->invalidHandle) {
1175 /* found a good file */
1176 /* lock it so it will not be closed on us */
Dave Kleikamp6ab409b2009-08-31 11:07:12 -04001177 cifsFileInfo_get(open_file);
Steve French630f3f0c2007-10-25 21:17:17 +00001178 read_unlock(&GlobalSMBSeslock);
1179 return open_file;
1180 } /* else might as well continue, and look for
1181 another, or simply have the caller reopen it
1182 again rather than trying to fix this handle */
1183 } else /* write only file */
1184 break; /* write only files are last so must be done */
1185 }
1186 read_unlock(&GlobalSMBSeslock);
1187 return NULL;
1188}
1189#endif
1190
Steve Frenchdd99cd82005-10-05 19:32:49 -07001191struct cifsFileInfo *find_writable_file(struct cifsInodeInfo *cifs_inode)
Steve French6148a742005-10-05 12:23:19 -07001192{
1193 struct cifsFileInfo *open_file;
Jeff Layton2846d382008-09-22 21:33:33 -04001194 bool any_available = false;
Steve Frenchdd99cd82005-10-05 19:32:49 -07001195 int rc;
Steve French6148a742005-10-05 12:23:19 -07001196
Steve French60808232006-04-22 15:53:05 +00001197 /* Having a null inode here (because mapping->host was set to zero by
1198 the VFS or MM) should not happen but we had reports of on oops (due to
1199 it being zero) during stress testcases so we need to check for it */
1200
Steve Frenchfb8c4b12007-07-10 01:16:18 +00001201 if (cifs_inode == NULL) {
Joe Perchesb6b38f72010-04-21 03:50:45 +00001202 cERROR(1, "Null inode passed to cifs_writeable_file");
Steve French60808232006-04-22 15:53:05 +00001203 dump_stack();
1204 return NULL;
1205 }
1206
Steve French6148a742005-10-05 12:23:19 -07001207 read_lock(&GlobalSMBSeslock);
Steve French9b22b0b2007-10-02 01:11:08 +00001208refind_writable:
Steve French6148a742005-10-05 12:23:19 -07001209 list_for_each_entry(open_file, &cifs_inode->openFileList, flist) {
Jeff Layton2846d382008-09-22 21:33:33 -04001210 if (open_file->closePend ||
1211 (!any_available && open_file->pid != current->tgid))
Steve French6148a742005-10-05 12:23:19 -07001212 continue;
Jeff Layton2846d382008-09-22 21:33:33 -04001213
Steve French6148a742005-10-05 12:23:19 -07001214 if (open_file->pfile &&
1215 ((open_file->pfile->f_flags & O_RDWR) ||
1216 (open_file->pfile->f_flags & O_WRONLY))) {
Dave Kleikamp6ab409b2009-08-31 11:07:12 -04001217 cifsFileInfo_get(open_file);
Steve French9b22b0b2007-10-02 01:11:08 +00001218
1219 if (!open_file->invalidHandle) {
1220 /* found a good writable file */
1221 read_unlock(&GlobalSMBSeslock);
1222 return open_file;
1223 }
Steve French8840dee2007-11-16 23:05:52 +00001224
Steve French6148a742005-10-05 12:23:19 -07001225 read_unlock(&GlobalSMBSeslock);
Steve French9b22b0b2007-10-02 01:11:08 +00001226 /* Had to unlock since following call can block */
Steve French4b18f2a2008-04-29 00:06:05 +00001227 rc = cifs_reopen_file(open_file->pfile, false);
Steve French8840dee2007-11-16 23:05:52 +00001228 if (!rc) {
Steve French9b22b0b2007-10-02 01:11:08 +00001229 if (!open_file->closePend)
1230 return open_file;
1231 else { /* start over in case this was deleted */
1232 /* since the list could be modified */
Steve French37c0eb42005-10-05 14:50:29 -07001233 read_lock(&GlobalSMBSeslock);
Dave Kleikamp6ab409b2009-08-31 11:07:12 -04001234 cifsFileInfo_put(open_file);
Steve French9b22b0b2007-10-02 01:11:08 +00001235 goto refind_writable;
Steve French37c0eb42005-10-05 14:50:29 -07001236 }
1237 }
Steve French9b22b0b2007-10-02 01:11:08 +00001238
1239 /* if it fails, try another handle if possible -
1240 (we can not do this if closePending since
1241 loop could be modified - in which case we
1242 have to start at the beginning of the list
1243 again. Note that it would be bad
1244 to hold up writepages here (rather than
1245 in caller) with continuous retries */
Joe Perchesb6b38f72010-04-21 03:50:45 +00001246 cFYI(1, "wp failed on reopen file");
Steve French9b22b0b2007-10-02 01:11:08 +00001247 read_lock(&GlobalSMBSeslock);
1248 /* can not use this handle, no write
1249 pending on this one after all */
Dave Kleikamp6ab409b2009-08-31 11:07:12 -04001250 cifsFileInfo_put(open_file);
Steve French8840dee2007-11-16 23:05:52 +00001251
Steve French9b22b0b2007-10-02 01:11:08 +00001252 if (open_file->closePend) /* list could have changed */
1253 goto refind_writable;
1254 /* else we simply continue to the next entry. Thus
1255 we do not loop on reopen errors. If we
1256 can not reopen the file, for example if we
1257 reconnected to a server with another client
1258 racing to delete or lock the file we would not
1259 make progress if we restarted before the beginning
1260 of the loop here. */
Steve French6148a742005-10-05 12:23:19 -07001261 }
1262 }
Jeff Layton2846d382008-09-22 21:33:33 -04001263 /* couldn't find useable FH with same pid, try any available */
1264 if (!any_available) {
1265 any_available = true;
1266 goto refind_writable;
1267 }
Steve French6148a742005-10-05 12:23:19 -07001268 read_unlock(&GlobalSMBSeslock);
1269 return NULL;
1270}
1271
Linus Torvalds1da177e2005-04-16 15:20:36 -07001272static int cifs_partialpagewrite(struct page *page, unsigned from, unsigned to)
1273{
1274 struct address_space *mapping = page->mapping;
1275 loff_t offset = (loff_t)page->index << PAGE_CACHE_SHIFT;
1276 char *write_data;
1277 int rc = -EFAULT;
1278 int bytes_written = 0;
1279 struct cifs_sb_info *cifs_sb;
1280 struct cifsTconInfo *pTcon;
1281 struct inode *inode;
Steve French6148a742005-10-05 12:23:19 -07001282 struct cifsFileInfo *open_file;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001283
1284 if (!mapping || !mapping->host)
1285 return -EFAULT;
1286
1287 inode = page->mapping->host;
1288 cifs_sb = CIFS_SB(inode->i_sb);
1289 pTcon = cifs_sb->tcon;
1290
1291 offset += (loff_t)from;
1292 write_data = kmap(page);
1293 write_data += from;
1294
1295 if ((to > PAGE_CACHE_SIZE) || (from > to)) {
1296 kunmap(page);
1297 return -EIO;
1298 }
1299
1300 /* racing with truncate? */
1301 if (offset > mapping->host->i_size) {
1302 kunmap(page);
1303 return 0; /* don't care */
1304 }
1305
1306 /* check to make sure that we are not extending the file */
1307 if (mapping->host->i_size - offset < (loff_t)to)
Steve Frenchfb8c4b12007-07-10 01:16:18 +00001308 to = (unsigned)(mapping->host->i_size - offset);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001309
Steve French6148a742005-10-05 12:23:19 -07001310 open_file = find_writable_file(CIFS_I(mapping->host));
1311 if (open_file) {
1312 bytes_written = cifs_write(open_file->pfile, write_data,
1313 to-from, &offset);
Dave Kleikamp6ab409b2009-08-31 11:07:12 -04001314 cifsFileInfo_put(open_file);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001315 /* Does mm or vfs already set times? */
Steve French6148a742005-10-05 12:23:19 -07001316 inode->i_atime = inode->i_mtime = current_fs_time(inode->i_sb);
Steve Frenchbb5a9a02007-12-31 04:21:29 +00001317 if ((bytes_written > 0) && (offset))
Steve French6148a742005-10-05 12:23:19 -07001318 rc = 0;
Steve Frenchbb5a9a02007-12-31 04:21:29 +00001319 else if (bytes_written < 0)
1320 rc = bytes_written;
Steve French6148a742005-10-05 12:23:19 -07001321 } else {
Joe Perchesb6b38f72010-04-21 03:50:45 +00001322 cFYI(1, "No writeable filehandles for inode");
Linus Torvalds1da177e2005-04-16 15:20:36 -07001323 rc = -EIO;
1324 }
1325
1326 kunmap(page);
1327 return rc;
1328}
1329
Linus Torvalds1da177e2005-04-16 15:20:36 -07001330static int cifs_writepages(struct address_space *mapping,
Steve French37c0eb42005-10-05 14:50:29 -07001331 struct writeback_control *wbc)
Linus Torvalds1da177e2005-04-16 15:20:36 -07001332{
Steve French37c0eb42005-10-05 14:50:29 -07001333 struct backing_dev_info *bdi = mapping->backing_dev_info;
1334 unsigned int bytes_to_write;
1335 unsigned int bytes_written;
1336 struct cifs_sb_info *cifs_sb;
1337 int done = 0;
OGAWA Hirofumi111ebb62006-06-23 02:03:26 -07001338 pgoff_t end;
Steve French37c0eb42005-10-05 14:50:29 -07001339 pgoff_t index;
Steve Frenchfb8c4b12007-07-10 01:16:18 +00001340 int range_whole = 0;
1341 struct kvec *iov;
Steve French84d2f072005-10-12 15:32:05 -07001342 int len;
Steve French37c0eb42005-10-05 14:50:29 -07001343 int n_iov = 0;
1344 pgoff_t next;
1345 int nr_pages;
1346 __u64 offset = 0;
Steve French23e7dd72005-10-20 13:44:56 -07001347 struct cifsFileInfo *open_file;
Jeff Laytonfbec9ab2009-04-03 13:44:00 -04001348 struct cifsInodeInfo *cifsi = CIFS_I(mapping->host);
Steve French37c0eb42005-10-05 14:50:29 -07001349 struct page *page;
1350 struct pagevec pvec;
1351 int rc = 0;
1352 int scanned = 0;
Jeff Laytonfbec9ab2009-04-03 13:44:00 -04001353 int xid, long_op;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001354
Steve French37c0eb42005-10-05 14:50:29 -07001355 cifs_sb = CIFS_SB(mapping->host->i_sb);
Steve French50c2f752007-07-13 00:33:32 +00001356
Steve French37c0eb42005-10-05 14:50:29 -07001357 /*
1358 * If wsize is smaller that the page cache size, default to writing
1359 * one page at a time via cifs_writepage
1360 */
1361 if (cifs_sb->wsize < PAGE_CACHE_SIZE)
1362 return generic_writepages(mapping, wbc);
1363
Steve Frenchfb8c4b12007-07-10 01:16:18 +00001364 if ((cifs_sb->tcon->ses) && (cifs_sb->tcon->ses->server))
1365 if (cifs_sb->tcon->ses->server->secMode &
1366 (SECMODE_SIGN_REQUIRED | SECMODE_SIGN_ENABLED))
1367 if (!experimEnabled)
Steve French60808232006-04-22 15:53:05 +00001368 return generic_writepages(mapping, wbc);
Steve French4a771182005-10-05 15:14:33 -07001369
Steve French9a0c8232007-02-02 04:21:57 +00001370 iov = kmalloc(32 * sizeof(struct kvec), GFP_KERNEL);
Steve Frenchfb8c4b12007-07-10 01:16:18 +00001371 if (iov == NULL)
Steve French9a0c8232007-02-02 04:21:57 +00001372 return generic_writepages(mapping, wbc);
1373
1374
Steve French37c0eb42005-10-05 14:50:29 -07001375 /*
1376 * BB: Is this meaningful for a non-block-device file system?
1377 * If it is, we should test it again after we do I/O
1378 */
1379 if (wbc->nonblocking && bdi_write_congested(bdi)) {
1380 wbc->encountered_congestion = 1;
Steve French9a0c8232007-02-02 04:21:57 +00001381 kfree(iov);
Steve French37c0eb42005-10-05 14:50:29 -07001382 return 0;
1383 }
1384
Linus Torvalds1da177e2005-04-16 15:20:36 -07001385 xid = GetXid();
1386
Steve French37c0eb42005-10-05 14:50:29 -07001387 pagevec_init(&pvec, 0);
OGAWA Hirofumi111ebb62006-06-23 02:03:26 -07001388 if (wbc->range_cyclic) {
Steve French37c0eb42005-10-05 14:50:29 -07001389 index = mapping->writeback_index; /* Start from prev offset */
OGAWA Hirofumi111ebb62006-06-23 02:03:26 -07001390 end = -1;
1391 } else {
1392 index = wbc->range_start >> PAGE_CACHE_SHIFT;
1393 end = wbc->range_end >> PAGE_CACHE_SHIFT;
1394 if (wbc->range_start == 0 && wbc->range_end == LLONG_MAX)
1395 range_whole = 1;
Steve French37c0eb42005-10-05 14:50:29 -07001396 scanned = 1;
1397 }
1398retry:
1399 while (!done && (index <= end) &&
1400 (nr_pages = pagevec_lookup_tag(&pvec, mapping, &index,
1401 PAGECACHE_TAG_DIRTY,
1402 min(end - index, (pgoff_t)PAGEVEC_SIZE - 1) + 1))) {
1403 int first;
1404 unsigned int i;
1405
Steve French37c0eb42005-10-05 14:50:29 -07001406 first = -1;
1407 next = 0;
1408 n_iov = 0;
1409 bytes_to_write = 0;
1410
1411 for (i = 0; i < nr_pages; i++) {
1412 page = pvec.pages[i];
1413 /*
1414 * At this point we hold neither mapping->tree_lock nor
1415 * lock on the page itself: the page may be truncated or
1416 * invalidated (changing page->mapping to NULL), or even
1417 * swizzled back from swapper_space to tmpfs file
1418 * mapping
1419 */
1420
1421 if (first < 0)
1422 lock_page(page);
Nick Piggin529ae9a2008-08-02 12:01:03 +02001423 else if (!trylock_page(page))
Steve French37c0eb42005-10-05 14:50:29 -07001424 break;
1425
1426 if (unlikely(page->mapping != mapping)) {
1427 unlock_page(page);
1428 break;
1429 }
1430
OGAWA Hirofumi111ebb62006-06-23 02:03:26 -07001431 if (!wbc->range_cyclic && page->index > end) {
Steve French37c0eb42005-10-05 14:50:29 -07001432 done = 1;
1433 unlock_page(page);
1434 break;
1435 }
1436
1437 if (next && (page->index != next)) {
1438 /* Not next consecutive page */
1439 unlock_page(page);
1440 break;
1441 }
1442
1443 if (wbc->sync_mode != WB_SYNC_NONE)
1444 wait_on_page_writeback(page);
1445
1446 if (PageWriteback(page) ||
Linus Torvaldscb876f42006-12-23 16:19:07 -08001447 !clear_page_dirty_for_io(page)) {
Steve French37c0eb42005-10-05 14:50:29 -07001448 unlock_page(page);
1449 break;
1450 }
Steve French84d2f072005-10-12 15:32:05 -07001451
Linus Torvaldscb876f42006-12-23 16:19:07 -08001452 /*
1453 * This actually clears the dirty bit in the radix tree.
1454 * See cifs_writepage() for more commentary.
1455 */
1456 set_page_writeback(page);
1457
Steve French84d2f072005-10-12 15:32:05 -07001458 if (page_offset(page) >= mapping->host->i_size) {
1459 done = 1;
1460 unlock_page(page);
Linus Torvaldscb876f42006-12-23 16:19:07 -08001461 end_page_writeback(page);
Steve French84d2f072005-10-12 15:32:05 -07001462 break;
1463 }
1464
Steve French37c0eb42005-10-05 14:50:29 -07001465 /*
1466 * BB can we get rid of this? pages are held by pvec
1467 */
1468 page_cache_get(page);
1469
Steve French84d2f072005-10-12 15:32:05 -07001470 len = min(mapping->host->i_size - page_offset(page),
1471 (loff_t)PAGE_CACHE_SIZE);
1472
Steve French37c0eb42005-10-05 14:50:29 -07001473 /* reserve iov[0] for the smb header */
1474 n_iov++;
1475 iov[n_iov].iov_base = kmap(page);
Steve French84d2f072005-10-12 15:32:05 -07001476 iov[n_iov].iov_len = len;
1477 bytes_to_write += len;
Steve French37c0eb42005-10-05 14:50:29 -07001478
1479 if (first < 0) {
1480 first = i;
1481 offset = page_offset(page);
1482 }
1483 next = page->index + 1;
1484 if (bytes_to_write + PAGE_CACHE_SIZE > cifs_sb->wsize)
1485 break;
1486 }
1487 if (n_iov) {
Steve French23e7dd72005-10-20 13:44:56 -07001488 /* Search for a writable handle every time we call
1489 * CIFSSMBWrite2. We can't rely on the last handle
1490 * we used to still be valid
1491 */
1492 open_file = find_writable_file(CIFS_I(mapping->host));
1493 if (!open_file) {
Joe Perchesb6b38f72010-04-21 03:50:45 +00001494 cERROR(1, "No writable handles for inode");
Steve French23e7dd72005-10-20 13:44:56 -07001495 rc = -EBADF;
Steve French1047abc2005-10-11 19:58:06 -07001496 } else {
Jeff Laytonfbec9ab2009-04-03 13:44:00 -04001497 long_op = cifs_write_timeout(cifsi, offset);
Steve French23e7dd72005-10-20 13:44:56 -07001498 rc = CIFSSMBWrite2(xid, cifs_sb->tcon,
1499 open_file->netfid,
1500 bytes_to_write, offset,
1501 &bytes_written, iov, n_iov,
Jeff Laytonfbec9ab2009-04-03 13:44:00 -04001502 long_op);
Dave Kleikamp6ab409b2009-08-31 11:07:12 -04001503 cifsFileInfo_put(open_file);
Jeff Laytonfbec9ab2009-04-03 13:44:00 -04001504 cifs_update_eof(cifsi, offset, bytes_written);
1505
Steve French23e7dd72005-10-20 13:44:56 -07001506 if (rc || bytes_written < bytes_to_write) {
Joe Perchesb6b38f72010-04-21 03:50:45 +00001507 cERROR(1, "Write2 ret %d, wrote %d",
1508 rc, bytes_written);
Steve French23e7dd72005-10-20 13:44:56 -07001509 /* BB what if continued retry is
1510 requested via mount flags? */
Jeff Laytoncea21802007-11-20 23:19:03 +00001511 if (rc == -ENOSPC)
1512 set_bit(AS_ENOSPC, &mapping->flags);
1513 else
1514 set_bit(AS_EIO, &mapping->flags);
Steve French23e7dd72005-10-20 13:44:56 -07001515 } else {
1516 cifs_stats_bytes_written(cifs_sb->tcon,
1517 bytes_written);
1518 }
Steve French37c0eb42005-10-05 14:50:29 -07001519 }
1520 for (i = 0; i < n_iov; i++) {
1521 page = pvec.pages[first + i];
Steve Frencheb9bdaa2006-01-27 15:11:47 -08001522 /* Should we also set page error on
1523 success rc but too little data written? */
1524 /* BB investigate retry logic on temporary
1525 server crash cases and how recovery works
Steve Frenchfb8c4b12007-07-10 01:16:18 +00001526 when page marked as error */
1527 if (rc)
Steve Frencheb9bdaa2006-01-27 15:11:47 -08001528 SetPageError(page);
Steve French37c0eb42005-10-05 14:50:29 -07001529 kunmap(page);
1530 unlock_page(page);
Linus Torvaldscb876f42006-12-23 16:19:07 -08001531 end_page_writeback(page);
Steve French37c0eb42005-10-05 14:50:29 -07001532 page_cache_release(page);
1533 }
1534 if ((wbc->nr_to_write -= n_iov) <= 0)
1535 done = 1;
1536 index = next;
Dave Kleikampb066a482008-11-18 03:49:05 +00001537 } else
1538 /* Need to re-find the pages we skipped */
1539 index = pvec.pages[0]->index + 1;
1540
Steve French37c0eb42005-10-05 14:50:29 -07001541 pagevec_release(&pvec);
1542 }
1543 if (!scanned && !done) {
1544 /*
1545 * We hit the last page and there is more work to be done: wrap
1546 * back to the start of the file
1547 */
1548 scanned = 1;
1549 index = 0;
1550 goto retry;
1551 }
OGAWA Hirofumi111ebb62006-06-23 02:03:26 -07001552 if (wbc->range_cyclic || (range_whole && wbc->nr_to_write > 0))
Steve French37c0eb42005-10-05 14:50:29 -07001553 mapping->writeback_index = index;
1554
Linus Torvalds1da177e2005-04-16 15:20:36 -07001555 FreeXid(xid);
Steve French9a0c8232007-02-02 04:21:57 +00001556 kfree(iov);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001557 return rc;
1558}
Linus Torvalds1da177e2005-04-16 15:20:36 -07001559
Steve Frenchfb8c4b12007-07-10 01:16:18 +00001560static int cifs_writepage(struct page *page, struct writeback_control *wbc)
Linus Torvalds1da177e2005-04-16 15:20:36 -07001561{
1562 int rc = -EFAULT;
1563 int xid;
1564
1565 xid = GetXid();
1566/* BB add check for wbc flags */
1567 page_cache_get(page);
Steve Frenchad7a2922008-02-07 23:25:02 +00001568 if (!PageUptodate(page))
Joe Perchesb6b38f72010-04-21 03:50:45 +00001569 cFYI(1, "ppw - page not up to date");
Linus Torvaldscb876f42006-12-23 16:19:07 -08001570
1571 /*
1572 * Set the "writeback" flag, and clear "dirty" in the radix tree.
1573 *
1574 * A writepage() implementation always needs to do either this,
1575 * or re-dirty the page with "redirty_page_for_writepage()" in
1576 * the case of a failure.
1577 *
1578 * Just unlocking the page will cause the radix tree tag-bits
1579 * to fail to update with the state of the page correctly.
1580 */
Steve Frenchfb8c4b12007-07-10 01:16:18 +00001581 set_page_writeback(page);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001582 rc = cifs_partialpagewrite(page, 0, PAGE_CACHE_SIZE);
1583 SetPageUptodate(page); /* BB add check for error and Clearuptodate? */
1584 unlock_page(page);
Linus Torvaldscb876f42006-12-23 16:19:07 -08001585 end_page_writeback(page);
1586 page_cache_release(page);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001587 FreeXid(xid);
1588 return rc;
1589}
1590
Nick Piggind9414772008-09-24 11:32:59 -04001591static int cifs_write_end(struct file *file, struct address_space *mapping,
1592 loff_t pos, unsigned len, unsigned copied,
1593 struct page *page, void *fsdata)
Linus Torvalds1da177e2005-04-16 15:20:36 -07001594{
Nick Piggind9414772008-09-24 11:32:59 -04001595 int rc;
1596 struct inode *inode = mapping->host;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001597
Joe Perchesb6b38f72010-04-21 03:50:45 +00001598 cFYI(1, "write_end for page %p from pos %lld with %d bytes",
1599 page, pos, copied);
Steve Frenchad7a2922008-02-07 23:25:02 +00001600
Jeff Laytona98ee8c2008-11-26 19:32:33 +00001601 if (PageChecked(page)) {
1602 if (copied == len)
1603 SetPageUptodate(page);
1604 ClearPageChecked(page);
1605 } else if (!PageUptodate(page) && copied == PAGE_CACHE_SIZE)
Nick Piggind9414772008-09-24 11:32:59 -04001606 SetPageUptodate(page);
1607
Linus Torvalds1da177e2005-04-16 15:20:36 -07001608 if (!PageUptodate(page)) {
Nick Piggind9414772008-09-24 11:32:59 -04001609 char *page_data;
1610 unsigned offset = pos & (PAGE_CACHE_SIZE - 1);
1611 int xid;
1612
1613 xid = GetXid();
Linus Torvalds1da177e2005-04-16 15:20:36 -07001614 /* this is probably better than directly calling
1615 partialpage_write since in this function the file handle is
1616 known which we might as well leverage */
1617 /* BB check if anything else missing out of ppw
1618 such as updating last write time */
1619 page_data = kmap(page);
Nick Piggind9414772008-09-24 11:32:59 -04001620 rc = cifs_write(file, page_data + offset, copied, &pos);
1621 /* if (rc < 0) should we set writebehind rc? */
Linus Torvalds1da177e2005-04-16 15:20:36 -07001622 kunmap(page);
Nick Piggind9414772008-09-24 11:32:59 -04001623
1624 FreeXid(xid);
Steve Frenchfb8c4b12007-07-10 01:16:18 +00001625 } else {
Nick Piggind9414772008-09-24 11:32:59 -04001626 rc = copied;
1627 pos += copied;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001628 set_page_dirty(page);
1629 }
1630
Nick Piggind9414772008-09-24 11:32:59 -04001631 if (rc > 0) {
1632 spin_lock(&inode->i_lock);
1633 if (pos > inode->i_size)
1634 i_size_write(inode, pos);
1635 spin_unlock(&inode->i_lock);
1636 }
1637
1638 unlock_page(page);
1639 page_cache_release(page);
1640
Linus Torvalds1da177e2005-04-16 15:20:36 -07001641 return rc;
1642}
1643
Christoph Hellwig7ea80852010-05-26 17:53:25 +02001644int cifs_fsync(struct file *file, int datasync)
Linus Torvalds1da177e2005-04-16 15:20:36 -07001645{
1646 int xid;
1647 int rc = 0;
Steve Frenchb298f222009-02-21 21:17:43 +00001648 struct cifsTconInfo *tcon;
1649 struct cifsFileInfo *smbfile =
1650 (struct cifsFileInfo *)file->private_data;
Josef "Jeff" Sipeke6a00292006-12-08 02:36:48 -08001651 struct inode *inode = file->f_path.dentry->d_inode;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001652
1653 xid = GetXid();
1654
Joe Perchesb6b38f72010-04-21 03:50:45 +00001655 cFYI(1, "Sync file - name: %s datasync: 0x%x",
Christoph Hellwig7ea80852010-05-26 17:53:25 +02001656 file->f_path.dentry->d_name.name, datasync);
Steve French50c2f752007-07-13 00:33:32 +00001657
Jeff Laytoncea21802007-11-20 23:19:03 +00001658 rc = filemap_write_and_wait(inode->i_mapping);
1659 if (rc == 0) {
1660 rc = CIFS_I(inode)->write_behind_rc;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001661 CIFS_I(inode)->write_behind_rc = 0;
Steve Frenchb298f222009-02-21 21:17:43 +00001662 tcon = CIFS_SB(inode->i_sb)->tcon;
Steve Frenchbe652442009-02-23 15:21:59 +00001663 if (!rc && tcon && smbfile &&
Steve French4717bed2009-02-24 14:44:19 +00001664 !(CIFS_SB(inode->i_sb)->mnt_cifs_flags & CIFS_MOUNT_NOSSYNC))
Steve Frenchb298f222009-02-21 21:17:43 +00001665 rc = CIFSSMBFlush(xid, tcon, smbfile->netfid);
Jeff Laytoncea21802007-11-20 23:19:03 +00001666 }
Steve Frenchb298f222009-02-21 21:17:43 +00001667
Linus Torvalds1da177e2005-04-16 15:20:36 -07001668 FreeXid(xid);
1669 return rc;
1670}
1671
NeilBrown3978d7172006-03-26 01:37:17 -08001672/* static void cifs_sync_page(struct page *page)
Linus Torvalds1da177e2005-04-16 15:20:36 -07001673{
1674 struct address_space *mapping;
1675 struct inode *inode;
1676 unsigned long index = page->index;
1677 unsigned int rpages = 0;
1678 int rc = 0;
1679
Steve Frenchf19159d2010-04-21 04:12:10 +00001680 cFYI(1, "sync page %p", page);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001681 mapping = page->mapping;
1682 if (!mapping)
1683 return 0;
1684 inode = mapping->host;
1685 if (!inode)
NeilBrown3978d7172006-03-26 01:37:17 -08001686 return; */
Linus Torvalds1da177e2005-04-16 15:20:36 -07001687
Steve Frenchfb8c4b12007-07-10 01:16:18 +00001688/* fill in rpages then
Linus Torvalds1da177e2005-04-16 15:20:36 -07001689 result = cifs_pagein_inode(inode, index, rpages); */ /* BB finish */
1690
Joe Perchesb6b38f72010-04-21 03:50:45 +00001691/* cFYI(1, "rpages is %d for sync page of Index %ld", rpages, index);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001692
NeilBrown3978d7172006-03-26 01:37:17 -08001693#if 0
Linus Torvalds1da177e2005-04-16 15:20:36 -07001694 if (rc < 0)
1695 return rc;
1696 return 0;
NeilBrown3978d7172006-03-26 01:37:17 -08001697#endif
Linus Torvalds1da177e2005-04-16 15:20:36 -07001698} */
1699
1700/*
1701 * As file closes, flush all cached write data for this inode checking
1702 * for write behind errors.
1703 */
Miklos Szeredi75e1fcc2006-06-23 02:05:12 -07001704int cifs_flush(struct file *file, fl_owner_t id)
Linus Torvalds1da177e2005-04-16 15:20:36 -07001705{
Steve Frenchfb8c4b12007-07-10 01:16:18 +00001706 struct inode *inode = file->f_path.dentry->d_inode;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001707 int rc = 0;
1708
1709 /* Rather than do the steps manually:
1710 lock the inode for writing
1711 loop through pages looking for write behind data (dirty pages)
1712 coalesce into contiguous 16K (or smaller) chunks to write to server
1713 send to server (prefer in parallel)
1714 deal with writebehind errors
1715 unlock inode for writing
1716 filemapfdatawrite appears easier for the time being */
1717
1718 rc = filemap_fdatawrite(inode->i_mapping);
Jeff Laytoncea21802007-11-20 23:19:03 +00001719 /* reset wb rc if we were able to write out dirty pages */
1720 if (!rc) {
1721 rc = CIFS_I(inode)->write_behind_rc;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001722 CIFS_I(inode)->write_behind_rc = 0;
Jeff Laytoncea21802007-11-20 23:19:03 +00001723 }
Steve French50c2f752007-07-13 00:33:32 +00001724
Joe Perchesb6b38f72010-04-21 03:50:45 +00001725 cFYI(1, "Flush inode %p file %p rc %d", inode, file, rc);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001726
1727 return rc;
1728}
1729
1730ssize_t cifs_user_read(struct file *file, char __user *read_data,
1731 size_t read_size, loff_t *poffset)
1732{
1733 int rc = -EACCES;
1734 unsigned int bytes_read = 0;
1735 unsigned int total_read = 0;
1736 unsigned int current_read_size;
1737 struct cifs_sb_info *cifs_sb;
1738 struct cifsTconInfo *pTcon;
1739 int xid;
1740 struct cifsFileInfo *open_file;
1741 char *smb_read_data;
1742 char __user *current_offset;
1743 struct smb_com_read_rsp *pSMBr;
1744
1745 xid = GetXid();
Josef "Jeff" Sipeke6a00292006-12-08 02:36:48 -08001746 cifs_sb = CIFS_SB(file->f_path.dentry->d_sb);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001747 pTcon = cifs_sb->tcon;
1748
1749 if (file->private_data == NULL) {
Suresh Jayaraman0f3bc092009-06-25 18:12:34 +05301750 rc = -EBADF;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001751 FreeXid(xid);
Suresh Jayaraman0f3bc092009-06-25 18:12:34 +05301752 return rc;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001753 }
1754 open_file = (struct cifsFileInfo *)file->private_data;
1755
Steve Frenchad7a2922008-02-07 23:25:02 +00001756 if ((file->f_flags & O_ACCMODE) == O_WRONLY)
Joe Perchesb6b38f72010-04-21 03:50:45 +00001757 cFYI(1, "attempting read on write only file instance");
Steve Frenchad7a2922008-02-07 23:25:02 +00001758
Linus Torvalds1da177e2005-04-16 15:20:36 -07001759 for (total_read = 0, current_offset = read_data;
1760 read_size > total_read;
1761 total_read += bytes_read, current_offset += bytes_read) {
Steve Frenchfb8c4b12007-07-10 01:16:18 +00001762 current_read_size = min_t(const int, read_size - total_read,
Linus Torvalds1da177e2005-04-16 15:20:36 -07001763 cifs_sb->rsize);
1764 rc = -EAGAIN;
1765 smb_read_data = NULL;
1766 while (rc == -EAGAIN) {
Steve Frenchec637e32005-12-12 20:53:18 -08001767 int buf_type = CIFS_NO_BUFFER;
Steve Frenchfb8c4b12007-07-10 01:16:18 +00001768 if ((open_file->invalidHandle) &&
Linus Torvalds1da177e2005-04-16 15:20:36 -07001769 (!open_file->closePend)) {
Steve French4b18f2a2008-04-29 00:06:05 +00001770 rc = cifs_reopen_file(file, true);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001771 if (rc != 0)
1772 break;
1773 }
Steve Frenchbfa0d752005-08-31 21:50:37 -07001774 rc = CIFSSMBRead(xid, pTcon,
Steve Frenchec637e32005-12-12 20:53:18 -08001775 open_file->netfid,
1776 current_read_size, *poffset,
1777 &bytes_read, &smb_read_data,
1778 &buf_type);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001779 pSMBr = (struct smb_com_read_rsp *)smb_read_data;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001780 if (smb_read_data) {
Steve French93544cc2006-02-14 22:30:52 -06001781 if (copy_to_user(current_offset,
1782 smb_read_data +
1783 4 /* RFC1001 length field */ +
1784 le16_to_cpu(pSMBr->DataOffset),
Steve Frenchad7a2922008-02-07 23:25:02 +00001785 bytes_read))
Steve French93544cc2006-02-14 22:30:52 -06001786 rc = -EFAULT;
Steve French93544cc2006-02-14 22:30:52 -06001787
Steve Frenchfb8c4b12007-07-10 01:16:18 +00001788 if (buf_type == CIFS_SMALL_BUFFER)
Steve Frenchec637e32005-12-12 20:53:18 -08001789 cifs_small_buf_release(smb_read_data);
Steve Frenchfb8c4b12007-07-10 01:16:18 +00001790 else if (buf_type == CIFS_LARGE_BUFFER)
Steve Frenchec637e32005-12-12 20:53:18 -08001791 cifs_buf_release(smb_read_data);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001792 smb_read_data = NULL;
1793 }
1794 }
1795 if (rc || (bytes_read == 0)) {
1796 if (total_read) {
1797 break;
1798 } else {
1799 FreeXid(xid);
1800 return rc;
1801 }
1802 } else {
Steve Frencha4544342005-08-24 13:59:35 -07001803 cifs_stats_bytes_read(pTcon, bytes_read);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001804 *poffset += bytes_read;
1805 }
1806 }
1807 FreeXid(xid);
1808 return total_read;
1809}
1810
1811
1812static ssize_t cifs_read(struct file *file, char *read_data, size_t read_size,
1813 loff_t *poffset)
1814{
1815 int rc = -EACCES;
1816 unsigned int bytes_read = 0;
1817 unsigned int total_read;
1818 unsigned int current_read_size;
1819 struct cifs_sb_info *cifs_sb;
1820 struct cifsTconInfo *pTcon;
1821 int xid;
1822 char *current_offset;
1823 struct cifsFileInfo *open_file;
Steve Frenchec637e32005-12-12 20:53:18 -08001824 int buf_type = CIFS_NO_BUFFER;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001825
1826 xid = GetXid();
Josef "Jeff" Sipeke6a00292006-12-08 02:36:48 -08001827 cifs_sb = CIFS_SB(file->f_path.dentry->d_sb);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001828 pTcon = cifs_sb->tcon;
1829
1830 if (file->private_data == NULL) {
Suresh Jayaraman0f3bc092009-06-25 18:12:34 +05301831 rc = -EBADF;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001832 FreeXid(xid);
Suresh Jayaraman0f3bc092009-06-25 18:12:34 +05301833 return rc;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001834 }
1835 open_file = (struct cifsFileInfo *)file->private_data;
1836
1837 if ((file->f_flags & O_ACCMODE) == O_WRONLY)
Joe Perchesb6b38f72010-04-21 03:50:45 +00001838 cFYI(1, "attempting read on write only file instance");
Linus Torvalds1da177e2005-04-16 15:20:36 -07001839
Steve Frenchfb8c4b12007-07-10 01:16:18 +00001840 for (total_read = 0, current_offset = read_data;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001841 read_size > total_read;
1842 total_read += bytes_read, current_offset += bytes_read) {
1843 current_read_size = min_t(const int, read_size - total_read,
1844 cifs_sb->rsize);
Steve Frenchf9f5c8172005-09-15 23:06:38 -07001845 /* For windows me and 9x we do not want to request more
1846 than it negotiated since it will refuse the read then */
Steve Frenchfb8c4b12007-07-10 01:16:18 +00001847 if ((pTcon->ses) &&
Steve Frenchf9f5c8172005-09-15 23:06:38 -07001848 !(pTcon->ses->capabilities & CAP_LARGE_FILES)) {
1849 current_read_size = min_t(const int, current_read_size,
1850 pTcon->ses->server->maxBuf - 128);
1851 }
Linus Torvalds1da177e2005-04-16 15:20:36 -07001852 rc = -EAGAIN;
1853 while (rc == -EAGAIN) {
Steve Frenchfb8c4b12007-07-10 01:16:18 +00001854 if ((open_file->invalidHandle) &&
Linus Torvalds1da177e2005-04-16 15:20:36 -07001855 (!open_file->closePend)) {
Steve French4b18f2a2008-04-29 00:06:05 +00001856 rc = cifs_reopen_file(file, true);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001857 if (rc != 0)
1858 break;
1859 }
Steve Frenchbfa0d752005-08-31 21:50:37 -07001860 rc = CIFSSMBRead(xid, pTcon,
Steve Frenchec637e32005-12-12 20:53:18 -08001861 open_file->netfid,
1862 current_read_size, *poffset,
1863 &bytes_read, &current_offset,
1864 &buf_type);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001865 }
1866 if (rc || (bytes_read == 0)) {
1867 if (total_read) {
1868 break;
1869 } else {
1870 FreeXid(xid);
1871 return rc;
1872 }
1873 } else {
Steve Frencha4544342005-08-24 13:59:35 -07001874 cifs_stats_bytes_read(pTcon, total_read);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001875 *poffset += bytes_read;
1876 }
1877 }
1878 FreeXid(xid);
1879 return total_read;
1880}
1881
1882int cifs_file_mmap(struct file *file, struct vm_area_struct *vma)
1883{
Linus Torvalds1da177e2005-04-16 15:20:36 -07001884 int rc, xid;
1885
1886 xid = GetXid();
Jeff Laytonabab0952010-02-12 07:44:18 -05001887 rc = cifs_revalidate_file(file);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001888 if (rc) {
Joe Perchesb6b38f72010-04-21 03:50:45 +00001889 cFYI(1, "Validation prior to mmap failed, error=%d", rc);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001890 FreeXid(xid);
1891 return rc;
1892 }
1893 rc = generic_file_mmap(file, vma);
1894 FreeXid(xid);
1895 return rc;
1896}
1897
1898
Steve Frenchfb8c4b12007-07-10 01:16:18 +00001899static void cifs_copy_cache_pages(struct address_space *mapping,
Nick Piggin315e9952010-04-21 03:18:28 +00001900 struct list_head *pages, int bytes_read, char *data)
Linus Torvalds1da177e2005-04-16 15:20:36 -07001901{
1902 struct page *page;
1903 char *target;
1904
1905 while (bytes_read > 0) {
1906 if (list_empty(pages))
1907 break;
1908
1909 page = list_entry(pages->prev, struct page, lru);
1910 list_del(&page->lru);
1911
Nick Piggin315e9952010-04-21 03:18:28 +00001912 if (add_to_page_cache_lru(page, mapping, page->index,
Linus Torvalds1da177e2005-04-16 15:20:36 -07001913 GFP_KERNEL)) {
1914 page_cache_release(page);
Joe Perchesb6b38f72010-04-21 03:50:45 +00001915 cFYI(1, "Add page cache failed");
Steve French3079ca62005-06-09 14:44:07 -07001916 data += PAGE_CACHE_SIZE;
1917 bytes_read -= PAGE_CACHE_SIZE;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001918 continue;
1919 }
Jeff Layton06b43672010-06-01 10:54:45 -04001920 page_cache_release(page);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001921
Steve Frenchfb8c4b12007-07-10 01:16:18 +00001922 target = kmap_atomic(page, KM_USER0);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001923
1924 if (PAGE_CACHE_SIZE > bytes_read) {
1925 memcpy(target, data, bytes_read);
1926 /* zero the tail end of this partial page */
Steve Frenchfb8c4b12007-07-10 01:16:18 +00001927 memset(target + bytes_read, 0,
Linus Torvalds1da177e2005-04-16 15:20:36 -07001928 PAGE_CACHE_SIZE - bytes_read);
1929 bytes_read = 0;
1930 } else {
1931 memcpy(target, data, PAGE_CACHE_SIZE);
1932 bytes_read -= PAGE_CACHE_SIZE;
1933 }
1934 kunmap_atomic(target, KM_USER0);
1935
1936 flush_dcache_page(page);
1937 SetPageUptodate(page);
1938 unlock_page(page);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001939 data += PAGE_CACHE_SIZE;
1940 }
1941 return;
1942}
1943
1944static int cifs_readpages(struct file *file, struct address_space *mapping,
1945 struct list_head *page_list, unsigned num_pages)
1946{
1947 int rc = -EACCES;
1948 int xid;
1949 loff_t offset;
1950 struct page *page;
1951 struct cifs_sb_info *cifs_sb;
1952 struct cifsTconInfo *pTcon;
Steve French2c2130e2007-10-12 19:10:28 +00001953 unsigned int bytes_read = 0;
Steve Frenchfb8c4b12007-07-10 01:16:18 +00001954 unsigned int read_size, i;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001955 char *smb_read_data = NULL;
1956 struct smb_com_read_rsp *pSMBr;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001957 struct cifsFileInfo *open_file;
Steve Frenchec637e32005-12-12 20:53:18 -08001958 int buf_type = CIFS_NO_BUFFER;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001959
1960 xid = GetXid();
1961 if (file->private_data == NULL) {
Suresh Jayaraman0f3bc092009-06-25 18:12:34 +05301962 rc = -EBADF;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001963 FreeXid(xid);
Suresh Jayaraman0f3bc092009-06-25 18:12:34 +05301964 return rc;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001965 }
1966 open_file = (struct cifsFileInfo *)file->private_data;
Josef "Jeff" Sipeke6a00292006-12-08 02:36:48 -08001967 cifs_sb = CIFS_SB(file->f_path.dentry->d_sb);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001968 pTcon = cifs_sb->tcon;
Steve Frenchbfa0d752005-08-31 21:50:37 -07001969
Steve Frenchf19159d2010-04-21 04:12:10 +00001970 cFYI(DBG2, "rpages: num pages %d", num_pages);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001971 for (i = 0; i < num_pages; ) {
1972 unsigned contig_pages;
1973 struct page *tmp_page;
1974 unsigned long expected_index;
1975
1976 if (list_empty(page_list))
1977 break;
1978
1979 page = list_entry(page_list->prev, struct page, lru);
1980 offset = (loff_t)page->index << PAGE_CACHE_SHIFT;
1981
1982 /* count adjacent pages that we will read into */
1983 contig_pages = 0;
Steve Frenchfb8c4b12007-07-10 01:16:18 +00001984 expected_index =
Linus Torvalds1da177e2005-04-16 15:20:36 -07001985 list_entry(page_list->prev, struct page, lru)->index;
Steve Frenchfb8c4b12007-07-10 01:16:18 +00001986 list_for_each_entry_reverse(tmp_page, page_list, lru) {
Linus Torvalds1da177e2005-04-16 15:20:36 -07001987 if (tmp_page->index == expected_index) {
1988 contig_pages++;
1989 expected_index++;
1990 } else
Steve Frenchfb8c4b12007-07-10 01:16:18 +00001991 break;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001992 }
1993 if (contig_pages + i > num_pages)
1994 contig_pages = num_pages - i;
1995
1996 /* for reads over a certain size could initiate async
1997 read ahead */
1998
1999 read_size = contig_pages * PAGE_CACHE_SIZE;
2000 /* Read size needs to be in multiples of one page */
2001 read_size = min_t(const unsigned int, read_size,
2002 cifs_sb->rsize & PAGE_CACHE_MASK);
Joe Perchesb6b38f72010-04-21 03:50:45 +00002003 cFYI(DBG2, "rpages: read size 0x%x contiguous pages %d",
2004 read_size, contig_pages);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002005 rc = -EAGAIN;
2006 while (rc == -EAGAIN) {
Steve Frenchfb8c4b12007-07-10 01:16:18 +00002007 if ((open_file->invalidHandle) &&
Linus Torvalds1da177e2005-04-16 15:20:36 -07002008 (!open_file->closePend)) {
Steve French4b18f2a2008-04-29 00:06:05 +00002009 rc = cifs_reopen_file(file, true);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002010 if (rc != 0)
2011 break;
2012 }
2013
Steve Frenchbfa0d752005-08-31 21:50:37 -07002014 rc = CIFSSMBRead(xid, pTcon,
Steve Frenchec637e32005-12-12 20:53:18 -08002015 open_file->netfid,
2016 read_size, offset,
2017 &bytes_read, &smb_read_data,
2018 &buf_type);
Steve Frencha9d02ad2005-08-24 23:06:05 -07002019 /* BB more RC checks ? */
Steve Frenchfb8c4b12007-07-10 01:16:18 +00002020 if (rc == -EAGAIN) {
Linus Torvalds1da177e2005-04-16 15:20:36 -07002021 if (smb_read_data) {
Steve Frenchfb8c4b12007-07-10 01:16:18 +00002022 if (buf_type == CIFS_SMALL_BUFFER)
Steve Frenchec637e32005-12-12 20:53:18 -08002023 cifs_small_buf_release(smb_read_data);
Steve Frenchfb8c4b12007-07-10 01:16:18 +00002024 else if (buf_type == CIFS_LARGE_BUFFER)
Steve Frenchec637e32005-12-12 20:53:18 -08002025 cifs_buf_release(smb_read_data);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002026 smb_read_data = NULL;
2027 }
2028 }
2029 }
2030 if ((rc < 0) || (smb_read_data == NULL)) {
Joe Perchesb6b38f72010-04-21 03:50:45 +00002031 cFYI(1, "Read error in readpages: %d", rc);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002032 break;
2033 } else if (bytes_read > 0) {
Andrew Morton6f88cc22006-12-10 02:19:44 -08002034 task_io_account_read(bytes_read);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002035 pSMBr = (struct smb_com_read_rsp *)smb_read_data;
2036 cifs_copy_cache_pages(mapping, page_list, bytes_read,
2037 smb_read_data + 4 /* RFC1001 hdr */ +
Nick Piggin315e9952010-04-21 03:18:28 +00002038 le16_to_cpu(pSMBr->DataOffset));
Linus Torvalds1da177e2005-04-16 15:20:36 -07002039
2040 i += bytes_read >> PAGE_CACHE_SHIFT;
Steve Frencha4544342005-08-24 13:59:35 -07002041 cifs_stats_bytes_read(pTcon, bytes_read);
Steve French2c2130e2007-10-12 19:10:28 +00002042 if ((bytes_read & PAGE_CACHE_MASK) != bytes_read) {
Linus Torvalds1da177e2005-04-16 15:20:36 -07002043 i++; /* account for partial page */
2044
Steve Frenchfb8c4b12007-07-10 01:16:18 +00002045 /* server copy of file can have smaller size
Linus Torvalds1da177e2005-04-16 15:20:36 -07002046 than client */
Steve Frenchfb8c4b12007-07-10 01:16:18 +00002047 /* BB do we need to verify this common case ?
2048 this case is ok - if we are at server EOF
Linus Torvalds1da177e2005-04-16 15:20:36 -07002049 we will hit it on next read */
2050
OGAWA Hirofumi05ac9d42006-11-02 22:07:08 -08002051 /* break; */
Linus Torvalds1da177e2005-04-16 15:20:36 -07002052 }
2053 } else {
Joe Perchesb6b38f72010-04-21 03:50:45 +00002054 cFYI(1, "No bytes read (%d) at offset %lld . "
Steve Frenchf19159d2010-04-21 04:12:10 +00002055 "Cleaning remaining pages from readahead list",
Joe Perchesb6b38f72010-04-21 03:50:45 +00002056 bytes_read, offset);
Steve Frenchfb8c4b12007-07-10 01:16:18 +00002057 /* BB turn off caching and do new lookup on
Linus Torvalds1da177e2005-04-16 15:20:36 -07002058 file size at server? */
Linus Torvalds1da177e2005-04-16 15:20:36 -07002059 break;
2060 }
2061 if (smb_read_data) {
Steve Frenchfb8c4b12007-07-10 01:16:18 +00002062 if (buf_type == CIFS_SMALL_BUFFER)
Steve Frenchec637e32005-12-12 20:53:18 -08002063 cifs_small_buf_release(smb_read_data);
Steve Frenchfb8c4b12007-07-10 01:16:18 +00002064 else if (buf_type == CIFS_LARGE_BUFFER)
Steve Frenchec637e32005-12-12 20:53:18 -08002065 cifs_buf_release(smb_read_data);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002066 smb_read_data = NULL;
2067 }
2068 bytes_read = 0;
2069 }
2070
Linus Torvalds1da177e2005-04-16 15:20:36 -07002071/* need to free smb_read_data buf before exit */
2072 if (smb_read_data) {
Steve Frenchfb8c4b12007-07-10 01:16:18 +00002073 if (buf_type == CIFS_SMALL_BUFFER)
Steve French47c886b2006-01-18 14:20:39 -08002074 cifs_small_buf_release(smb_read_data);
Steve Frenchfb8c4b12007-07-10 01:16:18 +00002075 else if (buf_type == CIFS_LARGE_BUFFER)
Steve French47c886b2006-01-18 14:20:39 -08002076 cifs_buf_release(smb_read_data);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002077 smb_read_data = NULL;
Steve Frenchfb8c4b12007-07-10 01:16:18 +00002078 }
Linus Torvalds1da177e2005-04-16 15:20:36 -07002079
2080 FreeXid(xid);
2081 return rc;
2082}
2083
2084static int cifs_readpage_worker(struct file *file, struct page *page,
2085 loff_t *poffset)
2086{
2087 char *read_data;
2088 int rc;
2089
2090 page_cache_get(page);
2091 read_data = kmap(page);
2092 /* for reads over a certain size could initiate async read ahead */
Steve Frenchfb8c4b12007-07-10 01:16:18 +00002093
Linus Torvalds1da177e2005-04-16 15:20:36 -07002094 rc = cifs_read(file, read_data, PAGE_CACHE_SIZE, poffset);
Steve Frenchfb8c4b12007-07-10 01:16:18 +00002095
Linus Torvalds1da177e2005-04-16 15:20:36 -07002096 if (rc < 0)
2097 goto io_error;
2098 else
Joe Perchesb6b38f72010-04-21 03:50:45 +00002099 cFYI(1, "Bytes read %d", rc);
Steve Frenchfb8c4b12007-07-10 01:16:18 +00002100
Josef "Jeff" Sipeke6a00292006-12-08 02:36:48 -08002101 file->f_path.dentry->d_inode->i_atime =
2102 current_fs_time(file->f_path.dentry->d_inode->i_sb);
Steve Frenchfb8c4b12007-07-10 01:16:18 +00002103
Linus Torvalds1da177e2005-04-16 15:20:36 -07002104 if (PAGE_CACHE_SIZE > rc)
2105 memset(read_data + rc, 0, PAGE_CACHE_SIZE - rc);
2106
2107 flush_dcache_page(page);
2108 SetPageUptodate(page);
2109 rc = 0;
Steve Frenchfb8c4b12007-07-10 01:16:18 +00002110
Linus Torvalds1da177e2005-04-16 15:20:36 -07002111io_error:
Steve Frenchfb8c4b12007-07-10 01:16:18 +00002112 kunmap(page);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002113 page_cache_release(page);
2114 return rc;
2115}
2116
2117static int cifs_readpage(struct file *file, struct page *page)
2118{
2119 loff_t offset = (loff_t)page->index << PAGE_CACHE_SHIFT;
2120 int rc = -EACCES;
2121 int xid;
2122
2123 xid = GetXid();
2124
2125 if (file->private_data == NULL) {
Suresh Jayaraman0f3bc092009-06-25 18:12:34 +05302126 rc = -EBADF;
Linus Torvalds1da177e2005-04-16 15:20:36 -07002127 FreeXid(xid);
Suresh Jayaraman0f3bc092009-06-25 18:12:34 +05302128 return rc;
Linus Torvalds1da177e2005-04-16 15:20:36 -07002129 }
2130
Joe Perchesb6b38f72010-04-21 03:50:45 +00002131 cFYI(1, "readpage %p at offset %d 0x%x\n",
2132 page, (int)offset, (int)offset);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002133
2134 rc = cifs_readpage_worker(file, page, &offset);
2135
2136 unlock_page(page);
2137
2138 FreeXid(xid);
2139 return rc;
2140}
2141
Steve Frencha403a0a2007-07-26 15:54:16 +00002142static int is_inode_writable(struct cifsInodeInfo *cifs_inode)
2143{
2144 struct cifsFileInfo *open_file;
2145
2146 read_lock(&GlobalSMBSeslock);
2147 list_for_each_entry(open_file, &cifs_inode->openFileList, flist) {
2148 if (open_file->closePend)
2149 continue;
2150 if (open_file->pfile &&
2151 ((open_file->pfile->f_flags & O_RDWR) ||
2152 (open_file->pfile->f_flags & O_WRONLY))) {
2153 read_unlock(&GlobalSMBSeslock);
2154 return 1;
2155 }
2156 }
2157 read_unlock(&GlobalSMBSeslock);
2158 return 0;
2159}
2160
Linus Torvalds1da177e2005-04-16 15:20:36 -07002161/* We do not want to update the file size from server for inodes
2162 open for write - to avoid races with writepage extending
2163 the file - in the future we could consider allowing
Steve Frenchfb8c4b12007-07-10 01:16:18 +00002164 refreshing the inode only on increases in the file size
Linus Torvalds1da177e2005-04-16 15:20:36 -07002165 but this is tricky to do without racing with writebehind
2166 page caching in the current Linux kernel design */
Steve French4b18f2a2008-04-29 00:06:05 +00002167bool is_size_safe_to_change(struct cifsInodeInfo *cifsInode, __u64 end_of_file)
Linus Torvalds1da177e2005-04-16 15:20:36 -07002168{
Steve Frencha403a0a2007-07-26 15:54:16 +00002169 if (!cifsInode)
Steve French4b18f2a2008-04-29 00:06:05 +00002170 return true;
Steve French23e7dd72005-10-20 13:44:56 -07002171
Steve Frencha403a0a2007-07-26 15:54:16 +00002172 if (is_inode_writable(cifsInode)) {
2173 /* This inode is open for write at least once */
Steve Frenchc32a0b62006-01-12 14:41:28 -08002174 struct cifs_sb_info *cifs_sb;
2175
Steve Frenchc32a0b62006-01-12 14:41:28 -08002176 cifs_sb = CIFS_SB(cifsInode->vfs_inode.i_sb);
Steve Frenchad7a2922008-02-07 23:25:02 +00002177 if (cifs_sb->mnt_cifs_flags & CIFS_MOUNT_DIRECT_IO) {
Steve Frenchfb8c4b12007-07-10 01:16:18 +00002178 /* since no page cache to corrupt on directio
Steve Frenchc32a0b62006-01-12 14:41:28 -08002179 we can change size safely */
Steve French4b18f2a2008-04-29 00:06:05 +00002180 return true;
Steve Frenchc32a0b62006-01-12 14:41:28 -08002181 }
2182
Steve Frenchfb8c4b12007-07-10 01:16:18 +00002183 if (i_size_read(&cifsInode->vfs_inode) < end_of_file)
Steve French4b18f2a2008-04-29 00:06:05 +00002184 return true;
Steve French7ba52632007-02-08 18:14:13 +00002185
Steve French4b18f2a2008-04-29 00:06:05 +00002186 return false;
Steve French23e7dd72005-10-20 13:44:56 -07002187 } else
Steve French4b18f2a2008-04-29 00:06:05 +00002188 return true;
Linus Torvalds1da177e2005-04-16 15:20:36 -07002189}
2190
Nick Piggind9414772008-09-24 11:32:59 -04002191static int cifs_write_begin(struct file *file, struct address_space *mapping,
2192 loff_t pos, unsigned len, unsigned flags,
2193 struct page **pagep, void **fsdata)
Linus Torvalds1da177e2005-04-16 15:20:36 -07002194{
Nick Piggind9414772008-09-24 11:32:59 -04002195 pgoff_t index = pos >> PAGE_CACHE_SHIFT;
2196 loff_t offset = pos & (PAGE_CACHE_SIZE - 1);
Jeff Laytona98ee8c2008-11-26 19:32:33 +00002197 loff_t page_start = pos & PAGE_MASK;
2198 loff_t i_size;
2199 struct page *page;
2200 int rc = 0;
Linus Torvalds1da177e2005-04-16 15:20:36 -07002201
Joe Perchesb6b38f72010-04-21 03:50:45 +00002202 cFYI(1, "write_begin from %lld len %d", (long long)pos, len);
Nick Piggind9414772008-09-24 11:32:59 -04002203
Nick Piggin54566b22009-01-04 12:00:53 -08002204 page = grab_cache_page_write_begin(mapping, index, flags);
Jeff Laytona98ee8c2008-11-26 19:32:33 +00002205 if (!page) {
2206 rc = -ENOMEM;
2207 goto out;
2208 }
Nick Piggind9414772008-09-24 11:32:59 -04002209
Jeff Laytona98ee8c2008-11-26 19:32:33 +00002210 if (PageUptodate(page))
2211 goto out;
Steve French8a236262007-03-06 00:31:00 +00002212
Jeff Laytona98ee8c2008-11-26 19:32:33 +00002213 /*
2214 * If we write a full page it will be up to date, no need to read from
2215 * the server. If the write is short, we'll end up doing a sync write
2216 * instead.
2217 */
2218 if (len == PAGE_CACHE_SIZE)
2219 goto out;
2220
2221 /*
2222 * optimize away the read when we have an oplock, and we're not
2223 * expecting to use any of the data we'd be reading in. That
2224 * is, when the page lies beyond the EOF, or straddles the EOF
2225 * and the write will cover all of the existing data.
2226 */
2227 if (CIFS_I(mapping->host)->clientCanCacheRead) {
2228 i_size = i_size_read(mapping->host);
2229 if (page_start >= i_size ||
2230 (offset == 0 && (pos + len) >= i_size)) {
2231 zero_user_segments(page, 0, offset,
2232 offset + len,
2233 PAGE_CACHE_SIZE);
2234 /*
2235 * PageChecked means that the parts of the page
2236 * to which we're not writing are considered up
2237 * to date. Once the data is copied to the
2238 * page, it can be set uptodate.
2239 */
2240 SetPageChecked(page);
2241 goto out;
2242 }
2243 }
Linus Torvalds1da177e2005-04-16 15:20:36 -07002244
Nick Piggind9414772008-09-24 11:32:59 -04002245 if ((file->f_flags & O_ACCMODE) != O_WRONLY) {
Jeff Laytona98ee8c2008-11-26 19:32:33 +00002246 /*
2247 * might as well read a page, it is fast enough. If we get
2248 * an error, we don't need to return it. cifs_write_end will
2249 * do a sync write instead since PG_uptodate isn't set.
2250 */
2251 cifs_readpage_worker(file, page, &page_start);
Steve French8a236262007-03-06 00:31:00 +00002252 } else {
2253 /* we could try using another file handle if there is one -
2254 but how would we lock it to prevent close of that handle
2255 racing with this read? In any case
Nick Piggind9414772008-09-24 11:32:59 -04002256 this will be written out by write_end so is fine */
Steve French8a236262007-03-06 00:31:00 +00002257 }
Jeff Laytona98ee8c2008-11-26 19:32:33 +00002258out:
2259 *pagep = page;
2260 return rc;
Linus Torvalds1da177e2005-04-16 15:20:36 -07002261}
2262
Jeff Layton3bc303c2009-09-21 06:47:50 -04002263static void
2264cifs_oplock_break(struct slow_work *work)
2265{
2266 struct cifsFileInfo *cfile = container_of(work, struct cifsFileInfo,
2267 oplock_break);
2268 struct inode *inode = cfile->pInode;
2269 struct cifsInodeInfo *cinode = CIFS_I(inode);
2270 struct cifs_sb_info *cifs_sb = CIFS_SB(cfile->mnt->mnt_sb);
2271 int rc, waitrc = 0;
2272
2273 if (inode && S_ISREG(inode->i_mode)) {
Steve Frenchd54ff732010-04-27 04:38:15 +00002274 if (cinode->clientCanCacheRead)
Al Viro8737c932009-12-24 06:47:55 -05002275 break_lease(inode, O_RDONLY);
Steve Frenchd54ff732010-04-27 04:38:15 +00002276 else
Al Viro8737c932009-12-24 06:47:55 -05002277 break_lease(inode, O_WRONLY);
Jeff Layton3bc303c2009-09-21 06:47:50 -04002278 rc = filemap_fdatawrite(inode->i_mapping);
2279 if (cinode->clientCanCacheRead == 0) {
2280 waitrc = filemap_fdatawait(inode->i_mapping);
2281 invalidate_remote_inode(inode);
2282 }
2283 if (!rc)
2284 rc = waitrc;
2285 if (rc)
2286 cinode->write_behind_rc = rc;
Joe Perchesb6b38f72010-04-21 03:50:45 +00002287 cFYI(1, "Oplock flush inode %p rc %d", inode, rc);
Jeff Layton3bc303c2009-09-21 06:47:50 -04002288 }
2289
2290 /*
2291 * releasing stale oplock after recent reconnect of smb session using
2292 * a now incorrect file handle is not a data integrity issue but do
2293 * not bother sending an oplock release if session to server still is
2294 * disconnected since oplock already released by the server
2295 */
2296 if (!cfile->closePend && !cfile->oplock_break_cancelled) {
2297 rc = CIFSSMBLock(0, cifs_sb->tcon, cfile->netfid, 0, 0, 0, 0,
2298 LOCKING_ANDX_OPLOCK_RELEASE, false);
Joe Perchesb6b38f72010-04-21 03:50:45 +00002299 cFYI(1, "Oplock release rc = %d", rc);
Jeff Layton3bc303c2009-09-21 06:47:50 -04002300 }
2301}
2302
2303static int
2304cifs_oplock_break_get(struct slow_work *work)
2305{
2306 struct cifsFileInfo *cfile = container_of(work, struct cifsFileInfo,
2307 oplock_break);
2308 mntget(cfile->mnt);
2309 cifsFileInfo_get(cfile);
2310 return 0;
2311}
2312
2313static void
2314cifs_oplock_break_put(struct slow_work *work)
2315{
2316 struct cifsFileInfo *cfile = container_of(work, struct cifsFileInfo,
2317 oplock_break);
2318 mntput(cfile->mnt);
2319 cifsFileInfo_put(cfile);
2320}
2321
2322const struct slow_work_ops cifs_oplock_break_ops = {
2323 .get_ref = cifs_oplock_break_get,
2324 .put_ref = cifs_oplock_break_put,
2325 .execute = cifs_oplock_break,
2326};
2327
Christoph Hellwigf5e54d62006-06-28 04:26:44 -07002328const struct address_space_operations cifs_addr_ops = {
Linus Torvalds1da177e2005-04-16 15:20:36 -07002329 .readpage = cifs_readpage,
2330 .readpages = cifs_readpages,
2331 .writepage = cifs_writepage,
Steve French37c0eb42005-10-05 14:50:29 -07002332 .writepages = cifs_writepages,
Nick Piggind9414772008-09-24 11:32:59 -04002333 .write_begin = cifs_write_begin,
2334 .write_end = cifs_write_end,
Linus Torvalds1da177e2005-04-16 15:20:36 -07002335 .set_page_dirty = __set_page_dirty_nobuffers,
2336 /* .sync_page = cifs_sync_page, */
2337 /* .direct_IO = */
2338};
Dave Kleikamp273d81d2006-06-01 19:41:23 +00002339
2340/*
2341 * cifs_readpages requires the server to support a buffer large enough to
2342 * contain the header plus one complete page of data. Otherwise, we need
2343 * to leave cifs_readpages out of the address space operations.
2344 */
Christoph Hellwigf5e54d62006-06-28 04:26:44 -07002345const struct address_space_operations cifs_addr_ops_smallbuf = {
Dave Kleikamp273d81d2006-06-01 19:41:23 +00002346 .readpage = cifs_readpage,
2347 .writepage = cifs_writepage,
2348 .writepages = cifs_writepages,
Nick Piggind9414772008-09-24 11:32:59 -04002349 .write_begin = cifs_write_begin,
2350 .write_end = cifs_write_end,
Dave Kleikamp273d81d2006-06-01 19:41:23 +00002351 .set_page_dirty = __set_page_dirty_nobuffers,
2352 /* .sync_page = cifs_sync_page, */
2353 /* .direct_IO = */
2354};