diff options
author | Jeremy Allison <jra@samba.org> | 2005-06-22 20:26:35 -0400 |
---|---|---|
committer | Steve French <sfrench@hera.kernel.org> | 2005-06-22 20:26:35 -0400 |
commit | ac67055ef2378ea95c34b593ddf9d0a0737a240a (patch) | |
tree | 78f76cde63f158b318a57a3972a77731d8fb0ef6 | |
parent | dfb7533b5f157ac7135da23883e80d895227d965 (diff) |
[CIFS] POSIX extensions, SetFSInfo added
Signed-off-by: Steve French@sfrench@us.ibm.com
Signed-off-by: Jeremy Allison (jra@samba.org)
-rw-r--r-- | fs/cifs/cifs_fs_sb.h | 1 | ||||
-rw-r--r-- | fs/cifs/cifsglob.h | 7 | ||||
-rw-r--r-- | fs/cifs/cifspdu.h | 46 | ||||
-rw-r--r-- | fs/cifs/cifsproto.h | 7 | ||||
-rw-r--r-- | fs/cifs/cifssmb.c | 77 | ||||
-rw-r--r-- | fs/cifs/connect.c | 20 | ||||
-rw-r--r-- | fs/cifs/dir.c | 10 | ||||
-rw-r--r-- | fs/cifs/fcntl.c | 2 | ||||
-rw-r--r-- | fs/cifs/file.c | 4 | ||||
-rw-r--r-- | fs/cifs/inode.c | 14 | ||||
-rw-r--r-- | fs/cifs/link.c | 15 | ||||
-rw-r--r-- | fs/cifs/readdir.c | 4 | ||||
-rw-r--r-- | fs/cifs/xattr.c | 8 |
13 files changed, 182 insertions, 33 deletions
diff --git a/fs/cifs/cifs_fs_sb.h b/fs/cifs/cifs_fs_sb.h index ec00d61d5308..5dc5fe6b486d 100644 --- a/fs/cifs/cifs_fs_sb.h +++ b/fs/cifs/cifs_fs_sb.h | |||
@@ -24,6 +24,7 @@ | |||
24 | #define CIFS_MOUNT_DIRECT_IO 8 /* do not write nor read through page cache */ | 24 | #define CIFS_MOUNT_DIRECT_IO 8 /* do not write nor read through page cache */ |
25 | #define CIFS_MOUNT_NO_XATTR 0x10 /* if set - disable xattr support */ | 25 | #define CIFS_MOUNT_NO_XATTR 0x10 /* if set - disable xattr support */ |
26 | #define CIFS_MOUNT_MAP_SPECIAL_CHR 0x20 /* remap illegal chars in filenames */ | 26 | #define CIFS_MOUNT_MAP_SPECIAL_CHR 0x20 /* remap illegal chars in filenames */ |
27 | #define CIFS_MOUNT_POSIX_PATHS 0x40 /* Negotiate posix pathnames if possible. */ | ||
27 | 28 | ||
28 | struct cifs_sb_info { | 29 | struct cifs_sb_info { |
29 | struct cifsTconInfo *tcon; /* primary mount */ | 30 | struct cifsTconInfo *tcon; /* primary mount */ |
diff --git a/fs/cifs/cifsglob.h b/fs/cifs/cifsglob.h index 4ed9c13fff55..d3773e57acf9 100644 --- a/fs/cifs/cifsglob.h +++ b/fs/cifs/cifsglob.h | |||
@@ -309,6 +309,13 @@ CIFS_SB(struct super_block *sb) | |||
309 | return sb->s_fs_info; | 309 | return sb->s_fs_info; |
310 | } | 310 | } |
311 | 311 | ||
312 | static inline const char CIFS_DIR_SEP(const struct cifs_sb_info *cifs_sb) | ||
313 | { | ||
314 | if (cifs_sb->mnt_cifs_flags & CIFS_MOUNT_POSIX_PATHS) | ||
315 | return '/'; | ||
316 | else | ||
317 | return '\\'; | ||
318 | } | ||
312 | 319 | ||
313 | /* one of these for every pending CIFS request to the server */ | 320 | /* one of these for every pending CIFS request to the server */ |
314 | struct mid_q_entry { | 321 | struct mid_q_entry { |
diff --git a/fs/cifs/cifspdu.h b/fs/cifs/cifspdu.h index aede6a813167..84d37f8e986e 100644 --- a/fs/cifs/cifspdu.h +++ b/fs/cifs/cifspdu.h | |||
@@ -59,6 +59,7 @@ | |||
59 | #define TRANS2_FIND_FIRST 0x01 | 59 | #define TRANS2_FIND_FIRST 0x01 |
60 | #define TRANS2_FIND_NEXT 0x02 | 60 | #define TRANS2_FIND_NEXT 0x02 |
61 | #define TRANS2_QUERY_FS_INFORMATION 0x03 | 61 | #define TRANS2_QUERY_FS_INFORMATION 0x03 |
62 | #define TRANS2_SET_FS_INFORMATION 0x04 | ||
62 | #define TRANS2_QUERY_PATH_INFORMATION 0x05 | 63 | #define TRANS2_QUERY_PATH_INFORMATION 0x05 |
63 | #define TRANS2_SET_PATH_INFORMATION 0x06 | 64 | #define TRANS2_SET_PATH_INFORMATION 0x06 |
64 | #define TRANS2_QUERY_FILE_INFORMATION 0x07 | 65 | #define TRANS2_QUERY_FILE_INFORMATION 0x07 |
@@ -1411,6 +1412,43 @@ typedef struct smb_com_transaction_qfsi_rsp { | |||
1411 | __u8 Pad; /* may be three bytes *//* followed by data area */ | 1412 | __u8 Pad; /* may be three bytes *//* followed by data area */ |
1412 | } TRANSACTION2_QFSI_RSP; | 1413 | } TRANSACTION2_QFSI_RSP; |
1413 | 1414 | ||
1415 | |||
1416 | /* SETFSInfo Levels */ | ||
1417 | #define SMB_SET_CIFS_UNIX_INFO 0x200 | ||
1418 | typedef struct smb_com_transaction2_setfsi_req { | ||
1419 | struct smb_hdr hdr; /* wct = 15 */ | ||
1420 | __le16 TotalParameterCount; | ||
1421 | __le16 TotalDataCount; | ||
1422 | __le16 MaxParameterCount; | ||
1423 | __le16 MaxDataCount; | ||
1424 | __u8 MaxSetupCount; | ||
1425 | __u8 Reserved; | ||
1426 | __le16 Flags; | ||
1427 | __le32 Timeout; | ||
1428 | __u16 Reserved2; | ||
1429 | __le16 ParameterCount; /* 4 */ | ||
1430 | __le16 ParameterOffset; | ||
1431 | __le16 DataCount; /* 12 */ | ||
1432 | __le16 DataOffset; | ||
1433 | __u8 SetupCount; /* one */ | ||
1434 | __u8 Reserved3; | ||
1435 | __le16 SubCommand; /* TRANS2_SET_FS_INFORMATION */ | ||
1436 | __le16 ByteCount; | ||
1437 | __u8 Pad; | ||
1438 | __u16 FileNum; /* Parameters start. */ | ||
1439 | __le16 InformationLevel;/* Parameters end. */ | ||
1440 | __le16 ClientUnixMajor; /* Data start. */ | ||
1441 | __le16 ClientUnixMinor; | ||
1442 | __le64 ClientUnixCap; /* Data end */ | ||
1443 | } TRANSACTION2_SETFSI_REQ; | ||
1444 | |||
1445 | typedef struct smb_com_transaction2_setfsi_rsp { | ||
1446 | struct smb_hdr hdr; /* wct = 10 */ | ||
1447 | struct trans2_resp t2; | ||
1448 | __u16 ByteCount; | ||
1449 | } TRANSACTION2_SETFSI_RSP; | ||
1450 | |||
1451 | |||
1414 | typedef struct smb_com_transaction2_get_dfs_refer_req { | 1452 | typedef struct smb_com_transaction2_get_dfs_refer_req { |
1415 | struct smb_hdr hdr; /* wct = 15 */ | 1453 | struct smb_hdr hdr; /* wct = 15 */ |
1416 | __le16 TotalParameterCount; | 1454 | __le16 TotalParameterCount; |
@@ -1551,12 +1589,20 @@ typedef struct { | |||
1551 | __le16 MinorVersionNumber; | 1589 | __le16 MinorVersionNumber; |
1552 | __le64 Capability; | 1590 | __le64 Capability; |
1553 | } FILE_SYSTEM_UNIX_INFO; /* Unix extensions info, level 0x200 */ | 1591 | } FILE_SYSTEM_UNIX_INFO; /* Unix extensions info, level 0x200 */ |
1592 | |||
1593 | /* Version numbers for CIFS UNIX major and minor. */ | ||
1594 | #define CIFS_UNIX_MAJOR_VERSION 1 | ||
1595 | #define CIFS_UNIX_MINOR_VERSION 0 | ||
1596 | |||
1554 | /* Linux/Unix extensions capability flags */ | 1597 | /* Linux/Unix extensions capability flags */ |
1555 | #define CIFS_UNIX_FCNTL_CAP 0x00000001 /* support for fcntl locks */ | 1598 | #define CIFS_UNIX_FCNTL_CAP 0x00000001 /* support for fcntl locks */ |
1556 | #define CIFS_UNIX_POSIX_ACL_CAP 0x00000002 /* support getfacl/setfacl */ | 1599 | #define CIFS_UNIX_POSIX_ACL_CAP 0x00000002 /* support getfacl/setfacl */ |
1557 | #define CIFS_UNIX_XATTR_CAP 0x00000004 /* support new namespace */ | 1600 | #define CIFS_UNIX_XATTR_CAP 0x00000004 /* support new namespace */ |
1558 | #define CIFS_UNIX_EXTATTR_CAP 0x00000008 /* support chattr/chflag */ | 1601 | #define CIFS_UNIX_EXTATTR_CAP 0x00000008 /* support chattr/chflag */ |
1602 | #define CIFS_UNIX_POSIX_PATHNAMES_CAP 0x00000010 /* Use POSIX pathnames on the wire. */ | ||
1603 | |||
1559 | #define CIFS_POSIX_EXTENSIONS 0x00000010 /* support for new QFSInfo */ | 1604 | #define CIFS_POSIX_EXTENSIONS 0x00000010 /* support for new QFSInfo */ |
1605 | |||
1560 | typedef struct { | 1606 | typedef struct { |
1561 | /* For undefined recommended transfer size return -1 in that field */ | 1607 | /* For undefined recommended transfer size return -1 in that field */ |
1562 | __le32 OptimalTransferSize; /* bsize on some os, iosize on other os */ | 1608 | __le32 OptimalTransferSize; /* bsize on some os, iosize on other os */ |
diff --git a/fs/cifs/cifsproto.h b/fs/cifs/cifsproto.h index ea239dea571e..db2adf0b206c 100644 --- a/fs/cifs/cifsproto.h +++ b/fs/cifs/cifsproto.h | |||
@@ -40,7 +40,7 @@ extern unsigned int _GetXid(void); | |||
40 | extern void _FreeXid(unsigned int); | 40 | extern void _FreeXid(unsigned int); |
41 | #define GetXid() (int)_GetXid(); cFYI(1,("CIFS VFS: in %s as Xid: %d with uid: %d",__FUNCTION__, xid,current->fsuid)); | 41 | #define GetXid() (int)_GetXid(); cFYI(1,("CIFS VFS: in %s as Xid: %d with uid: %d",__FUNCTION__, xid,current->fsuid)); |
42 | #define FreeXid(curr_xid) {_FreeXid(curr_xid); cFYI(1,("CIFS VFS: leaving %s (xid = %d) rc = %d",__FUNCTION__,curr_xid,(int)rc));} | 42 | #define FreeXid(curr_xid) {_FreeXid(curr_xid); cFYI(1,("CIFS VFS: leaving %s (xid = %d) rc = %d",__FUNCTION__,curr_xid,(int)rc));} |
43 | extern char *build_path_from_dentry(struct dentry *); | 43 | extern char *build_path_from_dentry(struct dentry *, const struct cifs_sb_info *cifs_sb); |
44 | extern char *build_wildcard_path_from_dentry(struct dentry *direntry); | 44 | extern char *build_wildcard_path_from_dentry(struct dentry *direntry); |
45 | extern void renew_parental_timestamps(struct dentry *direntry); | 45 | extern void renew_parental_timestamps(struct dentry *direntry); |
46 | extern int SendReceive(const unsigned int /* xid */ , struct cifsSesInfo *, | 46 | extern int SendReceive(const unsigned int /* xid */ , struct cifsSesInfo *, |
@@ -89,7 +89,7 @@ extern int CIFSTCon(unsigned int xid, struct cifsSesInfo *ses, | |||
89 | 89 | ||
90 | extern int CIFSFindFirst(const int xid, struct cifsTconInfo *tcon, | 90 | extern int CIFSFindFirst(const int xid, struct cifsTconInfo *tcon, |
91 | const char *searchName, const struct nls_table *nls_codepage, | 91 | const char *searchName, const struct nls_table *nls_codepage, |
92 | __u16 *searchHandle, struct cifs_search_info * psrch_inf, int map); | 92 | __u16 *searchHandle, struct cifs_search_info * psrch_inf, int map, const char dirsep); |
93 | 93 | ||
94 | extern int CIFSFindNext(const int xid, struct cifsTconInfo *tcon, | 94 | extern int CIFSFindNext(const int xid, struct cifsTconInfo *tcon, |
95 | __u16 searchHandle, struct cifs_search_info * psrch_inf); | 95 | __u16 searchHandle, struct cifs_search_info * psrch_inf); |
@@ -125,6 +125,9 @@ extern int get_dfs_path(int xid, struct cifsSesInfo *pSesInfo, | |||
125 | int remap); | 125 | int remap); |
126 | extern int CIFSSMBQFSInfo(const int xid, struct cifsTconInfo *tcon, | 126 | extern int CIFSSMBQFSInfo(const int xid, struct cifsTconInfo *tcon, |
127 | struct kstatfs *FSData); | 127 | struct kstatfs *FSData); |
128 | extern int CIFSSMBSETFSUnixInfo(const int xid, struct cifsTconInfo *tcon, | ||
129 | __u64 cap); | ||
130 | |||
128 | extern int CIFSSMBQFSAttributeInfo(const int xid, | 131 | extern int CIFSSMBQFSAttributeInfo(const int xid, |
129 | struct cifsTconInfo *tcon); | 132 | struct cifsTconInfo *tcon); |
130 | extern int CIFSSMBQFSDeviceInfo(const int xid, struct cifsTconInfo *tcon); | 133 | extern int CIFSSMBQFSDeviceInfo(const int xid, struct cifsTconInfo *tcon); |
diff --git a/fs/cifs/cifssmb.c b/fs/cifs/cifssmb.c index b31158a2643d..81c9d3f393f5 100644 --- a/fs/cifs/cifssmb.c +++ b/fs/cifs/cifssmb.c | |||
@@ -2416,7 +2416,7 @@ CIFSFindFirst(const int xid, struct cifsTconInfo *tcon, | |||
2416 | const char *searchName, | 2416 | const char *searchName, |
2417 | const struct nls_table *nls_codepage, | 2417 | const struct nls_table *nls_codepage, |
2418 | __u16 * pnetfid, | 2418 | __u16 * pnetfid, |
2419 | struct cifs_search_info * psrch_inf, int remap) | 2419 | struct cifs_search_info * psrch_inf, int remap, const char dirsep) |
2420 | { | 2420 | { |
2421 | /* level 257 SMB_ */ | 2421 | /* level 257 SMB_ */ |
2422 | TRANSACTION2_FFIRST_REQ *pSMB = NULL; | 2422 | TRANSACTION2_FFIRST_REQ *pSMB = NULL; |
@@ -2443,7 +2443,7 @@ findFirstRetry: | |||
2443 | it got remapped to 0xF03A as if it were part of the | 2443 | it got remapped to 0xF03A as if it were part of the |
2444 | directory name instead of a wildcard */ | 2444 | directory name instead of a wildcard */ |
2445 | name_len *= 2; | 2445 | name_len *= 2; |
2446 | pSMB->FileName[name_len] = '\\'; | 2446 | pSMB->FileName[name_len] = dirsep; |
2447 | pSMB->FileName[name_len+1] = 0; | 2447 | pSMB->FileName[name_len+1] = 0; |
2448 | pSMB->FileName[name_len+2] = '*'; | 2448 | pSMB->FileName[name_len+2] = '*'; |
2449 | pSMB->FileName[name_len+3] = 0; | 2449 | pSMB->FileName[name_len+3] = 0; |
@@ -2457,7 +2457,7 @@ findFirstRetry: | |||
2457 | if(name_len > buffersize-header) | 2457 | if(name_len > buffersize-header) |
2458 | free buffer exit; BB */ | 2458 | free buffer exit; BB */ |
2459 | strncpy(pSMB->FileName, searchName, name_len); | 2459 | strncpy(pSMB->FileName, searchName, name_len); |
2460 | pSMB->FileName[name_len] = '\\'; | 2460 | pSMB->FileName[name_len] = dirsep; |
2461 | pSMB->FileName[name_len+1] = '*'; | 2461 | pSMB->FileName[name_len+1] = '*'; |
2462 | pSMB->FileName[name_len+2] = 0; | 2462 | pSMB->FileName[name_len+2] = 0; |
2463 | name_len += 3; | 2463 | name_len += 3; |
@@ -3265,6 +3265,77 @@ QFSUnixRetry: | |||
3265 | return rc; | 3265 | return rc; |
3266 | } | 3266 | } |
3267 | 3267 | ||
3268 | int | ||
3269 | CIFSSMBSETFSUnixInfo(const int xid, struct cifsTconInfo *tcon, __u64 cap) | ||
3270 | { | ||
3271 | /* level 0x200 SMB_SET_CIFS_UNIX_INFO */ | ||
3272 | TRANSACTION2_SETFSI_REQ *pSMB = NULL; | ||
3273 | TRANSACTION2_SETFSI_RSP *pSMBr = NULL; | ||
3274 | int rc = 0; | ||
3275 | int bytes_returned = 0; | ||
3276 | __u16 params, param_offset, offset, byte_count; | ||
3277 | |||
3278 | cFYI(1, ("In SETFSUnixInfo")); | ||
3279 | SETFSUnixRetry: | ||
3280 | rc = smb_init(SMB_COM_TRANSACTION2, 15, tcon, (void **) &pSMB, | ||
3281 | (void **) &pSMBr); | ||
3282 | if (rc) | ||
3283 | return rc; | ||
3284 | |||
3285 | params = 4; /* 2 bytes zero followed by info level. */ | ||
3286 | pSMB->MaxSetupCount = 0; | ||
3287 | pSMB->Reserved = 0; | ||
3288 | pSMB->Flags = 0; | ||
3289 | pSMB->Timeout = 0; | ||
3290 | pSMB->Reserved2 = 0; | ||
3291 | param_offset = offsetof(struct smb_com_transaction2_setfsi_req, FileNum) - 4; | ||
3292 | offset = param_offset + params; | ||
3293 | |||
3294 | pSMB->MaxParameterCount = cpu_to_le16(4); | ||
3295 | pSMB->MaxDataCount = cpu_to_le16(100); /* BB find exact max SMB PDU from sess structure BB */ | ||
3296 | pSMB->SetupCount = 1; | ||
3297 | pSMB->Reserved3 = 0; | ||
3298 | pSMB->SubCommand = cpu_to_le16(TRANS2_SET_FS_INFORMATION); | ||
3299 | byte_count = 1 /* pad */ + params + 12; | ||
3300 | |||
3301 | pSMB->DataCount = cpu_to_le16(12); | ||
3302 | pSMB->ParameterCount = cpu_to_le16(params); | ||
3303 | pSMB->TotalDataCount = pSMB->DataCount; | ||
3304 | pSMB->TotalParameterCount = pSMB->ParameterCount; | ||
3305 | pSMB->ParameterOffset = cpu_to_le16(param_offset); | ||
3306 | pSMB->DataOffset = cpu_to_le16(offset); | ||
3307 | |||
3308 | /* Params. */ | ||
3309 | pSMB->FileNum = 0; | ||
3310 | pSMB->InformationLevel = cpu_to_le16(SMB_SET_CIFS_UNIX_INFO); | ||
3311 | |||
3312 | /* Data. */ | ||
3313 | pSMB->ClientUnixMajor = cpu_to_le16(CIFS_UNIX_MAJOR_VERSION); | ||
3314 | pSMB->ClientUnixMinor = cpu_to_le16(CIFS_UNIX_MINOR_VERSION); | ||
3315 | pSMB->ClientUnixCap = cpu_to_le64(cap); | ||
3316 | |||
3317 | pSMB->hdr.smb_buf_length += byte_count; | ||
3318 | pSMB->ByteCount = cpu_to_le16(byte_count); | ||
3319 | |||
3320 | rc = SendReceive(xid, tcon->ses, (struct smb_hdr *) pSMB, | ||
3321 | (struct smb_hdr *) pSMBr, &bytes_returned, 0); | ||
3322 | if (rc) { | ||
3323 | cERROR(1, ("Send error in SETFSUnixInfo = %d", rc)); | ||
3324 | } else { /* decode response */ | ||
3325 | rc = validate_t2((struct smb_t2_rsp *)pSMBr); | ||
3326 | if (rc) { | ||
3327 | rc = -EIO; /* bad smb */ | ||
3328 | } | ||
3329 | } | ||
3330 | cifs_buf_release(pSMB); | ||
3331 | |||
3332 | if (rc == -EAGAIN) | ||
3333 | goto SETFSUnixRetry; | ||
3334 | |||
3335 | return rc; | ||
3336 | } | ||
3337 | |||
3338 | |||
3268 | 3339 | ||
3269 | int | 3340 | int |
3270 | CIFSSMBQFSPosixInfo(const int xid, struct cifsTconInfo *tcon, | 3341 | CIFSSMBQFSPosixInfo(const int xid, struct cifsTconInfo *tcon, |
diff --git a/fs/cifs/connect.c b/fs/cifs/connect.c index e568cc47a7f9..bef5d6f30975 100644 --- a/fs/cifs/connect.c +++ b/fs/cifs/connect.c | |||
@@ -74,6 +74,7 @@ struct smb_vol { | |||
74 | unsigned server_ino:1; /* use inode numbers from server ie UniqueId */ | 74 | unsigned server_ino:1; /* use inode numbers from server ie UniqueId */ |
75 | unsigned direct_io:1; | 75 | unsigned direct_io:1; |
76 | unsigned remap:1; /* set to remap seven reserved chars in filenames */ | 76 | unsigned remap:1; /* set to remap seven reserved chars in filenames */ |
77 | unsigned posix_paths:1; /* unset to not ask for posix pathnames. */ | ||
77 | unsigned int rsize; | 78 | unsigned int rsize; |
78 | unsigned int wsize; | 79 | unsigned int wsize; |
79 | unsigned int sockopt; | 80 | unsigned int sockopt; |
@@ -745,6 +746,9 @@ cifs_parse_mount_options(char *options, const char *devname,struct smb_vol *vol) | |||
745 | /* vol->retry default is 0 (i.e. "soft" limited retry not hard retry) */ | 746 | /* vol->retry default is 0 (i.e. "soft" limited retry not hard retry) */ |
746 | vol->rw = TRUE; | 747 | vol->rw = TRUE; |
747 | 748 | ||
749 | /* default is always to request posix paths. */ | ||
750 | vol->posix_paths = 1; | ||
751 | |||
748 | if (!options) | 752 | if (!options) |
749 | return 1; | 753 | return 1; |
750 | 754 | ||
@@ -1023,6 +1027,10 @@ cifs_parse_mount_options(char *options, const char *devname,struct smb_vol *vol) | |||
1023 | vol->remap = 1; | 1027 | vol->remap = 1; |
1024 | } else if (strnicmp(data, "nomapchars", 10) == 0) { | 1028 | } else if (strnicmp(data, "nomapchars", 10) == 0) { |
1025 | vol->remap = 0; | 1029 | vol->remap = 0; |
1030 | } else if (strnicmp(data, "posixpaths", 10) == 0) { | ||
1031 | vol->posix_paths = 1; | ||
1032 | } else if (strnicmp(data, "noposixpaths", 12) == 0) { | ||
1033 | vol->posix_paths = 0; | ||
1026 | } else if (strnicmp(data, "setuids", 7) == 0) { | 1034 | } else if (strnicmp(data, "setuids", 7) == 0) { |
1027 | vol->setuids = 1; | 1035 | vol->setuids = 1; |
1028 | } else if (strnicmp(data, "nosetuids", 9) == 0) { | 1036 | } else if (strnicmp(data, "nosetuids", 9) == 0) { |
@@ -1679,6 +1687,7 @@ cifs_mount(struct super_block *sb, struct cifs_sb_info *cifs_sb, | |||
1679 | cifs_sb->mnt_cifs_flags |= CIFS_MOUNT_MAP_SPECIAL_CHR; | 1687 | cifs_sb->mnt_cifs_flags |= CIFS_MOUNT_MAP_SPECIAL_CHR; |
1680 | if(volume_info.no_xattr) | 1688 | if(volume_info.no_xattr) |
1681 | cifs_sb->mnt_cifs_flags |= CIFS_MOUNT_NO_XATTR; | 1689 | cifs_sb->mnt_cifs_flags |= CIFS_MOUNT_NO_XATTR; |
1690 | |||
1682 | if(volume_info.direct_io) { | 1691 | if(volume_info.direct_io) { |
1683 | cERROR(1,("mounting share using direct i/o")); | 1692 | cERROR(1,("mounting share using direct i/o")); |
1684 | cifs_sb->mnt_cifs_flags |= CIFS_MOUNT_DIRECT_IO; | 1693 | cifs_sb->mnt_cifs_flags |= CIFS_MOUNT_DIRECT_IO; |
@@ -1781,6 +1790,17 @@ cifs_mount(struct super_block *sb, struct cifs_sb_info *cifs_sb, | |||
1781 | cFYI(1,("server negotiated posix acl support")); | 1790 | cFYI(1,("server negotiated posix acl support")); |
1782 | sb->s_flags |= MS_POSIXACL; | 1791 | sb->s_flags |= MS_POSIXACL; |
1783 | } | 1792 | } |
1793 | |||
1794 | /* Try and negotiate POSIX pathnames if we can. */ | ||
1795 | if (volume_info.posix_paths && (CIFS_UNIX_POSIX_PATHNAMES_CAP & | ||
1796 | le64_to_cpu(tcon->fsUnixInfo.Capability))) { | ||
1797 | if (!CIFSSMBSETFSUnixInfo(xid, tcon, CIFS_UNIX_POSIX_PATHNAMES_CAP, 0)) { | ||
1798 | cFYI(1,("negotiated posix pathnames support")); | ||
1799 | cifs_sb->mnt_cifs_flags |= CIFS_MOUNT_POSIX_PATHS; | ||
1800 | } else { | ||
1801 | cFYI(1,("posix pathnames support requested but not supported")); | ||
1802 | } | ||
1803 | } | ||
1784 | } | 1804 | } |
1785 | } | 1805 | } |
1786 | } | 1806 | } |
diff --git a/fs/cifs/dir.c b/fs/cifs/dir.c index 3f3538d4a1fa..9360d8fb9ef7 100644 --- a/fs/cifs/dir.c +++ b/fs/cifs/dir.c | |||
@@ -43,7 +43,7 @@ renew_parental_timestamps(struct dentry *direntry) | |||
43 | 43 | ||
44 | /* Note: caller must free return buffer */ | 44 | /* Note: caller must free return buffer */ |
45 | char * | 45 | char * |
46 | build_path_from_dentry(struct dentry *direntry) | 46 | build_path_from_dentry(struct dentry *direntry, const struct cifs_sb_info *cifs_sb) |
47 | { | 47 | { |
48 | struct dentry *temp; | 48 | struct dentry *temp; |
49 | int namelen = 0; | 49 | int namelen = 0; |
@@ -74,7 +74,7 @@ cifs_bp_rename_retry: | |||
74 | if (namelen < 0) { | 74 | if (namelen < 0) { |
75 | break; | 75 | break; |
76 | } else { | 76 | } else { |
77 | full_path[namelen] = '\\'; | 77 | full_path[namelen] = CIFS_DIR_SEP(cifs_sb); |
78 | strncpy(full_path + namelen + 1, temp->d_name.name, | 78 | strncpy(full_path + namelen + 1, temp->d_name.name, |
79 | temp->d_name.len); | 79 | temp->d_name.len); |
80 | cFYI(0, (" name: %s ", full_path + namelen)); | 80 | cFYI(0, (" name: %s ", full_path + namelen)); |
@@ -138,7 +138,7 @@ cifs_create(struct inode *inode, struct dentry *direntry, int mode, | |||
138 | pTcon = cifs_sb->tcon; | 138 | pTcon = cifs_sb->tcon; |
139 | 139 | ||
140 | down(&direntry->d_sb->s_vfs_rename_sem); | 140 | down(&direntry->d_sb->s_vfs_rename_sem); |
141 | full_path = build_path_from_dentry(direntry); | 141 | full_path = build_path_from_dentry(direntry, cifs_sb); |
142 | up(&direntry->d_sb->s_vfs_rename_sem); | 142 | up(&direntry->d_sb->s_vfs_rename_sem); |
143 | if(full_path == NULL) { | 143 | if(full_path == NULL) { |
144 | FreeXid(xid); | 144 | FreeXid(xid); |
@@ -299,7 +299,7 @@ int cifs_mknod(struct inode *inode, struct dentry *direntry, int mode, dev_t dev | |||
299 | pTcon = cifs_sb->tcon; | 299 | pTcon = cifs_sb->tcon; |
300 | 300 | ||
301 | down(&direntry->d_sb->s_vfs_rename_sem); | 301 | down(&direntry->d_sb->s_vfs_rename_sem); |
302 | full_path = build_path_from_dentry(direntry); | 302 | full_path = build_path_from_dentry(direntry, cifs_sb); |
303 | up(&direntry->d_sb->s_vfs_rename_sem); | 303 | up(&direntry->d_sb->s_vfs_rename_sem); |
304 | if(full_path == NULL) | 304 | if(full_path == NULL) |
305 | rc = -ENOMEM; | 305 | rc = -ENOMEM; |
@@ -360,7 +360,7 @@ cifs_lookup(struct inode *parent_dir_inode, struct dentry *direntry, struct name | |||
360 | /* can not grab the rename sem here since it would | 360 | /* can not grab the rename sem here since it would |
361 | deadlock in the cases (beginning of sys_rename itself) | 361 | deadlock in the cases (beginning of sys_rename itself) |
362 | in which we already have the sb rename sem */ | 362 | in which we already have the sb rename sem */ |
363 | full_path = build_path_from_dentry(direntry); | 363 | full_path = build_path_from_dentry(direntry, cifs_sb); |
364 | if(full_path == NULL) { | 364 | if(full_path == NULL) { |
365 | FreeXid(xid); | 365 | FreeXid(xid); |
366 | return ERR_PTR(-ENOMEM); | 366 | return ERR_PTR(-ENOMEM); |
diff --git a/fs/cifs/fcntl.c b/fs/cifs/fcntl.c index 7d2a9202c39a..d47ce7f49dc3 100644 --- a/fs/cifs/fcntl.c +++ b/fs/cifs/fcntl.c | |||
@@ -83,7 +83,7 @@ int cifs_dir_notify(struct file * file, unsigned long arg) | |||
83 | pTcon = cifs_sb->tcon; | 83 | pTcon = cifs_sb->tcon; |
84 | 84 | ||
85 | down(&file->f_dentry->d_sb->s_vfs_rename_sem); | 85 | down(&file->f_dentry->d_sb->s_vfs_rename_sem); |
86 | full_path = build_path_from_dentry(file->f_dentry); | 86 | full_path = build_path_from_dentry(file->f_dentry, cifs_sb); |
87 | up(&file->f_dentry->d_sb->s_vfs_rename_sem); | 87 | up(&file->f_dentry->d_sb->s_vfs_rename_sem); |
88 | 88 | ||
89 | if(full_path == NULL) { | 89 | if(full_path == NULL) { |
diff --git a/fs/cifs/file.c b/fs/cifs/file.c index 30ab70ce5547..8dd11fecaaca 100644 --- a/fs/cifs/file.c +++ b/fs/cifs/file.c | |||
@@ -196,7 +196,7 @@ int cifs_open(struct inode *inode, struct file *file) | |||
196 | } | 196 | } |
197 | 197 | ||
198 | down(&inode->i_sb->s_vfs_rename_sem); | 198 | down(&inode->i_sb->s_vfs_rename_sem); |
199 | full_path = build_path_from_dentry(file->f_dentry); | 199 | full_path = build_path_from_dentry(file->f_dentry, cifs_sb); |
200 | up(&inode->i_sb->s_vfs_rename_sem); | 200 | up(&inode->i_sb->s_vfs_rename_sem); |
201 | if (full_path == NULL) { | 201 | if (full_path == NULL) { |
202 | FreeXid(xid); | 202 | FreeXid(xid); |
@@ -359,7 +359,7 @@ static int cifs_reopen_file(struct inode *inode, struct file *file, | |||
359 | those that already have the rename sem can end up causing writepage | 359 | those that already have the rename sem can end up causing writepage |
360 | to get called and if the server was down that means we end up here, | 360 | to get called and if the server was down that means we end up here, |
361 | and we can never tell if the caller already has the rename_sem */ | 361 | and we can never tell if the caller already has the rename_sem */ |
362 | full_path = build_path_from_dentry(file->f_dentry); | 362 | full_path = build_path_from_dentry(file->f_dentry, cifs_sb); |
363 | if (full_path == NULL) { | 363 | if (full_path == NULL) { |
364 | up(&pCifsFile->fh_sem); | 364 | up(&pCifsFile->fh_sem); |
365 | FreeXid(xid); | 365 | FreeXid(xid); |
diff --git a/fs/cifs/inode.c b/fs/cifs/inode.c index 8d336a900255..95354da606d6 100644 --- a/fs/cifs/inode.c +++ b/fs/cifs/inode.c | |||
@@ -412,7 +412,7 @@ int cifs_unlink(struct inode *inode, struct dentry *direntry) | |||
412 | /* Unlink can be called from rename so we can not grab the sem here | 412 | /* Unlink can be called from rename so we can not grab the sem here |
413 | since we deadlock otherwise */ | 413 | since we deadlock otherwise */ |
414 | /* down(&direntry->d_sb->s_vfs_rename_sem);*/ | 414 | /* down(&direntry->d_sb->s_vfs_rename_sem);*/ |
415 | full_path = build_path_from_dentry(direntry); | 415 | full_path = build_path_from_dentry(direntry, cifs_sb); |
416 | /* up(&direntry->d_sb->s_vfs_rename_sem);*/ | 416 | /* up(&direntry->d_sb->s_vfs_rename_sem);*/ |
417 | if (full_path == NULL) { | 417 | if (full_path == NULL) { |
418 | FreeXid(xid); | 418 | FreeXid(xid); |
@@ -556,7 +556,7 @@ int cifs_mkdir(struct inode *inode, struct dentry *direntry, int mode) | |||
556 | pTcon = cifs_sb->tcon; | 556 | pTcon = cifs_sb->tcon; |
557 | 557 | ||
558 | down(&inode->i_sb->s_vfs_rename_sem); | 558 | down(&inode->i_sb->s_vfs_rename_sem); |
559 | full_path = build_path_from_dentry(direntry); | 559 | full_path = build_path_from_dentry(direntry, cifs_sb); |
560 | up(&inode->i_sb->s_vfs_rename_sem); | 560 | up(&inode->i_sb->s_vfs_rename_sem); |
561 | if (full_path == NULL) { | 561 | if (full_path == NULL) { |
562 | FreeXid(xid); | 562 | FreeXid(xid); |
@@ -627,7 +627,7 @@ int cifs_rmdir(struct inode *inode, struct dentry *direntry) | |||
627 | pTcon = cifs_sb->tcon; | 627 | pTcon = cifs_sb->tcon; |
628 | 628 | ||
629 | down(&inode->i_sb->s_vfs_rename_sem); | 629 | down(&inode->i_sb->s_vfs_rename_sem); |
630 | full_path = build_path_from_dentry(direntry); | 630 | full_path = build_path_from_dentry(direntry, cifs_sb); |
631 | up(&inode->i_sb->s_vfs_rename_sem); | 631 | up(&inode->i_sb->s_vfs_rename_sem); |
632 | if (full_path == NULL) { | 632 | if (full_path == NULL) { |
633 | FreeXid(xid); | 633 | FreeXid(xid); |
@@ -680,8 +680,8 @@ int cifs_rename(struct inode *source_inode, struct dentry *source_direntry, | |||
680 | 680 | ||
681 | /* we already have the rename sem so we do not need to grab it again | 681 | /* we already have the rename sem so we do not need to grab it again |
682 | here to protect the path integrity */ | 682 | here to protect the path integrity */ |
683 | fromName = build_path_from_dentry(source_direntry); | 683 | fromName = build_path_from_dentry(source_direntry, cifs_sb_source); |
684 | toName = build_path_from_dentry(target_direntry); | 684 | toName = build_path_from_dentry(target_direntry, cifs_sb_target); |
685 | if ((fromName == NULL) || (toName == NULL)) { | 685 | if ((fromName == NULL) || (toName == NULL)) { |
686 | rc = -ENOMEM; | 686 | rc = -ENOMEM; |
687 | goto cifs_rename_exit; | 687 | goto cifs_rename_exit; |
@@ -797,7 +797,7 @@ int cifs_revalidate(struct dentry *direntry) | |||
797 | 797 | ||
798 | /* can not safely grab the rename sem here if rename calls revalidate | 798 | /* can not safely grab the rename sem here if rename calls revalidate |
799 | since that would deadlock */ | 799 | since that would deadlock */ |
800 | full_path = build_path_from_dentry(direntry); | 800 | full_path = build_path_from_dentry(direntry, cifs_sb); |
801 | if (full_path == NULL) { | 801 | if (full_path == NULL) { |
802 | FreeXid(xid); | 802 | FreeXid(xid); |
803 | return -ENOMEM; | 803 | return -ENOMEM; |
@@ -946,7 +946,7 @@ int cifs_setattr(struct dentry *direntry, struct iattr *attrs) | |||
946 | pTcon = cifs_sb->tcon; | 946 | pTcon = cifs_sb->tcon; |
947 | 947 | ||
948 | down(&direntry->d_sb->s_vfs_rename_sem); | 948 | down(&direntry->d_sb->s_vfs_rename_sem); |
949 | full_path = build_path_from_dentry(direntry); | 949 | full_path = build_path_from_dentry(direntry, cifs_sb); |
950 | up(&direntry->d_sb->s_vfs_rename_sem); | 950 | up(&direntry->d_sb->s_vfs_rename_sem); |
951 | if (full_path == NULL) { | 951 | if (full_path == NULL) { |
952 | FreeXid(xid); | 952 | FreeXid(xid); |
diff --git a/fs/cifs/link.c b/fs/cifs/link.c index bde0fabfece0..214aa816f669 100644 --- a/fs/cifs/link.c +++ b/fs/cifs/link.c | |||
@@ -49,8 +49,8 @@ cifs_hardlink(struct dentry *old_file, struct inode *inode, | |||
49 | BB note DFS case in future though (when we may have to check) */ | 49 | BB note DFS case in future though (when we may have to check) */ |
50 | 50 | ||
51 | down(&inode->i_sb->s_vfs_rename_sem); | 51 | down(&inode->i_sb->s_vfs_rename_sem); |
52 | fromName = build_path_from_dentry(old_file); | 52 | fromName = build_path_from_dentry(old_file, cifs_sb_target); |
53 | toName = build_path_from_dentry(direntry); | 53 | toName = build_path_from_dentry(direntry, cifs_sb_target); |
54 | up(&inode->i_sb->s_vfs_rename_sem); | 54 | up(&inode->i_sb->s_vfs_rename_sem); |
55 | if((fromName == NULL) || (toName == NULL)) { | 55 | if((fromName == NULL) || (toName == NULL)) { |
56 | rc = -ENOMEM; | 56 | rc = -ENOMEM; |
@@ -105,16 +105,17 @@ cifs_follow_link(struct dentry *direntry, struct nameidata *nd) | |||
105 | 105 | ||
106 | xid = GetXid(); | 106 | xid = GetXid(); |
107 | 107 | ||
108 | cifs_sb = CIFS_SB(inode->i_sb); | ||
109 | pTcon = cifs_sb->tcon; | ||
110 | |||
108 | down(&direntry->d_sb->s_vfs_rename_sem); | 111 | down(&direntry->d_sb->s_vfs_rename_sem); |
109 | full_path = build_path_from_dentry(direntry); | 112 | full_path = build_path_from_dentry(direntry, cifs_sb); |
110 | up(&direntry->d_sb->s_vfs_rename_sem); | 113 | up(&direntry->d_sb->s_vfs_rename_sem); |
111 | 114 | ||
112 | if (!full_path) | 115 | if (!full_path) |
113 | goto out_no_free; | 116 | goto out_no_free; |
114 | 117 | ||
115 | cFYI(1, ("Full path: %s inode = 0x%p", full_path, inode)); | 118 | cFYI(1, ("Full path: %s inode = 0x%p", full_path, inode)); |
116 | cifs_sb = CIFS_SB(inode->i_sb); | ||
117 | pTcon = cifs_sb->tcon; | ||
118 | target_path = kmalloc(PATH_MAX, GFP_KERNEL); | 119 | target_path = kmalloc(PATH_MAX, GFP_KERNEL); |
119 | if (!target_path) { | 120 | if (!target_path) { |
120 | target_path = ERR_PTR(-ENOMEM); | 121 | target_path = ERR_PTR(-ENOMEM); |
@@ -167,7 +168,7 @@ cifs_symlink(struct inode *inode, struct dentry *direntry, const char *symname) | |||
167 | pTcon = cifs_sb->tcon; | 168 | pTcon = cifs_sb->tcon; |
168 | 169 | ||
169 | down(&inode->i_sb->s_vfs_rename_sem); | 170 | down(&inode->i_sb->s_vfs_rename_sem); |
170 | full_path = build_path_from_dentry(direntry); | 171 | full_path = build_path_from_dentry(direntry, cifs_sb); |
171 | up(&inode->i_sb->s_vfs_rename_sem); | 172 | up(&inode->i_sb->s_vfs_rename_sem); |
172 | 173 | ||
173 | if(full_path == NULL) { | 174 | if(full_path == NULL) { |
@@ -233,7 +234,7 @@ cifs_readlink(struct dentry *direntry, char __user *pBuffer, int buflen) | |||
233 | /* BB would it be safe against deadlock to grab this sem | 234 | /* BB would it be safe against deadlock to grab this sem |
234 | even though rename itself grabs the sem and calls lookup? */ | 235 | even though rename itself grabs the sem and calls lookup? */ |
235 | /* down(&inode->i_sb->s_vfs_rename_sem);*/ | 236 | /* down(&inode->i_sb->s_vfs_rename_sem);*/ |
236 | full_path = build_path_from_dentry(direntry); | 237 | full_path = build_path_from_dentry(direntry, cifs_sb); |
237 | /* up(&inode->i_sb->s_vfs_rename_sem);*/ | 238 | /* up(&inode->i_sb->s_vfs_rename_sem);*/ |
238 | 239 | ||
239 | if(full_path == NULL) { | 240 | if(full_path == NULL) { |
diff --git a/fs/cifs/readdir.c b/fs/cifs/readdir.c index 487221eeddb7..42310281871c 100644 --- a/fs/cifs/readdir.c +++ b/fs/cifs/readdir.c | |||
@@ -354,7 +354,7 @@ static int initiate_cifs_search(const int xid, struct file *file) | |||
354 | return -EINVAL; | 354 | return -EINVAL; |
355 | 355 | ||
356 | down(&file->f_dentry->d_sb->s_vfs_rename_sem); | 356 | down(&file->f_dentry->d_sb->s_vfs_rename_sem); |
357 | full_path = build_path_from_dentry(file->f_dentry); | 357 | full_path = build_path_from_dentry(file->f_dentry, cifs_sb); |
358 | up(&file->f_dentry->d_sb->s_vfs_rename_sem); | 358 | up(&file->f_dentry->d_sb->s_vfs_rename_sem); |
359 | 359 | ||
360 | if(full_path == NULL) { | 360 | if(full_path == NULL) { |
@@ -375,7 +375,7 @@ ffirst_retry: | |||
375 | 375 | ||
376 | rc = CIFSFindFirst(xid, pTcon,full_path,cifs_sb->local_nls, | 376 | rc = CIFSFindFirst(xid, pTcon,full_path,cifs_sb->local_nls, |
377 | &cifsFile->netfid, &cifsFile->srch_inf, | 377 | &cifsFile->netfid, &cifsFile->srch_inf, |
378 | cifs_sb->mnt_cifs_flags & CIFS_MOUNT_MAP_SPECIAL_CHR); | 378 | cifs_sb->mnt_cifs_flags & CIFS_MOUNT_MAP_SPECIAL_CHR, CIFS_DIR_SEP(cifs_sb)); |
379 | if(rc == 0) | 379 | if(rc == 0) |
380 | cifsFile->invalidHandle = FALSE; | 380 | cifsFile->invalidHandle = FALSE; |
381 | if((rc == -EOPNOTSUPP) && | 381 | if((rc == -EOPNOTSUPP) && |
diff --git a/fs/cifs/xattr.c b/fs/cifs/xattr.c index c1e02eff1d25..f4fc8ddebba7 100644 --- a/fs/cifs/xattr.c +++ b/fs/cifs/xattr.c | |||
@@ -63,7 +63,7 @@ int cifs_removexattr(struct dentry * direntry, const char * ea_name) | |||
63 | pTcon = cifs_sb->tcon; | 63 | pTcon = cifs_sb->tcon; |
64 | 64 | ||
65 | down(&sb->s_vfs_rename_sem); | 65 | down(&sb->s_vfs_rename_sem); |
66 | full_path = build_path_from_dentry(direntry); | 66 | full_path = build_path_from_dentry(direntry, cifs_sb); |
67 | up(&sb->s_vfs_rename_sem); | 67 | up(&sb->s_vfs_rename_sem); |
68 | if(full_path == NULL) { | 68 | if(full_path == NULL) { |
69 | FreeXid(xid); | 69 | FreeXid(xid); |
@@ -118,7 +118,7 @@ int cifs_setxattr(struct dentry * direntry, const char * ea_name, | |||
118 | pTcon = cifs_sb->tcon; | 118 | pTcon = cifs_sb->tcon; |
119 | 119 | ||
120 | down(&sb->s_vfs_rename_sem); | 120 | down(&sb->s_vfs_rename_sem); |
121 | full_path = build_path_from_dentry(direntry); | 121 | full_path = build_path_from_dentry(direntry, cifs_sb); |
122 | up(&sb->s_vfs_rename_sem); | 122 | up(&sb->s_vfs_rename_sem); |
123 | if(full_path == NULL) { | 123 | if(full_path == NULL) { |
124 | FreeXid(xid); | 124 | FreeXid(xid); |
@@ -227,7 +227,7 @@ ssize_t cifs_getxattr(struct dentry * direntry, const char * ea_name, | |||
227 | pTcon = cifs_sb->tcon; | 227 | pTcon = cifs_sb->tcon; |
228 | 228 | ||
229 | down(&sb->s_vfs_rename_sem); | 229 | down(&sb->s_vfs_rename_sem); |
230 | full_path = build_path_from_dentry(direntry); | 230 | full_path = build_path_from_dentry(direntry, cifs_sb); |
231 | up(&sb->s_vfs_rename_sem); | 231 | up(&sb->s_vfs_rename_sem); |
232 | if(full_path == NULL) { | 232 | if(full_path == NULL) { |
233 | FreeXid(xid); | 233 | FreeXid(xid); |
@@ -328,7 +328,7 @@ ssize_t cifs_listxattr(struct dentry * direntry, char * data, size_t buf_size) | |||
328 | pTcon = cifs_sb->tcon; | 328 | pTcon = cifs_sb->tcon; |
329 | 329 | ||
330 | down(&sb->s_vfs_rename_sem); | 330 | down(&sb->s_vfs_rename_sem); |
331 | full_path = build_path_from_dentry(direntry); | 331 | full_path = build_path_from_dentry(direntry, cifs_sb); |
332 | up(&sb->s_vfs_rename_sem); | 332 | up(&sb->s_vfs_rename_sem); |
333 | if(full_path == NULL) { | 333 | if(full_path == NULL) { |
334 | FreeXid(xid); | 334 | FreeXid(xid); |