diff options
| -rw-r--r-- | fs/cifs/cifssmb.c | 312 |
1 files changed, 123 insertions, 189 deletions
diff --git a/fs/cifs/cifssmb.c b/fs/cifs/cifssmb.c index 5f0b80d39923..301e307e1279 100644 --- a/fs/cifs/cifssmb.c +++ b/fs/cifs/cifssmb.c | |||
| @@ -100,110 +100,138 @@ static void mark_open_files_invalid(struct cifsTconInfo *pTcon) | |||
| 100 | to this tcon */ | 100 | to this tcon */ |
| 101 | } | 101 | } |
| 102 | 102 | ||
| 103 | /* Allocate and return pointer to an SMB request buffer, and set basic | 103 | /* reconnect the socket, tcon, and smb session if needed */ |
| 104 | SMB information in the SMB header. If the return code is zero, this | ||
| 105 | function must have filled in request_buf pointer */ | ||
| 106 | static int | 104 | static int |
| 107 | small_smb_init(int smb_command, int wct, struct cifsTconInfo *tcon, | 105 | cifs_reconnect_tcon(struct cifsTconInfo *tcon, int smb_command) |
| 108 | void **request_buf) | ||
| 109 | { | 106 | { |
| 110 | int rc = 0; | 107 | int rc = 0; |
| 108 | struct cifsSesInfo *ses; | ||
| 109 | struct TCP_Server_Info *server; | ||
| 110 | struct nls_table *nls_codepage; | ||
| 111 | 111 | ||
| 112 | /* SMBs NegProt, SessSetup, uLogoff do not have tcon yet so | 112 | /* |
| 113 | check for tcp and smb session status done differently | 113 | * SMBs NegProt, SessSetup, uLogoff do not have tcon yet so check for |
| 114 | for those three - in the calling routine */ | 114 | * tcp and smb session status done differently for those three - in the |
| 115 | if (tcon) { | 115 | * calling routine |
| 116 | if (tcon->tidStatus == CifsExiting) { | 116 | */ |
| 117 | /* only tree disconnect, open, and write, | 117 | if (!tcon) |
| 118 | (and ulogoff which does not have tcon) | 118 | return 0; |
| 119 | are allowed as we start force umount */ | 119 | |
| 120 | if ((smb_command != SMB_COM_WRITE_ANDX) && | 120 | ses = tcon->ses; |
| 121 | (smb_command != SMB_COM_OPEN_ANDX) && | 121 | server = ses->server; |
| 122 | (smb_command != SMB_COM_TREE_DISCONNECT)) { | 122 | |
| 123 | cFYI(1, ("can not send cmd %d while umounting", | 123 | /* |
| 124 | smb_command)); | 124 | * only tree disconnect, open, and write, (and ulogoff which does not |
| 125 | return -ENODEV; | 125 | * have tcon) are allowed as we start force umount |
| 126 | } | 126 | */ |
| 127 | if (tcon->tidStatus == CifsExiting) { | ||
| 128 | if (smb_command != SMB_COM_WRITE_ANDX && | ||
| 129 | smb_command != SMB_COM_OPEN_ANDX && | ||
| 130 | smb_command != SMB_COM_TREE_DISCONNECT) { | ||
| 131 | cFYI(1, ("can not send cmd %d while umounting", | ||
| 132 | smb_command)); | ||
| 133 | return -ENODEV; | ||
| 127 | } | 134 | } |
| 128 | if ((tcon->ses) && (tcon->ses->status != CifsExiting) && | 135 | } |
| 129 | (tcon->ses->server)) { | ||
| 130 | struct nls_table *nls_codepage; | ||
| 131 | /* Give Demultiplex thread up to 10 seconds to | ||
| 132 | reconnect, should be greater than cifs socket | ||
| 133 | timeout which is 7 seconds */ | ||
| 134 | while (tcon->ses->server->tcpStatus == | ||
| 135 | CifsNeedReconnect) { | ||
| 136 | wait_event_interruptible_timeout(tcon->ses->server->response_q, | ||
| 137 | (tcon->ses->server->tcpStatus == | ||
| 138 | CifsGood), 10 * HZ); | ||
| 139 | if (tcon->ses->server->tcpStatus == | ||
| 140 | CifsNeedReconnect) { | ||
| 141 | /* on "soft" mounts we wait once */ | ||
| 142 | if (!tcon->retry || | ||
| 143 | (tcon->ses->status == CifsExiting)) { | ||
| 144 | cFYI(1, ("gave up waiting on " | ||
| 145 | "reconnect in smb_init")); | ||
| 146 | return -EHOSTDOWN; | ||
| 147 | } /* else "hard" mount - keep retrying | ||
| 148 | until process is killed or server | ||
| 149 | comes back on-line */ | ||
| 150 | } else /* TCP session is reestablished now */ | ||
| 151 | break; | ||
| 152 | } | ||
| 153 | 136 | ||
| 154 | nls_codepage = load_nls_default(); | 137 | if (ses->status == CifsExiting) |
| 155 | /* need to prevent multiple threads trying to | 138 | return -EIO; |
| 156 | simultaneously reconnect the same SMB session */ | ||
| 157 | down(&tcon->ses->sesSem); | ||
| 158 | if (tcon->ses->need_reconnect) | ||
| 159 | rc = cifs_setup_session(0, tcon->ses, | ||
| 160 | nls_codepage); | ||
| 161 | if (!rc && (tcon->need_reconnect)) { | ||
| 162 | mark_open_files_invalid(tcon); | ||
| 163 | rc = CIFSTCon(0, tcon->ses, tcon->treeName, | ||
| 164 | tcon, nls_codepage); | ||
| 165 | up(&tcon->ses->sesSem); | ||
| 166 | /* BB FIXME add code to check if wsize needs | ||
| 167 | update due to negotiated smb buffer size | ||
| 168 | shrinking */ | ||
| 169 | if (rc == 0) { | ||
| 170 | atomic_inc(&tconInfoReconnectCount); | ||
| 171 | /* tell server Unix caps we support */ | ||
| 172 | if (tcon->ses->capabilities & CAP_UNIX) | ||
| 173 | reset_cifs_unix_caps( | ||
| 174 | 0 /* no xid */, | ||
| 175 | tcon, | ||
| 176 | NULL /* we do not know sb */, | ||
| 177 | NULL /* no vol info */); | ||
| 178 | } | ||
| 179 | 139 | ||
| 180 | cFYI(1, ("reconnect tcon rc = %d", rc)); | 140 | /* |
| 181 | /* Removed call to reopen open files here. | 141 | * Give demultiplex thread up to 10 seconds to reconnect, should be |
| 182 | It is safer (and faster) to reopen files | 142 | * greater than cifs socket timeout which is 7 seconds |
| 183 | one at a time as needed in read and write */ | 143 | */ |
| 184 | 144 | while (server->tcpStatus == CifsNeedReconnect) { | |
| 185 | /* Check if handle based operation so we | 145 | wait_event_interruptible_timeout(server->response_q, |
| 186 | know whether we can continue or not without | 146 | (server->tcpStatus == CifsGood), 10 * HZ); |
| 187 | returning to caller to reset file handle */ | ||
| 188 | switch (smb_command) { | ||
| 189 | case SMB_COM_READ_ANDX: | ||
| 190 | case SMB_COM_WRITE_ANDX: | ||
| 191 | case SMB_COM_CLOSE: | ||
| 192 | case SMB_COM_FIND_CLOSE2: | ||
| 193 | case SMB_COM_LOCKING_ANDX: { | ||
| 194 | unload_nls(nls_codepage); | ||
| 195 | return -EAGAIN; | ||
| 196 | } | ||
| 197 | } | ||
| 198 | } else { | ||
| 199 | up(&tcon->ses->sesSem); | ||
| 200 | } | ||
| 201 | unload_nls(nls_codepage); | ||
| 202 | 147 | ||
| 203 | } else { | 148 | /* is TCP session is reestablished now ?*/ |
| 204 | return -EIO; | 149 | if (server->tcpStatus != CifsNeedReconnect) |
| 150 | break; | ||
| 151 | |||
| 152 | /* | ||
| 153 | * on "soft" mounts we wait once. Hard mounts keep | ||
| 154 | * retrying until process is killed or server comes | ||
| 155 | * back on-line | ||
| 156 | */ | ||
| 157 | if (!tcon->retry || ses->status == CifsExiting) { | ||
| 158 | cFYI(1, ("gave up waiting on reconnect in smb_init")); | ||
| 159 | return -EHOSTDOWN; | ||
| 205 | } | 160 | } |
| 206 | } | 161 | } |
| 162 | |||
| 163 | if (!ses->need_reconnect && !tcon->need_reconnect) | ||
| 164 | return 0; | ||
| 165 | |||
| 166 | nls_codepage = load_nls_default(); | ||
| 167 | |||
| 168 | /* | ||
| 169 | * need to prevent multiple threads trying to simultaneously | ||
| 170 | * reconnect the same SMB session | ||
| 171 | */ | ||
| 172 | down(&ses->sesSem); | ||
| 173 | if (ses->need_reconnect) | ||
| 174 | rc = cifs_setup_session(0, ses, nls_codepage); | ||
| 175 | |||
| 176 | /* do we need to reconnect tcon? */ | ||
| 177 | if (rc || !tcon->need_reconnect) { | ||
| 178 | up(&ses->sesSem); | ||
| 179 | goto out; | ||
| 180 | } | ||
| 181 | |||
| 182 | mark_open_files_invalid(tcon); | ||
| 183 | rc = CIFSTCon(0, ses, tcon->treeName, tcon, nls_codepage); | ||
| 184 | up(&ses->sesSem); | ||
| 185 | cFYI(1, ("reconnect tcon rc = %d", rc)); | ||
| 186 | |||
| 187 | if (rc) | ||
| 188 | goto out; | ||
| 189 | |||
| 190 | /* | ||
| 191 | * FIXME: check if wsize needs updated due to negotiated smb buffer | ||
| 192 | * size shrinking | ||
| 193 | */ | ||
| 194 | atomic_inc(&tconInfoReconnectCount); | ||
| 195 | |||
| 196 | /* tell server Unix caps we support */ | ||
| 197 | if (ses->capabilities & CAP_UNIX) | ||
| 198 | reset_cifs_unix_caps(0, tcon, NULL, NULL); | ||
| 199 | |||
| 200 | /* | ||
| 201 | * Removed call to reopen open files here. It is safer (and faster) to | ||
| 202 | * reopen files one at a time as needed in read and write. | ||
| 203 | * | ||
| 204 | * FIXME: what about file locks? don't we need to reclaim them ASAP? | ||
| 205 | */ | ||
| 206 | |||
| 207 | out: | ||
| 208 | /* | ||
| 209 | * Check if handle based operation so we know whether we can continue | ||
| 210 | * or not without returning to caller to reset file handle | ||
| 211 | */ | ||
| 212 | switch (smb_command) { | ||
| 213 | case SMB_COM_READ_ANDX: | ||
| 214 | case SMB_COM_WRITE_ANDX: | ||
| 215 | case SMB_COM_CLOSE: | ||
| 216 | case SMB_COM_FIND_CLOSE2: | ||
| 217 | case SMB_COM_LOCKING_ANDX: | ||
| 218 | rc = -EAGAIN; | ||
| 219 | } | ||
| 220 | |||
| 221 | unload_nls(nls_codepage); | ||
| 222 | return rc; | ||
| 223 | } | ||
| 224 | |||
| 225 | /* Allocate and return pointer to an SMB request buffer, and set basic | ||
| 226 | SMB information in the SMB header. If the return code is zero, this | ||
| 227 | function must have filled in request_buf pointer */ | ||
| 228 | static int | ||
| 229 | small_smb_init(int smb_command, int wct, struct cifsTconInfo *tcon, | ||
| 230 | void **request_buf) | ||
| 231 | { | ||
| 232 | int rc = 0; | ||
| 233 | |||
| 234 | rc = cifs_reconnect_tcon(tcon, smb_command); | ||
| 207 | if (rc) | 235 | if (rc) |
| 208 | return rc; | 236 | return rc; |
| 209 | 237 | ||
| @@ -256,101 +284,7 @@ smb_init(int smb_command, int wct, struct cifsTconInfo *tcon, | |||
| 256 | { | 284 | { |
| 257 | int rc = 0; | 285 | int rc = 0; |
| 258 | 286 | ||
| 259 | /* SMBs NegProt, SessSetup, uLogoff do not have tcon yet so | 287 | rc = cifs_reconnect_tcon(tcon, smb_command); |
| 260 | check for tcp and smb session status done differently | ||
| 261 | for those three - in the calling routine */ | ||
| 262 | if (tcon) { | ||
| 263 | if (tcon->tidStatus == CifsExiting) { | ||
| 264 | /* only tree disconnect, open, and write, | ||
| 265 | (and ulogoff which does not have tcon) | ||
| 266 | are allowed as we start force umount */ | ||
| 267 | if ((smb_command != SMB_COM_WRITE_ANDX) && | ||
| 268 | (smb_command != SMB_COM_OPEN_ANDX) && | ||
| 269 | (smb_command != SMB_COM_TREE_DISCONNECT)) { | ||
| 270 | cFYI(1, ("can not send cmd %d while umounting", | ||
| 271 | smb_command)); | ||
| 272 | return -ENODEV; | ||
| 273 | } | ||
| 274 | } | ||
| 275 | |||
| 276 | if ((tcon->ses) && (tcon->ses->status != CifsExiting) && | ||
| 277 | (tcon->ses->server)) { | ||
| 278 | struct nls_table *nls_codepage; | ||
| 279 | /* Give Demultiplex thread up to 10 seconds to | ||
| 280 | reconnect, should be greater than cifs socket | ||
| 281 | timeout which is 7 seconds */ | ||
| 282 | while (tcon->ses->server->tcpStatus == | ||
| 283 | CifsNeedReconnect) { | ||
| 284 | wait_event_interruptible_timeout(tcon->ses->server->response_q, | ||
| 285 | (tcon->ses->server->tcpStatus == | ||
| 286 | CifsGood), 10 * HZ); | ||
| 287 | if (tcon->ses->server->tcpStatus == | ||
| 288 | CifsNeedReconnect) { | ||
| 289 | /* on "soft" mounts we wait once */ | ||
| 290 | if (!tcon->retry || | ||
| 291 | (tcon->ses->status == CifsExiting)) { | ||
| 292 | cFYI(1, ("gave up waiting on " | ||
| 293 | "reconnect in smb_init")); | ||
| 294 | return -EHOSTDOWN; | ||
| 295 | } /* else "hard" mount - keep retrying | ||
| 296 | until process is killed or server | ||
| 297 | comes on-line */ | ||
| 298 | } else /* TCP session is reestablished now */ | ||
| 299 | break; | ||
| 300 | } | ||
| 301 | nls_codepage = load_nls_default(); | ||
| 302 | /* need to prevent multiple threads trying to | ||
| 303 | simultaneously reconnect the same SMB session */ | ||
| 304 | down(&tcon->ses->sesSem); | ||
| 305 | if (tcon->ses->need_reconnect) | ||
| 306 | rc = cifs_setup_session(0, tcon->ses, | ||
| 307 | nls_codepage); | ||
| 308 | if (!rc && (tcon->need_reconnect)) { | ||
| 309 | mark_open_files_invalid(tcon); | ||
| 310 | rc = CIFSTCon(0, tcon->ses, tcon->treeName, | ||
| 311 | tcon, nls_codepage); | ||
| 312 | up(&tcon->ses->sesSem); | ||
| 313 | /* BB FIXME add code to check if wsize needs | ||
| 314 | update due to negotiated smb buffer size | ||
| 315 | shrinking */ | ||
| 316 | if (rc == 0) { | ||
| 317 | atomic_inc(&tconInfoReconnectCount); | ||
| 318 | /* tell server Unix caps we support */ | ||
| 319 | if (tcon->ses->capabilities & CAP_UNIX) | ||
| 320 | reset_cifs_unix_caps( | ||
| 321 | 0 /* no xid */, | ||
| 322 | tcon, | ||
| 323 | NULL /* do not know sb */, | ||
| 324 | NULL /* no vol info */); | ||
| 325 | } | ||
| 326 | |||
| 327 | cFYI(1, ("reconnect tcon rc = %d", rc)); | ||
| 328 | /* Removed call to reopen open files here. | ||
| 329 | It is safer (and faster) to reopen files | ||
| 330 | one at a time as needed in read and write */ | ||
| 331 | |||
| 332 | /* Check if handle based operation so we | ||
| 333 | know whether we can continue or not without | ||
| 334 | returning to caller to reset file handle */ | ||
| 335 | switch (smb_command) { | ||
| 336 | case SMB_COM_READ_ANDX: | ||
| 337 | case SMB_COM_WRITE_ANDX: | ||
| 338 | case SMB_COM_CLOSE: | ||
| 339 | case SMB_COM_FIND_CLOSE2: | ||
| 340 | case SMB_COM_LOCKING_ANDX: { | ||
| 341 | unload_nls(nls_codepage); | ||
| 342 | return -EAGAIN; | ||
| 343 | } | ||
| 344 | } | ||
| 345 | } else { | ||
| 346 | up(&tcon->ses->sesSem); | ||
| 347 | } | ||
| 348 | unload_nls(nls_codepage); | ||
| 349 | |||
| 350 | } else { | ||
| 351 | return -EIO; | ||
| 352 | } | ||
| 353 | } | ||
| 354 | if (rc) | 288 | if (rc) |
| 355 | return rc; | 289 | return rc; |
| 356 | 290 | ||
