diff options
Diffstat (limited to 'fs/cifs')
| -rw-r--r-- | fs/cifs/CHANGES | 15 | ||||
| -rw-r--r-- | fs/cifs/cifsfs.h | 2 | ||||
| -rw-r--r-- | fs/cifs/cifsglob.h | 6 | ||||
| -rw-r--r-- | fs/cifs/cifsproto.h | 4 | ||||
| -rw-r--r-- | fs/cifs/cifssmb.c | 7 | ||||
| -rw-r--r-- | fs/cifs/connect.c | 51 | ||||
| -rw-r--r-- | fs/cifs/dir.c | 307 | ||||
| -rw-r--r-- | fs/cifs/inode.c | 104 | ||||
| -rw-r--r-- | fs/cifs/readdir.c | 58 | ||||
| -rw-r--r-- | fs/cifs/sess.c | 91 |
10 files changed, 458 insertions, 187 deletions
diff --git a/fs/cifs/CHANGES b/fs/cifs/CHANGES index 73ac7ebd1dfc..851388fafc73 100644 --- a/fs/cifs/CHANGES +++ b/fs/cifs/CHANGES | |||
| @@ -1,3 +1,13 @@ | |||
| 1 | Version 1.57 | ||
| 2 | ------------ | ||
| 3 | Improve support for multiple security contexts to the same server. We | ||
| 4 | used to use the same "vcnumber" for all connections which could cause | ||
| 5 | the server to treat subsequent connections, especially those that | ||
| 6 | are authenticated as guest, as reconnections, invalidating the earlier | ||
| 7 | user's smb session. This fix allows cifs to mount multiple times to the | ||
| 8 | same server with different userids without risking invalidating earlier | ||
| 9 | established security contexts. | ||
| 10 | |||
| 1 | Version 1.56 | 11 | Version 1.56 |
| 2 | ------------ | 12 | ------------ |
| 3 | Add "forcemandatorylock" mount option to allow user to use mandatory | 13 | Add "forcemandatorylock" mount option to allow user to use mandatory |
| @@ -7,7 +17,10 @@ specified and user does not have access to query information about the | |||
| 7 | top of the share. Fix problem in 2.6.28 resolving DFS paths to | 17 | top of the share. Fix problem in 2.6.28 resolving DFS paths to |
| 8 | Samba servers (worked to Windows). Fix rmdir so that pending search | 18 | Samba servers (worked to Windows). Fix rmdir so that pending search |
| 9 | (readdir) requests do not get invalid results which include the now | 19 | (readdir) requests do not get invalid results which include the now |
| 10 | removed directory. | 20 | removed directory. Fix oops in cifs_dfs_ref.c when prefixpath is not reachable |
| 21 | when using DFS. Add better file create support to servers which support | ||
| 22 | the CIFS POSIX protocol extensions (this adds support for new flags | ||
| 23 | on create, and improves semantics for write of locked ranges). | ||
| 11 | 24 | ||
| 12 | Version 1.55 | 25 | Version 1.55 |
| 13 | ------------ | 26 | ------------ |
diff --git a/fs/cifs/cifsfs.h b/fs/cifs/cifsfs.h index 7ac481841f87..2b1d28a9ee28 100644 --- a/fs/cifs/cifsfs.h +++ b/fs/cifs/cifsfs.h | |||
| @@ -100,5 +100,5 @@ extern long cifs_ioctl(struct file *filep, unsigned int cmd, unsigned long arg); | |||
| 100 | extern const struct export_operations cifs_export_ops; | 100 | extern const struct export_operations cifs_export_ops; |
| 101 | #endif /* EXPERIMENTAL */ | 101 | #endif /* EXPERIMENTAL */ |
| 102 | 102 | ||
| 103 | #define CIFS_VERSION "1.56" | 103 | #define CIFS_VERSION "1.57" |
| 104 | #endif /* _CIFSFS_H */ | 104 | #endif /* _CIFSFS_H */ |
diff --git a/fs/cifs/cifsglob.h b/fs/cifs/cifsglob.h index 94c1ca0ec953..e004f6db5fc8 100644 --- a/fs/cifs/cifsglob.h +++ b/fs/cifs/cifsglob.h | |||
| @@ -164,9 +164,12 @@ struct TCP_Server_Info { | |||
| 164 | /* multiplexed reads or writes */ | 164 | /* multiplexed reads or writes */ |
| 165 | unsigned int maxBuf; /* maxBuf specifies the maximum */ | 165 | unsigned int maxBuf; /* maxBuf specifies the maximum */ |
| 166 | /* message size the server can send or receive for non-raw SMBs */ | 166 | /* message size the server can send or receive for non-raw SMBs */ |
| 167 | unsigned int maxRw; /* maxRw specifies the maximum */ | 167 | unsigned int max_rw; /* maxRw specifies the maximum */ |
| 168 | /* message size the server can send or receive for */ | 168 | /* message size the server can send or receive for */ |
| 169 | /* SMB_COM_WRITE_RAW or SMB_COM_READ_RAW. */ | 169 | /* SMB_COM_WRITE_RAW or SMB_COM_READ_RAW. */ |
| 170 | unsigned int max_vcs; /* maximum number of smb sessions, at least | ||
| 171 | those that can be specified uniquely with | ||
| 172 | vcnumbers */ | ||
| 170 | char sessid[4]; /* unique token id for this session */ | 173 | char sessid[4]; /* unique token id for this session */ |
| 171 | /* (returned on Negotiate */ | 174 | /* (returned on Negotiate */ |
| 172 | int capabilities; /* allow selective disabling of caps by smb sess */ | 175 | int capabilities; /* allow selective disabling of caps by smb sess */ |
| @@ -210,6 +213,7 @@ struct cifsSesInfo { | |||
| 210 | unsigned overrideSecFlg; /* if non-zero override global sec flags */ | 213 | unsigned overrideSecFlg; /* if non-zero override global sec flags */ |
| 211 | __u16 ipc_tid; /* special tid for connection to IPC share */ | 214 | __u16 ipc_tid; /* special tid for connection to IPC share */ |
| 212 | __u16 flags; | 215 | __u16 flags; |
| 216 | __u16 vcnum; | ||
| 213 | char *serverOS; /* name of operating system underlying server */ | 217 | char *serverOS; /* name of operating system underlying server */ |
| 214 | char *serverNOS; /* name of network operating system of server */ | 218 | char *serverNOS; /* name of network operating system of server */ |
| 215 | char *serverDomain; /* security realm of server */ | 219 | char *serverDomain; /* security realm of server */ |
diff --git a/fs/cifs/cifsproto.h b/fs/cifs/cifsproto.h index 382ba6298809..083dfc57c7a3 100644 --- a/fs/cifs/cifsproto.h +++ b/fs/cifs/cifsproto.h | |||
| @@ -42,6 +42,7 @@ extern void _FreeXid(unsigned int); | |||
| 42 | #define GetXid() (int)_GetXid(); cFYI(1,("CIFS VFS: in %s as Xid: %d with uid: %d",__func__, xid,current_fsuid())); | 42 | #define GetXid() (int)_GetXid(); cFYI(1,("CIFS VFS: in %s as Xid: %d with uid: %d",__func__, xid,current_fsuid())); |
| 43 | #define FreeXid(curr_xid) {_FreeXid(curr_xid); cFYI(1,("CIFS VFS: leaving %s (xid = %d) rc = %d",__func__,curr_xid,(int)rc));} | 43 | #define FreeXid(curr_xid) {_FreeXid(curr_xid); cFYI(1,("CIFS VFS: leaving %s (xid = %d) rc = %d",__func__,curr_xid,(int)rc));} |
| 44 | extern char *build_path_from_dentry(struct dentry *); | 44 | extern char *build_path_from_dentry(struct dentry *); |
| 45 | extern char *cifs_build_path_to_root(struct cifs_sb_info *cifs_sb); | ||
| 45 | extern char *build_wildcard_path_from_dentry(struct dentry *direntry); | 46 | extern char *build_wildcard_path_from_dentry(struct dentry *direntry); |
| 46 | /* extern void renew_parental_timestamps(struct dentry *direntry);*/ | 47 | /* extern void renew_parental_timestamps(struct dentry *direntry);*/ |
| 47 | extern int SendReceive(const unsigned int /* xid */ , struct cifsSesInfo *, | 48 | extern int SendReceive(const unsigned int /* xid */ , struct cifsSesInfo *, |
| @@ -91,6 +92,9 @@ extern u64 cifs_UnixTimeToNT(struct timespec); | |||
| 91 | extern __le64 cnvrtDosCifsTm(__u16 date, __u16 time); | 92 | extern __le64 cnvrtDosCifsTm(__u16 date, __u16 time); |
| 92 | extern struct timespec cnvrtDosUnixTm(__u16 date, __u16 time); | 93 | extern struct timespec cnvrtDosUnixTm(__u16 date, __u16 time); |
| 93 | 94 | ||
| 95 | extern void posix_fill_in_inode(struct inode *tmp_inode, | ||
| 96 | FILE_UNIX_BASIC_INFO *pData, int isNewInode); | ||
| 97 | extern struct inode *cifs_new_inode(struct super_block *sb, __u64 *inum); | ||
| 94 | extern int cifs_get_inode_info(struct inode **pinode, | 98 | extern int cifs_get_inode_info(struct inode **pinode, |
| 95 | const unsigned char *search_path, | 99 | const unsigned char *search_path, |
| 96 | FILE_ALL_INFO *pfile_info, | 100 | FILE_ALL_INFO *pfile_info, |
diff --git a/fs/cifs/cifssmb.c b/fs/cifs/cifssmb.c index 552642a507c4..939e2f76b959 100644 --- a/fs/cifs/cifssmb.c +++ b/fs/cifs/cifssmb.c | |||
| @@ -528,14 +528,15 @@ CIFSSMBNegotiate(unsigned int xid, struct cifsSesInfo *ses) | |||
| 528 | server->maxReq = le16_to_cpu(rsp->MaxMpxCount); | 528 | server->maxReq = le16_to_cpu(rsp->MaxMpxCount); |
| 529 | server->maxBuf = min((__u32)le16_to_cpu(rsp->MaxBufSize), | 529 | server->maxBuf = min((__u32)le16_to_cpu(rsp->MaxBufSize), |
| 530 | (__u32)CIFSMaxBufSize + MAX_CIFS_HDR_SIZE); | 530 | (__u32)CIFSMaxBufSize + MAX_CIFS_HDR_SIZE); |
| 531 | server->max_vcs = le16_to_cpu(rsp->MaxNumberVcs); | ||
| 531 | GETU32(server->sessid) = le32_to_cpu(rsp->SessionKey); | 532 | GETU32(server->sessid) = le32_to_cpu(rsp->SessionKey); |
| 532 | /* even though we do not use raw we might as well set this | 533 | /* even though we do not use raw we might as well set this |
| 533 | accurately, in case we ever find a need for it */ | 534 | accurately, in case we ever find a need for it */ |
| 534 | if ((le16_to_cpu(rsp->RawMode) & RAW_ENABLE) == RAW_ENABLE) { | 535 | if ((le16_to_cpu(rsp->RawMode) & RAW_ENABLE) == RAW_ENABLE) { |
| 535 | server->maxRw = 0xFF00; | 536 | server->max_rw = 0xFF00; |
| 536 | server->capabilities = CAP_MPX_MODE | CAP_RAW_MODE; | 537 | server->capabilities = CAP_MPX_MODE | CAP_RAW_MODE; |
| 537 | } else { | 538 | } else { |
| 538 | server->maxRw = 0;/* we do not need to use raw anyway */ | 539 | server->max_rw = 0;/* do not need to use raw anyway */ |
| 539 | server->capabilities = CAP_MPX_MODE; | 540 | server->capabilities = CAP_MPX_MODE; |
| 540 | } | 541 | } |
| 541 | tmp = (__s16)le16_to_cpu(rsp->ServerTimeZone); | 542 | tmp = (__s16)le16_to_cpu(rsp->ServerTimeZone); |
| @@ -638,7 +639,7 @@ CIFSSMBNegotiate(unsigned int xid, struct cifsSesInfo *ses) | |||
| 638 | /* probably no need to store and check maxvcs */ | 639 | /* probably no need to store and check maxvcs */ |
| 639 | server->maxBuf = min(le32_to_cpu(pSMBr->MaxBufferSize), | 640 | server->maxBuf = min(le32_to_cpu(pSMBr->MaxBufferSize), |
| 640 | (__u32) CIFSMaxBufSize + MAX_CIFS_HDR_SIZE); | 641 | (__u32) CIFSMaxBufSize + MAX_CIFS_HDR_SIZE); |
| 641 | server->maxRw = le32_to_cpu(pSMBr->MaxRawSize); | 642 | server->max_rw = le32_to_cpu(pSMBr->MaxRawSize); |
| 642 | cFYI(DBG2, ("Max buf = %d", ses->server->maxBuf)); | 643 | cFYI(DBG2, ("Max buf = %d", ses->server->maxBuf)); |
| 643 | GETU32(ses->server->sessid) = le32_to_cpu(pSMBr->SessionKey); | 644 | GETU32(ses->server->sessid) = le32_to_cpu(pSMBr->SessionKey); |
| 644 | server->capabilities = le32_to_cpu(pSMBr->Capabilities); | 645 | server->capabilities = le32_to_cpu(pSMBr->Capabilities); |
diff --git a/fs/cifs/connect.c b/fs/cifs/connect.c index 2209be943051..da0f4ffa0613 100644 --- a/fs/cifs/connect.c +++ b/fs/cifs/connect.c | |||
| @@ -23,7 +23,6 @@ | |||
| 23 | #include <linux/string.h> | 23 | #include <linux/string.h> |
| 24 | #include <linux/list.h> | 24 | #include <linux/list.h> |
| 25 | #include <linux/wait.h> | 25 | #include <linux/wait.h> |
| 26 | #include <linux/ipv6.h> | ||
| 27 | #include <linux/pagemap.h> | 26 | #include <linux/pagemap.h> |
| 28 | #include <linux/ctype.h> | 27 | #include <linux/ctype.h> |
| 29 | #include <linux/utsname.h> | 28 | #include <linux/utsname.h> |
| @@ -35,6 +34,7 @@ | |||
| 35 | #include <linux/freezer.h> | 34 | #include <linux/freezer.h> |
| 36 | #include <asm/uaccess.h> | 35 | #include <asm/uaccess.h> |
| 37 | #include <asm/processor.h> | 36 | #include <asm/processor.h> |
| 37 | #include <net/ipv6.h> | ||
| 38 | #include "cifspdu.h" | 38 | #include "cifspdu.h" |
| 39 | #include "cifsglob.h" | 39 | #include "cifsglob.h" |
| 40 | #include "cifsproto.h" | 40 | #include "cifsproto.h" |
| @@ -1379,8 +1379,8 @@ cifs_find_tcp_session(struct sockaddr_storage *addr) | |||
| 1379 | server->addr.sockAddr.sin_addr.s_addr)) | 1379 | server->addr.sockAddr.sin_addr.s_addr)) |
| 1380 | continue; | 1380 | continue; |
| 1381 | else if (addr->ss_family == AF_INET6 && | 1381 | else if (addr->ss_family == AF_INET6 && |
| 1382 | memcmp(&server->addr.sockAddr6.sin6_addr, | 1382 | !ipv6_addr_equal(&server->addr.sockAddr6.sin6_addr, |
| 1383 | &addr6->sin6_addr, sizeof(addr6->sin6_addr))) | 1383 | &addr6->sin6_addr)) |
| 1384 | continue; | 1384 | continue; |
| 1385 | 1385 | ||
| 1386 | ++server->srv_count; | 1386 | ++server->srv_count; |
| @@ -2180,6 +2180,33 @@ static void setup_cifs_sb(struct smb_vol *pvolume_info, | |||
| 2180 | "mount option supported")); | 2180 | "mount option supported")); |
| 2181 | } | 2181 | } |
| 2182 | 2182 | ||
| 2183 | static int | ||
| 2184 | is_path_accessible(int xid, struct cifsTconInfo *tcon, | ||
| 2185 | struct cifs_sb_info *cifs_sb, const char *full_path) | ||
| 2186 | { | ||
| 2187 | int rc; | ||
| 2188 | __u64 inode_num; | ||
| 2189 | FILE_ALL_INFO *pfile_info; | ||
| 2190 | |||
| 2191 | rc = CIFSGetSrvInodeNumber(xid, tcon, full_path, &inode_num, | ||
| 2192 | cifs_sb->local_nls, | ||
| 2193 | cifs_sb->mnt_cifs_flags & | ||
| 2194 | CIFS_MOUNT_MAP_SPECIAL_CHR); | ||
| 2195 | if (rc != -EOPNOTSUPP) | ||
| 2196 | return rc; | ||
| 2197 | |||
| 2198 | pfile_info = kmalloc(sizeof(FILE_ALL_INFO), GFP_KERNEL); | ||
| 2199 | if (pfile_info == NULL) | ||
| 2200 | return -ENOMEM; | ||
| 2201 | |||
| 2202 | rc = CIFSSMBQPathInfo(xid, tcon, full_path, pfile_info, | ||
| 2203 | 0 /* not legacy */, cifs_sb->local_nls, | ||
| 2204 | cifs_sb->mnt_cifs_flags & | ||
| 2205 | CIFS_MOUNT_MAP_SPECIAL_CHR); | ||
| 2206 | kfree(pfile_info); | ||
| 2207 | return rc; | ||
| 2208 | } | ||
| 2209 | |||
| 2183 | int | 2210 | int |
| 2184 | cifs_mount(struct super_block *sb, struct cifs_sb_info *cifs_sb, | 2211 | cifs_mount(struct super_block *sb, struct cifs_sb_info *cifs_sb, |
| 2185 | char *mount_data, const char *devname) | 2212 | char *mount_data, const char *devname) |
| @@ -2190,6 +2217,7 @@ cifs_mount(struct super_block *sb, struct cifs_sb_info *cifs_sb, | |||
| 2190 | struct cifsSesInfo *pSesInfo = NULL; | 2217 | struct cifsSesInfo *pSesInfo = NULL; |
| 2191 | struct cifsTconInfo *tcon = NULL; | 2218 | struct cifsTconInfo *tcon = NULL; |
| 2192 | struct TCP_Server_Info *srvTcp = NULL; | 2219 | struct TCP_Server_Info *srvTcp = NULL; |
| 2220 | char *full_path; | ||
| 2193 | 2221 | ||
| 2194 | xid = GetXid(); | 2222 | xid = GetXid(); |
| 2195 | 2223 | ||
| @@ -2426,6 +2454,23 @@ mount_fail_check: | |||
| 2426 | cifs_sb->rsize = min(cifs_sb->rsize, | 2454 | cifs_sb->rsize = min(cifs_sb->rsize, |
| 2427 | (tcon->ses->server->maxBuf - MAX_CIFS_HDR_SIZE)); | 2455 | (tcon->ses->server->maxBuf - MAX_CIFS_HDR_SIZE)); |
| 2428 | 2456 | ||
| 2457 | if (!rc && cifs_sb->prepathlen) { | ||
| 2458 | /* build_path_to_root works only when we have a valid tcon */ | ||
| 2459 | full_path = cifs_build_path_to_root(cifs_sb); | ||
| 2460 | if (full_path == NULL) { | ||
| 2461 | rc = -ENOMEM; | ||
| 2462 | goto mount_fail_check; | ||
| 2463 | } | ||
| 2464 | rc = is_path_accessible(xid, tcon, cifs_sb, full_path); | ||
| 2465 | if (rc) { | ||
| 2466 | cERROR(1, ("Path %s in not accessible: %d", | ||
| 2467 | full_path, rc)); | ||
| 2468 | kfree(full_path); | ||
| 2469 | goto mount_fail_check; | ||
| 2470 | } | ||
| 2471 | kfree(full_path); | ||
| 2472 | } | ||
| 2473 | |||
| 2429 | /* volume_info->password is freed above when existing session found | 2474 | /* volume_info->password is freed above when existing session found |
| 2430 | (in which case it is not needed anymore) but when new sesion is created | 2475 | (in which case it is not needed anymore) but when new sesion is created |
| 2431 | the password ptr is put in the new session structure (in which case the | 2476 | the password ptr is put in the new session structure (in which case the |
diff --git a/fs/cifs/dir.c b/fs/cifs/dir.c index 964aad03c5ad..89fb72832652 100644 --- a/fs/cifs/dir.c +++ b/fs/cifs/dir.c | |||
| @@ -3,7 +3,7 @@ | |||
| 3 | * | 3 | * |
| 4 | * vfs operations that deal with dentries | 4 | * vfs operations that deal with dentries |
| 5 | * | 5 | * |
| 6 | * Copyright (C) International Business Machines Corp., 2002,2008 | 6 | * Copyright (C) International Business Machines Corp., 2002,2009 |
| 7 | * Author(s): Steve French (sfrench@us.ibm.com) | 7 | * Author(s): Steve French (sfrench@us.ibm.com) |
| 8 | * | 8 | * |
| 9 | * This library is free software; you can redistribute it and/or modify | 9 | * This library is free software; you can redistribute it and/or modify |
| @@ -129,6 +129,78 @@ cifs_bp_rename_retry: | |||
| 129 | return full_path; | 129 | return full_path; |
| 130 | } | 130 | } |
| 131 | 131 | ||
| 132 | static int cifs_posix_open(char *full_path, struct inode **pinode, | ||
| 133 | struct super_block *sb, int mode, int oflags, | ||
| 134 | int *poplock, __u16 *pnetfid, int xid) | ||
| 135 | { | ||
| 136 | int rc; | ||
| 137 | __u32 oplock; | ||
| 138 | FILE_UNIX_BASIC_INFO *presp_data; | ||
| 139 | __u32 posix_flags = 0; | ||
| 140 | struct cifs_sb_info *cifs_sb = CIFS_SB(sb); | ||
| 141 | |||
| 142 | cFYI(1, ("posix open %s", full_path)); | ||
| 143 | |||
| 144 | presp_data = kzalloc(sizeof(FILE_UNIX_BASIC_INFO), GFP_KERNEL); | ||
| 145 | if (presp_data == NULL) | ||
| 146 | return -ENOMEM; | ||
| 147 | |||
| 148 | /* So far cifs posix extensions can only map the following flags. | ||
| 149 | There are other valid fmode oflags such as FMODE_LSEEK, FMODE_PREAD, but | ||
| 150 | so far we do not seem to need them, and we can treat them as local only */ | ||
| 151 | if ((oflags & (FMODE_READ | FMODE_WRITE)) == | ||
| 152 | (FMODE_READ | FMODE_WRITE)) | ||
| 153 | posix_flags = SMB_O_RDWR; | ||
| 154 | else if (oflags & FMODE_READ) | ||
| 155 | posix_flags = SMB_O_RDONLY; | ||
| 156 | else if (oflags & FMODE_WRITE) | ||
| 157 | posix_flags = SMB_O_WRONLY; | ||
| 158 | if (oflags & O_CREAT) | ||
| 159 | posix_flags |= SMB_O_CREAT; | ||
| 160 | if (oflags & O_EXCL) | ||
| 161 | posix_flags |= SMB_O_EXCL; | ||
| 162 | if (oflags & O_TRUNC) | ||
| 163 | posix_flags |= SMB_O_TRUNC; | ||
| 164 | if (oflags & O_APPEND) | ||
| 165 | posix_flags |= SMB_O_APPEND; | ||
| 166 | if (oflags & O_SYNC) | ||
| 167 | posix_flags |= SMB_O_SYNC; | ||
| 168 | if (oflags & O_DIRECTORY) | ||
| 169 | posix_flags |= SMB_O_DIRECTORY; | ||
| 170 | if (oflags & O_NOFOLLOW) | ||
| 171 | posix_flags |= SMB_O_NOFOLLOW; | ||
| 172 | if (oflags & O_DIRECT) | ||
| 173 | posix_flags |= SMB_O_DIRECT; | ||
| 174 | |||
| 175 | |||
| 176 | rc = CIFSPOSIXCreate(xid, cifs_sb->tcon, posix_flags, mode, | ||
| 177 | pnetfid, presp_data, &oplock, full_path, | ||
| 178 | cifs_sb->local_nls, cifs_sb->mnt_cifs_flags & | ||
| 179 | CIFS_MOUNT_MAP_SPECIAL_CHR); | ||
| 180 | if (rc) | ||
| 181 | goto posix_open_ret; | ||
| 182 | |||
| 183 | if (presp_data->Type == cpu_to_le32(-1)) | ||
| 184 | goto posix_open_ret; /* open ok, caller does qpathinfo */ | ||
| 185 | |||
| 186 | /* get new inode and set it up */ | ||
| 187 | if (!pinode) | ||
| 188 | goto posix_open_ret; /* caller does not need info */ | ||
| 189 | |||
| 190 | *pinode = cifs_new_inode(sb, &presp_data->UniqueId); | ||
| 191 | |||
| 192 | /* We do not need to close the file if new_inode fails since | ||
| 193 | the caller will retry qpathinfo as long as inode is null */ | ||
| 194 | if (*pinode == NULL) | ||
| 195 | goto posix_open_ret; | ||
| 196 | |||
| 197 | posix_fill_in_inode(*pinode, presp_data, 1); | ||
| 198 | |||
| 199 | posix_open_ret: | ||
| 200 | kfree(presp_data); | ||
| 201 | return rc; | ||
| 202 | } | ||
| 203 | |||
| 132 | static void setup_cifs_dentry(struct cifsTconInfo *tcon, | 204 | static void setup_cifs_dentry(struct cifsTconInfo *tcon, |
| 133 | struct dentry *direntry, | 205 | struct dentry *direntry, |
| 134 | struct inode *newinode) | 206 | struct inode *newinode) |
| @@ -150,7 +222,14 @@ cifs_create(struct inode *inode, struct dentry *direntry, int mode, | |||
| 150 | int xid; | 222 | int xid; |
| 151 | int create_options = CREATE_NOT_DIR; | 223 | int create_options = CREATE_NOT_DIR; |
| 152 | int oplock = 0; | 224 | int oplock = 0; |
| 153 | /* BB below access is too much for the mknod to request */ | 225 | int oflags; |
| 226 | /* | ||
| 227 | * BB below access is probably too much for mknod to request | ||
| 228 | * but we have to do query and setpathinfo so requesting | ||
| 229 | * less could fail (unless we want to request getatr and setatr | ||
| 230 | * permissions (only). At least for POSIX we do not have to | ||
| 231 | * request so much. | ||
| 232 | */ | ||
| 154 | int desiredAccess = GENERIC_READ | GENERIC_WRITE; | 233 | int desiredAccess = GENERIC_READ | GENERIC_WRITE; |
| 155 | __u16 fileHandle; | 234 | __u16 fileHandle; |
| 156 | struct cifs_sb_info *cifs_sb; | 235 | struct cifs_sb_info *cifs_sb; |
| @@ -174,13 +253,43 @@ cifs_create(struct inode *inode, struct dentry *direntry, int mode, | |||
| 174 | } | 253 | } |
| 175 | 254 | ||
| 176 | mode &= ~current->fs->umask; | 255 | mode &= ~current->fs->umask; |
| 256 | if (oplockEnabled) | ||
| 257 | oplock = REQ_OPLOCK; | ||
| 177 | 258 | ||
| 178 | if (nd && (nd->flags & LOOKUP_OPEN)) { | 259 | if (nd && (nd->flags & LOOKUP_OPEN)) |
| 179 | int oflags = nd->intent.open.flags; | 260 | oflags = nd->intent.open.flags; |
| 261 | else | ||
| 262 | oflags = FMODE_READ; | ||
| 263 | |||
| 264 | if (tcon->unix_ext && (tcon->ses->capabilities & CAP_UNIX) && | ||
| 265 | (CIFS_UNIX_POSIX_PATH_OPS_CAP & | ||
| 266 | le64_to_cpu(tcon->fsUnixInfo.Capability))) { | ||
| 267 | rc = cifs_posix_open(full_path, &newinode, inode->i_sb, | ||
| 268 | mode, oflags, &oplock, &fileHandle, xid); | ||
| 269 | /* EIO could indicate that (posix open) operation is not | ||
| 270 | supported, despite what server claimed in capability | ||
| 271 | negotation. EREMOTE indicates DFS junction, which is not | ||
| 272 | handled in posix open */ | ||
| 273 | |||
| 274 | if ((rc == 0) && (newinode == NULL)) | ||
| 275 | goto cifs_create_get_file_info; /* query inode info */ | ||
| 276 | else if (rc == 0) /* success, no need to query */ | ||
| 277 | goto cifs_create_set_dentry; | ||
| 278 | else if ((rc != -EIO) && (rc != -EREMOTE) && | ||
| 279 | (rc != -EOPNOTSUPP)) /* path not found or net err */ | ||
| 280 | goto cifs_create_out; | ||
| 281 | /* else fallthrough to retry, using older open call, this is | ||
| 282 | case where server does not support this SMB level, and | ||
| 283 | falsely claims capability (also get here for DFS case | ||
| 284 | which should be rare for path not covered on files) */ | ||
| 285 | } | ||
| 180 | 286 | ||
| 287 | if (nd && (nd->flags & LOOKUP_OPEN)) { | ||
| 288 | /* if the file is going to stay open, then we | ||
| 289 | need to set the desired access properly */ | ||
| 181 | desiredAccess = 0; | 290 | desiredAccess = 0; |
| 182 | if (oflags & FMODE_READ) | 291 | if (oflags & FMODE_READ) |
| 183 | desiredAccess |= GENERIC_READ; | 292 | desiredAccess |= GENERIC_READ; /* is this too little? */ |
| 184 | if (oflags & FMODE_WRITE) { | 293 | if (oflags & FMODE_WRITE) { |
| 185 | desiredAccess |= GENERIC_WRITE; | 294 | desiredAccess |= GENERIC_WRITE; |
| 186 | if (!(oflags & FMODE_READ)) | 295 | if (!(oflags & FMODE_READ)) |
| @@ -199,8 +308,6 @@ cifs_create(struct inode *inode, struct dentry *direntry, int mode, | |||
| 199 | 308 | ||
| 200 | /* BB add processing to set equivalent of mode - e.g. via CreateX with | 309 | /* BB add processing to set equivalent of mode - e.g. via CreateX with |
| 201 | ACLs */ | 310 | ACLs */ |
| 202 | if (oplockEnabled) | ||
| 203 | oplock = REQ_OPLOCK; | ||
| 204 | 311 | ||
| 205 | buf = kmalloc(sizeof(FILE_ALL_INFO), GFP_KERNEL); | 312 | buf = kmalloc(sizeof(FILE_ALL_INFO), GFP_KERNEL); |
| 206 | if (buf == NULL) { | 313 | if (buf == NULL) { |
| @@ -233,116 +340,112 @@ cifs_create(struct inode *inode, struct dentry *direntry, int mode, | |||
| 233 | } | 340 | } |
| 234 | if (rc) { | 341 | if (rc) { |
| 235 | cFYI(1, ("cifs_create returned 0x%x", rc)); | 342 | cFYI(1, ("cifs_create returned 0x%x", rc)); |
| 236 | } else { | 343 | goto cifs_create_out; |
| 237 | /* If Open reported that we actually created a file | 344 | } |
| 238 | then we now have to set the mode if possible */ | 345 | |
| 239 | if ((tcon->unix_ext) && (oplock & CIFS_CREATE_ACTION)) { | 346 | /* If Open reported that we actually created a file |
| 240 | struct cifs_unix_set_info_args args = { | 347 | then we now have to set the mode if possible */ |
| 348 | if ((tcon->unix_ext) && (oplock & CIFS_CREATE_ACTION)) { | ||
| 349 | struct cifs_unix_set_info_args args = { | ||
| 241 | .mode = mode, | 350 | .mode = mode, |
| 242 | .ctime = NO_CHANGE_64, | 351 | .ctime = NO_CHANGE_64, |
| 243 | .atime = NO_CHANGE_64, | 352 | .atime = NO_CHANGE_64, |
| 244 | .mtime = NO_CHANGE_64, | 353 | .mtime = NO_CHANGE_64, |
| 245 | .device = 0, | 354 | .device = 0, |
| 246 | }; | 355 | }; |
| 247 | 356 | ||
| 248 | if (cifs_sb->mnt_cifs_flags & CIFS_MOUNT_SET_UID) { | 357 | if (cifs_sb->mnt_cifs_flags & CIFS_MOUNT_SET_UID) { |
| 249 | args.uid = (__u64) current_fsuid(); | 358 | args.uid = (__u64) current_fsuid(); |
| 250 | if (inode->i_mode & S_ISGID) | 359 | if (inode->i_mode & S_ISGID) |
| 251 | args.gid = (__u64) inode->i_gid; | 360 | args.gid = (__u64) inode->i_gid; |
| 252 | else | 361 | else |
| 253 | args.gid = (__u64) current_fsgid(); | 362 | args.gid = (__u64) current_fsgid(); |
| 254 | } else { | ||
| 255 | args.uid = NO_CHANGE_64; | ||
| 256 | args.gid = NO_CHANGE_64; | ||
| 257 | } | ||
| 258 | CIFSSMBUnixSetInfo(xid, tcon, full_path, &args, | ||
| 259 | cifs_sb->local_nls, | ||
| 260 | cifs_sb->mnt_cifs_flags & | ||
| 261 | CIFS_MOUNT_MAP_SPECIAL_CHR); | ||
| 262 | } else { | 363 | } else { |
| 263 | /* BB implement mode setting via Windows security | 364 | args.uid = NO_CHANGE_64; |
| 264 | descriptors e.g. */ | 365 | args.gid = NO_CHANGE_64; |
| 265 | /* CIFSSMBWinSetPerms(xid,tcon,path,mode,-1,-1,nls);*/ | ||
| 266 | |||
| 267 | /* Could set r/o dos attribute if mode & 0222 == 0 */ | ||
| 268 | } | 366 | } |
| 367 | CIFSSMBUnixSetInfo(xid, tcon, full_path, &args, | ||
| 368 | cifs_sb->local_nls, | ||
| 369 | cifs_sb->mnt_cifs_flags & CIFS_MOUNT_MAP_SPECIAL_CHR); | ||
| 370 | } else { | ||
| 371 | /* BB implement mode setting via Windows security | ||
| 372 | descriptors e.g. */ | ||
| 373 | /* CIFSSMBWinSetPerms(xid,tcon,path,mode,-1,-1,nls);*/ | ||
| 269 | 374 | ||
| 270 | /* server might mask mode so we have to query for it */ | 375 | /* Could set r/o dos attribute if mode & 0222 == 0 */ |
| 271 | if (tcon->unix_ext) | 376 | } |
| 272 | rc = cifs_get_inode_info_unix(&newinode, full_path, | 377 | |
| 273 | inode->i_sb, xid); | 378 | cifs_create_get_file_info: |
| 274 | else { | 379 | /* server might mask mode so we have to query for it */ |
| 275 | rc = cifs_get_inode_info(&newinode, full_path, | 380 | if (tcon->unix_ext) |
| 276 | buf, inode->i_sb, xid, | 381 | rc = cifs_get_inode_info_unix(&newinode, full_path, |
| 277 | &fileHandle); | 382 | inode->i_sb, xid); |
| 278 | if (newinode) { | 383 | else { |
| 279 | if (cifs_sb->mnt_cifs_flags & | 384 | rc = cifs_get_inode_info(&newinode, full_path, buf, |
| 280 | CIFS_MOUNT_DYNPERM) | 385 | inode->i_sb, xid, &fileHandle); |
| 281 | newinode->i_mode = mode; | 386 | if (newinode) { |
| 282 | if ((oplock & CIFS_CREATE_ACTION) && | 387 | if (cifs_sb->mnt_cifs_flags & CIFS_MOUNT_DYNPERM) |
| 283 | (cifs_sb->mnt_cifs_flags & | 388 | newinode->i_mode = mode; |
| 284 | CIFS_MOUNT_SET_UID)) { | 389 | if ((oplock & CIFS_CREATE_ACTION) && |
| 285 | newinode->i_uid = current_fsuid(); | 390 | (cifs_sb->mnt_cifs_flags & CIFS_MOUNT_SET_UID)) { |
| 286 | if (inode->i_mode & S_ISGID) | 391 | newinode->i_uid = current_fsuid(); |
| 287 | newinode->i_gid = | 392 | if (inode->i_mode & S_ISGID) |
| 288 | inode->i_gid; | 393 | newinode->i_gid = inode->i_gid; |
| 289 | else | 394 | else |
| 290 | newinode->i_gid = | 395 | newinode->i_gid = current_fsgid(); |
| 291 | current_fsgid(); | ||
| 292 | } | ||
| 293 | } | 396 | } |
| 294 | } | 397 | } |
| 398 | } | ||
| 295 | 399 | ||
| 296 | if (rc != 0) { | 400 | cifs_create_set_dentry: |
| 297 | cFYI(1, ("Create worked, get_inode_info failed rc = %d", | 401 | if (rc == 0) |
| 298 | rc)); | 402 | setup_cifs_dentry(tcon, direntry, newinode); |
| 299 | } else | 403 | else |
| 300 | setup_cifs_dentry(tcon, direntry, newinode); | 404 | cFYI(1, ("Create worked, get_inode_info failed rc = %d", rc)); |
| 301 | 405 | ||
| 302 | if ((nd == NULL /* nfsd case - nfs srv does not set nd */) || | 406 | /* nfsd case - nfs srv does not set nd */ |
| 303 | (!(nd->flags & LOOKUP_OPEN))) { | 407 | if ((nd == NULL) || (!(nd->flags & LOOKUP_OPEN))) { |
| 304 | /* mknod case - do not leave file open */ | 408 | /* mknod case - do not leave file open */ |
| 305 | CIFSSMBClose(xid, tcon, fileHandle); | 409 | CIFSSMBClose(xid, tcon, fileHandle); |
| 306 | } else if (newinode) { | 410 | } else if (newinode) { |
| 307 | struct cifsFileInfo *pCifsFile = | 411 | struct cifsFileInfo *pCifsFile = |
| 308 | kzalloc(sizeof(struct cifsFileInfo), GFP_KERNEL); | 412 | kzalloc(sizeof(struct cifsFileInfo), GFP_KERNEL); |
| 309 | 413 | ||
| 310 | if (pCifsFile == NULL) | 414 | if (pCifsFile == NULL) |
| 311 | goto cifs_create_out; | 415 | goto cifs_create_out; |
| 312 | pCifsFile->netfid = fileHandle; | 416 | pCifsFile->netfid = fileHandle; |
| 313 | pCifsFile->pid = current->tgid; | 417 | pCifsFile->pid = current->tgid; |
| 314 | pCifsFile->pInode = newinode; | 418 | pCifsFile->pInode = newinode; |
| 315 | pCifsFile->invalidHandle = false; | 419 | pCifsFile->invalidHandle = false; |
| 316 | pCifsFile->closePend = false; | 420 | pCifsFile->closePend = false; |
| 317 | init_MUTEX(&pCifsFile->fh_sem); | 421 | init_MUTEX(&pCifsFile->fh_sem); |
| 318 | mutex_init(&pCifsFile->lock_mutex); | 422 | mutex_init(&pCifsFile->lock_mutex); |
| 319 | INIT_LIST_HEAD(&pCifsFile->llist); | 423 | INIT_LIST_HEAD(&pCifsFile->llist); |
| 320 | atomic_set(&pCifsFile->wrtPending, 0); | 424 | atomic_set(&pCifsFile->wrtPending, 0); |
| 321 | 425 | ||
| 322 | /* set the following in open now | 426 | /* set the following in open now |
| 323 | pCifsFile->pfile = file; */ | 427 | pCifsFile->pfile = file; */ |
| 324 | write_lock(&GlobalSMBSeslock); | 428 | write_lock(&GlobalSMBSeslock); |
| 325 | list_add(&pCifsFile->tlist, &tcon->openFileList); | 429 | list_add(&pCifsFile->tlist, &tcon->openFileList); |
| 326 | pCifsInode = CIFS_I(newinode); | 430 | pCifsInode = CIFS_I(newinode); |
| 327 | if (pCifsInode) { | 431 | if (pCifsInode) { |
| 328 | /* if readable file instance put first in list*/ | 432 | /* if readable file instance put first in list*/ |
| 329 | if (write_only) { | 433 | if (write_only) { |
| 330 | list_add_tail(&pCifsFile->flist, | 434 | list_add_tail(&pCifsFile->flist, |
| 331 | &pCifsInode->openFileList); | 435 | &pCifsInode->openFileList); |
| 332 | } else { | 436 | } else { |
| 333 | list_add(&pCifsFile->flist, | 437 | list_add(&pCifsFile->flist, |
| 334 | &pCifsInode->openFileList); | 438 | &pCifsInode->openFileList); |
| 335 | } | ||
| 336 | if ((oplock & 0xF) == OPLOCK_EXCLUSIVE) { | ||
| 337 | pCifsInode->clientCanCacheAll = true; | ||
| 338 | pCifsInode->clientCanCacheRead = true; | ||
| 339 | cFYI(1, ("Exclusive Oplock inode %p", | ||
| 340 | newinode)); | ||
| 341 | } else if ((oplock & 0xF) == OPLOCK_READ) | ||
| 342 | pCifsInode->clientCanCacheRead = true; | ||
| 343 | } | 439 | } |
| 344 | write_unlock(&GlobalSMBSeslock); | 440 | if ((oplock & 0xF) == OPLOCK_EXCLUSIVE) { |
| 441 | pCifsInode->clientCanCacheAll = true; | ||
| 442 | pCifsInode->clientCanCacheRead = true; | ||
| 443 | cFYI(1, ("Exclusive Oplock inode %p", | ||
| 444 | newinode)); | ||
| 445 | } else if ((oplock & 0xF) == OPLOCK_READ) | ||
| 446 | pCifsInode->clientCanCacheRead = true; | ||
| 345 | } | 447 | } |
| 448 | write_unlock(&GlobalSMBSeslock); | ||
| 346 | } | 449 | } |
| 347 | cifs_create_out: | 450 | cifs_create_out: |
| 348 | kfree(buf); | 451 | kfree(buf); |
diff --git a/fs/cifs/inode.c b/fs/cifs/inode.c index bcf7b5184664..4690a360c855 100644 --- a/fs/cifs/inode.c +++ b/fs/cifs/inode.c | |||
| @@ -199,6 +199,49 @@ static void fill_fake_finddataunix(FILE_UNIX_BASIC_INFO *pfnd_dat, | |||
| 199 | pfnd_dat->Gid = cpu_to_le64(pinode->i_gid); | 199 | pfnd_dat->Gid = cpu_to_le64(pinode->i_gid); |
| 200 | } | 200 | } |
| 201 | 201 | ||
| 202 | /** | ||
| 203 | * cifs_new inode - create new inode, initialize, and hash it | ||
| 204 | * @sb - pointer to superblock | ||
| 205 | * @inum - if valid pointer and serverino is enabled, replace i_ino with val | ||
| 206 | * | ||
| 207 | * Create a new inode, initialize it for CIFS and hash it. Returns the new | ||
| 208 | * inode or NULL if one couldn't be allocated. | ||
| 209 | * | ||
| 210 | * If the share isn't mounted with "serverino" or inum is a NULL pointer then | ||
| 211 | * we'll just use the inode number assigned by new_inode(). Note that this can | ||
| 212 | * mean i_ino collisions since the i_ino assigned by new_inode is not | ||
| 213 | * guaranteed to be unique. | ||
| 214 | */ | ||
| 215 | struct inode * | ||
| 216 | cifs_new_inode(struct super_block *sb, __u64 *inum) | ||
| 217 | { | ||
| 218 | struct inode *inode; | ||
| 219 | |||
| 220 | inode = new_inode(sb); | ||
| 221 | if (inode == NULL) | ||
| 222 | return NULL; | ||
| 223 | |||
| 224 | /* | ||
| 225 | * BB: Is i_ino == 0 legal? Here, we assume that it is. If it isn't we | ||
| 226 | * stop passing inum as ptr. Are there sanity checks we can use to | ||
| 227 | * ensure that the server is really filling in that field? Also, | ||
| 228 | * if serverino is disabled, perhaps we should be using iunique()? | ||
| 229 | */ | ||
| 230 | if (inum && (CIFS_SB(sb)->mnt_cifs_flags & CIFS_MOUNT_SERVER_INUM)) | ||
| 231 | inode->i_ino = (unsigned long) *inum; | ||
| 232 | |||
| 233 | /* | ||
| 234 | * must set this here instead of cifs_alloc_inode since VFS will | ||
| 235 | * clobber i_flags | ||
| 236 | */ | ||
| 237 | if (sb->s_flags & MS_NOATIME) | ||
| 238 | inode->i_flags |= S_NOATIME | S_NOCMTIME; | ||
| 239 | |||
| 240 | insert_inode_hash(inode); | ||
| 241 | |||
| 242 | return inode; | ||
| 243 | } | ||
| 244 | |||
| 202 | int cifs_get_inode_info_unix(struct inode **pinode, | 245 | int cifs_get_inode_info_unix(struct inode **pinode, |
| 203 | const unsigned char *full_path, struct super_block *sb, int xid) | 246 | const unsigned char *full_path, struct super_block *sb, int xid) |
| 204 | { | 247 | { |
| @@ -233,22 +276,11 @@ int cifs_get_inode_info_unix(struct inode **pinode, | |||
| 233 | 276 | ||
| 234 | /* get new inode */ | 277 | /* get new inode */ |
| 235 | if (*pinode == NULL) { | 278 | if (*pinode == NULL) { |
| 236 | *pinode = new_inode(sb); | 279 | *pinode = cifs_new_inode(sb, &find_data.UniqueId); |
| 237 | if (*pinode == NULL) { | 280 | if (*pinode == NULL) { |
| 238 | rc = -ENOMEM; | 281 | rc = -ENOMEM; |
| 239 | goto cgiiu_exit; | 282 | goto cgiiu_exit; |
| 240 | } | 283 | } |
| 241 | /* Is an i_ino of zero legal? */ | ||
| 242 | /* note ino incremented to unique num in new_inode */ | ||
| 243 | /* Are there sanity checks we can use to ensure that | ||
| 244 | the server is really filling in that field? */ | ||
| 245 | if (cifs_sb->mnt_cifs_flags & CIFS_MOUNT_SERVER_INUM) | ||
| 246 | (*pinode)->i_ino = (unsigned long)find_data.UniqueId; | ||
| 247 | |||
| 248 | if (sb->s_flags & MS_NOATIME) | ||
| 249 | (*pinode)->i_flags |= S_NOATIME | S_NOCMTIME; | ||
| 250 | |||
| 251 | insert_inode_hash(*pinode); | ||
| 252 | } | 284 | } |
| 253 | 285 | ||
| 254 | inode = *pinode; | 286 | inode = *pinode; |
| @@ -465,11 +497,9 @@ int cifs_get_inode_info(struct inode **pinode, | |||
| 465 | 497 | ||
| 466 | /* get new inode */ | 498 | /* get new inode */ |
| 467 | if (*pinode == NULL) { | 499 | if (*pinode == NULL) { |
| 468 | *pinode = new_inode(sb); | 500 | __u64 inode_num; |
| 469 | if (*pinode == NULL) { | 501 | __u64 *pinum = &inode_num; |
| 470 | rc = -ENOMEM; | 502 | |
| 471 | goto cgii_exit; | ||
| 472 | } | ||
| 473 | /* Is an i_ino of zero legal? Can we use that to check | 503 | /* Is an i_ino of zero legal? Can we use that to check |
| 474 | if the server supports returning inode numbers? Are | 504 | if the server supports returning inode numbers? Are |
| 475 | there other sanity checks we can use to ensure that | 505 | there other sanity checks we can use to ensure that |
| @@ -486,22 +516,26 @@ int cifs_get_inode_info(struct inode **pinode, | |||
| 486 | 516 | ||
| 487 | if (cifs_sb->mnt_cifs_flags & CIFS_MOUNT_SERVER_INUM) { | 517 | if (cifs_sb->mnt_cifs_flags & CIFS_MOUNT_SERVER_INUM) { |
| 488 | int rc1 = 0; | 518 | int rc1 = 0; |
| 489 | __u64 inode_num; | ||
| 490 | 519 | ||
| 491 | rc1 = CIFSGetSrvInodeNumber(xid, pTcon, | 520 | rc1 = CIFSGetSrvInodeNumber(xid, pTcon, |
| 492 | full_path, &inode_num, | 521 | full_path, pinum, |
| 493 | cifs_sb->local_nls, | 522 | cifs_sb->local_nls, |
| 494 | cifs_sb->mnt_cifs_flags & | 523 | cifs_sb->mnt_cifs_flags & |
| 495 | CIFS_MOUNT_MAP_SPECIAL_CHR); | 524 | CIFS_MOUNT_MAP_SPECIAL_CHR); |
| 496 | if (rc1) { | 525 | if (rc1) { |
| 497 | cFYI(1, ("GetSrvInodeNum rc %d", rc1)); | 526 | cFYI(1, ("GetSrvInodeNum rc %d", rc1)); |
| 527 | pinum = NULL; | ||
| 498 | /* BB EOPNOSUPP disable SERVER_INUM? */ | 528 | /* BB EOPNOSUPP disable SERVER_INUM? */ |
| 499 | } else /* do we need cast or hash to ino? */ | 529 | } |
| 500 | (*pinode)->i_ino = inode_num; | 530 | } else { |
| 501 | } /* else ino incremented to unique num in new_inode*/ | 531 | pinum = NULL; |
| 502 | if (sb->s_flags & MS_NOATIME) | 532 | } |
| 503 | (*pinode)->i_flags |= S_NOATIME | S_NOCMTIME; | 533 | |
| 504 | insert_inode_hash(*pinode); | 534 | *pinode = cifs_new_inode(sb, pinum); |
| 535 | if (*pinode == NULL) { | ||
| 536 | rc = -ENOMEM; | ||
| 537 | goto cgii_exit; | ||
| 538 | } | ||
| 505 | } | 539 | } |
| 506 | inode = *pinode; | 540 | inode = *pinode; |
| 507 | cifsInfo = CIFS_I(inode); | 541 | cifsInfo = CIFS_I(inode); |
| @@ -621,7 +655,7 @@ static const struct inode_operations cifs_ipc_inode_ops = { | |||
| 621 | .lookup = cifs_lookup, | 655 | .lookup = cifs_lookup, |
| 622 | }; | 656 | }; |
| 623 | 657 | ||
| 624 | static char *build_path_to_root(struct cifs_sb_info *cifs_sb) | 658 | char *cifs_build_path_to_root(struct cifs_sb_info *cifs_sb) |
| 625 | { | 659 | { |
| 626 | int pplen = cifs_sb->prepathlen; | 660 | int pplen = cifs_sb->prepathlen; |
| 627 | int dfsplen; | 661 | int dfsplen; |
| @@ -678,7 +712,7 @@ struct inode *cifs_iget(struct super_block *sb, unsigned long ino) | |||
| 678 | return inode; | 712 | return inode; |
| 679 | 713 | ||
| 680 | cifs_sb = CIFS_SB(inode->i_sb); | 714 | cifs_sb = CIFS_SB(inode->i_sb); |
| 681 | full_path = build_path_to_root(cifs_sb); | 715 | full_path = cifs_build_path_to_root(cifs_sb); |
| 682 | if (full_path == NULL) | 716 | if (full_path == NULL) |
| 683 | return ERR_PTR(-ENOMEM); | 717 | return ERR_PTR(-ENOMEM); |
| 684 | 718 | ||
| @@ -1017,7 +1051,7 @@ out_reval: | |||
| 1017 | return rc; | 1051 | return rc; |
| 1018 | } | 1052 | } |
| 1019 | 1053 | ||
| 1020 | static void posix_fill_in_inode(struct inode *tmp_inode, | 1054 | void posix_fill_in_inode(struct inode *tmp_inode, |
| 1021 | FILE_UNIX_BASIC_INFO *pData, int isNewInode) | 1055 | FILE_UNIX_BASIC_INFO *pData, int isNewInode) |
| 1022 | { | 1056 | { |
| 1023 | struct cifsInodeInfo *cifsInfo = CIFS_I(tmp_inode); | 1057 | struct cifsInodeInfo *cifsInfo = CIFS_I(tmp_inode); |
| @@ -1114,24 +1148,14 @@ int cifs_mkdir(struct inode *inode, struct dentry *direntry, int mode) | |||
| 1114 | else | 1148 | else |
| 1115 | direntry->d_op = &cifs_dentry_ops; | 1149 | direntry->d_op = &cifs_dentry_ops; |
| 1116 | 1150 | ||
| 1117 | newinode = new_inode(inode->i_sb); | 1151 | newinode = cifs_new_inode(inode->i_sb, |
| 1152 | &pInfo->UniqueId); | ||
| 1118 | if (newinode == NULL) { | 1153 | if (newinode == NULL) { |
| 1119 | kfree(pInfo); | 1154 | kfree(pInfo); |
| 1120 | goto mkdir_get_info; | 1155 | goto mkdir_get_info; |
| 1121 | } | 1156 | } |
| 1122 | 1157 | ||
| 1123 | /* Is an i_ino of zero legal? */ | ||
| 1124 | /* Are there sanity checks we can use to ensure that | ||
| 1125 | the server is really filling in that field? */ | ||
| 1126 | if (cifs_sb->mnt_cifs_flags & CIFS_MOUNT_SERVER_INUM) { | ||
| 1127 | newinode->i_ino = | ||
| 1128 | (unsigned long)pInfo->UniqueId; | ||
| 1129 | } /* note ino incremented to unique num in new_inode */ | ||
| 1130 | if (inode->i_sb->s_flags & MS_NOATIME) | ||
| 1131 | newinode->i_flags |= S_NOATIME | S_NOCMTIME; | ||
| 1132 | newinode->i_nlink = 2; | 1158 | newinode->i_nlink = 2; |
| 1133 | |||
| 1134 | insert_inode_hash(newinode); | ||
| 1135 | d_instantiate(direntry, newinode); | 1159 | d_instantiate(direntry, newinode); |
| 1136 | 1160 | ||
| 1137 | /* we already checked in POSIXCreate whether | 1161 | /* we already checked in POSIXCreate whether |
diff --git a/fs/cifs/readdir.c b/fs/cifs/readdir.c index 9f51f9bf0292..c2c01ff4c32c 100644 --- a/fs/cifs/readdir.c +++ b/fs/cifs/readdir.c | |||
| @@ -56,35 +56,34 @@ static inline void dump_cifs_file_struct(struct file *file, char *label) | |||
| 56 | } | 56 | } |
| 57 | #endif /* DEBUG2 */ | 57 | #endif /* DEBUG2 */ |
| 58 | 58 | ||
| 59 | /* Returns one if new inode created (which therefore needs to be hashed) */ | 59 | /* Returns 1 if new inode created, 2 if both dentry and inode were */ |
| 60 | /* Might check in the future if inode number changed so we can rehash inode */ | 60 | /* Might check in the future if inode number changed so we can rehash inode */ |
| 61 | static int construct_dentry(struct qstr *qstring, struct file *file, | 61 | static int |
| 62 | struct inode **ptmp_inode, struct dentry **pnew_dentry) | 62 | construct_dentry(struct qstr *qstring, struct file *file, |
| 63 | struct inode **ptmp_inode, struct dentry **pnew_dentry, | ||
| 64 | __u64 *inum) | ||
| 63 | { | 65 | { |
| 64 | struct dentry *tmp_dentry; | 66 | struct dentry *tmp_dentry = NULL; |
| 65 | struct cifs_sb_info *cifs_sb; | 67 | struct super_block *sb = file->f_path.dentry->d_sb; |
| 66 | struct cifsTconInfo *pTcon; | ||
| 67 | int rc = 0; | 68 | int rc = 0; |
| 68 | 69 | ||
| 69 | cFYI(1, ("For %s", qstring->name)); | 70 | cFYI(1, ("For %s", qstring->name)); |
| 70 | cifs_sb = CIFS_SB(file->f_path.dentry->d_sb); | ||
| 71 | pTcon = cifs_sb->tcon; | ||
| 72 | 71 | ||
| 73 | qstring->hash = full_name_hash(qstring->name, qstring->len); | 72 | qstring->hash = full_name_hash(qstring->name, qstring->len); |
| 74 | tmp_dentry = d_lookup(file->f_path.dentry, qstring); | 73 | tmp_dentry = d_lookup(file->f_path.dentry, qstring); |
| 75 | if (tmp_dentry) { | 74 | if (tmp_dentry) { |
| 75 | /* BB: overwrite old name? i.e. tmp_dentry->d_name and | ||
| 76 | * tmp_dentry->d_name.len?? | ||
| 77 | */ | ||
| 76 | cFYI(0, ("existing dentry with inode 0x%p", | 78 | cFYI(0, ("existing dentry with inode 0x%p", |
| 77 | tmp_dentry->d_inode)); | 79 | tmp_dentry->d_inode)); |
| 78 | *ptmp_inode = tmp_dentry->d_inode; | 80 | *ptmp_inode = tmp_dentry->d_inode; |
| 79 | /* BB overwrite old name? i.e. tmp_dentry->d_name and tmp_dentry->d_name.len??*/ | ||
| 80 | if (*ptmp_inode == NULL) { | 81 | if (*ptmp_inode == NULL) { |
| 81 | *ptmp_inode = new_inode(file->f_path.dentry->d_sb); | 82 | *ptmp_inode = cifs_new_inode(sb, inum); |
| 82 | if (*ptmp_inode == NULL) | 83 | if (*ptmp_inode == NULL) |
| 83 | return rc; | 84 | return rc; |
| 84 | rc = 1; | 85 | rc = 1; |
| 85 | } | 86 | } |
| 86 | if (file->f_path.dentry->d_sb->s_flags & MS_NOATIME) | ||
| 87 | (*ptmp_inode)->i_flags |= S_NOATIME | S_NOCMTIME; | ||
| 88 | } else { | 87 | } else { |
| 89 | tmp_dentry = d_alloc(file->f_path.dentry, qstring); | 88 | tmp_dentry = d_alloc(file->f_path.dentry, qstring); |
| 90 | if (tmp_dentry == NULL) { | 89 | if (tmp_dentry == NULL) { |
| @@ -93,15 +92,14 @@ static int construct_dentry(struct qstr *qstring, struct file *file, | |||
| 93 | return rc; | 92 | return rc; |
| 94 | } | 93 | } |
| 95 | 94 | ||
| 96 | *ptmp_inode = new_inode(file->f_path.dentry->d_sb); | 95 | if (CIFS_SB(sb)->tcon->nocase) |
| 97 | if (pTcon->nocase) | ||
| 98 | tmp_dentry->d_op = &cifs_ci_dentry_ops; | 96 | tmp_dentry->d_op = &cifs_ci_dentry_ops; |
| 99 | else | 97 | else |
| 100 | tmp_dentry->d_op = &cifs_dentry_ops; | 98 | tmp_dentry->d_op = &cifs_dentry_ops; |
| 99 | |||
| 100 | *ptmp_inode = cifs_new_inode(sb, inum); | ||
| 101 | if (*ptmp_inode == NULL) | 101 | if (*ptmp_inode == NULL) |
| 102 | return rc; | 102 | return rc; |
| 103 | if (file->f_path.dentry->d_sb->s_flags & MS_NOATIME) | ||
| 104 | (*ptmp_inode)->i_flags |= S_NOATIME | S_NOCMTIME; | ||
| 105 | rc = 2; | 103 | rc = 2; |
| 106 | } | 104 | } |
| 107 | 105 | ||
| @@ -822,7 +820,7 @@ static int find_cifs_entry(const int xid, struct cifsTconInfo *pTcon, | |||
| 822 | /* inode num, inode type and filename returned */ | 820 | /* inode num, inode type and filename returned */ |
| 823 | static int cifs_get_name_from_search_buf(struct qstr *pqst, | 821 | static int cifs_get_name_from_search_buf(struct qstr *pqst, |
| 824 | char *current_entry, __u16 level, unsigned int unicode, | 822 | char *current_entry, __u16 level, unsigned int unicode, |
| 825 | struct cifs_sb_info *cifs_sb, int max_len, ino_t *pinum) | 823 | struct cifs_sb_info *cifs_sb, int max_len, __u64 *pinum) |
| 826 | { | 824 | { |
| 827 | int rc = 0; | 825 | int rc = 0; |
| 828 | unsigned int len = 0; | 826 | unsigned int len = 0; |
| @@ -842,9 +840,7 @@ static int cifs_get_name_from_search_buf(struct qstr *pqst, | |||
| 842 | len = strnlen(filename, PATH_MAX); | 840 | len = strnlen(filename, PATH_MAX); |
| 843 | } | 841 | } |
| 844 | 842 | ||
| 845 | /* BB fixme - hash low and high 32 bits if not 64 bit arch BB */ | 843 | *pinum = pFindData->UniqueId; |
| 846 | if (cifs_sb->mnt_cifs_flags & CIFS_MOUNT_SERVER_INUM) | ||
| 847 | *pinum = pFindData->UniqueId; | ||
| 848 | } else if (level == SMB_FIND_FILE_DIRECTORY_INFO) { | 844 | } else if (level == SMB_FIND_FILE_DIRECTORY_INFO) { |
| 849 | FILE_DIRECTORY_INFO *pFindData = | 845 | FILE_DIRECTORY_INFO *pFindData = |
| 850 | (FILE_DIRECTORY_INFO *)current_entry; | 846 | (FILE_DIRECTORY_INFO *)current_entry; |
| @@ -907,7 +903,7 @@ static int cifs_filldir(char *pfindEntry, struct file *file, | |||
| 907 | struct qstr qstring; | 903 | struct qstr qstring; |
| 908 | struct cifsFileInfo *pCifsF; | 904 | struct cifsFileInfo *pCifsF; |
| 909 | unsigned int obj_type; | 905 | unsigned int obj_type; |
| 910 | ino_t inum; | 906 | __u64 inum; |
| 911 | struct cifs_sb_info *cifs_sb; | 907 | struct cifs_sb_info *cifs_sb; |
| 912 | struct inode *tmp_inode; | 908 | struct inode *tmp_inode; |
| 913 | struct dentry *tmp_dentry; | 909 | struct dentry *tmp_dentry; |
| @@ -940,20 +936,18 @@ static int cifs_filldir(char *pfindEntry, struct file *file, | |||
| 940 | if (rc) | 936 | if (rc) |
| 941 | return rc; | 937 | return rc; |
| 942 | 938 | ||
| 943 | rc = construct_dentry(&qstring, file, &tmp_inode, &tmp_dentry); | 939 | /* only these two infolevels return valid inode numbers */ |
| 940 | if (pCifsF->srch_inf.info_level == SMB_FIND_FILE_UNIX || | ||
| 941 | pCifsF->srch_inf.info_level == SMB_FIND_FILE_ID_FULL_DIR_INFO) | ||
| 942 | rc = construct_dentry(&qstring, file, &tmp_inode, &tmp_dentry, | ||
| 943 | &inum); | ||
| 944 | else | ||
| 945 | rc = construct_dentry(&qstring, file, &tmp_inode, &tmp_dentry, | ||
| 946 | NULL); | ||
| 947 | |||
| 944 | if ((tmp_inode == NULL) || (tmp_dentry == NULL)) | 948 | if ((tmp_inode == NULL) || (tmp_dentry == NULL)) |
| 945 | return -ENOMEM; | 949 | return -ENOMEM; |
| 946 | 950 | ||
| 947 | if (rc) { | ||
| 948 | /* inode created, we need to hash it with right inode number */ | ||
| 949 | if (inum != 0) { | ||
| 950 | /* BB fixme - hash the 2 32 quantities bits together if | ||
| 951 | * necessary BB */ | ||
| 952 | tmp_inode->i_ino = inum; | ||
| 953 | } | ||
| 954 | insert_inode_hash(tmp_inode); | ||
| 955 | } | ||
| 956 | |||
| 957 | /* we pass in rc below, indicating whether it is a new inode, | 951 | /* we pass in rc below, indicating whether it is a new inode, |
| 958 | so we can figure out whether to invalidate the inode cached | 952 | so we can figure out whether to invalidate the inode cached |
| 959 | data if the file has changed */ | 953 | data if the file has changed */ |
diff --git a/fs/cifs/sess.c b/fs/cifs/sess.c index 5f22de7b79a9..5c68b4282be9 100644 --- a/fs/cifs/sess.c +++ b/fs/cifs/sess.c | |||
| @@ -34,15 +34,99 @@ | |||
| 34 | extern void SMBNTencrypt(unsigned char *passwd, unsigned char *c8, | 34 | extern void SMBNTencrypt(unsigned char *passwd, unsigned char *c8, |
| 35 | unsigned char *p24); | 35 | unsigned char *p24); |
| 36 | 36 | ||
| 37 | /* Checks if this is the first smb session to be reconnected after | ||
| 38 | the socket has been reestablished (so we know whether to use vc 0). | ||
| 39 | Called while holding the cifs_tcp_ses_lock, so do not block */ | ||
| 40 | static bool is_first_ses_reconnect(struct cifsSesInfo *ses) | ||
| 41 | { | ||
| 42 | struct list_head *tmp; | ||
| 43 | struct cifsSesInfo *tmp_ses; | ||
| 44 | |||
| 45 | list_for_each(tmp, &ses->server->smb_ses_list) { | ||
| 46 | tmp_ses = list_entry(tmp, struct cifsSesInfo, | ||
| 47 | smb_ses_list); | ||
| 48 | if (tmp_ses->need_reconnect == false) | ||
| 49 | return false; | ||
| 50 | } | ||
| 51 | /* could not find a session that was already connected, | ||
| 52 | this must be the first one we are reconnecting */ | ||
| 53 | return true; | ||
| 54 | } | ||
| 55 | |||
| 56 | /* | ||
| 57 | * vc number 0 is treated specially by some servers, and should be the | ||
| 58 | * first one we request. After that we can use vcnumbers up to maxvcs, | ||
| 59 | * one for each smb session (some Windows versions set maxvcs incorrectly | ||
| 60 | * so maxvc=1 can be ignored). If we have too many vcs, we can reuse | ||
| 61 | * any vc but zero (some servers reset the connection on vcnum zero) | ||
| 62 | * | ||
| 63 | */ | ||
| 64 | static __le16 get_next_vcnum(struct cifsSesInfo *ses) | ||
| 65 | { | ||
| 66 | __u16 vcnum = 0; | ||
| 67 | struct list_head *tmp; | ||
| 68 | struct cifsSesInfo *tmp_ses; | ||
| 69 | __u16 max_vcs = ses->server->max_vcs; | ||
| 70 | __u16 i; | ||
| 71 | int free_vc_found = 0; | ||
| 72 | |||
| 73 | /* Quoting the MS-SMB specification: "Windows-based SMB servers set this | ||
| 74 | field to one but do not enforce this limit, which allows an SMB client | ||
| 75 | to establish more virtual circuits than allowed by this value ... but | ||
| 76 | other server implementations can enforce this limit." */ | ||
| 77 | if (max_vcs < 2) | ||
| 78 | max_vcs = 0xFFFF; | ||
| 79 | |||
| 80 | write_lock(&cifs_tcp_ses_lock); | ||
| 81 | if ((ses->need_reconnect) && is_first_ses_reconnect(ses)) | ||
| 82 | goto get_vc_num_exit; /* vcnum will be zero */ | ||
| 83 | for (i = ses->server->srv_count - 1; i < max_vcs; i++) { | ||
| 84 | if (i == 0) /* this is the only connection, use vc 0 */ | ||
| 85 | break; | ||
| 86 | |||
| 87 | free_vc_found = 1; | ||
| 88 | |||
| 89 | list_for_each(tmp, &ses->server->smb_ses_list) { | ||
| 90 | tmp_ses = list_entry(tmp, struct cifsSesInfo, | ||
| 91 | smb_ses_list); | ||
| 92 | if (tmp_ses->vcnum == i) { | ||
| 93 | free_vc_found = 0; | ||
| 94 | break; /* found duplicate, try next vcnum */ | ||
| 95 | } | ||
| 96 | } | ||
| 97 | if (free_vc_found) | ||
| 98 | break; /* we found a vcnumber that will work - use it */ | ||
| 99 | } | ||
| 100 | |||
| 101 | if (i == 0) | ||
| 102 | vcnum = 0; /* for most common case, ie if one smb session, use | ||
| 103 | vc zero. Also for case when no free vcnum, zero | ||
| 104 | is safest to send (some clients only send zero) */ | ||
| 105 | else if (free_vc_found == 0) | ||
| 106 | vcnum = 1; /* we can not reuse vc=0 safely, since some servers | ||
| 107 | reset all uids on that, but 1 is ok. */ | ||
| 108 | else | ||
| 109 | vcnum = i; | ||
| 110 | ses->vcnum = vcnum; | ||
| 111 | get_vc_num_exit: | ||
| 112 | write_unlock(&cifs_tcp_ses_lock); | ||
| 113 | |||
| 114 | return le16_to_cpu(vcnum); | ||
| 115 | } | ||
| 116 | |||
| 37 | static __u32 cifs_ssetup_hdr(struct cifsSesInfo *ses, SESSION_SETUP_ANDX *pSMB) | 117 | static __u32 cifs_ssetup_hdr(struct cifsSesInfo *ses, SESSION_SETUP_ANDX *pSMB) |
| 38 | { | 118 | { |
| 39 | __u32 capabilities = 0; | 119 | __u32 capabilities = 0; |
| 40 | 120 | ||
| 41 | /* init fields common to all four types of SessSetup */ | 121 | /* init fields common to all four types of SessSetup */ |
| 42 | /* note that header is initialized to zero in header_assemble */ | 122 | /* Note that offsets for first seven fields in req struct are same */ |
| 123 | /* in CIFS Specs so does not matter which of 3 forms of struct */ | ||
| 124 | /* that we use in next few lines */ | ||
| 125 | /* Note that header is initialized to zero in header_assemble */ | ||
| 43 | pSMB->req.AndXCommand = 0xFF; | 126 | pSMB->req.AndXCommand = 0xFF; |
| 44 | pSMB->req.MaxBufferSize = cpu_to_le16(ses->server->maxBuf); | 127 | pSMB->req.MaxBufferSize = cpu_to_le16(ses->server->maxBuf); |
| 45 | pSMB->req.MaxMpxCount = cpu_to_le16(ses->server->maxReq); | 128 | pSMB->req.MaxMpxCount = cpu_to_le16(ses->server->maxReq); |
| 129 | pSMB->req.VcNumber = get_next_vcnum(ses); | ||
| 46 | 130 | ||
| 47 | /* Now no need to set SMBFLG_CASELESS or obsolete CANONICAL PATH */ | 131 | /* Now no need to set SMBFLG_CASELESS or obsolete CANONICAL PATH */ |
| 48 | 132 | ||
| @@ -71,7 +155,6 @@ static __u32 cifs_ssetup_hdr(struct cifsSesInfo *ses, SESSION_SETUP_ANDX *pSMB) | |||
| 71 | if (ses->capabilities & CAP_UNIX) | 155 | if (ses->capabilities & CAP_UNIX) |
| 72 | capabilities |= CAP_UNIX; | 156 | capabilities |= CAP_UNIX; |
| 73 | 157 | ||
| 74 | /* BB check whether to init vcnum BB */ | ||
| 75 | return capabilities; | 158 | return capabilities; |
| 76 | } | 159 | } |
| 77 | 160 | ||
| @@ -228,7 +311,7 @@ static int decode_unicode_ssetup(char **pbcc_area, int bleft, | |||
| 228 | 311 | ||
| 229 | kfree(ses->serverOS); | 312 | kfree(ses->serverOS); |
| 230 | /* UTF-8 string will not grow more than four times as big as UCS-16 */ | 313 | /* UTF-8 string will not grow more than four times as big as UCS-16 */ |
| 231 | ses->serverOS = kzalloc(4 * len, GFP_KERNEL); | 314 | ses->serverOS = kzalloc((4 * len) + 2 /* trailing null */, GFP_KERNEL); |
| 232 | if (ses->serverOS != NULL) | 315 | if (ses->serverOS != NULL) |
| 233 | cifs_strfromUCS_le(ses->serverOS, (__le16 *)data, len, nls_cp); | 316 | cifs_strfromUCS_le(ses->serverOS, (__le16 *)data, len, nls_cp); |
| 234 | data += 2 * (len + 1); | 317 | data += 2 * (len + 1); |
| @@ -241,7 +324,7 @@ static int decode_unicode_ssetup(char **pbcc_area, int bleft, | |||
| 241 | return rc; | 324 | return rc; |
| 242 | 325 | ||
| 243 | kfree(ses->serverNOS); | 326 | kfree(ses->serverNOS); |
| 244 | ses->serverNOS = kzalloc(4 * len, GFP_KERNEL); /* BB this is wrong length FIXME BB */ | 327 | ses->serverNOS = kzalloc((4 * len) + 2 /* trailing null */, GFP_KERNEL); |
| 245 | if (ses->serverNOS != NULL) { | 328 | if (ses->serverNOS != NULL) { |
| 246 | cifs_strfromUCS_le(ses->serverNOS, (__le16 *)data, len, | 329 | cifs_strfromUCS_le(ses->serverNOS, (__le16 *)data, len, |
| 247 | nls_cp); | 330 | nls_cp); |
