aboutsummaryrefslogtreecommitdiffstats
path: root/fs/cifs/file.c
diff options
context:
space:
mode:
Diffstat (limited to 'fs/cifs/file.c')
-rw-r--r--fs/cifs/file.c199
1 files changed, 180 insertions, 19 deletions
diff --git a/fs/cifs/file.c b/fs/cifs/file.c
index 12bb656fbe75..81747acca4c4 100644
--- a/fs/cifs/file.c
+++ b/fs/cifs/file.c
@@ -78,8 +78,36 @@ static inline int cifs_convert_flags(unsigned int flags)
78 return (READ_CONTROL | FILE_WRITE_ATTRIBUTES | FILE_READ_ATTRIBUTES | 78 return (READ_CONTROL | FILE_WRITE_ATTRIBUTES | FILE_READ_ATTRIBUTES |
79 FILE_WRITE_EA | FILE_APPEND_DATA | FILE_WRITE_DATA | 79 FILE_WRITE_EA | FILE_APPEND_DATA | FILE_WRITE_DATA |
80 FILE_READ_DATA); 80 FILE_READ_DATA);
81}
81 82
83static inline fmode_t cifs_posix_convert_flags(unsigned int flags)
84{
85 fmode_t posix_flags = 0;
82 86
87 if ((flags & O_ACCMODE) == O_RDONLY)
88 posix_flags = FMODE_READ;
89 else if ((flags & O_ACCMODE) == O_WRONLY)
90 posix_flags = FMODE_WRITE;
91 else if ((flags & O_ACCMODE) == O_RDWR) {
92 /* GENERIC_ALL is too much permission to request
93 can cause unnecessary access denied on create */
94 /* return GENERIC_ALL; */
95 posix_flags = FMODE_READ | FMODE_WRITE;
96 }
97 /* can not map O_CREAT or O_EXCL or O_TRUNC flags when
98 reopening a file. They had their effect on the original open */
99 if (flags & O_APPEND)
100 posix_flags |= (fmode_t)O_APPEND;
101 if (flags & O_SYNC)
102 posix_flags |= (fmode_t)O_SYNC;
103 if (flags & O_DIRECTORY)
104 posix_flags |= (fmode_t)O_DIRECTORY;
105 if (flags & O_NOFOLLOW)
106 posix_flags |= (fmode_t)O_NOFOLLOW;
107 if (flags & O_DIRECT)
108 posix_flags |= (fmode_t)O_DIRECT;
109
110 return posix_flags;
83} 111}
84 112
85static inline int cifs_get_disposition(unsigned int flags) 113static inline int cifs_get_disposition(unsigned int flags)
@@ -97,6 +125,80 @@ static inline int cifs_get_disposition(unsigned int flags)
97} 125}
98 126
99/* all arguments to this function must be checked for validity in caller */ 127/* all arguments to this function must be checked for validity in caller */
128static inline int cifs_posix_open_inode_helper(struct inode *inode,
129 struct file *file, struct cifsInodeInfo *pCifsInode,
130 struct cifsFileInfo *pCifsFile, int oplock, u16 netfid)
131{
132 struct cifs_sb_info *cifs_sb = CIFS_SB(inode->i_sb);
133/* struct timespec temp; */ /* BB REMOVEME BB */
134
135 file->private_data = kmalloc(sizeof(struct cifsFileInfo), GFP_KERNEL);
136 if (file->private_data == NULL)
137 return -ENOMEM;
138 pCifsFile = cifs_init_private(file->private_data, inode, file, netfid);
139 write_lock(&GlobalSMBSeslock);
140 list_add(&pCifsFile->tlist, &cifs_sb->tcon->openFileList);
141
142 pCifsInode = CIFS_I(file->f_path.dentry->d_inode);
143 if (pCifsInode == NULL) {
144 write_unlock(&GlobalSMBSeslock);
145 return -EINVAL;
146 }
147
148 /* want handles we can use to read with first
149 in the list so we do not have to walk the
150 list to search for one in write_begin */
151 if ((file->f_flags & O_ACCMODE) == O_WRONLY) {
152 list_add_tail(&pCifsFile->flist,
153 &pCifsInode->openFileList);
154 } else {
155 list_add(&pCifsFile->flist,
156 &pCifsInode->openFileList);
157 }
158
159 if (pCifsInode->clientCanCacheRead) {
160 /* we have the inode open somewhere else
161 no need to discard cache data */
162 goto psx_client_can_cache;
163 }
164
165 /* BB FIXME need to fix this check to move it earlier into posix_open
166 BB fIX following section BB FIXME */
167
168 /* if not oplocked, invalidate inode pages if mtime or file
169 size changed */
170/* temp = cifs_NTtimeToUnix(le64_to_cpu(buf->LastWriteTime));
171 if (timespec_equal(&file->f_path.dentry->d_inode->i_mtime, &temp) &&
172 (file->f_path.dentry->d_inode->i_size ==
173 (loff_t)le64_to_cpu(buf->EndOfFile))) {
174 cFYI(1, ("inode unchanged on server"));
175 } else {
176 if (file->f_path.dentry->d_inode->i_mapping) {
177 rc = filemap_write_and_wait(file->f_path.dentry->d_inode->i_mapping);
178 if (rc != 0)
179 CIFS_I(file->f_path.dentry->d_inode)->write_behind_rc = rc;
180 }
181 cFYI(1, ("invalidating remote inode since open detected it "
182 "changed"));
183 invalidate_remote_inode(file->f_path.dentry->d_inode);
184 } */
185
186psx_client_can_cache:
187 if ((oplock & 0xF) == OPLOCK_EXCLUSIVE) {
188 pCifsInode->clientCanCacheAll = true;
189 pCifsInode->clientCanCacheRead = true;
190 cFYI(1, ("Exclusive Oplock granted on inode %p",
191 file->f_path.dentry->d_inode));
192 } else if ((oplock & 0xF) == OPLOCK_READ)
193 pCifsInode->clientCanCacheRead = true;
194
195 /* will have to change the unlock if we reenable the
196 filemap_fdatawrite (which does not seem necessary */
197 write_unlock(&GlobalSMBSeslock);
198 return 0;
199}
200
201/* all arguments to this function must be checked for validity in caller */
100static inline int cifs_open_inode_helper(struct inode *inode, struct file *file, 202static inline int cifs_open_inode_helper(struct inode *inode, struct file *file,
101 struct cifsInodeInfo *pCifsInode, struct cifsFileInfo *pCifsFile, 203 struct cifsInodeInfo *pCifsInode, struct cifsFileInfo *pCifsFile,
102 struct cifsTconInfo *pTcon, int *oplock, FILE_ALL_INFO *buf, 204 struct cifsTconInfo *pTcon, int *oplock, FILE_ALL_INFO *buf,
@@ -167,7 +269,7 @@ int cifs_open(struct inode *inode, struct file *file)
167 int rc = -EACCES; 269 int rc = -EACCES;
168 int xid, oplock; 270 int xid, oplock;
169 struct cifs_sb_info *cifs_sb; 271 struct cifs_sb_info *cifs_sb;
170 struct cifsTconInfo *pTcon; 272 struct cifsTconInfo *tcon;
171 struct cifsFileInfo *pCifsFile; 273 struct cifsFileInfo *pCifsFile;
172 struct cifsInodeInfo *pCifsInode; 274 struct cifsInodeInfo *pCifsInode;
173 struct list_head *tmp; 275 struct list_head *tmp;
@@ -180,7 +282,7 @@ int cifs_open(struct inode *inode, struct file *file)
180 xid = GetXid(); 282 xid = GetXid();
181 283
182 cifs_sb = CIFS_SB(inode->i_sb); 284 cifs_sb = CIFS_SB(inode->i_sb);
183 pTcon = cifs_sb->tcon; 285 tcon = cifs_sb->tcon;
184 286
185 if (file->f_flags & O_CREAT) { 287 if (file->f_flags & O_CREAT) {
186 /* search inode for this file and fill in file->private_data */ 288 /* search inode for this file and fill in file->private_data */
@@ -220,6 +322,45 @@ int cifs_open(struct inode *inode, struct file *file)
220 322
221 cFYI(1, ("inode = 0x%p file flags are 0x%x for %s", 323 cFYI(1, ("inode = 0x%p file flags are 0x%x for %s",
222 inode, file->f_flags, full_path)); 324 inode, file->f_flags, full_path));
325
326 if (oplockEnabled)
327 oplock = REQ_OPLOCK;
328 else
329 oplock = 0;
330
331 if (!tcon->broken_posix_open && tcon->unix_ext &&
332 (tcon->ses->capabilities & CAP_UNIX) &&
333 (CIFS_UNIX_POSIX_PATH_OPS_CAP &
334 le64_to_cpu(tcon->fsUnixInfo.Capability))) {
335 int oflags = (int) cifs_posix_convert_flags(file->f_flags);
336 /* can not refresh inode info since size could be stale */
337 rc = cifs_posix_open(full_path, &inode, inode->i_sb,
338 cifs_sb->mnt_file_mode /* ignored */,
339 oflags, &oplock, &netfid, xid);
340 if (rc == 0) {
341 cFYI(1, ("posix open succeeded"));
342 /* no need for special case handling of setting mode
343 on read only files needed here */
344
345 cifs_posix_open_inode_helper(inode, file, pCifsInode,
346 pCifsFile, oplock, netfid);
347 goto out;
348 } else if ((rc == -EINVAL) || (rc == -EOPNOTSUPP)) {
349 if (tcon->ses->serverNOS)
350 cERROR(1, ("server %s of type %s returned"
351 " unexpected error on SMB posix open"
352 ", disabling posix open support."
353 " Check if server update available.",
354 tcon->ses->serverName,
355 tcon->ses->serverNOS));
356 tcon->broken_posix_open = true;
357 } else if ((rc != -EIO) && (rc != -EREMOTE) &&
358 (rc != -EOPNOTSUPP)) /* path not found or net err */
359 goto out;
360 /* else fallthrough to retry open the old way on network i/o
361 or DFS errors */
362 }
363
223 desiredAccess = cifs_convert_flags(file->f_flags); 364 desiredAccess = cifs_convert_flags(file->f_flags);
224 365
225/********************************************************************* 366/*********************************************************************
@@ -248,11 +389,6 @@ int cifs_open(struct inode *inode, struct file *file)
248 389
249 disposition = cifs_get_disposition(file->f_flags); 390 disposition = cifs_get_disposition(file->f_flags);
250 391
251 if (oplockEnabled)
252 oplock = REQ_OPLOCK;
253 else
254 oplock = 0;
255
256 /* BB pass O_SYNC flag through on file attributes .. BB */ 392 /* BB pass O_SYNC flag through on file attributes .. BB */
257 393
258 /* Also refresh inode by passing in file_info buf returned by SMBOpen 394 /* Also refresh inode by passing in file_info buf returned by SMBOpen
@@ -269,7 +405,7 @@ int cifs_open(struct inode *inode, struct file *file)
269 } 405 }
270 406
271 if (cifs_sb->tcon->ses->capabilities & CAP_NT_SMBS) 407 if (cifs_sb->tcon->ses->capabilities & CAP_NT_SMBS)
272 rc = CIFSSMBOpen(xid, pTcon, full_path, disposition, 408 rc = CIFSSMBOpen(xid, tcon, full_path, disposition,
273 desiredAccess, CREATE_NOT_DIR, &netfid, &oplock, buf, 409 desiredAccess, CREATE_NOT_DIR, &netfid, &oplock, buf,
274 cifs_sb->local_nls, cifs_sb->mnt_cifs_flags 410 cifs_sb->local_nls, cifs_sb->mnt_cifs_flags
275 & CIFS_MOUNT_MAP_SPECIAL_CHR); 411 & CIFS_MOUNT_MAP_SPECIAL_CHR);
@@ -278,7 +414,7 @@ int cifs_open(struct inode *inode, struct file *file)
278 414
279 if (rc == -EIO) { 415 if (rc == -EIO) {
280 /* Old server, try legacy style OpenX */ 416 /* Old server, try legacy style OpenX */
281 rc = SMBLegacyOpen(xid, pTcon, full_path, disposition, 417 rc = SMBLegacyOpen(xid, tcon, full_path, disposition,
282 desiredAccess, CREATE_NOT_DIR, &netfid, &oplock, buf, 418 desiredAccess, CREATE_NOT_DIR, &netfid, &oplock, buf,
283 cifs_sb->local_nls, cifs_sb->mnt_cifs_flags 419 cifs_sb->local_nls, cifs_sb->mnt_cifs_flags
284 & CIFS_MOUNT_MAP_SPECIAL_CHR); 420 & CIFS_MOUNT_MAP_SPECIAL_CHR);
@@ -295,12 +431,12 @@ int cifs_open(struct inode *inode, struct file *file)
295 } 431 }
296 pCifsFile = cifs_init_private(file->private_data, inode, file, netfid); 432 pCifsFile = cifs_init_private(file->private_data, inode, file, netfid);
297 write_lock(&GlobalSMBSeslock); 433 write_lock(&GlobalSMBSeslock);
298 list_add(&pCifsFile->tlist, &pTcon->openFileList); 434 list_add(&pCifsFile->tlist, &tcon->openFileList);
299 435
300 pCifsInode = CIFS_I(file->f_path.dentry->d_inode); 436 pCifsInode = CIFS_I(file->f_path.dentry->d_inode);
301 if (pCifsInode) { 437 if (pCifsInode) {
302 rc = cifs_open_inode_helper(inode, file, pCifsInode, 438 rc = cifs_open_inode_helper(inode, file, pCifsInode,
303 pCifsFile, pTcon, 439 pCifsFile, tcon,
304 &oplock, buf, full_path, xid); 440 &oplock, buf, full_path, xid);
305 } else { 441 } else {
306 write_unlock(&GlobalSMBSeslock); 442 write_unlock(&GlobalSMBSeslock);
@@ -309,7 +445,7 @@ int cifs_open(struct inode *inode, struct file *file)
309 if (oplock & CIFS_CREATE_ACTION) { 445 if (oplock & CIFS_CREATE_ACTION) {
310 /* time to set mode which we can not set earlier due to 446 /* time to set mode which we can not set earlier due to
311 problems creating new read-only files */ 447 problems creating new read-only files */
312 if (pTcon->unix_ext) { 448 if (tcon->unix_ext) {
313 struct cifs_unix_set_info_args args = { 449 struct cifs_unix_set_info_args args = {
314 .mode = inode->i_mode, 450 .mode = inode->i_mode,
315 .uid = NO_CHANGE_64, 451 .uid = NO_CHANGE_64,
@@ -319,7 +455,7 @@ int cifs_open(struct inode *inode, struct file *file)
319 .mtime = NO_CHANGE_64, 455 .mtime = NO_CHANGE_64,
320 .device = 0, 456 .device = 0,
321 }; 457 };
322 CIFSSMBUnixSetInfo(xid, pTcon, full_path, &args, 458 CIFSSMBUnixSetInfo(xid, tcon, full_path, &args,
323 cifs_sb->local_nls, 459 cifs_sb->local_nls,
324 cifs_sb->mnt_cifs_flags & 460 cifs_sb->mnt_cifs_flags &
325 CIFS_MOUNT_MAP_SPECIAL_CHR); 461 CIFS_MOUNT_MAP_SPECIAL_CHR);
@@ -349,7 +485,7 @@ static int cifs_reopen_file(struct file *file, bool can_flush)
349 int rc = -EACCES; 485 int rc = -EACCES;
350 int xid, oplock; 486 int xid, oplock;
351 struct cifs_sb_info *cifs_sb; 487 struct cifs_sb_info *cifs_sb;
352 struct cifsTconInfo *pTcon; 488 struct cifsTconInfo *tcon;
353 struct cifsFileInfo *pCifsFile; 489 struct cifsFileInfo *pCifsFile;
354 struct cifsInodeInfo *pCifsInode; 490 struct cifsInodeInfo *pCifsInode;
355 struct inode *inode; 491 struct inode *inode;
@@ -387,7 +523,7 @@ static int cifs_reopen_file(struct file *file, bool can_flush)
387 } 523 }
388 524
389 cifs_sb = CIFS_SB(inode->i_sb); 525 cifs_sb = CIFS_SB(inode->i_sb);
390 pTcon = cifs_sb->tcon; 526 tcon = cifs_sb->tcon;
391 527
392/* can not grab rename sem here because various ops, including 528/* can not grab rename sem here because various ops, including
393 those that already have the rename sem can end up causing writepage 529 those that already have the rename sem can end up causing writepage
@@ -404,20 +540,37 @@ reopen_error_exit:
404 540
405 cFYI(1, ("inode = 0x%p file flags 0x%x for %s", 541 cFYI(1, ("inode = 0x%p file flags 0x%x for %s",
406 inode, file->f_flags, full_path)); 542 inode, file->f_flags, full_path));
407 desiredAccess = cifs_convert_flags(file->f_flags);
408 543
409 if (oplockEnabled) 544 if (oplockEnabled)
410 oplock = REQ_OPLOCK; 545 oplock = REQ_OPLOCK;
411 else 546 else
412 oplock = 0; 547 oplock = 0;
413 548
549 if (tcon->unix_ext && (tcon->ses->capabilities & CAP_UNIX) &&
550 (CIFS_UNIX_POSIX_PATH_OPS_CAP &
551 le64_to_cpu(tcon->fsUnixInfo.Capability))) {
552 int oflags = (int) cifs_posix_convert_flags(file->f_flags);
553 /* can not refresh inode info since size could be stale */
554 rc = cifs_posix_open(full_path, NULL, inode->i_sb,
555 cifs_sb->mnt_file_mode /* ignored */,
556 oflags, &oplock, &netfid, xid);
557 if (rc == 0) {
558 cFYI(1, ("posix reopen succeeded"));
559 goto reopen_success;
560 }
561 /* fallthrough to retry open the old way on errors, especially
562 in the reconnect path it is important to retry hard */
563 }
564
565 desiredAccess = cifs_convert_flags(file->f_flags);
566
414 /* Can not refresh inode by passing in file_info buf to be returned 567 /* Can not refresh inode by passing in file_info buf to be returned
415 by SMBOpen and then calling get_inode_info with returned buf 568 by SMBOpen and then calling get_inode_info with returned buf
416 since file might have write behind data that needs to be flushed 569 since file might have write behind data that needs to be flushed
417 and server version of file size can be stale. If we knew for sure 570 and server version of file size can be stale. If we knew for sure
418 that inode was not dirty locally we could do this */ 571 that inode was not dirty locally we could do this */
419 572
420 rc = CIFSSMBOpen(xid, pTcon, full_path, disposition, desiredAccess, 573 rc = CIFSSMBOpen(xid, tcon, full_path, disposition, desiredAccess,
421 CREATE_NOT_DIR, &netfid, &oplock, NULL, 574 CREATE_NOT_DIR, &netfid, &oplock, NULL,
422 cifs_sb->local_nls, cifs_sb->mnt_cifs_flags & 575 cifs_sb->local_nls, cifs_sb->mnt_cifs_flags &
423 CIFS_MOUNT_MAP_SPECIAL_CHR); 576 CIFS_MOUNT_MAP_SPECIAL_CHR);
@@ -426,6 +579,7 @@ reopen_error_exit:
426 cFYI(1, ("cifs_open returned 0x%x", rc)); 579 cFYI(1, ("cifs_open returned 0x%x", rc));
427 cFYI(1, ("oplock: %d", oplock)); 580 cFYI(1, ("oplock: %d", oplock));
428 } else { 581 } else {
582reopen_success:
429 pCifsFile->netfid = netfid; 583 pCifsFile->netfid = netfid;
430 pCifsFile->invalidHandle = false; 584 pCifsFile->invalidHandle = false;
431 up(&pCifsFile->fh_sem); 585 up(&pCifsFile->fh_sem);
@@ -439,7 +593,7 @@ reopen_error_exit:
439 go to server to get inode info */ 593 go to server to get inode info */
440 pCifsInode->clientCanCacheAll = false; 594 pCifsInode->clientCanCacheAll = false;
441 pCifsInode->clientCanCacheRead = false; 595 pCifsInode->clientCanCacheRead = false;
442 if (pTcon->unix_ext) 596 if (tcon->unix_ext)
443 rc = cifs_get_inode_info_unix(&inode, 597 rc = cifs_get_inode_info_unix(&inode,
444 full_path, inode->i_sb, xid); 598 full_path, inode->i_sb, xid);
445 else 599 else
@@ -467,7 +621,6 @@ reopen_error_exit:
467 cifs_relock_file(pCifsFile); 621 cifs_relock_file(pCifsFile);
468 } 622 }
469 } 623 }
470
471 kfree(full_path); 624 kfree(full_path);
472 FreeXid(xid); 625 FreeXid(xid);
473 return rc; 626 return rc;
@@ -1523,6 +1676,9 @@ int cifs_fsync(struct file *file, struct dentry *dentry, int datasync)
1523{ 1676{
1524 int xid; 1677 int xid;
1525 int rc = 0; 1678 int rc = 0;
1679 struct cifsTconInfo *tcon;
1680 struct cifsFileInfo *smbfile =
1681 (struct cifsFileInfo *)file->private_data;
1526 struct inode *inode = file->f_path.dentry->d_inode; 1682 struct inode *inode = file->f_path.dentry->d_inode;
1527 1683
1528 xid = GetXid(); 1684 xid = GetXid();
@@ -1534,7 +1690,12 @@ int cifs_fsync(struct file *file, struct dentry *dentry, int datasync)
1534 if (rc == 0) { 1690 if (rc == 0) {
1535 rc = CIFS_I(inode)->write_behind_rc; 1691 rc = CIFS_I(inode)->write_behind_rc;
1536 CIFS_I(inode)->write_behind_rc = 0; 1692 CIFS_I(inode)->write_behind_rc = 0;
1693 tcon = CIFS_SB(inode->i_sb)->tcon;
1694 if (!rc && tcon && smbfile &&
1695 !(CIFS_SB(inode->i_sb)->mnt_cifs_flags & CIFS_MOUNT_NOSSYNC))
1696 rc = CIFSSMBFlush(xid, tcon, smbfile->netfid);
1537 } 1697 }
1698
1538 FreeXid(xid); 1699 FreeXid(xid);
1539 return rc; 1700 return rc;
1540} 1701}