diff options
Diffstat (limited to 'fs/cifs/file.c')
-rw-r--r-- | fs/cifs/file.c | 174 |
1 files changed, 93 insertions, 81 deletions
diff --git a/fs/cifs/file.c b/fs/cifs/file.c index c34b7f8a217b..429337eb7afe 100644 --- a/fs/cifs/file.c +++ b/fs/cifs/file.c | |||
@@ -30,6 +30,7 @@ | |||
30 | #include <linux/writeback.h> | 30 | #include <linux/writeback.h> |
31 | #include <linux/task_io_accounting_ops.h> | 31 | #include <linux/task_io_accounting_ops.h> |
32 | #include <linux/delay.h> | 32 | #include <linux/delay.h> |
33 | #include <linux/mount.h> | ||
33 | #include <asm/div64.h> | 34 | #include <asm/div64.h> |
34 | #include "cifsfs.h" | 35 | #include "cifsfs.h" |
35 | #include "cifspdu.h" | 36 | #include "cifspdu.h" |
@@ -39,29 +40,6 @@ | |||
39 | #include "cifs_debug.h" | 40 | #include "cifs_debug.h" |
40 | #include "cifs_fs_sb.h" | 41 | #include "cifs_fs_sb.h" |
41 | 42 | ||
42 | static inline struct cifsFileInfo *cifs_init_private( | ||
43 | struct cifsFileInfo *private_data, struct inode *inode, | ||
44 | struct file *file, __u16 netfid) | ||
45 | { | ||
46 | memset(private_data, 0, sizeof(struct cifsFileInfo)); | ||
47 | private_data->netfid = netfid; | ||
48 | private_data->pid = current->tgid; | ||
49 | mutex_init(&private_data->fh_mutex); | ||
50 | mutex_init(&private_data->lock_mutex); | ||
51 | INIT_LIST_HEAD(&private_data->llist); | ||
52 | private_data->pfile = file; /* needed for writepage */ | ||
53 | private_data->pInode = inode; | ||
54 | private_data->invalidHandle = false; | ||
55 | private_data->closePend = false; | ||
56 | /* we have to track num writers to the inode, since writepages | ||
57 | does not tell us which handle the write is for so there can | ||
58 | be a close (overlapping with write) of the filehandle that | ||
59 | cifs_writepages chose to use */ | ||
60 | atomic_set(&private_data->wrtPending, 0); | ||
61 | |||
62 | return private_data; | ||
63 | } | ||
64 | |||
65 | static inline int cifs_convert_flags(unsigned int flags) | 43 | static inline int cifs_convert_flags(unsigned int flags) |
66 | { | 44 | { |
67 | if ((flags & O_ACCMODE) == O_RDONLY) | 45 | if ((flags & O_ACCMODE) == O_RDONLY) |
@@ -125,9 +103,11 @@ static inline int cifs_get_disposition(unsigned int flags) | |||
125 | } | 103 | } |
126 | 104 | ||
127 | /* all arguments to this function must be checked for validity in caller */ | 105 | /* all arguments to this function must be checked for validity in caller */ |
128 | static inline int cifs_posix_open_inode_helper(struct inode *inode, | 106 | static inline int |
129 | struct file *file, struct cifsInodeInfo *pCifsInode, | 107 | cifs_posix_open_inode_helper(struct inode *inode, struct file *file, |
130 | struct cifsFileInfo *pCifsFile, int oplock, u16 netfid) | 108 | struct cifsInodeInfo *pCifsInode, |
109 | struct cifsFileInfo *pCifsFile, __u32 oplock, | ||
110 | u16 netfid) | ||
131 | { | 111 | { |
132 | 112 | ||
133 | write_lock(&GlobalSMBSeslock); | 113 | write_lock(&GlobalSMBSeslock); |
@@ -221,17 +201,6 @@ static inline int cifs_open_inode_helper(struct inode *inode, struct file *file, | |||
221 | struct timespec temp; | 201 | struct timespec temp; |
222 | int rc; | 202 | int rc; |
223 | 203 | ||
224 | /* want handles we can use to read with first | ||
225 | in the list so we do not have to walk the | ||
226 | list to search for one in write_begin */ | ||
227 | if ((file->f_flags & O_ACCMODE) == O_WRONLY) { | ||
228 | list_add_tail(&pCifsFile->flist, | ||
229 | &pCifsInode->openFileList); | ||
230 | } else { | ||
231 | list_add(&pCifsFile->flist, | ||
232 | &pCifsInode->openFileList); | ||
233 | } | ||
234 | write_unlock(&GlobalSMBSeslock); | ||
235 | if (pCifsInode->clientCanCacheRead) { | 204 | if (pCifsInode->clientCanCacheRead) { |
236 | /* we have the inode open somewhere else | 205 | /* we have the inode open somewhere else |
237 | no need to discard cache data */ | 206 | no need to discard cache data */ |
@@ -281,7 +250,8 @@ client_can_cache: | |||
281 | int cifs_open(struct inode *inode, struct file *file) | 250 | int cifs_open(struct inode *inode, struct file *file) |
282 | { | 251 | { |
283 | int rc = -EACCES; | 252 | int rc = -EACCES; |
284 | int xid, oplock; | 253 | int xid; |
254 | __u32 oplock; | ||
285 | struct cifs_sb_info *cifs_sb; | 255 | struct cifs_sb_info *cifs_sb; |
286 | struct cifsTconInfo *tcon; | 256 | struct cifsTconInfo *tcon; |
287 | struct cifsFileInfo *pCifsFile; | 257 | struct cifsFileInfo *pCifsFile; |
@@ -326,7 +296,7 @@ int cifs_open(struct inode *inode, struct file *file) | |||
326 | le64_to_cpu(tcon->fsUnixInfo.Capability))) { | 296 | le64_to_cpu(tcon->fsUnixInfo.Capability))) { |
327 | int oflags = (int) cifs_posix_convert_flags(file->f_flags); | 297 | int oflags = (int) cifs_posix_convert_flags(file->f_flags); |
328 | /* can not refresh inode info since size could be stale */ | 298 | /* can not refresh inode info since size could be stale */ |
329 | rc = cifs_posix_open(full_path, &inode, inode->i_sb, | 299 | rc = cifs_posix_open(full_path, &inode, file->f_path.mnt, |
330 | cifs_sb->mnt_file_mode /* ignored */, | 300 | cifs_sb->mnt_file_mode /* ignored */, |
331 | oflags, &oplock, &netfid, xid); | 301 | oflags, &oplock, &netfid, xid); |
332 | if (rc == 0) { | 302 | if (rc == 0) { |
@@ -416,24 +386,17 @@ int cifs_open(struct inode *inode, struct file *file) | |||
416 | cFYI(1, ("cifs_open returned 0x%x", rc)); | 386 | cFYI(1, ("cifs_open returned 0x%x", rc)); |
417 | goto out; | 387 | goto out; |
418 | } | 388 | } |
419 | file->private_data = | 389 | |
420 | kmalloc(sizeof(struct cifsFileInfo), GFP_KERNEL); | 390 | pCifsFile = cifs_new_fileinfo(inode, netfid, file, file->f_path.mnt, |
391 | file->f_flags); | ||
392 | file->private_data = pCifsFile; | ||
421 | if (file->private_data == NULL) { | 393 | if (file->private_data == NULL) { |
422 | rc = -ENOMEM; | 394 | rc = -ENOMEM; |
423 | goto out; | 395 | goto out; |
424 | } | 396 | } |
425 | pCifsFile = cifs_init_private(file->private_data, inode, file, netfid); | ||
426 | write_lock(&GlobalSMBSeslock); | ||
427 | list_add(&pCifsFile->tlist, &tcon->openFileList); | ||
428 | 397 | ||
429 | pCifsInode = CIFS_I(file->f_path.dentry->d_inode); | 398 | rc = cifs_open_inode_helper(inode, file, pCifsInode, pCifsFile, tcon, |
430 | if (pCifsInode) { | 399 | &oplock, buf, full_path, xid); |
431 | rc = cifs_open_inode_helper(inode, file, pCifsInode, | ||
432 | pCifsFile, tcon, | ||
433 | &oplock, buf, full_path, xid); | ||
434 | } else { | ||
435 | write_unlock(&GlobalSMBSeslock); | ||
436 | } | ||
437 | 400 | ||
438 | if (oplock & CIFS_CREATE_ACTION) { | 401 | if (oplock & CIFS_CREATE_ACTION) { |
439 | /* time to set mode which we can not set earlier due to | 402 | /* time to set mode which we can not set earlier due to |
@@ -476,7 +439,8 @@ static int cifs_relock_file(struct cifsFileInfo *cifsFile) | |||
476 | static int cifs_reopen_file(struct file *file, bool can_flush) | 439 | static int cifs_reopen_file(struct file *file, bool can_flush) |
477 | { | 440 | { |
478 | int rc = -EACCES; | 441 | int rc = -EACCES; |
479 | int xid, oplock; | 442 | int xid; |
443 | __u32 oplock; | ||
480 | struct cifs_sb_info *cifs_sb; | 444 | struct cifs_sb_info *cifs_sb; |
481 | struct cifsTconInfo *tcon; | 445 | struct cifsTconInfo *tcon; |
482 | struct cifsFileInfo *pCifsFile; | 446 | struct cifsFileInfo *pCifsFile; |
@@ -545,7 +509,7 @@ reopen_error_exit: | |||
545 | le64_to_cpu(tcon->fsUnixInfo.Capability))) { | 509 | le64_to_cpu(tcon->fsUnixInfo.Capability))) { |
546 | int oflags = (int) cifs_posix_convert_flags(file->f_flags); | 510 | int oflags = (int) cifs_posix_convert_flags(file->f_flags); |
547 | /* can not refresh inode info since size could be stale */ | 511 | /* can not refresh inode info since size could be stale */ |
548 | rc = cifs_posix_open(full_path, NULL, inode->i_sb, | 512 | rc = cifs_posix_open(full_path, NULL, file->f_path.mnt, |
549 | cifs_sb->mnt_file_mode /* ignored */, | 513 | cifs_sb->mnt_file_mode /* ignored */, |
550 | oflags, &oplock, &netfid, xid); | 514 | oflags, &oplock, &netfid, xid); |
551 | if (rc == 0) { | 515 | if (rc == 0) { |
@@ -643,7 +607,7 @@ int cifs_close(struct inode *inode, struct file *file) | |||
643 | if (!pTcon->need_reconnect) { | 607 | if (!pTcon->need_reconnect) { |
644 | write_unlock(&GlobalSMBSeslock); | 608 | write_unlock(&GlobalSMBSeslock); |
645 | timeout = 2; | 609 | timeout = 2; |
646 | while ((atomic_read(&pSMBFile->wrtPending) != 0) | 610 | while ((atomic_read(&pSMBFile->count) != 1) |
647 | && (timeout <= 2048)) { | 611 | && (timeout <= 2048)) { |
648 | /* Give write a better chance to get to | 612 | /* Give write a better chance to get to |
649 | server ahead of the close. We do not | 613 | server ahead of the close. We do not |
@@ -657,8 +621,6 @@ int cifs_close(struct inode *inode, struct file *file) | |||
657 | msleep(timeout); | 621 | msleep(timeout); |
658 | timeout *= 4; | 622 | timeout *= 4; |
659 | } | 623 | } |
660 | if (atomic_read(&pSMBFile->wrtPending)) | ||
661 | cERROR(1, ("close with pending write")); | ||
662 | if (!pTcon->need_reconnect && | 624 | if (!pTcon->need_reconnect && |
663 | !pSMBFile->invalidHandle) | 625 | !pSMBFile->invalidHandle) |
664 | rc = CIFSSMBClose(xid, pTcon, | 626 | rc = CIFSSMBClose(xid, pTcon, |
@@ -681,24 +643,7 @@ int cifs_close(struct inode *inode, struct file *file) | |||
681 | list_del(&pSMBFile->flist); | 643 | list_del(&pSMBFile->flist); |
682 | list_del(&pSMBFile->tlist); | 644 | list_del(&pSMBFile->tlist); |
683 | write_unlock(&GlobalSMBSeslock); | 645 | write_unlock(&GlobalSMBSeslock); |
684 | timeout = 10; | 646 | cifsFileInfo_put(file->private_data); |
685 | /* We waited above to give the SMBWrite a chance to issue | ||
686 | on the wire (so we do not get SMBWrite returning EBADF | ||
687 | if writepages is racing with close. Note that writepages | ||
688 | does not specify a file handle, so it is possible for a file | ||
689 | to be opened twice, and the application close the "wrong" | ||
690 | file handle - in these cases we delay long enough to allow | ||
691 | the SMBWrite to get on the wire before the SMB Close. | ||
692 | We allow total wait here over 45 seconds, more than | ||
693 | oplock break time, and more than enough to allow any write | ||
694 | to complete on the server, or to time out on the client */ | ||
695 | while ((atomic_read(&pSMBFile->wrtPending) != 0) | ||
696 | && (timeout <= 50000)) { | ||
697 | cERROR(1, ("writes pending, delay free of handle")); | ||
698 | msleep(timeout); | ||
699 | timeout *= 8; | ||
700 | } | ||
701 | kfree(file->private_data); | ||
702 | file->private_data = NULL; | 647 | file->private_data = NULL; |
703 | } else | 648 | } else |
704 | rc = -EBADF; | 649 | rc = -EBADF; |
@@ -1236,7 +1181,7 @@ struct cifsFileInfo *find_readable_file(struct cifsInodeInfo *cifs_inode) | |||
1236 | if (!open_file->invalidHandle) { | 1181 | if (!open_file->invalidHandle) { |
1237 | /* found a good file */ | 1182 | /* found a good file */ |
1238 | /* lock it so it will not be closed on us */ | 1183 | /* lock it so it will not be closed on us */ |
1239 | atomic_inc(&open_file->wrtPending); | 1184 | cifsFileInfo_get(open_file); |
1240 | read_unlock(&GlobalSMBSeslock); | 1185 | read_unlock(&GlobalSMBSeslock); |
1241 | return open_file; | 1186 | return open_file; |
1242 | } /* else might as well continue, and look for | 1187 | } /* else might as well continue, and look for |
@@ -1276,7 +1221,7 @@ refind_writable: | |||
1276 | if (open_file->pfile && | 1221 | if (open_file->pfile && |
1277 | ((open_file->pfile->f_flags & O_RDWR) || | 1222 | ((open_file->pfile->f_flags & O_RDWR) || |
1278 | (open_file->pfile->f_flags & O_WRONLY))) { | 1223 | (open_file->pfile->f_flags & O_WRONLY))) { |
1279 | atomic_inc(&open_file->wrtPending); | 1224 | cifsFileInfo_get(open_file); |
1280 | 1225 | ||
1281 | if (!open_file->invalidHandle) { | 1226 | if (!open_file->invalidHandle) { |
1282 | /* found a good writable file */ | 1227 | /* found a good writable file */ |
@@ -1293,7 +1238,7 @@ refind_writable: | |||
1293 | else { /* start over in case this was deleted */ | 1238 | else { /* start over in case this was deleted */ |
1294 | /* since the list could be modified */ | 1239 | /* since the list could be modified */ |
1295 | read_lock(&GlobalSMBSeslock); | 1240 | read_lock(&GlobalSMBSeslock); |
1296 | atomic_dec(&open_file->wrtPending); | 1241 | cifsFileInfo_put(open_file); |
1297 | goto refind_writable; | 1242 | goto refind_writable; |
1298 | } | 1243 | } |
1299 | } | 1244 | } |
@@ -1309,7 +1254,7 @@ refind_writable: | |||
1309 | read_lock(&GlobalSMBSeslock); | 1254 | read_lock(&GlobalSMBSeslock); |
1310 | /* can not use this handle, no write | 1255 | /* can not use this handle, no write |
1311 | pending on this one after all */ | 1256 | pending on this one after all */ |
1312 | atomic_dec(&open_file->wrtPending); | 1257 | cifsFileInfo_put(open_file); |
1313 | 1258 | ||
1314 | if (open_file->closePend) /* list could have changed */ | 1259 | if (open_file->closePend) /* list could have changed */ |
1315 | goto refind_writable; | 1260 | goto refind_writable; |
@@ -1373,7 +1318,7 @@ static int cifs_partialpagewrite(struct page *page, unsigned from, unsigned to) | |||
1373 | if (open_file) { | 1318 | if (open_file) { |
1374 | bytes_written = cifs_write(open_file->pfile, write_data, | 1319 | bytes_written = cifs_write(open_file->pfile, write_data, |
1375 | to-from, &offset); | 1320 | to-from, &offset); |
1376 | atomic_dec(&open_file->wrtPending); | 1321 | cifsFileInfo_put(open_file); |
1377 | /* Does mm or vfs already set times? */ | 1322 | /* Does mm or vfs already set times? */ |
1378 | inode->i_atime = inode->i_mtime = current_fs_time(inode->i_sb); | 1323 | inode->i_atime = inode->i_mtime = current_fs_time(inode->i_sb); |
1379 | if ((bytes_written > 0) && (offset)) | 1324 | if ((bytes_written > 0) && (offset)) |
@@ -1562,7 +1507,7 @@ retry: | |||
1562 | bytes_to_write, offset, | 1507 | bytes_to_write, offset, |
1563 | &bytes_written, iov, n_iov, | 1508 | &bytes_written, iov, n_iov, |
1564 | long_op); | 1509 | long_op); |
1565 | atomic_dec(&open_file->wrtPending); | 1510 | cifsFileInfo_put(open_file); |
1566 | cifs_update_eof(cifsi, offset, bytes_written); | 1511 | cifs_update_eof(cifsi, offset, bytes_written); |
1567 | 1512 | ||
1568 | if (rc || bytes_written < bytes_to_write) { | 1513 | if (rc || bytes_written < bytes_to_write) { |
@@ -2329,6 +2274,73 @@ out: | |||
2329 | return rc; | 2274 | return rc; |
2330 | } | 2275 | } |
2331 | 2276 | ||
2277 | static void | ||
2278 | cifs_oplock_break(struct slow_work *work) | ||
2279 | { | ||
2280 | struct cifsFileInfo *cfile = container_of(work, struct cifsFileInfo, | ||
2281 | oplock_break); | ||
2282 | struct inode *inode = cfile->pInode; | ||
2283 | struct cifsInodeInfo *cinode = CIFS_I(inode); | ||
2284 | struct cifs_sb_info *cifs_sb = CIFS_SB(cfile->mnt->mnt_sb); | ||
2285 | int rc, waitrc = 0; | ||
2286 | |||
2287 | if (inode && S_ISREG(inode->i_mode)) { | ||
2288 | #ifdef CONFIG_CIFS_EXPERIMENTAL | ||
2289 | if (cinode->clientCanCacheAll == 0) | ||
2290 | break_lease(inode, FMODE_READ); | ||
2291 | else if (cinode->clientCanCacheRead == 0) | ||
2292 | break_lease(inode, FMODE_WRITE); | ||
2293 | #endif | ||
2294 | rc = filemap_fdatawrite(inode->i_mapping); | ||
2295 | if (cinode->clientCanCacheRead == 0) { | ||
2296 | waitrc = filemap_fdatawait(inode->i_mapping); | ||
2297 | invalidate_remote_inode(inode); | ||
2298 | } | ||
2299 | if (!rc) | ||
2300 | rc = waitrc; | ||
2301 | if (rc) | ||
2302 | cinode->write_behind_rc = rc; | ||
2303 | cFYI(1, ("Oplock flush inode %p rc %d", inode, rc)); | ||
2304 | } | ||
2305 | |||
2306 | /* | ||
2307 | * releasing stale oplock after recent reconnect of smb session using | ||
2308 | * a now incorrect file handle is not a data integrity issue but do | ||
2309 | * not bother sending an oplock release if session to server still is | ||
2310 | * disconnected since oplock already released by the server | ||
2311 | */ | ||
2312 | if (!cfile->closePend && !cfile->oplock_break_cancelled) { | ||
2313 | rc = CIFSSMBLock(0, cifs_sb->tcon, cfile->netfid, 0, 0, 0, 0, | ||
2314 | LOCKING_ANDX_OPLOCK_RELEASE, false); | ||
2315 | cFYI(1, ("Oplock release rc = %d", rc)); | ||
2316 | } | ||
2317 | } | ||
2318 | |||
2319 | static int | ||
2320 | cifs_oplock_break_get(struct slow_work *work) | ||
2321 | { | ||
2322 | struct cifsFileInfo *cfile = container_of(work, struct cifsFileInfo, | ||
2323 | oplock_break); | ||
2324 | mntget(cfile->mnt); | ||
2325 | cifsFileInfo_get(cfile); | ||
2326 | return 0; | ||
2327 | } | ||
2328 | |||
2329 | static void | ||
2330 | cifs_oplock_break_put(struct slow_work *work) | ||
2331 | { | ||
2332 | struct cifsFileInfo *cfile = container_of(work, struct cifsFileInfo, | ||
2333 | oplock_break); | ||
2334 | mntput(cfile->mnt); | ||
2335 | cifsFileInfo_put(cfile); | ||
2336 | } | ||
2337 | |||
2338 | const struct slow_work_ops cifs_oplock_break_ops = { | ||
2339 | .get_ref = cifs_oplock_break_get, | ||
2340 | .put_ref = cifs_oplock_break_put, | ||
2341 | .execute = cifs_oplock_break, | ||
2342 | }; | ||
2343 | |||
2332 | const struct address_space_operations cifs_addr_ops = { | 2344 | const struct address_space_operations cifs_addr_ops = { |
2333 | .readpage = cifs_readpage, | 2345 | .readpage = cifs_readpage, |
2334 | .readpages = cifs_readpages, | 2346 | .readpages = cifs_readpages, |