diff options
Diffstat (limited to 'fs/cifs')
-rw-r--r-- | fs/cifs/CHANGES | 15 | ||||
-rw-r--r-- | fs/cifs/README | 2 | ||||
-rw-r--r-- | fs/cifs/cifs_fs_sb.h | 2 | ||||
-rw-r--r-- | fs/cifs/cifsencrypt.c | 3 | ||||
-rw-r--r-- | fs/cifs/cifsfs.c | 8 | ||||
-rw-r--r-- | fs/cifs/cifsfs.h | 2 | ||||
-rw-r--r-- | fs/cifs/cifsglob.h | 18 | ||||
-rw-r--r-- | fs/cifs/cifspdu.h | 2 | ||||
-rw-r--r-- | fs/cifs/cifsproto.h | 4 | ||||
-rw-r--r-- | fs/cifs/cifssmb.c | 28 | ||||
-rw-r--r-- | fs/cifs/connect.c | 79 | ||||
-rw-r--r-- | fs/cifs/dir.c | 27 | ||||
-rw-r--r-- | fs/cifs/file.c | 98 | ||||
-rw-r--r-- | fs/cifs/netmisc.c | 1 | ||||
-rw-r--r-- | fs/cifs/readdir.c | 13 | ||||
-rw-r--r-- | fs/cifs/sess.c | 2 | ||||
-rw-r--r-- | fs/cifs/smberr.h | 1 | ||||
-rw-r--r-- | fs/cifs/transport.c | 618 | ||||
-rw-r--r-- | fs/cifs/xattr.c | 8 |
19 files changed, 656 insertions, 275 deletions
diff --git a/fs/cifs/CHANGES b/fs/cifs/CHANGES index a61d17ed1827..1eb9a2ec0a3b 100644 --- a/fs/cifs/CHANGES +++ b/fs/cifs/CHANGES | |||
@@ -1,3 +1,18 @@ | |||
1 | Version 1.46 | ||
2 | ------------ | ||
3 | Support deep tree mounts. Better support OS/2, Win9x (DOS) time stamps. | ||
4 | |||
5 | Version 1.45 | ||
6 | ------------ | ||
7 | Do not time out lockw calls when using posix extensions. Do not | ||
8 | time out requests if server still responding reasonably fast | ||
9 | on requests on other threads. Improve POSIX locking emulation, | ||
10 | (lock cancel now works, and unlock of merged range works even | ||
11 | to Windows servers now). Fix oops on mount to lanman servers | ||
12 | (win9x, os/2 etc.) when null password. Do not send listxattr | ||
13 | (SMB to query all EAs) if nouser_xattr specified. Fix SE Linux | ||
14 | problem (instantiate inodes/dentries in right order for readdir). | ||
15 | |||
1 | Version 1.44 | 16 | Version 1.44 |
2 | ------------ | 17 | ------------ |
3 | Rewritten sessionsetup support, including support for legacy SMB | 18 | Rewritten sessionsetup support, including support for legacy SMB |
diff --git a/fs/cifs/README b/fs/cifs/README index 7986d0d97ace..5f0e1bd64fee 100644 --- a/fs/cifs/README +++ b/fs/cifs/README | |||
@@ -408,7 +408,7 @@ A partial list of the supported mount options follows: | |||
408 | user_xattr Allow getting and setting user xattrs as OS/2 EAs (extended | 408 | user_xattr Allow getting and setting user xattrs as OS/2 EAs (extended |
409 | attributes) to the server (default) e.g. via setfattr | 409 | attributes) to the server (default) e.g. via setfattr |
410 | and getfattr utilities. | 410 | and getfattr utilities. |
411 | nouser_xattr Do not allow getfattr/setfattr to get/set xattrs | 411 | nouser_xattr Do not allow getfattr/setfattr to get/set/list xattrs |
412 | mapchars Translate six of the seven reserved characters (not backslash) | 412 | mapchars Translate six of the seven reserved characters (not backslash) |
413 | *?<>|: | 413 | *?<>|: |
414 | to the remap range (above 0xF000), which also | 414 | to the remap range (above 0xF000), which also |
diff --git a/fs/cifs/cifs_fs_sb.h b/fs/cifs/cifs_fs_sb.h index ad58eb0c4d6d..fd1e52ebcee6 100644 --- a/fs/cifs/cifs_fs_sb.h +++ b/fs/cifs/cifs_fs_sb.h | |||
@@ -40,5 +40,7 @@ struct cifs_sb_info { | |||
40 | mode_t mnt_file_mode; | 40 | mode_t mnt_file_mode; |
41 | mode_t mnt_dir_mode; | 41 | mode_t mnt_dir_mode; |
42 | int mnt_cifs_flags; | 42 | int mnt_cifs_flags; |
43 | int prepathlen; | ||
44 | char * prepath; | ||
43 | }; | 45 | }; |
44 | #endif /* _CIFS_FS_SB_H */ | 46 | #endif /* _CIFS_FS_SB_H */ |
diff --git a/fs/cifs/cifsencrypt.c b/fs/cifs/cifsencrypt.c index a89efaf78a26..4bc250b2d9fc 100644 --- a/fs/cifs/cifsencrypt.c +++ b/fs/cifs/cifsencrypt.c | |||
@@ -277,7 +277,8 @@ void calc_lanman_hash(struct cifsSesInfo * ses, char * lnm_session_key) | |||
277 | return; | 277 | return; |
278 | 278 | ||
279 | memset(password_with_pad, 0, CIFS_ENCPWD_SIZE); | 279 | memset(password_with_pad, 0, CIFS_ENCPWD_SIZE); |
280 | strncpy(password_with_pad, ses->password, CIFS_ENCPWD_SIZE); | 280 | if(ses->password) |
281 | strncpy(password_with_pad, ses->password, CIFS_ENCPWD_SIZE); | ||
281 | 282 | ||
282 | if((ses->server->secMode & SECMODE_PW_ENCRYPT) == 0) | 283 | if((ses->server->secMode & SECMODE_PW_ENCRYPT) == 0) |
283 | if(extended_security & CIFSSEC_MAY_PLNTXT) { | 284 | if(extended_security & CIFSSEC_MAY_PLNTXT) { |
diff --git a/fs/cifs/cifsfs.c b/fs/cifs/cifsfs.c index c28ede599946..c3ef1c0d0e68 100644 --- a/fs/cifs/cifsfs.c +++ b/fs/cifs/cifsfs.c | |||
@@ -189,7 +189,6 @@ cifs_statfs(struct dentry *dentry, struct kstatfs *buf) | |||
189 | buf->f_files = 0; /* undefined */ | 189 | buf->f_files = 0; /* undefined */ |
190 | buf->f_ffree = 0; /* unlimited */ | 190 | buf->f_ffree = 0; /* unlimited */ |
191 | 191 | ||
192 | #ifdef CONFIG_CIFS_EXPERIMENTAL | ||
193 | /* BB we could add a second check for a QFS Unix capability bit */ | 192 | /* BB we could add a second check for a QFS Unix capability bit */ |
194 | /* BB FIXME check CIFS_POSIX_EXTENSIONS Unix cap first FIXME BB */ | 193 | /* BB FIXME check CIFS_POSIX_EXTENSIONS Unix cap first FIXME BB */ |
195 | if ((pTcon->ses->capabilities & CAP_UNIX) && (CIFS_POSIX_EXTENSIONS & | 194 | if ((pTcon->ses->capabilities & CAP_UNIX) && (CIFS_POSIX_EXTENSIONS & |
@@ -199,7 +198,6 @@ cifs_statfs(struct dentry *dentry, struct kstatfs *buf) | |||
199 | /* Only need to call the old QFSInfo if failed | 198 | /* Only need to call the old QFSInfo if failed |
200 | on newer one */ | 199 | on newer one */ |
201 | if(rc) | 200 | if(rc) |
202 | #endif /* CIFS_EXPERIMENTAL */ | ||
203 | rc = CIFSSMBQFSInfo(xid, pTcon, buf); | 201 | rc = CIFSSMBQFSInfo(xid, pTcon, buf); |
204 | 202 | ||
205 | /* Old Windows servers do not support level 103, retry with level | 203 | /* Old Windows servers do not support level 103, retry with level |
@@ -402,7 +400,6 @@ static struct quotactl_ops cifs_quotactl_ops = { | |||
402 | }; | 400 | }; |
403 | #endif | 401 | #endif |
404 | 402 | ||
405 | #ifdef CONFIG_CIFS_EXPERIMENTAL | ||
406 | static void cifs_umount_begin(struct vfsmount * vfsmnt, int flags) | 403 | static void cifs_umount_begin(struct vfsmount * vfsmnt, int flags) |
407 | { | 404 | { |
408 | struct cifs_sb_info *cifs_sb; | 405 | struct cifs_sb_info *cifs_sb; |
@@ -422,7 +419,7 @@ static void cifs_umount_begin(struct vfsmount * vfsmnt, int flags) | |||
422 | tcon->tidStatus = CifsExiting; | 419 | tcon->tidStatus = CifsExiting; |
423 | up(&tcon->tconSem); | 420 | up(&tcon->tconSem); |
424 | 421 | ||
425 | /* cancel_brl_requests(tcon); */ | 422 | /* cancel_brl_requests(tcon); */ /* BB mark all brl mids as exiting */ |
426 | /* cancel_notify_requests(tcon); */ | 423 | /* cancel_notify_requests(tcon); */ |
427 | if(tcon->ses && tcon->ses->server) | 424 | if(tcon->ses && tcon->ses->server) |
428 | { | 425 | { |
@@ -438,7 +435,6 @@ static void cifs_umount_begin(struct vfsmount * vfsmnt, int flags) | |||
438 | 435 | ||
439 | return; | 436 | return; |
440 | } | 437 | } |
441 | #endif | ||
442 | 438 | ||
443 | static int cifs_remount(struct super_block *sb, int *flags, char *data) | 439 | static int cifs_remount(struct super_block *sb, int *flags, char *data) |
444 | { | 440 | { |
@@ -457,9 +453,7 @@ struct super_operations cifs_super_ops = { | |||
457 | unless later we add lazy close of inodes or unless the kernel forgets to call | 453 | unless later we add lazy close of inodes or unless the kernel forgets to call |
458 | us with the same number of releases (closes) as opens */ | 454 | us with the same number of releases (closes) as opens */ |
459 | .show_options = cifs_show_options, | 455 | .show_options = cifs_show_options, |
460 | #ifdef CONFIG_CIFS_EXPERIMENTAL | ||
461 | .umount_begin = cifs_umount_begin, | 456 | .umount_begin = cifs_umount_begin, |
462 | #endif | ||
463 | .remount_fs = cifs_remount, | 457 | .remount_fs = cifs_remount, |
464 | }; | 458 | }; |
465 | 459 | ||
diff --git a/fs/cifs/cifsfs.h b/fs/cifs/cifsfs.h index 8f75c6f24701..bea875d9a46a 100644 --- a/fs/cifs/cifsfs.h +++ b/fs/cifs/cifsfs.h | |||
@@ -100,5 +100,5 @@ extern ssize_t cifs_getxattr(struct dentry *, const char *, void *, size_t); | |||
100 | extern ssize_t cifs_listxattr(struct dentry *, char *, size_t); | 100 | extern ssize_t cifs_listxattr(struct dentry *, char *, size_t); |
101 | extern int cifs_ioctl (struct inode * inode, struct file * filep, | 101 | extern int cifs_ioctl (struct inode * inode, struct file * filep, |
102 | unsigned int command, unsigned long arg); | 102 | unsigned int command, unsigned long arg); |
103 | #define CIFS_VERSION "1.44" | 103 | #define CIFS_VERSION "1.46" |
104 | #endif /* _CIFSFS_H */ | 104 | #endif /* _CIFSFS_H */ |
diff --git a/fs/cifs/cifsglob.h b/fs/cifs/cifsglob.h index 6d7cf5f3bc0b..b24006c47df1 100644 --- a/fs/cifs/cifsglob.h +++ b/fs/cifs/cifsglob.h | |||
@@ -3,6 +3,7 @@ | |||
3 | * | 3 | * |
4 | * Copyright (C) International Business Machines Corp., 2002,2006 | 4 | * Copyright (C) International Business Machines Corp., 2002,2006 |
5 | * Author(s): Steve French (sfrench@us.ibm.com) | 5 | * Author(s): Steve French (sfrench@us.ibm.com) |
6 | * Jeremy Allison (jra@samba.org) | ||
6 | * | 7 | * |
7 | * This library is free software; you can redistribute it and/or modify | 8 | * This library is free software; you can redistribute it and/or modify |
8 | * it under the terms of the GNU Lesser General Public License as published | 9 | * it under the terms of the GNU Lesser General Public License as published |
@@ -158,7 +159,8 @@ struct TCP_Server_Info { | |||
158 | /* 16th byte of RFC1001 workstation name is always null */ | 159 | /* 16th byte of RFC1001 workstation name is always null */ |
159 | char workstation_RFC1001_name[SERVER_NAME_LEN_WITH_NULL]; | 160 | char workstation_RFC1001_name[SERVER_NAME_LEN_WITH_NULL]; |
160 | __u32 sequence_number; /* needed for CIFS PDU signature */ | 161 | __u32 sequence_number; /* needed for CIFS PDU signature */ |
161 | char mac_signing_key[CIFS_SESS_KEY_SIZE + 16]; | 162 | char mac_signing_key[CIFS_SESS_KEY_SIZE + 16]; |
163 | unsigned long lstrp; /* when we got last response from this server */ | ||
162 | }; | 164 | }; |
163 | 165 | ||
164 | /* | 166 | /* |
@@ -266,14 +268,14 @@ struct cifsTconInfo { | |||
266 | }; | 268 | }; |
267 | 269 | ||
268 | /* | 270 | /* |
269 | * This info hangs off the cifsFileInfo structure. This is used to track | 271 | * This info hangs off the cifsFileInfo structure, pointed to by llist. |
270 | * byte stream locks on the file | 272 | * This is used to track byte stream locks on the file |
271 | */ | 273 | */ |
272 | struct cifsLockInfo { | 274 | struct cifsLockInfo { |
273 | struct cifsLockInfo *next; | 275 | struct list_head llist; /* pointer to next cifsLockInfo */ |
274 | int start; | 276 | __u64 offset; |
275 | int length; | 277 | __u64 length; |
276 | int type; | 278 | __u8 type; |
277 | }; | 279 | }; |
278 | 280 | ||
279 | /* | 281 | /* |
@@ -304,6 +306,8 @@ struct cifsFileInfo { | |||
304 | /* lock scope id (0 if none) */ | 306 | /* lock scope id (0 if none) */ |
305 | struct file * pfile; /* needed for writepage */ | 307 | struct file * pfile; /* needed for writepage */ |
306 | struct inode * pInode; /* needed for oplock break */ | 308 | struct inode * pInode; /* needed for oplock break */ |
309 | struct semaphore lock_sem; | ||
310 | struct list_head llist; /* list of byte range locks we have. */ | ||
307 | unsigned closePend:1; /* file is marked to close */ | 311 | unsigned closePend:1; /* file is marked to close */ |
308 | unsigned invalidHandle:1; /* file closed via session abend */ | 312 | unsigned invalidHandle:1; /* file closed via session abend */ |
309 | atomic_t wrtPending; /* handle in use - defer close */ | 313 | atomic_t wrtPending; /* handle in use - defer close */ |
diff --git a/fs/cifs/cifspdu.h b/fs/cifs/cifspdu.h index 86239023545b..81df2bf8e75a 100644 --- a/fs/cifs/cifspdu.h +++ b/fs/cifs/cifspdu.h | |||
@@ -1344,6 +1344,7 @@ struct smb_t2_rsp { | |||
1344 | #define SMB_QUERY_ATTR_FLAGS 0x206 /* append,immutable etc. */ | 1344 | #define SMB_QUERY_ATTR_FLAGS 0x206 /* append,immutable etc. */ |
1345 | #define SMB_QUERY_POSIX_PERMISSION 0x207 | 1345 | #define SMB_QUERY_POSIX_PERMISSION 0x207 |
1346 | #define SMB_QUERY_POSIX_LOCK 0x208 | 1346 | #define SMB_QUERY_POSIX_LOCK 0x208 |
1347 | /* #define SMB_POSIX_OPEN 0x209 */ | ||
1347 | #define SMB_QUERY_FILE_INTERNAL_INFO 0x3ee | 1348 | #define SMB_QUERY_FILE_INTERNAL_INFO 0x3ee |
1348 | #define SMB_QUERY_FILE_ACCESS_INFO 0x3f0 | 1349 | #define SMB_QUERY_FILE_ACCESS_INFO 0x3f0 |
1349 | #define SMB_QUERY_FILE_NAME_INFO2 0x3f1 /* 0x30 bytes */ | 1350 | #define SMB_QUERY_FILE_NAME_INFO2 0x3f1 /* 0x30 bytes */ |
@@ -1363,6 +1364,7 @@ struct smb_t2_rsp { | |||
1363 | #define SMB_SET_XATTR 0x205 | 1364 | #define SMB_SET_XATTR 0x205 |
1364 | #define SMB_SET_ATTR_FLAGS 0x206 /* append, immutable etc. */ | 1365 | #define SMB_SET_ATTR_FLAGS 0x206 /* append, immutable etc. */ |
1365 | #define SMB_SET_POSIX_LOCK 0x208 | 1366 | #define SMB_SET_POSIX_LOCK 0x208 |
1367 | #define SMB_POSIX_OPEN 0x209 | ||
1366 | #define SMB_SET_FILE_BASIC_INFO2 0x3ec | 1368 | #define SMB_SET_FILE_BASIC_INFO2 0x3ec |
1367 | #define SMB_SET_FILE_RENAME_INFORMATION 0x3f2 /* BB check if qpathinfo level too */ | 1369 | #define SMB_SET_FILE_RENAME_INFORMATION 0x3f2 /* BB check if qpathinfo level too */ |
1368 | #define SMB_FILE_ALL_INFO2 0x3fa | 1370 | #define SMB_FILE_ALL_INFO2 0x3fa |
diff --git a/fs/cifs/cifsproto.h b/fs/cifs/cifsproto.h index a5ddc62d6fe6..b35c55c3c8bb 100644 --- a/fs/cifs/cifsproto.h +++ b/fs/cifs/cifsproto.h | |||
@@ -50,6 +50,10 @@ extern int SendReceive(const unsigned int /* xid */ , struct cifsSesInfo *, | |||
50 | extern int SendReceive2(const unsigned int /* xid */ , struct cifsSesInfo *, | 50 | extern int SendReceive2(const unsigned int /* xid */ , struct cifsSesInfo *, |
51 | struct kvec *, int /* nvec to send */, | 51 | struct kvec *, int /* nvec to send */, |
52 | int * /* type of buf returned */ , const int long_op); | 52 | int * /* type of buf returned */ , const int long_op); |
53 | extern int SendReceiveBlockingLock(const unsigned int /* xid */ , struct cifsTconInfo *, | ||
54 | struct smb_hdr * /* input */ , | ||
55 | struct smb_hdr * /* out */ , | ||
56 | int * /* bytes returned */); | ||
53 | extern int checkSMBhdr(struct smb_hdr *smb, __u16 mid); | 57 | extern int checkSMBhdr(struct smb_hdr *smb, __u16 mid); |
54 | extern int checkSMB(struct smb_hdr *smb, __u16 mid, int length); | 58 | extern int checkSMB(struct smb_hdr *smb, __u16 mid, int length); |
55 | extern int is_valid_oplock_break(struct smb_hdr *smb, struct TCP_Server_Info *); | 59 | extern int is_valid_oplock_break(struct smb_hdr *smb, struct TCP_Server_Info *); |
diff --git a/fs/cifs/cifssmb.c b/fs/cifs/cifssmb.c index 19678c575dfc..075d8fb3d376 100644 --- a/fs/cifs/cifssmb.c +++ b/fs/cifs/cifssmb.c | |||
@@ -477,7 +477,7 @@ CIFSSMBNegotiate(unsigned int xid, struct cifsSesInfo *ses) | |||
477 | /* BB get server time for time conversions and add | 477 | /* BB get server time for time conversions and add |
478 | code to use it and timezone since this is not UTC */ | 478 | code to use it and timezone since this is not UTC */ |
479 | 479 | ||
480 | if (rsp->EncryptionKeyLength == CIFS_CRYPTO_KEY_SIZE) { | 480 | if (rsp->EncryptionKeyLength == cpu_to_le16(CIFS_CRYPTO_KEY_SIZE)) { |
481 | memcpy(server->cryptKey, rsp->EncryptionKey, | 481 | memcpy(server->cryptKey, rsp->EncryptionKey, |
482 | CIFS_CRYPTO_KEY_SIZE); | 482 | CIFS_CRYPTO_KEY_SIZE); |
483 | } else if (server->secMode & SECMODE_PW_ENCRYPT) { | 483 | } else if (server->secMode & SECMODE_PW_ENCRYPT) { |
@@ -1460,8 +1460,13 @@ CIFSSMBLock(const int xid, struct cifsTconInfo *tcon, | |||
1460 | pSMB->hdr.smb_buf_length += count; | 1460 | pSMB->hdr.smb_buf_length += count; |
1461 | pSMB->ByteCount = cpu_to_le16(count); | 1461 | pSMB->ByteCount = cpu_to_le16(count); |
1462 | 1462 | ||
1463 | rc = SendReceive(xid, tcon->ses, (struct smb_hdr *) pSMB, | 1463 | if (waitFlag) { |
1464 | rc = SendReceiveBlockingLock(xid, tcon, (struct smb_hdr *) pSMB, | ||
1465 | (struct smb_hdr *) pSMBr, &bytes_returned); | ||
1466 | } else { | ||
1467 | rc = SendReceive(xid, tcon->ses, (struct smb_hdr *) pSMB, | ||
1464 | (struct smb_hdr *) pSMBr, &bytes_returned, timeout); | 1468 | (struct smb_hdr *) pSMBr, &bytes_returned, timeout); |
1469 | } | ||
1465 | cifs_stats_inc(&tcon->num_locks); | 1470 | cifs_stats_inc(&tcon->num_locks); |
1466 | if (rc) { | 1471 | if (rc) { |
1467 | cFYI(1, ("Send error in Lock = %d", rc)); | 1472 | cFYI(1, ("Send error in Lock = %d", rc)); |
@@ -1484,6 +1489,7 @@ CIFSSMBPosixLock(const int xid, struct cifsTconInfo *tcon, | |||
1484 | char *data_offset; | 1489 | char *data_offset; |
1485 | struct cifs_posix_lock *parm_data; | 1490 | struct cifs_posix_lock *parm_data; |
1486 | int rc = 0; | 1491 | int rc = 0; |
1492 | int timeout = 0; | ||
1487 | int bytes_returned = 0; | 1493 | int bytes_returned = 0; |
1488 | __u16 params, param_offset, offset, byte_count, count; | 1494 | __u16 params, param_offset, offset, byte_count, count; |
1489 | 1495 | ||
@@ -1503,7 +1509,6 @@ CIFSSMBPosixLock(const int xid, struct cifsTconInfo *tcon, | |||
1503 | pSMB->MaxSetupCount = 0; | 1509 | pSMB->MaxSetupCount = 0; |
1504 | pSMB->Reserved = 0; | 1510 | pSMB->Reserved = 0; |
1505 | pSMB->Flags = 0; | 1511 | pSMB->Flags = 0; |
1506 | pSMB->Timeout = 0; | ||
1507 | pSMB->Reserved2 = 0; | 1512 | pSMB->Reserved2 = 0; |
1508 | param_offset = offsetof(struct smb_com_transaction2_sfi_req, Fid) - 4; | 1513 | param_offset = offsetof(struct smb_com_transaction2_sfi_req, Fid) - 4; |
1509 | offset = param_offset + params; | 1514 | offset = param_offset + params; |
@@ -1529,8 +1534,13 @@ CIFSSMBPosixLock(const int xid, struct cifsTconInfo *tcon, | |||
1529 | (((char *) &pSMB->hdr.Protocol) + offset); | 1534 | (((char *) &pSMB->hdr.Protocol) + offset); |
1530 | 1535 | ||
1531 | parm_data->lock_type = cpu_to_le16(lock_type); | 1536 | parm_data->lock_type = cpu_to_le16(lock_type); |
1532 | if(waitFlag) | 1537 | if(waitFlag) { |
1538 | timeout = 3; /* blocking operation, no timeout */ | ||
1533 | parm_data->lock_flags = cpu_to_le16(1); | 1539 | parm_data->lock_flags = cpu_to_le16(1); |
1540 | pSMB->Timeout = cpu_to_le32(-1); | ||
1541 | } else | ||
1542 | pSMB->Timeout = 0; | ||
1543 | |||
1534 | parm_data->pid = cpu_to_le32(current->tgid); | 1544 | parm_data->pid = cpu_to_le32(current->tgid); |
1535 | parm_data->start = cpu_to_le64(pLockData->fl_start); | 1545 | parm_data->start = cpu_to_le64(pLockData->fl_start); |
1536 | parm_data->length = cpu_to_le64(len); /* normalize negative numbers */ | 1546 | parm_data->length = cpu_to_le64(len); /* normalize negative numbers */ |
@@ -1541,8 +1551,14 @@ CIFSSMBPosixLock(const int xid, struct cifsTconInfo *tcon, | |||
1541 | pSMB->Reserved4 = 0; | 1551 | pSMB->Reserved4 = 0; |
1542 | pSMB->hdr.smb_buf_length += byte_count; | 1552 | pSMB->hdr.smb_buf_length += byte_count; |
1543 | pSMB->ByteCount = cpu_to_le16(byte_count); | 1553 | pSMB->ByteCount = cpu_to_le16(byte_count); |
1544 | rc = SendReceive(xid, tcon->ses, (struct smb_hdr *) pSMB, | 1554 | if (waitFlag) { |
1545 | (struct smb_hdr *) pSMBr, &bytes_returned, 0); | 1555 | rc = SendReceiveBlockingLock(xid, tcon, (struct smb_hdr *) pSMB, |
1556 | (struct smb_hdr *) pSMBr, &bytes_returned); | ||
1557 | } else { | ||
1558 | rc = SendReceive(xid, tcon->ses, (struct smb_hdr *) pSMB, | ||
1559 | (struct smb_hdr *) pSMBr, &bytes_returned, timeout); | ||
1560 | } | ||
1561 | |||
1546 | if (rc) { | 1562 | if (rc) { |
1547 | cFYI(1, ("Send error in Posix Lock = %d", rc)); | 1563 | cFYI(1, ("Send error in Posix Lock = %d", rc)); |
1548 | } else if (get_flag) { | 1564 | } else if (get_flag) { |
diff --git a/fs/cifs/connect.c b/fs/cifs/connect.c index 876eb9ef85fe..0e9ba0b9d71e 100644 --- a/fs/cifs/connect.c +++ b/fs/cifs/connect.c | |||
@@ -89,6 +89,7 @@ struct smb_vol { | |||
89 | unsigned int wsize; | 89 | unsigned int wsize; |
90 | unsigned int sockopt; | 90 | unsigned int sockopt; |
91 | unsigned short int port; | 91 | unsigned short int port; |
92 | char * prepath; | ||
92 | }; | 93 | }; |
93 | 94 | ||
94 | static int ipv4_connect(struct sockaddr_in *psin_server, | 95 | static int ipv4_connect(struct sockaddr_in *psin_server, |
@@ -182,6 +183,7 @@ cifs_reconnect(struct TCP_Server_Info *server) | |||
182 | 183 | ||
183 | while ((server->tcpStatus != CifsExiting) && (server->tcpStatus != CifsGood)) | 184 | while ((server->tcpStatus != CifsExiting) && (server->tcpStatus != CifsGood)) |
184 | { | 185 | { |
186 | try_to_freeze(); | ||
185 | if(server->protocolType == IPV6) { | 187 | if(server->protocolType == IPV6) { |
186 | rc = ipv6_connect(&server->addr.sockAddr6,&server->ssocket); | 188 | rc = ipv6_connect(&server->addr.sockAddr6,&server->ssocket); |
187 | } else { | 189 | } else { |
@@ -612,6 +614,10 @@ multi_t2_fnd: | |||
612 | #ifdef CONFIG_CIFS_STATS2 | 614 | #ifdef CONFIG_CIFS_STATS2 |
613 | mid_entry->when_received = jiffies; | 615 | mid_entry->when_received = jiffies; |
614 | #endif | 616 | #endif |
617 | /* so we do not time out requests to server | ||
618 | which is still responding (since server could | ||
619 | be busy but not dead) */ | ||
620 | server->lstrp = jiffies; | ||
615 | break; | 621 | break; |
616 | } | 622 | } |
617 | } | 623 | } |
@@ -988,6 +994,28 @@ cifs_parse_mount_options(char *options, const char *devname,struct smb_vol *vol) | |||
988 | printk(KERN_WARNING "CIFS: domain name too long\n"); | 994 | printk(KERN_WARNING "CIFS: domain name too long\n"); |
989 | return 1; | 995 | return 1; |
990 | } | 996 | } |
997 | } else if (strnicmp(data, "prefixpath", 10) == 0) { | ||
998 | if (!value || !*value) { | ||
999 | printk(KERN_WARNING | ||
1000 | "CIFS: invalid path prefix\n"); | ||
1001 | return 1; /* needs_arg; */ | ||
1002 | } | ||
1003 | if ((temp_len = strnlen(value, 1024)) < 1024) { | ||
1004 | if(value[0] != '/') | ||
1005 | temp_len++; /* missing leading slash */ | ||
1006 | vol->prepath = kmalloc(temp_len+1,GFP_KERNEL); | ||
1007 | if(vol->prepath == NULL) | ||
1008 | return 1; | ||
1009 | if(value[0] != '/') { | ||
1010 | vol->prepath[0] = '/'; | ||
1011 | strcpy(vol->prepath+1,value); | ||
1012 | } else | ||
1013 | strcpy(vol->prepath,value); | ||
1014 | cFYI(1,("prefix path %s",vol->prepath)); | ||
1015 | } else { | ||
1016 | printk(KERN_WARNING "CIFS: prefix too long\n"); | ||
1017 | return 1; | ||
1018 | } | ||
991 | } else if (strnicmp(data, "iocharset", 9) == 0) { | 1019 | } else if (strnicmp(data, "iocharset", 9) == 0) { |
992 | if (!value || !*value) { | 1020 | if (!value || !*value) { |
993 | printk(KERN_WARNING "CIFS: invalid iocharset specified\n"); | 1021 | printk(KERN_WARNING "CIFS: invalid iocharset specified\n"); |
@@ -1266,33 +1294,35 @@ find_unc(__be32 new_target_ip_addr, char *uncName, char *userName) | |||
1266 | 1294 | ||
1267 | read_lock(&GlobalSMBSeslock); | 1295 | read_lock(&GlobalSMBSeslock); |
1268 | list_for_each(tmp, &GlobalTreeConnectionList) { | 1296 | list_for_each(tmp, &GlobalTreeConnectionList) { |
1269 | cFYI(1, ("Next tcon - ")); | 1297 | cFYI(1, ("Next tcon")); |
1270 | tcon = list_entry(tmp, struct cifsTconInfo, cifsConnectionList); | 1298 | tcon = list_entry(tmp, struct cifsTconInfo, cifsConnectionList); |
1271 | if (tcon->ses) { | 1299 | if (tcon->ses) { |
1272 | if (tcon->ses->server) { | 1300 | if (tcon->ses->server) { |
1273 | cFYI(1, | 1301 | cFYI(1, |
1274 | (" old ip addr: %x == new ip %x ?", | 1302 | ("old ip addr: %x == new ip %x ?", |
1275 | tcon->ses->server->addr.sockAddr.sin_addr. | 1303 | tcon->ses->server->addr.sockAddr.sin_addr. |
1276 | s_addr, new_target_ip_addr)); | 1304 | s_addr, new_target_ip_addr)); |
1277 | if (tcon->ses->server->addr.sockAddr.sin_addr. | 1305 | if (tcon->ses->server->addr.sockAddr.sin_addr. |
1278 | s_addr == new_target_ip_addr) { | 1306 | s_addr == new_target_ip_addr) { |
1279 | /* BB lock tcon and server and tcp session and increment use count here? */ | 1307 | /* BB lock tcon, server and tcp session and increment use count here? */ |
1280 | /* found a match on the TCP session */ | 1308 | /* found a match on the TCP session */ |
1281 | /* BB check if reconnection needed */ | 1309 | /* BB check if reconnection needed */ |
1282 | cFYI(1,("Matched ip, old UNC: %s == new: %s ?", | 1310 | cFYI(1,("IP match, old UNC: %s new: %s", |
1283 | tcon->treeName, uncName)); | 1311 | tcon->treeName, uncName)); |
1284 | if (strncmp | 1312 | if (strncmp |
1285 | (tcon->treeName, uncName, | 1313 | (tcon->treeName, uncName, |
1286 | MAX_TREE_SIZE) == 0) { | 1314 | MAX_TREE_SIZE) == 0) { |
1287 | cFYI(1, | 1315 | cFYI(1, |
1288 | ("Matched UNC, old user: %s == new: %s ?", | 1316 | ("and old usr: %s new: %s", |
1289 | tcon->treeName, uncName)); | 1317 | tcon->treeName, uncName)); |
1290 | if (strncmp | 1318 | if (strncmp |
1291 | (tcon->ses->userName, | 1319 | (tcon->ses->userName, |
1292 | userName, | 1320 | userName, |
1293 | MAX_USERNAME_SIZE) == 0) { | 1321 | MAX_USERNAME_SIZE) == 0) { |
1294 | read_unlock(&GlobalSMBSeslock); | 1322 | read_unlock(&GlobalSMBSeslock); |
1295 | return tcon;/* also matched user (smb session)*/ | 1323 | /* matched smb session |
1324 | (user name */ | ||
1325 | return tcon; | ||
1296 | } | 1326 | } |
1297 | } | 1327 | } |
1298 | } | 1328 | } |
@@ -1598,6 +1628,7 @@ cifs_mount(struct super_block *sb, struct cifs_sb_info *cifs_sb, | |||
1598 | if (cifs_parse_mount_options(mount_data, devname, &volume_info)) { | 1628 | if (cifs_parse_mount_options(mount_data, devname, &volume_info)) { |
1599 | kfree(volume_info.UNC); | 1629 | kfree(volume_info.UNC); |
1600 | kfree(volume_info.password); | 1630 | kfree(volume_info.password); |
1631 | kfree(volume_info.prepath); | ||
1601 | FreeXid(xid); | 1632 | FreeXid(xid); |
1602 | return -EINVAL; | 1633 | return -EINVAL; |
1603 | } | 1634 | } |
@@ -1612,6 +1643,7 @@ cifs_mount(struct super_block *sb, struct cifs_sb_info *cifs_sb, | |||
1612 | locations such as env variables and files on disk */ | 1643 | locations such as env variables and files on disk */ |
1613 | kfree(volume_info.UNC); | 1644 | kfree(volume_info.UNC); |
1614 | kfree(volume_info.password); | 1645 | kfree(volume_info.password); |
1646 | kfree(volume_info.prepath); | ||
1615 | FreeXid(xid); | 1647 | FreeXid(xid); |
1616 | return -EINVAL; | 1648 | return -EINVAL; |
1617 | } | 1649 | } |
@@ -1632,6 +1664,7 @@ cifs_mount(struct super_block *sb, struct cifs_sb_info *cifs_sb, | |||
1632 | /* we failed translating address */ | 1664 | /* we failed translating address */ |
1633 | kfree(volume_info.UNC); | 1665 | kfree(volume_info.UNC); |
1634 | kfree(volume_info.password); | 1666 | kfree(volume_info.password); |
1667 | kfree(volume_info.prepath); | ||
1635 | FreeXid(xid); | 1668 | FreeXid(xid); |
1636 | return -EINVAL; | 1669 | return -EINVAL; |
1637 | } | 1670 | } |
@@ -1644,6 +1677,7 @@ cifs_mount(struct super_block *sb, struct cifs_sb_info *cifs_sb, | |||
1644 | cERROR(1,("Connecting to DFS root not implemented yet")); | 1677 | cERROR(1,("Connecting to DFS root not implemented yet")); |
1645 | kfree(volume_info.UNC); | 1678 | kfree(volume_info.UNC); |
1646 | kfree(volume_info.password); | 1679 | kfree(volume_info.password); |
1680 | kfree(volume_info.prepath); | ||
1647 | FreeXid(xid); | 1681 | FreeXid(xid); |
1648 | return -EINVAL; | 1682 | return -EINVAL; |
1649 | } else /* which servers DFS root would we conect to */ { | 1683 | } else /* which servers DFS root would we conect to */ { |
@@ -1651,6 +1685,7 @@ cifs_mount(struct super_block *sb, struct cifs_sb_info *cifs_sb, | |||
1651 | ("CIFS mount error: No UNC path (e.g. -o unc=//192.168.1.100/public) specified")); | 1685 | ("CIFS mount error: No UNC path (e.g. -o unc=//192.168.1.100/public) specified")); |
1652 | kfree(volume_info.UNC); | 1686 | kfree(volume_info.UNC); |
1653 | kfree(volume_info.password); | 1687 | kfree(volume_info.password); |
1688 | kfree(volume_info.prepath); | ||
1654 | FreeXid(xid); | 1689 | FreeXid(xid); |
1655 | return -EINVAL; | 1690 | return -EINVAL; |
1656 | } | 1691 | } |
@@ -1665,6 +1700,7 @@ cifs_mount(struct super_block *sb, struct cifs_sb_info *cifs_sb, | |||
1665 | cERROR(1,("CIFS mount error: iocharset %s not found",volume_info.iocharset)); | 1700 | cERROR(1,("CIFS mount error: iocharset %s not found",volume_info.iocharset)); |
1666 | kfree(volume_info.UNC); | 1701 | kfree(volume_info.UNC); |
1667 | kfree(volume_info.password); | 1702 | kfree(volume_info.password); |
1703 | kfree(volume_info.prepath); | ||
1668 | FreeXid(xid); | 1704 | FreeXid(xid); |
1669 | return -ELIBACC; | 1705 | return -ELIBACC; |
1670 | } | 1706 | } |
@@ -1681,6 +1717,7 @@ cifs_mount(struct super_block *sb, struct cifs_sb_info *cifs_sb, | |||
1681 | else { | 1717 | else { |
1682 | kfree(volume_info.UNC); | 1718 | kfree(volume_info.UNC); |
1683 | kfree(volume_info.password); | 1719 | kfree(volume_info.password); |
1720 | kfree(volume_info.prepath); | ||
1684 | FreeXid(xid); | 1721 | FreeXid(xid); |
1685 | return -EINVAL; | 1722 | return -EINVAL; |
1686 | } | 1723 | } |
@@ -1703,6 +1740,7 @@ cifs_mount(struct super_block *sb, struct cifs_sb_info *cifs_sb, | |||
1703 | sock_release(csocket); | 1740 | sock_release(csocket); |
1704 | kfree(volume_info.UNC); | 1741 | kfree(volume_info.UNC); |
1705 | kfree(volume_info.password); | 1742 | kfree(volume_info.password); |
1743 | kfree(volume_info.prepath); | ||
1706 | FreeXid(xid); | 1744 | FreeXid(xid); |
1707 | return rc; | 1745 | return rc; |
1708 | } | 1746 | } |
@@ -1713,6 +1751,7 @@ cifs_mount(struct super_block *sb, struct cifs_sb_info *cifs_sb, | |||
1713 | sock_release(csocket); | 1751 | sock_release(csocket); |
1714 | kfree(volume_info.UNC); | 1752 | kfree(volume_info.UNC); |
1715 | kfree(volume_info.password); | 1753 | kfree(volume_info.password); |
1754 | kfree(volume_info.prepath); | ||
1716 | FreeXid(xid); | 1755 | FreeXid(xid); |
1717 | return rc; | 1756 | return rc; |
1718 | } else { | 1757 | } else { |
@@ -1737,6 +1776,7 @@ cifs_mount(struct super_block *sb, struct cifs_sb_info *cifs_sb, | |||
1737 | sock_release(csocket); | 1776 | sock_release(csocket); |
1738 | kfree(volume_info.UNC); | 1777 | kfree(volume_info.UNC); |
1739 | kfree(volume_info.password); | 1778 | kfree(volume_info.password); |
1779 | kfree(volume_info.prepath); | ||
1740 | FreeXid(xid); | 1780 | FreeXid(xid); |
1741 | return rc; | 1781 | return rc; |
1742 | } | 1782 | } |
@@ -1824,6 +1864,14 @@ cifs_mount(struct super_block *sb, struct cifs_sb_info *cifs_sb, | |||
1824 | /* Windows ME may prefer this */ | 1864 | /* Windows ME may prefer this */ |
1825 | cFYI(1,("readsize set to minimum 2048")); | 1865 | cFYI(1,("readsize set to minimum 2048")); |
1826 | } | 1866 | } |
1867 | /* calculate prepath */ | ||
1868 | cifs_sb->prepath = volume_info.prepath; | ||
1869 | if(cifs_sb->prepath) { | ||
1870 | cifs_sb->prepathlen = strlen(cifs_sb->prepath); | ||
1871 | cifs_sb->prepath[0] = CIFS_DIR_SEP(cifs_sb); | ||
1872 | volume_info.prepath = NULL; | ||
1873 | } else | ||
1874 | cifs_sb->prepathlen = 0; | ||
1827 | cifs_sb->mnt_uid = volume_info.linux_uid; | 1875 | cifs_sb->mnt_uid = volume_info.linux_uid; |
1828 | cifs_sb->mnt_gid = volume_info.linux_gid; | 1876 | cifs_sb->mnt_gid = volume_info.linux_gid; |
1829 | cifs_sb->mnt_file_mode = volume_info.file_mode; | 1877 | cifs_sb->mnt_file_mode = volume_info.file_mode; |
@@ -1969,7 +2017,18 @@ cifs_mount(struct super_block *sb, struct cifs_sb_info *cifs_sb, | |||
1969 | } | 2017 | } |
1970 | 2018 | ||
1971 | cFYI(1,("Negotiate caps 0x%x",(int)cap)); | 2019 | cFYI(1,("Negotiate caps 0x%x",(int)cap)); |
1972 | 2020 | #ifdef CONFIG_CIFS_DEBUG2 | |
2021 | if(cap & CIFS_UNIX_FCNTL_CAP) | ||
2022 | cFYI(1,("FCNTL cap")); | ||
2023 | if(cap & CIFS_UNIX_EXTATTR_CAP) | ||
2024 | cFYI(1,("EXTATTR cap")); | ||
2025 | if(cap & CIFS_UNIX_POSIX_PATHNAMES_CAP) | ||
2026 | cFYI(1,("POSIX path cap")); | ||
2027 | if(cap & CIFS_UNIX_XATTR_CAP) | ||
2028 | cFYI(1,("XATTR cap")); | ||
2029 | if(cap & CIFS_UNIX_POSIX_ACL_CAP) | ||
2030 | cFYI(1,("POSIX ACL cap")); | ||
2031 | #endif /* CIFS_DEBUG2 */ | ||
1973 | if (CIFSSMBSetFSUnixInfo(xid, tcon, cap)) { | 2032 | if (CIFSSMBSetFSUnixInfo(xid, tcon, cap)) { |
1974 | cFYI(1,("setting capabilities failed")); | 2033 | cFYI(1,("setting capabilities failed")); |
1975 | } | 2034 | } |
@@ -1990,6 +2049,7 @@ cifs_mount(struct super_block *sb, struct cifs_sb_info *cifs_sb, | |||
1990 | the password ptr is put in the new session structure (in which case the | 2049 | the password ptr is put in the new session structure (in which case the |
1991 | password will be freed at unmount time) */ | 2050 | password will be freed at unmount time) */ |
1992 | kfree(volume_info.UNC); | 2051 | kfree(volume_info.UNC); |
2052 | kfree(volume_info.prepath); | ||
1993 | FreeXid(xid); | 2053 | FreeXid(xid); |
1994 | return rc; | 2054 | return rc; |
1995 | } | 2055 | } |
@@ -3177,6 +3237,7 @@ cifs_umount(struct super_block *sb, struct cifs_sb_info *cifs_sb) | |||
3177 | int xid; | 3237 | int xid; |
3178 | struct cifsSesInfo *ses = NULL; | 3238 | struct cifsSesInfo *ses = NULL; |
3179 | struct task_struct *cifsd_task; | 3239 | struct task_struct *cifsd_task; |
3240 | char * tmp; | ||
3180 | 3241 | ||
3181 | xid = GetXid(); | 3242 | xid = GetXid(); |
3182 | 3243 | ||
@@ -3210,6 +3271,10 @@ cifs_umount(struct super_block *sb, struct cifs_sb_info *cifs_sb) | |||
3210 | } | 3271 | } |
3211 | 3272 | ||
3212 | cifs_sb->tcon = NULL; | 3273 | cifs_sb->tcon = NULL; |
3274 | tmp = cifs_sb->prepath; | ||
3275 | cifs_sb->prepathlen = 0; | ||
3276 | cifs_sb->prepath = NULL; | ||
3277 | kfree(tmp); | ||
3213 | if (ses) | 3278 | if (ses) |
3214 | schedule_timeout_interruptible(msecs_to_jiffies(500)); | 3279 | schedule_timeout_interruptible(msecs_to_jiffies(500)); |
3215 | if (ses) | 3280 | if (ses) |
diff --git a/fs/cifs/dir.c b/fs/cifs/dir.c index ba4cbe9b0684..66b825ade3e1 100644 --- a/fs/cifs/dir.c +++ b/fs/cifs/dir.c | |||
@@ -46,7 +46,8 @@ char * | |||
46 | build_path_from_dentry(struct dentry *direntry) | 46 | build_path_from_dentry(struct dentry *direntry) |
47 | { | 47 | { |
48 | struct dentry *temp; | 48 | struct dentry *temp; |
49 | int namelen = 0; | 49 | int namelen; |
50 | int pplen; | ||
50 | char *full_path; | 51 | char *full_path; |
51 | char dirsep; | 52 | char dirsep; |
52 | 53 | ||
@@ -56,7 +57,9 @@ build_path_from_dentry(struct dentry *direntry) | |||
56 | when the server crashed */ | 57 | when the server crashed */ |
57 | 58 | ||
58 | dirsep = CIFS_DIR_SEP(CIFS_SB(direntry->d_sb)); | 59 | dirsep = CIFS_DIR_SEP(CIFS_SB(direntry->d_sb)); |
60 | pplen = CIFS_SB(direntry->d_sb)->prepathlen; | ||
59 | cifs_bp_rename_retry: | 61 | cifs_bp_rename_retry: |
62 | namelen = pplen; | ||
60 | for (temp = direntry; !IS_ROOT(temp);) { | 63 | for (temp = direntry; !IS_ROOT(temp);) { |
61 | namelen += (1 + temp->d_name.len); | 64 | namelen += (1 + temp->d_name.len); |
62 | temp = temp->d_parent; | 65 | temp = temp->d_parent; |
@@ -70,7 +73,6 @@ cifs_bp_rename_retry: | |||
70 | if(full_path == NULL) | 73 | if(full_path == NULL) |
71 | return full_path; | 74 | return full_path; |
72 | full_path[namelen] = 0; /* trailing null */ | 75 | full_path[namelen] = 0; /* trailing null */ |
73 | |||
74 | for (temp = direntry; !IS_ROOT(temp);) { | 76 | for (temp = direntry; !IS_ROOT(temp);) { |
75 | namelen -= 1 + temp->d_name.len; | 77 | namelen -= 1 + temp->d_name.len; |
76 | if (namelen < 0) { | 78 | if (namelen < 0) { |
@@ -79,7 +81,7 @@ cifs_bp_rename_retry: | |||
79 | full_path[namelen] = dirsep; | 81 | full_path[namelen] = dirsep; |
80 | strncpy(full_path + namelen + 1, temp->d_name.name, | 82 | strncpy(full_path + namelen + 1, temp->d_name.name, |
81 | temp->d_name.len); | 83 | temp->d_name.len); |
82 | cFYI(0, (" name: %s ", full_path + namelen)); | 84 | cFYI(0, ("name: %s", full_path + namelen)); |
83 | } | 85 | } |
84 | temp = temp->d_parent; | 86 | temp = temp->d_parent; |
85 | if(temp == NULL) { | 87 | if(temp == NULL) { |
@@ -88,18 +90,23 @@ cifs_bp_rename_retry: | |||
88 | return NULL; | 90 | return NULL; |
89 | } | 91 | } |
90 | } | 92 | } |
91 | if (namelen != 0) { | 93 | if (namelen != pplen) { |
92 | cERROR(1, | 94 | cERROR(1, |
93 | ("We did not end path lookup where we expected namelen is %d", | 95 | ("did not end path lookup where expected namelen is %d", |
94 | namelen)); | 96 | namelen)); |
95 | /* presumably this is only possible if we were racing with a rename | 97 | /* presumably this is only possible if racing with a rename |
96 | of one of the parent directories (we can not lock the dentries | 98 | of one of the parent directories (we can not lock the dentries |
97 | above us to prevent this, but retrying should be harmless) */ | 99 | above us to prevent this, but retrying should be harmless) */ |
98 | kfree(full_path); | 100 | kfree(full_path); |
99 | namelen = 0; | ||
100 | goto cifs_bp_rename_retry; | 101 | goto cifs_bp_rename_retry; |
101 | } | 102 | } |
102 | 103 | /* DIR_SEP already set for byte 0 / vs \ but not for | |
104 | subsequent slashes in prepath which currently must | ||
105 | be entered the right way - not sure if there is an alternative | ||
106 | since the '\' is a valid posix character so we can not switch | ||
107 | those safely to '/' if any are found in the middle of the prepath */ | ||
108 | /* BB test paths to Windows with '/' in the midst of prepath */ | ||
109 | strncpy(full_path,CIFS_SB(direntry->d_sb)->prepath,pplen); | ||
103 | return full_path; | 110 | return full_path; |
104 | } | 111 | } |
105 | 112 | ||
@@ -267,6 +274,10 @@ cifs_create(struct inode *inode, struct dentry *direntry, int mode, | |||
267 | pCifsFile->invalidHandle = FALSE; | 274 | pCifsFile->invalidHandle = FALSE; |
268 | pCifsFile->closePend = FALSE; | 275 | pCifsFile->closePend = FALSE; |
269 | init_MUTEX(&pCifsFile->fh_sem); | 276 | init_MUTEX(&pCifsFile->fh_sem); |
277 | init_MUTEX(&pCifsFile->lock_sem); | ||
278 | INIT_LIST_HEAD(&pCifsFile->llist); | ||
279 | atomic_set(&pCifsFile->wrtPending,0); | ||
280 | |||
270 | /* set the following in open now | 281 | /* set the following in open now |
271 | pCifsFile->pfile = file; */ | 282 | pCifsFile->pfile = file; */ |
272 | write_lock(&GlobalSMBSeslock); | 283 | write_lock(&GlobalSMBSeslock); |
diff --git a/fs/cifs/file.c b/fs/cifs/file.c index 944d2b9e092d..ddb012a68023 100644 --- a/fs/cifs/file.c +++ b/fs/cifs/file.c | |||
@@ -5,6 +5,7 @@ | |||
5 | * | 5 | * |
6 | * Copyright (C) International Business Machines Corp., 2002,2003 | 6 | * Copyright (C) International Business Machines Corp., 2002,2003 |
7 | * Author(s): Steve French (sfrench@us.ibm.com) | 7 | * Author(s): Steve French (sfrench@us.ibm.com) |
8 | * Jeremy Allison (jra@samba.org) | ||
8 | * | 9 | * |
9 | * This library is free software; you can redistribute it and/or modify | 10 | * This library is free software; you can redistribute it and/or modify |
10 | * it under the terms of the GNU Lesser General Public License as published | 11 | * it under the terms of the GNU Lesser General Public License as published |
@@ -47,6 +48,8 @@ static inline struct cifsFileInfo *cifs_init_private( | |||
47 | private_data->netfid = netfid; | 48 | private_data->netfid = netfid; |
48 | private_data->pid = current->tgid; | 49 | private_data->pid = current->tgid; |
49 | init_MUTEX(&private_data->fh_sem); | 50 | init_MUTEX(&private_data->fh_sem); |
51 | init_MUTEX(&private_data->lock_sem); | ||
52 | INIT_LIST_HEAD(&private_data->llist); | ||
50 | private_data->pfile = file; /* needed for writepage */ | 53 | private_data->pfile = file; /* needed for writepage */ |
51 | private_data->pInode = inode; | 54 | private_data->pInode = inode; |
52 | private_data->invalidHandle = FALSE; | 55 | private_data->invalidHandle = FALSE; |
@@ -473,6 +476,8 @@ int cifs_close(struct inode *inode, struct file *file) | |||
473 | cifs_sb = CIFS_SB(inode->i_sb); | 476 | cifs_sb = CIFS_SB(inode->i_sb); |
474 | pTcon = cifs_sb->tcon; | 477 | pTcon = cifs_sb->tcon; |
475 | if (pSMBFile) { | 478 | if (pSMBFile) { |
479 | struct cifsLockInfo *li, *tmp; | ||
480 | |||
476 | pSMBFile->closePend = TRUE; | 481 | pSMBFile->closePend = TRUE; |
477 | if (pTcon) { | 482 | if (pTcon) { |
478 | /* no sense reconnecting to close a file that is | 483 | /* no sense reconnecting to close a file that is |
@@ -496,6 +501,16 @@ int cifs_close(struct inode *inode, struct file *file) | |||
496 | pSMBFile->netfid); | 501 | pSMBFile->netfid); |
497 | } | 502 | } |
498 | } | 503 | } |
504 | |||
505 | /* Delete any outstanding lock records. | ||
506 | We'll lose them when the file is closed anyway. */ | ||
507 | down(&pSMBFile->lock_sem); | ||
508 | list_for_each_entry_safe(li, tmp, &pSMBFile->llist, llist) { | ||
509 | list_del(&li->llist); | ||
510 | kfree(li); | ||
511 | } | ||
512 | up(&pSMBFile->lock_sem); | ||
513 | |||
499 | write_lock(&GlobalSMBSeslock); | 514 | write_lock(&GlobalSMBSeslock); |
500 | list_del(&pSMBFile->flist); | 515 | list_del(&pSMBFile->flist); |
501 | list_del(&pSMBFile->tlist); | 516 | list_del(&pSMBFile->tlist); |
@@ -570,6 +585,21 @@ int cifs_closedir(struct inode *inode, struct file *file) | |||
570 | return rc; | 585 | return rc; |
571 | } | 586 | } |
572 | 587 | ||
588 | static int store_file_lock(struct cifsFileInfo *fid, __u64 len, | ||
589 | __u64 offset, __u8 lockType) | ||
590 | { | ||
591 | struct cifsLockInfo *li = kmalloc(sizeof(struct cifsLockInfo), GFP_KERNEL); | ||
592 | if (li == NULL) | ||
593 | return -ENOMEM; | ||
594 | li->offset = offset; | ||
595 | li->length = len; | ||
596 | li->type = lockType; | ||
597 | down(&fid->lock_sem); | ||
598 | list_add(&li->llist, &fid->llist); | ||
599 | up(&fid->lock_sem); | ||
600 | return 0; | ||
601 | } | ||
602 | |||
573 | int cifs_lock(struct file *file, int cmd, struct file_lock *pfLock) | 603 | int cifs_lock(struct file *file, int cmd, struct file_lock *pfLock) |
574 | { | 604 | { |
575 | int rc, xid; | 605 | int rc, xid; |
@@ -581,6 +611,7 @@ int cifs_lock(struct file *file, int cmd, struct file_lock *pfLock) | |||
581 | struct cifsTconInfo *pTcon; | 611 | struct cifsTconInfo *pTcon; |
582 | __u16 netfid; | 612 | __u16 netfid; |
583 | __u8 lockType = LOCKING_ANDX_LARGE_FILES; | 613 | __u8 lockType = LOCKING_ANDX_LARGE_FILES; |
614 | int posix_locking; | ||
584 | 615 | ||
585 | length = 1 + pfLock->fl_end - pfLock->fl_start; | 616 | length = 1 + pfLock->fl_end - pfLock->fl_start; |
586 | rc = -EACCES; | 617 | rc = -EACCES; |
@@ -639,15 +670,14 @@ int cifs_lock(struct file *file, int cmd, struct file_lock *pfLock) | |||
639 | } | 670 | } |
640 | netfid = ((struct cifsFileInfo *)file->private_data)->netfid; | 671 | netfid = ((struct cifsFileInfo *)file->private_data)->netfid; |
641 | 672 | ||
673 | posix_locking = (cifs_sb->tcon->ses->capabilities & CAP_UNIX) && | ||
674 | (CIFS_UNIX_FCNTL_CAP & le64_to_cpu(cifs_sb->tcon->fsUnixInfo.Capability)); | ||
642 | 675 | ||
643 | /* BB add code here to normalize offset and length to | 676 | /* BB add code here to normalize offset and length to |
644 | account for negative length which we can not accept over the | 677 | account for negative length which we can not accept over the |
645 | wire */ | 678 | wire */ |
646 | if (IS_GETLK(cmd)) { | 679 | if (IS_GETLK(cmd)) { |
647 | if(experimEnabled && | 680 | if(posix_locking) { |
648 | (cifs_sb->tcon->ses->capabilities & CAP_UNIX) && | ||
649 | (CIFS_UNIX_FCNTL_CAP & | ||
650 | le64_to_cpu(cifs_sb->tcon->fsUnixInfo.Capability))) { | ||
651 | int posix_lock_type; | 681 | int posix_lock_type; |
652 | if(lockType & LOCKING_ANDX_SHARED_LOCK) | 682 | if(lockType & LOCKING_ANDX_SHARED_LOCK) |
653 | posix_lock_type = CIFS_RDLCK; | 683 | posix_lock_type = CIFS_RDLCK; |
@@ -683,10 +713,15 @@ int cifs_lock(struct file *file, int cmd, struct file_lock *pfLock) | |||
683 | FreeXid(xid); | 713 | FreeXid(xid); |
684 | return rc; | 714 | return rc; |
685 | } | 715 | } |
686 | if (experimEnabled && | 716 | |
687 | (cifs_sb->tcon->ses->capabilities & CAP_UNIX) && | 717 | if (!numLock && !numUnlock) { |
688 | (CIFS_UNIX_FCNTL_CAP & | 718 | /* if no lock or unlock then nothing |
689 | le64_to_cpu(cifs_sb->tcon->fsUnixInfo.Capability))) { | 719 | to do since we do not know what it is */ |
720 | FreeXid(xid); | ||
721 | return -EOPNOTSUPP; | ||
722 | } | ||
723 | |||
724 | if (posix_locking) { | ||
690 | int posix_lock_type; | 725 | int posix_lock_type; |
691 | if(lockType & LOCKING_ANDX_SHARED_LOCK) | 726 | if(lockType & LOCKING_ANDX_SHARED_LOCK) |
692 | posix_lock_type = CIFS_RDLCK; | 727 | posix_lock_type = CIFS_RDLCK; |
@@ -695,18 +730,47 @@ int cifs_lock(struct file *file, int cmd, struct file_lock *pfLock) | |||
695 | 730 | ||
696 | if(numUnlock == 1) | 731 | if(numUnlock == 1) |
697 | posix_lock_type = CIFS_UNLCK; | 732 | posix_lock_type = CIFS_UNLCK; |
698 | else if(numLock == 0) { | 733 | |
699 | /* if no lock or unlock then nothing | ||
700 | to do since we do not know what it is */ | ||
701 | FreeXid(xid); | ||
702 | return -EOPNOTSUPP; | ||
703 | } | ||
704 | rc = CIFSSMBPosixLock(xid, pTcon, netfid, 0 /* set */, | 734 | rc = CIFSSMBPosixLock(xid, pTcon, netfid, 0 /* set */, |
705 | length, pfLock, | 735 | length, pfLock, |
706 | posix_lock_type, wait_flag); | 736 | posix_lock_type, wait_flag); |
707 | } else | 737 | } else { |
708 | rc = CIFSSMBLock(xid, pTcon, netfid, length, pfLock->fl_start, | 738 | struct cifsFileInfo *fid = (struct cifsFileInfo *)file->private_data; |
709 | numUnlock, numLock, lockType, wait_flag); | 739 | |
740 | if (numLock) { | ||
741 | rc = CIFSSMBLock(xid, pTcon, netfid, length, pfLock->fl_start, | ||
742 | 0, numLock, lockType, wait_flag); | ||
743 | |||
744 | if (rc == 0) { | ||
745 | /* For Windows locks we must store them. */ | ||
746 | rc = store_file_lock(fid, length, | ||
747 | pfLock->fl_start, lockType); | ||
748 | } | ||
749 | } else if (numUnlock) { | ||
750 | /* For each stored lock that this unlock overlaps | ||
751 | completely, unlock it. */ | ||
752 | int stored_rc = 0; | ||
753 | struct cifsLockInfo *li, *tmp; | ||
754 | |||
755 | rc = 0; | ||
756 | down(&fid->lock_sem); | ||
757 | list_for_each_entry_safe(li, tmp, &fid->llist, llist) { | ||
758 | if (pfLock->fl_start <= li->offset && | ||
759 | length >= li->length) { | ||
760 | stored_rc = CIFSSMBLock(xid, pTcon, netfid, | ||
761 | li->length, li->offset, | ||
762 | 1, 0, li->type, FALSE); | ||
763 | if (stored_rc) | ||
764 | rc = stored_rc; | ||
765 | |||
766 | list_del(&li->llist); | ||
767 | kfree(li); | ||
768 | } | ||
769 | } | ||
770 | up(&fid->lock_sem); | ||
771 | } | ||
772 | } | ||
773 | |||
710 | if (pfLock->fl_flags & FL_POSIX) | 774 | if (pfLock->fl_flags & FL_POSIX) |
711 | posix_lock_file_wait(file, pfLock); | 775 | posix_lock_file_wait(file, pfLock); |
712 | FreeXid(xid); | 776 | FreeXid(xid); |
diff --git a/fs/cifs/netmisc.c b/fs/cifs/netmisc.c index b66eff5dc624..ce87550e918f 100644 --- a/fs/cifs/netmisc.c +++ b/fs/cifs/netmisc.c | |||
@@ -72,6 +72,7 @@ static const struct smb_to_posix_error mapping_table_ERRDOS[] = { | |||
72 | {ERRinvlevel,-EOPNOTSUPP}, | 72 | {ERRinvlevel,-EOPNOTSUPP}, |
73 | {ERRdirnotempty, -ENOTEMPTY}, | 73 | {ERRdirnotempty, -ENOTEMPTY}, |
74 | {ERRnotlocked, -ENOLCK}, | 74 | {ERRnotlocked, -ENOLCK}, |
75 | {ERRcancelviolation, -ENOLCK}, | ||
75 | {ERRalreadyexists, -EEXIST}, | 76 | {ERRalreadyexists, -EEXIST}, |
76 | {ERRmoredata, -EOVERFLOW}, | 77 | {ERRmoredata, -EOVERFLOW}, |
77 | {ERReasnotsupported,-EOPNOTSUPP}, | 78 | {ERReasnotsupported,-EOPNOTSUPP}, |
diff --git a/fs/cifs/readdir.c b/fs/cifs/readdir.c index 03bbcb377913..9aeb58a7d369 100644 --- a/fs/cifs/readdir.c +++ b/fs/cifs/readdir.c | |||
@@ -82,7 +82,6 @@ static int construct_dentry(struct qstr *qstring, struct file *file, | |||
82 | if(*ptmp_inode == NULL) | 82 | if(*ptmp_inode == NULL) |
83 | return rc; | 83 | return rc; |
84 | rc = 1; | 84 | rc = 1; |
85 | d_instantiate(tmp_dentry, *ptmp_inode); | ||
86 | } | 85 | } |
87 | } else { | 86 | } else { |
88 | tmp_dentry = d_alloc(file->f_dentry, qstring); | 87 | tmp_dentry = d_alloc(file->f_dentry, qstring); |
@@ -99,9 +98,7 @@ static int construct_dentry(struct qstr *qstring, struct file *file, | |||
99 | tmp_dentry->d_op = &cifs_dentry_ops; | 98 | tmp_dentry->d_op = &cifs_dentry_ops; |
100 | if(*ptmp_inode == NULL) | 99 | if(*ptmp_inode == NULL) |
101 | return rc; | 100 | return rc; |
102 | rc = 1; | 101 | rc = 2; |
103 | d_instantiate(tmp_dentry, *ptmp_inode); | ||
104 | d_rehash(tmp_dentry); | ||
105 | } | 102 | } |
106 | 103 | ||
107 | tmp_dentry->d_time = jiffies; | 104 | tmp_dentry->d_time = jiffies; |
@@ -556,7 +553,7 @@ static int cifs_entry_is_dot(char *current_entry, struct cifsFileInfo *cfile) | |||
556 | FIND_FILE_STANDARD_INFO * pFindData = | 553 | FIND_FILE_STANDARD_INFO * pFindData = |
557 | (FIND_FILE_STANDARD_INFO *)current_entry; | 554 | (FIND_FILE_STANDARD_INFO *)current_entry; |
558 | filename = &pFindData->FileName[0]; | 555 | filename = &pFindData->FileName[0]; |
559 | len = le32_to_cpu(pFindData->FileNameLength); | 556 | len = pFindData->FileNameLength; |
560 | } else { | 557 | } else { |
561 | cFYI(1,("Unknown findfirst level %d",cfile->srch_inf.info_level)); | 558 | cFYI(1,("Unknown findfirst level %d",cfile->srch_inf.info_level)); |
562 | } | 559 | } |
@@ -870,6 +867,12 @@ static int cifs_filldir(char *pfindEntry, struct file *file, | |||
870 | pfindEntry, &obj_type, rc); | 867 | pfindEntry, &obj_type, rc); |
871 | else | 868 | else |
872 | fill_in_inode(tmp_inode, 1 /* NT */, pfindEntry, &obj_type, rc); | 869 | fill_in_inode(tmp_inode, 1 /* NT */, pfindEntry, &obj_type, rc); |
870 | |||
871 | if(rc) /* new inode - needs to be tied to dentry */ { | ||
872 | d_instantiate(tmp_dentry, tmp_inode); | ||
873 | if(rc == 2) | ||
874 | d_rehash(tmp_dentry); | ||
875 | } | ||
873 | 876 | ||
874 | 877 | ||
875 | rc = filldir(direntry,qstring.name,qstring.len,file->f_pos, | 878 | rc = filldir(direntry,qstring.name,qstring.len,file->f_pos, |
diff --git a/fs/cifs/sess.c b/fs/cifs/sess.c index 7202d534ef0b..d1705ab8136e 100644 --- a/fs/cifs/sess.c +++ b/fs/cifs/sess.c | |||
@@ -372,7 +372,7 @@ CIFS_SessSetup(unsigned int xid, struct cifsSesInfo *ses, int first_time, | |||
372 | 372 | ||
373 | /* no capabilities flags in old lanman negotiation */ | 373 | /* no capabilities flags in old lanman negotiation */ |
374 | 374 | ||
375 | pSMB->old_req.PasswordLength = CIFS_SESS_KEY_SIZE; | 375 | pSMB->old_req.PasswordLength = cpu_to_le16(CIFS_SESS_KEY_SIZE); |
376 | /* BB calculate hash with password */ | 376 | /* BB calculate hash with password */ |
377 | /* and copy into bcc */ | 377 | /* and copy into bcc */ |
378 | 378 | ||
diff --git a/fs/cifs/smberr.h b/fs/cifs/smberr.h index cd41c67ff8d3..212c3c296409 100644 --- a/fs/cifs/smberr.h +++ b/fs/cifs/smberr.h | |||
@@ -95,6 +95,7 @@ | |||
95 | #define ERRinvlevel 124 | 95 | #define ERRinvlevel 124 |
96 | #define ERRdirnotempty 145 | 96 | #define ERRdirnotempty 145 |
97 | #define ERRnotlocked 158 | 97 | #define ERRnotlocked 158 |
98 | #define ERRcancelviolation 173 | ||
98 | #define ERRalreadyexists 183 | 99 | #define ERRalreadyexists 183 |
99 | #define ERRbadpipe 230 | 100 | #define ERRbadpipe 230 |
100 | #define ERRpipebusy 231 | 101 | #define ERRpipebusy 231 |
diff --git a/fs/cifs/transport.c b/fs/cifs/transport.c index 17ba329e2b3d..48d47b46b1fb 100644 --- a/fs/cifs/transport.c +++ b/fs/cifs/transport.c | |||
@@ -3,7 +3,8 @@ | |||
3 | * | 3 | * |
4 | * Copyright (C) International Business Machines Corp., 2002,2005 | 4 | * Copyright (C) International Business Machines Corp., 2002,2005 |
5 | * Author(s): Steve French (sfrench@us.ibm.com) | 5 | * Author(s): Steve French (sfrench@us.ibm.com) |
6 | * | 6 | * Jeremy Allison (jra@samba.org) 2006. |
7 | * | ||
7 | * This library is free software; you can redistribute it and/or modify | 8 | * This library is free software; you can redistribute it and/or modify |
8 | * it under the terms of the GNU Lesser General Public License as published | 9 | * it under the terms of the GNU Lesser General Public License as published |
9 | * by the Free Software Foundation; either version 2.1 of the License, or | 10 | * by the Free Software Foundation; either version 2.1 of the License, or |
@@ -36,7 +37,7 @@ extern mempool_t *cifs_mid_poolp; | |||
36 | extern kmem_cache_t *cifs_oplock_cachep; | 37 | extern kmem_cache_t *cifs_oplock_cachep; |
37 | 38 | ||
38 | static struct mid_q_entry * | 39 | static struct mid_q_entry * |
39 | AllocMidQEntry(struct smb_hdr *smb_buffer, struct cifsSesInfo *ses) | 40 | AllocMidQEntry(const struct smb_hdr *smb_buffer, struct cifsSesInfo *ses) |
40 | { | 41 | { |
41 | struct mid_q_entry *temp; | 42 | struct mid_q_entry *temp; |
42 | 43 | ||
@@ -203,6 +204,10 @@ smb_send(struct socket *ssocket, struct smb_hdr *smb_buffer, | |||
203 | rc = 0; | 204 | rc = 0; |
204 | } | 205 | } |
205 | 206 | ||
207 | /* Don't want to modify the buffer as a | ||
208 | side effect of this call. */ | ||
209 | smb_buffer->smb_buf_length = smb_buf_length; | ||
210 | |||
206 | return rc; | 211 | return rc; |
207 | } | 212 | } |
208 | 213 | ||
@@ -217,6 +222,7 @@ smb_send2(struct socket *ssocket, struct kvec *iov, int n_vec, | |||
217 | unsigned int len = iov[0].iov_len; | 222 | unsigned int len = iov[0].iov_len; |
218 | unsigned int total_len; | 223 | unsigned int total_len; |
219 | int first_vec = 0; | 224 | int first_vec = 0; |
225 | unsigned int smb_buf_length = smb_buffer->smb_buf_length; | ||
220 | 226 | ||
221 | if(ssocket == NULL) | 227 | if(ssocket == NULL) |
222 | return -ENOTSOCK; /* BB eventually add reconnect code here */ | 228 | return -ENOTSOCK; /* BB eventually add reconnect code here */ |
@@ -293,36 +299,15 @@ smb_send2(struct socket *ssocket, struct kvec *iov, int n_vec, | |||
293 | } else | 299 | } else |
294 | rc = 0; | 300 | rc = 0; |
295 | 301 | ||
302 | /* Don't want to modify the buffer as a | ||
303 | side effect of this call. */ | ||
304 | smb_buffer->smb_buf_length = smb_buf_length; | ||
305 | |||
296 | return rc; | 306 | return rc; |
297 | } | 307 | } |
298 | 308 | ||
299 | int | 309 | static int wait_for_free_request(struct cifsSesInfo *ses, const int long_op) |
300 | SendReceive2(const unsigned int xid, struct cifsSesInfo *ses, | ||
301 | struct kvec *iov, int n_vec, int * pRespBufType /* ret */, | ||
302 | const int long_op) | ||
303 | { | 310 | { |
304 | int rc = 0; | ||
305 | unsigned int receive_len; | ||
306 | unsigned long timeout; | ||
307 | struct mid_q_entry *midQ; | ||
308 | struct smb_hdr *in_buf = iov[0].iov_base; | ||
309 | |||
310 | *pRespBufType = CIFS_NO_BUFFER; /* no response buf yet */ | ||
311 | |||
312 | if ((ses == NULL) || (ses->server == NULL)) { | ||
313 | cifs_small_buf_release(in_buf); | ||
314 | cERROR(1,("Null session")); | ||
315 | return -EIO; | ||
316 | } | ||
317 | |||
318 | if(ses->server->tcpStatus == CifsExiting) { | ||
319 | cifs_small_buf_release(in_buf); | ||
320 | return -ENOENT; | ||
321 | } | ||
322 | |||
323 | /* Ensure that we do not send more than 50 overlapping requests | ||
324 | to the same server. We may make this configurable later or | ||
325 | use ses->maxReq */ | ||
326 | if(long_op == -1) { | 311 | if(long_op == -1) { |
327 | /* oplock breaks must not be held up */ | 312 | /* oplock breaks must not be held up */ |
328 | atomic_inc(&ses->server->inFlight); | 313 | atomic_inc(&ses->server->inFlight); |
@@ -345,53 +330,140 @@ SendReceive2(const unsigned int xid, struct cifsSesInfo *ses, | |||
345 | } else { | 330 | } else { |
346 | if(ses->server->tcpStatus == CifsExiting) { | 331 | if(ses->server->tcpStatus == CifsExiting) { |
347 | spin_unlock(&GlobalMid_Lock); | 332 | spin_unlock(&GlobalMid_Lock); |
348 | cifs_small_buf_release(in_buf); | ||
349 | return -ENOENT; | 333 | return -ENOENT; |
350 | } | 334 | } |
351 | 335 | ||
352 | /* can not count locking commands against total since | 336 | /* can not count locking commands against total since |
353 | they are allowed to block on server */ | 337 | they are allowed to block on server */ |
354 | 338 | ||
355 | if(long_op < 3) { | ||
356 | /* update # of requests on the wire to server */ | 339 | /* update # of requests on the wire to server */ |
340 | if (long_op < 3) | ||
357 | atomic_inc(&ses->server->inFlight); | 341 | atomic_inc(&ses->server->inFlight); |
358 | } | ||
359 | spin_unlock(&GlobalMid_Lock); | 342 | spin_unlock(&GlobalMid_Lock); |
360 | break; | 343 | break; |
361 | } | 344 | } |
362 | } | 345 | } |
363 | } | 346 | } |
364 | /* make sure that we sign in the same order that we send on this socket | 347 | return 0; |
365 | and avoid races inside tcp sendmsg code that could cause corruption | 348 | } |
366 | of smb data */ | ||
367 | |||
368 | down(&ses->server->tcpSem); | ||
369 | 349 | ||
350 | static int allocate_mid(struct cifsSesInfo *ses, struct smb_hdr *in_buf, | ||
351 | struct mid_q_entry **ppmidQ) | ||
352 | { | ||
370 | if (ses->server->tcpStatus == CifsExiting) { | 353 | if (ses->server->tcpStatus == CifsExiting) { |
371 | rc = -ENOENT; | 354 | return -ENOENT; |
372 | goto out_unlock2; | ||
373 | } else if (ses->server->tcpStatus == CifsNeedReconnect) { | 355 | } else if (ses->server->tcpStatus == CifsNeedReconnect) { |
374 | cFYI(1,("tcp session dead - return to caller to retry")); | 356 | cFYI(1,("tcp session dead - return to caller to retry")); |
375 | rc = -EAGAIN; | 357 | return -EAGAIN; |
376 | goto out_unlock2; | ||
377 | } else if (ses->status != CifsGood) { | 358 | } else if (ses->status != CifsGood) { |
378 | /* check if SMB session is bad because we are setting it up */ | 359 | /* check if SMB session is bad because we are setting it up */ |
379 | if((in_buf->Command != SMB_COM_SESSION_SETUP_ANDX) && | 360 | if((in_buf->Command != SMB_COM_SESSION_SETUP_ANDX) && |
380 | (in_buf->Command != SMB_COM_NEGOTIATE)) { | 361 | (in_buf->Command != SMB_COM_NEGOTIATE)) { |
381 | rc = -EAGAIN; | 362 | return -EAGAIN; |
382 | goto out_unlock2; | ||
383 | } /* else ok - we are setting up session */ | 363 | } /* else ok - we are setting up session */ |
384 | } | 364 | } |
385 | midQ = AllocMidQEntry(in_buf, ses); | 365 | *ppmidQ = AllocMidQEntry(in_buf, ses); |
386 | if (midQ == NULL) { | 366 | if (*ppmidQ == NULL) { |
367 | return -ENOMEM; | ||
368 | } | ||
369 | return 0; | ||
370 | } | ||
371 | |||
372 | static int wait_for_response(struct cifsSesInfo *ses, | ||
373 | struct mid_q_entry *midQ, | ||
374 | unsigned long timeout, | ||
375 | unsigned long time_to_wait) | ||
376 | { | ||
377 | unsigned long curr_timeout; | ||
378 | |||
379 | for (;;) { | ||
380 | curr_timeout = timeout + jiffies; | ||
381 | wait_event(ses->server->response_q, | ||
382 | (!(midQ->midState == MID_REQUEST_SUBMITTED)) || | ||
383 | time_after(jiffies, curr_timeout) || | ||
384 | ((ses->server->tcpStatus != CifsGood) && | ||
385 | (ses->server->tcpStatus != CifsNew))); | ||
386 | |||
387 | if (time_after(jiffies, curr_timeout) && | ||
388 | (midQ->midState == MID_REQUEST_SUBMITTED) && | ||
389 | ((ses->server->tcpStatus == CifsGood) || | ||
390 | (ses->server->tcpStatus == CifsNew))) { | ||
391 | |||
392 | unsigned long lrt; | ||
393 | |||
394 | /* We timed out. Is the server still | ||
395 | sending replies ? */ | ||
396 | spin_lock(&GlobalMid_Lock); | ||
397 | lrt = ses->server->lstrp; | ||
398 | spin_unlock(&GlobalMid_Lock); | ||
399 | |||
400 | /* Calculate time_to_wait past last receive time. | ||
401 | Although we prefer not to time out if the | ||
402 | server is still responding - we will time | ||
403 | out if the server takes more than 15 (or 45 | ||
404 | or 180) seconds to respond to this request | ||
405 | and has not responded to any request from | ||
406 | other threads on the client within 10 seconds */ | ||
407 | lrt += time_to_wait; | ||
408 | if (time_after(jiffies, lrt)) { | ||
409 | /* No replies for time_to_wait. */ | ||
410 | cERROR(1,("server not responding")); | ||
411 | return -1; | ||
412 | } | ||
413 | } else { | ||
414 | return 0; | ||
415 | } | ||
416 | } | ||
417 | } | ||
418 | |||
419 | int | ||
420 | SendReceive2(const unsigned int xid, struct cifsSesInfo *ses, | ||
421 | struct kvec *iov, int n_vec, int * pRespBufType /* ret */, | ||
422 | const int long_op) | ||
423 | { | ||
424 | int rc = 0; | ||
425 | unsigned int receive_len; | ||
426 | unsigned long timeout; | ||
427 | struct mid_q_entry *midQ; | ||
428 | struct smb_hdr *in_buf = iov[0].iov_base; | ||
429 | |||
430 | *pRespBufType = CIFS_NO_BUFFER; /* no response buf yet */ | ||
431 | |||
432 | if ((ses == NULL) || (ses->server == NULL)) { | ||
433 | cifs_small_buf_release(in_buf); | ||
434 | cERROR(1,("Null session")); | ||
435 | return -EIO; | ||
436 | } | ||
437 | |||
438 | if(ses->server->tcpStatus == CifsExiting) { | ||
439 | cifs_small_buf_release(in_buf); | ||
440 | return -ENOENT; | ||
441 | } | ||
442 | |||
443 | /* Ensure that we do not send more than 50 overlapping requests | ||
444 | to the same server. We may make this configurable later or | ||
445 | use ses->maxReq */ | ||
446 | |||
447 | rc = wait_for_free_request(ses, long_op); | ||
448 | if (rc) { | ||
449 | cifs_small_buf_release(in_buf); | ||
450 | return rc; | ||
451 | } | ||
452 | |||
453 | /* make sure that we sign in the same order that we send on this socket | ||
454 | and avoid races inside tcp sendmsg code that could cause corruption | ||
455 | of smb data */ | ||
456 | |||
457 | down(&ses->server->tcpSem); | ||
458 | |||
459 | rc = allocate_mid(ses, in_buf, &midQ); | ||
460 | if (rc) { | ||
387 | up(&ses->server->tcpSem); | 461 | up(&ses->server->tcpSem); |
388 | cifs_small_buf_release(in_buf); | 462 | cifs_small_buf_release(in_buf); |
389 | /* If not lock req, update # of requests on wire to server */ | 463 | /* Update # of requests on wire to server */ |
390 | if(long_op < 3) { | 464 | atomic_dec(&ses->server->inFlight); |
391 | atomic_dec(&ses->server->inFlight); | 465 | wake_up(&ses->server->request_q); |
392 | wake_up(&ses->server->request_q); | 466 | return rc; |
393 | } | ||
394 | return -ENOMEM; | ||
395 | } | 467 | } |
396 | 468 | ||
397 | rc = cifs_sign_smb2(iov, n_vec, ses->server, &midQ->sequence_number); | 469 | rc = cifs_sign_smb2(iov, n_vec, ses->server, &midQ->sequence_number); |
@@ -406,32 +478,23 @@ SendReceive2(const unsigned int xid, struct cifsSesInfo *ses, | |||
406 | atomic_dec(&ses->server->inSend); | 478 | atomic_dec(&ses->server->inSend); |
407 | midQ->when_sent = jiffies; | 479 | midQ->when_sent = jiffies; |
408 | #endif | 480 | #endif |
409 | if(rc < 0) { | 481 | |
410 | DeleteMidQEntry(midQ); | 482 | up(&ses->server->tcpSem); |
411 | up(&ses->server->tcpSem); | 483 | cifs_small_buf_release(in_buf); |
412 | cifs_small_buf_release(in_buf); | 484 | |
413 | /* If not lock req, update # of requests on wire to server */ | 485 | if(rc < 0) |
414 | if(long_op < 3) { | 486 | goto out; |
415 | atomic_dec(&ses->server->inFlight); | ||
416 | wake_up(&ses->server->request_q); | ||
417 | } | ||
418 | return rc; | ||
419 | } else { | ||
420 | up(&ses->server->tcpSem); | ||
421 | cifs_small_buf_release(in_buf); | ||
422 | } | ||
423 | 487 | ||
424 | if (long_op == -1) | 488 | if (long_op == -1) |
425 | goto cifs_no_response_exit2; | 489 | goto out; |
426 | else if (long_op == 2) /* writes past end of file can take loong time */ | 490 | else if (long_op == 2) /* writes past end of file can take loong time */ |
427 | timeout = 180 * HZ; | 491 | timeout = 180 * HZ; |
428 | else if (long_op == 1) | 492 | else if (long_op == 1) |
429 | timeout = 45 * HZ; /* should be greater than | 493 | timeout = 45 * HZ; /* should be greater than |
430 | servers oplock break timeout (about 43 seconds) */ | 494 | servers oplock break timeout (about 43 seconds) */ |
431 | else if (long_op > 2) { | 495 | else |
432 | timeout = MAX_SCHEDULE_TIMEOUT; | ||
433 | } else | ||
434 | timeout = 15 * HZ; | 496 | timeout = 15 * HZ; |
497 | |||
435 | /* wait for 15 seconds or until woken up due to response arriving or | 498 | /* wait for 15 seconds or until woken up due to response arriving or |
436 | due to last connection to this server being unmounted */ | 499 | due to last connection to this server being unmounted */ |
437 | if (signal_pending(current)) { | 500 | if (signal_pending(current)) { |
@@ -441,19 +504,7 @@ SendReceive2(const unsigned int xid, struct cifsSesInfo *ses, | |||
441 | } | 504 | } |
442 | 505 | ||
443 | /* No user interrupts in wait - wreaks havoc with performance */ | 506 | /* No user interrupts in wait - wreaks havoc with performance */ |
444 | if(timeout != MAX_SCHEDULE_TIMEOUT) { | 507 | wait_for_response(ses, midQ, timeout, 10 * HZ); |
445 | timeout += jiffies; | ||
446 | wait_event(ses->server->response_q, | ||
447 | (!(midQ->midState & MID_REQUEST_SUBMITTED)) || | ||
448 | time_after(jiffies, timeout) || | ||
449 | ((ses->server->tcpStatus != CifsGood) && | ||
450 | (ses->server->tcpStatus != CifsNew))); | ||
451 | } else { | ||
452 | wait_event(ses->server->response_q, | ||
453 | (!(midQ->midState & MID_REQUEST_SUBMITTED)) || | ||
454 | ((ses->server->tcpStatus != CifsGood) && | ||
455 | (ses->server->tcpStatus != CifsNew))); | ||
456 | } | ||
457 | 508 | ||
458 | spin_lock(&GlobalMid_Lock); | 509 | spin_lock(&GlobalMid_Lock); |
459 | if (midQ->resp_buf) { | 510 | if (midQ->resp_buf) { |
@@ -481,11 +532,9 @@ SendReceive2(const unsigned int xid, struct cifsSesInfo *ses, | |||
481 | } | 532 | } |
482 | spin_unlock(&GlobalMid_Lock); | 533 | spin_unlock(&GlobalMid_Lock); |
483 | DeleteMidQEntry(midQ); | 534 | DeleteMidQEntry(midQ); |
484 | /* If not lock req, update # of requests on wire to server */ | 535 | /* Update # of requests on wire to server */ |
485 | if(long_op < 3) { | 536 | atomic_dec(&ses->server->inFlight); |
486 | atomic_dec(&ses->server->inFlight); | 537 | wake_up(&ses->server->request_q); |
487 | wake_up(&ses->server->request_q); | ||
488 | } | ||
489 | return rc; | 538 | return rc; |
490 | } | 539 | } |
491 | 540 | ||
@@ -536,24 +585,12 @@ SendReceive2(const unsigned int xid, struct cifsSesInfo *ses, | |||
536 | cFYI(1,("Bad MID state?")); | 585 | cFYI(1,("Bad MID state?")); |
537 | } | 586 | } |
538 | } | 587 | } |
539 | cifs_no_response_exit2: | ||
540 | DeleteMidQEntry(midQ); | ||
541 | |||
542 | if(long_op < 3) { | ||
543 | atomic_dec(&ses->server->inFlight); | ||
544 | wake_up(&ses->server->request_q); | ||
545 | } | ||
546 | 588 | ||
547 | return rc; | 589 | out: |
548 | 590 | ||
549 | out_unlock2: | 591 | DeleteMidQEntry(midQ); |
550 | up(&ses->server->tcpSem); | 592 | atomic_dec(&ses->server->inFlight); |
551 | cifs_small_buf_release(in_buf); | 593 | wake_up(&ses->server->request_q); |
552 | /* If not lock req, update # of requests on wire to server */ | ||
553 | if(long_op < 3) { | ||
554 | atomic_dec(&ses->server->inFlight); | ||
555 | wake_up(&ses->server->request_q); | ||
556 | } | ||
557 | 594 | ||
558 | return rc; | 595 | return rc; |
559 | } | 596 | } |
@@ -583,85 +620,34 @@ SendReceive(const unsigned int xid, struct cifsSesInfo *ses, | |||
583 | /* Ensure that we do not send more than 50 overlapping requests | 620 | /* Ensure that we do not send more than 50 overlapping requests |
584 | to the same server. We may make this configurable later or | 621 | to the same server. We may make this configurable later or |
585 | use ses->maxReq */ | 622 | use ses->maxReq */ |
586 | if(long_op == -1) { | ||
587 | /* oplock breaks must not be held up */ | ||
588 | atomic_inc(&ses->server->inFlight); | ||
589 | } else { | ||
590 | spin_lock(&GlobalMid_Lock); | ||
591 | while(1) { | ||
592 | if(atomic_read(&ses->server->inFlight) >= | ||
593 | cifs_max_pending){ | ||
594 | spin_unlock(&GlobalMid_Lock); | ||
595 | #ifdef CONFIG_CIFS_STATS2 | ||
596 | atomic_inc(&ses->server->num_waiters); | ||
597 | #endif | ||
598 | wait_event(ses->server->request_q, | ||
599 | atomic_read(&ses->server->inFlight) | ||
600 | < cifs_max_pending); | ||
601 | #ifdef CONFIG_CIFS_STATS2 | ||
602 | atomic_dec(&ses->server->num_waiters); | ||
603 | #endif | ||
604 | spin_lock(&GlobalMid_Lock); | ||
605 | } else { | ||
606 | if(ses->server->tcpStatus == CifsExiting) { | ||
607 | spin_unlock(&GlobalMid_Lock); | ||
608 | return -ENOENT; | ||
609 | } | ||
610 | 623 | ||
611 | /* can not count locking commands against total since | 624 | rc = wait_for_free_request(ses, long_op); |
612 | they are allowed to block on server */ | 625 | if (rc) |
613 | 626 | return rc; | |
614 | if(long_op < 3) { | 627 | |
615 | /* update # of requests on the wire to server */ | ||
616 | atomic_inc(&ses->server->inFlight); | ||
617 | } | ||
618 | spin_unlock(&GlobalMid_Lock); | ||
619 | break; | ||
620 | } | ||
621 | } | ||
622 | } | ||
623 | /* make sure that we sign in the same order that we send on this socket | 628 | /* make sure that we sign in the same order that we send on this socket |
624 | and avoid races inside tcp sendmsg code that could cause corruption | 629 | and avoid races inside tcp sendmsg code that could cause corruption |
625 | of smb data */ | 630 | of smb data */ |
626 | 631 | ||
627 | down(&ses->server->tcpSem); | 632 | down(&ses->server->tcpSem); |
628 | 633 | ||
629 | if (ses->server->tcpStatus == CifsExiting) { | 634 | rc = allocate_mid(ses, in_buf, &midQ); |
630 | rc = -ENOENT; | 635 | if (rc) { |
631 | goto out_unlock; | ||
632 | } else if (ses->server->tcpStatus == CifsNeedReconnect) { | ||
633 | cFYI(1,("tcp session dead - return to caller to retry")); | ||
634 | rc = -EAGAIN; | ||
635 | goto out_unlock; | ||
636 | } else if (ses->status != CifsGood) { | ||
637 | /* check if SMB session is bad because we are setting it up */ | ||
638 | if((in_buf->Command != SMB_COM_SESSION_SETUP_ANDX) && | ||
639 | (in_buf->Command != SMB_COM_NEGOTIATE)) { | ||
640 | rc = -EAGAIN; | ||
641 | goto out_unlock; | ||
642 | } /* else ok - we are setting up session */ | ||
643 | } | ||
644 | midQ = AllocMidQEntry(in_buf, ses); | ||
645 | if (midQ == NULL) { | ||
646 | up(&ses->server->tcpSem); | 636 | up(&ses->server->tcpSem); |
647 | /* If not lock req, update # of requests on wire to server */ | 637 | /* Update # of requests on wire to server */ |
648 | if(long_op < 3) { | 638 | atomic_dec(&ses->server->inFlight); |
649 | atomic_dec(&ses->server->inFlight); | 639 | wake_up(&ses->server->request_q); |
650 | wake_up(&ses->server->request_q); | 640 | return rc; |
651 | } | ||
652 | return -ENOMEM; | ||
653 | } | 641 | } |
654 | 642 | ||
655 | if (in_buf->smb_buf_length > CIFSMaxBufSize + MAX_CIFS_HDR_SIZE - 4) { | 643 | if (in_buf->smb_buf_length > CIFSMaxBufSize + MAX_CIFS_HDR_SIZE - 4) { |
656 | up(&ses->server->tcpSem); | ||
657 | cERROR(1, ("Illegal length, greater than maximum frame, %d", | 644 | cERROR(1, ("Illegal length, greater than maximum frame, %d", |
658 | in_buf->smb_buf_length)); | 645 | in_buf->smb_buf_length)); |
659 | DeleteMidQEntry(midQ); | 646 | DeleteMidQEntry(midQ); |
660 | /* If not lock req, update # of requests on wire to server */ | 647 | up(&ses->server->tcpSem); |
661 | if(long_op < 3) { | 648 | /* Update # of requests on wire to server */ |
662 | atomic_dec(&ses->server->inFlight); | 649 | atomic_dec(&ses->server->inFlight); |
663 | wake_up(&ses->server->request_q); | 650 | wake_up(&ses->server->request_q); |
664 | } | ||
665 | return -EIO; | 651 | return -EIO; |
666 | } | 652 | } |
667 | 653 | ||
@@ -677,27 +663,19 @@ SendReceive(const unsigned int xid, struct cifsSesInfo *ses, | |||
677 | atomic_dec(&ses->server->inSend); | 663 | atomic_dec(&ses->server->inSend); |
678 | midQ->when_sent = jiffies; | 664 | midQ->when_sent = jiffies; |
679 | #endif | 665 | #endif |
680 | if(rc < 0) { | 666 | up(&ses->server->tcpSem); |
681 | DeleteMidQEntry(midQ); | 667 | |
682 | up(&ses->server->tcpSem); | 668 | if(rc < 0) |
683 | /* If not lock req, update # of requests on wire to server */ | 669 | goto out; |
684 | if(long_op < 3) { | 670 | |
685 | atomic_dec(&ses->server->inFlight); | ||
686 | wake_up(&ses->server->request_q); | ||
687 | } | ||
688 | return rc; | ||
689 | } else | ||
690 | up(&ses->server->tcpSem); | ||
691 | if (long_op == -1) | 671 | if (long_op == -1) |
692 | goto cifs_no_response_exit; | 672 | goto out; |
693 | else if (long_op == 2) /* writes past end of file can take loong time */ | 673 | else if (long_op == 2) /* writes past end of file can take loong time */ |
694 | timeout = 180 * HZ; | 674 | timeout = 180 * HZ; |
695 | else if (long_op == 1) | 675 | else if (long_op == 1) |
696 | timeout = 45 * HZ; /* should be greater than | 676 | timeout = 45 * HZ; /* should be greater than |
697 | servers oplock break timeout (about 43 seconds) */ | 677 | servers oplock break timeout (about 43 seconds) */ |
698 | else if (long_op > 2) { | 678 | else |
699 | timeout = MAX_SCHEDULE_TIMEOUT; | ||
700 | } else | ||
701 | timeout = 15 * HZ; | 679 | timeout = 15 * HZ; |
702 | /* wait for 15 seconds or until woken up due to response arriving or | 680 | /* wait for 15 seconds or until woken up due to response arriving or |
703 | due to last connection to this server being unmounted */ | 681 | due to last connection to this server being unmounted */ |
@@ -708,19 +686,7 @@ SendReceive(const unsigned int xid, struct cifsSesInfo *ses, | |||
708 | } | 686 | } |
709 | 687 | ||
710 | /* No user interrupts in wait - wreaks havoc with performance */ | 688 | /* No user interrupts in wait - wreaks havoc with performance */ |
711 | if(timeout != MAX_SCHEDULE_TIMEOUT) { | 689 | wait_for_response(ses, midQ, timeout, 10 * HZ); |
712 | timeout += jiffies; | ||
713 | wait_event(ses->server->response_q, | ||
714 | (!(midQ->midState & MID_REQUEST_SUBMITTED)) || | ||
715 | time_after(jiffies, timeout) || | ||
716 | ((ses->server->tcpStatus != CifsGood) && | ||
717 | (ses->server->tcpStatus != CifsNew))); | ||
718 | } else { | ||
719 | wait_event(ses->server->response_q, | ||
720 | (!(midQ->midState & MID_REQUEST_SUBMITTED)) || | ||
721 | ((ses->server->tcpStatus != CifsGood) && | ||
722 | (ses->server->tcpStatus != CifsNew))); | ||
723 | } | ||
724 | 690 | ||
725 | spin_lock(&GlobalMid_Lock); | 691 | spin_lock(&GlobalMid_Lock); |
726 | if (midQ->resp_buf) { | 692 | if (midQ->resp_buf) { |
@@ -748,11 +714,9 @@ SendReceive(const unsigned int xid, struct cifsSesInfo *ses, | |||
748 | } | 714 | } |
749 | spin_unlock(&GlobalMid_Lock); | 715 | spin_unlock(&GlobalMid_Lock); |
750 | DeleteMidQEntry(midQ); | 716 | DeleteMidQEntry(midQ); |
751 | /* If not lock req, update # of requests on wire to server */ | 717 | /* Update # of requests on wire to server */ |
752 | if(long_op < 3) { | 718 | atomic_dec(&ses->server->inFlight); |
753 | atomic_dec(&ses->server->inFlight); | 719 | wake_up(&ses->server->request_q); |
754 | wake_up(&ses->server->request_q); | ||
755 | } | ||
756 | return rc; | 720 | return rc; |
757 | } | 721 | } |
758 | 722 | ||
@@ -799,23 +763,253 @@ SendReceive(const unsigned int xid, struct cifsSesInfo *ses, | |||
799 | cERROR(1,("Bad MID state?")); | 763 | cERROR(1,("Bad MID state?")); |
800 | } | 764 | } |
801 | } | 765 | } |
802 | cifs_no_response_exit: | 766 | |
767 | out: | ||
768 | |||
803 | DeleteMidQEntry(midQ); | 769 | DeleteMidQEntry(midQ); |
770 | atomic_dec(&ses->server->inFlight); | ||
771 | wake_up(&ses->server->request_q); | ||
804 | 772 | ||
805 | if(long_op < 3) { | 773 | return rc; |
806 | atomic_dec(&ses->server->inFlight); | 774 | } |
807 | wake_up(&ses->server->request_q); | 775 | |
808 | } | 776 | /* Send an NT_CANCEL SMB to cause the POSIX blocking lock to return. */ |
777 | |||
778 | static int | ||
779 | send_nt_cancel(struct cifsTconInfo *tcon, struct smb_hdr *in_buf, | ||
780 | struct mid_q_entry *midQ) | ||
781 | { | ||
782 | int rc = 0; | ||
783 | struct cifsSesInfo *ses = tcon->ses; | ||
784 | __u16 mid = in_buf->Mid; | ||
809 | 785 | ||
786 | header_assemble(in_buf, SMB_COM_NT_CANCEL, tcon, 0); | ||
787 | in_buf->Mid = mid; | ||
788 | down(&ses->server->tcpSem); | ||
789 | rc = cifs_sign_smb(in_buf, ses->server, &midQ->sequence_number); | ||
790 | if (rc) { | ||
791 | up(&ses->server->tcpSem); | ||
792 | return rc; | ||
793 | } | ||
794 | rc = smb_send(ses->server->ssocket, in_buf, in_buf->smb_buf_length, | ||
795 | (struct sockaddr *) &(ses->server->addr.sockAddr)); | ||
796 | up(&ses->server->tcpSem); | ||
810 | return rc; | 797 | return rc; |
798 | } | ||
799 | |||
800 | /* We send a LOCKINGX_CANCEL_LOCK to cause the Windows | ||
801 | blocking lock to return. */ | ||
802 | |||
803 | static int | ||
804 | send_lock_cancel(const unsigned int xid, struct cifsTconInfo *tcon, | ||
805 | struct smb_hdr *in_buf, | ||
806 | struct smb_hdr *out_buf) | ||
807 | { | ||
808 | int bytes_returned; | ||
809 | struct cifsSesInfo *ses = tcon->ses; | ||
810 | LOCK_REQ *pSMB = (LOCK_REQ *)in_buf; | ||
811 | |||
812 | /* We just modify the current in_buf to change | ||
813 | the type of lock from LOCKING_ANDX_SHARED_LOCK | ||
814 | or LOCKING_ANDX_EXCLUSIVE_LOCK to | ||
815 | LOCKING_ANDX_CANCEL_LOCK. */ | ||
816 | |||
817 | pSMB->LockType = LOCKING_ANDX_CANCEL_LOCK|LOCKING_ANDX_LARGE_FILES; | ||
818 | pSMB->Timeout = 0; | ||
819 | pSMB->hdr.Mid = GetNextMid(ses->server); | ||
820 | |||
821 | return SendReceive(xid, ses, in_buf, out_buf, | ||
822 | &bytes_returned, 0); | ||
823 | } | ||
811 | 824 | ||
812 | out_unlock: | 825 | int |
826 | SendReceiveBlockingLock(const unsigned int xid, struct cifsTconInfo *tcon, | ||
827 | struct smb_hdr *in_buf, struct smb_hdr *out_buf, | ||
828 | int *pbytes_returned) | ||
829 | { | ||
830 | int rc = 0; | ||
831 | int rstart = 0; | ||
832 | unsigned int receive_len; | ||
833 | struct mid_q_entry *midQ; | ||
834 | struct cifsSesInfo *ses; | ||
835 | |||
836 | if (tcon == NULL || tcon->ses == NULL) { | ||
837 | cERROR(1,("Null smb session")); | ||
838 | return -EIO; | ||
839 | } | ||
840 | ses = tcon->ses; | ||
841 | |||
842 | if(ses->server == NULL) { | ||
843 | cERROR(1,("Null tcp session")); | ||
844 | return -EIO; | ||
845 | } | ||
846 | |||
847 | if(ses->server->tcpStatus == CifsExiting) | ||
848 | return -ENOENT; | ||
849 | |||
850 | /* Ensure that we do not send more than 50 overlapping requests | ||
851 | to the same server. We may make this configurable later or | ||
852 | use ses->maxReq */ | ||
853 | |||
854 | rc = wait_for_free_request(ses, 3); | ||
855 | if (rc) | ||
856 | return rc; | ||
857 | |||
858 | /* make sure that we sign in the same order that we send on this socket | ||
859 | and avoid races inside tcp sendmsg code that could cause corruption | ||
860 | of smb data */ | ||
861 | |||
862 | down(&ses->server->tcpSem); | ||
863 | |||
864 | rc = allocate_mid(ses, in_buf, &midQ); | ||
865 | if (rc) { | ||
866 | up(&ses->server->tcpSem); | ||
867 | return rc; | ||
868 | } | ||
869 | |||
870 | if (in_buf->smb_buf_length > CIFSMaxBufSize + MAX_CIFS_HDR_SIZE - 4) { | ||
871 | up(&ses->server->tcpSem); | ||
872 | cERROR(1, ("Illegal length, greater than maximum frame, %d", | ||
873 | in_buf->smb_buf_length)); | ||
874 | DeleteMidQEntry(midQ); | ||
875 | return -EIO; | ||
876 | } | ||
877 | |||
878 | rc = cifs_sign_smb(in_buf, ses->server, &midQ->sequence_number); | ||
879 | |||
880 | midQ->midState = MID_REQUEST_SUBMITTED; | ||
881 | #ifdef CONFIG_CIFS_STATS2 | ||
882 | atomic_inc(&ses->server->inSend); | ||
883 | #endif | ||
884 | rc = smb_send(ses->server->ssocket, in_buf, in_buf->smb_buf_length, | ||
885 | (struct sockaddr *) &(ses->server->addr.sockAddr)); | ||
886 | #ifdef CONFIG_CIFS_STATS2 | ||
887 | atomic_dec(&ses->server->inSend); | ||
888 | midQ->when_sent = jiffies; | ||
889 | #endif | ||
813 | up(&ses->server->tcpSem); | 890 | up(&ses->server->tcpSem); |
814 | /* If not lock req, update # of requests on wire to server */ | 891 | |
815 | if(long_op < 3) { | 892 | if(rc < 0) { |
816 | atomic_dec(&ses->server->inFlight); | 893 | DeleteMidQEntry(midQ); |
817 | wake_up(&ses->server->request_q); | 894 | return rc; |
895 | } | ||
896 | |||
897 | /* Wait for a reply - allow signals to interrupt. */ | ||
898 | rc = wait_event_interruptible(ses->server->response_q, | ||
899 | (!(midQ->midState == MID_REQUEST_SUBMITTED)) || | ||
900 | ((ses->server->tcpStatus != CifsGood) && | ||
901 | (ses->server->tcpStatus != CifsNew))); | ||
902 | |||
903 | /* Were we interrupted by a signal ? */ | ||
904 | if ((rc == -ERESTARTSYS) && | ||
905 | (midQ->midState == MID_REQUEST_SUBMITTED) && | ||
906 | ((ses->server->tcpStatus == CifsGood) || | ||
907 | (ses->server->tcpStatus == CifsNew))) { | ||
908 | |||
909 | if (in_buf->Command == SMB_COM_TRANSACTION2) { | ||
910 | /* POSIX lock. We send a NT_CANCEL SMB to cause the | ||
911 | blocking lock to return. */ | ||
912 | |||
913 | rc = send_nt_cancel(tcon, in_buf, midQ); | ||
914 | if (rc) { | ||
915 | DeleteMidQEntry(midQ); | ||
916 | return rc; | ||
917 | } | ||
918 | } else { | ||
919 | /* Windows lock. We send a LOCKINGX_CANCEL_LOCK | ||
920 | to cause the blocking lock to return. */ | ||
921 | |||
922 | rc = send_lock_cancel(xid, tcon, in_buf, out_buf); | ||
923 | |||
924 | /* If we get -ENOLCK back the lock may have | ||
925 | already been removed. Don't exit in this case. */ | ||
926 | if (rc && rc != -ENOLCK) { | ||
927 | DeleteMidQEntry(midQ); | ||
928 | return rc; | ||
929 | } | ||
930 | } | ||
931 | |||
932 | /* Wait 5 seconds for the response. */ | ||
933 | if (wait_for_response(ses, midQ, 5 * HZ, 5 * HZ)==0) { | ||
934 | /* We got the response - restart system call. */ | ||
935 | rstart = 1; | ||
936 | } | ||
937 | } | ||
938 | |||
939 | spin_lock(&GlobalMid_Lock); | ||
940 | if (midQ->resp_buf) { | ||
941 | spin_unlock(&GlobalMid_Lock); | ||
942 | receive_len = midQ->resp_buf->smb_buf_length; | ||
943 | } else { | ||
944 | cERROR(1,("No response for cmd %d mid %d", | ||
945 | midQ->command, midQ->mid)); | ||
946 | if(midQ->midState == MID_REQUEST_SUBMITTED) { | ||
947 | if(ses->server->tcpStatus == CifsExiting) | ||
948 | rc = -EHOSTDOWN; | ||
949 | else { | ||
950 | ses->server->tcpStatus = CifsNeedReconnect; | ||
951 | midQ->midState = MID_RETRY_NEEDED; | ||
952 | } | ||
953 | } | ||
954 | |||
955 | if (rc != -EHOSTDOWN) { | ||
956 | if(midQ->midState == MID_RETRY_NEEDED) { | ||
957 | rc = -EAGAIN; | ||
958 | cFYI(1,("marking request for retry")); | ||
959 | } else { | ||
960 | rc = -EIO; | ||
961 | } | ||
962 | } | ||
963 | spin_unlock(&GlobalMid_Lock); | ||
964 | DeleteMidQEntry(midQ); | ||
965 | return rc; | ||
818 | } | 966 | } |
967 | |||
968 | if (receive_len > CIFSMaxBufSize + MAX_CIFS_HDR_SIZE) { | ||
969 | cERROR(1, ("Frame too large received. Length: %d Xid: %d", | ||
970 | receive_len, xid)); | ||
971 | rc = -EIO; | ||
972 | } else { /* rcvd frame is ok */ | ||
973 | |||
974 | if (midQ->resp_buf && out_buf | ||
975 | && (midQ->midState == MID_RESPONSE_RECEIVED)) { | ||
976 | out_buf->smb_buf_length = receive_len; | ||
977 | memcpy((char *)out_buf + 4, | ||
978 | (char *)midQ->resp_buf + 4, | ||
979 | receive_len); | ||
980 | |||
981 | dump_smb(out_buf, 92); | ||
982 | /* convert the length into a more usable form */ | ||
983 | if((receive_len > 24) && | ||
984 | (ses->server->secMode & (SECMODE_SIGN_REQUIRED | | ||
985 | SECMODE_SIGN_ENABLED))) { | ||
986 | rc = cifs_verify_signature(out_buf, | ||
987 | ses->server->mac_signing_key, | ||
988 | midQ->sequence_number+1); | ||
989 | if(rc) { | ||
990 | cERROR(1,("Unexpected SMB signature")); | ||
991 | /* BB FIXME add code to kill session */ | ||
992 | } | ||
993 | } | ||
994 | |||
995 | *pbytes_returned = out_buf->smb_buf_length; | ||
996 | |||
997 | /* BB special case reconnect tid and uid here? */ | ||
998 | rc = map_smb_to_linux_error(out_buf); | ||
819 | 999 | ||
1000 | /* convert ByteCount if necessary */ | ||
1001 | if (receive_len >= | ||
1002 | sizeof (struct smb_hdr) - | ||
1003 | 4 /* do not count RFC1001 header */ + | ||
1004 | (2 * out_buf->WordCount) + 2 /* bcc */ ) | ||
1005 | BCC(out_buf) = le16_to_cpu(BCC_LE(out_buf)); | ||
1006 | } else { | ||
1007 | rc = -EIO; | ||
1008 | cERROR(1,("Bad MID state?")); | ||
1009 | } | ||
1010 | } | ||
1011 | DeleteMidQEntry(midQ); | ||
1012 | if (rstart && rc == -EACCES) | ||
1013 | return -ERESTARTSYS; | ||
820 | return rc; | 1014 | return rc; |
821 | } | 1015 | } |
diff --git a/fs/cifs/xattr.c b/fs/cifs/xattr.c index 7754d641775e..18fcec190f8b 100644 --- a/fs/cifs/xattr.c +++ b/fs/cifs/xattr.c | |||
@@ -269,7 +269,7 @@ ssize_t cifs_getxattr(struct dentry * direntry, const char * ea_name, | |||
269 | rc = CIFSSMBGetCIFSACL(xid, pTcon, fid, | 269 | rc = CIFSSMBGetCIFSACL(xid, pTcon, fid, |
270 | ea_value, buf_size, | 270 | ea_value, buf_size, |
271 | ACL_TYPE_ACCESS); | 271 | ACL_TYPE_ACCESS); |
272 | CIFSSMBClose(xid, pTcon, fid) | 272 | CIFSSMBClose(xid, pTcon, fid); |
273 | } | 273 | } |
274 | } */ /* BB enable after fixing up return data */ | 274 | } */ /* BB enable after fixing up return data */ |
275 | 275 | ||
@@ -330,11 +330,15 @@ ssize_t cifs_listxattr(struct dentry * direntry, char * data, size_t buf_size) | |||
330 | sb = direntry->d_inode->i_sb; | 330 | sb = direntry->d_inode->i_sb; |
331 | if(sb == NULL) | 331 | if(sb == NULL) |
332 | return -EIO; | 332 | return -EIO; |
333 | xid = GetXid(); | ||
334 | 333 | ||
335 | cifs_sb = CIFS_SB(sb); | 334 | cifs_sb = CIFS_SB(sb); |
336 | pTcon = cifs_sb->tcon; | 335 | pTcon = cifs_sb->tcon; |
337 | 336 | ||
337 | if(cifs_sb->mnt_cifs_flags & CIFS_MOUNT_NO_XATTR) | ||
338 | return -EOPNOTSUPP; | ||
339 | |||
340 | xid = GetXid(); | ||
341 | |||
338 | full_path = build_path_from_dentry(direntry); | 342 | full_path = build_path_from_dentry(direntry); |
339 | if(full_path == NULL) { | 343 | if(full_path == NULL) { |
340 | FreeXid(xid); | 344 | FreeXid(xid); |