]>
Commit | Line | Data |
---|---|---|
929be906 | 1 | // SPDX-License-Identifier: LGPL-2.1 |
1da177e4 | 2 | /* |
1da177e4 LT |
3 | * |
4 | * vfs operations that deal with files | |
fb8c4b14 | 5 | * |
f19159dc | 6 | * Copyright (C) International Business Machines Corp., 2002,2010 |
1da177e4 | 7 | * Author(s): Steve French ([email protected]) |
7ee1af76 | 8 | * Jeremy Allison ([email protected]) |
1da177e4 | 9 | * |
1da177e4 LT |
10 | */ |
11 | #include <linux/fs.h> | |
5970e15d | 12 | #include <linux/filelock.h> |
37c0eb46 | 13 | #include <linux/backing-dev.h> |
1da177e4 LT |
14 | #include <linux/stat.h> |
15 | #include <linux/fcntl.h> | |
16 | #include <linux/pagemap.h> | |
17 | #include <linux/pagevec.h> | |
37c0eb46 | 18 | #include <linux/writeback.h> |
6f88cc2e | 19 | #include <linux/task_io_accounting_ops.h> |
23e7dd7d | 20 | #include <linux/delay.h> |
3bc303c2 | 21 | #include <linux/mount.h> |
5a0e3ad6 | 22 | #include <linux/slab.h> |
690c5e31 | 23 | #include <linux/swap.h> |
f86196ea | 24 | #include <linux/mm.h> |
1da177e4 LT |
25 | #include <asm/div64.h> |
26 | #include "cifsfs.h" | |
27 | #include "cifspdu.h" | |
28 | #include "cifsglob.h" | |
29 | #include "cifsproto.h" | |
fb157ed2 | 30 | #include "smb2proto.h" |
1da177e4 LT |
31 | #include "cifs_unicode.h" |
32 | #include "cifs_debug.h" | |
33 | #include "cifs_fs_sb.h" | |
9451a9a5 | 34 | #include "fscache.h" |
bd3dcc6a | 35 | #include "smbdirect.h" |
8401e936 | 36 | #include "fs_context.h" |
087f757b | 37 | #include "cifs_ioctl.h" |
05b98fd2 | 38 | #include "cached_dir.h" |
69c3c023 DH |
39 | #include <trace/events/netfs.h> |
40 | ||
41 | static int cifs_reopen_file(struct cifsFileInfo *cfile, bool can_flush); | |
42 | ||
43 | /* | |
44 | * Prepare a subrequest to upload to the server. We need to allocate credits | |
45 | * so that we know the maximum amount of data that we can include in it. | |
46 | */ | |
47 | static void cifs_prepare_write(struct netfs_io_subrequest *subreq) | |
48 | { | |
49 | struct cifs_io_subrequest *wdata = | |
50 | container_of(subreq, struct cifs_io_subrequest, subreq); | |
51 | struct cifs_io_request *req = wdata->req; | |
52d55922 | 52 | struct netfs_io_stream *stream = &req->rreq.io_streams[subreq->stream_nr]; |
69c3c023 DH |
53 | struct TCP_Server_Info *server; |
54 | struct cifsFileInfo *open_file = req->cfile; | |
55 | size_t wsize = req->rreq.wsize; | |
56 | int rc; | |
57 | ||
58 | if (!wdata->have_xid) { | |
59 | wdata->xid = get_xid(); | |
60 | wdata->have_xid = true; | |
61 | } | |
62 | ||
63 | server = cifs_pick_channel(tlink_tcon(open_file->tlink)->ses); | |
64 | wdata->server = server; | |
65 | ||
66 | retry: | |
67 | if (open_file->invalidHandle) { | |
68 | rc = cifs_reopen_file(open_file, false); | |
69 | if (rc < 0) { | |
70 | if (rc == -EAGAIN) | |
71 | goto retry; | |
72 | subreq->error = rc; | |
73 | return netfs_prepare_write_failed(subreq); | |
74 | } | |
75 | } | |
76 | ||
52d55922 | 77 | rc = server->ops->wait_mtu_credits(server, wsize, &stream->sreq_max_len, |
69c3c023 DH |
78 | &wdata->credits); |
79 | if (rc < 0) { | |
80 | subreq->error = rc; | |
81 | return netfs_prepare_write_failed(subreq); | |
82 | } | |
83 | ||
519be989 DH |
84 | wdata->credits.rreq_debug_id = subreq->rreq->debug_id; |
85 | wdata->credits.rreq_debug_index = subreq->debug_index; | |
86 | wdata->credits.in_flight_check = 1; | |
87 | trace_smb3_rw_credits(wdata->rreq->debug_id, | |
88 | wdata->subreq.debug_index, | |
89 | wdata->credits.value, | |
90 | server->credits, server->in_flight, | |
91 | wdata->credits.value, | |
92 | cifs_trace_rw_credits_write_prepare); | |
93 | ||
69c3c023 DH |
94 | #ifdef CONFIG_CIFS_SMB_DIRECT |
95 | if (server->smbd_conn) | |
52d55922 | 96 | stream->sreq_max_segs = server->smbd_conn->max_frmr_depth; |
69c3c023 DH |
97 | #endif |
98 | } | |
99 | ||
100 | /* | |
101 | * Issue a subrequest to upload to the server. | |
102 | */ | |
103 | static void cifs_issue_write(struct netfs_io_subrequest *subreq) | |
104 | { | |
105 | struct cifs_io_subrequest *wdata = | |
106 | container_of(subreq, struct cifs_io_subrequest, subreq); | |
107 | struct cifs_sb_info *sbi = CIFS_SB(subreq->rreq->inode->i_sb); | |
108 | int rc; | |
109 | ||
110 | if (cifs_forced_shutdown(sbi)) { | |
111 | rc = -EIO; | |
112 | goto fail; | |
113 | } | |
114 | ||
519be989 | 115 | rc = adjust_credits(wdata->server, wdata, cifs_trace_rw_credits_issue_write_adjust); |
69c3c023 DH |
116 | if (rc) |
117 | goto fail; | |
118 | ||
119 | rc = -EAGAIN; | |
120 | if (wdata->req->cfile->invalidHandle) | |
121 | goto fail; | |
122 | ||
123 | wdata->server->ops->async_writev(wdata); | |
124 | out: | |
125 | return; | |
126 | ||
127 | fail: | |
128 | if (rc == -EAGAIN) | |
129 | trace_netfs_sreq(subreq, netfs_sreq_trace_retry); | |
130 | else | |
131 | trace_netfs_sreq(subreq, netfs_sreq_trace_fail); | |
132 | add_credits_and_wake_if(wdata->server, &wdata->credits, 0); | |
3ee1a1fc | 133 | cifs_write_subrequest_terminated(wdata, rc, false); |
69c3c023 DH |
134 | goto out; |
135 | } | |
136 | ||
a07d38af DH |
137 | static void cifs_netfs_invalidate_cache(struct netfs_io_request *wreq) |
138 | { | |
139 | cifs_invalidate_cache(wreq->inode, 0); | |
140 | } | |
141 | ||
69c3c023 | 142 | /* |
ee4cdf7b | 143 | * Negotiate the size of a read operation on behalf of the netfs library. |
69c3c023 | 144 | */ |
ee4cdf7b | 145 | static int cifs_prepare_read(struct netfs_io_subrequest *subreq) |
69c3c023 DH |
146 | { |
147 | struct netfs_io_request *rreq = subreq->rreq; | |
69c3c023 DH |
148 | struct cifs_io_subrequest *rdata = container_of(subreq, struct cifs_io_subrequest, subreq); |
149 | struct cifs_io_request *req = container_of(subreq->rreq, struct cifs_io_request, rreq); | |
f1bf10d7 | 150 | struct TCP_Server_Info *server; |
69c3c023 | 151 | struct cifs_sb_info *cifs_sb = CIFS_SB(rreq->inode->i_sb); |
ee4cdf7b DH |
152 | size_t size; |
153 | int rc = 0; | |
69c3c023 | 154 | |
ee4cdf7b DH |
155 | if (!rdata->have_xid) { |
156 | rdata->xid = get_xid(); | |
157 | rdata->have_xid = true; | |
158 | } | |
f1bf10d7 SP |
159 | |
160 | server = cifs_pick_channel(tlink_tcon(req->cfile->tlink)->ses); | |
69c3c023 DH |
161 | rdata->server = server; |
162 | ||
163 | if (cifs_sb->ctx->rsize == 0) | |
164 | cifs_sb->ctx->rsize = | |
165 | server->ops->negotiate_rsize(tlink_tcon(req->cfile->tlink), | |
166 | cifs_sb->ctx); | |
167 | ||
6a5dcd48 | 168 | rc = server->ops->wait_mtu_credits(server, cifs_sb->ctx->rsize, |
ee4cdf7b DH |
169 | &size, &rdata->credits); |
170 | if (rc) | |
171 | return rc; | |
172 | ||
173 | rreq->io_streams[0].sreq_max_len = size; | |
69c3c023 | 174 | |
519be989 DH |
175 | rdata->credits.in_flight_check = 1; |
176 | rdata->credits.rreq_debug_id = rreq->debug_id; | |
177 | rdata->credits.rreq_debug_index = subreq->debug_index; | |
178 | ||
179 | trace_smb3_rw_credits(rdata->rreq->debug_id, | |
180 | rdata->subreq.debug_index, | |
181 | rdata->credits.value, | |
182 | server->credits, server->in_flight, 0, | |
183 | cifs_trace_rw_credits_read_submit); | |
184 | ||
69c3c023 DH |
185 | #ifdef CONFIG_CIFS_SMB_DIRECT |
186 | if (server->smbd_conn) | |
ee4cdf7b | 187 | rreq->io_streams[0].sreq_max_segs = server->smbd_conn->max_frmr_depth; |
69c3c023 | 188 | #endif |
ee4cdf7b | 189 | return 0; |
69c3c023 DH |
190 | } |
191 | ||
192 | /* | |
193 | * Issue a read operation on behalf of the netfs helper functions. We're asked | |
194 | * to make a read of a certain size at a point in the file. We are permitted | |
195 | * to only read a portion of that, but as long as we read something, the netfs | |
196 | * helper will call us again so that we can issue another read. | |
197 | */ | |
ee4cdf7b | 198 | static void cifs_issue_read(struct netfs_io_subrequest *subreq) |
69c3c023 DH |
199 | { |
200 | struct netfs_io_request *rreq = subreq->rreq; | |
201 | struct cifs_io_subrequest *rdata = container_of(subreq, struct cifs_io_subrequest, subreq); | |
202 | struct cifs_io_request *req = container_of(subreq->rreq, struct cifs_io_request, rreq); | |
f1bf10d7 | 203 | struct TCP_Server_Info *server = rdata->server; |
69c3c023 DH |
204 | int rc = 0; |
205 | ||
69c3c023 DH |
206 | cifs_dbg(FYI, "%s: op=%08x[%x] mapping=%p len=%zu/%zu\n", |
207 | __func__, rreq->debug_id, subreq->debug_index, rreq->mapping, | |
208 | subreq->transferred, subreq->len); | |
209 | ||
ee4cdf7b DH |
210 | rc = adjust_credits(server, rdata, cifs_trace_rw_credits_issue_read_adjust); |
211 | if (rc) | |
212 | goto failed; | |
6a5dcd48 | 213 | |
69c3c023 DH |
214 | if (req->cfile->invalidHandle) { |
215 | do { | |
216 | rc = cifs_reopen_file(req->cfile, true); | |
217 | } while (rc == -EAGAIN); | |
218 | if (rc) | |
ee4cdf7b | 219 | goto failed; |
69c3c023 DH |
220 | } |
221 | ||
e3786b29 DM |
222 | if (subreq->rreq->origin != NETFS_DIO_READ) |
223 | __set_bit(NETFS_SREQ_CLEAR_TAIL, &subreq->flags); | |
69c3c023 | 224 | |
ee4cdf7b | 225 | trace_netfs_sreq(subreq, netfs_sreq_trace_submit); |
969b3010 | 226 | rc = rdata->server->ops->async_readv(rdata); |
69c3c023 | 227 | if (rc) |
ee4cdf7b DH |
228 | goto failed; |
229 | return; | |
230 | ||
231 | failed: | |
36015782 | 232 | subreq->error = rc; |
31fc366a | 233 | netfs_read_subreq_terminated(subreq); |
69c3c023 DH |
234 | } |
235 | ||
236 | /* | |
237 | * Writeback calls this when it finds a folio that needs uploading. This isn't | |
238 | * called if writeback only has copy-to-cache to deal with. | |
239 | */ | |
240 | static void cifs_begin_writeback(struct netfs_io_request *wreq) | |
241 | { | |
242 | struct cifs_io_request *req = container_of(wreq, struct cifs_io_request, rreq); | |
243 | int ret; | |
244 | ||
245 | ret = cifs_get_writable_file(CIFS_I(wreq->inode), FIND_WR_ANY, &req->cfile); | |
246 | if (ret) { | |
247 | cifs_dbg(VFS, "No writable handle in writepages ret=%d\n", ret); | |
248 | return; | |
249 | } | |
250 | ||
251 | wreq->io_streams[0].avail = true; | |
252 | } | |
253 | ||
254 | /* | |
255 | * Initialise a request. | |
256 | */ | |
257 | static int cifs_init_request(struct netfs_io_request *rreq, struct file *file) | |
258 | { | |
259 | struct cifs_io_request *req = container_of(rreq, struct cifs_io_request, rreq); | |
260 | struct cifs_sb_info *cifs_sb = CIFS_SB(rreq->inode->i_sb); | |
261 | struct cifsFileInfo *open_file = NULL; | |
262 | ||
263 | rreq->rsize = cifs_sb->ctx->rsize; | |
264 | rreq->wsize = cifs_sb->ctx->wsize; | |
3f591385 | 265 | req->pid = current->tgid; // Ummm... This may be a workqueue |
69c3c023 DH |
266 | |
267 | if (file) { | |
268 | open_file = file->private_data; | |
269 | rreq->netfs_priv = file->private_data; | |
270 | req->cfile = cifsFileInfo_get(open_file); | |
3f591385 DH |
271 | if (cifs_sb->mnt_cifs_flags & CIFS_MOUNT_RWPIDFORWARD) |
272 | req->pid = req->cfile->pid; | |
69c3c023 DH |
273 | } else if (rreq->origin != NETFS_WRITEBACK) { |
274 | WARN_ON_ONCE(1); | |
275 | return -EIO; | |
276 | } | |
277 | ||
278 | return 0; | |
279 | } | |
280 | ||
69c3c023 DH |
281 | /* |
282 | * Completion of a request operation. | |
283 | */ | |
284 | static void cifs_rreq_done(struct netfs_io_request *rreq) | |
285 | { | |
286 | struct timespec64 atime, mtime; | |
287 | struct inode *inode = rreq->inode; | |
288 | ||
289 | /* we do not want atime to be less than mtime, it broke some apps */ | |
290 | atime = inode_set_atime_to_ts(inode, current_time(inode)); | |
291 | mtime = inode_get_mtime(inode); | |
292 | if (timespec64_compare(&atime, &mtime)) | |
293 | inode_set_atime_to_ts(inode, inode_get_mtime(inode)); | |
294 | } | |
295 | ||
69c3c023 DH |
296 | static void cifs_free_request(struct netfs_io_request *rreq) |
297 | { | |
298 | struct cifs_io_request *req = container_of(rreq, struct cifs_io_request, rreq); | |
299 | ||
300 | if (req->cfile) | |
301 | cifsFileInfo_put(req->cfile); | |
302 | } | |
303 | ||
304 | static void cifs_free_subrequest(struct netfs_io_subrequest *subreq) | |
305 | { | |
306 | struct cifs_io_subrequest *rdata = | |
307 | container_of(subreq, struct cifs_io_subrequest, subreq); | |
308 | int rc = subreq->error; | |
309 | ||
310 | if (rdata->subreq.source == NETFS_DOWNLOAD_FROM_SERVER) { | |
311 | #ifdef CONFIG_CIFS_SMB_DIRECT | |
312 | if (rdata->mr) { | |
313 | smbd_deregister_mr(rdata->mr); | |
314 | rdata->mr = NULL; | |
315 | } | |
316 | #endif | |
317 | } | |
318 | ||
74c2ab6d | 319 | if (rdata->credits.value != 0) { |
519be989 DH |
320 | trace_smb3_rw_credits(rdata->rreq->debug_id, |
321 | rdata->subreq.debug_index, | |
322 | rdata->credits.value, | |
323 | rdata->server ? rdata->server->credits : 0, | |
324 | rdata->server ? rdata->server->in_flight : 0, | |
325 | -rdata->credits.value, | |
326 | cifs_trace_rw_credits_free_subreq); | |
74c2ab6d SH |
327 | if (rdata->server) |
328 | add_credits_and_wake_if(rdata->server, &rdata->credits, 0); | |
329 | else | |
330 | rdata->credits.value = 0; | |
331 | } | |
519be989 | 332 | |
69c3c023 DH |
333 | if (rdata->have_xid) |
334 | free_xid(rdata->xid); | |
335 | } | |
336 | ||
337 | const struct netfs_request_ops cifs_req_ops = { | |
338 | .request_pool = &cifs_io_request_pool, | |
339 | .subrequest_pool = &cifs_io_subrequest_pool, | |
340 | .init_request = cifs_init_request, | |
341 | .free_request = cifs_free_request, | |
342 | .free_subrequest = cifs_free_subrequest, | |
ee4cdf7b DH |
343 | .prepare_read = cifs_prepare_read, |
344 | .issue_read = cifs_issue_read, | |
69c3c023 | 345 | .done = cifs_rreq_done, |
69c3c023 DH |
346 | .begin_writeback = cifs_begin_writeback, |
347 | .prepare_write = cifs_prepare_write, | |
348 | .issue_write = cifs_issue_write, | |
a07d38af | 349 | .invalidate_cache = cifs_netfs_invalidate_cache, |
69c3c023 | 350 | }; |
07b92d0d | 351 | |
fb157ed2 SF |
352 | /* |
353 | * Mark as invalid, all open files on tree connections since they | |
354 | * were closed when session to server was lost. | |
355 | */ | |
356 | void | |
357 | cifs_mark_open_files_invalid(struct cifs_tcon *tcon) | |
358 | { | |
359 | struct cifsFileInfo *open_file = NULL; | |
360 | struct list_head *tmp; | |
361 | struct list_head *tmp1; | |
362 | ||
363 | /* only send once per connect */ | |
2f0e4f03 | 364 | spin_lock(&tcon->tc_lock); |
c6e02eef SP |
365 | if (tcon->need_reconnect) |
366 | tcon->status = TID_NEED_RECON; | |
367 | ||
2f0e4f03 SP |
368 | if (tcon->status != TID_NEED_RECON) { |
369 | spin_unlock(&tcon->tc_lock); | |
fb157ed2 SF |
370 | return; |
371 | } | |
372 | tcon->status = TID_IN_FILES_INVALIDATE; | |
2f0e4f03 | 373 | spin_unlock(&tcon->tc_lock); |
fb157ed2 SF |
374 | |
375 | /* list all files open on tree connection and mark them invalid */ | |
376 | spin_lock(&tcon->open_file_lock); | |
377 | list_for_each_safe(tmp, tmp1, &tcon->openFileList) { | |
378 | open_file = list_entry(tmp, struct cifsFileInfo, tlist); | |
379 | open_file->invalidHandle = true; | |
380 | open_file->oplock_break_cancelled = true; | |
381 | } | |
382 | spin_unlock(&tcon->open_file_lock); | |
383 | ||
05b98fd2 | 384 | invalidate_all_cached_dirs(tcon); |
fb157ed2 SF |
385 | spin_lock(&tcon->tc_lock); |
386 | if (tcon->status == TID_IN_FILES_INVALIDATE) | |
387 | tcon->status = TID_NEED_TCON; | |
388 | spin_unlock(&tcon->tc_lock); | |
389 | ||
390 | /* | |
391 | * BB Add call to invalidate_inodes(sb) for all superblocks mounted | |
392 | * to this tcon. | |
393 | */ | |
394 | } | |
395 | ||
e9e62243 | 396 | static inline int cifs_convert_flags(unsigned int flags, int rdwr_for_fscache) |
1da177e4 LT |
397 | { |
398 | if ((flags & O_ACCMODE) == O_RDONLY) | |
399 | return GENERIC_READ; | |
400 | else if ((flags & O_ACCMODE) == O_WRONLY) | |
e9e62243 | 401 | return rdwr_for_fscache == 1 ? (GENERIC_READ | GENERIC_WRITE) : GENERIC_WRITE; |
1da177e4 LT |
402 | else if ((flags & O_ACCMODE) == O_RDWR) { |
403 | /* GENERIC_ALL is too much permission to request | |
404 | can cause unnecessary access denied on create */ | |
405 | /* return GENERIC_ALL; */ | |
406 | return (GENERIC_READ | GENERIC_WRITE); | |
407 | } | |
408 | ||
e10f7b55 JL |
409 | return (READ_CONTROL | FILE_WRITE_ATTRIBUTES | FILE_READ_ATTRIBUTES | |
410 | FILE_WRITE_EA | FILE_APPEND_DATA | FILE_WRITE_DATA | | |
411 | FILE_READ_DATA); | |
7fc8f4e9 | 412 | } |
e10f7b55 | 413 | |
fb157ed2 | 414 | #ifdef CONFIG_CIFS_ALLOW_INSECURE_LEGACY |
608712fe | 415 | static u32 cifs_posix_convert_flags(unsigned int flags) |
7fc8f4e9 | 416 | { |
608712fe | 417 | u32 posix_flags = 0; |
e10f7b55 | 418 | |
7fc8f4e9 | 419 | if ((flags & O_ACCMODE) == O_RDONLY) |
608712fe | 420 | posix_flags = SMB_O_RDONLY; |
7fc8f4e9 | 421 | else if ((flags & O_ACCMODE) == O_WRONLY) |
608712fe JL |
422 | posix_flags = SMB_O_WRONLY; |
423 | else if ((flags & O_ACCMODE) == O_RDWR) | |
424 | posix_flags = SMB_O_RDWR; | |
425 | ||
07b92d0d | 426 | if (flags & O_CREAT) { |
608712fe | 427 | posix_flags |= SMB_O_CREAT; |
07b92d0d SF |
428 | if (flags & O_EXCL) |
429 | posix_flags |= SMB_O_EXCL; | |
430 | } else if (flags & O_EXCL) | |
f96637be JP |
431 | cifs_dbg(FYI, "Application %s pid %d has incorrectly set O_EXCL flag but not O_CREAT on file open. Ignoring O_EXCL\n", |
432 | current->comm, current->tgid); | |
07b92d0d | 433 | |
608712fe JL |
434 | if (flags & O_TRUNC) |
435 | posix_flags |= SMB_O_TRUNC; | |
436 | /* be safe and imply O_SYNC for O_DSYNC */ | |
6b2f3d1f | 437 | if (flags & O_DSYNC) |
608712fe | 438 | posix_flags |= SMB_O_SYNC; |
7fc8f4e9 | 439 | if (flags & O_DIRECTORY) |
608712fe | 440 | posix_flags |= SMB_O_DIRECTORY; |
7fc8f4e9 | 441 | if (flags & O_NOFOLLOW) |
608712fe | 442 | posix_flags |= SMB_O_NOFOLLOW; |
7fc8f4e9 | 443 | if (flags & O_DIRECT) |
608712fe | 444 | posix_flags |= SMB_O_DIRECT; |
7fc8f4e9 SF |
445 | |
446 | return posix_flags; | |
1da177e4 | 447 | } |
fb157ed2 | 448 | #endif /* CONFIG_CIFS_ALLOW_INSECURE_LEGACY */ |
1da177e4 LT |
449 | |
450 | static inline int cifs_get_disposition(unsigned int flags) | |
451 | { | |
452 | if ((flags & (O_CREAT | O_EXCL)) == (O_CREAT | O_EXCL)) | |
453 | return FILE_CREATE; | |
454 | else if ((flags & (O_CREAT | O_TRUNC)) == (O_CREAT | O_TRUNC)) | |
455 | return FILE_OVERWRITE_IF; | |
456 | else if ((flags & O_CREAT) == O_CREAT) | |
457 | return FILE_OPEN_IF; | |
55aa2e09 SF |
458 | else if ((flags & O_TRUNC) == O_TRUNC) |
459 | return FILE_OVERWRITE; | |
1da177e4 LT |
460 | else |
461 | return FILE_OPEN; | |
462 | } | |
463 | ||
fb157ed2 | 464 | #ifdef CONFIG_CIFS_ALLOW_INSECURE_LEGACY |
f6f1f179 | 465 | int cifs_posix_open(const char *full_path, struct inode **pinode, |
608712fe | 466 | struct super_block *sb, int mode, unsigned int f_flags, |
6d5786a3 | 467 | __u32 *poplock, __u16 *pnetfid, unsigned int xid) |
608712fe JL |
468 | { |
469 | int rc; | |
470 | FILE_UNIX_BASIC_INFO *presp_data; | |
471 | __u32 posix_flags = 0; | |
472 | struct cifs_sb_info *cifs_sb = CIFS_SB(sb); | |
473 | struct cifs_fattr fattr; | |
474 | struct tcon_link *tlink; | |
96daf2b0 | 475 | struct cifs_tcon *tcon; |
608712fe | 476 | |
f96637be | 477 | cifs_dbg(FYI, "posix open %s\n", full_path); |
608712fe JL |
478 | |
479 | presp_data = kzalloc(sizeof(FILE_UNIX_BASIC_INFO), GFP_KERNEL); | |
480 | if (presp_data == NULL) | |
481 | return -ENOMEM; | |
482 | ||
483 | tlink = cifs_sb_tlink(cifs_sb); | |
484 | if (IS_ERR(tlink)) { | |
485 | rc = PTR_ERR(tlink); | |
486 | goto posix_open_ret; | |
487 | } | |
488 | ||
489 | tcon = tlink_tcon(tlink); | |
490 | mode &= ~current_umask(); | |
491 | ||
492 | posix_flags = cifs_posix_convert_flags(f_flags); | |
493 | rc = CIFSPOSIXCreate(xid, tcon, posix_flags, mode, pnetfid, presp_data, | |
494 | poplock, full_path, cifs_sb->local_nls, | |
bc8ebdc4 | 495 | cifs_remap(cifs_sb)); |
608712fe JL |
496 | cifs_put_tlink(tlink); |
497 | ||
498 | if (rc) | |
499 | goto posix_open_ret; | |
500 | ||
501 | if (presp_data->Type == cpu_to_le32(-1)) | |
502 | goto posix_open_ret; /* open ok, caller does qpathinfo */ | |
503 | ||
504 | if (!pinode) | |
505 | goto posix_open_ret; /* caller does not need info */ | |
506 | ||
507 | cifs_unix_basic_to_fattr(&fattr, presp_data, cifs_sb); | |
508 | ||
509 | /* get new inode and set it up */ | |
510 | if (*pinode == NULL) { | |
511 | cifs_fill_uniqueid(sb, &fattr); | |
512 | *pinode = cifs_iget(sb, &fattr); | |
513 | if (!*pinode) { | |
514 | rc = -ENOMEM; | |
515 | goto posix_open_ret; | |
516 | } | |
517 | } else { | |
cee8f4f6 | 518 | cifs_revalidate_mapping(*pinode); |
e4b61f3b | 519 | rc = cifs_fattr_to_inode(*pinode, &fattr, false); |
608712fe JL |
520 | } |
521 | ||
522 | posix_open_ret: | |
523 | kfree(presp_data); | |
524 | return rc; | |
525 | } | |
fb157ed2 | 526 | #endif /* CONFIG_CIFS_ALLOW_INSECURE_LEGACY */ |
608712fe | 527 | |
76894f3e PA |
528 | static int cifs_nt_open(const char *full_path, struct inode *inode, struct cifs_sb_info *cifs_sb, |
529 | struct cifs_tcon *tcon, unsigned int f_flags, __u32 *oplock, | |
530 | struct cifs_fid *fid, unsigned int xid, struct cifs_open_info_data *buf) | |
eeb910a6 PS |
531 | { |
532 | int rc; | |
fb1214e4 | 533 | int desired_access; |
eeb910a6 | 534 | int disposition; |
3d3ea8e6 | 535 | int create_options = CREATE_NOT_DIR; |
b8c32dbb | 536 | struct TCP_Server_Info *server = tcon->ses->server; |
226730b4 | 537 | struct cifs_open_parms oparms; |
e9e62243 | 538 | int rdwr_for_fscache = 0; |
eeb910a6 | 539 | |
b8c32dbb | 540 | if (!server->ops->open) |
fb1214e4 PS |
541 | return -ENOSYS; |
542 | ||
e9e62243 DH |
543 | /* If we're caching, we need to be able to fill in around partial writes. */ |
544 | if (cifs_fscache_enabled(inode) && (f_flags & O_ACCMODE) == O_WRONLY) | |
545 | rdwr_for_fscache = 1; | |
546 | ||
547 | desired_access = cifs_convert_flags(f_flags, rdwr_for_fscache); | |
eeb910a6 PS |
548 | |
549 | /********************************************************************* | |
550 | * open flag mapping table: | |
551 | * | |
552 | * POSIX Flag CIFS Disposition | |
553 | * ---------- ---------------- | |
554 | * O_CREAT FILE_OPEN_IF | |
555 | * O_CREAT | O_EXCL FILE_CREATE | |
556 | * O_CREAT | O_TRUNC FILE_OVERWRITE_IF | |
557 | * O_TRUNC FILE_OVERWRITE | |
558 | * none of the above FILE_OPEN | |
559 | * | |
560 | * Note that there is not a direct match between disposition | |
561 | * FILE_SUPERSEDE (ie create whether or not file exists although | |
562 | * O_CREAT | O_TRUNC is similar but truncates the existing | |
563 | * file rather than creating a new file as FILE_SUPERSEDE does | |
564 | * (which uses the attributes / metadata passed in on open call) | |
565 | *? | |
566 | *? O_SYNC is a reasonable match to CIFS writethrough flag | |
567 | *? and the read write flags match reasonably. O_LARGEFILE | |
568 | *? is irrelevant because largefile support is always used | |
569 | *? by this client. Flags O_APPEND, O_DIRECT, O_DIRECTORY, | |
570 | * O_FASYNC, O_NOFOLLOW, O_NONBLOCK need further investigation | |
571 | *********************************************************************/ | |
572 | ||
573 | disposition = cifs_get_disposition(f_flags); | |
574 | ||
575 | /* BB pass O_SYNC flag through on file attributes .. BB */ | |
576 | ||
1013e760 SF |
577 | /* O_SYNC also has bit for O_DSYNC so following check picks up either */ |
578 | if (f_flags & O_SYNC) | |
579 | create_options |= CREATE_WRITE_THROUGH; | |
580 | ||
581 | if (f_flags & O_DIRECT) | |
582 | create_options |= CREATE_NO_BUFFER; | |
583 | ||
e9e62243 | 584 | retry_open: |
de036dca VL |
585 | oparms = (struct cifs_open_parms) { |
586 | .tcon = tcon, | |
587 | .cifs_sb = cifs_sb, | |
588 | .desired_access = desired_access, | |
589 | .create_options = cifs_create_options(cifs_sb, create_options), | |
590 | .disposition = disposition, | |
591 | .path = full_path, | |
592 | .fid = fid, | |
593 | }; | |
226730b4 PS |
594 | |
595 | rc = server->ops->open(xid, &oparms, oplock, buf); | |
e9e62243 DH |
596 | if (rc) { |
597 | if (rc == -EACCES && rdwr_for_fscache == 1) { | |
598 | desired_access = cifs_convert_flags(f_flags, 0); | |
599 | rdwr_for_fscache = 2; | |
600 | goto retry_open; | |
601 | } | |
76894f3e | 602 | return rc; |
e9e62243 DH |
603 | } |
604 | if (rdwr_for_fscache == 2) | |
605 | cifs_invalidate_cache(inode, FSCACHE_INVAL_DIO_WRITE); | |
eeb910a6 | 606 | |
d313852d | 607 | /* TODO: Add support for calling posix query info but with passing in fid */ |
eeb910a6 PS |
608 | if (tcon->unix_ext) |
609 | rc = cifs_get_inode_info_unix(&inode, full_path, inode->i_sb, | |
610 | xid); | |
611 | else | |
612 | rc = cifs_get_inode_info(&inode, full_path, buf, inode->i_sb, | |
42eacf9e | 613 | xid, fid); |
eeb910a6 | 614 | |
30573a82 PS |
615 | if (rc) { |
616 | server->ops->close(xid, tcon, fid); | |
617 | if (rc == -ESTALE) | |
618 | rc = -EOPENSTALE; | |
619 | } | |
620 | ||
eeb910a6 PS |
621 | return rc; |
622 | } | |
623 | ||
63b7d3a4 PS |
624 | static bool |
625 | cifs_has_mand_locks(struct cifsInodeInfo *cinode) | |
626 | { | |
627 | struct cifs_fid_locks *cur; | |
628 | bool has_locks = false; | |
629 | ||
630 | down_read(&cinode->lock_sem); | |
631 | list_for_each_entry(cur, &cinode->llist, llist) { | |
632 | if (!list_empty(&cur->locks)) { | |
633 | has_locks = true; | |
634 | break; | |
635 | } | |
636 | } | |
637 | up_read(&cinode->lock_sem); | |
638 | return has_locks; | |
639 | } | |
640 | ||
d46b0da7 DW |
641 | void |
642 | cifs_down_write(struct rw_semaphore *sem) | |
643 | { | |
644 | while (!down_write_trylock(sem)) | |
645 | msleep(10); | |
646 | } | |
647 | ||
32546a95 | 648 | static void cifsFileInfo_put_work(struct work_struct *work); |
173217bd | 649 | void serverclose_work(struct work_struct *work); |
32546a95 | 650 | |
76894f3e PA |
651 | struct cifsFileInfo *cifs_new_fileinfo(struct cifs_fid *fid, struct file *file, |
652 | struct tcon_link *tlink, __u32 oplock, | |
653 | const char *symlink_target) | |
15ecb436 | 654 | { |
1f1735cb | 655 | struct dentry *dentry = file_dentry(file); |
2b0143b5 | 656 | struct inode *inode = d_inode(dentry); |
4b4de76e PS |
657 | struct cifsInodeInfo *cinode = CIFS_I(inode); |
658 | struct cifsFileInfo *cfile; | |
f45d3416 | 659 | struct cifs_fid_locks *fdlocks; |
233839b1 | 660 | struct cifs_tcon *tcon = tlink_tcon(tlink); |
63b7d3a4 | 661 | struct TCP_Server_Info *server = tcon->ses->server; |
4b4de76e PS |
662 | |
663 | cfile = kzalloc(sizeof(struct cifsFileInfo), GFP_KERNEL); | |
664 | if (cfile == NULL) | |
665 | return cfile; | |
666 | ||
f45d3416 PS |
667 | fdlocks = kzalloc(sizeof(struct cifs_fid_locks), GFP_KERNEL); |
668 | if (!fdlocks) { | |
669 | kfree(cfile); | |
670 | return NULL; | |
671 | } | |
672 | ||
76894f3e PA |
673 | if (symlink_target) { |
674 | cfile->symlink_target = kstrdup(symlink_target, GFP_KERNEL); | |
675 | if (!cfile->symlink_target) { | |
676 | kfree(fdlocks); | |
677 | kfree(cfile); | |
678 | return NULL; | |
679 | } | |
680 | } | |
681 | ||
f45d3416 PS |
682 | INIT_LIST_HEAD(&fdlocks->locks); |
683 | fdlocks->cfile = cfile; | |
684 | cfile->llist = fdlocks; | |
f45d3416 | 685 | |
4b4de76e | 686 | cfile->count = 1; |
4b4de76e PS |
687 | cfile->pid = current->tgid; |
688 | cfile->uid = current_fsuid(); | |
689 | cfile->dentry = dget(dentry); | |
690 | cfile->f_flags = file->f_flags; | |
691 | cfile->invalidHandle = false; | |
860b69a9 | 692 | cfile->deferred_close_scheduled = false; |
4b4de76e | 693 | cfile->tlink = cifs_get_tlink(tlink); |
4b4de76e | 694 | INIT_WORK(&cfile->oplock_break, cifs_oplock_break); |
32546a95 | 695 | INIT_WORK(&cfile->put, cifsFileInfo_put_work); |
173217bd | 696 | INIT_WORK(&cfile->serverclose, serverclose_work); |
c3f207ab | 697 | INIT_DELAYED_WORK(&cfile->deferred, smb2_deferred_work_close); |
f45d3416 | 698 | mutex_init(&cfile->fh_mutex); |
3afca265 | 699 | spin_lock_init(&cfile->file_info_lock); |
15ecb436 | 700 | |
24261fc2 MG |
701 | cifs_sb_active(inode->i_sb); |
702 | ||
63b7d3a4 PS |
703 | /* |
704 | * If the server returned a read oplock and we have mandatory brlocks, | |
705 | * set oplock level to None. | |
706 | */ | |
53ef1016 | 707 | if (server->ops->is_read_op(oplock) && cifs_has_mand_locks(cinode)) { |
f96637be | 708 | cifs_dbg(FYI, "Reset oplock val from read to None due to mand locks\n"); |
63b7d3a4 PS |
709 | oplock = 0; |
710 | } | |
711 | ||
6f582b27 PS |
712 | cifs_down_write(&cinode->lock_sem); |
713 | list_add(&fdlocks->llist, &cinode->llist); | |
714 | up_write(&cinode->lock_sem); | |
715 | ||
3afca265 | 716 | spin_lock(&tcon->open_file_lock); |
63b7d3a4 | 717 | if (fid->pending_open->oplock != CIFS_OPLOCK_NO_CHANGE && oplock) |
233839b1 PS |
718 | oplock = fid->pending_open->oplock; |
719 | list_del(&fid->pending_open->olist); | |
720 | ||
42873b0a | 721 | fid->purge_cache = false; |
63b7d3a4 | 722 | server->ops->set_fid(cfile, fid, oplock); |
233839b1 PS |
723 | |
724 | list_add(&cfile->tlist, &tcon->openFileList); | |
fae8044c | 725 | atomic_inc(&tcon->num_local_opens); |
3afca265 | 726 | |
15ecb436 | 727 | /* if readable file instance put first in list*/ |
487317c9 | 728 | spin_lock(&cinode->open_file_lock); |
15ecb436 | 729 | if (file->f_mode & FMODE_READ) |
4b4de76e | 730 | list_add(&cfile->flist, &cinode->openFileList); |
15ecb436 | 731 | else |
4b4de76e | 732 | list_add_tail(&cfile->flist, &cinode->openFileList); |
487317c9 | 733 | spin_unlock(&cinode->open_file_lock); |
3afca265 | 734 | spin_unlock(&tcon->open_file_lock); |
15ecb436 | 735 | |
42873b0a | 736 | if (fid->purge_cache) |
4f73c7d3 | 737 | cifs_zap_mapping(inode); |
42873b0a | 738 | |
4b4de76e PS |
739 | file->private_data = cfile; |
740 | return cfile; | |
15ecb436 JL |
741 | } |
742 | ||
764a1b1a JL |
743 | struct cifsFileInfo * |
744 | cifsFileInfo_get(struct cifsFileInfo *cifs_file) | |
745 | { | |
3afca265 | 746 | spin_lock(&cifs_file->file_info_lock); |
764a1b1a | 747 | cifsFileInfo_get_locked(cifs_file); |
3afca265 | 748 | spin_unlock(&cifs_file->file_info_lock); |
764a1b1a JL |
749 | return cifs_file; |
750 | } | |
751 | ||
32546a95 RS |
752 | static void cifsFileInfo_put_final(struct cifsFileInfo *cifs_file) |
753 | { | |
754 | struct inode *inode = d_inode(cifs_file->dentry); | |
755 | struct cifsInodeInfo *cifsi = CIFS_I(inode); | |
756 | struct cifsLockInfo *li, *tmp; | |
757 | struct super_block *sb = inode->i_sb; | |
758 | ||
759 | /* | |
760 | * Delete any outstanding lock records. We'll lose them when the file | |
761 | * is closed anyway. | |
762 | */ | |
763 | cifs_down_write(&cifsi->lock_sem); | |
764 | list_for_each_entry_safe(li, tmp, &cifs_file->llist->locks, llist) { | |
765 | list_del(&li->llist); | |
766 | cifs_del_lock_waiters(li); | |
767 | kfree(li); | |
768 | } | |
769 | list_del(&cifs_file->llist->llist); | |
770 | kfree(cifs_file->llist); | |
771 | up_write(&cifsi->lock_sem); | |
772 | ||
773 | cifs_put_tlink(cifs_file->tlink); | |
774 | dput(cifs_file->dentry); | |
775 | cifs_sb_deactive(sb); | |
76894f3e | 776 | kfree(cifs_file->symlink_target); |
32546a95 RS |
777 | kfree(cifs_file); |
778 | } | |
779 | ||
780 | static void cifsFileInfo_put_work(struct work_struct *work) | |
781 | { | |
782 | struct cifsFileInfo *cifs_file = container_of(work, | |
783 | struct cifsFileInfo, put); | |
784 | ||
785 | cifsFileInfo_put_final(cifs_file); | |
786 | } | |
787 | ||
173217bd RB |
788 | void serverclose_work(struct work_struct *work) |
789 | { | |
790 | struct cifsFileInfo *cifs_file = container_of(work, | |
791 | struct cifsFileInfo, serverclose); | |
792 | ||
793 | struct cifs_tcon *tcon = tlink_tcon(cifs_file->tlink); | |
794 | ||
795 | struct TCP_Server_Info *server = tcon->ses->server; | |
796 | int rc = 0; | |
797 | int retries = 0; | |
798 | int MAX_RETRIES = 4; | |
799 | ||
800 | do { | |
801 | if (server->ops->close_getattr) | |
802 | rc = server->ops->close_getattr(0, tcon, cifs_file); | |
803 | else if (server->ops->close) | |
804 | rc = server->ops->close(0, tcon, &cifs_file->fid); | |
805 | ||
806 | if (rc == -EBUSY || rc == -EAGAIN) { | |
807 | retries++; | |
808 | msleep(250); | |
809 | } | |
810 | } while ((rc == -EBUSY || rc == -EAGAIN) && (retries < MAX_RETRIES) | |
811 | ); | |
812 | ||
813 | if (retries == MAX_RETRIES) | |
814 | pr_warn("Serverclose failed %d times, giving up\n", MAX_RETRIES); | |
815 | ||
816 | if (cifs_file->offload) | |
817 | queue_work(fileinfo_put_wq, &cifs_file->put); | |
818 | else | |
819 | cifsFileInfo_put_final(cifs_file); | |
820 | } | |
821 | ||
b98749ca AA |
822 | /** |
823 | * cifsFileInfo_put - release a reference of file priv data | |
824 | * | |
825 | * Always potentially wait for oplock handler. See _cifsFileInfo_put(). | |
607dfc79 SF |
826 | * |
827 | * @cifs_file: cifs/smb3 specific info (eg refcounts) for an open file | |
cdff08e7 | 828 | */ |
b33879aa | 829 | void cifsFileInfo_put(struct cifsFileInfo *cifs_file) |
b98749ca | 830 | { |
32546a95 | 831 | _cifsFileInfo_put(cifs_file, true, true); |
b98749ca AA |
832 | } |
833 | ||
834 | /** | |
835 | * _cifsFileInfo_put - release a reference of file priv data | |
836 | * | |
837 | * This may involve closing the filehandle @cifs_file out on the | |
32546a95 RS |
838 | * server. Must be called without holding tcon->open_file_lock, |
839 | * cinode->open_file_lock and cifs_file->file_info_lock. | |
b98749ca AA |
840 | * |
841 | * If @wait_for_oplock_handler is true and we are releasing the last | |
842 | * reference, wait for any running oplock break handler of the file | |
607dfc79 SF |
843 | * and cancel any pending one. |
844 | * | |
845 | * @cifs_file: cifs/smb3 specific info (eg refcounts) for an open file | |
846 | * @wait_oplock_handler: must be false if called from oplock_break_handler | |
847 | * @offload: not offloaded on close and oplock breaks | |
b98749ca AA |
848 | * |
849 | */ | |
32546a95 RS |
850 | void _cifsFileInfo_put(struct cifsFileInfo *cifs_file, |
851 | bool wait_oplock_handler, bool offload) | |
b33879aa | 852 | { |
2b0143b5 | 853 | struct inode *inode = d_inode(cifs_file->dentry); |
96daf2b0 | 854 | struct cifs_tcon *tcon = tlink_tcon(cifs_file->tlink); |
233839b1 | 855 | struct TCP_Server_Info *server = tcon->ses->server; |
e66673e3 | 856 | struct cifsInodeInfo *cifsi = CIFS_I(inode); |
24261fc2 MG |
857 | struct super_block *sb = inode->i_sb; |
858 | struct cifs_sb_info *cifs_sb = CIFS_SB(sb); | |
2bff0659 | 859 | struct cifs_fid fid = {}; |
233839b1 | 860 | struct cifs_pending_open open; |
ca7df8e0 | 861 | bool oplock_break_cancelled; |
173217bd | 862 | bool serverclose_offloaded = false; |
cdff08e7 | 863 | |
3afca265 | 864 | spin_lock(&tcon->open_file_lock); |
1a67c415 | 865 | spin_lock(&cifsi->open_file_lock); |
3afca265 | 866 | spin_lock(&cifs_file->file_info_lock); |
173217bd RB |
867 | |
868 | cifs_file->offload = offload; | |
5f6dbc9e | 869 | if (--cifs_file->count > 0) { |
3afca265 | 870 | spin_unlock(&cifs_file->file_info_lock); |
1a67c415 | 871 | spin_unlock(&cifsi->open_file_lock); |
3afca265 | 872 | spin_unlock(&tcon->open_file_lock); |
cdff08e7 SF |
873 | return; |
874 | } | |
3afca265 | 875 | spin_unlock(&cifs_file->file_info_lock); |
cdff08e7 | 876 | |
233839b1 PS |
877 | if (server->ops->get_lease_key) |
878 | server->ops->get_lease_key(inode, &fid); | |
879 | ||
880 | /* store open in pending opens to make sure we don't miss lease break */ | |
881 | cifs_add_pending_open_locked(&fid, cifs_file->tlink, &open); | |
882 | ||
cdff08e7 SF |
883 | /* remove it from the lists */ |
884 | list_del(&cifs_file->flist); | |
885 | list_del(&cifs_file->tlist); | |
fae8044c | 886 | atomic_dec(&tcon->num_local_opens); |
cdff08e7 SF |
887 | |
888 | if (list_empty(&cifsi->openFileList)) { | |
f96637be | 889 | cifs_dbg(FYI, "closing last open instance for inode %p\n", |
2b0143b5 | 890 | d_inode(cifs_file->dentry)); |
25364138 PS |
891 | /* |
892 | * In strict cache mode we need invalidate mapping on the last | |
893 | * close because it may cause a error when we open this file | |
894 | * again and get at least level II oplock. | |
895 | */ | |
4f8ba8a0 | 896 | if (cifs_sb->mnt_cifs_flags & CIFS_MOUNT_STRICT_IO) |
aff8d5ca | 897 | set_bit(CIFS_INO_INVALID_MAPPING, &cifsi->flags); |
c6723628 | 898 | cifs_set_oplock_level(cifsi, 0); |
cdff08e7 | 899 | } |
3afca265 | 900 | |
1a67c415 | 901 | spin_unlock(&cifsi->open_file_lock); |
3afca265 | 902 | spin_unlock(&tcon->open_file_lock); |
cdff08e7 | 903 | |
b98749ca AA |
904 | oplock_break_cancelled = wait_oplock_handler ? |
905 | cancel_work_sync(&cifs_file->oplock_break) : false; | |
ad635942 | 906 | |
cdff08e7 | 907 | if (!tcon->need_reconnect && !cifs_file->invalidHandle) { |
0ff78a22 | 908 | struct TCP_Server_Info *server = tcon->ses->server; |
6d5786a3 | 909 | unsigned int xid; |
173217bd | 910 | int rc = 0; |
0ff78a22 | 911 | |
6d5786a3 | 912 | xid = get_xid(); |
43f8a6a7 | 913 | if (server->ops->close_getattr) |
173217bd | 914 | rc = server->ops->close_getattr(xid, tcon, cifs_file); |
43f8a6a7 | 915 | else if (server->ops->close) |
173217bd | 916 | rc = server->ops->close(xid, tcon, &cifs_file->fid); |
760ad0ca | 917 | _free_xid(xid); |
173217bd RB |
918 | |
919 | if (rc == -EBUSY || rc == -EAGAIN) { | |
920 | // Server close failed, hence offloading it as an async op | |
921 | queue_work(serverclose_wq, &cifs_file->serverclose); | |
922 | serverclose_offloaded = true; | |
923 | } | |
cdff08e7 SF |
924 | } |
925 | ||
ca7df8e0 SP |
926 | if (oplock_break_cancelled) |
927 | cifs_done_oplock_break(cifsi); | |
928 | ||
233839b1 PS |
929 | cifs_del_pending_open(&open); |
930 | ||
173217bd RB |
931 | // if serverclose has been offloaded to wq (on failure), it will |
932 | // handle offloading put as well. If serverclose not offloaded, | |
933 | // we need to handle offloading put here. | |
934 | if (!serverclose_offloaded) { | |
935 | if (offload) | |
936 | queue_work(fileinfo_put_wq, &cifs_file->put); | |
937 | else | |
938 | cifsFileInfo_put_final(cifs_file); | |
939 | } | |
b33879aa JL |
940 | } |
941 | ||
1da177e4 | 942 | int cifs_open(struct inode *inode, struct file *file) |
233839b1 | 943 | |
1da177e4 LT |
944 | { |
945 | int rc = -EACCES; | |
6d5786a3 | 946 | unsigned int xid; |
590a3fe0 | 947 | __u32 oplock; |
1da177e4 | 948 | struct cifs_sb_info *cifs_sb; |
b8c32dbb | 949 | struct TCP_Server_Info *server; |
96daf2b0 | 950 | struct cifs_tcon *tcon; |
7ffec372 | 951 | struct tcon_link *tlink; |
fb1214e4 | 952 | struct cifsFileInfo *cfile = NULL; |
f6a9bc33 AV |
953 | void *page; |
954 | const char *full_path; | |
7e12eddb | 955 | bool posix_open_ok = false; |
2bff0659 | 956 | struct cifs_fid fid = {}; |
233839b1 | 957 | struct cifs_pending_open open; |
76894f3e | 958 | struct cifs_open_info_data data = {}; |
1da177e4 | 959 | |
6d5786a3 | 960 | xid = get_xid(); |
1da177e4 LT |
961 | |
962 | cifs_sb = CIFS_SB(inode->i_sb); | |
087f757b SF |
963 | if (unlikely(cifs_forced_shutdown(cifs_sb))) { |
964 | free_xid(xid); | |
965 | return -EIO; | |
966 | } | |
967 | ||
7ffec372 JL |
968 | tlink = cifs_sb_tlink(cifs_sb); |
969 | if (IS_ERR(tlink)) { | |
6d5786a3 | 970 | free_xid(xid); |
7ffec372 JL |
971 | return PTR_ERR(tlink); |
972 | } | |
973 | tcon = tlink_tcon(tlink); | |
b8c32dbb | 974 | server = tcon->ses->server; |
1da177e4 | 975 | |
f6a9bc33 AV |
976 | page = alloc_dentry_path(); |
977 | full_path = build_path_from_dentry(file_dentry(file), page); | |
978 | if (IS_ERR(full_path)) { | |
979 | rc = PTR_ERR(full_path); | |
232341ba | 980 | goto out; |
1da177e4 LT |
981 | } |
982 | ||
f96637be | 983 | cifs_dbg(FYI, "inode = 0x%p file flags are 0x%x for %s\n", |
b6b38f70 | 984 | inode, file->f_flags, full_path); |
276a74a4 | 985 | |
787aded6 NJ |
986 | if (file->f_flags & O_DIRECT && |
987 | cifs_sb->mnt_cifs_flags & CIFS_MOUNT_STRICT_IO) { | |
988 | if (cifs_sb->mnt_cifs_flags & CIFS_MOUNT_NO_BRL) | |
989 | file->f_op = &cifs_file_direct_nobrl_ops; | |
990 | else | |
991 | file->f_op = &cifs_file_direct_ops; | |
992 | } | |
993 | ||
c3f207ab | 994 | /* Get the cached handle as SMB2 close is deferred */ |
b8ea3b1f BS |
995 | if (OPEN_FMODE(file->f_flags) & FMODE_WRITE) { |
996 | rc = cifs_get_writable_path(tcon, full_path, FIND_WR_FSUID_ONLY, &cfile); | |
997 | } else { | |
998 | rc = cifs_get_readable_path(tcon, full_path, &cfile); | |
999 | } | |
c3f207ab RS |
1000 | if (rc == 0) { |
1001 | if (file->f_flags == cfile->f_flags) { | |
1002 | file->private_data = cfile; | |
860b69a9 | 1003 | spin_lock(&CIFS_I(inode)->deferred_lock); |
c3f207ab RS |
1004 | cifs_del_deferred_close(cfile); |
1005 | spin_unlock(&CIFS_I(inode)->deferred_lock); | |
70431bfd | 1006 | goto use_cache; |
c3f207ab | 1007 | } else { |
c3f207ab RS |
1008 | _cifsFileInfo_put(cfile, true, false); |
1009 | } | |
c3f207ab RS |
1010 | } |
1011 | ||
233839b1 | 1012 | if (server->oplocks) |
276a74a4 SF |
1013 | oplock = REQ_OPLOCK; |
1014 | else | |
1015 | oplock = 0; | |
1016 | ||
fb157ed2 | 1017 | #ifdef CONFIG_CIFS_ALLOW_INSECURE_LEGACY |
64cc2c63 | 1018 | if (!tcon->broken_posix_open && tcon->unix_ext && |
29e20f9c PS |
1019 | cap_unix(tcon->ses) && (CIFS_UNIX_POSIX_PATH_OPS_CAP & |
1020 | le64_to_cpu(tcon->fsUnixInfo.Capability))) { | |
276a74a4 | 1021 | /* can not refresh inode info since size could be stale */ |
2422f676 | 1022 | rc = cifs_posix_open(full_path, &inode, inode->i_sb, |
8401e936 | 1023 | cifs_sb->ctx->file_mode /* ignored */, |
fb1214e4 | 1024 | file->f_flags, &oplock, &fid.netfid, xid); |
276a74a4 | 1025 | if (rc == 0) { |
f96637be | 1026 | cifs_dbg(FYI, "posix open succeeded\n"); |
7e12eddb | 1027 | posix_open_ok = true; |
64cc2c63 SF |
1028 | } else if ((rc == -EINVAL) || (rc == -EOPNOTSUPP)) { |
1029 | if (tcon->ses->serverNOS) | |
f96637be | 1030 | cifs_dbg(VFS, "server %s of type %s returned unexpected error on SMB posix open, disabling posix open support. Check if server update available.\n", |
b438fcf1 | 1031 | tcon->ses->ip_addr, |
f96637be | 1032 | tcon->ses->serverNOS); |
64cc2c63 | 1033 | tcon->broken_posix_open = true; |
276a74a4 SF |
1034 | } else if ((rc != -EIO) && (rc != -EREMOTE) && |
1035 | (rc != -EOPNOTSUPP)) /* path not found or net err */ | |
1036 | goto out; | |
fb1214e4 PS |
1037 | /* |
1038 | * Else fallthrough to retry open the old way on network i/o | |
1039 | * or DFS errors. | |
1040 | */ | |
276a74a4 | 1041 | } |
fb157ed2 | 1042 | #endif /* CONFIG_CIFS_ALLOW_INSECURE_LEGACY */ |
276a74a4 | 1043 | |
233839b1 PS |
1044 | if (server->ops->get_lease_key) |
1045 | server->ops->get_lease_key(inode, &fid); | |
1046 | ||
1047 | cifs_add_pending_open(&fid, tlink, &open); | |
1048 | ||
7e12eddb | 1049 | if (!posix_open_ok) { |
b8c32dbb PS |
1050 | if (server->ops->get_lease_key) |
1051 | server->ops->get_lease_key(inode, &fid); | |
1052 | ||
76894f3e PA |
1053 | rc = cifs_nt_open(full_path, inode, cifs_sb, tcon, file->f_flags, &oplock, &fid, |
1054 | xid, &data); | |
233839b1 PS |
1055 | if (rc) { |
1056 | cifs_del_pending_open(&open); | |
7e12eddb | 1057 | goto out; |
233839b1 | 1058 | } |
7e12eddb | 1059 | } |
47c78b7f | 1060 | |
76894f3e | 1061 | cfile = cifs_new_fileinfo(&fid, file, tlink, oplock, data.symlink_target); |
fb1214e4 | 1062 | if (cfile == NULL) { |
b8c32dbb PS |
1063 | if (server->ops->close) |
1064 | server->ops->close(xid, tcon, &fid); | |
233839b1 | 1065 | cifs_del_pending_open(&open); |
1da177e4 LT |
1066 | rc = -ENOMEM; |
1067 | goto out; | |
1068 | } | |
1da177e4 | 1069 | |
fb157ed2 | 1070 | #ifdef CONFIG_CIFS_ALLOW_INSECURE_LEGACY |
7e12eddb | 1071 | if ((oplock & CIFS_CREATE_ACTION) && !posix_open_ok && tcon->unix_ext) { |
fb1214e4 PS |
1072 | /* |
1073 | * Time to set mode which we can not set earlier due to | |
1074 | * problems creating new read-only files. | |
1075 | */ | |
7e12eddb PS |
1076 | struct cifs_unix_set_info_args args = { |
1077 | .mode = inode->i_mode, | |
49418b2c EB |
1078 | .uid = INVALID_UID, /* no change */ |
1079 | .gid = INVALID_GID, /* no change */ | |
7e12eddb PS |
1080 | .ctime = NO_CHANGE_64, |
1081 | .atime = NO_CHANGE_64, | |
1082 | .mtime = NO_CHANGE_64, | |
1083 | .device = 0, | |
1084 | }; | |
fb1214e4 PS |
1085 | CIFSSMBUnixSetFileInfo(xid, tcon, &args, fid.netfid, |
1086 | cfile->pid); | |
1da177e4 | 1087 | } |
fb157ed2 | 1088 | #endif /* CONFIG_CIFS_ALLOW_INSECURE_LEGACY */ |
1da177e4 | 1089 | |
70431bfd DH |
1090 | use_cache: |
1091 | fscache_use_cookie(cifs_inode_cookie(file_inode(file)), | |
1092 | file->f_mode & FMODE_WRITE); | |
e9e62243 DH |
1093 | if (!(file->f_flags & O_DIRECT)) |
1094 | goto out; | |
1095 | if ((file->f_flags & (O_ACCMODE | O_APPEND)) == O_RDONLY) | |
1096 | goto out; | |
1097 | cifs_invalidate_cache(file_inode(file), FSCACHE_INVAL_DIO_WRITE); | |
70431bfd | 1098 | |
1da177e4 | 1099 | out: |
f6a9bc33 | 1100 | free_dentry_path(page); |
6d5786a3 | 1101 | free_xid(xid); |
7ffec372 | 1102 | cifs_put_tlink(tlink); |
76894f3e | 1103 | cifs_free_open_info(&data); |
1da177e4 LT |
1104 | return rc; |
1105 | } | |
1106 | ||
fb157ed2 | 1107 | #ifdef CONFIG_CIFS_ALLOW_INSECURE_LEGACY |
f152fd5f | 1108 | static int cifs_push_posix_locks(struct cifsFileInfo *cfile); |
fb157ed2 | 1109 | #endif /* CONFIG_CIFS_ALLOW_INSECURE_LEGACY */ |
f152fd5f | 1110 | |
2ae78ba8 PS |
1111 | /* |
1112 | * Try to reacquire byte range locks that were released when session | |
f152fd5f | 1113 | * to server was lost. |
2ae78ba8 | 1114 | */ |
f152fd5f PS |
1115 | static int |
1116 | cifs_relock_file(struct cifsFileInfo *cfile) | |
1da177e4 | 1117 | { |
2b0143b5 | 1118 | struct cifsInodeInfo *cinode = CIFS_I(d_inode(cfile->dentry)); |
f152fd5f | 1119 | struct cifs_tcon *tcon = tlink_tcon(cfile->tlink); |
1da177e4 | 1120 | int rc = 0; |
fb157ed2 SF |
1121 | #ifdef CONFIG_CIFS_ALLOW_INSECURE_LEGACY |
1122 | struct cifs_sb_info *cifs_sb = CIFS_SB(cfile->dentry->d_sb); | |
1123 | #endif /* CONFIG_CIFS_ALLOW_INSECURE_LEGACY */ | |
1da177e4 | 1124 | |
560d3889 | 1125 | down_read_nested(&cinode->lock_sem, SINGLE_DEPTH_NESTING); |
f152fd5f | 1126 | if (cinode->can_cache_brlcks) { |
689c3db4 PS |
1127 | /* can cache locks - no need to relock */ |
1128 | up_read(&cinode->lock_sem); | |
f152fd5f PS |
1129 | return rc; |
1130 | } | |
1131 | ||
fb157ed2 | 1132 | #ifdef CONFIG_CIFS_ALLOW_INSECURE_LEGACY |
f152fd5f PS |
1133 | if (cap_unix(tcon->ses) && |
1134 | (CIFS_UNIX_FCNTL_CAP & le64_to_cpu(tcon->fsUnixInfo.Capability)) && | |
1135 | ((cifs_sb->mnt_cifs_flags & CIFS_MOUNT_NOPOSIXBRL) == 0)) | |
1136 | rc = cifs_push_posix_locks(cfile); | |
1137 | else | |
fb157ed2 | 1138 | #endif /* CONFIG_CIFS_ALLOW_INSECURE_LEGACY */ |
f152fd5f | 1139 | rc = tcon->ses->server->ops->push_mand_locks(cfile); |
1da177e4 | 1140 | |
689c3db4 | 1141 | up_read(&cinode->lock_sem); |
1da177e4 LT |
1142 | return rc; |
1143 | } | |
1144 | ||
2ae78ba8 PS |
1145 | static int |
1146 | cifs_reopen_file(struct cifsFileInfo *cfile, bool can_flush) | |
1da177e4 LT |
1147 | { |
1148 | int rc = -EACCES; | |
6d5786a3 | 1149 | unsigned int xid; |
590a3fe0 | 1150 | __u32 oplock; |
1da177e4 | 1151 | struct cifs_sb_info *cifs_sb; |
96daf2b0 | 1152 | struct cifs_tcon *tcon; |
2ae78ba8 PS |
1153 | struct TCP_Server_Info *server; |
1154 | struct cifsInodeInfo *cinode; | |
fb8c4b14 | 1155 | struct inode *inode; |
f6a9bc33 AV |
1156 | void *page; |
1157 | const char *full_path; | |
2ae78ba8 | 1158 | int desired_access; |
1da177e4 | 1159 | int disposition = FILE_OPEN; |
3d3ea8e6 | 1160 | int create_options = CREATE_NOT_DIR; |
226730b4 | 1161 | struct cifs_open_parms oparms; |
e9e62243 | 1162 | int rdwr_for_fscache = 0; |
1da177e4 | 1163 | |
6d5786a3 | 1164 | xid = get_xid(); |
2ae78ba8 PS |
1165 | mutex_lock(&cfile->fh_mutex); |
1166 | if (!cfile->invalidHandle) { | |
1167 | mutex_unlock(&cfile->fh_mutex); | |
6d5786a3 | 1168 | free_xid(xid); |
f6a9bc33 | 1169 | return 0; |
1da177e4 LT |
1170 | } |
1171 | ||
2b0143b5 | 1172 | inode = d_inode(cfile->dentry); |
1da177e4 | 1173 | cifs_sb = CIFS_SB(inode->i_sb); |
2ae78ba8 PS |
1174 | tcon = tlink_tcon(cfile->tlink); |
1175 | server = tcon->ses->server; | |
1176 | ||
1177 | /* | |
1178 | * Can not grab rename sem here because various ops, including those | |
1179 | * that already have the rename sem can end up causing writepage to get | |
1180 | * called and if the server was down that means we end up here, and we | |
1181 | * can never tell if the caller already has the rename_sem. | |
1182 | */ | |
f6a9bc33 AV |
1183 | page = alloc_dentry_path(); |
1184 | full_path = build_path_from_dentry(cfile->dentry, page); | |
1185 | if (IS_ERR(full_path)) { | |
2ae78ba8 | 1186 | mutex_unlock(&cfile->fh_mutex); |
f6a9bc33 | 1187 | free_dentry_path(page); |
6d5786a3 | 1188 | free_xid(xid); |
f6a9bc33 | 1189 | return PTR_ERR(full_path); |
1da177e4 LT |
1190 | } |
1191 | ||
f96637be JP |
1192 | cifs_dbg(FYI, "inode = 0x%p file flags 0x%x for %s\n", |
1193 | inode, cfile->f_flags, full_path); | |
1da177e4 | 1194 | |
10b9b98e | 1195 | if (tcon->ses->server->oplocks) |
1da177e4 LT |
1196 | oplock = REQ_OPLOCK; |
1197 | else | |
4b18f2a9 | 1198 | oplock = 0; |
1da177e4 | 1199 | |
fb157ed2 | 1200 | #ifdef CONFIG_CIFS_ALLOW_INSECURE_LEGACY |
29e20f9c | 1201 | if (tcon->unix_ext && cap_unix(tcon->ses) && |
7fc8f4e9 | 1202 | (CIFS_UNIX_POSIX_PATH_OPS_CAP & |
29e20f9c | 1203 | le64_to_cpu(tcon->fsUnixInfo.Capability))) { |
608712fe JL |
1204 | /* |
1205 | * O_CREAT, O_EXCL and O_TRUNC already had their effect on the | |
1206 | * original open. Must mask them off for a reopen. | |
1207 | */ | |
2ae78ba8 | 1208 | unsigned int oflags = cfile->f_flags & |
15886177 | 1209 | ~(O_CREAT | O_EXCL | O_TRUNC); |
608712fe | 1210 | |
2422f676 | 1211 | rc = cifs_posix_open(full_path, NULL, inode->i_sb, |
8401e936 | 1212 | cifs_sb->ctx->file_mode /* ignored */, |
9cbc0b73 | 1213 | oflags, &oplock, &cfile->fid.netfid, xid); |
7fc8f4e9 | 1214 | if (rc == 0) { |
f96637be | 1215 | cifs_dbg(FYI, "posix reopen succeeded\n"); |
fe090e4e | 1216 | oparms.reconnect = true; |
7fc8f4e9 SF |
1217 | goto reopen_success; |
1218 | } | |
2ae78ba8 PS |
1219 | /* |
1220 | * fallthrough to retry open the old way on errors, especially | |
1221 | * in the reconnect path it is important to retry hard | |
1222 | */ | |
7fc8f4e9 | 1223 | } |
fb157ed2 | 1224 | #endif /* CONFIG_CIFS_ALLOW_INSECURE_LEGACY */ |
7fc8f4e9 | 1225 | |
e9e62243 DH |
1226 | /* If we're caching, we need to be able to fill in around partial writes. */ |
1227 | if (cifs_fscache_enabled(inode) && (cfile->f_flags & O_ACCMODE) == O_WRONLY) | |
1228 | rdwr_for_fscache = 1; | |
1229 | ||
1230 | desired_access = cifs_convert_flags(cfile->f_flags, rdwr_for_fscache); | |
7fc8f4e9 | 1231 | |
44805b0e PS |
1232 | /* O_SYNC also has bit for O_DSYNC so following check picks up either */ |
1233 | if (cfile->f_flags & O_SYNC) | |
1234 | create_options |= CREATE_WRITE_THROUGH; | |
1235 | ||
1236 | if (cfile->f_flags & O_DIRECT) | |
1237 | create_options |= CREATE_NO_BUFFER; | |
1238 | ||
b8c32dbb | 1239 | if (server->ops->get_lease_key) |
9cbc0b73 | 1240 | server->ops->get_lease_key(inode, &cfile->fid); |
b8c32dbb | 1241 | |
e9e62243 | 1242 | retry_open: |
de036dca VL |
1243 | oparms = (struct cifs_open_parms) { |
1244 | .tcon = tcon, | |
1245 | .cifs_sb = cifs_sb, | |
1246 | .desired_access = desired_access, | |
1247 | .create_options = cifs_create_options(cifs_sb, create_options), | |
1248 | .disposition = disposition, | |
1249 | .path = full_path, | |
1250 | .fid = &cfile->fid, | |
1251 | .reconnect = true, | |
1252 | }; | |
226730b4 | 1253 | |
2ae78ba8 PS |
1254 | /* |
1255 | * Can not refresh inode by passing in file_info buf to be returned by | |
d81b8a40 | 1256 | * ops->open and then calling get_inode_info with returned buf since |
2ae78ba8 PS |
1257 | * file might have write behind data that needs to be flushed and server |
1258 | * version of file size can be stale. If we knew for sure that inode was | |
1259 | * not dirty locally we could do this. | |
1260 | */ | |
226730b4 | 1261 | rc = server->ops->open(xid, &oparms, &oplock, NULL); |
b33fcf1c PS |
1262 | if (rc == -ENOENT && oparms.reconnect == false) { |
1263 | /* durable handle timeout is expired - open the file again */ | |
1264 | rc = server->ops->open(xid, &oparms, &oplock, NULL); | |
1265 | /* indicate that we need to relock the file */ | |
1266 | oparms.reconnect = true; | |
1267 | } | |
e9e62243 DH |
1268 | if (rc == -EACCES && rdwr_for_fscache == 1) { |
1269 | desired_access = cifs_convert_flags(cfile->f_flags, 0); | |
1270 | rdwr_for_fscache = 2; | |
1271 | goto retry_open; | |
1272 | } | |
b33fcf1c | 1273 | |
1da177e4 | 1274 | if (rc) { |
2ae78ba8 | 1275 | mutex_unlock(&cfile->fh_mutex); |
f96637be JP |
1276 | cifs_dbg(FYI, "cifs_reopen returned 0x%x\n", rc); |
1277 | cifs_dbg(FYI, "oplock: %d\n", oplock); | |
15886177 JL |
1278 | goto reopen_error_exit; |
1279 | } | |
1280 | ||
e9e62243 DH |
1281 | if (rdwr_for_fscache == 2) |
1282 | cifs_invalidate_cache(inode, FSCACHE_INVAL_DIO_WRITE); | |
1283 | ||
fb157ed2 | 1284 | #ifdef CONFIG_CIFS_ALLOW_INSECURE_LEGACY |
7fc8f4e9 | 1285 | reopen_success: |
fb157ed2 | 1286 | #endif /* CONFIG_CIFS_ALLOW_INSECURE_LEGACY */ |
2ae78ba8 PS |
1287 | cfile->invalidHandle = false; |
1288 | mutex_unlock(&cfile->fh_mutex); | |
1289 | cinode = CIFS_I(inode); | |
15886177 JL |
1290 | |
1291 | if (can_flush) { | |
1292 | rc = filemap_write_and_wait(inode->i_mapping); | |
9a66396f PS |
1293 | if (!is_interrupt_error(rc)) |
1294 | mapping_set_error(inode->i_mapping, rc); | |
15886177 | 1295 | |
102466f3 PA |
1296 | if (tcon->posix_extensions) { |
1297 | rc = smb311_posix_get_inode_info(&inode, full_path, | |
1298 | NULL, inode->i_sb, xid); | |
1299 | } else if (tcon->unix_ext) { | |
2ae78ba8 PS |
1300 | rc = cifs_get_inode_info_unix(&inode, full_path, |
1301 | inode->i_sb, xid); | |
102466f3 | 1302 | } else { |
2ae78ba8 PS |
1303 | rc = cifs_get_inode_info(&inode, full_path, NULL, |
1304 | inode->i_sb, xid, NULL); | |
102466f3 | 1305 | } |
2ae78ba8 PS |
1306 | } |
1307 | /* | |
1308 | * Else we are writing out data to server already and could deadlock if | |
1309 | * we tried to flush data, and since we do not know if we have data that | |
1310 | * would invalidate the current end of file on the server we can not go | |
1311 | * to the server to get the new inode info. | |
1312 | */ | |
1313 | ||
de740250 PS |
1314 | /* |
1315 | * If the server returned a read oplock and we have mandatory brlocks, | |
1316 | * set oplock level to None. | |
1317 | */ | |
1318 | if (server->ops->is_read_op(oplock) && cifs_has_mand_locks(cinode)) { | |
1319 | cifs_dbg(FYI, "Reset oplock val from read to None due to mand locks\n"); | |
1320 | oplock = 0; | |
1321 | } | |
1322 | ||
9cbc0b73 PS |
1323 | server->ops->set_fid(cfile, &cfile->fid, oplock); |
1324 | if (oparms.reconnect) | |
1325 | cifs_relock_file(cfile); | |
15886177 JL |
1326 | |
1327 | reopen_error_exit: | |
f6a9bc33 | 1328 | free_dentry_path(page); |
6d5786a3 | 1329 | free_xid(xid); |
1da177e4 LT |
1330 | return rc; |
1331 | } | |
1332 | ||
c3f207ab RS |
1333 | void smb2_deferred_work_close(struct work_struct *work) |
1334 | { | |
1335 | struct cifsFileInfo *cfile = container_of(work, | |
1336 | struct cifsFileInfo, deferred.work); | |
1337 | ||
1338 | spin_lock(&CIFS_I(d_inode(cfile->dentry))->deferred_lock); | |
1339 | cifs_del_deferred_close(cfile); | |
860b69a9 | 1340 | cfile->deferred_close_scheduled = false; |
c3f207ab RS |
1341 | spin_unlock(&CIFS_I(d_inode(cfile->dentry))->deferred_lock); |
1342 | _cifsFileInfo_put(cfile, true, false); | |
1343 | } | |
1344 | ||
dc528770 BS |
1345 | static bool |
1346 | smb2_can_defer_close(struct inode *inode, struct cifs_deferred_close *dclose) | |
1347 | { | |
1348 | struct cifs_sb_info *cifs_sb = CIFS_SB(inode->i_sb); | |
1349 | struct cifsInodeInfo *cinode = CIFS_I(inode); | |
1350 | ||
1351 | return (cifs_sb->ctx->closetimeo && cinode->lease_granted && dclose && | |
1352 | (cinode->oplock == CIFS_CACHE_RHW_FLG || | |
1353 | cinode->oplock == CIFS_CACHE_RH_FLG) && | |
1354 | !test_bit(CIFS_INO_CLOSE_ON_LOCK, &cinode->flags)); | |
1355 | ||
1356 | } | |
1357 | ||
1da177e4 LT |
1358 | int cifs_close(struct inode *inode, struct file *file) |
1359 | { | |
c3f207ab RS |
1360 | struct cifsFileInfo *cfile; |
1361 | struct cifsInodeInfo *cinode = CIFS_I(inode); | |
1362 | struct cifs_sb_info *cifs_sb = CIFS_SB(inode->i_sb); | |
1363 | struct cifs_deferred_close *dclose; | |
1364 | ||
70431bfd DH |
1365 | cifs_fscache_unuse_inode_cookie(inode, file->f_mode & FMODE_WRITE); |
1366 | ||
77970693 | 1367 | if (file->private_data != NULL) { |
c3f207ab | 1368 | cfile = file->private_data; |
77970693 | 1369 | file->private_data = NULL; |
c3f207ab | 1370 | dclose = kmalloc(sizeof(struct cifs_deferred_close), GFP_KERNEL); |
dc528770 BS |
1371 | if ((cfile->status_file_deleted == false) && |
1372 | (smb2_can_defer_close(inode, dclose))) { | |
73425800 | 1373 | if (test_and_clear_bit(NETFS_ICTX_MODIFIED_ATTR, &cinode->netfs.flags)) { |
8f22ce70 JL |
1374 | inode_set_mtime_to_ts(inode, |
1375 | inode_set_ctime_current(inode)); | |
18d04062 | 1376 | } |
c3f207ab RS |
1377 | spin_lock(&cinode->deferred_lock); |
1378 | cifs_add_deferred_close(cfile, dclose); | |
860b69a9 RS |
1379 | if (cfile->deferred_close_scheduled && |
1380 | delayed_work_pending(&cfile->deferred)) { | |
9687c85d RS |
1381 | /* |
1382 | * If there is no pending work, mod_delayed_work queues new work. | |
1383 | * So, Increase the ref count to avoid use-after-free. | |
1384 | */ | |
1385 | if (!mod_delayed_work(deferredclose_wq, | |
5efdd912 | 1386 | &cfile->deferred, cifs_sb->ctx->closetimeo)) |
9687c85d | 1387 | cifsFileInfo_get(cfile); |
c3f207ab RS |
1388 | } else { |
1389 | /* Deferred close for files */ | |
1390 | queue_delayed_work(deferredclose_wq, | |
5efdd912 | 1391 | &cfile->deferred, cifs_sb->ctx->closetimeo); |
860b69a9 | 1392 | cfile->deferred_close_scheduled = true; |
c3f207ab RS |
1393 | spin_unlock(&cinode->deferred_lock); |
1394 | return 0; | |
1395 | } | |
1396 | spin_unlock(&cinode->deferred_lock); | |
1397 | _cifsFileInfo_put(cfile, true, false); | |
1398 | } else { | |
1399 | _cifsFileInfo_put(cfile, true, false); | |
1400 | kfree(dclose); | |
1401 | } | |
77970693 | 1402 | } |
7ee1af76 | 1403 | |
cdff08e7 SF |
1404 | /* return code from the ->release op is always ignored */ |
1405 | return 0; | |
1da177e4 LT |
1406 | } |
1407 | ||
52ace1ef SF |
1408 | void |
1409 | cifs_reopen_persistent_handles(struct cifs_tcon *tcon) | |
1410 | { | |
9543c8ab | 1411 | struct cifsFileInfo *open_file, *tmp; |
21dcbc17 | 1412 | LIST_HEAD(tmp_list); |
f2cca6a7 | 1413 | |
96a988ff PS |
1414 | if (!tcon->use_persistent || !tcon->need_reopen_files) |
1415 | return; | |
1416 | ||
1417 | tcon->need_reopen_files = false; | |
1418 | ||
a0a3036b | 1419 | cifs_dbg(FYI, "Reopen persistent handles\n"); |
52ace1ef SF |
1420 | |
1421 | /* list all files open on tree connection, reopen resilient handles */ | |
1422 | spin_lock(&tcon->open_file_lock); | |
9543c8ab | 1423 | list_for_each_entry(open_file, &tcon->openFileList, tlist) { |
f2cca6a7 PS |
1424 | if (!open_file->invalidHandle) |
1425 | continue; | |
1426 | cifsFileInfo_get(open_file); | |
1427 | list_add_tail(&open_file->rlist, &tmp_list); | |
52ace1ef SF |
1428 | } |
1429 | spin_unlock(&tcon->open_file_lock); | |
f2cca6a7 | 1430 | |
9543c8ab | 1431 | list_for_each_entry_safe(open_file, tmp, &tmp_list, rlist) { |
96a988ff PS |
1432 | if (cifs_reopen_file(open_file, false /* do not flush */)) |
1433 | tcon->need_reopen_files = true; | |
f2cca6a7 PS |
1434 | list_del_init(&open_file->rlist); |
1435 | cifsFileInfo_put(open_file); | |
1436 | } | |
52ace1ef SF |
1437 | } |
1438 | ||
1da177e4 LT |
1439 | int cifs_closedir(struct inode *inode, struct file *file) |
1440 | { | |
1441 | int rc = 0; | |
6d5786a3 | 1442 | unsigned int xid; |
4b4de76e | 1443 | struct cifsFileInfo *cfile = file->private_data; |
92fc65a7 PS |
1444 | struct cifs_tcon *tcon; |
1445 | struct TCP_Server_Info *server; | |
1446 | char *buf; | |
1da177e4 | 1447 | |
f96637be | 1448 | cifs_dbg(FYI, "Closedir inode = 0x%p\n", inode); |
1da177e4 | 1449 | |
92fc65a7 PS |
1450 | if (cfile == NULL) |
1451 | return rc; | |
1452 | ||
6d5786a3 | 1453 | xid = get_xid(); |
92fc65a7 PS |
1454 | tcon = tlink_tcon(cfile->tlink); |
1455 | server = tcon->ses->server; | |
1da177e4 | 1456 | |
f96637be | 1457 | cifs_dbg(FYI, "Freeing private data in close dir\n"); |
3afca265 | 1458 | spin_lock(&cfile->file_info_lock); |
52755808 | 1459 | if (server->ops->dir_needs_close(cfile)) { |
92fc65a7 | 1460 | cfile->invalidHandle = true; |
3afca265 | 1461 | spin_unlock(&cfile->file_info_lock); |
92fc65a7 PS |
1462 | if (server->ops->close_dir) |
1463 | rc = server->ops->close_dir(xid, tcon, &cfile->fid); | |
1464 | else | |
1465 | rc = -ENOSYS; | |
f96637be | 1466 | cifs_dbg(FYI, "Closing uncompleted readdir with rc %d\n", rc); |
92fc65a7 PS |
1467 | /* not much we can do if it fails anyway, ignore rc */ |
1468 | rc = 0; | |
1469 | } else | |
3afca265 | 1470 | spin_unlock(&cfile->file_info_lock); |
92fc65a7 PS |
1471 | |
1472 | buf = cfile->srch_inf.ntwrk_buf_start; | |
1473 | if (buf) { | |
f96637be | 1474 | cifs_dbg(FYI, "closedir free smb buf in srch struct\n"); |
92fc65a7 PS |
1475 | cfile->srch_inf.ntwrk_buf_start = NULL; |
1476 | if (cfile->srch_inf.smallBuf) | |
1477 | cifs_small_buf_release(buf); | |
1478 | else | |
1479 | cifs_buf_release(buf); | |
1da177e4 | 1480 | } |
92fc65a7 PS |
1481 | |
1482 | cifs_put_tlink(cfile->tlink); | |
1483 | kfree(file->private_data); | |
1484 | file->private_data = NULL; | |
1da177e4 | 1485 | /* BB can we lock the filestruct while this is going on? */ |
6d5786a3 | 1486 | free_xid(xid); |
1da177e4 LT |
1487 | return rc; |
1488 | } | |
1489 | ||
85160e03 | 1490 | static struct cifsLockInfo * |
9645759c | 1491 | cifs_lock_init(__u64 offset, __u64 length, __u8 type, __u16 flags) |
7ee1af76 | 1492 | { |
a88b4707 | 1493 | struct cifsLockInfo *lock = |
fb8c4b14 | 1494 | kmalloc(sizeof(struct cifsLockInfo), GFP_KERNEL); |
a88b4707 PS |
1495 | if (!lock) |
1496 | return lock; | |
1497 | lock->offset = offset; | |
1498 | lock->length = length; | |
1499 | lock->type = type; | |
a88b4707 | 1500 | lock->pid = current->tgid; |
9645759c | 1501 | lock->flags = flags; |
a88b4707 PS |
1502 | INIT_LIST_HEAD(&lock->blist); |
1503 | init_waitqueue_head(&lock->block_q); | |
1504 | return lock; | |
85160e03 PS |
1505 | } |
1506 | ||
f7ba7fe6 | 1507 | void |
85160e03 PS |
1508 | cifs_del_lock_waiters(struct cifsLockInfo *lock) |
1509 | { | |
1510 | struct cifsLockInfo *li, *tmp; | |
1511 | list_for_each_entry_safe(li, tmp, &lock->blist, blist) { | |
1512 | list_del_init(&li->blist); | |
1513 | wake_up(&li->block_q); | |
1514 | } | |
1515 | } | |
1516 | ||
081c0414 PS |
1517 | #define CIFS_LOCK_OP 0 |
1518 | #define CIFS_READ_OP 1 | |
1519 | #define CIFS_WRITE_OP 2 | |
1520 | ||
1521 | /* @rw_check : 0 - no op, 1 - read, 2 - write */ | |
85160e03 | 1522 | static bool |
f45d3416 | 1523 | cifs_find_fid_lock_conflict(struct cifs_fid_locks *fdlocks, __u64 offset, |
9645759c RS |
1524 | __u64 length, __u8 type, __u16 flags, |
1525 | struct cifsFileInfo *cfile, | |
081c0414 | 1526 | struct cifsLockInfo **conf_lock, int rw_check) |
85160e03 | 1527 | { |
fbd35aca | 1528 | struct cifsLockInfo *li; |
f45d3416 | 1529 | struct cifsFileInfo *cur_cfile = fdlocks->cfile; |
106dc538 | 1530 | struct TCP_Server_Info *server = tlink_tcon(cfile->tlink)->ses->server; |
85160e03 | 1531 | |
f45d3416 | 1532 | list_for_each_entry(li, &fdlocks->locks, llist) { |
85160e03 PS |
1533 | if (offset + length <= li->offset || |
1534 | offset >= li->offset + li->length) | |
1535 | continue; | |
081c0414 PS |
1536 | if (rw_check != CIFS_LOCK_OP && current->tgid == li->pid && |
1537 | server->ops->compare_fids(cfile, cur_cfile)) { | |
1538 | /* shared lock prevents write op through the same fid */ | |
1539 | if (!(li->type & server->vals->shared_lock_type) || | |
1540 | rw_check != CIFS_WRITE_OP) | |
1541 | continue; | |
1542 | } | |
f45d3416 PS |
1543 | if ((type & server->vals->shared_lock_type) && |
1544 | ((server->ops->compare_fids(cfile, cur_cfile) && | |
1545 | current->tgid == li->pid) || type == li->type)) | |
85160e03 | 1546 | continue; |
9645759c RS |
1547 | if (rw_check == CIFS_LOCK_OP && |
1548 | (flags & FL_OFDLCK) && (li->flags & FL_OFDLCK) && | |
1549 | server->ops->compare_fids(cfile, cur_cfile)) | |
1550 | continue; | |
579f9053 PS |
1551 | if (conf_lock) |
1552 | *conf_lock = li; | |
f45d3416 | 1553 | return true; |
85160e03 PS |
1554 | } |
1555 | return false; | |
1556 | } | |
1557 | ||
579f9053 | 1558 | bool |
55157dfb | 1559 | cifs_find_lock_conflict(struct cifsFileInfo *cfile, __u64 offset, __u64 length, |
9645759c RS |
1560 | __u8 type, __u16 flags, |
1561 | struct cifsLockInfo **conf_lock, int rw_check) | |
161ebf9f | 1562 | { |
fbd35aca | 1563 | bool rc = false; |
f45d3416 | 1564 | struct cifs_fid_locks *cur; |
2b0143b5 | 1565 | struct cifsInodeInfo *cinode = CIFS_I(d_inode(cfile->dentry)); |
fbd35aca | 1566 | |
f45d3416 PS |
1567 | list_for_each_entry(cur, &cinode->llist, llist) { |
1568 | rc = cifs_find_fid_lock_conflict(cur, offset, length, type, | |
9645759c RS |
1569 | flags, cfile, conf_lock, |
1570 | rw_check); | |
fbd35aca PS |
1571 | if (rc) |
1572 | break; | |
1573 | } | |
fbd35aca PS |
1574 | |
1575 | return rc; | |
161ebf9f PS |
1576 | } |
1577 | ||
9a5101c8 PS |
1578 | /* |
1579 | * Check if there is another lock that prevents us to set the lock (mandatory | |
1580 | * style). If such a lock exists, update the flock structure with its | |
1581 | * properties. Otherwise, set the flock type to F_UNLCK if we can cache brlocks | |
1582 | * or leave it the same if we can't. Returns 0 if we don't need to request to | |
1583 | * the server or 1 otherwise. | |
1584 | */ | |
85160e03 | 1585 | static int |
fbd35aca PS |
1586 | cifs_lock_test(struct cifsFileInfo *cfile, __u64 offset, __u64 length, |
1587 | __u8 type, struct file_lock *flock) | |
85160e03 PS |
1588 | { |
1589 | int rc = 0; | |
1590 | struct cifsLockInfo *conf_lock; | |
2b0143b5 | 1591 | struct cifsInodeInfo *cinode = CIFS_I(d_inode(cfile->dentry)); |
106dc538 | 1592 | struct TCP_Server_Info *server = tlink_tcon(cfile->tlink)->ses->server; |
85160e03 PS |
1593 | bool exist; |
1594 | ||
1b4b55a1 | 1595 | down_read(&cinode->lock_sem); |
85160e03 | 1596 | |
55157dfb | 1597 | exist = cifs_find_lock_conflict(cfile, offset, length, type, |
84e286c1 | 1598 | flock->c.flc_flags, &conf_lock, |
9645759c | 1599 | CIFS_LOCK_OP); |
85160e03 PS |
1600 | if (exist) { |
1601 | flock->fl_start = conf_lock->offset; | |
1602 | flock->fl_end = conf_lock->offset + conf_lock->length - 1; | |
84e286c1 | 1603 | flock->c.flc_pid = conf_lock->pid; |
106dc538 | 1604 | if (conf_lock->type & server->vals->shared_lock_type) |
84e286c1 | 1605 | flock->c.flc_type = F_RDLCK; |
85160e03 | 1606 | else |
84e286c1 | 1607 | flock->c.flc_type = F_WRLCK; |
85160e03 PS |
1608 | } else if (!cinode->can_cache_brlcks) |
1609 | rc = 1; | |
1610 | else | |
84e286c1 | 1611 | flock->c.flc_type = F_UNLCK; |
85160e03 | 1612 | |
1b4b55a1 | 1613 | up_read(&cinode->lock_sem); |
85160e03 PS |
1614 | return rc; |
1615 | } | |
1616 | ||
161ebf9f | 1617 | static void |
fbd35aca | 1618 | cifs_lock_add(struct cifsFileInfo *cfile, struct cifsLockInfo *lock) |
85160e03 | 1619 | { |
2b0143b5 | 1620 | struct cifsInodeInfo *cinode = CIFS_I(d_inode(cfile->dentry)); |
d46b0da7 | 1621 | cifs_down_write(&cinode->lock_sem); |
f45d3416 | 1622 | list_add_tail(&lock->llist, &cfile->llist->locks); |
1b4b55a1 | 1623 | up_write(&cinode->lock_sem); |
7ee1af76 JA |
1624 | } |
1625 | ||
9a5101c8 PS |
1626 | /* |
1627 | * Set the byte-range lock (mandatory style). Returns: | |
1628 | * 1) 0, if we set the lock and don't need to request to the server; | |
1629 | * 2) 1, if no locks prevent us but we need to request to the server; | |
413d6100 | 1630 | * 3) -EACCES, if there is a lock that prevents us and wait is false. |
9a5101c8 | 1631 | */ |
85160e03 | 1632 | static int |
fbd35aca | 1633 | cifs_lock_add_if(struct cifsFileInfo *cfile, struct cifsLockInfo *lock, |
161ebf9f | 1634 | bool wait) |
85160e03 | 1635 | { |
161ebf9f | 1636 | struct cifsLockInfo *conf_lock; |
2b0143b5 | 1637 | struct cifsInodeInfo *cinode = CIFS_I(d_inode(cfile->dentry)); |
85160e03 PS |
1638 | bool exist; |
1639 | int rc = 0; | |
1640 | ||
85160e03 PS |
1641 | try_again: |
1642 | exist = false; | |
d46b0da7 | 1643 | cifs_down_write(&cinode->lock_sem); |
85160e03 | 1644 | |
55157dfb | 1645 | exist = cifs_find_lock_conflict(cfile, lock->offset, lock->length, |
9645759c RS |
1646 | lock->type, lock->flags, &conf_lock, |
1647 | CIFS_LOCK_OP); | |
85160e03 | 1648 | if (!exist && cinode->can_cache_brlcks) { |
f45d3416 | 1649 | list_add_tail(&lock->llist, &cfile->llist->locks); |
1b4b55a1 | 1650 | up_write(&cinode->lock_sem); |
85160e03 PS |
1651 | return rc; |
1652 | } | |
1653 | ||
1654 | if (!exist) | |
1655 | rc = 1; | |
1656 | else if (!wait) | |
1657 | rc = -EACCES; | |
1658 | else { | |
1659 | list_add_tail(&lock->blist, &conf_lock->blist); | |
1b4b55a1 | 1660 | up_write(&cinode->lock_sem); |
85160e03 PS |
1661 | rc = wait_event_interruptible(lock->block_q, |
1662 | (lock->blist.prev == &lock->blist) && | |
1663 | (lock->blist.next == &lock->blist)); | |
1664 | if (!rc) | |
1665 | goto try_again; | |
d46b0da7 | 1666 | cifs_down_write(&cinode->lock_sem); |
a88b4707 | 1667 | list_del_init(&lock->blist); |
85160e03 PS |
1668 | } |
1669 | ||
1b4b55a1 | 1670 | up_write(&cinode->lock_sem); |
85160e03 PS |
1671 | return rc; |
1672 | } | |
1673 | ||
fb157ed2 | 1674 | #ifdef CONFIG_CIFS_ALLOW_INSECURE_LEGACY |
9a5101c8 PS |
1675 | /* |
1676 | * Check if there is another lock that prevents us to set the lock (posix | |
1677 | * style). If such a lock exists, update the flock structure with its | |
1678 | * properties. Otherwise, set the flock type to F_UNLCK if we can cache brlocks | |
1679 | * or leave it the same if we can't. Returns 0 if we don't need to request to | |
1680 | * the server or 1 otherwise. | |
1681 | */ | |
85160e03 | 1682 | static int |
4f6bcec9 PS |
1683 | cifs_posix_lock_test(struct file *file, struct file_lock *flock) |
1684 | { | |
1685 | int rc = 0; | |
496ad9aa | 1686 | struct cifsInodeInfo *cinode = CIFS_I(file_inode(file)); |
84e286c1 | 1687 | unsigned char saved_type = flock->c.flc_type; |
4f6bcec9 | 1688 | |
84e286c1 | 1689 | if ((flock->c.flc_flags & FL_POSIX) == 0) |
50792760 PS |
1690 | return 1; |
1691 | ||
1b4b55a1 | 1692 | down_read(&cinode->lock_sem); |
4f6bcec9 PS |
1693 | posix_test_lock(file, flock); |
1694 | ||
2cd11429 | 1695 | if (lock_is_unlock(flock) && !cinode->can_cache_brlcks) { |
84e286c1 | 1696 | flock->c.flc_type = saved_type; |
4f6bcec9 PS |
1697 | rc = 1; |
1698 | } | |
1699 | ||
1b4b55a1 | 1700 | up_read(&cinode->lock_sem); |
4f6bcec9 PS |
1701 | return rc; |
1702 | } | |
1703 | ||
9a5101c8 PS |
1704 | /* |
1705 | * Set the byte-range lock (posix style). Returns: | |
2e98c018 | 1706 | * 1) <0, if the error occurs while setting the lock; |
1707 | * 2) 0, if we set the lock and don't need to request to the server; | |
1708 | * 3) FILE_LOCK_DEFERRED, if we will wait for some other file_lock; | |
1709 | * 4) FILE_LOCK_DEFERRED + 1, if we need to request to the server. | |
9a5101c8 | 1710 | */ |
4f6bcec9 PS |
1711 | static int |
1712 | cifs_posix_lock_set(struct file *file, struct file_lock *flock) | |
1713 | { | |
496ad9aa | 1714 | struct cifsInodeInfo *cinode = CIFS_I(file_inode(file)); |
2e98c018 | 1715 | int rc = FILE_LOCK_DEFERRED + 1; |
50792760 | 1716 | |
84e286c1 | 1717 | if ((flock->c.flc_flags & FL_POSIX) == 0) |
50792760 | 1718 | return rc; |
4f6bcec9 | 1719 | |
d46b0da7 | 1720 | cifs_down_write(&cinode->lock_sem); |
4f6bcec9 | 1721 | if (!cinode->can_cache_brlcks) { |
1b4b55a1 | 1722 | up_write(&cinode->lock_sem); |
50792760 | 1723 | return rc; |
4f6bcec9 | 1724 | } |
66189be7 PS |
1725 | |
1726 | rc = posix_lock_file(file, flock, NULL); | |
1b4b55a1 | 1727 | up_write(&cinode->lock_sem); |
9ebb389d | 1728 | return rc; |
4f6bcec9 PS |
1729 | } |
1730 | ||
d39a4f71 | 1731 | int |
4f6bcec9 | 1732 | cifs_push_mandatory_locks(struct cifsFileInfo *cfile) |
85160e03 | 1733 | { |
6d5786a3 PS |
1734 | unsigned int xid; |
1735 | int rc = 0, stored_rc; | |
85160e03 PS |
1736 | struct cifsLockInfo *li, *tmp; |
1737 | struct cifs_tcon *tcon; | |
0013fb4c | 1738 | unsigned int num, max_num, max_buf; |
32b9aaf1 | 1739 | LOCKING_ANDX_RANGE *buf, *cur; |
4d61eda8 CIK |
1740 | static const int types[] = { |
1741 | LOCKING_ANDX_LARGE_FILES, | |
1742 | LOCKING_ANDX_SHARED_LOCK | LOCKING_ANDX_LARGE_FILES | |
1743 | }; | |
32b9aaf1 | 1744 | int i; |
85160e03 | 1745 | |
6d5786a3 | 1746 | xid = get_xid(); |
85160e03 PS |
1747 | tcon = tlink_tcon(cfile->tlink); |
1748 | ||
0013fb4c PS |
1749 | /* |
1750 | * Accessing maxBuf is racy with cifs_reconnect - need to store value | |
b9a74cde | 1751 | * and check it before using. |
0013fb4c PS |
1752 | */ |
1753 | max_buf = tcon->ses->server->maxBuf; | |
b9a74cde | 1754 | if (max_buf < (sizeof(struct smb_hdr) + sizeof(LOCKING_ANDX_RANGE))) { |
6d5786a3 | 1755 | free_xid(xid); |
0013fb4c PS |
1756 | return -EINVAL; |
1757 | } | |
1758 | ||
92a8109e RL |
1759 | BUILD_BUG_ON(sizeof(struct smb_hdr) + sizeof(LOCKING_ANDX_RANGE) > |
1760 | PAGE_SIZE); | |
1761 | max_buf = min_t(unsigned int, max_buf - sizeof(struct smb_hdr), | |
1762 | PAGE_SIZE); | |
0013fb4c PS |
1763 | max_num = (max_buf - sizeof(struct smb_hdr)) / |
1764 | sizeof(LOCKING_ANDX_RANGE); | |
4b99d39b | 1765 | buf = kcalloc(max_num, sizeof(LOCKING_ANDX_RANGE), GFP_KERNEL); |
32b9aaf1 | 1766 | if (!buf) { |
6d5786a3 | 1767 | free_xid(xid); |
e2f2886a | 1768 | return -ENOMEM; |
32b9aaf1 PS |
1769 | } |
1770 | ||
1771 | for (i = 0; i < 2; i++) { | |
1772 | cur = buf; | |
1773 | num = 0; | |
f45d3416 | 1774 | list_for_each_entry_safe(li, tmp, &cfile->llist->locks, llist) { |
32b9aaf1 PS |
1775 | if (li->type != types[i]) |
1776 | continue; | |
1777 | cur->Pid = cpu_to_le16(li->pid); | |
1778 | cur->LengthLow = cpu_to_le32((u32)li->length); | |
1779 | cur->LengthHigh = cpu_to_le32((u32)(li->length>>32)); | |
1780 | cur->OffsetLow = cpu_to_le32((u32)li->offset); | |
1781 | cur->OffsetHigh = cpu_to_le32((u32)(li->offset>>32)); | |
1782 | if (++num == max_num) { | |
4b4de76e PS |
1783 | stored_rc = cifs_lockv(xid, tcon, |
1784 | cfile->fid.netfid, | |
04a6aa8a PS |
1785 | (__u8)li->type, 0, num, |
1786 | buf); | |
32b9aaf1 PS |
1787 | if (stored_rc) |
1788 | rc = stored_rc; | |
1789 | cur = buf; | |
1790 | num = 0; | |
1791 | } else | |
1792 | cur++; | |
1793 | } | |
1794 | ||
1795 | if (num) { | |
4b4de76e | 1796 | stored_rc = cifs_lockv(xid, tcon, cfile->fid.netfid, |
04a6aa8a | 1797 | (__u8)types[i], 0, num, buf); |
32b9aaf1 PS |
1798 | if (stored_rc) |
1799 | rc = stored_rc; | |
1800 | } | |
85160e03 PS |
1801 | } |
1802 | ||
32b9aaf1 | 1803 | kfree(buf); |
6d5786a3 | 1804 | free_xid(xid); |
85160e03 PS |
1805 | return rc; |
1806 | } | |
1807 | ||
3d22462a JL |
1808 | static __u32 |
1809 | hash_lockowner(fl_owner_t owner) | |
1810 | { | |
1811 | return cifs_lock_secret ^ hash32_ptr((const void *)owner); | |
1812 | } | |
fb157ed2 | 1813 | #endif /* CONFIG_CIFS_ALLOW_INSECURE_LEGACY */ |
3d22462a | 1814 | |
d5751469 PS |
1815 | struct lock_to_push { |
1816 | struct list_head llist; | |
1817 | __u64 offset; | |
1818 | __u64 length; | |
1819 | __u32 pid; | |
1820 | __u16 netfid; | |
1821 | __u8 type; | |
1822 | }; | |
1823 | ||
fb157ed2 | 1824 | #ifdef CONFIG_CIFS_ALLOW_INSECURE_LEGACY |
4f6bcec9 | 1825 | static int |
b8db928b | 1826 | cifs_push_posix_locks(struct cifsFileInfo *cfile) |
4f6bcec9 | 1827 | { |
2b0143b5 | 1828 | struct inode *inode = d_inode(cfile->dentry); |
4f6bcec9 | 1829 | struct cifs_tcon *tcon = tlink_tcon(cfile->tlink); |
bd61e0a9 | 1830 | struct file_lock *flock; |
a1fde8ee | 1831 | struct file_lock_context *flctx = locks_inode_context(inode); |
e084c1bd | 1832 | unsigned int count = 0, i; |
4f6bcec9 | 1833 | int rc = 0, xid, type; |
d5751469 PS |
1834 | struct list_head locks_to_send, *el; |
1835 | struct lock_to_push *lck, *tmp; | |
4f6bcec9 | 1836 | __u64 length; |
4f6bcec9 | 1837 | |
6d5786a3 | 1838 | xid = get_xid(); |
4f6bcec9 | 1839 | |
bd61e0a9 JL |
1840 | if (!flctx) |
1841 | goto out; | |
d5751469 | 1842 | |
e084c1bd JL |
1843 | spin_lock(&flctx->flc_lock); |
1844 | list_for_each(el, &flctx->flc_posix) { | |
1845 | count++; | |
1846 | } | |
1847 | spin_unlock(&flctx->flc_lock); | |
1848 | ||
4f6bcec9 PS |
1849 | INIT_LIST_HEAD(&locks_to_send); |
1850 | ||
d5751469 | 1851 | /* |
e084c1bd JL |
1852 | * Allocating count locks is enough because no FL_POSIX locks can be |
1853 | * added to the list while we are holding cinode->lock_sem that | |
ce85852b | 1854 | * protects locking operations of this inode. |
d5751469 | 1855 | */ |
e084c1bd | 1856 | for (i = 0; i < count; i++) { |
d5751469 PS |
1857 | lck = kmalloc(sizeof(struct lock_to_push), GFP_KERNEL); |
1858 | if (!lck) { | |
1859 | rc = -ENOMEM; | |
1860 | goto err_out; | |
1861 | } | |
1862 | list_add_tail(&lck->llist, &locks_to_send); | |
1863 | } | |
1864 | ||
d5751469 | 1865 | el = locks_to_send.next; |
6109c850 | 1866 | spin_lock(&flctx->flc_lock); |
2cd11429 | 1867 | for_each_file_lock(flock, &flctx->flc_posix) { |
84e286c1 JL |
1868 | unsigned char ftype = flock->c.flc_type; |
1869 | ||
d5751469 | 1870 | if (el == &locks_to_send) { |
ce85852b PS |
1871 | /* |
1872 | * The list ended. We don't have enough allocated | |
1873 | * structures - something is really wrong. | |
1874 | */ | |
f96637be | 1875 | cifs_dbg(VFS, "Can't push all brlocks!\n"); |
d5751469 PS |
1876 | break; |
1877 | } | |
d80c6984 | 1878 | length = cifs_flock_len(flock); |
84e286c1 | 1879 | if (ftype == F_RDLCK || ftype == F_SHLCK) |
4f6bcec9 PS |
1880 | type = CIFS_RDLCK; |
1881 | else | |
1882 | type = CIFS_WRLCK; | |
d5751469 | 1883 | lck = list_entry(el, struct lock_to_push, llist); |
84e286c1 | 1884 | lck->pid = hash_lockowner(flock->c.flc_owner); |
4b4de76e | 1885 | lck->netfid = cfile->fid.netfid; |
d5751469 PS |
1886 | lck->length = length; |
1887 | lck->type = type; | |
1888 | lck->offset = flock->fl_start; | |
4f6bcec9 | 1889 | } |
6109c850 | 1890 | spin_unlock(&flctx->flc_lock); |
4f6bcec9 PS |
1891 | |
1892 | list_for_each_entry_safe(lck, tmp, &locks_to_send, llist) { | |
4f6bcec9 PS |
1893 | int stored_rc; |
1894 | ||
4f6bcec9 | 1895 | stored_rc = CIFSSMBPosixLock(xid, tcon, lck->netfid, lck->pid, |
c5fd363d | 1896 | lck->offset, lck->length, NULL, |
4f6bcec9 PS |
1897 | lck->type, 0); |
1898 | if (stored_rc) | |
1899 | rc = stored_rc; | |
1900 | list_del(&lck->llist); | |
1901 | kfree(lck); | |
1902 | } | |
1903 | ||
d5751469 | 1904 | out: |
6d5786a3 | 1905 | free_xid(xid); |
4f6bcec9 | 1906 | return rc; |
d5751469 PS |
1907 | err_out: |
1908 | list_for_each_entry_safe(lck, tmp, &locks_to_send, llist) { | |
1909 | list_del(&lck->llist); | |
1910 | kfree(lck); | |
1911 | } | |
1912 | goto out; | |
4f6bcec9 | 1913 | } |
fb157ed2 | 1914 | #endif /* CONFIG_CIFS_ALLOW_INSECURE_LEGACY */ |
4f6bcec9 | 1915 | |
9ec3c882 | 1916 | static int |
b8db928b | 1917 | cifs_push_locks(struct cifsFileInfo *cfile) |
9ec3c882 | 1918 | { |
2b0143b5 | 1919 | struct cifsInodeInfo *cinode = CIFS_I(d_inode(cfile->dentry)); |
b8db928b | 1920 | struct cifs_tcon *tcon = tlink_tcon(cfile->tlink); |
9ec3c882 | 1921 | int rc = 0; |
fb157ed2 SF |
1922 | #ifdef CONFIG_CIFS_ALLOW_INSECURE_LEGACY |
1923 | struct cifs_sb_info *cifs_sb = CIFS_SB(cfile->dentry->d_sb); | |
1924 | #endif /* CONFIG_CIFS_ALLOW_INSECURE_LEGACY */ | |
9ec3c882 PS |
1925 | |
1926 | /* we are going to update can_cache_brlcks here - need a write access */ | |
d46b0da7 | 1927 | cifs_down_write(&cinode->lock_sem); |
9ec3c882 PS |
1928 | if (!cinode->can_cache_brlcks) { |
1929 | up_write(&cinode->lock_sem); | |
1930 | return rc; | |
1931 | } | |
4f6bcec9 | 1932 | |
fb157ed2 | 1933 | #ifdef CONFIG_CIFS_ALLOW_INSECURE_LEGACY |
29e20f9c | 1934 | if (cap_unix(tcon->ses) && |
4f6bcec9 PS |
1935 | (CIFS_UNIX_FCNTL_CAP & le64_to_cpu(tcon->fsUnixInfo.Capability)) && |
1936 | ((cifs_sb->mnt_cifs_flags & CIFS_MOUNT_NOPOSIXBRL) == 0)) | |
b8db928b PS |
1937 | rc = cifs_push_posix_locks(cfile); |
1938 | else | |
fb157ed2 | 1939 | #endif /* CONFIG_CIFS_ALLOW_INSECURE_LEGACY */ |
b8db928b | 1940 | rc = tcon->ses->server->ops->push_mand_locks(cfile); |
4f6bcec9 | 1941 | |
b8db928b PS |
1942 | cinode->can_cache_brlcks = false; |
1943 | up_write(&cinode->lock_sem); | |
1944 | return rc; | |
4f6bcec9 PS |
1945 | } |
1946 | ||
03776f45 | 1947 | static void |
04a6aa8a | 1948 | cifs_read_flock(struct file_lock *flock, __u32 *type, int *lock, int *unlock, |
106dc538 | 1949 | bool *wait_flag, struct TCP_Server_Info *server) |
1da177e4 | 1950 | { |
84e286c1 | 1951 | if (flock->c.flc_flags & FL_POSIX) |
f96637be | 1952 | cifs_dbg(FYI, "Posix\n"); |
84e286c1 | 1953 | if (flock->c.flc_flags & FL_FLOCK) |
f96637be | 1954 | cifs_dbg(FYI, "Flock\n"); |
84e286c1 | 1955 | if (flock->c.flc_flags & FL_SLEEP) { |
f96637be | 1956 | cifs_dbg(FYI, "Blocking lock\n"); |
03776f45 | 1957 | *wait_flag = true; |
1da177e4 | 1958 | } |
84e286c1 | 1959 | if (flock->c.flc_flags & FL_ACCESS) |
f96637be | 1960 | cifs_dbg(FYI, "Process suspended by mandatory locking - not implemented yet\n"); |
84e286c1 | 1961 | if (flock->c.flc_flags & FL_LEASE) |
f96637be | 1962 | cifs_dbg(FYI, "Lease on file - not implemented yet\n"); |
84e286c1 | 1963 | if (flock->c.flc_flags & |
3d6d854a | 1964 | (~(FL_POSIX | FL_FLOCK | FL_SLEEP | |
9645759c | 1965 | FL_ACCESS | FL_LEASE | FL_CLOSE | FL_OFDLCK))) |
84e286c1 JL |
1966 | cifs_dbg(FYI, "Unknown lock flags 0x%x\n", |
1967 | flock->c.flc_flags); | |
1da177e4 | 1968 | |
106dc538 | 1969 | *type = server->vals->large_lock_type; |
2cd11429 | 1970 | if (lock_is_write(flock)) { |
f96637be | 1971 | cifs_dbg(FYI, "F_WRLCK\n"); |
106dc538 | 1972 | *type |= server->vals->exclusive_lock_type; |
03776f45 | 1973 | *lock = 1; |
2cd11429 | 1974 | } else if (lock_is_unlock(flock)) { |
f96637be | 1975 | cifs_dbg(FYI, "F_UNLCK\n"); |
106dc538 | 1976 | *type |= server->vals->unlock_lock_type; |
03776f45 PS |
1977 | *unlock = 1; |
1978 | /* Check if unlock includes more than one lock range */ | |
2cd11429 | 1979 | } else if (lock_is_read(flock)) { |
f96637be | 1980 | cifs_dbg(FYI, "F_RDLCK\n"); |
106dc538 | 1981 | *type |= server->vals->shared_lock_type; |
03776f45 | 1982 | *lock = 1; |
84e286c1 | 1983 | } else if (flock->c.flc_type == F_EXLCK) { |
f96637be | 1984 | cifs_dbg(FYI, "F_EXLCK\n"); |
106dc538 | 1985 | *type |= server->vals->exclusive_lock_type; |
03776f45 | 1986 | *lock = 1; |
84e286c1 | 1987 | } else if (flock->c.flc_type == F_SHLCK) { |
f96637be | 1988 | cifs_dbg(FYI, "F_SHLCK\n"); |
106dc538 | 1989 | *type |= server->vals->shared_lock_type; |
03776f45 | 1990 | *lock = 1; |
1da177e4 | 1991 | } else |
f96637be | 1992 | cifs_dbg(FYI, "Unknown type of lock\n"); |
03776f45 | 1993 | } |
1da177e4 | 1994 | |
03776f45 | 1995 | static int |
04a6aa8a | 1996 | cifs_getlk(struct file *file, struct file_lock *flock, __u32 type, |
6d5786a3 | 1997 | bool wait_flag, bool posix_lck, unsigned int xid) |
03776f45 PS |
1998 | { |
1999 | int rc = 0; | |
d80c6984 | 2000 | __u64 length = cifs_flock_len(flock); |
4f6bcec9 PS |
2001 | struct cifsFileInfo *cfile = (struct cifsFileInfo *)file->private_data; |
2002 | struct cifs_tcon *tcon = tlink_tcon(cfile->tlink); | |
106dc538 | 2003 | struct TCP_Server_Info *server = tcon->ses->server; |
fb157ed2 | 2004 | #ifdef CONFIG_CIFS_ALLOW_INSECURE_LEGACY |
4b4de76e | 2005 | __u16 netfid = cfile->fid.netfid; |
f05337c6 | 2006 | |
03776f45 PS |
2007 | if (posix_lck) { |
2008 | int posix_lock_type; | |
4f6bcec9 PS |
2009 | |
2010 | rc = cifs_posix_lock_test(file, flock); | |
2011 | if (!rc) | |
2012 | return rc; | |
2013 | ||
106dc538 | 2014 | if (type & server->vals->shared_lock_type) |
03776f45 PS |
2015 | posix_lock_type = CIFS_RDLCK; |
2016 | else | |
2017 | posix_lock_type = CIFS_WRLCK; | |
3d22462a | 2018 | rc = CIFSSMBPosixLock(xid, tcon, netfid, |
84e286c1 | 2019 | hash_lockowner(flock->c.flc_owner), |
c5fd363d | 2020 | flock->fl_start, length, flock, |
4f6bcec9 | 2021 | posix_lock_type, wait_flag); |
03776f45 PS |
2022 | return rc; |
2023 | } | |
fb157ed2 | 2024 | #endif /* CONFIG_CIFS_ALLOW_INSECURE_LEGACY */ |
1da177e4 | 2025 | |
fbd35aca | 2026 | rc = cifs_lock_test(cfile, flock->fl_start, length, type, flock); |
85160e03 PS |
2027 | if (!rc) |
2028 | return rc; | |
2029 | ||
03776f45 | 2030 | /* BB we could chain these into one lock request BB */ |
d39a4f71 PS |
2031 | rc = server->ops->mand_lock(xid, cfile, flock->fl_start, length, type, |
2032 | 1, 0, false); | |
03776f45 | 2033 | if (rc == 0) { |
d39a4f71 PS |
2034 | rc = server->ops->mand_lock(xid, cfile, flock->fl_start, length, |
2035 | type, 0, 1, false); | |
84e286c1 | 2036 | flock->c.flc_type = F_UNLCK; |
03776f45 | 2037 | if (rc != 0) |
f96637be JP |
2038 | cifs_dbg(VFS, "Error unlocking previously locked range %d during test of lock\n", |
2039 | rc); | |
a88b4707 | 2040 | return 0; |
1da177e4 | 2041 | } |
7ee1af76 | 2042 | |
106dc538 | 2043 | if (type & server->vals->shared_lock_type) { |
84e286c1 | 2044 | flock->c.flc_type = F_WRLCK; |
a88b4707 | 2045 | return 0; |
7ee1af76 JA |
2046 | } |
2047 | ||
d39a4f71 PS |
2048 | type &= ~server->vals->exclusive_lock_type; |
2049 | ||
2050 | rc = server->ops->mand_lock(xid, cfile, flock->fl_start, length, | |
2051 | type | server->vals->shared_lock_type, | |
2052 | 1, 0, false); | |
03776f45 | 2053 | if (rc == 0) { |
d39a4f71 PS |
2054 | rc = server->ops->mand_lock(xid, cfile, flock->fl_start, length, |
2055 | type | server->vals->shared_lock_type, 0, 1, false); | |
84e286c1 | 2056 | flock->c.flc_type = F_RDLCK; |
03776f45 | 2057 | if (rc != 0) |
f96637be JP |
2058 | cifs_dbg(VFS, "Error unlocking previously locked range %d during test of lock\n", |
2059 | rc); | |
03776f45 | 2060 | } else |
84e286c1 | 2061 | flock->c.flc_type = F_WRLCK; |
03776f45 | 2062 | |
a88b4707 | 2063 | return 0; |
03776f45 PS |
2064 | } |
2065 | ||
f7ba7fe6 | 2066 | void |
9ee305b7 PS |
2067 | cifs_move_llist(struct list_head *source, struct list_head *dest) |
2068 | { | |
2069 | struct list_head *li, *tmp; | |
2070 | list_for_each_safe(li, tmp, source) | |
2071 | list_move(li, dest); | |
2072 | } | |
2073 | ||
f7ba7fe6 | 2074 | void |
9ee305b7 PS |
2075 | cifs_free_llist(struct list_head *llist) |
2076 | { | |
2077 | struct cifsLockInfo *li, *tmp; | |
2078 | list_for_each_entry_safe(li, tmp, llist, llist) { | |
2079 | cifs_del_lock_waiters(li); | |
2080 | list_del(&li->llist); | |
2081 | kfree(li); | |
2082 | } | |
2083 | } | |
2084 | ||
fb157ed2 | 2085 | #ifdef CONFIG_CIFS_ALLOW_INSECURE_LEGACY |
d39a4f71 | 2086 | int |
6d5786a3 PS |
2087 | cifs_unlock_range(struct cifsFileInfo *cfile, struct file_lock *flock, |
2088 | unsigned int xid) | |
9ee305b7 PS |
2089 | { |
2090 | int rc = 0, stored_rc; | |
4d61eda8 CIK |
2091 | static const int types[] = { |
2092 | LOCKING_ANDX_LARGE_FILES, | |
2093 | LOCKING_ANDX_SHARED_LOCK | LOCKING_ANDX_LARGE_FILES | |
2094 | }; | |
9ee305b7 | 2095 | unsigned int i; |
0013fb4c | 2096 | unsigned int max_num, num, max_buf; |
9ee305b7 PS |
2097 | LOCKING_ANDX_RANGE *buf, *cur; |
2098 | struct cifs_tcon *tcon = tlink_tcon(cfile->tlink); | |
2b0143b5 | 2099 | struct cifsInodeInfo *cinode = CIFS_I(d_inode(cfile->dentry)); |
9ee305b7 | 2100 | struct cifsLockInfo *li, *tmp; |
d80c6984 | 2101 | __u64 length = cifs_flock_len(flock); |
21dcbc17 | 2102 | LIST_HEAD(tmp_llist); |
9ee305b7 | 2103 | |
0013fb4c PS |
2104 | /* |
2105 | * Accessing maxBuf is racy with cifs_reconnect - need to store value | |
b9a74cde | 2106 | * and check it before using. |
0013fb4c PS |
2107 | */ |
2108 | max_buf = tcon->ses->server->maxBuf; | |
b9a74cde | 2109 | if (max_buf < (sizeof(struct smb_hdr) + sizeof(LOCKING_ANDX_RANGE))) |
0013fb4c PS |
2110 | return -EINVAL; |
2111 | ||
92a8109e RL |
2112 | BUILD_BUG_ON(sizeof(struct smb_hdr) + sizeof(LOCKING_ANDX_RANGE) > |
2113 | PAGE_SIZE); | |
2114 | max_buf = min_t(unsigned int, max_buf - sizeof(struct smb_hdr), | |
2115 | PAGE_SIZE); | |
0013fb4c PS |
2116 | max_num = (max_buf - sizeof(struct smb_hdr)) / |
2117 | sizeof(LOCKING_ANDX_RANGE); | |
4b99d39b | 2118 | buf = kcalloc(max_num, sizeof(LOCKING_ANDX_RANGE), GFP_KERNEL); |
9ee305b7 PS |
2119 | if (!buf) |
2120 | return -ENOMEM; | |
2121 | ||
d46b0da7 | 2122 | cifs_down_write(&cinode->lock_sem); |
9ee305b7 PS |
2123 | for (i = 0; i < 2; i++) { |
2124 | cur = buf; | |
2125 | num = 0; | |
f45d3416 | 2126 | list_for_each_entry_safe(li, tmp, &cfile->llist->locks, llist) { |
9ee305b7 PS |
2127 | if (flock->fl_start > li->offset || |
2128 | (flock->fl_start + length) < | |
2129 | (li->offset + li->length)) | |
2130 | continue; | |
2131 | if (current->tgid != li->pid) | |
2132 | continue; | |
9ee305b7 PS |
2133 | if (types[i] != li->type) |
2134 | continue; | |
ea319d57 | 2135 | if (cinode->can_cache_brlcks) { |
9ee305b7 PS |
2136 | /* |
2137 | * We can cache brlock requests - simply remove | |
fbd35aca | 2138 | * a lock from the file's list. |
9ee305b7 PS |
2139 | */ |
2140 | list_del(&li->llist); | |
2141 | cifs_del_lock_waiters(li); | |
2142 | kfree(li); | |
ea319d57 | 2143 | continue; |
9ee305b7 | 2144 | } |
ea319d57 PS |
2145 | cur->Pid = cpu_to_le16(li->pid); |
2146 | cur->LengthLow = cpu_to_le32((u32)li->length); | |
2147 | cur->LengthHigh = cpu_to_le32((u32)(li->length>>32)); | |
2148 | cur->OffsetLow = cpu_to_le32((u32)li->offset); | |
2149 | cur->OffsetHigh = cpu_to_le32((u32)(li->offset>>32)); | |
2150 | /* | |
2151 | * We need to save a lock here to let us add it again to | |
2152 | * the file's list if the unlock range request fails on | |
2153 | * the server. | |
2154 | */ | |
2155 | list_move(&li->llist, &tmp_llist); | |
2156 | if (++num == max_num) { | |
4b4de76e PS |
2157 | stored_rc = cifs_lockv(xid, tcon, |
2158 | cfile->fid.netfid, | |
ea319d57 PS |
2159 | li->type, num, 0, buf); |
2160 | if (stored_rc) { | |
2161 | /* | |
2162 | * We failed on the unlock range | |
2163 | * request - add all locks from the tmp | |
2164 | * list to the head of the file's list. | |
2165 | */ | |
2166 | cifs_move_llist(&tmp_llist, | |
f45d3416 | 2167 | &cfile->llist->locks); |
ea319d57 PS |
2168 | rc = stored_rc; |
2169 | } else | |
2170 | /* | |
2171 | * The unlock range request succeed - | |
2172 | * free the tmp list. | |
2173 | */ | |
2174 | cifs_free_llist(&tmp_llist); | |
2175 | cur = buf; | |
2176 | num = 0; | |
2177 | } else | |
2178 | cur++; | |
9ee305b7 PS |
2179 | } |
2180 | if (num) { | |
4b4de76e | 2181 | stored_rc = cifs_lockv(xid, tcon, cfile->fid.netfid, |
9ee305b7 PS |
2182 | types[i], num, 0, buf); |
2183 | if (stored_rc) { | |
f45d3416 PS |
2184 | cifs_move_llist(&tmp_llist, |
2185 | &cfile->llist->locks); | |
9ee305b7 PS |
2186 | rc = stored_rc; |
2187 | } else | |
2188 | cifs_free_llist(&tmp_llist); | |
2189 | } | |
2190 | } | |
2191 | ||
1b4b55a1 | 2192 | up_write(&cinode->lock_sem); |
9ee305b7 PS |
2193 | kfree(buf); |
2194 | return rc; | |
2195 | } | |
fb157ed2 | 2196 | #endif /* CONFIG_CIFS_ALLOW_INSECURE_LEGACY */ |
9ee305b7 | 2197 | |
03776f45 | 2198 | static int |
f45d3416 | 2199 | cifs_setlk(struct file *file, struct file_lock *flock, __u32 type, |
6d5786a3 PS |
2200 | bool wait_flag, bool posix_lck, int lock, int unlock, |
2201 | unsigned int xid) | |
03776f45 PS |
2202 | { |
2203 | int rc = 0; | |
d80c6984 | 2204 | __u64 length = cifs_flock_len(flock); |
03776f45 PS |
2205 | struct cifsFileInfo *cfile = (struct cifsFileInfo *)file->private_data; |
2206 | struct cifs_tcon *tcon = tlink_tcon(cfile->tlink); | |
106dc538 | 2207 | struct TCP_Server_Info *server = tcon->ses->server; |
2b0143b5 | 2208 | struct inode *inode = d_inode(cfile->dentry); |
03776f45 | 2209 | |
fb157ed2 | 2210 | #ifdef CONFIG_CIFS_ALLOW_INSECURE_LEGACY |
03776f45 | 2211 | if (posix_lck) { |
08547b03 | 2212 | int posix_lock_type; |
4f6bcec9 PS |
2213 | |
2214 | rc = cifs_posix_lock_set(file, flock); | |
2e98c018 | 2215 | if (rc <= FILE_LOCK_DEFERRED) |
4f6bcec9 PS |
2216 | return rc; |
2217 | ||
106dc538 | 2218 | if (type & server->vals->shared_lock_type) |
08547b03 SF |
2219 | posix_lock_type = CIFS_RDLCK; |
2220 | else | |
2221 | posix_lock_type = CIFS_WRLCK; | |
50c2f753 | 2222 | |
03776f45 | 2223 | if (unlock == 1) |
beb84dc8 | 2224 | posix_lock_type = CIFS_UNLCK; |
7ee1af76 | 2225 | |
f45d3416 | 2226 | rc = CIFSSMBPosixLock(xid, tcon, cfile->fid.netfid, |
84e286c1 | 2227 | hash_lockowner(flock->c.flc_owner), |
3d22462a | 2228 | flock->fl_start, length, |
f45d3416 | 2229 | NULL, posix_lock_type, wait_flag); |
03776f45 PS |
2230 | goto out; |
2231 | } | |
fb157ed2 | 2232 | #endif /* CONFIG_CIFS_ALLOW_INSECURE_LEGACY */ |
03776f45 | 2233 | if (lock) { |
161ebf9f PS |
2234 | struct cifsLockInfo *lock; |
2235 | ||
9645759c | 2236 | lock = cifs_lock_init(flock->fl_start, length, type, |
84e286c1 | 2237 | flock->c.flc_flags); |
161ebf9f PS |
2238 | if (!lock) |
2239 | return -ENOMEM; | |
2240 | ||
fbd35aca | 2241 | rc = cifs_lock_add_if(cfile, lock, wait_flag); |
21cb2d90 | 2242 | if (rc < 0) { |
161ebf9f | 2243 | kfree(lock); |
21cb2d90 PS |
2244 | return rc; |
2245 | } | |
2246 | if (!rc) | |
85160e03 PS |
2247 | goto out; |
2248 | ||
63b7d3a4 PS |
2249 | /* |
2250 | * Windows 7 server can delay breaking lease from read to None | |
2251 | * if we set a byte-range lock on a file - break it explicitly | |
2252 | * before sending the lock to the server to be sure the next | |
2253 | * read won't conflict with non-overlapted locks due to | |
2254 | * pagereading. | |
2255 | */ | |
18cceb6a PS |
2256 | if (!CIFS_CACHE_WRITE(CIFS_I(inode)) && |
2257 | CIFS_CACHE_READ(CIFS_I(inode))) { | |
4f73c7d3 | 2258 | cifs_zap_mapping(inode); |
f96637be JP |
2259 | cifs_dbg(FYI, "Set no oplock for inode=%p due to mand locks\n", |
2260 | inode); | |
18cceb6a | 2261 | CIFS_I(inode)->oplock = 0; |
63b7d3a4 PS |
2262 | } |
2263 | ||
d39a4f71 PS |
2264 | rc = server->ops->mand_lock(xid, cfile, flock->fl_start, length, |
2265 | type, 1, 0, wait_flag); | |
161ebf9f PS |
2266 | if (rc) { |
2267 | kfree(lock); | |
21cb2d90 | 2268 | return rc; |
03776f45 | 2269 | } |
161ebf9f | 2270 | |
fbd35aca | 2271 | cifs_lock_add(cfile, lock); |
9ee305b7 | 2272 | } else if (unlock) |
d39a4f71 | 2273 | rc = server->ops->mand_unlock_range(cfile, flock, xid); |
03776f45 | 2274 | |
03776f45 | 2275 | out: |
84e286c1 | 2276 | if ((flock->c.flc_flags & FL_POSIX) || (flock->c.flc_flags & FL_FLOCK)) { |
bc31d0cd AA |
2277 | /* |
2278 | * If this is a request to remove all locks because we | |
2279 | * are closing the file, it doesn't matter if the | |
2280 | * unlocking failed as both cifs.ko and the SMB server | |
2281 | * remove the lock on file close | |
2282 | */ | |
2283 | if (rc) { | |
2284 | cifs_dbg(VFS, "%s failed rc=%d\n", __func__, rc); | |
84e286c1 | 2285 | if (!(flock->c.flc_flags & FL_CLOSE)) |
bc31d0cd AA |
2286 | return rc; |
2287 | } | |
4f656367 | 2288 | rc = locks_lock_file_wait(file, flock); |
bc31d0cd | 2289 | } |
03776f45 PS |
2290 | return rc; |
2291 | } | |
2292 | ||
d0677992 SF |
2293 | int cifs_flock(struct file *file, int cmd, struct file_lock *fl) |
2294 | { | |
2295 | int rc, xid; | |
2296 | int lock = 0, unlock = 0; | |
2297 | bool wait_flag = false; | |
2298 | bool posix_lck = false; | |
2299 | struct cifs_sb_info *cifs_sb; | |
2300 | struct cifs_tcon *tcon; | |
d0677992 | 2301 | struct cifsFileInfo *cfile; |
d0677992 SF |
2302 | __u32 type; |
2303 | ||
d0677992 SF |
2304 | xid = get_xid(); |
2305 | ||
84e286c1 | 2306 | if (!(fl->c.flc_flags & FL_FLOCK)) { |
575e079c ZX |
2307 | rc = -ENOLCK; |
2308 | free_xid(xid); | |
2309 | return rc; | |
2310 | } | |
d0677992 SF |
2311 | |
2312 | cfile = (struct cifsFileInfo *)file->private_data; | |
2313 | tcon = tlink_tcon(cfile->tlink); | |
2314 | ||
2315 | cifs_read_flock(fl, &type, &lock, &unlock, &wait_flag, | |
2316 | tcon->ses->server); | |
2317 | cifs_sb = CIFS_FILE_SB(file); | |
d0677992 SF |
2318 | |
2319 | if (cap_unix(tcon->ses) && | |
2320 | (CIFS_UNIX_FCNTL_CAP & le64_to_cpu(tcon->fsUnixInfo.Capability)) && | |
2321 | ((cifs_sb->mnt_cifs_flags & CIFS_MOUNT_NOPOSIXBRL) == 0)) | |
2322 | posix_lck = true; | |
2323 | ||
2324 | if (!lock && !unlock) { | |
2325 | /* | |
2326 | * if no lock or unlock then nothing to do since we do not | |
2327 | * know what it is | |
2328 | */ | |
575e079c | 2329 | rc = -EOPNOTSUPP; |
d0677992 | 2330 | free_xid(xid); |
575e079c | 2331 | return rc; |
d0677992 SF |
2332 | } |
2333 | ||
2334 | rc = cifs_setlk(file, fl, type, wait_flag, posix_lck, lock, unlock, | |
2335 | xid); | |
2336 | free_xid(xid); | |
2337 | return rc; | |
2338 | ||
2339 | ||
2340 | } | |
2341 | ||
03776f45 PS |
2342 | int cifs_lock(struct file *file, int cmd, struct file_lock *flock) |
2343 | { | |
2344 | int rc, xid; | |
2345 | int lock = 0, unlock = 0; | |
2346 | bool wait_flag = false; | |
2347 | bool posix_lck = false; | |
2348 | struct cifs_sb_info *cifs_sb; | |
2349 | struct cifs_tcon *tcon; | |
03776f45 | 2350 | struct cifsFileInfo *cfile; |
04a6aa8a | 2351 | __u32 type; |
03776f45 PS |
2352 | |
2353 | rc = -EACCES; | |
6d5786a3 | 2354 | xid = get_xid(); |
03776f45 | 2355 | |
773891ff | 2356 | cifs_dbg(FYI, "%s: %pD2 cmd=0x%x type=0x%x flags=0x%x r=%lld:%lld\n", __func__, file, cmd, |
84e286c1 JL |
2357 | flock->c.flc_flags, flock->c.flc_type, |
2358 | (long long)flock->fl_start, | |
773891ff | 2359 | (long long)flock->fl_end); |
03776f45 | 2360 | |
03776f45 PS |
2361 | cfile = (struct cifsFileInfo *)file->private_data; |
2362 | tcon = tlink_tcon(cfile->tlink); | |
106dc538 PS |
2363 | |
2364 | cifs_read_flock(flock, &type, &lock, &unlock, &wait_flag, | |
2365 | tcon->ses->server); | |
7119e220 | 2366 | cifs_sb = CIFS_FILE_SB(file); |
35866f3f | 2367 | set_bit(CIFS_INO_CLOSE_ON_LOCK, &CIFS_I(d_inode(cfile->dentry))->flags); |
03776f45 | 2368 | |
29e20f9c | 2369 | if (cap_unix(tcon->ses) && |
03776f45 PS |
2370 | (CIFS_UNIX_FCNTL_CAP & le64_to_cpu(tcon->fsUnixInfo.Capability)) && |
2371 | ((cifs_sb->mnt_cifs_flags & CIFS_MOUNT_NOPOSIXBRL) == 0)) | |
2372 | posix_lck = true; | |
2373 | /* | |
2374 | * BB add code here to normalize offset and length to account for | |
2375 | * negative length which we can not accept over the wire. | |
2376 | */ | |
2377 | if (IS_GETLK(cmd)) { | |
4f6bcec9 | 2378 | rc = cifs_getlk(file, flock, type, wait_flag, posix_lck, xid); |
6d5786a3 | 2379 | free_xid(xid); |
03776f45 PS |
2380 | return rc; |
2381 | } | |
2382 | ||
2383 | if (!lock && !unlock) { | |
2384 | /* | |
2385 | * if no lock or unlock then nothing to do since we do not | |
2386 | * know what it is | |
2387 | */ | |
6d5786a3 | 2388 | free_xid(xid); |
03776f45 | 2389 | return -EOPNOTSUPP; |
7ee1af76 JA |
2390 | } |
2391 | ||
03776f45 PS |
2392 | rc = cifs_setlk(file, flock, type, wait_flag, posix_lck, lock, unlock, |
2393 | xid); | |
6d5786a3 | 2394 | free_xid(xid); |
1da177e4 LT |
2395 | return rc; |
2396 | } | |
2397 | ||
3ee1a1fc DH |
2398 | void cifs_write_subrequest_terminated(struct cifs_io_subrequest *wdata, ssize_t result, |
2399 | bool was_async) | |
fbec9ab9 | 2400 | { |
3ee1a1fc | 2401 | struct netfs_io_request *wreq = wdata->rreq; |
61ea6b3a DH |
2402 | struct netfs_inode *ictx = netfs_inode(wreq->inode); |
2403 | loff_t wrend; | |
fbec9ab9 | 2404 | |
3ee1a1fc | 2405 | if (result > 0) { |
61ea6b3a DH |
2406 | wrend = wdata->subreq.start + wdata->subreq.transferred + result; |
2407 | ||
2408 | if (wrend > ictx->zero_point && | |
2409 | (wdata->rreq->origin == NETFS_UNBUFFERED_WRITE || | |
2410 | wdata->rreq->origin == NETFS_DIO_WRITE)) | |
2411 | ictx->zero_point = wrend; | |
2412 | if (wrend > ictx->remote_i_size) | |
2413 | netfs_resize_file(ictx, wrend, true); | |
3ee1a1fc DH |
2414 | } |
2415 | ||
2416 | netfs_write_subrequest_terminated(&wdata->subreq, result, was_async); | |
fbec9ab9 JL |
2417 | } |
2418 | ||
6508d904 JL |
2419 | struct cifsFileInfo *find_readable_file(struct cifsInodeInfo *cifs_inode, |
2420 | bool fsuid_only) | |
630f3f0c SF |
2421 | { |
2422 | struct cifsFileInfo *open_file = NULL; | |
874c8ca1 | 2423 | struct cifs_sb_info *cifs_sb = CIFS_SB(cifs_inode->netfs.inode.i_sb); |
6508d904 JL |
2424 | |
2425 | /* only filter by fsuid on multiuser mounts */ | |
2426 | if (!(cifs_sb->mnt_cifs_flags & CIFS_MOUNT_MULTIUSER)) | |
2427 | fsuid_only = false; | |
630f3f0c | 2428 | |
cb248819 | 2429 | spin_lock(&cifs_inode->open_file_lock); |
630f3f0c SF |
2430 | /* we could simply get the first_list_entry since write-only entries |
2431 | are always at the end of the list but since the first entry might | |
2432 | have a close pending, we go through the whole list */ | |
2433 | list_for_each_entry(open_file, &cifs_inode->openFileList, flist) { | |
fef59fd7 | 2434 | if (fsuid_only && !uid_eq(open_file->uid, current_fsuid())) |
6508d904 | 2435 | continue; |
2e396b83 | 2436 | if (OPEN_FMODE(open_file->f_flags) & FMODE_READ) { |
860b69a9 | 2437 | if ((!open_file->invalidHandle)) { |
630f3f0c SF |
2438 | /* found a good file */ |
2439 | /* lock it so it will not be closed on us */ | |
3afca265 | 2440 | cifsFileInfo_get(open_file); |
cb248819 | 2441 | spin_unlock(&cifs_inode->open_file_lock); |
630f3f0c SF |
2442 | return open_file; |
2443 | } /* else might as well continue, and look for | |
2444 | another, or simply have the caller reopen it | |
2445 | again rather than trying to fix this handle */ | |
2446 | } else /* write only file */ | |
2447 | break; /* write only files are last so must be done */ | |
2448 | } | |
cb248819 | 2449 | spin_unlock(&cifs_inode->open_file_lock); |
630f3f0c SF |
2450 | return NULL; |
2451 | } | |
630f3f0c | 2452 | |
fe768d51 PS |
2453 | /* Return -EBADF if no handle is found and general rc otherwise */ |
2454 | int | |
86f740f2 | 2455 | cifs_get_writable_file(struct cifsInodeInfo *cifs_inode, int flags, |
fe768d51 | 2456 | struct cifsFileInfo **ret_file) |
6148a742 | 2457 | { |
2c0c2a08 | 2458 | struct cifsFileInfo *open_file, *inv_file = NULL; |
d3892294 | 2459 | struct cifs_sb_info *cifs_sb; |
2846d386 | 2460 | bool any_available = false; |
fe768d51 | 2461 | int rc = -EBADF; |
2c0c2a08 | 2462 | unsigned int refind = 0; |
86f740f2 AA |
2463 | bool fsuid_only = flags & FIND_WR_FSUID_ONLY; |
2464 | bool with_delete = flags & FIND_WR_WITH_DELETE; | |
fe768d51 PS |
2465 | *ret_file = NULL; |
2466 | ||
2467 | /* | |
2468 | * Having a null inode here (because mapping->host was set to zero by | |
2469 | * the VFS or MM) should not happen but we had reports of on oops (due | |
2470 | * to it being zero) during stress testcases so we need to check for it | |
2471 | */ | |
60808233 | 2472 | |
fb8c4b14 | 2473 | if (cifs_inode == NULL) { |
f96637be | 2474 | cifs_dbg(VFS, "Null inode passed to cifs_writeable_file\n"); |
60808233 | 2475 | dump_stack(); |
fe768d51 | 2476 | return rc; |
60808233 SF |
2477 | } |
2478 | ||
874c8ca1 | 2479 | cifs_sb = CIFS_SB(cifs_inode->netfs.inode.i_sb); |
d3892294 | 2480 | |
6508d904 JL |
2481 | /* only filter by fsuid on multiuser mounts */ |
2482 | if (!(cifs_sb->mnt_cifs_flags & CIFS_MOUNT_MULTIUSER)) | |
2483 | fsuid_only = false; | |
2484 | ||
cb248819 | 2485 | spin_lock(&cifs_inode->open_file_lock); |
9b22b0b7 | 2486 | refind_writable: |
2c0c2a08 | 2487 | if (refind > MAX_REOPEN_ATT) { |
cb248819 | 2488 | spin_unlock(&cifs_inode->open_file_lock); |
fe768d51 | 2489 | return rc; |
2c0c2a08 | 2490 | } |
6148a742 | 2491 | list_for_each_entry(open_file, &cifs_inode->openFileList, flist) { |
6508d904 JL |
2492 | if (!any_available && open_file->pid != current->tgid) |
2493 | continue; | |
fef59fd7 | 2494 | if (fsuid_only && !uid_eq(open_file->uid, current_fsuid())) |
6148a742 | 2495 | continue; |
86f740f2 AA |
2496 | if (with_delete && !(open_file->fid.access & DELETE)) |
2497 | continue; | |
2e396b83 | 2498 | if (OPEN_FMODE(open_file->f_flags) & FMODE_WRITE) { |
9b22b0b7 SF |
2499 | if (!open_file->invalidHandle) { |
2500 | /* found a good writable file */ | |
3afca265 | 2501 | cifsFileInfo_get(open_file); |
cb248819 | 2502 | spin_unlock(&cifs_inode->open_file_lock); |
fe768d51 PS |
2503 | *ret_file = open_file; |
2504 | return 0; | |
2c0c2a08 SP |
2505 | } else { |
2506 | if (!inv_file) | |
2507 | inv_file = open_file; | |
9b22b0b7 | 2508 | } |
6148a742 SF |
2509 | } |
2510 | } | |
e9f49fee | 2511 | /* couldn't find usable FH with same pid, try any available */ |
2846d386 JL |
2512 | if (!any_available) { |
2513 | any_available = true; | |
2514 | goto refind_writable; | |
2515 | } | |
2c0c2a08 SP |
2516 | |
2517 | if (inv_file) { | |
2518 | any_available = false; | |
3afca265 | 2519 | cifsFileInfo_get(inv_file); |
2c0c2a08 SP |
2520 | } |
2521 | ||
cb248819 | 2522 | spin_unlock(&cifs_inode->open_file_lock); |
2c0c2a08 SP |
2523 | |
2524 | if (inv_file) { | |
2525 | rc = cifs_reopen_file(inv_file, false); | |
fe768d51 PS |
2526 | if (!rc) { |
2527 | *ret_file = inv_file; | |
2528 | return 0; | |
2c0c2a08 | 2529 | } |
fe768d51 | 2530 | |
487317c9 | 2531 | spin_lock(&cifs_inode->open_file_lock); |
fe768d51 | 2532 | list_move_tail(&inv_file->flist, &cifs_inode->openFileList); |
487317c9 | 2533 | spin_unlock(&cifs_inode->open_file_lock); |
fe768d51 PS |
2534 | cifsFileInfo_put(inv_file); |
2535 | ++refind; | |
2536 | inv_file = NULL; | |
cb248819 | 2537 | spin_lock(&cifs_inode->open_file_lock); |
fe768d51 | 2538 | goto refind_writable; |
2c0c2a08 SP |
2539 | } |
2540 | ||
fe768d51 PS |
2541 | return rc; |
2542 | } | |
2543 | ||
2544 | struct cifsFileInfo * | |
86f740f2 | 2545 | find_writable_file(struct cifsInodeInfo *cifs_inode, int flags) |
fe768d51 PS |
2546 | { |
2547 | struct cifsFileInfo *cfile; | |
2548 | int rc; | |
2549 | ||
86f740f2 | 2550 | rc = cifs_get_writable_file(cifs_inode, flags, &cfile); |
fe768d51 | 2551 | if (rc) |
a0a3036b | 2552 | cifs_dbg(FYI, "Couldn't find writable handle rc=%d\n", rc); |
fe768d51 PS |
2553 | |
2554 | return cfile; | |
6148a742 SF |
2555 | } |
2556 | ||
8de9e86c RS |
2557 | int |
2558 | cifs_get_writable_path(struct cifs_tcon *tcon, const char *name, | |
86f740f2 | 2559 | int flags, |
8de9e86c RS |
2560 | struct cifsFileInfo **ret_file) |
2561 | { | |
8de9e86c | 2562 | struct cifsFileInfo *cfile; |
f6a9bc33 | 2563 | void *page = alloc_dentry_path(); |
8de9e86c RS |
2564 | |
2565 | *ret_file = NULL; | |
2566 | ||
2567 | spin_lock(&tcon->open_file_lock); | |
f6a9bc33 AV |
2568 | list_for_each_entry(cfile, &tcon->openFileList, tlist) { |
2569 | struct cifsInodeInfo *cinode; | |
2570 | const char *full_path = build_path_from_dentry(cfile->dentry, page); | |
2571 | if (IS_ERR(full_path)) { | |
8de9e86c | 2572 | spin_unlock(&tcon->open_file_lock); |
f6a9bc33 AV |
2573 | free_dentry_path(page); |
2574 | return PTR_ERR(full_path); | |
8de9e86c | 2575 | } |
f6a9bc33 | 2576 | if (strcmp(full_path, name)) |
8de9e86c | 2577 | continue; |
8de9e86c | 2578 | |
8de9e86c RS |
2579 | cinode = CIFS_I(d_inode(cfile->dentry)); |
2580 | spin_unlock(&tcon->open_file_lock); | |
f6a9bc33 | 2581 | free_dentry_path(page); |
86f740f2 | 2582 | return cifs_get_writable_file(cinode, flags, ret_file); |
8de9e86c RS |
2583 | } |
2584 | ||
2585 | spin_unlock(&tcon->open_file_lock); | |
f6a9bc33 | 2586 | free_dentry_path(page); |
8de9e86c RS |
2587 | return -ENOENT; |
2588 | } | |
2589 | ||
496902dc RS |
2590 | int |
2591 | cifs_get_readable_path(struct cifs_tcon *tcon, const char *name, | |
2592 | struct cifsFileInfo **ret_file) | |
2593 | { | |
496902dc | 2594 | struct cifsFileInfo *cfile; |
f6a9bc33 | 2595 | void *page = alloc_dentry_path(); |
496902dc RS |
2596 | |
2597 | *ret_file = NULL; | |
2598 | ||
2599 | spin_lock(&tcon->open_file_lock); | |
f6a9bc33 AV |
2600 | list_for_each_entry(cfile, &tcon->openFileList, tlist) { |
2601 | struct cifsInodeInfo *cinode; | |
2602 | const char *full_path = build_path_from_dentry(cfile->dentry, page); | |
2603 | if (IS_ERR(full_path)) { | |
496902dc | 2604 | spin_unlock(&tcon->open_file_lock); |
f6a9bc33 AV |
2605 | free_dentry_path(page); |
2606 | return PTR_ERR(full_path); | |
496902dc | 2607 | } |
f6a9bc33 | 2608 | if (strcmp(full_path, name)) |
496902dc | 2609 | continue; |
496902dc | 2610 | |
496902dc RS |
2611 | cinode = CIFS_I(d_inode(cfile->dentry)); |
2612 | spin_unlock(&tcon->open_file_lock); | |
f6a9bc33 | 2613 | free_dentry_path(page); |
496902dc RS |
2614 | *ret_file = find_readable_file(cinode, 0); |
2615 | return *ret_file ? 0 : -ENOENT; | |
2616 | } | |
2617 | ||
2618 | spin_unlock(&tcon->open_file_lock); | |
f6a9bc33 | 2619 | free_dentry_path(page); |
496902dc RS |
2620 | return -ENOENT; |
2621 | } | |
2622 | ||
3ee1a1fc DH |
2623 | /* |
2624 | * Flush data on a strict file. | |
2625 | */ | |
02c24a82 JB |
2626 | int cifs_strict_fsync(struct file *file, loff_t start, loff_t end, |
2627 | int datasync) | |
1da177e4 | 2628 | { |
6d5786a3 | 2629 | unsigned int xid; |
1da177e4 | 2630 | int rc = 0; |
96daf2b0 | 2631 | struct cifs_tcon *tcon; |
1d8c4c00 | 2632 | struct TCP_Server_Info *server; |
c21dfb69 | 2633 | struct cifsFileInfo *smbfile = file->private_data; |
496ad9aa | 2634 | struct inode *inode = file_inode(file); |
8be7e6ba | 2635 | struct cifs_sb_info *cifs_sb = CIFS_SB(inode->i_sb); |
1da177e4 | 2636 | |
3b49c9a1 | 2637 | rc = file_write_and_wait_range(file, start, end); |
2391ca41 SF |
2638 | if (rc) { |
2639 | trace_cifs_fsync_err(inode->i_ino, rc); | |
02c24a82 | 2640 | return rc; |
2391ca41 | 2641 | } |
02c24a82 | 2642 | |
6d5786a3 | 2643 | xid = get_xid(); |
1da177e4 | 2644 | |
35c265e0 AV |
2645 | cifs_dbg(FYI, "Sync file - name: %pD datasync: 0x%x\n", |
2646 | file, datasync); | |
50c2f753 | 2647 | |
18cceb6a | 2648 | if (!CIFS_CACHE_READ(CIFS_I(inode))) { |
4f73c7d3 | 2649 | rc = cifs_zap_mapping(inode); |
6feb9891 | 2650 | if (rc) { |
f96637be | 2651 | cifs_dbg(FYI, "rc: %d during invalidate phase\n", rc); |
6feb9891 PS |
2652 | rc = 0; /* don't care about it in fsync */ |
2653 | } | |
2654 | } | |
eb4b756b | 2655 | |
8be7e6ba | 2656 | tcon = tlink_tcon(smbfile->tlink); |
1d8c4c00 PS |
2657 | if (!(cifs_sb->mnt_cifs_flags & CIFS_MOUNT_NOSSYNC)) { |
2658 | server = tcon->ses->server; | |
71e6864e | 2659 | if (server->ops->flush == NULL) { |
1d8c4c00 | 2660 | rc = -ENOSYS; |
71e6864e SF |
2661 | goto strict_fsync_exit; |
2662 | } | |
2663 | ||
2664 | if ((OPEN_FMODE(smbfile->f_flags) & FMODE_WRITE) == 0) { | |
2665 | smbfile = find_writable_file(CIFS_I(inode), FIND_WR_ANY); | |
2666 | if (smbfile) { | |
2667 | rc = server->ops->flush(xid, tcon, &smbfile->fid); | |
2668 | cifsFileInfo_put(smbfile); | |
2669 | } else | |
2670 | cifs_dbg(FYI, "ignore fsync for file not open for write\n"); | |
2671 | } else | |
2672 | rc = server->ops->flush(xid, tcon, &smbfile->fid); | |
1d8c4c00 | 2673 | } |
8be7e6ba | 2674 | |
71e6864e | 2675 | strict_fsync_exit: |
6d5786a3 | 2676 | free_xid(xid); |
8be7e6ba PS |
2677 | return rc; |
2678 | } | |
2679 | ||
3ee1a1fc DH |
2680 | /* |
2681 | * Flush data on a non-strict data. | |
2682 | */ | |
02c24a82 | 2683 | int cifs_fsync(struct file *file, loff_t start, loff_t end, int datasync) |
8be7e6ba | 2684 | { |
6d5786a3 | 2685 | unsigned int xid; |
8be7e6ba | 2686 | int rc = 0; |
96daf2b0 | 2687 | struct cifs_tcon *tcon; |
1d8c4c00 | 2688 | struct TCP_Server_Info *server; |
8be7e6ba | 2689 | struct cifsFileInfo *smbfile = file->private_data; |
71e6864e | 2690 | struct inode *inode = file_inode(file); |
7119e220 | 2691 | struct cifs_sb_info *cifs_sb = CIFS_FILE_SB(file); |
02c24a82 | 2692 | |
3b49c9a1 | 2693 | rc = file_write_and_wait_range(file, start, end); |
f2bf09e9 SF |
2694 | if (rc) { |
2695 | trace_cifs_fsync_err(file_inode(file)->i_ino, rc); | |
02c24a82 | 2696 | return rc; |
f2bf09e9 | 2697 | } |
8be7e6ba | 2698 | |
6d5786a3 | 2699 | xid = get_xid(); |
8be7e6ba | 2700 | |
35c265e0 AV |
2701 | cifs_dbg(FYI, "Sync file - name: %pD datasync: 0x%x\n", |
2702 | file, datasync); | |
8be7e6ba PS |
2703 | |
2704 | tcon = tlink_tcon(smbfile->tlink); | |
1d8c4c00 PS |
2705 | if (!(cifs_sb->mnt_cifs_flags & CIFS_MOUNT_NOSSYNC)) { |
2706 | server = tcon->ses->server; | |
71e6864e | 2707 | if (server->ops->flush == NULL) { |
1d8c4c00 | 2708 | rc = -ENOSYS; |
71e6864e SF |
2709 | goto fsync_exit; |
2710 | } | |
2711 | ||
2712 | if ((OPEN_FMODE(smbfile->f_flags) & FMODE_WRITE) == 0) { | |
2713 | smbfile = find_writable_file(CIFS_I(inode), FIND_WR_ANY); | |
2714 | if (smbfile) { | |
2715 | rc = server->ops->flush(xid, tcon, &smbfile->fid); | |
2716 | cifsFileInfo_put(smbfile); | |
2717 | } else | |
2718 | cifs_dbg(FYI, "ignore fsync for file not open for write\n"); | |
2719 | } else | |
2720 | rc = server->ops->flush(xid, tcon, &smbfile->fid); | |
1d8c4c00 | 2721 | } |
b298f223 | 2722 | |
71e6864e | 2723 | fsync_exit: |
6d5786a3 | 2724 | free_xid(xid); |
1da177e4 LT |
2725 | return rc; |
2726 | } | |
2727 | ||
1da177e4 LT |
2728 | /* |
2729 | * As file closes, flush all cached write data for this inode checking | |
2730 | * for write behind errors. | |
2731 | */ | |
75e1fcc0 | 2732 | int cifs_flush(struct file *file, fl_owner_t id) |
1da177e4 | 2733 | { |
496ad9aa | 2734 | struct inode *inode = file_inode(file); |
1da177e4 LT |
2735 | int rc = 0; |
2736 | ||
eb4b756b | 2737 | if (file->f_mode & FMODE_WRITE) |
d3f1322a | 2738 | rc = filemap_write_and_wait(inode->i_mapping); |
50c2f753 | 2739 | |
f96637be | 2740 | cifs_dbg(FYI, "Flush inode %p file %p rc %d\n", inode, file, rc); |
2b058ace C |
2741 | if (rc) { |
2742 | /* get more nuanced writeback errors */ | |
2743 | rc = filemap_check_wb_err(file->f_mapping, 0); | |
f2bf09e9 | 2744 | trace_cifs_flush_err(inode->i_ino, rc); |
2b058ace | 2745 | } |
1da177e4 LT |
2746 | return rc; |
2747 | } | |
2748 | ||
579f9053 | 2749 | static ssize_t |
3dae8750 | 2750 | cifs_writev(struct kiocb *iocb, struct iov_iter *from) |
72432ffc | 2751 | { |
579f9053 PS |
2752 | struct file *file = iocb->ki_filp; |
2753 | struct cifsFileInfo *cfile = (struct cifsFileInfo *)file->private_data; | |
2754 | struct inode *inode = file->f_mapping->host; | |
2755 | struct cifsInodeInfo *cinode = CIFS_I(inode); | |
2756 | struct TCP_Server_Info *server = tlink_tcon(cfile->tlink)->ses->server; | |
836bb326 | 2757 | struct cifs_sb_info *cifs_sb = CIFS_SB(inode->i_sb); |
5f380c7f | 2758 | ssize_t rc; |
72432ffc | 2759 | |
3ee1a1fc DH |
2760 | rc = netfs_start_io_write(inode); |
2761 | if (rc < 0) | |
2762 | return rc; | |
2763 | ||
579f9053 PS |
2764 | /* |
2765 | * We need to hold the sem to be sure nobody modifies lock list | |
2766 | * with a brlock that prevents writing. | |
2767 | */ | |
2768 | down_read(&cinode->lock_sem); | |
5f380c7f | 2769 | |
3309dd04 AV |
2770 | rc = generic_write_checks(iocb, from); |
2771 | if (rc <= 0) | |
5f380c7f AV |
2772 | goto out; |
2773 | ||
836bb326 SF |
2774 | if ((cifs_sb->mnt_cifs_flags & CIFS_MOUNT_NOPOSIXBRL) && |
2775 | (cifs_find_lock_conflict(cfile, iocb->ki_pos, iov_iter_count(from), | |
9645759c | 2776 | server->vals->exclusive_lock_type, 0, |
836bb326 | 2777 | NULL, CIFS_WRITE_OP))) { |
5f380c7f | 2778 | rc = -EACCES; |
836bb326 SF |
2779 | goto out; |
2780 | } | |
2781 | ||
2782 | rc = netfs_buffered_write_iter_locked(iocb, from, NULL); | |
2783 | ||
5f380c7f | 2784 | out: |
966681c9 | 2785 | up_read(&cinode->lock_sem); |
3ee1a1fc | 2786 | netfs_end_io_write(inode); |
e2592217 CH |
2787 | if (rc > 0) |
2788 | rc = generic_write_sync(iocb, rc); | |
579f9053 PS |
2789 | return rc; |
2790 | } | |
2791 | ||
2792 | ssize_t | |
3dae8750 | 2793 | cifs_strict_writev(struct kiocb *iocb, struct iov_iter *from) |
579f9053 | 2794 | { |
496ad9aa | 2795 | struct inode *inode = file_inode(iocb->ki_filp); |
579f9053 PS |
2796 | struct cifsInodeInfo *cinode = CIFS_I(inode); |
2797 | struct cifs_sb_info *cifs_sb = CIFS_SB(inode->i_sb); | |
2798 | struct cifsFileInfo *cfile = (struct cifsFileInfo *) | |
2799 | iocb->ki_filp->private_data; | |
2800 | struct cifs_tcon *tcon = tlink_tcon(cfile->tlink); | |
88cf75aa | 2801 | ssize_t written; |
ca8aa29c | 2802 | |
c11f1df5 SP |
2803 | written = cifs_get_writer(cinode); |
2804 | if (written) | |
2805 | return written; | |
2806 | ||
18cceb6a | 2807 | if (CIFS_CACHE_WRITE(cinode)) { |
88cf75aa | 2808 | if (cap_unix(tcon->ses) && |
3ee1a1fc DH |
2809 | (CIFS_UNIX_FCNTL_CAP & le64_to_cpu(tcon->fsUnixInfo.Capability)) && |
2810 | ((cifs_sb->mnt_cifs_flags & CIFS_MOUNT_NOPOSIXBRL) == 0)) { | |
2811 | written = netfs_file_write_iter(iocb, from); | |
c11f1df5 SP |
2812 | goto out; |
2813 | } | |
3dae8750 | 2814 | written = cifs_writev(iocb, from); |
c11f1df5 | 2815 | goto out; |
25078105 | 2816 | } |
25078105 | 2817 | /* |
ca8aa29c PS |
2818 | * For non-oplocked files in strict cache mode we need to write the data |
2819 | * to the server exactly from the pos to pos+len-1 rather than flush all | |
2820 | * affected pages because it may cause a error with mandatory locks on | |
2821 | * these pages but not on the region from pos to ppos+len-1. | |
72432ffc | 2822 | */ |
3ee1a1fc | 2823 | written = netfs_file_write_iter(iocb, from); |
6dfbd846 | 2824 | if (CIFS_CACHE_READ(cinode)) { |
88cf75aa | 2825 | /* |
6dfbd846 PS |
2826 | * We have read level caching and we have just sent a write |
2827 | * request to the server thus making data in the cache stale. | |
2828 | * Zap the cache and set oplock/lease level to NONE to avoid | |
2829 | * reading stale data from the cache. All subsequent read | |
2830 | * operations will read new data from the server. | |
88cf75aa | 2831 | */ |
4f73c7d3 | 2832 | cifs_zap_mapping(inode); |
6dfbd846 | 2833 | cifs_dbg(FYI, "Set Oplock/Lease to NONE for inode=%p after write\n", |
f96637be | 2834 | inode); |
18cceb6a | 2835 | cinode->oplock = 0; |
88cf75aa | 2836 | } |
c11f1df5 SP |
2837 | out: |
2838 | cifs_put_writer(cinode); | |
88cf75aa | 2839 | return written; |
72432ffc PS |
2840 | } |
2841 | ||
1a5b4edd DH |
2842 | ssize_t cifs_loose_read_iter(struct kiocb *iocb, struct iov_iter *iter) |
2843 | { | |
2844 | ssize_t rc; | |
2845 | struct inode *inode = file_inode(iocb->ki_filp); | |
2846 | ||
2847 | if (iocb->ki_flags & IOCB_DIRECT) | |
3ee1a1fc | 2848 | return netfs_unbuffered_read_iter(iocb, iter); |
1a5b4edd DH |
2849 | |
2850 | rc = cifs_revalidate_mapping(inode); | |
2851 | if (rc) | |
2852 | return rc; | |
2853 | ||
3ee1a1fc | 2854 | return netfs_file_read_iter(iocb, iter); |
1a5b4edd DH |
2855 | } |
2856 | ||
2857 | ssize_t cifs_file_write_iter(struct kiocb *iocb, struct iov_iter *from) | |
2858 | { | |
2859 | struct inode *inode = file_inode(iocb->ki_filp); | |
2860 | struct cifsInodeInfo *cinode = CIFS_I(inode); | |
2861 | ssize_t written; | |
2862 | int rc; | |
2863 | ||
2864 | if (iocb->ki_filp->f_flags & O_DIRECT) { | |
3ee1a1fc | 2865 | written = netfs_unbuffered_write_iter(iocb, from); |
1a5b4edd DH |
2866 | if (written > 0 && CIFS_CACHE_READ(cinode)) { |
2867 | cifs_zap_mapping(inode); | |
2868 | cifs_dbg(FYI, | |
2869 | "Set no oplock for inode=%p after a write operation\n", | |
2870 | inode); | |
2871 | cinode->oplock = 0; | |
2872 | } | |
2873 | return written; | |
2874 | } | |
2875 | ||
2876 | written = cifs_get_writer(cinode); | |
2877 | if (written) | |
2878 | return written; | |
2879 | ||
3ee1a1fc | 2880 | written = netfs_file_write_iter(iocb, from); |
1a5b4edd | 2881 | |
3ee1a1fc DH |
2882 | if (!CIFS_CACHE_WRITE(CIFS_I(inode))) { |
2883 | rc = filemap_fdatawrite(inode->i_mapping); | |
2884 | if (rc) | |
2885 | cifs_dbg(FYI, "cifs_file_write_iter: %d rc on %p inode\n", | |
2886 | rc, inode); | |
2887 | } | |
1a5b4edd | 2888 | |
1a5b4edd DH |
2889 | cifs_put_writer(cinode); |
2890 | return written; | |
2891 | } | |
2892 | ||
579f9053 | 2893 | ssize_t |
e6a7bcb4 | 2894 | cifs_strict_readv(struct kiocb *iocb, struct iov_iter *to) |
a70307ee | 2895 | { |
496ad9aa | 2896 | struct inode *inode = file_inode(iocb->ki_filp); |
579f9053 PS |
2897 | struct cifsInodeInfo *cinode = CIFS_I(inode); |
2898 | struct cifs_sb_info *cifs_sb = CIFS_SB(inode->i_sb); | |
2899 | struct cifsFileInfo *cfile = (struct cifsFileInfo *) | |
2900 | iocb->ki_filp->private_data; | |
2901 | struct cifs_tcon *tcon = tlink_tcon(cfile->tlink); | |
2902 | int rc = -EACCES; | |
a70307ee PS |
2903 | |
2904 | /* | |
2905 | * In strict cache mode we need to read from the server all the time | |
2906 | * if we don't have level II oplock because the server can delay mtime | |
2907 | * change - so we can't make a decision about inode invalidating. | |
2908 | * And we can also fail with pagereading if there are mandatory locks | |
2909 | * on pages affected by this read but not on the region from pos to | |
2910 | * pos+len-1. | |
2911 | */ | |
18cceb6a | 2912 | if (!CIFS_CACHE_READ(cinode)) |
3ee1a1fc | 2913 | return netfs_unbuffered_read_iter(iocb, to); |
a70307ee | 2914 | |
e4be320e | 2915 | if ((cifs_sb->mnt_cifs_flags & CIFS_MOUNT_NOPOSIXBRL) == 0) { |
3ee1a1fc DH |
2916 | if (iocb->ki_flags & IOCB_DIRECT) |
2917 | return netfs_unbuffered_read_iter(iocb, to); | |
2918 | return netfs_buffered_read_iter(iocb, to); | |
2919 | } | |
579f9053 PS |
2920 | |
2921 | /* | |
2922 | * We need to hold the sem to be sure nobody modifies lock list | |
2923 | * with a brlock that prevents reading. | |
2924 | */ | |
14b1cd25 SF |
2925 | if (iocb->ki_flags & IOCB_DIRECT) { |
2926 | rc = netfs_start_io_direct(inode); | |
2927 | if (rc < 0) | |
2928 | goto out; | |
d2c5eb57 | 2929 | rc = -EACCES; |
14b1cd25 SF |
2930 | down_read(&cinode->lock_sem); |
2931 | if (!cifs_find_lock_conflict( | |
2932 | cfile, iocb->ki_pos, iov_iter_count(to), | |
2933 | tcon->ses->server->vals->shared_lock_type, | |
2934 | 0, NULL, CIFS_READ_OP)) | |
2935 | rc = netfs_unbuffered_read_iter_locked(iocb, to); | |
2936 | up_read(&cinode->lock_sem); | |
2937 | netfs_end_io_direct(inode); | |
2938 | } else { | |
2939 | rc = netfs_start_io_read(inode); | |
2940 | if (rc < 0) | |
2941 | goto out; | |
d2c5eb57 | 2942 | rc = -EACCES; |
14b1cd25 SF |
2943 | down_read(&cinode->lock_sem); |
2944 | if (!cifs_find_lock_conflict( | |
2945 | cfile, iocb->ki_pos, iov_iter_count(to), | |
2946 | tcon->ses->server->vals->shared_lock_type, | |
2947 | 0, NULL, CIFS_READ_OP)) | |
2948 | rc = filemap_read(iocb, to, 0); | |
2949 | up_read(&cinode->lock_sem); | |
2950 | netfs_end_io_read(inode); | |
3ee1a1fc | 2951 | } |
14b1cd25 | 2952 | out: |
579f9053 | 2953 | return rc; |
a70307ee | 2954 | } |
1da177e4 | 2955 | |
c191bc07 | 2956 | static vm_fault_t cifs_page_mkwrite(struct vm_fault *vmf) |
ca83ce3d | 2957 | { |
3ee1a1fc | 2958 | return netfs_page_mkwrite(vmf, NULL); |
ca83ce3d JL |
2959 | } |
2960 | ||
7cbea8dc | 2961 | static const struct vm_operations_struct cifs_file_vm_ops = { |
ca83ce3d | 2962 | .fault = filemap_fault, |
f1820361 | 2963 | .map_pages = filemap_map_pages, |
ca83ce3d JL |
2964 | .page_mkwrite = cifs_page_mkwrite, |
2965 | }; | |
2966 | ||
7a6a19b1 PS |
2967 | int cifs_file_strict_mmap(struct file *file, struct vm_area_struct *vma) |
2968 | { | |
f04a703c | 2969 | int xid, rc = 0; |
496ad9aa | 2970 | struct inode *inode = file_inode(file); |
7a6a19b1 | 2971 | |
6d5786a3 | 2972 | xid = get_xid(); |
7a6a19b1 | 2973 | |
f04a703c | 2974 | if (!CIFS_CACHE_READ(CIFS_I(inode))) |
4f73c7d3 | 2975 | rc = cifs_zap_mapping(inode); |
f04a703c MW |
2976 | if (!rc) |
2977 | rc = generic_file_mmap(file, vma); | |
2978 | if (!rc) | |
ca83ce3d | 2979 | vma->vm_ops = &cifs_file_vm_ops; |
f04a703c | 2980 | |
6d5786a3 | 2981 | free_xid(xid); |
7a6a19b1 PS |
2982 | return rc; |
2983 | } | |
2984 | ||
1da177e4 LT |
2985 | int cifs_file_mmap(struct file *file, struct vm_area_struct *vma) |
2986 | { | |
1da177e4 LT |
2987 | int rc, xid; |
2988 | ||
6d5786a3 | 2989 | xid = get_xid(); |
f04a703c | 2990 | |
abab095d | 2991 | rc = cifs_revalidate_file(file); |
f04a703c | 2992 | if (rc) |
f96637be JP |
2993 | cifs_dbg(FYI, "Validation prior to mmap failed, error=%d\n", |
2994 | rc); | |
f04a703c MW |
2995 | if (!rc) |
2996 | rc = generic_file_mmap(file, vma); | |
2997 | if (!rc) | |
ca83ce3d | 2998 | vma->vm_ops = &cifs_file_vm_ops; |
f04a703c | 2999 | |
6d5786a3 | 3000 | free_xid(xid); |
1da177e4 LT |
3001 | return rc; |
3002 | } | |
3003 | ||
a403a0a3 SF |
3004 | static int is_inode_writable(struct cifsInodeInfo *cifs_inode) |
3005 | { | |
3006 | struct cifsFileInfo *open_file; | |
3007 | ||
cb248819 | 3008 | spin_lock(&cifs_inode->open_file_lock); |
a403a0a3 | 3009 | list_for_each_entry(open_file, &cifs_inode->openFileList, flist) { |
2e396b83 | 3010 | if (OPEN_FMODE(open_file->f_flags) & FMODE_WRITE) { |
cb248819 | 3011 | spin_unlock(&cifs_inode->open_file_lock); |
a403a0a3 SF |
3012 | return 1; |
3013 | } | |
3014 | } | |
cb248819 | 3015 | spin_unlock(&cifs_inode->open_file_lock); |
a403a0a3 SF |
3016 | return 0; |
3017 | } | |
3018 | ||
1da177e4 LT |
3019 | /* We do not want to update the file size from server for inodes |
3020 | open for write - to avoid races with writepage extending | |
3021 | the file - in the future we could consider allowing | |
fb8c4b14 | 3022 | refreshing the inode only on increases in the file size |
1da177e4 LT |
3023 | but this is tricky to do without racing with writebehind |
3024 | page caching in the current Linux kernel design */ | |
e4b61f3b BS |
3025 | bool is_size_safe_to_change(struct cifsInodeInfo *cifsInode, __u64 end_of_file, |
3026 | bool from_readdir) | |
1da177e4 | 3027 | { |
a403a0a3 | 3028 | if (!cifsInode) |
4b18f2a9 | 3029 | return true; |
50c2f753 | 3030 | |
e4b61f3b BS |
3031 | if (is_inode_writable(cifsInode) || |
3032 | ((cifsInode->oplock & CIFS_CACHE_RW_FLG) != 0 && from_readdir)) { | |
a403a0a3 | 3033 | /* This inode is open for write at least once */ |
c32a0b68 SF |
3034 | struct cifs_sb_info *cifs_sb; |
3035 | ||
874c8ca1 | 3036 | cifs_sb = CIFS_SB(cifsInode->netfs.inode.i_sb); |
ad7a2926 | 3037 | if (cifs_sb->mnt_cifs_flags & CIFS_MOUNT_DIRECT_IO) { |
fb8c4b14 | 3038 | /* since no page cache to corrupt on directio |
c32a0b68 | 3039 | we can change size safely */ |
4b18f2a9 | 3040 | return true; |
c32a0b68 SF |
3041 | } |
3042 | ||
874c8ca1 | 3043 | if (i_size_read(&cifsInode->netfs.inode) < end_of_file) |
4b18f2a9 | 3044 | return true; |
7ba52631 | 3045 | |
4b18f2a9 | 3046 | return false; |
23e7dd7d | 3047 | } else |
4b18f2a9 | 3048 | return true; |
1da177e4 LT |
3049 | } |
3050 | ||
9b646972 | 3051 | void cifs_oplock_break(struct work_struct *work) |
3bc303c2 JL |
3052 | { |
3053 | struct cifsFileInfo *cfile = container_of(work, struct cifsFileInfo, | |
3054 | oplock_break); | |
2b0143b5 | 3055 | struct inode *inode = d_inode(cfile->dentry); |
e8f5f849 | 3056 | struct cifs_sb_info *cifs_sb = CIFS_SB(inode->i_sb); |
3bc303c2 | 3057 | struct cifsInodeInfo *cinode = CIFS_I(inode); |
e8f5f849 SF |
3058 | struct cifs_tcon *tcon; |
3059 | struct TCP_Server_Info *server; | |
3060 | struct tcon_link *tlink; | |
eb4b756b | 3061 | int rc = 0; |
59a556ae BS |
3062 | bool purge_cache = false, oplock_break_cancelled; |
3063 | __u64 persistent_fid, volatile_fid; | |
3064 | __u16 net_fid; | |
3bc303c2 | 3065 | |
c11f1df5 | 3066 | wait_on_bit(&cinode->flags, CIFS_INODE_PENDING_WRITERS, |
74316201 | 3067 | TASK_UNINTERRUPTIBLE); |
c11f1df5 | 3068 | |
e8f5f849 SF |
3069 | tlink = cifs_sb_tlink(cifs_sb); |
3070 | if (IS_ERR(tlink)) | |
3071 | goto out; | |
3072 | tcon = tlink_tcon(tlink); | |
3073 | server = tcon->ses->server; | |
3074 | ||
9bd45408 PS |
3075 | server->ops->downgrade_oplock(server, cinode, cfile->oplock_level, |
3076 | cfile->oplock_epoch, &purge_cache); | |
c11f1df5 | 3077 | |
18cceb6a | 3078 | if (!CIFS_CACHE_WRITE(cinode) && CIFS_CACHE_READ(cinode) && |
63b7d3a4 | 3079 | cifs_has_mand_locks(cinode)) { |
f96637be JP |
3080 | cifs_dbg(FYI, "Reset oplock to None for inode=%p due to mand locks\n", |
3081 | inode); | |
18cceb6a | 3082 | cinode->oplock = 0; |
63b7d3a4 PS |
3083 | } |
3084 | ||
3bc303c2 | 3085 | if (inode && S_ISREG(inode->i_mode)) { |
18cceb6a | 3086 | if (CIFS_CACHE_READ(cinode)) |
8737c930 | 3087 | break_lease(inode, O_RDONLY); |
d54ff732 | 3088 | else |
8737c930 | 3089 | break_lease(inode, O_WRONLY); |
3bc303c2 | 3090 | rc = filemap_fdatawrite(inode->i_mapping); |
9bd45408 | 3091 | if (!CIFS_CACHE_READ(cinode) || purge_cache) { |
eb4b756b JL |
3092 | rc = filemap_fdatawait(inode->i_mapping); |
3093 | mapping_set_error(inode->i_mapping, rc); | |
4f73c7d3 | 3094 | cifs_zap_mapping(inode); |
3bc303c2 | 3095 | } |
f96637be | 3096 | cifs_dbg(FYI, "Oplock flush inode %p rc %d\n", inode, rc); |
9bd45408 PS |
3097 | if (CIFS_CACHE_WRITE(cinode)) |
3098 | goto oplock_break_ack; | |
3bc303c2 JL |
3099 | } |
3100 | ||
85160e03 PS |
3101 | rc = cifs_push_locks(cfile); |
3102 | if (rc) | |
f96637be | 3103 | cifs_dbg(VFS, "Push locks rc = %d\n", rc); |
85160e03 | 3104 | |
9bd45408 | 3105 | oplock_break_ack: |
d906be3f BS |
3106 | /* |
3107 | * When oplock break is received and there are no active | |
3108 | * file handles but cached, then schedule deferred close immediately. | |
3109 | * So, new open will not use cached handle. | |
3110 | */ | |
d906be3f | 3111 | |
47592fa8 | 3112 | if (!CIFS_CACHE_HANDLE(cinode) && !list_empty(&cinode->deferred_closes)) |
d906be3f | 3113 | cifs_close_deferred_file(cinode); |
d906be3f | 3114 | |
59a556ae BS |
3115 | persistent_fid = cfile->fid.persistent_fid; |
3116 | volatile_fid = cfile->fid.volatile_fid; | |
3117 | net_fid = cfile->fid.netfid; | |
3118 | oplock_break_cancelled = cfile->oplock_break_cancelled; | |
3119 | ||
3120 | _cifsFileInfo_put(cfile, false /* do not wait for ourself */, false); | |
9e992755 | 3121 | /* |
da787d5b BS |
3122 | * MS-SMB2 3.2.5.19.1 and 3.2.5.19.2 (and MS-CIFS 3.2.5.42) do not require |
3123 | * an acknowledgment to be sent when the file has already been closed. | |
9e992755 | 3124 | */ |
da787d5b | 3125 | spin_lock(&cinode->open_file_lock); |
e8f5f849 SF |
3126 | /* check list empty since can race with kill_sb calling tree disconnect */ |
3127 | if (!oplock_break_cancelled && !list_empty(&cinode->openFileList)) { | |
da787d5b | 3128 | spin_unlock(&cinode->open_file_lock); |
e8f5f849 SF |
3129 | rc = server->ops->oplock_response(tcon, persistent_fid, |
3130 | volatile_fid, net_fid, cinode); | |
da787d5b BS |
3131 | cifs_dbg(FYI, "Oplock release rc = %d\n", rc); |
3132 | } else | |
3133 | spin_unlock(&cinode->open_file_lock); | |
9e31678f | 3134 | |
e8f5f849 SF |
3135 | cifs_put_tlink(tlink); |
3136 | out: | |
c11f1df5 | 3137 | cifs_done_oplock_break(cinode); |
3bc303c2 JL |
3138 | } |
3139 | ||
4e8aea30 SF |
3140 | static int cifs_swap_activate(struct swap_info_struct *sis, |
3141 | struct file *swap_file, sector_t *span) | |
3142 | { | |
3143 | struct cifsFileInfo *cfile = swap_file->private_data; | |
3144 | struct inode *inode = swap_file->f_mapping->host; | |
3145 | unsigned long blocks; | |
3146 | long long isize; | |
3147 | ||
3148 | cifs_dbg(FYI, "swap activate\n"); | |
3149 | ||
e1209d3a N |
3150 | if (!swap_file->f_mapping->a_ops->swap_rw) |
3151 | /* Cannot support swap */ | |
3152 | return -EINVAL; | |
3153 | ||
4e8aea30 SF |
3154 | spin_lock(&inode->i_lock); |
3155 | blocks = inode->i_blocks; | |
3156 | isize = inode->i_size; | |
3157 | spin_unlock(&inode->i_lock); | |
3158 | if (blocks*512 < isize) { | |
3159 | pr_warn("swap activate: swapfile has holes\n"); | |
3160 | return -EINVAL; | |
3161 | } | |
3162 | *span = sis->pages; | |
3163 | ||
a0a3036b | 3164 | pr_warn_once("Swap support over SMB3 is experimental\n"); |
4e8aea30 SF |
3165 | |
3166 | /* | |
3167 | * TODO: consider adding ACL (or documenting how) to prevent other | |
3168 | * users (on this or other systems) from reading it | |
3169 | */ | |
3170 | ||
3171 | ||
3172 | /* TODO: add sk_set_memalloc(inet) or similar */ | |
3173 | ||
3174 | if (cfile) | |
3175 | cfile->swapfile = true; | |
3176 | /* | |
3177 | * TODO: Since file already open, we can't open with DENY_ALL here | |
3178 | * but we could add call to grab a byte range lock to prevent others | |
3179 | * from reading or writing the file | |
3180 | */ | |
3181 | ||
4b60c0ff N |
3182 | sis->flags |= SWP_FS_OPS; |
3183 | return add_swap_extent(sis, 0, sis->max, 0); | |
4e8aea30 SF |
3184 | } |
3185 | ||
3186 | static void cifs_swap_deactivate(struct file *file) | |
3187 | { | |
3188 | struct cifsFileInfo *cfile = file->private_data; | |
3189 | ||
3190 | cifs_dbg(FYI, "swap deactivate\n"); | |
3191 | ||
3192 | /* TODO: undo sk_set_memalloc(inet) will eventually be needed */ | |
3193 | ||
3194 | if (cfile) | |
3195 | cfile->swapfile = false; | |
3196 | ||
3197 | /* do we need to unpin (or unlock) the file */ | |
3198 | } | |
dca69288 | 3199 | |
16e00683 SF |
3200 | /** |
3201 | * cifs_swap_rw - SMB3 address space operation for swap I/O | |
3202 | * @iocb: target I/O control block | |
3203 | * @iter: I/O buffer | |
3204 | * | |
3205 | * Perform IO to the swap-file. This is much like direct IO. | |
3206 | */ | |
3207 | static int cifs_swap_rw(struct kiocb *iocb, struct iov_iter *iter) | |
3208 | { | |
3209 | ssize_t ret; | |
3210 | ||
16e00683 SF |
3211 | if (iov_iter_rw(iter) == READ) |
3212 | ret = netfs_unbuffered_read_iter_locked(iocb, iter); | |
3213 | else | |
3214 | ret = netfs_unbuffered_write_iter_locked(iocb, iter, NULL); | |
3215 | if (ret < 0) | |
3216 | return ret; | |
3217 | return 0; | |
3218 | } | |
3219 | ||
f5e54d6e | 3220 | const struct address_space_operations cifs_addr_ops = { |
3ee1a1fc DH |
3221 | .read_folio = netfs_read_folio, |
3222 | .readahead = netfs_readahead, | |
3223 | .writepages = netfs_writepages, | |
3224 | .dirty_folio = netfs_dirty_folio, | |
3225 | .release_folio = netfs_release_folio, | |
3226 | .direct_IO = noop_direct_IO, | |
3227 | .invalidate_folio = netfs_invalidate_folio, | |
3228 | .migrate_folio = filemap_migrate_folio, | |
4e8aea30 | 3229 | /* |
9381666e CH |
3230 | * TODO: investigate and if useful we could add an is_dirty_writeback |
3231 | * helper if needed | |
4e8aea30 | 3232 | */ |
3ee1a1fc | 3233 | .swap_activate = cifs_swap_activate, |
4e8aea30 | 3234 | .swap_deactivate = cifs_swap_deactivate, |
16e00683 | 3235 | .swap_rw = cifs_swap_rw, |
1da177e4 | 3236 | }; |
273d81d6 DK |
3237 | |
3238 | /* | |
ce3bb0d2 | 3239 | * cifs_readahead requires the server to support a buffer large enough to |
273d81d6 | 3240 | * contain the header plus one complete page of data. Otherwise, we need |
ce3bb0d2 | 3241 | * to leave cifs_readahead out of the address space operations. |
273d81d6 | 3242 | */ |
f5e54d6e | 3243 | const struct address_space_operations cifs_addr_ops_smallbuf = { |
3ee1a1fc DH |
3244 | .read_folio = netfs_read_folio, |
3245 | .writepages = netfs_writepages, | |
3246 | .dirty_folio = netfs_dirty_folio, | |
3247 | .release_folio = netfs_release_folio, | |
3248 | .invalidate_folio = netfs_invalidate_folio, | |
3249 | .migrate_folio = filemap_migrate_folio, | |
273d81d6 | 3250 | }; |