blob: fa7beac8b80e6df1a3e25d936f3048a0b14cc584 [file] [log] [blame]
Linus Torvalds1da177e2005-04-16 15:20:36 -07001/*
2 * fs/cifs/file.c
3 *
4 * vfs operations that deal with files
Steve Frenchfb8c4b12007-07-10 01:16:18 +00005 *
6 * Copyright (C) International Business Machines Corp., 2002,2007
Linus Torvalds1da177e2005-04-16 15:20:36 -07007 * Author(s): Steve French (sfrench@us.ibm.com)
Jeremy Allison7ee1af72006-08-02 21:56:33 +00008 * Jeremy Allison (jra@samba.org)
Linus Torvalds1da177e2005-04-16 15:20:36 -07009 *
10 * This library is free software; you can redistribute it and/or modify
11 * it under the terms of the GNU Lesser General Public License as published
12 * by the Free Software Foundation; either version 2.1 of the License, or
13 * (at your option) any later version.
14 *
15 * This library is distributed in the hope that it will be useful,
16 * but WITHOUT ANY WARRANTY; without even the implied warranty of
17 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See
18 * the GNU Lesser General Public License for more details.
19 *
20 * You should have received a copy of the GNU Lesser General Public License
21 * along with this library; if not, write to the Free Software
22 * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
23 */
24#include <linux/fs.h>
Steve French37c0eb42005-10-05 14:50:29 -070025#include <linux/backing-dev.h>
Linus Torvalds1da177e2005-04-16 15:20:36 -070026#include <linux/stat.h>
27#include <linux/fcntl.h>
28#include <linux/pagemap.h>
29#include <linux/pagevec.h>
Steve French37c0eb42005-10-05 14:50:29 -070030#include <linux/writeback.h>
Andrew Morton6f88cc22006-12-10 02:19:44 -080031#include <linux/task_io_accounting_ops.h>
Steve French23e7dd72005-10-20 13:44:56 -070032#include <linux/delay.h>
Linus Torvalds1da177e2005-04-16 15:20:36 -070033#include <asm/div64.h>
34#include "cifsfs.h"
35#include "cifspdu.h"
36#include "cifsglob.h"
37#include "cifsproto.h"
38#include "cifs_unicode.h"
39#include "cifs_debug.h"
40#include "cifs_fs_sb.h"
41
42static inline struct cifsFileInfo *cifs_init_private(
43 struct cifsFileInfo *private_data, struct inode *inode,
44 struct file *file, __u16 netfid)
45{
46 memset(private_data, 0, sizeof(struct cifsFileInfo));
47 private_data->netfid = netfid;
Steve Frenchfb8c4b12007-07-10 01:16:18 +000048 private_data->pid = current->tgid;
Steve Frencha6ce4932009-04-09 01:14:32 +000049 mutex_init(&private_data->fh_mutex);
Roland Dreier796e5662007-05-03 04:33:45 +000050 mutex_init(&private_data->lock_mutex);
Jeremy Allison7ee1af72006-08-02 21:56:33 +000051 INIT_LIST_HEAD(&private_data->llist);
Linus Torvalds1da177e2005-04-16 15:20:36 -070052 private_data->pfile = file; /* needed for writepage */
53 private_data->pInode = inode;
Steve French4b18f2a2008-04-29 00:06:05 +000054 private_data->invalidHandle = false;
55 private_data->closePend = false;
Dave Kleikamp6ab409b2009-08-31 11:07:12 -040056 /* Initialize reference count to one. The private data is
57 freed on the release of the last reference */
58 atomic_set(&private_data->count, 1);
Linus Torvalds1da177e2005-04-16 15:20:36 -070059
60 return private_data;
61}
62
63static inline int cifs_convert_flags(unsigned int flags)
64{
65 if ((flags & O_ACCMODE) == O_RDONLY)
66 return GENERIC_READ;
67 else if ((flags & O_ACCMODE) == O_WRONLY)
68 return GENERIC_WRITE;
69 else if ((flags & O_ACCMODE) == O_RDWR) {
70 /* GENERIC_ALL is too much permission to request
71 can cause unnecessary access denied on create */
72 /* return GENERIC_ALL; */
73 return (GENERIC_READ | GENERIC_WRITE);
74 }
75
Jeff Laytone10f7b52008-05-14 10:21:33 -070076 return (READ_CONTROL | FILE_WRITE_ATTRIBUTES | FILE_READ_ATTRIBUTES |
77 FILE_WRITE_EA | FILE_APPEND_DATA | FILE_WRITE_DATA |
78 FILE_READ_DATA);
Steve French7fc8f4e2009-02-23 20:43:11 +000079}
Jeff Laytone10f7b52008-05-14 10:21:33 -070080
Steve French7fc8f4e2009-02-23 20:43:11 +000081static inline fmode_t cifs_posix_convert_flags(unsigned int flags)
82{
83 fmode_t posix_flags = 0;
Jeff Laytone10f7b52008-05-14 10:21:33 -070084
Steve French7fc8f4e2009-02-23 20:43:11 +000085 if ((flags & O_ACCMODE) == O_RDONLY)
86 posix_flags = FMODE_READ;
87 else if ((flags & O_ACCMODE) == O_WRONLY)
88 posix_flags = FMODE_WRITE;
89 else if ((flags & O_ACCMODE) == O_RDWR) {
90 /* GENERIC_ALL is too much permission to request
91 can cause unnecessary access denied on create */
92 /* return GENERIC_ALL; */
93 posix_flags = FMODE_READ | FMODE_WRITE;
94 }
95 /* can not map O_CREAT or O_EXCL or O_TRUNC flags when
96 reopening a file. They had their effect on the original open */
97 if (flags & O_APPEND)
98 posix_flags |= (fmode_t)O_APPEND;
99 if (flags & O_SYNC)
100 posix_flags |= (fmode_t)O_SYNC;
101 if (flags & O_DIRECTORY)
102 posix_flags |= (fmode_t)O_DIRECTORY;
103 if (flags & O_NOFOLLOW)
104 posix_flags |= (fmode_t)O_NOFOLLOW;
105 if (flags & O_DIRECT)
106 posix_flags |= (fmode_t)O_DIRECT;
107
108 return posix_flags;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700109}
110
111static inline int cifs_get_disposition(unsigned int flags)
112{
113 if ((flags & (O_CREAT | O_EXCL)) == (O_CREAT | O_EXCL))
114 return FILE_CREATE;
115 else if ((flags & (O_CREAT | O_TRUNC)) == (O_CREAT | O_TRUNC))
116 return FILE_OVERWRITE_IF;
117 else if ((flags & O_CREAT) == O_CREAT)
118 return FILE_OPEN_IF;
Steve French55aa2e02006-05-30 18:09:31 +0000119 else if ((flags & O_TRUNC) == O_TRUNC)
120 return FILE_OVERWRITE;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700121 else
122 return FILE_OPEN;
123}
124
125/* all arguments to this function must be checked for validity in caller */
Steve French276a74a2009-03-03 18:00:34 +0000126static inline int cifs_posix_open_inode_helper(struct inode *inode,
127 struct file *file, struct cifsInodeInfo *pCifsInode,
128 struct cifsFileInfo *pCifsFile, int oplock, u16 netfid)
129{
Steve French276a74a2009-03-03 18:00:34 +0000130
Steve French276a74a2009-03-03 18:00:34 +0000131 write_lock(&GlobalSMBSeslock);
Steve French276a74a2009-03-03 18:00:34 +0000132
133 pCifsInode = CIFS_I(file->f_path.dentry->d_inode);
134 if (pCifsInode == NULL) {
135 write_unlock(&GlobalSMBSeslock);
136 return -EINVAL;
137 }
138
Steve French276a74a2009-03-03 18:00:34 +0000139 if (pCifsInode->clientCanCacheRead) {
140 /* we have the inode open somewhere else
141 no need to discard cache data */
142 goto psx_client_can_cache;
143 }
144
145 /* BB FIXME need to fix this check to move it earlier into posix_open
146 BB fIX following section BB FIXME */
147
148 /* if not oplocked, invalidate inode pages if mtime or file
149 size changed */
150/* temp = cifs_NTtimeToUnix(le64_to_cpu(buf->LastWriteTime));
151 if (timespec_equal(&file->f_path.dentry->d_inode->i_mtime, &temp) &&
152 (file->f_path.dentry->d_inode->i_size ==
153 (loff_t)le64_to_cpu(buf->EndOfFile))) {
154 cFYI(1, ("inode unchanged on server"));
155 } else {
156 if (file->f_path.dentry->d_inode->i_mapping) {
157 rc = filemap_write_and_wait(file->f_path.dentry->d_inode->i_mapping);
158 if (rc != 0)
159 CIFS_I(file->f_path.dentry->d_inode)->write_behind_rc = rc;
160 }
161 cFYI(1, ("invalidating remote inode since open detected it "
162 "changed"));
163 invalidate_remote_inode(file->f_path.dentry->d_inode);
164 } */
165
166psx_client_can_cache:
167 if ((oplock & 0xF) == OPLOCK_EXCLUSIVE) {
168 pCifsInode->clientCanCacheAll = true;
169 pCifsInode->clientCanCacheRead = true;
170 cFYI(1, ("Exclusive Oplock granted on inode %p",
171 file->f_path.dentry->d_inode));
172 } else if ((oplock & 0xF) == OPLOCK_READ)
173 pCifsInode->clientCanCacheRead = true;
174
175 /* will have to change the unlock if we reenable the
176 filemap_fdatawrite (which does not seem necessary */
177 write_unlock(&GlobalSMBSeslock);
178 return 0;
179}
180
Steve French703a3b82009-05-21 22:21:53 +0000181static struct cifsFileInfo *
182cifs_fill_filedata(struct file *file)
183{
184 struct list_head *tmp;
185 struct cifsFileInfo *pCifsFile = NULL;
186 struct cifsInodeInfo *pCifsInode = NULL;
187
188 /* search inode for this file and fill in file->private_data */
189 pCifsInode = CIFS_I(file->f_path.dentry->d_inode);
190 read_lock(&GlobalSMBSeslock);
191 list_for_each(tmp, &pCifsInode->openFileList) {
192 pCifsFile = list_entry(tmp, struct cifsFileInfo, flist);
193 if ((pCifsFile->pfile == NULL) &&
194 (pCifsFile->pid == current->tgid)) {
195 /* mode set in cifs_create */
196
197 /* needed for writepage */
198 pCifsFile->pfile = file;
199 file->private_data = pCifsFile;
200 break;
201 }
202 }
203 read_unlock(&GlobalSMBSeslock);
204
205 if (file->private_data != NULL) {
206 return pCifsFile;
207 } else if ((file->f_flags & O_CREAT) && (file->f_flags & O_EXCL))
208 cERROR(1, ("could not find file instance for "
209 "new file %p", file));
210 return NULL;
211}
212
Steve French276a74a2009-03-03 18:00:34 +0000213/* all arguments to this function must be checked for validity in caller */
Linus Torvalds1da177e2005-04-16 15:20:36 -0700214static inline int cifs_open_inode_helper(struct inode *inode, struct file *file,
215 struct cifsInodeInfo *pCifsInode, struct cifsFileInfo *pCifsFile,
216 struct cifsTconInfo *pTcon, int *oplock, FILE_ALL_INFO *buf,
217 char *full_path, int xid)
218{
219 struct timespec temp;
220 int rc;
221
222 /* want handles we can use to read with first
223 in the list so we do not have to walk the
Nick Piggind9414772008-09-24 11:32:59 -0400224 list to search for one in write_begin */
Linus Torvalds1da177e2005-04-16 15:20:36 -0700225 if ((file->f_flags & O_ACCMODE) == O_WRONLY) {
Steve Frenchfb8c4b12007-07-10 01:16:18 +0000226 list_add_tail(&pCifsFile->flist,
Linus Torvalds1da177e2005-04-16 15:20:36 -0700227 &pCifsInode->openFileList);
228 } else {
229 list_add(&pCifsFile->flist,
230 &pCifsInode->openFileList);
231 }
232 write_unlock(&GlobalSMBSeslock);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700233 if (pCifsInode->clientCanCacheRead) {
234 /* we have the inode open somewhere else
235 no need to discard cache data */
236 goto client_can_cache;
237 }
238
239 /* BB need same check in cifs_create too? */
240 /* if not oplocked, invalidate inode pages if mtime or file
241 size changed */
Jeff Layton07119a42009-05-27 09:37:33 -0400242 temp = cifs_NTtimeToUnix(buf->LastWriteTime);
Josef "Jeff" Sipeke6a00292006-12-08 02:36:48 -0800243 if (timespec_equal(&file->f_path.dentry->d_inode->i_mtime, &temp) &&
244 (file->f_path.dentry->d_inode->i_size ==
Linus Torvalds1da177e2005-04-16 15:20:36 -0700245 (loff_t)le64_to_cpu(buf->EndOfFile))) {
246 cFYI(1, ("inode unchanged on server"));
247 } else {
Josef "Jeff" Sipeke6a00292006-12-08 02:36:48 -0800248 if (file->f_path.dentry->d_inode->i_mapping) {
Linus Torvalds1da177e2005-04-16 15:20:36 -0700249 /* BB no need to lock inode until after invalidate
250 since namei code should already have it locked? */
Jeff Laytoncea21802007-11-20 23:19:03 +0000251 rc = filemap_write_and_wait(file->f_path.dentry->d_inode->i_mapping);
252 if (rc != 0)
253 CIFS_I(file->f_path.dentry->d_inode)->write_behind_rc = rc;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700254 }
255 cFYI(1, ("invalidating remote inode since open detected it "
256 "changed"));
Josef "Jeff" Sipeke6a00292006-12-08 02:36:48 -0800257 invalidate_remote_inode(file->f_path.dentry->d_inode);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700258 }
259
260client_can_cache:
Steve Frenchc18c8422007-07-18 23:21:09 +0000261 if (pTcon->unix_ext)
Josef "Jeff" Sipeke6a00292006-12-08 02:36:48 -0800262 rc = cifs_get_inode_info_unix(&file->f_path.dentry->d_inode,
Linus Torvalds1da177e2005-04-16 15:20:36 -0700263 full_path, inode->i_sb, xid);
264 else
Josef "Jeff" Sipeke6a00292006-12-08 02:36:48 -0800265 rc = cifs_get_inode_info(&file->f_path.dentry->d_inode,
Steve French8b1327f2008-03-14 22:37:16 +0000266 full_path, buf, inode->i_sb, xid, NULL);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700267
268 if ((*oplock & 0xF) == OPLOCK_EXCLUSIVE) {
Steve French4b18f2a2008-04-29 00:06:05 +0000269 pCifsInode->clientCanCacheAll = true;
270 pCifsInode->clientCanCacheRead = true;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700271 cFYI(1, ("Exclusive Oplock granted on inode %p",
Josef "Jeff" Sipeke6a00292006-12-08 02:36:48 -0800272 file->f_path.dentry->d_inode));
Linus Torvalds1da177e2005-04-16 15:20:36 -0700273 } else if ((*oplock & 0xF) == OPLOCK_READ)
Steve French4b18f2a2008-04-29 00:06:05 +0000274 pCifsInode->clientCanCacheRead = true;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700275
276 return rc;
277}
278
279int cifs_open(struct inode *inode, struct file *file)
280{
281 int rc = -EACCES;
282 int xid, oplock;
283 struct cifs_sb_info *cifs_sb;
Steve French276a74a2009-03-03 18:00:34 +0000284 struct cifsTconInfo *tcon;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700285 struct cifsFileInfo *pCifsFile;
286 struct cifsInodeInfo *pCifsInode;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700287 char *full_path = NULL;
288 int desiredAccess;
289 int disposition;
290 __u16 netfid;
291 FILE_ALL_INFO *buf = NULL;
292
293 xid = GetXid();
294
295 cifs_sb = CIFS_SB(inode->i_sb);
Steve French276a74a2009-03-03 18:00:34 +0000296 tcon = cifs_sb->tcon;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700297
Steve Frencha6ce4932009-04-09 01:14:32 +0000298 pCifsInode = CIFS_I(file->f_path.dentry->d_inode);
Steve French703a3b82009-05-21 22:21:53 +0000299 pCifsFile = cifs_fill_filedata(file);
300 if (pCifsFile) {
Suresh Jayaraman0f3bc092009-06-25 18:12:34 +0530301 rc = 0;
Steve Frencha6ce4932009-04-09 01:14:32 +0000302 FreeXid(xid);
Suresh Jayaraman0f3bc092009-06-25 18:12:34 +0530303 return rc;
Steve French703a3b82009-05-21 22:21:53 +0000304 }
Linus Torvalds1da177e2005-04-16 15:20:36 -0700305
Josef "Jeff" Sipeke6a00292006-12-08 02:36:48 -0800306 full_path = build_path_from_dentry(file->f_path.dentry);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700307 if (full_path == NULL) {
Suresh Jayaraman0f3bc092009-06-25 18:12:34 +0530308 rc = -ENOMEM;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700309 FreeXid(xid);
Suresh Jayaraman0f3bc092009-06-25 18:12:34 +0530310 return rc;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700311 }
312
Steve French7521a3c2007-07-11 18:30:34 +0000313 cFYI(1, ("inode = 0x%p file flags are 0x%x for %s",
Linus Torvalds1da177e2005-04-16 15:20:36 -0700314 inode, file->f_flags, full_path));
Steve French276a74a2009-03-03 18:00:34 +0000315
316 if (oplockEnabled)
317 oplock = REQ_OPLOCK;
318 else
319 oplock = 0;
320
Steve French64cc2c62009-03-04 19:54:08 +0000321 if (!tcon->broken_posix_open && tcon->unix_ext &&
322 (tcon->ses->capabilities & CAP_UNIX) &&
Steve French276a74a2009-03-03 18:00:34 +0000323 (CIFS_UNIX_POSIX_PATH_OPS_CAP &
324 le64_to_cpu(tcon->fsUnixInfo.Capability))) {
325 int oflags = (int) cifs_posix_convert_flags(file->f_flags);
326 /* can not refresh inode info since size could be stale */
327 rc = cifs_posix_open(full_path, &inode, inode->i_sb,
328 cifs_sb->mnt_file_mode /* ignored */,
329 oflags, &oplock, &netfid, xid);
330 if (rc == 0) {
331 cFYI(1, ("posix open succeeded"));
332 /* no need for special case handling of setting mode
333 on read only files needed here */
334
Steve French703a3b82009-05-21 22:21:53 +0000335 pCifsFile = cifs_fill_filedata(file);
Steve French276a74a2009-03-03 18:00:34 +0000336 cifs_posix_open_inode_helper(inode, file, pCifsInode,
337 pCifsFile, oplock, netfid);
338 goto out;
Steve French64cc2c62009-03-04 19:54:08 +0000339 } else if ((rc == -EINVAL) || (rc == -EOPNOTSUPP)) {
340 if (tcon->ses->serverNOS)
341 cERROR(1, ("server %s of type %s returned"
342 " unexpected error on SMB posix open"
343 ", disabling posix open support."
344 " Check if server update available.",
345 tcon->ses->serverName,
346 tcon->ses->serverNOS));
347 tcon->broken_posix_open = true;
Steve French276a74a2009-03-03 18:00:34 +0000348 } else if ((rc != -EIO) && (rc != -EREMOTE) &&
349 (rc != -EOPNOTSUPP)) /* path not found or net err */
350 goto out;
Steve French64cc2c62009-03-04 19:54:08 +0000351 /* else fallthrough to retry open the old way on network i/o
352 or DFS errors */
Steve French276a74a2009-03-03 18:00:34 +0000353 }
354
Linus Torvalds1da177e2005-04-16 15:20:36 -0700355 desiredAccess = cifs_convert_flags(file->f_flags);
356
357/*********************************************************************
358 * open flag mapping table:
Steve Frenchfb8c4b12007-07-10 01:16:18 +0000359 *
Linus Torvalds1da177e2005-04-16 15:20:36 -0700360 * POSIX Flag CIFS Disposition
Steve Frenchfb8c4b12007-07-10 01:16:18 +0000361 * ---------- ----------------
Linus Torvalds1da177e2005-04-16 15:20:36 -0700362 * O_CREAT FILE_OPEN_IF
363 * O_CREAT | O_EXCL FILE_CREATE
364 * O_CREAT | O_TRUNC FILE_OVERWRITE_IF
365 * O_TRUNC FILE_OVERWRITE
366 * none of the above FILE_OPEN
367 *
368 * Note that there is not a direct match between disposition
Steve Frenchfb8c4b12007-07-10 01:16:18 +0000369 * FILE_SUPERSEDE (ie create whether or not file exists although
Linus Torvalds1da177e2005-04-16 15:20:36 -0700370 * O_CREAT | O_TRUNC is similar but truncates the existing
371 * file rather than creating a new file as FILE_SUPERSEDE does
372 * (which uses the attributes / metadata passed in on open call)
373 *?
Steve Frenchfb8c4b12007-07-10 01:16:18 +0000374 *? O_SYNC is a reasonable match to CIFS writethrough flag
Linus Torvalds1da177e2005-04-16 15:20:36 -0700375 *? and the read write flags match reasonably. O_LARGEFILE
376 *? is irrelevant because largefile support is always used
377 *? by this client. Flags O_APPEND, O_DIRECT, O_DIRECTORY,
378 * O_FASYNC, O_NOFOLLOW, O_NONBLOCK need further investigation
379 *********************************************************************/
380
381 disposition = cifs_get_disposition(file->f_flags);
382
Linus Torvalds1da177e2005-04-16 15:20:36 -0700383 /* BB pass O_SYNC flag through on file attributes .. BB */
384
385 /* Also refresh inode by passing in file_info buf returned by SMBOpen
386 and calling get_inode_info with returned buf (at least helps
387 non-Unix server case) */
388
Steve Frenchfb8c4b12007-07-10 01:16:18 +0000389 /* BB we can not do this if this is the second open of a file
390 and the first handle has writebehind data, we might be
Linus Torvalds1da177e2005-04-16 15:20:36 -0700391 able to simply do a filemap_fdatawrite/filemap_fdatawait first */
392 buf = kmalloc(sizeof(FILE_ALL_INFO), GFP_KERNEL);
393 if (!buf) {
394 rc = -ENOMEM;
395 goto out;
396 }
Steve French5bafd762006-06-07 00:18:43 +0000397
398 if (cifs_sb->tcon->ses->capabilities & CAP_NT_SMBS)
Steve French276a74a2009-03-03 18:00:34 +0000399 rc = CIFSSMBOpen(xid, tcon, full_path, disposition,
Steve French5bafd762006-06-07 00:18:43 +0000400 desiredAccess, CREATE_NOT_DIR, &netfid, &oplock, buf,
Steve French737b7582005-04-28 22:41:06 -0700401 cifs_sb->local_nls, cifs_sb->mnt_cifs_flags
402 & CIFS_MOUNT_MAP_SPECIAL_CHR);
Steve French5bafd762006-06-07 00:18:43 +0000403 else
404 rc = -EIO; /* no NT SMB support fall into legacy open below */
405
Steve Frencha9d02ad2005-08-24 23:06:05 -0700406 if (rc == -EIO) {
407 /* Old server, try legacy style OpenX */
Steve French276a74a2009-03-03 18:00:34 +0000408 rc = SMBLegacyOpen(xid, tcon, full_path, disposition,
Steve Frencha9d02ad2005-08-24 23:06:05 -0700409 desiredAccess, CREATE_NOT_DIR, &netfid, &oplock, buf,
410 cifs_sb->local_nls, cifs_sb->mnt_cifs_flags
411 & CIFS_MOUNT_MAP_SPECIAL_CHR);
412 }
Linus Torvalds1da177e2005-04-16 15:20:36 -0700413 if (rc) {
Steve French26a21b92006-05-31 18:05:34 +0000414 cFYI(1, ("cifs_open returned 0x%x", rc));
Linus Torvalds1da177e2005-04-16 15:20:36 -0700415 goto out;
416 }
417 file->private_data =
418 kmalloc(sizeof(struct cifsFileInfo), GFP_KERNEL);
419 if (file->private_data == NULL) {
420 rc = -ENOMEM;
421 goto out;
422 }
423 pCifsFile = cifs_init_private(file->private_data, inode, file, netfid);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700424 write_lock(&GlobalSMBSeslock);
Steve French276a74a2009-03-03 18:00:34 +0000425 list_add(&pCifsFile->tlist, &tcon->openFileList);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700426
Josef "Jeff" Sipeke6a00292006-12-08 02:36:48 -0800427 pCifsInode = CIFS_I(file->f_path.dentry->d_inode);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700428 if (pCifsInode) {
429 rc = cifs_open_inode_helper(inode, file, pCifsInode,
Steve French276a74a2009-03-03 18:00:34 +0000430 pCifsFile, tcon,
Linus Torvalds1da177e2005-04-16 15:20:36 -0700431 &oplock, buf, full_path, xid);
432 } else {
433 write_unlock(&GlobalSMBSeslock);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700434 }
435
Steve Frenchfb8c4b12007-07-10 01:16:18 +0000436 if (oplock & CIFS_CREATE_ACTION) {
Linus Torvalds1da177e2005-04-16 15:20:36 -0700437 /* time to set mode which we can not set earlier due to
438 problems creating new read-only files */
Steve French276a74a2009-03-03 18:00:34 +0000439 if (tcon->unix_ext) {
Jeff Layton4e1e7fb2008-08-02 07:26:12 -0400440 struct cifs_unix_set_info_args args = {
441 .mode = inode->i_mode,
442 .uid = NO_CHANGE_64,
443 .gid = NO_CHANGE_64,
444 .ctime = NO_CHANGE_64,
445 .atime = NO_CHANGE_64,
446 .mtime = NO_CHANGE_64,
447 .device = 0,
448 };
Jeff Layton01ea95e2009-07-09 20:02:49 -0400449 CIFSSMBUnixSetPathInfo(xid, tcon, full_path, &args,
450 cifs_sb->local_nls,
451 cifs_sb->mnt_cifs_flags &
Steve French737b7582005-04-28 22:41:06 -0700452 CIFS_MOUNT_MAP_SPECIAL_CHR);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700453 }
454 }
455
456out:
457 kfree(buf);
458 kfree(full_path);
459 FreeXid(xid);
460 return rc;
461}
462
Adrian Bunk04187262006-06-30 18:23:04 +0200463/* Try to reacquire byte range locks that were released when session */
Linus Torvalds1da177e2005-04-16 15:20:36 -0700464/* to server was lost */
465static int cifs_relock_file(struct cifsFileInfo *cifsFile)
466{
467 int rc = 0;
468
469/* BB list all locks open on this file and relock */
470
471 return rc;
472}
473
Steve French4b18f2a2008-04-29 00:06:05 +0000474static int cifs_reopen_file(struct file *file, bool can_flush)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700475{
476 int rc = -EACCES;
477 int xid, oplock;
478 struct cifs_sb_info *cifs_sb;
Steve French7fc8f4e2009-02-23 20:43:11 +0000479 struct cifsTconInfo *tcon;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700480 struct cifsFileInfo *pCifsFile;
481 struct cifsInodeInfo *pCifsInode;
Steve Frenchfb8c4b12007-07-10 01:16:18 +0000482 struct inode *inode;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700483 char *full_path = NULL;
484 int desiredAccess;
485 int disposition = FILE_OPEN;
486 __u16 netfid;
487
Steve Frenchad7a2922008-02-07 23:25:02 +0000488 if (file->private_data)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700489 pCifsFile = (struct cifsFileInfo *)file->private_data;
Steve Frenchad7a2922008-02-07 23:25:02 +0000490 else
Linus Torvalds1da177e2005-04-16 15:20:36 -0700491 return -EBADF;
492
493 xid = GetXid();
Jeff Laytonf0a71eb2009-06-27 07:04:55 -0400494 mutex_lock(&pCifsFile->fh_mutex);
Steve French4b18f2a2008-04-29 00:06:05 +0000495 if (!pCifsFile->invalidHandle) {
Jeff Laytonf0a71eb2009-06-27 07:04:55 -0400496 mutex_unlock(&pCifsFile->fh_mutex);
Suresh Jayaraman0f3bc092009-06-25 18:12:34 +0530497 rc = 0;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700498 FreeXid(xid);
Suresh Jayaraman0f3bc092009-06-25 18:12:34 +0530499 return rc;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700500 }
501
Josef "Jeff" Sipeke6a00292006-12-08 02:36:48 -0800502 if (file->f_path.dentry == NULL) {
Steve French3a9f4622007-04-04 17:10:24 +0000503 cERROR(1, ("no valid name if dentry freed"));
504 dump_stack();
505 rc = -EBADF;
506 goto reopen_error_exit;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700507 }
Steve French3a9f4622007-04-04 17:10:24 +0000508
509 inode = file->f_path.dentry->d_inode;
Steve Frenchfb8c4b12007-07-10 01:16:18 +0000510 if (inode == NULL) {
Steve French3a9f4622007-04-04 17:10:24 +0000511 cERROR(1, ("inode not valid"));
512 dump_stack();
513 rc = -EBADF;
514 goto reopen_error_exit;
515 }
Steve French50c2f752007-07-13 00:33:32 +0000516
Linus Torvalds1da177e2005-04-16 15:20:36 -0700517 cifs_sb = CIFS_SB(inode->i_sb);
Steve French7fc8f4e2009-02-23 20:43:11 +0000518 tcon = cifs_sb->tcon;
Steve French3a9f4622007-04-04 17:10:24 +0000519
Linus Torvalds1da177e2005-04-16 15:20:36 -0700520/* can not grab rename sem here because various ops, including
521 those that already have the rename sem can end up causing writepage
522 to get called and if the server was down that means we end up here,
523 and we can never tell if the caller already has the rename_sem */
Josef "Jeff" Sipeke6a00292006-12-08 02:36:48 -0800524 full_path = build_path_from_dentry(file->f_path.dentry);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700525 if (full_path == NULL) {
Steve French3a9f4622007-04-04 17:10:24 +0000526 rc = -ENOMEM;
527reopen_error_exit:
Jeff Laytonf0a71eb2009-06-27 07:04:55 -0400528 mutex_unlock(&pCifsFile->fh_mutex);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700529 FreeXid(xid);
Steve French3a9f4622007-04-04 17:10:24 +0000530 return rc;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700531 }
532
Steve French3a9f4622007-04-04 17:10:24 +0000533 cFYI(1, ("inode = 0x%p file flags 0x%x for %s",
Steve Frenchfb8c4b12007-07-10 01:16:18 +0000534 inode, file->f_flags, full_path));
Linus Torvalds1da177e2005-04-16 15:20:36 -0700535
536 if (oplockEnabled)
537 oplock = REQ_OPLOCK;
538 else
Steve French4b18f2a2008-04-29 00:06:05 +0000539 oplock = 0;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700540
Steve French7fc8f4e2009-02-23 20:43:11 +0000541 if (tcon->unix_ext && (tcon->ses->capabilities & CAP_UNIX) &&
542 (CIFS_UNIX_POSIX_PATH_OPS_CAP &
543 le64_to_cpu(tcon->fsUnixInfo.Capability))) {
544 int oflags = (int) cifs_posix_convert_flags(file->f_flags);
545 /* can not refresh inode info since size could be stale */
546 rc = cifs_posix_open(full_path, NULL, inode->i_sb,
547 cifs_sb->mnt_file_mode /* ignored */,
548 oflags, &oplock, &netfid, xid);
549 if (rc == 0) {
550 cFYI(1, ("posix reopen succeeded"));
551 goto reopen_success;
552 }
553 /* fallthrough to retry open the old way on errors, especially
554 in the reconnect path it is important to retry hard */
555 }
556
557 desiredAccess = cifs_convert_flags(file->f_flags);
558
Linus Torvalds1da177e2005-04-16 15:20:36 -0700559 /* Can not refresh inode by passing in file_info buf to be returned
Steve Frenchfb8c4b12007-07-10 01:16:18 +0000560 by SMBOpen and then calling get_inode_info with returned buf
561 since file might have write behind data that needs to be flushed
Linus Torvalds1da177e2005-04-16 15:20:36 -0700562 and server version of file size can be stale. If we knew for sure
563 that inode was not dirty locally we could do this */
564
Steve French7fc8f4e2009-02-23 20:43:11 +0000565 rc = CIFSSMBOpen(xid, tcon, full_path, disposition, desiredAccess,
Linus Torvalds1da177e2005-04-16 15:20:36 -0700566 CREATE_NOT_DIR, &netfid, &oplock, NULL,
Steve Frenchfb8c4b12007-07-10 01:16:18 +0000567 cifs_sb->local_nls, cifs_sb->mnt_cifs_flags &
Steve French737b7582005-04-28 22:41:06 -0700568 CIFS_MOUNT_MAP_SPECIAL_CHR);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700569 if (rc) {
Jeff Laytonf0a71eb2009-06-27 07:04:55 -0400570 mutex_unlock(&pCifsFile->fh_mutex);
Steve French26a21b92006-05-31 18:05:34 +0000571 cFYI(1, ("cifs_open returned 0x%x", rc));
572 cFYI(1, ("oplock: %d", oplock));
Linus Torvalds1da177e2005-04-16 15:20:36 -0700573 } else {
Steve French7fc8f4e2009-02-23 20:43:11 +0000574reopen_success:
Linus Torvalds1da177e2005-04-16 15:20:36 -0700575 pCifsFile->netfid = netfid;
Steve French4b18f2a2008-04-29 00:06:05 +0000576 pCifsFile->invalidHandle = false;
Jeff Laytonf0a71eb2009-06-27 07:04:55 -0400577 mutex_unlock(&pCifsFile->fh_mutex);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700578 pCifsInode = CIFS_I(inode);
579 if (pCifsInode) {
580 if (can_flush) {
Jeff Laytoncea21802007-11-20 23:19:03 +0000581 rc = filemap_write_and_wait(inode->i_mapping);
582 if (rc != 0)
583 CIFS_I(inode)->write_behind_rc = rc;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700584 /* temporarily disable caching while we
585 go to server to get inode info */
Steve French4b18f2a2008-04-29 00:06:05 +0000586 pCifsInode->clientCanCacheAll = false;
587 pCifsInode->clientCanCacheRead = false;
Steve French7fc8f4e2009-02-23 20:43:11 +0000588 if (tcon->unix_ext)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700589 rc = cifs_get_inode_info_unix(&inode,
590 full_path, inode->i_sb, xid);
591 else
592 rc = cifs_get_inode_info(&inode,
593 full_path, NULL, inode->i_sb,
Steve French8b1327f2008-03-14 22:37:16 +0000594 xid, NULL);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700595 } /* else we are writing out data to server already
596 and could deadlock if we tried to flush data, and
597 since we do not know if we have data that would
598 invalidate the current end of file on the server
599 we can not go to the server to get the new inod
600 info */
601 if ((oplock & 0xF) == OPLOCK_EXCLUSIVE) {
Steve French4b18f2a2008-04-29 00:06:05 +0000602 pCifsInode->clientCanCacheAll = true;
603 pCifsInode->clientCanCacheRead = true;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700604 cFYI(1, ("Exclusive Oplock granted on inode %p",
Josef "Jeff" Sipeke6a00292006-12-08 02:36:48 -0800605 file->f_path.dentry->d_inode));
Linus Torvalds1da177e2005-04-16 15:20:36 -0700606 } else if ((oplock & 0xF) == OPLOCK_READ) {
Steve French4b18f2a2008-04-29 00:06:05 +0000607 pCifsInode->clientCanCacheRead = true;
608 pCifsInode->clientCanCacheAll = false;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700609 } else {
Steve French4b18f2a2008-04-29 00:06:05 +0000610 pCifsInode->clientCanCacheRead = false;
611 pCifsInode->clientCanCacheAll = false;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700612 }
613 cifs_relock_file(pCifsFile);
614 }
615 }
Linus Torvalds1da177e2005-04-16 15:20:36 -0700616 kfree(full_path);
617 FreeXid(xid);
618 return rc;
619}
620
621int cifs_close(struct inode *inode, struct file *file)
622{
623 int rc = 0;
Steve French15745322007-09-07 22:23:48 +0000624 int xid, timeout;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700625 struct cifs_sb_info *cifs_sb;
626 struct cifsTconInfo *pTcon;
627 struct cifsFileInfo *pSMBFile =
628 (struct cifsFileInfo *)file->private_data;
629
630 xid = GetXid();
631
632 cifs_sb = CIFS_SB(inode->i_sb);
633 pTcon = cifs_sb->tcon;
634 if (pSMBFile) {
Jeremy Allison7ee1af72006-08-02 21:56:33 +0000635 struct cifsLockInfo *li, *tmp;
Steve Frenchddb4cbf2008-11-20 20:00:44 +0000636 write_lock(&GlobalSMBSeslock);
Steve French4b18f2a2008-04-29 00:06:05 +0000637 pSMBFile->closePend = true;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700638 if (pTcon) {
639 /* no sense reconnecting to close a file that is
640 already closed */
Steve French3b795212008-11-13 19:45:32 +0000641 if (!pTcon->need_reconnect) {
Steve Frenchddb4cbf2008-11-20 20:00:44 +0000642 write_unlock(&GlobalSMBSeslock);
Steve French15745322007-09-07 22:23:48 +0000643 timeout = 2;
Dave Kleikamp6ab409b2009-08-31 11:07:12 -0400644 while ((atomic_read(&pSMBFile->count) != 1)
Steve French15745322007-09-07 22:23:48 +0000645 && (timeout <= 2048)) {
Steve French23e7dd72005-10-20 13:44:56 -0700646 /* Give write a better chance to get to
647 server ahead of the close. We do not
648 want to add a wait_q here as it would
649 increase the memory utilization as
650 the struct would be in each open file,
Steve Frenchfb8c4b12007-07-10 01:16:18 +0000651 but this should give enough time to
Steve French23e7dd72005-10-20 13:44:56 -0700652 clear the socket */
Steve French90c81e02008-02-12 20:32:36 +0000653 cFYI(DBG2,
654 ("close delay, write pending"));
Steve French23e7dd72005-10-20 13:44:56 -0700655 msleep(timeout);
656 timeout *= 4;
Steve French4891d532006-11-07 16:31:16 +0000657 }
Steve Frenchddb4cbf2008-11-20 20:00:44 +0000658 if (!pTcon->need_reconnect &&
659 !pSMBFile->invalidHandle)
660 rc = CIFSSMBClose(xid, pTcon,
Linus Torvalds1da177e2005-04-16 15:20:36 -0700661 pSMBFile->netfid);
Steve Frenchddb4cbf2008-11-20 20:00:44 +0000662 } else
663 write_unlock(&GlobalSMBSeslock);
664 } else
665 write_unlock(&GlobalSMBSeslock);
Jeremy Allison7ee1af72006-08-02 21:56:33 +0000666
667 /* Delete any outstanding lock records.
668 We'll lose them when the file is closed anyway. */
Roland Dreier796e5662007-05-03 04:33:45 +0000669 mutex_lock(&pSMBFile->lock_mutex);
Jeremy Allison7ee1af72006-08-02 21:56:33 +0000670 list_for_each_entry_safe(li, tmp, &pSMBFile->llist, llist) {
671 list_del(&li->llist);
672 kfree(li);
673 }
Roland Dreier796e5662007-05-03 04:33:45 +0000674 mutex_unlock(&pSMBFile->lock_mutex);
Jeremy Allison7ee1af72006-08-02 21:56:33 +0000675
Steve Frenchcbe04762005-04-28 22:41:05 -0700676 write_lock(&GlobalSMBSeslock);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700677 list_del(&pSMBFile->flist);
678 list_del(&pSMBFile->tlist);
Steve Frenchcbe04762005-04-28 22:41:05 -0700679 write_unlock(&GlobalSMBSeslock);
Dave Kleikamp6ab409b2009-08-31 11:07:12 -0400680 cifsFileInfo_put(file->private_data);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700681 file->private_data = NULL;
682 } else
683 rc = -EBADF;
684
Steve French4efa53f2007-09-11 05:50:53 +0000685 read_lock(&GlobalSMBSeslock);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700686 if (list_empty(&(CIFS_I(inode)->openFileList))) {
687 cFYI(1, ("closing last open instance for inode %p", inode));
688 /* if the file is not open we do not know if we can cache info
689 on this inode, much less write behind and read ahead */
Steve French4b18f2a2008-04-29 00:06:05 +0000690 CIFS_I(inode)->clientCanCacheRead = false;
691 CIFS_I(inode)->clientCanCacheAll = false;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700692 }
Steve French4efa53f2007-09-11 05:50:53 +0000693 read_unlock(&GlobalSMBSeslock);
Steve Frenchfb8c4b12007-07-10 01:16:18 +0000694 if ((rc == 0) && CIFS_I(inode)->write_behind_rc)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700695 rc = CIFS_I(inode)->write_behind_rc;
696 FreeXid(xid);
697 return rc;
698}
699
700int cifs_closedir(struct inode *inode, struct file *file)
701{
702 int rc = 0;
703 int xid;
704 struct cifsFileInfo *pCFileStruct =
705 (struct cifsFileInfo *)file->private_data;
706 char *ptmp;
707
Steve French26a21b92006-05-31 18:05:34 +0000708 cFYI(1, ("Closedir inode = 0x%p", inode));
Linus Torvalds1da177e2005-04-16 15:20:36 -0700709
710 xid = GetXid();
711
712 if (pCFileStruct) {
713 struct cifsTconInfo *pTcon;
Steve Frenchfb8c4b12007-07-10 01:16:18 +0000714 struct cifs_sb_info *cifs_sb =
715 CIFS_SB(file->f_path.dentry->d_sb);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700716
717 pTcon = cifs_sb->tcon;
718
719 cFYI(1, ("Freeing private data in close dir"));
Steve Frenchddb4cbf2008-11-20 20:00:44 +0000720 write_lock(&GlobalSMBSeslock);
Steve French4b18f2a2008-04-29 00:06:05 +0000721 if (!pCFileStruct->srch_inf.endOfSearch &&
722 !pCFileStruct->invalidHandle) {
723 pCFileStruct->invalidHandle = true;
Steve Frenchddb4cbf2008-11-20 20:00:44 +0000724 write_unlock(&GlobalSMBSeslock);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700725 rc = CIFSFindClose(xid, pTcon, pCFileStruct->netfid);
726 cFYI(1, ("Closing uncompleted readdir with rc %d",
727 rc));
728 /* not much we can do if it fails anyway, ignore rc */
729 rc = 0;
Steve Frenchddb4cbf2008-11-20 20:00:44 +0000730 } else
731 write_unlock(&GlobalSMBSeslock);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700732 ptmp = pCFileStruct->srch_inf.ntwrk_buf_start;
733 if (ptmp) {
Steve Frenchec637e32005-12-12 20:53:18 -0800734 cFYI(1, ("closedir free smb buf in srch struct"));
Linus Torvalds1da177e2005-04-16 15:20:36 -0700735 pCFileStruct->srch_inf.ntwrk_buf_start = NULL;
Steve Frenchfb8c4b12007-07-10 01:16:18 +0000736 if (pCFileStruct->srch_inf.smallBuf)
Steve Frenchd47d7c12006-02-28 03:45:48 +0000737 cifs_small_buf_release(ptmp);
738 else
739 cifs_buf_release(ptmp);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700740 }
Linus Torvalds1da177e2005-04-16 15:20:36 -0700741 kfree(file->private_data);
742 file->private_data = NULL;
743 }
744 /* BB can we lock the filestruct while this is going on? */
745 FreeXid(xid);
746 return rc;
747}
748
Jeremy Allison7ee1af72006-08-02 21:56:33 +0000749static int store_file_lock(struct cifsFileInfo *fid, __u64 len,
750 __u64 offset, __u8 lockType)
751{
Steve Frenchfb8c4b12007-07-10 01:16:18 +0000752 struct cifsLockInfo *li =
753 kmalloc(sizeof(struct cifsLockInfo), GFP_KERNEL);
Jeremy Allison7ee1af72006-08-02 21:56:33 +0000754 if (li == NULL)
755 return -ENOMEM;
756 li->offset = offset;
757 li->length = len;
758 li->type = lockType;
Roland Dreier796e5662007-05-03 04:33:45 +0000759 mutex_lock(&fid->lock_mutex);
Jeremy Allison7ee1af72006-08-02 21:56:33 +0000760 list_add(&li->llist, &fid->llist);
Roland Dreier796e5662007-05-03 04:33:45 +0000761 mutex_unlock(&fid->lock_mutex);
Jeremy Allison7ee1af72006-08-02 21:56:33 +0000762 return 0;
763}
764
Linus Torvalds1da177e2005-04-16 15:20:36 -0700765int cifs_lock(struct file *file, int cmd, struct file_lock *pfLock)
766{
767 int rc, xid;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700768 __u32 numLock = 0;
769 __u32 numUnlock = 0;
770 __u64 length;
Steve French4b18f2a2008-04-29 00:06:05 +0000771 bool wait_flag = false;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700772 struct cifs_sb_info *cifs_sb;
Steve French13a6e422008-12-02 17:24:33 +0000773 struct cifsTconInfo *tcon;
Steve French08547b02006-02-28 22:39:25 +0000774 __u16 netfid;
775 __u8 lockType = LOCKING_ANDX_LARGE_FILES;
Steve French13a6e422008-12-02 17:24:33 +0000776 bool posix_locking = 0;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700777
778 length = 1 + pfLock->fl_end - pfLock->fl_start;
779 rc = -EACCES;
780 xid = GetXid();
781
782 cFYI(1, ("Lock parm: 0x%x flockflags: "
783 "0x%x flocktype: 0x%x start: %lld end: %lld",
Steve Frenchfb8c4b12007-07-10 01:16:18 +0000784 cmd, pfLock->fl_flags, pfLock->fl_type, pfLock->fl_start,
785 pfLock->fl_end));
Linus Torvalds1da177e2005-04-16 15:20:36 -0700786
787 if (pfLock->fl_flags & FL_POSIX)
Steve Frenchd47d7c12006-02-28 03:45:48 +0000788 cFYI(1, ("Posix"));
Linus Torvalds1da177e2005-04-16 15:20:36 -0700789 if (pfLock->fl_flags & FL_FLOCK)
Steve Frenchd47d7c12006-02-28 03:45:48 +0000790 cFYI(1, ("Flock"));
Linus Torvalds1da177e2005-04-16 15:20:36 -0700791 if (pfLock->fl_flags & FL_SLEEP) {
Steve Frenchd47d7c12006-02-28 03:45:48 +0000792 cFYI(1, ("Blocking lock"));
Steve French4b18f2a2008-04-29 00:06:05 +0000793 wait_flag = true;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700794 }
795 if (pfLock->fl_flags & FL_ACCESS)
796 cFYI(1, ("Process suspended by mandatory locking - "
Steve French26a21b92006-05-31 18:05:34 +0000797 "not implemented yet"));
Linus Torvalds1da177e2005-04-16 15:20:36 -0700798 if (pfLock->fl_flags & FL_LEASE)
799 cFYI(1, ("Lease on file - not implemented yet"));
Steve Frenchfb8c4b12007-07-10 01:16:18 +0000800 if (pfLock->fl_flags &
Linus Torvalds1da177e2005-04-16 15:20:36 -0700801 (~(FL_POSIX | FL_FLOCK | FL_SLEEP | FL_ACCESS | FL_LEASE)))
802 cFYI(1, ("Unknown lock flags 0x%x", pfLock->fl_flags));
803
804 if (pfLock->fl_type == F_WRLCK) {
805 cFYI(1, ("F_WRLCK "));
806 numLock = 1;
807 } else if (pfLock->fl_type == F_UNLCK) {
Steve Frenchd47d7c12006-02-28 03:45:48 +0000808 cFYI(1, ("F_UNLCK"));
Linus Torvalds1da177e2005-04-16 15:20:36 -0700809 numUnlock = 1;
Steve Frenchd47d7c12006-02-28 03:45:48 +0000810 /* Check if unlock includes more than
811 one lock range */
Linus Torvalds1da177e2005-04-16 15:20:36 -0700812 } else if (pfLock->fl_type == F_RDLCK) {
Steve Frenchd47d7c12006-02-28 03:45:48 +0000813 cFYI(1, ("F_RDLCK"));
Linus Torvalds1da177e2005-04-16 15:20:36 -0700814 lockType |= LOCKING_ANDX_SHARED_LOCK;
815 numLock = 1;
816 } else if (pfLock->fl_type == F_EXLCK) {
Steve Frenchd47d7c12006-02-28 03:45:48 +0000817 cFYI(1, ("F_EXLCK"));
Linus Torvalds1da177e2005-04-16 15:20:36 -0700818 numLock = 1;
819 } else if (pfLock->fl_type == F_SHLCK) {
Steve Frenchd47d7c12006-02-28 03:45:48 +0000820 cFYI(1, ("F_SHLCK"));
Linus Torvalds1da177e2005-04-16 15:20:36 -0700821 lockType |= LOCKING_ANDX_SHARED_LOCK;
822 numLock = 1;
823 } else
Steve Frenchd47d7c12006-02-28 03:45:48 +0000824 cFYI(1, ("Unknown type of lock"));
Linus Torvalds1da177e2005-04-16 15:20:36 -0700825
Josef "Jeff" Sipeke6a00292006-12-08 02:36:48 -0800826 cifs_sb = CIFS_SB(file->f_path.dentry->d_sb);
Steve French13a6e422008-12-02 17:24:33 +0000827 tcon = cifs_sb->tcon;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700828
829 if (file->private_data == NULL) {
Suresh Jayaraman0f3bc092009-06-25 18:12:34 +0530830 rc = -EBADF;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700831 FreeXid(xid);
Suresh Jayaraman0f3bc092009-06-25 18:12:34 +0530832 return rc;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700833 }
Steve French08547b02006-02-28 22:39:25 +0000834 netfid = ((struct cifsFileInfo *)file->private_data)->netfid;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700835
Steve French13a6e422008-12-02 17:24:33 +0000836 if ((tcon->ses->capabilities & CAP_UNIX) &&
837 (CIFS_UNIX_FCNTL_CAP & le64_to_cpu(tcon->fsUnixInfo.Capability)) &&
Steve Frenchacc18aa2008-12-02 18:53:55 +0000838 ((cifs_sb->mnt_cifs_flags & CIFS_MOUNT_NOPOSIXBRL) == 0))
Steve French13a6e422008-12-02 17:24:33 +0000839 posix_locking = 1;
Steve French08547b02006-02-28 22:39:25 +0000840 /* BB add code here to normalize offset and length to
841 account for negative length which we can not accept over the
842 wire */
Linus Torvalds1da177e2005-04-16 15:20:36 -0700843 if (IS_GETLK(cmd)) {
Steve Frenchfb8c4b12007-07-10 01:16:18 +0000844 if (posix_locking) {
Steve French08547b02006-02-28 22:39:25 +0000845 int posix_lock_type;
Steve Frenchfb8c4b12007-07-10 01:16:18 +0000846 if (lockType & LOCKING_ANDX_SHARED_LOCK)
Steve French08547b02006-02-28 22:39:25 +0000847 posix_lock_type = CIFS_RDLCK;
848 else
849 posix_lock_type = CIFS_WRLCK;
Steve French13a6e422008-12-02 17:24:33 +0000850 rc = CIFSSMBPosixLock(xid, tcon, netfid, 1 /* get */,
Steve Frenchfc94cdb2006-05-30 18:03:32 +0000851 length, pfLock,
Steve French08547b02006-02-28 22:39:25 +0000852 posix_lock_type, wait_flag);
853 FreeXid(xid);
854 return rc;
855 }
856
857 /* BB we could chain these into one lock request BB */
Steve French13a6e422008-12-02 17:24:33 +0000858 rc = CIFSSMBLock(xid, tcon, netfid, length, pfLock->fl_start,
Steve French08547b02006-02-28 22:39:25 +0000859 0, 1, lockType, 0 /* wait flag */ );
Linus Torvalds1da177e2005-04-16 15:20:36 -0700860 if (rc == 0) {
Steve French13a6e422008-12-02 17:24:33 +0000861 rc = CIFSSMBLock(xid, tcon, netfid, length,
Linus Torvalds1da177e2005-04-16 15:20:36 -0700862 pfLock->fl_start, 1 /* numUnlock */ ,
863 0 /* numLock */ , lockType,
864 0 /* wait flag */ );
865 pfLock->fl_type = F_UNLCK;
866 if (rc != 0)
867 cERROR(1, ("Error unlocking previously locked "
Steve French08547b02006-02-28 22:39:25 +0000868 "range %d during test of lock", rc));
Linus Torvalds1da177e2005-04-16 15:20:36 -0700869 rc = 0;
870
871 } else {
872 /* if rc == ERR_SHARING_VIOLATION ? */
873 rc = 0; /* do not change lock type to unlock
874 since range in use */
875 }
876
877 FreeXid(xid);
878 return rc;
879 }
Jeremy Allison7ee1af72006-08-02 21:56:33 +0000880
881 if (!numLock && !numUnlock) {
882 /* if no lock or unlock then nothing
883 to do since we do not know what it is */
884 FreeXid(xid);
885 return -EOPNOTSUPP;
886 }
887
888 if (posix_locking) {
Steve French08547b02006-02-28 22:39:25 +0000889 int posix_lock_type;
Steve Frenchfb8c4b12007-07-10 01:16:18 +0000890 if (lockType & LOCKING_ANDX_SHARED_LOCK)
Steve French08547b02006-02-28 22:39:25 +0000891 posix_lock_type = CIFS_RDLCK;
892 else
893 posix_lock_type = CIFS_WRLCK;
Steve French50c2f752007-07-13 00:33:32 +0000894
Steve Frenchfb8c4b12007-07-10 01:16:18 +0000895 if (numUnlock == 1)
Steve Frenchbeb84dc2006-03-03 23:36:34 +0000896 posix_lock_type = CIFS_UNLCK;
Jeremy Allison7ee1af72006-08-02 21:56:33 +0000897
Steve French13a6e422008-12-02 17:24:33 +0000898 rc = CIFSSMBPosixLock(xid, tcon, netfid, 0 /* set */,
Steve Frenchfc94cdb2006-05-30 18:03:32 +0000899 length, pfLock,
Steve French08547b02006-02-28 22:39:25 +0000900 posix_lock_type, wait_flag);
Jeremy Allison7ee1af72006-08-02 21:56:33 +0000901 } else {
Steve Frenchfb8c4b12007-07-10 01:16:18 +0000902 struct cifsFileInfo *fid =
903 (struct cifsFileInfo *)file->private_data;
Jeremy Allison7ee1af72006-08-02 21:56:33 +0000904
905 if (numLock) {
Steve French13a6e422008-12-02 17:24:33 +0000906 rc = CIFSSMBLock(xid, tcon, netfid, length,
Steve Frenchfb8c4b12007-07-10 01:16:18 +0000907 pfLock->fl_start,
Jeremy Allison7ee1af72006-08-02 21:56:33 +0000908 0, numLock, lockType, wait_flag);
909
910 if (rc == 0) {
911 /* For Windows locks we must store them. */
912 rc = store_file_lock(fid, length,
913 pfLock->fl_start, lockType);
914 }
915 } else if (numUnlock) {
916 /* For each stored lock that this unlock overlaps
917 completely, unlock it. */
918 int stored_rc = 0;
919 struct cifsLockInfo *li, *tmp;
920
Steve French6b70c952006-09-21 07:35:29 +0000921 rc = 0;
Roland Dreier796e5662007-05-03 04:33:45 +0000922 mutex_lock(&fid->lock_mutex);
Jeremy Allison7ee1af72006-08-02 21:56:33 +0000923 list_for_each_entry_safe(li, tmp, &fid->llist, llist) {
924 if (pfLock->fl_start <= li->offset &&
Steve Frenchc19eb712007-08-24 03:22:48 +0000925 (pfLock->fl_start + length) >=
Jeff Layton39db8102007-08-24 03:16:51 +0000926 (li->offset + li->length)) {
Steve French13a6e422008-12-02 17:24:33 +0000927 stored_rc = CIFSSMBLock(xid, tcon,
Steve Frenchfb8c4b12007-07-10 01:16:18 +0000928 netfid,
Jeremy Allison7ee1af72006-08-02 21:56:33 +0000929 li->length, li->offset,
Steve French4b18f2a2008-04-29 00:06:05 +0000930 1, 0, li->type, false);
Jeremy Allison7ee1af72006-08-02 21:56:33 +0000931 if (stored_rc)
932 rc = stored_rc;
933
934 list_del(&li->llist);
935 kfree(li);
936 }
937 }
Roland Dreier796e5662007-05-03 04:33:45 +0000938 mutex_unlock(&fid->lock_mutex);
Jeremy Allison7ee1af72006-08-02 21:56:33 +0000939 }
940 }
941
Steve Frenchd634cc12005-08-26 14:42:59 -0500942 if (pfLock->fl_flags & FL_POSIX)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700943 posix_lock_file_wait(file, pfLock);
944 FreeXid(xid);
945 return rc;
946}
947
Jeff Laytonfbec9ab2009-04-03 13:44:00 -0400948/*
949 * Set the timeout on write requests past EOF. For some servers (Windows)
950 * these calls can be very long.
951 *
952 * If we're writing >10M past the EOF we give a 180s timeout. Anything less
953 * than that gets a 45s timeout. Writes not past EOF get 15s timeouts.
954 * The 10M cutoff is totally arbitrary. A better scheme for this would be
955 * welcome if someone wants to suggest one.
956 *
957 * We may be able to do a better job with this if there were some way to
958 * declare that a file should be sparse.
959 */
960static int
961cifs_write_timeout(struct cifsInodeInfo *cifsi, loff_t offset)
962{
963 if (offset <= cifsi->server_eof)
964 return CIFS_STD_OP;
965 else if (offset > (cifsi->server_eof + (10 * 1024 * 1024)))
966 return CIFS_VLONG_OP;
967 else
968 return CIFS_LONG_OP;
969}
970
971/* update the file size (if needed) after a write */
972static void
973cifs_update_eof(struct cifsInodeInfo *cifsi, loff_t offset,
974 unsigned int bytes_written)
975{
976 loff_t end_of_write = offset + bytes_written;
977
978 if (end_of_write > cifsi->server_eof)
979 cifsi->server_eof = end_of_write;
980}
981
Linus Torvalds1da177e2005-04-16 15:20:36 -0700982ssize_t cifs_user_write(struct file *file, const char __user *write_data,
983 size_t write_size, loff_t *poffset)
984{
985 int rc = 0;
986 unsigned int bytes_written = 0;
987 unsigned int total_written;
988 struct cifs_sb_info *cifs_sb;
989 struct cifsTconInfo *pTcon;
990 int xid, long_op;
991 struct cifsFileInfo *open_file;
Jeff Laytonfbec9ab2009-04-03 13:44:00 -0400992 struct cifsInodeInfo *cifsi = CIFS_I(file->f_path.dentry->d_inode);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700993
Josef "Jeff" Sipeke6a00292006-12-08 02:36:48 -0800994 cifs_sb = CIFS_SB(file->f_path.dentry->d_sb);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700995
996 pTcon = cifs_sb->tcon;
997
998 /* cFYI(1,
999 (" write %d bytes to offset %lld of %s", write_size,
Josef "Jeff" Sipeke6a00292006-12-08 02:36:48 -08001000 *poffset, file->f_path.dentry->d_name.name)); */
Linus Torvalds1da177e2005-04-16 15:20:36 -07001001
1002 if (file->private_data == NULL)
1003 return -EBADF;
Christoph Hellwigc33f8d32007-04-02 18:47:20 +00001004 open_file = (struct cifsFileInfo *) file->private_data;
Steve French50c2f752007-07-13 00:33:32 +00001005
Jeff Layton838726c2008-08-28 07:54:59 -04001006 rc = generic_write_checks(file, poffset, &write_size, 0);
1007 if (rc)
1008 return rc;
1009
Linus Torvalds1da177e2005-04-16 15:20:36 -07001010 xid = GetXid();
Linus Torvalds1da177e2005-04-16 15:20:36 -07001011
Jeff Laytonfbec9ab2009-04-03 13:44:00 -04001012 long_op = cifs_write_timeout(cifsi, *poffset);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001013 for (total_written = 0; write_size > total_written;
1014 total_written += bytes_written) {
1015 rc = -EAGAIN;
1016 while (rc == -EAGAIN) {
1017 if (file->private_data == NULL) {
1018 /* file has been closed on us */
1019 FreeXid(xid);
1020 /* if we have gotten here we have written some data
1021 and blocked, and the file has been freed on us while
1022 we blocked so return what we managed to write */
1023 return total_written;
Steve Frenchfb8c4b12007-07-10 01:16:18 +00001024 }
Linus Torvalds1da177e2005-04-16 15:20:36 -07001025 if (open_file->closePend) {
1026 FreeXid(xid);
1027 if (total_written)
1028 return total_written;
1029 else
1030 return -EBADF;
1031 }
1032 if (open_file->invalidHandle) {
Linus Torvalds1da177e2005-04-16 15:20:36 -07001033 /* we could deadlock if we called
1034 filemap_fdatawait from here so tell
1035 reopen_file not to flush data to server
1036 now */
Steve French4b18f2a2008-04-29 00:06:05 +00001037 rc = cifs_reopen_file(file, false);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001038 if (rc != 0)
1039 break;
1040 }
1041
1042 rc = CIFSSMBWrite(xid, pTcon,
1043 open_file->netfid,
1044 min_t(const int, cifs_sb->wsize,
1045 write_size - total_written),
1046 *poffset, &bytes_written,
1047 NULL, write_data + total_written, long_op);
1048 }
1049 if (rc || (bytes_written == 0)) {
1050 if (total_written)
1051 break;
1052 else {
1053 FreeXid(xid);
1054 return rc;
1055 }
Jeff Laytonfbec9ab2009-04-03 13:44:00 -04001056 } else {
1057 cifs_update_eof(cifsi, *poffset, bytes_written);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001058 *poffset += bytes_written;
Jeff Laytonfbec9ab2009-04-03 13:44:00 -04001059 }
Steve French133672e2007-11-13 22:41:37 +00001060 long_op = CIFS_STD_OP; /* subsequent writes fast -
Linus Torvalds1da177e2005-04-16 15:20:36 -07001061 15 seconds is plenty */
1062 }
1063
Steve Frencha4544342005-08-24 13:59:35 -07001064 cifs_stats_bytes_written(pTcon, total_written);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001065
1066 /* since the write may have blocked check these pointers again */
Steve French3677db12007-02-26 16:46:11 +00001067 if ((file->f_path.dentry) && (file->f_path.dentry->d_inode)) {
1068 struct inode *inode = file->f_path.dentry->d_inode;
Steve Frenchfb8c4b12007-07-10 01:16:18 +00001069/* Do not update local mtime - server will set its actual value on write
1070 * inode->i_ctime = inode->i_mtime =
Steve French3677db12007-02-26 16:46:11 +00001071 * current_fs_time(inode->i_sb);*/
1072 if (total_written > 0) {
1073 spin_lock(&inode->i_lock);
1074 if (*poffset > file->f_path.dentry->d_inode->i_size)
1075 i_size_write(file->f_path.dentry->d_inode,
Linus Torvalds1da177e2005-04-16 15:20:36 -07001076 *poffset);
Steve French3677db12007-02-26 16:46:11 +00001077 spin_unlock(&inode->i_lock);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001078 }
Steve Frenchfb8c4b12007-07-10 01:16:18 +00001079 mark_inode_dirty_sync(file->f_path.dentry->d_inode);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001080 }
1081 FreeXid(xid);
1082 return total_written;
1083}
1084
1085static ssize_t cifs_write(struct file *file, const char *write_data,
Nick Piggind9414772008-09-24 11:32:59 -04001086 size_t write_size, loff_t *poffset)
Linus Torvalds1da177e2005-04-16 15:20:36 -07001087{
1088 int rc = 0;
1089 unsigned int bytes_written = 0;
1090 unsigned int total_written;
1091 struct cifs_sb_info *cifs_sb;
1092 struct cifsTconInfo *pTcon;
1093 int xid, long_op;
1094 struct cifsFileInfo *open_file;
Jeff Laytonfbec9ab2009-04-03 13:44:00 -04001095 struct cifsInodeInfo *cifsi = CIFS_I(file->f_path.dentry->d_inode);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001096
Josef "Jeff" Sipeke6a00292006-12-08 02:36:48 -08001097 cifs_sb = CIFS_SB(file->f_path.dentry->d_sb);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001098
1099 pTcon = cifs_sb->tcon;
1100
Steve Frenchfb8c4b12007-07-10 01:16:18 +00001101 cFYI(1, ("write %zd bytes to offset %lld of %s", write_size,
Josef "Jeff" Sipeke6a00292006-12-08 02:36:48 -08001102 *poffset, file->f_path.dentry->d_name.name));
Linus Torvalds1da177e2005-04-16 15:20:36 -07001103
1104 if (file->private_data == NULL)
1105 return -EBADF;
Christoph Hellwigc33f8d32007-04-02 18:47:20 +00001106 open_file = (struct cifsFileInfo *)file->private_data;
Steve French50c2f752007-07-13 00:33:32 +00001107
Linus Torvalds1da177e2005-04-16 15:20:36 -07001108 xid = GetXid();
Linus Torvalds1da177e2005-04-16 15:20:36 -07001109
Jeff Laytonfbec9ab2009-04-03 13:44:00 -04001110 long_op = cifs_write_timeout(cifsi, *poffset);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001111 for (total_written = 0; write_size > total_written;
1112 total_written += bytes_written) {
1113 rc = -EAGAIN;
1114 while (rc == -EAGAIN) {
1115 if (file->private_data == NULL) {
1116 /* file has been closed on us */
1117 FreeXid(xid);
1118 /* if we have gotten here we have written some data
1119 and blocked, and the file has been freed on us
Steve Frenchfb8c4b12007-07-10 01:16:18 +00001120 while we blocked so return what we managed to
Linus Torvalds1da177e2005-04-16 15:20:36 -07001121 write */
1122 return total_written;
Steve Frenchfb8c4b12007-07-10 01:16:18 +00001123 }
Linus Torvalds1da177e2005-04-16 15:20:36 -07001124 if (open_file->closePend) {
1125 FreeXid(xid);
1126 if (total_written)
1127 return total_written;
1128 else
1129 return -EBADF;
1130 }
1131 if (open_file->invalidHandle) {
Linus Torvalds1da177e2005-04-16 15:20:36 -07001132 /* we could deadlock if we called
1133 filemap_fdatawait from here so tell
Steve Frenchfb8c4b12007-07-10 01:16:18 +00001134 reopen_file not to flush data to
Linus Torvalds1da177e2005-04-16 15:20:36 -07001135 server now */
Steve French4b18f2a2008-04-29 00:06:05 +00001136 rc = cifs_reopen_file(file, false);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001137 if (rc != 0)
1138 break;
1139 }
Steve Frenchfb8c4b12007-07-10 01:16:18 +00001140 if (experimEnabled || (pTcon->ses->server &&
1141 ((pTcon->ses->server->secMode &
Steve French08775832006-05-30 18:08:26 +00001142 (SECMODE_SIGN_REQUIRED | SECMODE_SIGN_ENABLED))
Steve Frenchc01f36a2006-05-30 18:05:10 +00001143 == 0))) {
Steve French3e844692005-10-03 13:37:24 -07001144 struct kvec iov[2];
1145 unsigned int len;
1146
Steve French0ae0efa2005-10-10 10:57:19 -07001147 len = min((size_t)cifs_sb->wsize,
Steve French3e844692005-10-03 13:37:24 -07001148 write_size - total_written);
1149 /* iov[0] is reserved for smb header */
1150 iov[1].iov_base = (char *)write_data +
1151 total_written;
1152 iov[1].iov_len = len;
Steve Frenchd6e04ae2005-06-13 13:24:43 -05001153 rc = CIFSSMBWrite2(xid, pTcon,
Steve French3e844692005-10-03 13:37:24 -07001154 open_file->netfid, len,
Steve Frenchd6e04ae2005-06-13 13:24:43 -05001155 *poffset, &bytes_written,
Steve French3e844692005-10-03 13:37:24 -07001156 iov, 1, long_op);
Steve Frenchd6e04ae2005-06-13 13:24:43 -05001157 } else
Steve French60808232006-04-22 15:53:05 +00001158 rc = CIFSSMBWrite(xid, pTcon,
1159 open_file->netfid,
1160 min_t(const int, cifs_sb->wsize,
1161 write_size - total_written),
1162 *poffset, &bytes_written,
1163 write_data + total_written,
1164 NULL, long_op);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001165 }
1166 if (rc || (bytes_written == 0)) {
1167 if (total_written)
1168 break;
1169 else {
1170 FreeXid(xid);
1171 return rc;
1172 }
Jeff Laytonfbec9ab2009-04-03 13:44:00 -04001173 } else {
1174 cifs_update_eof(cifsi, *poffset, bytes_written);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001175 *poffset += bytes_written;
Jeff Laytonfbec9ab2009-04-03 13:44:00 -04001176 }
Steve French133672e2007-11-13 22:41:37 +00001177 long_op = CIFS_STD_OP; /* subsequent writes fast -
Linus Torvalds1da177e2005-04-16 15:20:36 -07001178 15 seconds is plenty */
1179 }
1180
Steve Frencha4544342005-08-24 13:59:35 -07001181 cifs_stats_bytes_written(pTcon, total_written);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001182
1183 /* since the write may have blocked check these pointers again */
Steve French3677db12007-02-26 16:46:11 +00001184 if ((file->f_path.dentry) && (file->f_path.dentry->d_inode)) {
Steve French004c46b2007-02-17 04:34:13 +00001185/*BB We could make this contingent on superblock ATIME flag too */
Steve French3677db12007-02-26 16:46:11 +00001186/* file->f_path.dentry->d_inode->i_ctime =
1187 file->f_path.dentry->d_inode->i_mtime = CURRENT_TIME;*/
1188 if (total_written > 0) {
1189 spin_lock(&file->f_path.dentry->d_inode->i_lock);
1190 if (*poffset > file->f_path.dentry->d_inode->i_size)
1191 i_size_write(file->f_path.dentry->d_inode,
1192 *poffset);
1193 spin_unlock(&file->f_path.dentry->d_inode->i_lock);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001194 }
Steve French3677db12007-02-26 16:46:11 +00001195 mark_inode_dirty_sync(file->f_path.dentry->d_inode);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001196 }
1197 FreeXid(xid);
1198 return total_written;
1199}
1200
Steve French630f3f0c2007-10-25 21:17:17 +00001201#ifdef CONFIG_CIFS_EXPERIMENTAL
1202struct cifsFileInfo *find_readable_file(struct cifsInodeInfo *cifs_inode)
1203{
1204 struct cifsFileInfo *open_file = NULL;
1205
1206 read_lock(&GlobalSMBSeslock);
1207 /* we could simply get the first_list_entry since write-only entries
1208 are always at the end of the list but since the first entry might
1209 have a close pending, we go through the whole list */
1210 list_for_each_entry(open_file, &cifs_inode->openFileList, flist) {
1211 if (open_file->closePend)
1212 continue;
1213 if (open_file->pfile && ((open_file->pfile->f_flags & O_RDWR) ||
1214 (open_file->pfile->f_flags & O_RDONLY))) {
1215 if (!open_file->invalidHandle) {
1216 /* found a good file */
1217 /* lock it so it will not be closed on us */
Dave Kleikamp6ab409b2009-08-31 11:07:12 -04001218 cifsFileInfo_get(open_file);
Steve French630f3f0c2007-10-25 21:17:17 +00001219 read_unlock(&GlobalSMBSeslock);
1220 return open_file;
1221 } /* else might as well continue, and look for
1222 another, or simply have the caller reopen it
1223 again rather than trying to fix this handle */
1224 } else /* write only file */
1225 break; /* write only files are last so must be done */
1226 }
1227 read_unlock(&GlobalSMBSeslock);
1228 return NULL;
1229}
1230#endif
1231
Steve Frenchdd99cd82005-10-05 19:32:49 -07001232struct cifsFileInfo *find_writable_file(struct cifsInodeInfo *cifs_inode)
Steve French6148a742005-10-05 12:23:19 -07001233{
1234 struct cifsFileInfo *open_file;
Jeff Layton2846d382008-09-22 21:33:33 -04001235 bool any_available = false;
Steve Frenchdd99cd82005-10-05 19:32:49 -07001236 int rc;
Steve French6148a742005-10-05 12:23:19 -07001237
Steve French60808232006-04-22 15:53:05 +00001238 /* Having a null inode here (because mapping->host was set to zero by
1239 the VFS or MM) should not happen but we had reports of on oops (due to
1240 it being zero) during stress testcases so we need to check for it */
1241
Steve Frenchfb8c4b12007-07-10 01:16:18 +00001242 if (cifs_inode == NULL) {
1243 cERROR(1, ("Null inode passed to cifs_writeable_file"));
Steve French60808232006-04-22 15:53:05 +00001244 dump_stack();
1245 return NULL;
1246 }
1247
Steve French6148a742005-10-05 12:23:19 -07001248 read_lock(&GlobalSMBSeslock);
Steve French9b22b0b2007-10-02 01:11:08 +00001249refind_writable:
Steve French6148a742005-10-05 12:23:19 -07001250 list_for_each_entry(open_file, &cifs_inode->openFileList, flist) {
Jeff Layton2846d382008-09-22 21:33:33 -04001251 if (open_file->closePend ||
1252 (!any_available && open_file->pid != current->tgid))
Steve French6148a742005-10-05 12:23:19 -07001253 continue;
Jeff Layton2846d382008-09-22 21:33:33 -04001254
Steve French6148a742005-10-05 12:23:19 -07001255 if (open_file->pfile &&
1256 ((open_file->pfile->f_flags & O_RDWR) ||
1257 (open_file->pfile->f_flags & O_WRONLY))) {
Dave Kleikamp6ab409b2009-08-31 11:07:12 -04001258 cifsFileInfo_get(open_file);
Steve French9b22b0b2007-10-02 01:11:08 +00001259
1260 if (!open_file->invalidHandle) {
1261 /* found a good writable file */
1262 read_unlock(&GlobalSMBSeslock);
1263 return open_file;
1264 }
Steve French8840dee2007-11-16 23:05:52 +00001265
Steve French6148a742005-10-05 12:23:19 -07001266 read_unlock(&GlobalSMBSeslock);
Steve French9b22b0b2007-10-02 01:11:08 +00001267 /* Had to unlock since following call can block */
Steve French4b18f2a2008-04-29 00:06:05 +00001268 rc = cifs_reopen_file(open_file->pfile, false);
Steve French8840dee2007-11-16 23:05:52 +00001269 if (!rc) {
Steve French9b22b0b2007-10-02 01:11:08 +00001270 if (!open_file->closePend)
1271 return open_file;
1272 else { /* start over in case this was deleted */
1273 /* since the list could be modified */
Steve French37c0eb42005-10-05 14:50:29 -07001274 read_lock(&GlobalSMBSeslock);
Dave Kleikamp6ab409b2009-08-31 11:07:12 -04001275 cifsFileInfo_put(open_file);
Steve French9b22b0b2007-10-02 01:11:08 +00001276 goto refind_writable;
Steve French37c0eb42005-10-05 14:50:29 -07001277 }
1278 }
Steve French9b22b0b2007-10-02 01:11:08 +00001279
1280 /* if it fails, try another handle if possible -
1281 (we can not do this if closePending since
1282 loop could be modified - in which case we
1283 have to start at the beginning of the list
1284 again. Note that it would be bad
1285 to hold up writepages here (rather than
1286 in caller) with continuous retries */
1287 cFYI(1, ("wp failed on reopen file"));
1288 read_lock(&GlobalSMBSeslock);
1289 /* can not use this handle, no write
1290 pending on this one after all */
Dave Kleikamp6ab409b2009-08-31 11:07:12 -04001291 cifsFileInfo_put(open_file);
Steve French8840dee2007-11-16 23:05:52 +00001292
Steve French9b22b0b2007-10-02 01:11:08 +00001293 if (open_file->closePend) /* list could have changed */
1294 goto refind_writable;
1295 /* else we simply continue to the next entry. Thus
1296 we do not loop on reopen errors. If we
1297 can not reopen the file, for example if we
1298 reconnected to a server with another client
1299 racing to delete or lock the file we would not
1300 make progress if we restarted before the beginning
1301 of the loop here. */
Steve French6148a742005-10-05 12:23:19 -07001302 }
1303 }
Jeff Layton2846d382008-09-22 21:33:33 -04001304 /* couldn't find useable FH with same pid, try any available */
1305 if (!any_available) {
1306 any_available = true;
1307 goto refind_writable;
1308 }
Steve French6148a742005-10-05 12:23:19 -07001309 read_unlock(&GlobalSMBSeslock);
1310 return NULL;
1311}
1312
Linus Torvalds1da177e2005-04-16 15:20:36 -07001313static int cifs_partialpagewrite(struct page *page, unsigned from, unsigned to)
1314{
1315 struct address_space *mapping = page->mapping;
1316 loff_t offset = (loff_t)page->index << PAGE_CACHE_SHIFT;
1317 char *write_data;
1318 int rc = -EFAULT;
1319 int bytes_written = 0;
1320 struct cifs_sb_info *cifs_sb;
1321 struct cifsTconInfo *pTcon;
1322 struct inode *inode;
Steve French6148a742005-10-05 12:23:19 -07001323 struct cifsFileInfo *open_file;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001324
1325 if (!mapping || !mapping->host)
1326 return -EFAULT;
1327
1328 inode = page->mapping->host;
1329 cifs_sb = CIFS_SB(inode->i_sb);
1330 pTcon = cifs_sb->tcon;
1331
1332 offset += (loff_t)from;
1333 write_data = kmap(page);
1334 write_data += from;
1335
1336 if ((to > PAGE_CACHE_SIZE) || (from > to)) {
1337 kunmap(page);
1338 return -EIO;
1339 }
1340
1341 /* racing with truncate? */
1342 if (offset > mapping->host->i_size) {
1343 kunmap(page);
1344 return 0; /* don't care */
1345 }
1346
1347 /* check to make sure that we are not extending the file */
1348 if (mapping->host->i_size - offset < (loff_t)to)
Steve Frenchfb8c4b12007-07-10 01:16:18 +00001349 to = (unsigned)(mapping->host->i_size - offset);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001350
Steve French6148a742005-10-05 12:23:19 -07001351 open_file = find_writable_file(CIFS_I(mapping->host));
1352 if (open_file) {
1353 bytes_written = cifs_write(open_file->pfile, write_data,
1354 to-from, &offset);
Dave Kleikamp6ab409b2009-08-31 11:07:12 -04001355 cifsFileInfo_put(open_file);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001356 /* Does mm or vfs already set times? */
Steve French6148a742005-10-05 12:23:19 -07001357 inode->i_atime = inode->i_mtime = current_fs_time(inode->i_sb);
Steve Frenchbb5a9a02007-12-31 04:21:29 +00001358 if ((bytes_written > 0) && (offset))
Steve French6148a742005-10-05 12:23:19 -07001359 rc = 0;
Steve Frenchbb5a9a02007-12-31 04:21:29 +00001360 else if (bytes_written < 0)
1361 rc = bytes_written;
Steve French6148a742005-10-05 12:23:19 -07001362 } else {
Linus Torvalds1da177e2005-04-16 15:20:36 -07001363 cFYI(1, ("No writeable filehandles for inode"));
1364 rc = -EIO;
1365 }
1366
1367 kunmap(page);
1368 return rc;
1369}
1370
Linus Torvalds1da177e2005-04-16 15:20:36 -07001371static int cifs_writepages(struct address_space *mapping,
Steve French37c0eb42005-10-05 14:50:29 -07001372 struct writeback_control *wbc)
Linus Torvalds1da177e2005-04-16 15:20:36 -07001373{
Steve French37c0eb42005-10-05 14:50:29 -07001374 struct backing_dev_info *bdi = mapping->backing_dev_info;
1375 unsigned int bytes_to_write;
1376 unsigned int bytes_written;
1377 struct cifs_sb_info *cifs_sb;
1378 int done = 0;
OGAWA Hirofumi111ebb62006-06-23 02:03:26 -07001379 pgoff_t end;
Steve French37c0eb42005-10-05 14:50:29 -07001380 pgoff_t index;
Steve Frenchfb8c4b12007-07-10 01:16:18 +00001381 int range_whole = 0;
1382 struct kvec *iov;
Steve French84d2f072005-10-12 15:32:05 -07001383 int len;
Steve French37c0eb42005-10-05 14:50:29 -07001384 int n_iov = 0;
1385 pgoff_t next;
1386 int nr_pages;
1387 __u64 offset = 0;
Steve French23e7dd72005-10-20 13:44:56 -07001388 struct cifsFileInfo *open_file;
Jeff Laytonfbec9ab2009-04-03 13:44:00 -04001389 struct cifsInodeInfo *cifsi = CIFS_I(mapping->host);
Steve French37c0eb42005-10-05 14:50:29 -07001390 struct page *page;
1391 struct pagevec pvec;
1392 int rc = 0;
1393 int scanned = 0;
Jeff Laytonfbec9ab2009-04-03 13:44:00 -04001394 int xid, long_op;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001395
Steve French37c0eb42005-10-05 14:50:29 -07001396 cifs_sb = CIFS_SB(mapping->host->i_sb);
Steve French50c2f752007-07-13 00:33:32 +00001397
Steve French37c0eb42005-10-05 14:50:29 -07001398 /*
1399 * If wsize is smaller that the page cache size, default to writing
1400 * one page at a time via cifs_writepage
1401 */
1402 if (cifs_sb->wsize < PAGE_CACHE_SIZE)
1403 return generic_writepages(mapping, wbc);
1404
Steve Frenchfb8c4b12007-07-10 01:16:18 +00001405 if ((cifs_sb->tcon->ses) && (cifs_sb->tcon->ses->server))
1406 if (cifs_sb->tcon->ses->server->secMode &
1407 (SECMODE_SIGN_REQUIRED | SECMODE_SIGN_ENABLED))
1408 if (!experimEnabled)
Steve French60808232006-04-22 15:53:05 +00001409 return generic_writepages(mapping, wbc);
Steve French4a771182005-10-05 15:14:33 -07001410
Steve French9a0c8232007-02-02 04:21:57 +00001411 iov = kmalloc(32 * sizeof(struct kvec), GFP_KERNEL);
Steve Frenchfb8c4b12007-07-10 01:16:18 +00001412 if (iov == NULL)
Steve French9a0c8232007-02-02 04:21:57 +00001413 return generic_writepages(mapping, wbc);
1414
1415
Steve French37c0eb42005-10-05 14:50:29 -07001416 /*
1417 * BB: Is this meaningful for a non-block-device file system?
1418 * If it is, we should test it again after we do I/O
1419 */
1420 if (wbc->nonblocking && bdi_write_congested(bdi)) {
1421 wbc->encountered_congestion = 1;
Steve French9a0c8232007-02-02 04:21:57 +00001422 kfree(iov);
Steve French37c0eb42005-10-05 14:50:29 -07001423 return 0;
1424 }
1425
Linus Torvalds1da177e2005-04-16 15:20:36 -07001426 xid = GetXid();
1427
Steve French37c0eb42005-10-05 14:50:29 -07001428 pagevec_init(&pvec, 0);
OGAWA Hirofumi111ebb62006-06-23 02:03:26 -07001429 if (wbc->range_cyclic) {
Steve French37c0eb42005-10-05 14:50:29 -07001430 index = mapping->writeback_index; /* Start from prev offset */
OGAWA Hirofumi111ebb62006-06-23 02:03:26 -07001431 end = -1;
1432 } else {
1433 index = wbc->range_start >> PAGE_CACHE_SHIFT;
1434 end = wbc->range_end >> PAGE_CACHE_SHIFT;
1435 if (wbc->range_start == 0 && wbc->range_end == LLONG_MAX)
1436 range_whole = 1;
Steve French37c0eb42005-10-05 14:50:29 -07001437 scanned = 1;
1438 }
1439retry:
1440 while (!done && (index <= end) &&
1441 (nr_pages = pagevec_lookup_tag(&pvec, mapping, &index,
1442 PAGECACHE_TAG_DIRTY,
1443 min(end - index, (pgoff_t)PAGEVEC_SIZE - 1) + 1))) {
1444 int first;
1445 unsigned int i;
1446
Steve French37c0eb42005-10-05 14:50:29 -07001447 first = -1;
1448 next = 0;
1449 n_iov = 0;
1450 bytes_to_write = 0;
1451
1452 for (i = 0; i < nr_pages; i++) {
1453 page = pvec.pages[i];
1454 /*
1455 * At this point we hold neither mapping->tree_lock nor
1456 * lock on the page itself: the page may be truncated or
1457 * invalidated (changing page->mapping to NULL), or even
1458 * swizzled back from swapper_space to tmpfs file
1459 * mapping
1460 */
1461
1462 if (first < 0)
1463 lock_page(page);
Nick Piggin529ae9a2008-08-02 12:01:03 +02001464 else if (!trylock_page(page))
Steve French37c0eb42005-10-05 14:50:29 -07001465 break;
1466
1467 if (unlikely(page->mapping != mapping)) {
1468 unlock_page(page);
1469 break;
1470 }
1471
OGAWA Hirofumi111ebb62006-06-23 02:03:26 -07001472 if (!wbc->range_cyclic && page->index > end) {
Steve French37c0eb42005-10-05 14:50:29 -07001473 done = 1;
1474 unlock_page(page);
1475 break;
1476 }
1477
1478 if (next && (page->index != next)) {
1479 /* Not next consecutive page */
1480 unlock_page(page);
1481 break;
1482 }
1483
1484 if (wbc->sync_mode != WB_SYNC_NONE)
1485 wait_on_page_writeback(page);
1486
1487 if (PageWriteback(page) ||
Linus Torvaldscb876f42006-12-23 16:19:07 -08001488 !clear_page_dirty_for_io(page)) {
Steve French37c0eb42005-10-05 14:50:29 -07001489 unlock_page(page);
1490 break;
1491 }
Steve French84d2f072005-10-12 15:32:05 -07001492
Linus Torvaldscb876f42006-12-23 16:19:07 -08001493 /*
1494 * This actually clears the dirty bit in the radix tree.
1495 * See cifs_writepage() for more commentary.
1496 */
1497 set_page_writeback(page);
1498
Steve French84d2f072005-10-12 15:32:05 -07001499 if (page_offset(page) >= mapping->host->i_size) {
1500 done = 1;
1501 unlock_page(page);
Linus Torvaldscb876f42006-12-23 16:19:07 -08001502 end_page_writeback(page);
Steve French84d2f072005-10-12 15:32:05 -07001503 break;
1504 }
1505
Steve French37c0eb42005-10-05 14:50:29 -07001506 /*
1507 * BB can we get rid of this? pages are held by pvec
1508 */
1509 page_cache_get(page);
1510
Steve French84d2f072005-10-12 15:32:05 -07001511 len = min(mapping->host->i_size - page_offset(page),
1512 (loff_t)PAGE_CACHE_SIZE);
1513
Steve French37c0eb42005-10-05 14:50:29 -07001514 /* reserve iov[0] for the smb header */
1515 n_iov++;
1516 iov[n_iov].iov_base = kmap(page);
Steve French84d2f072005-10-12 15:32:05 -07001517 iov[n_iov].iov_len = len;
1518 bytes_to_write += len;
Steve French37c0eb42005-10-05 14:50:29 -07001519
1520 if (first < 0) {
1521 first = i;
1522 offset = page_offset(page);
1523 }
1524 next = page->index + 1;
1525 if (bytes_to_write + PAGE_CACHE_SIZE > cifs_sb->wsize)
1526 break;
1527 }
1528 if (n_iov) {
Steve French23e7dd72005-10-20 13:44:56 -07001529 /* Search for a writable handle every time we call
1530 * CIFSSMBWrite2. We can't rely on the last handle
1531 * we used to still be valid
1532 */
1533 open_file = find_writable_file(CIFS_I(mapping->host));
1534 if (!open_file) {
1535 cERROR(1, ("No writable handles for inode"));
1536 rc = -EBADF;
Steve French1047abc2005-10-11 19:58:06 -07001537 } else {
Jeff Laytonfbec9ab2009-04-03 13:44:00 -04001538 long_op = cifs_write_timeout(cifsi, offset);
Steve French23e7dd72005-10-20 13:44:56 -07001539 rc = CIFSSMBWrite2(xid, cifs_sb->tcon,
1540 open_file->netfid,
1541 bytes_to_write, offset,
1542 &bytes_written, iov, n_iov,
Jeff Laytonfbec9ab2009-04-03 13:44:00 -04001543 long_op);
Dave Kleikamp6ab409b2009-08-31 11:07:12 -04001544 cifsFileInfo_put(open_file);
Jeff Laytonfbec9ab2009-04-03 13:44:00 -04001545 cifs_update_eof(cifsi, offset, bytes_written);
1546
Steve French23e7dd72005-10-20 13:44:56 -07001547 if (rc || bytes_written < bytes_to_write) {
Steve French63135e02007-07-17 17:34:02 +00001548 cERROR(1, ("Write2 ret %d, wrote %d",
Steve French23e7dd72005-10-20 13:44:56 -07001549 rc, bytes_written));
1550 /* BB what if continued retry is
1551 requested via mount flags? */
Jeff Laytoncea21802007-11-20 23:19:03 +00001552 if (rc == -ENOSPC)
1553 set_bit(AS_ENOSPC, &mapping->flags);
1554 else
1555 set_bit(AS_EIO, &mapping->flags);
Steve French23e7dd72005-10-20 13:44:56 -07001556 } else {
1557 cifs_stats_bytes_written(cifs_sb->tcon,
1558 bytes_written);
1559 }
Steve French37c0eb42005-10-05 14:50:29 -07001560 }
1561 for (i = 0; i < n_iov; i++) {
1562 page = pvec.pages[first + i];
Steve Frencheb9bdaa2006-01-27 15:11:47 -08001563 /* Should we also set page error on
1564 success rc but too little data written? */
1565 /* BB investigate retry logic on temporary
1566 server crash cases and how recovery works
Steve Frenchfb8c4b12007-07-10 01:16:18 +00001567 when page marked as error */
1568 if (rc)
Steve Frencheb9bdaa2006-01-27 15:11:47 -08001569 SetPageError(page);
Steve French37c0eb42005-10-05 14:50:29 -07001570 kunmap(page);
1571 unlock_page(page);
Linus Torvaldscb876f42006-12-23 16:19:07 -08001572 end_page_writeback(page);
Steve French37c0eb42005-10-05 14:50:29 -07001573 page_cache_release(page);
1574 }
1575 if ((wbc->nr_to_write -= n_iov) <= 0)
1576 done = 1;
1577 index = next;
Dave Kleikampb066a482008-11-18 03:49:05 +00001578 } else
1579 /* Need to re-find the pages we skipped */
1580 index = pvec.pages[0]->index + 1;
1581
Steve French37c0eb42005-10-05 14:50:29 -07001582 pagevec_release(&pvec);
1583 }
1584 if (!scanned && !done) {
1585 /*
1586 * We hit the last page and there is more work to be done: wrap
1587 * back to the start of the file
1588 */
1589 scanned = 1;
1590 index = 0;
1591 goto retry;
1592 }
OGAWA Hirofumi111ebb62006-06-23 02:03:26 -07001593 if (wbc->range_cyclic || (range_whole && wbc->nr_to_write > 0))
Steve French37c0eb42005-10-05 14:50:29 -07001594 mapping->writeback_index = index;
1595
Linus Torvalds1da177e2005-04-16 15:20:36 -07001596 FreeXid(xid);
Steve French9a0c8232007-02-02 04:21:57 +00001597 kfree(iov);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001598 return rc;
1599}
Linus Torvalds1da177e2005-04-16 15:20:36 -07001600
Steve Frenchfb8c4b12007-07-10 01:16:18 +00001601static int cifs_writepage(struct page *page, struct writeback_control *wbc)
Linus Torvalds1da177e2005-04-16 15:20:36 -07001602{
1603 int rc = -EFAULT;
1604 int xid;
1605
1606 xid = GetXid();
1607/* BB add check for wbc flags */
1608 page_cache_get(page);
Steve Frenchad7a2922008-02-07 23:25:02 +00001609 if (!PageUptodate(page))
Linus Torvalds1da177e2005-04-16 15:20:36 -07001610 cFYI(1, ("ppw - page not up to date"));
Linus Torvaldscb876f42006-12-23 16:19:07 -08001611
1612 /*
1613 * Set the "writeback" flag, and clear "dirty" in the radix tree.
1614 *
1615 * A writepage() implementation always needs to do either this,
1616 * or re-dirty the page with "redirty_page_for_writepage()" in
1617 * the case of a failure.
1618 *
1619 * Just unlocking the page will cause the radix tree tag-bits
1620 * to fail to update with the state of the page correctly.
1621 */
Steve Frenchfb8c4b12007-07-10 01:16:18 +00001622 set_page_writeback(page);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001623 rc = cifs_partialpagewrite(page, 0, PAGE_CACHE_SIZE);
1624 SetPageUptodate(page); /* BB add check for error and Clearuptodate? */
1625 unlock_page(page);
Linus Torvaldscb876f42006-12-23 16:19:07 -08001626 end_page_writeback(page);
1627 page_cache_release(page);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001628 FreeXid(xid);
1629 return rc;
1630}
1631
Nick Piggind9414772008-09-24 11:32:59 -04001632static int cifs_write_end(struct file *file, struct address_space *mapping,
1633 loff_t pos, unsigned len, unsigned copied,
1634 struct page *page, void *fsdata)
Linus Torvalds1da177e2005-04-16 15:20:36 -07001635{
Nick Piggind9414772008-09-24 11:32:59 -04001636 int rc;
1637 struct inode *inode = mapping->host;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001638
Nick Piggind9414772008-09-24 11:32:59 -04001639 cFYI(1, ("write_end for page %p from pos %lld with %d bytes",
1640 page, pos, copied));
Steve Frenchad7a2922008-02-07 23:25:02 +00001641
Jeff Laytona98ee8c2008-11-26 19:32:33 +00001642 if (PageChecked(page)) {
1643 if (copied == len)
1644 SetPageUptodate(page);
1645 ClearPageChecked(page);
1646 } else if (!PageUptodate(page) && copied == PAGE_CACHE_SIZE)
Nick Piggind9414772008-09-24 11:32:59 -04001647 SetPageUptodate(page);
1648
Linus Torvalds1da177e2005-04-16 15:20:36 -07001649 if (!PageUptodate(page)) {
Nick Piggind9414772008-09-24 11:32:59 -04001650 char *page_data;
1651 unsigned offset = pos & (PAGE_CACHE_SIZE - 1);
1652 int xid;
1653
1654 xid = GetXid();
Linus Torvalds1da177e2005-04-16 15:20:36 -07001655 /* this is probably better than directly calling
1656 partialpage_write since in this function the file handle is
1657 known which we might as well leverage */
1658 /* BB check if anything else missing out of ppw
1659 such as updating last write time */
1660 page_data = kmap(page);
Nick Piggind9414772008-09-24 11:32:59 -04001661 rc = cifs_write(file, page_data + offset, copied, &pos);
1662 /* if (rc < 0) should we set writebehind rc? */
Linus Torvalds1da177e2005-04-16 15:20:36 -07001663 kunmap(page);
Nick Piggind9414772008-09-24 11:32:59 -04001664
1665 FreeXid(xid);
Steve Frenchfb8c4b12007-07-10 01:16:18 +00001666 } else {
Nick Piggind9414772008-09-24 11:32:59 -04001667 rc = copied;
1668 pos += copied;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001669 set_page_dirty(page);
1670 }
1671
Nick Piggind9414772008-09-24 11:32:59 -04001672 if (rc > 0) {
1673 spin_lock(&inode->i_lock);
1674 if (pos > inode->i_size)
1675 i_size_write(inode, pos);
1676 spin_unlock(&inode->i_lock);
1677 }
1678
1679 unlock_page(page);
1680 page_cache_release(page);
1681
Linus Torvalds1da177e2005-04-16 15:20:36 -07001682 return rc;
1683}
1684
1685int cifs_fsync(struct file *file, struct dentry *dentry, int datasync)
1686{
1687 int xid;
1688 int rc = 0;
Steve Frenchb298f222009-02-21 21:17:43 +00001689 struct cifsTconInfo *tcon;
1690 struct cifsFileInfo *smbfile =
1691 (struct cifsFileInfo *)file->private_data;
Josef "Jeff" Sipeke6a00292006-12-08 02:36:48 -08001692 struct inode *inode = file->f_path.dentry->d_inode;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001693
1694 xid = GetXid();
1695
Steve Frenchfb8c4b12007-07-10 01:16:18 +00001696 cFYI(1, ("Sync file - name: %s datasync: 0x%x",
Linus Torvalds1da177e2005-04-16 15:20:36 -07001697 dentry->d_name.name, datasync));
Steve French50c2f752007-07-13 00:33:32 +00001698
Jeff Laytoncea21802007-11-20 23:19:03 +00001699 rc = filemap_write_and_wait(inode->i_mapping);
1700 if (rc == 0) {
1701 rc = CIFS_I(inode)->write_behind_rc;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001702 CIFS_I(inode)->write_behind_rc = 0;
Steve Frenchb298f222009-02-21 21:17:43 +00001703 tcon = CIFS_SB(inode->i_sb)->tcon;
Steve Frenchbe652442009-02-23 15:21:59 +00001704 if (!rc && tcon && smbfile &&
Steve French4717bed2009-02-24 14:44:19 +00001705 !(CIFS_SB(inode->i_sb)->mnt_cifs_flags & CIFS_MOUNT_NOSSYNC))
Steve Frenchb298f222009-02-21 21:17:43 +00001706 rc = CIFSSMBFlush(xid, tcon, smbfile->netfid);
Jeff Laytoncea21802007-11-20 23:19:03 +00001707 }
Steve Frenchb298f222009-02-21 21:17:43 +00001708
Linus Torvalds1da177e2005-04-16 15:20:36 -07001709 FreeXid(xid);
1710 return rc;
1711}
1712
NeilBrown3978d7172006-03-26 01:37:17 -08001713/* static void cifs_sync_page(struct page *page)
Linus Torvalds1da177e2005-04-16 15:20:36 -07001714{
1715 struct address_space *mapping;
1716 struct inode *inode;
1717 unsigned long index = page->index;
1718 unsigned int rpages = 0;
1719 int rc = 0;
1720
1721 cFYI(1, ("sync page %p",page));
1722 mapping = page->mapping;
1723 if (!mapping)
1724 return 0;
1725 inode = mapping->host;
1726 if (!inode)
NeilBrown3978d7172006-03-26 01:37:17 -08001727 return; */
Linus Torvalds1da177e2005-04-16 15:20:36 -07001728
Steve Frenchfb8c4b12007-07-10 01:16:18 +00001729/* fill in rpages then
Linus Torvalds1da177e2005-04-16 15:20:36 -07001730 result = cifs_pagein_inode(inode, index, rpages); */ /* BB finish */
1731
Steve French26a21b92006-05-31 18:05:34 +00001732/* cFYI(1, ("rpages is %d for sync page of Index %ld", rpages, index));
Linus Torvalds1da177e2005-04-16 15:20:36 -07001733
NeilBrown3978d7172006-03-26 01:37:17 -08001734#if 0
Linus Torvalds1da177e2005-04-16 15:20:36 -07001735 if (rc < 0)
1736 return rc;
1737 return 0;
NeilBrown3978d7172006-03-26 01:37:17 -08001738#endif
Linus Torvalds1da177e2005-04-16 15:20:36 -07001739} */
1740
1741/*
1742 * As file closes, flush all cached write data for this inode checking
1743 * for write behind errors.
1744 */
Miklos Szeredi75e1fcc2006-06-23 02:05:12 -07001745int cifs_flush(struct file *file, fl_owner_t id)
Linus Torvalds1da177e2005-04-16 15:20:36 -07001746{
Steve Frenchfb8c4b12007-07-10 01:16:18 +00001747 struct inode *inode = file->f_path.dentry->d_inode;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001748 int rc = 0;
1749
1750 /* Rather than do the steps manually:
1751 lock the inode for writing
1752 loop through pages looking for write behind data (dirty pages)
1753 coalesce into contiguous 16K (or smaller) chunks to write to server
1754 send to server (prefer in parallel)
1755 deal with writebehind errors
1756 unlock inode for writing
1757 filemapfdatawrite appears easier for the time being */
1758
1759 rc = filemap_fdatawrite(inode->i_mapping);
Jeff Laytoncea21802007-11-20 23:19:03 +00001760 /* reset wb rc if we were able to write out dirty pages */
1761 if (!rc) {
1762 rc = CIFS_I(inode)->write_behind_rc;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001763 CIFS_I(inode)->write_behind_rc = 0;
Jeff Laytoncea21802007-11-20 23:19:03 +00001764 }
Steve French50c2f752007-07-13 00:33:32 +00001765
Steve Frenchfb8c4b12007-07-10 01:16:18 +00001766 cFYI(1, ("Flush inode %p file %p rc %d", inode, file, rc));
Linus Torvalds1da177e2005-04-16 15:20:36 -07001767
1768 return rc;
1769}
1770
1771ssize_t cifs_user_read(struct file *file, char __user *read_data,
1772 size_t read_size, loff_t *poffset)
1773{
1774 int rc = -EACCES;
1775 unsigned int bytes_read = 0;
1776 unsigned int total_read = 0;
1777 unsigned int current_read_size;
1778 struct cifs_sb_info *cifs_sb;
1779 struct cifsTconInfo *pTcon;
1780 int xid;
1781 struct cifsFileInfo *open_file;
1782 char *smb_read_data;
1783 char __user *current_offset;
1784 struct smb_com_read_rsp *pSMBr;
1785
1786 xid = GetXid();
Josef "Jeff" Sipeke6a00292006-12-08 02:36:48 -08001787 cifs_sb = CIFS_SB(file->f_path.dentry->d_sb);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001788 pTcon = cifs_sb->tcon;
1789
1790 if (file->private_data == NULL) {
Suresh Jayaraman0f3bc092009-06-25 18:12:34 +05301791 rc = -EBADF;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001792 FreeXid(xid);
Suresh Jayaraman0f3bc092009-06-25 18:12:34 +05301793 return rc;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001794 }
1795 open_file = (struct cifsFileInfo *)file->private_data;
1796
Steve Frenchad7a2922008-02-07 23:25:02 +00001797 if ((file->f_flags & O_ACCMODE) == O_WRONLY)
Linus Torvalds1da177e2005-04-16 15:20:36 -07001798 cFYI(1, ("attempting read on write only file instance"));
Steve Frenchad7a2922008-02-07 23:25:02 +00001799
Linus Torvalds1da177e2005-04-16 15:20:36 -07001800 for (total_read = 0, current_offset = read_data;
1801 read_size > total_read;
1802 total_read += bytes_read, current_offset += bytes_read) {
Steve Frenchfb8c4b12007-07-10 01:16:18 +00001803 current_read_size = min_t(const int, read_size - total_read,
Linus Torvalds1da177e2005-04-16 15:20:36 -07001804 cifs_sb->rsize);
1805 rc = -EAGAIN;
1806 smb_read_data = NULL;
1807 while (rc == -EAGAIN) {
Steve Frenchec637e32005-12-12 20:53:18 -08001808 int buf_type = CIFS_NO_BUFFER;
Steve Frenchfb8c4b12007-07-10 01:16:18 +00001809 if ((open_file->invalidHandle) &&
Linus Torvalds1da177e2005-04-16 15:20:36 -07001810 (!open_file->closePend)) {
Steve French4b18f2a2008-04-29 00:06:05 +00001811 rc = cifs_reopen_file(file, true);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001812 if (rc != 0)
1813 break;
1814 }
Steve Frenchbfa0d752005-08-31 21:50:37 -07001815 rc = CIFSSMBRead(xid, pTcon,
Steve Frenchec637e32005-12-12 20:53:18 -08001816 open_file->netfid,
1817 current_read_size, *poffset,
1818 &bytes_read, &smb_read_data,
1819 &buf_type);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001820 pSMBr = (struct smb_com_read_rsp *)smb_read_data;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001821 if (smb_read_data) {
Steve French93544cc2006-02-14 22:30:52 -06001822 if (copy_to_user(current_offset,
1823 smb_read_data +
1824 4 /* RFC1001 length field */ +
1825 le16_to_cpu(pSMBr->DataOffset),
Steve Frenchad7a2922008-02-07 23:25:02 +00001826 bytes_read))
Steve French93544cc2006-02-14 22:30:52 -06001827 rc = -EFAULT;
Steve French93544cc2006-02-14 22:30:52 -06001828
Steve Frenchfb8c4b12007-07-10 01:16:18 +00001829 if (buf_type == CIFS_SMALL_BUFFER)
Steve Frenchec637e32005-12-12 20:53:18 -08001830 cifs_small_buf_release(smb_read_data);
Steve Frenchfb8c4b12007-07-10 01:16:18 +00001831 else if (buf_type == CIFS_LARGE_BUFFER)
Steve Frenchec637e32005-12-12 20:53:18 -08001832 cifs_buf_release(smb_read_data);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001833 smb_read_data = NULL;
1834 }
1835 }
1836 if (rc || (bytes_read == 0)) {
1837 if (total_read) {
1838 break;
1839 } else {
1840 FreeXid(xid);
1841 return rc;
1842 }
1843 } else {
Steve Frencha4544342005-08-24 13:59:35 -07001844 cifs_stats_bytes_read(pTcon, bytes_read);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001845 *poffset += bytes_read;
1846 }
1847 }
1848 FreeXid(xid);
1849 return total_read;
1850}
1851
1852
1853static ssize_t cifs_read(struct file *file, char *read_data, size_t read_size,
1854 loff_t *poffset)
1855{
1856 int rc = -EACCES;
1857 unsigned int bytes_read = 0;
1858 unsigned int total_read;
1859 unsigned int current_read_size;
1860 struct cifs_sb_info *cifs_sb;
1861 struct cifsTconInfo *pTcon;
1862 int xid;
1863 char *current_offset;
1864 struct cifsFileInfo *open_file;
Steve Frenchec637e32005-12-12 20:53:18 -08001865 int buf_type = CIFS_NO_BUFFER;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001866
1867 xid = GetXid();
Josef "Jeff" Sipeke6a00292006-12-08 02:36:48 -08001868 cifs_sb = CIFS_SB(file->f_path.dentry->d_sb);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001869 pTcon = cifs_sb->tcon;
1870
1871 if (file->private_data == NULL) {
Suresh Jayaraman0f3bc092009-06-25 18:12:34 +05301872 rc = -EBADF;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001873 FreeXid(xid);
Suresh Jayaraman0f3bc092009-06-25 18:12:34 +05301874 return rc;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001875 }
1876 open_file = (struct cifsFileInfo *)file->private_data;
1877
1878 if ((file->f_flags & O_ACCMODE) == O_WRONLY)
1879 cFYI(1, ("attempting read on write only file instance"));
1880
Steve Frenchfb8c4b12007-07-10 01:16:18 +00001881 for (total_read = 0, current_offset = read_data;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001882 read_size > total_read;
1883 total_read += bytes_read, current_offset += bytes_read) {
1884 current_read_size = min_t(const int, read_size - total_read,
1885 cifs_sb->rsize);
Steve Frenchf9f5c8172005-09-15 23:06:38 -07001886 /* For windows me and 9x we do not want to request more
1887 than it negotiated since it will refuse the read then */
Steve Frenchfb8c4b12007-07-10 01:16:18 +00001888 if ((pTcon->ses) &&
Steve Frenchf9f5c8172005-09-15 23:06:38 -07001889 !(pTcon->ses->capabilities & CAP_LARGE_FILES)) {
1890 current_read_size = min_t(const int, current_read_size,
1891 pTcon->ses->server->maxBuf - 128);
1892 }
Linus Torvalds1da177e2005-04-16 15:20:36 -07001893 rc = -EAGAIN;
1894 while (rc == -EAGAIN) {
Steve Frenchfb8c4b12007-07-10 01:16:18 +00001895 if ((open_file->invalidHandle) &&
Linus Torvalds1da177e2005-04-16 15:20:36 -07001896 (!open_file->closePend)) {
Steve French4b18f2a2008-04-29 00:06:05 +00001897 rc = cifs_reopen_file(file, true);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001898 if (rc != 0)
1899 break;
1900 }
Steve Frenchbfa0d752005-08-31 21:50:37 -07001901 rc = CIFSSMBRead(xid, pTcon,
Steve Frenchec637e32005-12-12 20:53:18 -08001902 open_file->netfid,
1903 current_read_size, *poffset,
1904 &bytes_read, &current_offset,
1905 &buf_type);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001906 }
1907 if (rc || (bytes_read == 0)) {
1908 if (total_read) {
1909 break;
1910 } else {
1911 FreeXid(xid);
1912 return rc;
1913 }
1914 } else {
Steve Frencha4544342005-08-24 13:59:35 -07001915 cifs_stats_bytes_read(pTcon, total_read);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001916 *poffset += bytes_read;
1917 }
1918 }
1919 FreeXid(xid);
1920 return total_read;
1921}
1922
1923int cifs_file_mmap(struct file *file, struct vm_area_struct *vma)
1924{
Josef "Jeff" Sipeke6a00292006-12-08 02:36:48 -08001925 struct dentry *dentry = file->f_path.dentry;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001926 int rc, xid;
1927
1928 xid = GetXid();
1929 rc = cifs_revalidate(dentry);
1930 if (rc) {
1931 cFYI(1, ("Validation prior to mmap failed, error=%d", rc));
1932 FreeXid(xid);
1933 return rc;
1934 }
1935 rc = generic_file_mmap(file, vma);
1936 FreeXid(xid);
1937 return rc;
1938}
1939
1940
Steve Frenchfb8c4b12007-07-10 01:16:18 +00001941static void cifs_copy_cache_pages(struct address_space *mapping,
Linus Torvalds1da177e2005-04-16 15:20:36 -07001942 struct list_head *pages, int bytes_read, char *data,
1943 struct pagevec *plru_pvec)
1944{
1945 struct page *page;
1946 char *target;
1947
1948 while (bytes_read > 0) {
1949 if (list_empty(pages))
1950 break;
1951
1952 page = list_entry(pages->prev, struct page, lru);
1953 list_del(&page->lru);
1954
1955 if (add_to_page_cache(page, mapping, page->index,
1956 GFP_KERNEL)) {
1957 page_cache_release(page);
1958 cFYI(1, ("Add page cache failed"));
Steve French3079ca62005-06-09 14:44:07 -07001959 data += PAGE_CACHE_SIZE;
1960 bytes_read -= PAGE_CACHE_SIZE;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001961 continue;
1962 }
1963
Steve Frenchfb8c4b12007-07-10 01:16:18 +00001964 target = kmap_atomic(page, KM_USER0);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001965
1966 if (PAGE_CACHE_SIZE > bytes_read) {
1967 memcpy(target, data, bytes_read);
1968 /* zero the tail end of this partial page */
Steve Frenchfb8c4b12007-07-10 01:16:18 +00001969 memset(target + bytes_read, 0,
Linus Torvalds1da177e2005-04-16 15:20:36 -07001970 PAGE_CACHE_SIZE - bytes_read);
1971 bytes_read = 0;
1972 } else {
1973 memcpy(target, data, PAGE_CACHE_SIZE);
1974 bytes_read -= PAGE_CACHE_SIZE;
1975 }
1976 kunmap_atomic(target, KM_USER0);
1977
1978 flush_dcache_page(page);
1979 SetPageUptodate(page);
1980 unlock_page(page);
1981 if (!pagevec_add(plru_pvec, page))
Rik van Riel4f98a2f2008-10-18 20:26:32 -07001982 __pagevec_lru_add_file(plru_pvec);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001983 data += PAGE_CACHE_SIZE;
1984 }
1985 return;
1986}
1987
1988static int cifs_readpages(struct file *file, struct address_space *mapping,
1989 struct list_head *page_list, unsigned num_pages)
1990{
1991 int rc = -EACCES;
1992 int xid;
1993 loff_t offset;
1994 struct page *page;
1995 struct cifs_sb_info *cifs_sb;
1996 struct cifsTconInfo *pTcon;
Steve French2c2130e2007-10-12 19:10:28 +00001997 unsigned int bytes_read = 0;
Steve Frenchfb8c4b12007-07-10 01:16:18 +00001998 unsigned int read_size, i;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001999 char *smb_read_data = NULL;
2000 struct smb_com_read_rsp *pSMBr;
2001 struct pagevec lru_pvec;
2002 struct cifsFileInfo *open_file;
Steve Frenchec637e32005-12-12 20:53:18 -08002003 int buf_type = CIFS_NO_BUFFER;
Linus Torvalds1da177e2005-04-16 15:20:36 -07002004
2005 xid = GetXid();
2006 if (file->private_data == NULL) {
Suresh Jayaraman0f3bc092009-06-25 18:12:34 +05302007 rc = -EBADF;
Linus Torvalds1da177e2005-04-16 15:20:36 -07002008 FreeXid(xid);
Suresh Jayaraman0f3bc092009-06-25 18:12:34 +05302009 return rc;
Linus Torvalds1da177e2005-04-16 15:20:36 -07002010 }
2011 open_file = (struct cifsFileInfo *)file->private_data;
Josef "Jeff" Sipeke6a00292006-12-08 02:36:48 -08002012 cifs_sb = CIFS_SB(file->f_path.dentry->d_sb);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002013 pTcon = cifs_sb->tcon;
Steve Frenchbfa0d752005-08-31 21:50:37 -07002014
Linus Torvalds1da177e2005-04-16 15:20:36 -07002015 pagevec_init(&lru_pvec, 0);
Steve French61de8002008-10-30 20:15:22 +00002016 cFYI(DBG2, ("rpages: num pages %d", num_pages));
Linus Torvalds1da177e2005-04-16 15:20:36 -07002017 for (i = 0; i < num_pages; ) {
2018 unsigned contig_pages;
2019 struct page *tmp_page;
2020 unsigned long expected_index;
2021
2022 if (list_empty(page_list))
2023 break;
2024
2025 page = list_entry(page_list->prev, struct page, lru);
2026 offset = (loff_t)page->index << PAGE_CACHE_SHIFT;
2027
2028 /* count adjacent pages that we will read into */
2029 contig_pages = 0;
Steve Frenchfb8c4b12007-07-10 01:16:18 +00002030 expected_index =
Linus Torvalds1da177e2005-04-16 15:20:36 -07002031 list_entry(page_list->prev, struct page, lru)->index;
Steve Frenchfb8c4b12007-07-10 01:16:18 +00002032 list_for_each_entry_reverse(tmp_page, page_list, lru) {
Linus Torvalds1da177e2005-04-16 15:20:36 -07002033 if (tmp_page->index == expected_index) {
2034 contig_pages++;
2035 expected_index++;
2036 } else
Steve Frenchfb8c4b12007-07-10 01:16:18 +00002037 break;
Linus Torvalds1da177e2005-04-16 15:20:36 -07002038 }
2039 if (contig_pages + i > num_pages)
2040 contig_pages = num_pages - i;
2041
2042 /* for reads over a certain size could initiate async
2043 read ahead */
2044
2045 read_size = contig_pages * PAGE_CACHE_SIZE;
2046 /* Read size needs to be in multiples of one page */
2047 read_size = min_t(const unsigned int, read_size,
2048 cifs_sb->rsize & PAGE_CACHE_MASK);
Steve French90c81e02008-02-12 20:32:36 +00002049 cFYI(DBG2, ("rpages: read size 0x%x contiguous pages %d",
Steve French75865f8c2007-06-24 18:30:48 +00002050 read_size, contig_pages));
Linus Torvalds1da177e2005-04-16 15:20:36 -07002051 rc = -EAGAIN;
2052 while (rc == -EAGAIN) {
Steve Frenchfb8c4b12007-07-10 01:16:18 +00002053 if ((open_file->invalidHandle) &&
Linus Torvalds1da177e2005-04-16 15:20:36 -07002054 (!open_file->closePend)) {
Steve French4b18f2a2008-04-29 00:06:05 +00002055 rc = cifs_reopen_file(file, true);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002056 if (rc != 0)
2057 break;
2058 }
2059
Steve Frenchbfa0d752005-08-31 21:50:37 -07002060 rc = CIFSSMBRead(xid, pTcon,
Steve Frenchec637e32005-12-12 20:53:18 -08002061 open_file->netfid,
2062 read_size, offset,
2063 &bytes_read, &smb_read_data,
2064 &buf_type);
Steve Frencha9d02ad2005-08-24 23:06:05 -07002065 /* BB more RC checks ? */
Steve Frenchfb8c4b12007-07-10 01:16:18 +00002066 if (rc == -EAGAIN) {
Linus Torvalds1da177e2005-04-16 15:20:36 -07002067 if (smb_read_data) {
Steve Frenchfb8c4b12007-07-10 01:16:18 +00002068 if (buf_type == CIFS_SMALL_BUFFER)
Steve Frenchec637e32005-12-12 20:53:18 -08002069 cifs_small_buf_release(smb_read_data);
Steve Frenchfb8c4b12007-07-10 01:16:18 +00002070 else if (buf_type == CIFS_LARGE_BUFFER)
Steve Frenchec637e32005-12-12 20:53:18 -08002071 cifs_buf_release(smb_read_data);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002072 smb_read_data = NULL;
2073 }
2074 }
2075 }
2076 if ((rc < 0) || (smb_read_data == NULL)) {
2077 cFYI(1, ("Read error in readpages: %d", rc));
Linus Torvalds1da177e2005-04-16 15:20:36 -07002078 break;
2079 } else if (bytes_read > 0) {
Andrew Morton6f88cc22006-12-10 02:19:44 -08002080 task_io_account_read(bytes_read);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002081 pSMBr = (struct smb_com_read_rsp *)smb_read_data;
2082 cifs_copy_cache_pages(mapping, page_list, bytes_read,
2083 smb_read_data + 4 /* RFC1001 hdr */ +
2084 le16_to_cpu(pSMBr->DataOffset), &lru_pvec);
2085
2086 i += bytes_read >> PAGE_CACHE_SHIFT;
Steve Frencha4544342005-08-24 13:59:35 -07002087 cifs_stats_bytes_read(pTcon, bytes_read);
Steve French2c2130e2007-10-12 19:10:28 +00002088 if ((bytes_read & PAGE_CACHE_MASK) != bytes_read) {
Linus Torvalds1da177e2005-04-16 15:20:36 -07002089 i++; /* account for partial page */
2090
Steve Frenchfb8c4b12007-07-10 01:16:18 +00002091 /* server copy of file can have smaller size
Linus Torvalds1da177e2005-04-16 15:20:36 -07002092 than client */
Steve Frenchfb8c4b12007-07-10 01:16:18 +00002093 /* BB do we need to verify this common case ?
2094 this case is ok - if we are at server EOF
Linus Torvalds1da177e2005-04-16 15:20:36 -07002095 we will hit it on next read */
2096
OGAWA Hirofumi05ac9d42006-11-02 22:07:08 -08002097 /* break; */
Linus Torvalds1da177e2005-04-16 15:20:36 -07002098 }
2099 } else {
2100 cFYI(1, ("No bytes read (%d) at offset %lld . "
2101 "Cleaning remaining pages from readahead list",
2102 bytes_read, offset));
Steve Frenchfb8c4b12007-07-10 01:16:18 +00002103 /* BB turn off caching and do new lookup on
Linus Torvalds1da177e2005-04-16 15:20:36 -07002104 file size at server? */
Linus Torvalds1da177e2005-04-16 15:20:36 -07002105 break;
2106 }
2107 if (smb_read_data) {
Steve Frenchfb8c4b12007-07-10 01:16:18 +00002108 if (buf_type == CIFS_SMALL_BUFFER)
Steve Frenchec637e32005-12-12 20:53:18 -08002109 cifs_small_buf_release(smb_read_data);
Steve Frenchfb8c4b12007-07-10 01:16:18 +00002110 else if (buf_type == CIFS_LARGE_BUFFER)
Steve Frenchec637e32005-12-12 20:53:18 -08002111 cifs_buf_release(smb_read_data);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002112 smb_read_data = NULL;
2113 }
2114 bytes_read = 0;
2115 }
2116
Rik van Riel4f98a2f2008-10-18 20:26:32 -07002117 pagevec_lru_add_file(&lru_pvec);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002118
2119/* need to free smb_read_data buf before exit */
2120 if (smb_read_data) {
Steve Frenchfb8c4b12007-07-10 01:16:18 +00002121 if (buf_type == CIFS_SMALL_BUFFER)
Steve French47c886b2006-01-18 14:20:39 -08002122 cifs_small_buf_release(smb_read_data);
Steve Frenchfb8c4b12007-07-10 01:16:18 +00002123 else if (buf_type == CIFS_LARGE_BUFFER)
Steve French47c886b2006-01-18 14:20:39 -08002124 cifs_buf_release(smb_read_data);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002125 smb_read_data = NULL;
Steve Frenchfb8c4b12007-07-10 01:16:18 +00002126 }
Linus Torvalds1da177e2005-04-16 15:20:36 -07002127
2128 FreeXid(xid);
2129 return rc;
2130}
2131
2132static int cifs_readpage_worker(struct file *file, struct page *page,
2133 loff_t *poffset)
2134{
2135 char *read_data;
2136 int rc;
2137
2138 page_cache_get(page);
2139 read_data = kmap(page);
2140 /* for reads over a certain size could initiate async read ahead */
Steve Frenchfb8c4b12007-07-10 01:16:18 +00002141
Linus Torvalds1da177e2005-04-16 15:20:36 -07002142 rc = cifs_read(file, read_data, PAGE_CACHE_SIZE, poffset);
Steve Frenchfb8c4b12007-07-10 01:16:18 +00002143
Linus Torvalds1da177e2005-04-16 15:20:36 -07002144 if (rc < 0)
2145 goto io_error;
2146 else
Steve Frenchfb8c4b12007-07-10 01:16:18 +00002147 cFYI(1, ("Bytes read %d", rc));
2148
Josef "Jeff" Sipeke6a00292006-12-08 02:36:48 -08002149 file->f_path.dentry->d_inode->i_atime =
2150 current_fs_time(file->f_path.dentry->d_inode->i_sb);
Steve Frenchfb8c4b12007-07-10 01:16:18 +00002151
Linus Torvalds1da177e2005-04-16 15:20:36 -07002152 if (PAGE_CACHE_SIZE > rc)
2153 memset(read_data + rc, 0, PAGE_CACHE_SIZE - rc);
2154
2155 flush_dcache_page(page);
2156 SetPageUptodate(page);
2157 rc = 0;
Steve Frenchfb8c4b12007-07-10 01:16:18 +00002158
Linus Torvalds1da177e2005-04-16 15:20:36 -07002159io_error:
Steve Frenchfb8c4b12007-07-10 01:16:18 +00002160 kunmap(page);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002161 page_cache_release(page);
2162 return rc;
2163}
2164
2165static int cifs_readpage(struct file *file, struct page *page)
2166{
2167 loff_t offset = (loff_t)page->index << PAGE_CACHE_SHIFT;
2168 int rc = -EACCES;
2169 int xid;
2170
2171 xid = GetXid();
2172
2173 if (file->private_data == NULL) {
Suresh Jayaraman0f3bc092009-06-25 18:12:34 +05302174 rc = -EBADF;
Linus Torvalds1da177e2005-04-16 15:20:36 -07002175 FreeXid(xid);
Suresh Jayaraman0f3bc092009-06-25 18:12:34 +05302176 return rc;
Linus Torvalds1da177e2005-04-16 15:20:36 -07002177 }
2178
Steve Frenchfb8c4b12007-07-10 01:16:18 +00002179 cFYI(1, ("readpage %p at offset %d 0x%x\n",
Linus Torvalds1da177e2005-04-16 15:20:36 -07002180 page, (int)offset, (int)offset));
2181
2182 rc = cifs_readpage_worker(file, page, &offset);
2183
2184 unlock_page(page);
2185
2186 FreeXid(xid);
2187 return rc;
2188}
2189
Steve Frencha403a0a2007-07-26 15:54:16 +00002190static int is_inode_writable(struct cifsInodeInfo *cifs_inode)
2191{
2192 struct cifsFileInfo *open_file;
2193
2194 read_lock(&GlobalSMBSeslock);
2195 list_for_each_entry(open_file, &cifs_inode->openFileList, flist) {
2196 if (open_file->closePend)
2197 continue;
2198 if (open_file->pfile &&
2199 ((open_file->pfile->f_flags & O_RDWR) ||
2200 (open_file->pfile->f_flags & O_WRONLY))) {
2201 read_unlock(&GlobalSMBSeslock);
2202 return 1;
2203 }
2204 }
2205 read_unlock(&GlobalSMBSeslock);
2206 return 0;
2207}
2208
Linus Torvalds1da177e2005-04-16 15:20:36 -07002209/* We do not want to update the file size from server for inodes
2210 open for write - to avoid races with writepage extending
2211 the file - in the future we could consider allowing
Steve Frenchfb8c4b12007-07-10 01:16:18 +00002212 refreshing the inode only on increases in the file size
Linus Torvalds1da177e2005-04-16 15:20:36 -07002213 but this is tricky to do without racing with writebehind
2214 page caching in the current Linux kernel design */
Steve French4b18f2a2008-04-29 00:06:05 +00002215bool is_size_safe_to_change(struct cifsInodeInfo *cifsInode, __u64 end_of_file)
Linus Torvalds1da177e2005-04-16 15:20:36 -07002216{
Steve Frencha403a0a2007-07-26 15:54:16 +00002217 if (!cifsInode)
Steve French4b18f2a2008-04-29 00:06:05 +00002218 return true;
Steve French23e7dd72005-10-20 13:44:56 -07002219
Steve Frencha403a0a2007-07-26 15:54:16 +00002220 if (is_inode_writable(cifsInode)) {
2221 /* This inode is open for write at least once */
Steve Frenchc32a0b62006-01-12 14:41:28 -08002222 struct cifs_sb_info *cifs_sb;
2223
Steve Frenchc32a0b62006-01-12 14:41:28 -08002224 cifs_sb = CIFS_SB(cifsInode->vfs_inode.i_sb);
Steve Frenchad7a2922008-02-07 23:25:02 +00002225 if (cifs_sb->mnt_cifs_flags & CIFS_MOUNT_DIRECT_IO) {
Steve Frenchfb8c4b12007-07-10 01:16:18 +00002226 /* since no page cache to corrupt on directio
Steve Frenchc32a0b62006-01-12 14:41:28 -08002227 we can change size safely */
Steve French4b18f2a2008-04-29 00:06:05 +00002228 return true;
Steve Frenchc32a0b62006-01-12 14:41:28 -08002229 }
2230
Steve Frenchfb8c4b12007-07-10 01:16:18 +00002231 if (i_size_read(&cifsInode->vfs_inode) < end_of_file)
Steve French4b18f2a2008-04-29 00:06:05 +00002232 return true;
Steve French7ba52632007-02-08 18:14:13 +00002233
Steve French4b18f2a2008-04-29 00:06:05 +00002234 return false;
Steve French23e7dd72005-10-20 13:44:56 -07002235 } else
Steve French4b18f2a2008-04-29 00:06:05 +00002236 return true;
Linus Torvalds1da177e2005-04-16 15:20:36 -07002237}
2238
Nick Piggind9414772008-09-24 11:32:59 -04002239static int cifs_write_begin(struct file *file, struct address_space *mapping,
2240 loff_t pos, unsigned len, unsigned flags,
2241 struct page **pagep, void **fsdata)
Linus Torvalds1da177e2005-04-16 15:20:36 -07002242{
Nick Piggind9414772008-09-24 11:32:59 -04002243 pgoff_t index = pos >> PAGE_CACHE_SHIFT;
2244 loff_t offset = pos & (PAGE_CACHE_SIZE - 1);
Jeff Laytona98ee8c2008-11-26 19:32:33 +00002245 loff_t page_start = pos & PAGE_MASK;
2246 loff_t i_size;
2247 struct page *page;
2248 int rc = 0;
Linus Torvalds1da177e2005-04-16 15:20:36 -07002249
Nick Piggind9414772008-09-24 11:32:59 -04002250 cFYI(1, ("write_begin from %lld len %d", (long long)pos, len));
2251
Nick Piggin54566b22009-01-04 12:00:53 -08002252 page = grab_cache_page_write_begin(mapping, index, flags);
Jeff Laytona98ee8c2008-11-26 19:32:33 +00002253 if (!page) {
2254 rc = -ENOMEM;
2255 goto out;
2256 }
Nick Piggind9414772008-09-24 11:32:59 -04002257
Jeff Laytona98ee8c2008-11-26 19:32:33 +00002258 if (PageUptodate(page))
2259 goto out;
Steve French8a236262007-03-06 00:31:00 +00002260
Jeff Laytona98ee8c2008-11-26 19:32:33 +00002261 /*
2262 * If we write a full page it will be up to date, no need to read from
2263 * the server. If the write is short, we'll end up doing a sync write
2264 * instead.
2265 */
2266 if (len == PAGE_CACHE_SIZE)
2267 goto out;
2268
2269 /*
2270 * optimize away the read when we have an oplock, and we're not
2271 * expecting to use any of the data we'd be reading in. That
2272 * is, when the page lies beyond the EOF, or straddles the EOF
2273 * and the write will cover all of the existing data.
2274 */
2275 if (CIFS_I(mapping->host)->clientCanCacheRead) {
2276 i_size = i_size_read(mapping->host);
2277 if (page_start >= i_size ||
2278 (offset == 0 && (pos + len) >= i_size)) {
2279 zero_user_segments(page, 0, offset,
2280 offset + len,
2281 PAGE_CACHE_SIZE);
2282 /*
2283 * PageChecked means that the parts of the page
2284 * to which we're not writing are considered up
2285 * to date. Once the data is copied to the
2286 * page, it can be set uptodate.
2287 */
2288 SetPageChecked(page);
2289 goto out;
2290 }
2291 }
Linus Torvalds1da177e2005-04-16 15:20:36 -07002292
Nick Piggind9414772008-09-24 11:32:59 -04002293 if ((file->f_flags & O_ACCMODE) != O_WRONLY) {
Jeff Laytona98ee8c2008-11-26 19:32:33 +00002294 /*
2295 * might as well read a page, it is fast enough. If we get
2296 * an error, we don't need to return it. cifs_write_end will
2297 * do a sync write instead since PG_uptodate isn't set.
2298 */
2299 cifs_readpage_worker(file, page, &page_start);
Steve French8a236262007-03-06 00:31:00 +00002300 } else {
2301 /* we could try using another file handle if there is one -
2302 but how would we lock it to prevent close of that handle
2303 racing with this read? In any case
Nick Piggind9414772008-09-24 11:32:59 -04002304 this will be written out by write_end so is fine */
Steve French8a236262007-03-06 00:31:00 +00002305 }
Jeff Laytona98ee8c2008-11-26 19:32:33 +00002306out:
2307 *pagep = page;
2308 return rc;
Linus Torvalds1da177e2005-04-16 15:20:36 -07002309}
2310
Christoph Hellwigf5e54d62006-06-28 04:26:44 -07002311const struct address_space_operations cifs_addr_ops = {
Linus Torvalds1da177e2005-04-16 15:20:36 -07002312 .readpage = cifs_readpage,
2313 .readpages = cifs_readpages,
2314 .writepage = cifs_writepage,
Steve French37c0eb42005-10-05 14:50:29 -07002315 .writepages = cifs_writepages,
Nick Piggind9414772008-09-24 11:32:59 -04002316 .write_begin = cifs_write_begin,
2317 .write_end = cifs_write_end,
Linus Torvalds1da177e2005-04-16 15:20:36 -07002318 .set_page_dirty = __set_page_dirty_nobuffers,
2319 /* .sync_page = cifs_sync_page, */
2320 /* .direct_IO = */
2321};
Dave Kleikamp273d81d2006-06-01 19:41:23 +00002322
2323/*
2324 * cifs_readpages requires the server to support a buffer large enough to
2325 * contain the header plus one complete page of data. Otherwise, we need
2326 * to leave cifs_readpages out of the address space operations.
2327 */
Christoph Hellwigf5e54d62006-06-28 04:26:44 -07002328const struct address_space_operations cifs_addr_ops_smallbuf = {
Dave Kleikamp273d81d2006-06-01 19:41:23 +00002329 .readpage = cifs_readpage,
2330 .writepage = cifs_writepage,
2331 .writepages = cifs_writepages,
Nick Piggind9414772008-09-24 11:32:59 -04002332 .write_begin = cifs_write_begin,
2333 .write_end = cifs_write_end,
Dave Kleikamp273d81d2006-06-01 19:41:23 +00002334 .set_page_dirty = __set_page_dirty_nobuffers,
2335 /* .sync_page = cifs_sync_page, */
2336 /* .direct_IO = */
2337};