forked from Minki/linux
Merge git://git.kernel.org/pub/scm/linux/kernel/git/sfrench/cifs-2.6
* git://git.kernel.org/pub/scm/linux/kernel/git/sfrench/cifs-2.6: cifs: consolidate reconnect logic in smb_init routines cifs: Replace wrtPending with a real reference count cifs: protect GlobalOplock_Q with its own spinlock cifs: use tcon pointer in cifs_show_options cifs: send IPv6 addr in upcall with colon delimiters [CIFS] Fix checkpatch warnings PATCH] cifs: fix broken mounts when a SSH tunnel is used (try #4) [CIFS] Memory leak in ntlmv2 hash calculation [CIFS] potential NULL dereference in parse_DFS_referrals()
This commit is contained in:
commit
6cdb5930a6
@ -3,7 +3,10 @@ Version 1.60
|
||||
Fix memory leak in reconnect. Fix oops in DFS mount error path.
|
||||
Set s_maxbytes to smaller (the max that vfs can handle) so that
|
||||
sendfile will now work over cifs mounts again. Add noforcegid
|
||||
and noforceuid mount parameters.
|
||||
and noforceuid mount parameters. Fix small mem leak when using
|
||||
ntlmv2. Fix 2nd mount to same server but with different port to
|
||||
be allowed (rather than reusing the 1st port) - only when the
|
||||
user explicitly overrides the port on the 2nd mount.
|
||||
|
||||
Version 1.59
|
||||
------------
|
||||
|
@ -125,7 +125,7 @@ cifs_get_spnego_key(struct cifsSesInfo *sesInfo)
|
||||
if (server->addr.sockAddr.sin_family == AF_INET)
|
||||
sprintf(dp, "ip4=%pI4", &server->addr.sockAddr.sin_addr);
|
||||
else if (server->addr.sockAddr.sin_family == AF_INET6)
|
||||
sprintf(dp, "ip6=%pi6", &server->addr.sockAddr6.sin6_addr);
|
||||
sprintf(dp, "ip6=%pI6", &server->addr.sockAddr6.sin6_addr);
|
||||
else
|
||||
goto out;
|
||||
|
||||
|
@ -607,7 +607,7 @@ static struct cifs_ntsd *get_cifs_acl(struct cifs_sb_info *cifs_sb,
|
||||
return get_cifs_acl_by_path(cifs_sb, path, pacllen);
|
||||
|
||||
pntsd = get_cifs_acl_by_fid(cifs_sb, open_file->netfid, pacllen);
|
||||
atomic_dec(&open_file->wrtPending);
|
||||
cifsFileInfo_put(open_file);
|
||||
return pntsd;
|
||||
}
|
||||
|
||||
@ -665,7 +665,7 @@ static int set_cifs_acl(struct cifs_ntsd *pnntsd, __u32 acllen,
|
||||
return set_cifs_acl_by_path(cifs_sb, path, pnntsd, acllen);
|
||||
|
||||
rc = set_cifs_acl_by_fid(cifs_sb, open_file->netfid, pnntsd, acllen);
|
||||
atomic_dec(&open_file->wrtPending);
|
||||
cifsFileInfo_put(open_file);
|
||||
return rc;
|
||||
}
|
||||
|
||||
|
@ -373,6 +373,7 @@ calc_exit_2:
|
||||
compare with the NTLM example */
|
||||
hmac_md5_final(ses->server->ntlmv2_hash, pctxt);
|
||||
|
||||
kfree(pctxt);
|
||||
return rc;
|
||||
}
|
||||
|
||||
|
@ -361,13 +361,10 @@ cifs_show_address(struct seq_file *s, struct TCP_Server_Info *server)
|
||||
static int
|
||||
cifs_show_options(struct seq_file *s, struct vfsmount *m)
|
||||
{
|
||||
struct cifs_sb_info *cifs_sb;
|
||||
struct cifsTconInfo *tcon;
|
||||
struct cifs_sb_info *cifs_sb = CIFS_SB(m->mnt_sb);
|
||||
struct cifsTconInfo *tcon = cifs_sb->tcon;
|
||||
|
||||
cifs_sb = CIFS_SB(m->mnt_sb);
|
||||
tcon = cifs_sb->tcon;
|
||||
|
||||
seq_printf(s, ",unc=%s", cifs_sb->tcon->treeName);
|
||||
seq_printf(s, ",unc=%s", tcon->treeName);
|
||||
if (tcon->ses->userName)
|
||||
seq_printf(s, ",username=%s", tcon->ses->userName);
|
||||
if (tcon->ses->domainName)
|
||||
@ -989,19 +986,19 @@ static int cifs_oplock_thread(void *dummyarg)
|
||||
if (try_to_freeze())
|
||||
continue;
|
||||
|
||||
spin_lock(&GlobalMid_Lock);
|
||||
if (list_empty(&GlobalOplock_Q)) {
|
||||
spin_unlock(&GlobalMid_Lock);
|
||||
spin_lock(&cifs_oplock_lock);
|
||||
if (list_empty(&cifs_oplock_list)) {
|
||||
spin_unlock(&cifs_oplock_lock);
|
||||
set_current_state(TASK_INTERRUPTIBLE);
|
||||
schedule_timeout(39*HZ);
|
||||
} else {
|
||||
oplock_item = list_entry(GlobalOplock_Q.next,
|
||||
oplock_item = list_entry(cifs_oplock_list.next,
|
||||
struct oplock_q_entry, qhead);
|
||||
cFYI(1, ("found oplock item to write out"));
|
||||
pTcon = oplock_item->tcon;
|
||||
inode = oplock_item->pinode;
|
||||
netfid = oplock_item->netfid;
|
||||
spin_unlock(&GlobalMid_Lock);
|
||||
spin_unlock(&cifs_oplock_lock);
|
||||
DeleteOplockQEntry(oplock_item);
|
||||
/* can not grab inode sem here since it would
|
||||
deadlock when oplock received on delete
|
||||
@ -1058,7 +1055,7 @@ init_cifs(void)
|
||||
int rc = 0;
|
||||
cifs_proc_init();
|
||||
INIT_LIST_HEAD(&cifs_tcp_ses_list);
|
||||
INIT_LIST_HEAD(&GlobalOplock_Q);
|
||||
INIT_LIST_HEAD(&cifs_oplock_list);
|
||||
#ifdef CONFIG_CIFS_EXPERIMENTAL
|
||||
INIT_LIST_HEAD(&GlobalDnotifyReqList);
|
||||
INIT_LIST_HEAD(&GlobalDnotifyRsp_Q);
|
||||
@ -1087,6 +1084,7 @@ init_cifs(void)
|
||||
rwlock_init(&GlobalSMBSeslock);
|
||||
rwlock_init(&cifs_tcp_ses_lock);
|
||||
spin_lock_init(&GlobalMid_Lock);
|
||||
spin_lock_init(&cifs_oplock_lock);
|
||||
|
||||
if (cifs_max_pending < 2) {
|
||||
cifs_max_pending = 2;
|
||||
|
@ -113,5 +113,5 @@ extern long cifs_ioctl(struct file *filep, unsigned int cmd, unsigned long arg);
|
||||
extern const struct export_operations cifs_export_ops;
|
||||
#endif /* EXPERIMENTAL */
|
||||
|
||||
#define CIFS_VERSION "1.60"
|
||||
#define CIFS_VERSION "1.61"
|
||||
#endif /* _CIFSFS_H */
|
||||
|
@ -351,11 +351,24 @@ struct cifsFileInfo {
|
||||
bool closePend:1; /* file is marked to close */
|
||||
bool invalidHandle:1; /* file closed via session abend */
|
||||
bool messageMode:1; /* for pipes: message vs byte mode */
|
||||
atomic_t wrtPending; /* handle in use - defer close */
|
||||
atomic_t count; /* reference count */
|
||||
struct mutex fh_mutex; /* prevents reopen race after dead ses*/
|
||||
struct cifs_search_info srch_inf;
|
||||
};
|
||||
|
||||
/* Take a reference on the file private data */
|
||||
static inline void cifsFileInfo_get(struct cifsFileInfo *cifs_file)
|
||||
{
|
||||
atomic_inc(&cifs_file->count);
|
||||
}
|
||||
|
||||
/* Release a reference on the file private data */
|
||||
static inline void cifsFileInfo_put(struct cifsFileInfo *cifs_file)
|
||||
{
|
||||
if (atomic_dec_and_test(&cifs_file->count))
|
||||
kfree(cifs_file);
|
||||
}
|
||||
|
||||
/*
|
||||
* One of these for each file inode
|
||||
*/
|
||||
@ -656,7 +669,11 @@ GLOBAL_EXTERN rwlock_t cifs_tcp_ses_lock;
|
||||
*/
|
||||
GLOBAL_EXTERN rwlock_t GlobalSMBSeslock;
|
||||
|
||||
GLOBAL_EXTERN struct list_head GlobalOplock_Q;
|
||||
/* Global list of oplocks */
|
||||
GLOBAL_EXTERN struct list_head cifs_oplock_list;
|
||||
|
||||
/* Protects the cifs_oplock_list */
|
||||
GLOBAL_EXTERN spinlock_t cifs_oplock_lock;
|
||||
|
||||
/* Outstanding dir notify requests */
|
||||
GLOBAL_EXTERN struct list_head GlobalDnotifyReqList;
|
||||
|
@ -100,6 +100,128 @@ static void mark_open_files_invalid(struct cifsTconInfo *pTcon)
|
||||
to this tcon */
|
||||
}
|
||||
|
||||
/* reconnect the socket, tcon, and smb session if needed */
|
||||
static int
|
||||
cifs_reconnect_tcon(struct cifsTconInfo *tcon, int smb_command)
|
||||
{
|
||||
int rc = 0;
|
||||
struct cifsSesInfo *ses;
|
||||
struct TCP_Server_Info *server;
|
||||
struct nls_table *nls_codepage;
|
||||
|
||||
/*
|
||||
* SMBs NegProt, SessSetup, uLogoff do not have tcon yet so check for
|
||||
* tcp and smb session status done differently for those three - in the
|
||||
* calling routine
|
||||
*/
|
||||
if (!tcon)
|
||||
return 0;
|
||||
|
||||
ses = tcon->ses;
|
||||
server = ses->server;
|
||||
|
||||
/*
|
||||
* only tree disconnect, open, and write, (and ulogoff which does not
|
||||
* have tcon) are allowed as we start force umount
|
||||
*/
|
||||
if (tcon->tidStatus == CifsExiting) {
|
||||
if (smb_command != SMB_COM_WRITE_ANDX &&
|
||||
smb_command != SMB_COM_OPEN_ANDX &&
|
||||
smb_command != SMB_COM_TREE_DISCONNECT) {
|
||||
cFYI(1, ("can not send cmd %d while umounting",
|
||||
smb_command));
|
||||
return -ENODEV;
|
||||
}
|
||||
}
|
||||
|
||||
if (ses->status == CifsExiting)
|
||||
return -EIO;
|
||||
|
||||
/*
|
||||
* Give demultiplex thread up to 10 seconds to reconnect, should be
|
||||
* greater than cifs socket timeout which is 7 seconds
|
||||
*/
|
||||
while (server->tcpStatus == CifsNeedReconnect) {
|
||||
wait_event_interruptible_timeout(server->response_q,
|
||||
(server->tcpStatus == CifsGood), 10 * HZ);
|
||||
|
||||
/* is TCP session is reestablished now ?*/
|
||||
if (server->tcpStatus != CifsNeedReconnect)
|
||||
break;
|
||||
|
||||
/*
|
||||
* on "soft" mounts we wait once. Hard mounts keep
|
||||
* retrying until process is killed or server comes
|
||||
* back on-line
|
||||
*/
|
||||
if (!tcon->retry || ses->status == CifsExiting) {
|
||||
cFYI(1, ("gave up waiting on reconnect in smb_init"));
|
||||
return -EHOSTDOWN;
|
||||
}
|
||||
}
|
||||
|
||||
if (!ses->need_reconnect && !tcon->need_reconnect)
|
||||
return 0;
|
||||
|
||||
nls_codepage = load_nls_default();
|
||||
|
||||
/*
|
||||
* need to prevent multiple threads trying to simultaneously
|
||||
* reconnect the same SMB session
|
||||
*/
|
||||
down(&ses->sesSem);
|
||||
if (ses->need_reconnect)
|
||||
rc = cifs_setup_session(0, ses, nls_codepage);
|
||||
|
||||
/* do we need to reconnect tcon? */
|
||||
if (rc || !tcon->need_reconnect) {
|
||||
up(&ses->sesSem);
|
||||
goto out;
|
||||
}
|
||||
|
||||
mark_open_files_invalid(tcon);
|
||||
rc = CIFSTCon(0, ses, tcon->treeName, tcon, nls_codepage);
|
||||
up(&ses->sesSem);
|
||||
cFYI(1, ("reconnect tcon rc = %d", rc));
|
||||
|
||||
if (rc)
|
||||
goto out;
|
||||
|
||||
/*
|
||||
* FIXME: check if wsize needs updated due to negotiated smb buffer
|
||||
* size shrinking
|
||||
*/
|
||||
atomic_inc(&tconInfoReconnectCount);
|
||||
|
||||
/* tell server Unix caps we support */
|
||||
if (ses->capabilities & CAP_UNIX)
|
||||
reset_cifs_unix_caps(0, tcon, NULL, NULL);
|
||||
|
||||
/*
|
||||
* Removed call to reopen open files here. It is safer (and faster) to
|
||||
* reopen files one at a time as needed in read and write.
|
||||
*
|
||||
* FIXME: what about file locks? don't we need to reclaim them ASAP?
|
||||
*/
|
||||
|
||||
out:
|
||||
/*
|
||||
* Check if handle based operation so we know whether we can continue
|
||||
* or not without returning to caller to reset file handle
|
||||
*/
|
||||
switch (smb_command) {
|
||||
case SMB_COM_READ_ANDX:
|
||||
case SMB_COM_WRITE_ANDX:
|
||||
case SMB_COM_CLOSE:
|
||||
case SMB_COM_FIND_CLOSE2:
|
||||
case SMB_COM_LOCKING_ANDX:
|
||||
rc = -EAGAIN;
|
||||
}
|
||||
|
||||
unload_nls(nls_codepage);
|
||||
return rc;
|
||||
}
|
||||
|
||||
/* Allocate and return pointer to an SMB request buffer, and set basic
|
||||
SMB information in the SMB header. If the return code is zero, this
|
||||
function must have filled in request_buf pointer */
|
||||
@ -109,101 +231,7 @@ small_smb_init(int smb_command, int wct, struct cifsTconInfo *tcon,
|
||||
{
|
||||
int rc = 0;
|
||||
|
||||
/* SMBs NegProt, SessSetup, uLogoff do not have tcon yet so
|
||||
check for tcp and smb session status done differently
|
||||
for those three - in the calling routine */
|
||||
if (tcon) {
|
||||
if (tcon->tidStatus == CifsExiting) {
|
||||
/* only tree disconnect, open, and write,
|
||||
(and ulogoff which does not have tcon)
|
||||
are allowed as we start force umount */
|
||||
if ((smb_command != SMB_COM_WRITE_ANDX) &&
|
||||
(smb_command != SMB_COM_OPEN_ANDX) &&
|
||||
(smb_command != SMB_COM_TREE_DISCONNECT)) {
|
||||
cFYI(1, ("can not send cmd %d while umounting",
|
||||
smb_command));
|
||||
return -ENODEV;
|
||||
}
|
||||
}
|
||||
if ((tcon->ses) && (tcon->ses->status != CifsExiting) &&
|
||||
(tcon->ses->server)) {
|
||||
struct nls_table *nls_codepage;
|
||||
/* Give Demultiplex thread up to 10 seconds to
|
||||
reconnect, should be greater than cifs socket
|
||||
timeout which is 7 seconds */
|
||||
while (tcon->ses->server->tcpStatus ==
|
||||
CifsNeedReconnect) {
|
||||
wait_event_interruptible_timeout(tcon->ses->server->response_q,
|
||||
(tcon->ses->server->tcpStatus ==
|
||||
CifsGood), 10 * HZ);
|
||||
if (tcon->ses->server->tcpStatus ==
|
||||
CifsNeedReconnect) {
|
||||
/* on "soft" mounts we wait once */
|
||||
if (!tcon->retry ||
|
||||
(tcon->ses->status == CifsExiting)) {
|
||||
cFYI(1, ("gave up waiting on "
|
||||
"reconnect in smb_init"));
|
||||
return -EHOSTDOWN;
|
||||
} /* else "hard" mount - keep retrying
|
||||
until process is killed or server
|
||||
comes back on-line */
|
||||
} else /* TCP session is reestablished now */
|
||||
break;
|
||||
}
|
||||
|
||||
nls_codepage = load_nls_default();
|
||||
/* need to prevent multiple threads trying to
|
||||
simultaneously reconnect the same SMB session */
|
||||
down(&tcon->ses->sesSem);
|
||||
if (tcon->ses->need_reconnect)
|
||||
rc = cifs_setup_session(0, tcon->ses,
|
||||
nls_codepage);
|
||||
if (!rc && (tcon->need_reconnect)) {
|
||||
mark_open_files_invalid(tcon);
|
||||
rc = CIFSTCon(0, tcon->ses, tcon->treeName,
|
||||
tcon, nls_codepage);
|
||||
up(&tcon->ses->sesSem);
|
||||
/* BB FIXME add code to check if wsize needs
|
||||
update due to negotiated smb buffer size
|
||||
shrinking */
|
||||
if (rc == 0) {
|
||||
atomic_inc(&tconInfoReconnectCount);
|
||||
/* tell server Unix caps we support */
|
||||
if (tcon->ses->capabilities & CAP_UNIX)
|
||||
reset_cifs_unix_caps(
|
||||
0 /* no xid */,
|
||||
tcon,
|
||||
NULL /* we do not know sb */,
|
||||
NULL /* no vol info */);
|
||||
}
|
||||
|
||||
cFYI(1, ("reconnect tcon rc = %d", rc));
|
||||
/* Removed call to reopen open files here.
|
||||
It is safer (and faster) to reopen files
|
||||
one at a time as needed in read and write */
|
||||
|
||||
/* Check if handle based operation so we
|
||||
know whether we can continue or not without
|
||||
returning to caller to reset file handle */
|
||||
switch (smb_command) {
|
||||
case SMB_COM_READ_ANDX:
|
||||
case SMB_COM_WRITE_ANDX:
|
||||
case SMB_COM_CLOSE:
|
||||
case SMB_COM_FIND_CLOSE2:
|
||||
case SMB_COM_LOCKING_ANDX: {
|
||||
unload_nls(nls_codepage);
|
||||
return -EAGAIN;
|
||||
}
|
||||
}
|
||||
} else {
|
||||
up(&tcon->ses->sesSem);
|
||||
}
|
||||
unload_nls(nls_codepage);
|
||||
|
||||
} else {
|
||||
return -EIO;
|
||||
}
|
||||
}
|
||||
rc = cifs_reconnect_tcon(tcon, smb_command);
|
||||
if (rc)
|
||||
return rc;
|
||||
|
||||
@ -256,101 +284,7 @@ smb_init(int smb_command, int wct, struct cifsTconInfo *tcon,
|
||||
{
|
||||
int rc = 0;
|
||||
|
||||
/* SMBs NegProt, SessSetup, uLogoff do not have tcon yet so
|
||||
check for tcp and smb session status done differently
|
||||
for those three - in the calling routine */
|
||||
if (tcon) {
|
||||
if (tcon->tidStatus == CifsExiting) {
|
||||
/* only tree disconnect, open, and write,
|
||||
(and ulogoff which does not have tcon)
|
||||
are allowed as we start force umount */
|
||||
if ((smb_command != SMB_COM_WRITE_ANDX) &&
|
||||
(smb_command != SMB_COM_OPEN_ANDX) &&
|
||||
(smb_command != SMB_COM_TREE_DISCONNECT)) {
|
||||
cFYI(1, ("can not send cmd %d while umounting",
|
||||
smb_command));
|
||||
return -ENODEV;
|
||||
}
|
||||
}
|
||||
|
||||
if ((tcon->ses) && (tcon->ses->status != CifsExiting) &&
|
||||
(tcon->ses->server)) {
|
||||
struct nls_table *nls_codepage;
|
||||
/* Give Demultiplex thread up to 10 seconds to
|
||||
reconnect, should be greater than cifs socket
|
||||
timeout which is 7 seconds */
|
||||
while (tcon->ses->server->tcpStatus ==
|
||||
CifsNeedReconnect) {
|
||||
wait_event_interruptible_timeout(tcon->ses->server->response_q,
|
||||
(tcon->ses->server->tcpStatus ==
|
||||
CifsGood), 10 * HZ);
|
||||
if (tcon->ses->server->tcpStatus ==
|
||||
CifsNeedReconnect) {
|
||||
/* on "soft" mounts we wait once */
|
||||
if (!tcon->retry ||
|
||||
(tcon->ses->status == CifsExiting)) {
|
||||
cFYI(1, ("gave up waiting on "
|
||||
"reconnect in smb_init"));
|
||||
return -EHOSTDOWN;
|
||||
} /* else "hard" mount - keep retrying
|
||||
until process is killed or server
|
||||
comes on-line */
|
||||
} else /* TCP session is reestablished now */
|
||||
break;
|
||||
}
|
||||
nls_codepage = load_nls_default();
|
||||
/* need to prevent multiple threads trying to
|
||||
simultaneously reconnect the same SMB session */
|
||||
down(&tcon->ses->sesSem);
|
||||
if (tcon->ses->need_reconnect)
|
||||
rc = cifs_setup_session(0, tcon->ses,
|
||||
nls_codepage);
|
||||
if (!rc && (tcon->need_reconnect)) {
|
||||
mark_open_files_invalid(tcon);
|
||||
rc = CIFSTCon(0, tcon->ses, tcon->treeName,
|
||||
tcon, nls_codepage);
|
||||
up(&tcon->ses->sesSem);
|
||||
/* BB FIXME add code to check if wsize needs
|
||||
update due to negotiated smb buffer size
|
||||
shrinking */
|
||||
if (rc == 0) {
|
||||
atomic_inc(&tconInfoReconnectCount);
|
||||
/* tell server Unix caps we support */
|
||||
if (tcon->ses->capabilities & CAP_UNIX)
|
||||
reset_cifs_unix_caps(
|
||||
0 /* no xid */,
|
||||
tcon,
|
||||
NULL /* do not know sb */,
|
||||
NULL /* no vol info */);
|
||||
}
|
||||
|
||||
cFYI(1, ("reconnect tcon rc = %d", rc));
|
||||
/* Removed call to reopen open files here.
|
||||
It is safer (and faster) to reopen files
|
||||
one at a time as needed in read and write */
|
||||
|
||||
/* Check if handle based operation so we
|
||||
know whether we can continue or not without
|
||||
returning to caller to reset file handle */
|
||||
switch (smb_command) {
|
||||
case SMB_COM_READ_ANDX:
|
||||
case SMB_COM_WRITE_ANDX:
|
||||
case SMB_COM_CLOSE:
|
||||
case SMB_COM_FIND_CLOSE2:
|
||||
case SMB_COM_LOCKING_ANDX: {
|
||||
unload_nls(nls_codepage);
|
||||
return -EAGAIN;
|
||||
}
|
||||
}
|
||||
} else {
|
||||
up(&tcon->ses->sesSem);
|
||||
}
|
||||
unload_nls(nls_codepage);
|
||||
|
||||
} else {
|
||||
return -EIO;
|
||||
}
|
||||
}
|
||||
rc = cifs_reconnect_tcon(tcon, smb_command);
|
||||
if (rc)
|
||||
return rc;
|
||||
|
||||
@ -3961,6 +3895,10 @@ parse_DFS_referrals(TRANSACTION2_GET_DFS_REFER_RSP *pSMBr,
|
||||
if (is_unicode) {
|
||||
__le16 *tmp = kmalloc(strlen(searchName)*2 + 2,
|
||||
GFP_KERNEL);
|
||||
if (tmp == NULL) {
|
||||
rc = -ENOMEM;
|
||||
goto parse_DFS_referrals_exit;
|
||||
}
|
||||
cifsConvertToUCS((__le16 *) tmp, searchName,
|
||||
PATH_MAX, nls_codepage, remap);
|
||||
node->path_consumed = cifs_ucs2_bytes(tmp,
|
||||
|
@ -1377,7 +1377,7 @@ cifs_parse_mount_options(char *options, const char *devname,
|
||||
}
|
||||
|
||||
static struct TCP_Server_Info *
|
||||
cifs_find_tcp_session(struct sockaddr_storage *addr)
|
||||
cifs_find_tcp_session(struct sockaddr_storage *addr, unsigned short int port)
|
||||
{
|
||||
struct list_head *tmp;
|
||||
struct TCP_Server_Info *server;
|
||||
@ -1397,16 +1397,37 @@ cifs_find_tcp_session(struct sockaddr_storage *addr)
|
||||
if (server->tcpStatus == CifsNew)
|
||||
continue;
|
||||
|
||||
if (addr->ss_family == AF_INET &&
|
||||
(addr4->sin_addr.s_addr !=
|
||||
server->addr.sockAddr.sin_addr.s_addr))
|
||||
continue;
|
||||
else if (addr->ss_family == AF_INET6 &&
|
||||
(!ipv6_addr_equal(&server->addr.sockAddr6.sin6_addr,
|
||||
&addr6->sin6_addr) ||
|
||||
server->addr.sockAddr6.sin6_scope_id !=
|
||||
addr6->sin6_scope_id))
|
||||
continue;
|
||||
switch (addr->ss_family) {
|
||||
case AF_INET:
|
||||
if (addr4->sin_addr.s_addr ==
|
||||
server->addr.sockAddr.sin_addr.s_addr) {
|
||||
addr4->sin_port = htons(port);
|
||||
/* user overrode default port? */
|
||||
if (addr4->sin_port) {
|
||||
if (addr4->sin_port !=
|
||||
server->addr.sockAddr.sin_port)
|
||||
continue;
|
||||
}
|
||||
break;
|
||||
} else
|
||||
continue;
|
||||
|
||||
case AF_INET6:
|
||||
if (ipv6_addr_equal(&addr6->sin6_addr,
|
||||
&server->addr.sockAddr6.sin6_addr) &&
|
||||
(addr6->sin6_scope_id ==
|
||||
server->addr.sockAddr6.sin6_scope_id)) {
|
||||
addr6->sin6_port = htons(port);
|
||||
/* user overrode default port? */
|
||||
if (addr6->sin6_port) {
|
||||
if (addr6->sin6_port !=
|
||||
server->addr.sockAddr6.sin6_port)
|
||||
continue;
|
||||
}
|
||||
break;
|
||||
} else
|
||||
continue;
|
||||
}
|
||||
|
||||
++server->srv_count;
|
||||
write_unlock(&cifs_tcp_ses_lock);
|
||||
@ -1475,7 +1496,7 @@ cifs_get_tcp_session(struct smb_vol *volume_info)
|
||||
}
|
||||
|
||||
/* see if we already have a matching tcp_ses */
|
||||
tcp_ses = cifs_find_tcp_session(&addr);
|
||||
tcp_ses = cifs_find_tcp_session(&addr, volume_info->port);
|
||||
if (tcp_ses)
|
||||
return tcp_ses;
|
||||
|
||||
@ -2636,9 +2657,9 @@ CIFSTCon(unsigned int xid, struct cifsSesInfo *ses,
|
||||
return -EIO;
|
||||
|
||||
smb_buffer = cifs_buf_get();
|
||||
if (smb_buffer == NULL) {
|
||||
if (smb_buffer == NULL)
|
||||
return -ENOMEM;
|
||||
}
|
||||
|
||||
smb_buffer_response = smb_buffer;
|
||||
|
||||
header_assemble(smb_buffer, SMB_COM_TREE_CONNECT_ANDX,
|
||||
|
@ -153,7 +153,7 @@ cifs_fill_fileinfo(struct inode *newinode, __u16 fileHandle,
|
||||
mutex_init(&pCifsFile->fh_mutex);
|
||||
mutex_init(&pCifsFile->lock_mutex);
|
||||
INIT_LIST_HEAD(&pCifsFile->llist);
|
||||
atomic_set(&pCifsFile->wrtPending, 0);
|
||||
atomic_set(&pCifsFile->count, 1);
|
||||
|
||||
/* set the following in open now
|
||||
pCifsFile->pfile = file; */
|
||||
|
@ -53,11 +53,9 @@ static inline struct cifsFileInfo *cifs_init_private(
|
||||
private_data->pInode = inode;
|
||||
private_data->invalidHandle = false;
|
||||
private_data->closePend = false;
|
||||
/* we have to track num writers to the inode, since writepages
|
||||
does not tell us which handle the write is for so there can
|
||||
be a close (overlapping with write) of the filehandle that
|
||||
cifs_writepages chose to use */
|
||||
atomic_set(&private_data->wrtPending, 0);
|
||||
/* Initialize reference count to one. The private data is
|
||||
freed on the release of the last reference */
|
||||
atomic_set(&private_data->count, 1);
|
||||
|
||||
return private_data;
|
||||
}
|
||||
@ -643,7 +641,7 @@ int cifs_close(struct inode *inode, struct file *file)
|
||||
if (!pTcon->need_reconnect) {
|
||||
write_unlock(&GlobalSMBSeslock);
|
||||
timeout = 2;
|
||||
while ((atomic_read(&pSMBFile->wrtPending) != 0)
|
||||
while ((atomic_read(&pSMBFile->count) != 1)
|
||||
&& (timeout <= 2048)) {
|
||||
/* Give write a better chance to get to
|
||||
server ahead of the close. We do not
|
||||
@ -657,8 +655,6 @@ int cifs_close(struct inode *inode, struct file *file)
|
||||
msleep(timeout);
|
||||
timeout *= 4;
|
||||
}
|
||||
if (atomic_read(&pSMBFile->wrtPending))
|
||||
cERROR(1, ("close with pending write"));
|
||||
if (!pTcon->need_reconnect &&
|
||||
!pSMBFile->invalidHandle)
|
||||
rc = CIFSSMBClose(xid, pTcon,
|
||||
@ -681,24 +677,7 @@ int cifs_close(struct inode *inode, struct file *file)
|
||||
list_del(&pSMBFile->flist);
|
||||
list_del(&pSMBFile->tlist);
|
||||
write_unlock(&GlobalSMBSeslock);
|
||||
timeout = 10;
|
||||
/* We waited above to give the SMBWrite a chance to issue
|
||||
on the wire (so we do not get SMBWrite returning EBADF
|
||||
if writepages is racing with close. Note that writepages
|
||||
does not specify a file handle, so it is possible for a file
|
||||
to be opened twice, and the application close the "wrong"
|
||||
file handle - in these cases we delay long enough to allow
|
||||
the SMBWrite to get on the wire before the SMB Close.
|
||||
We allow total wait here over 45 seconds, more than
|
||||
oplock break time, and more than enough to allow any write
|
||||
to complete on the server, or to time out on the client */
|
||||
while ((atomic_read(&pSMBFile->wrtPending) != 0)
|
||||
&& (timeout <= 50000)) {
|
||||
cERROR(1, ("writes pending, delay free of handle"));
|
||||
msleep(timeout);
|
||||
timeout *= 8;
|
||||
}
|
||||
kfree(file->private_data);
|
||||
cifsFileInfo_put(file->private_data);
|
||||
file->private_data = NULL;
|
||||
} else
|
||||
rc = -EBADF;
|
||||
@ -1236,7 +1215,7 @@ struct cifsFileInfo *find_readable_file(struct cifsInodeInfo *cifs_inode)
|
||||
if (!open_file->invalidHandle) {
|
||||
/* found a good file */
|
||||
/* lock it so it will not be closed on us */
|
||||
atomic_inc(&open_file->wrtPending);
|
||||
cifsFileInfo_get(open_file);
|
||||
read_unlock(&GlobalSMBSeslock);
|
||||
return open_file;
|
||||
} /* else might as well continue, and look for
|
||||
@ -1276,7 +1255,7 @@ refind_writable:
|
||||
if (open_file->pfile &&
|
||||
((open_file->pfile->f_flags & O_RDWR) ||
|
||||
(open_file->pfile->f_flags & O_WRONLY))) {
|
||||
atomic_inc(&open_file->wrtPending);
|
||||
cifsFileInfo_get(open_file);
|
||||
|
||||
if (!open_file->invalidHandle) {
|
||||
/* found a good writable file */
|
||||
@ -1293,7 +1272,7 @@ refind_writable:
|
||||
else { /* start over in case this was deleted */
|
||||
/* since the list could be modified */
|
||||
read_lock(&GlobalSMBSeslock);
|
||||
atomic_dec(&open_file->wrtPending);
|
||||
cifsFileInfo_put(open_file);
|
||||
goto refind_writable;
|
||||
}
|
||||
}
|
||||
@ -1309,7 +1288,7 @@ refind_writable:
|
||||
read_lock(&GlobalSMBSeslock);
|
||||
/* can not use this handle, no write
|
||||
pending on this one after all */
|
||||
atomic_dec(&open_file->wrtPending);
|
||||
cifsFileInfo_put(open_file);
|
||||
|
||||
if (open_file->closePend) /* list could have changed */
|
||||
goto refind_writable;
|
||||
@ -1373,7 +1352,7 @@ static int cifs_partialpagewrite(struct page *page, unsigned from, unsigned to)
|
||||
if (open_file) {
|
||||
bytes_written = cifs_write(open_file->pfile, write_data,
|
||||
to-from, &offset);
|
||||
atomic_dec(&open_file->wrtPending);
|
||||
cifsFileInfo_put(open_file);
|
||||
/* Does mm or vfs already set times? */
|
||||
inode->i_atime = inode->i_mtime = current_fs_time(inode->i_sb);
|
||||
if ((bytes_written > 0) && (offset))
|
||||
@ -1562,7 +1541,7 @@ retry:
|
||||
bytes_to_write, offset,
|
||||
&bytes_written, iov, n_iov,
|
||||
long_op);
|
||||
atomic_dec(&open_file->wrtPending);
|
||||
cifsFileInfo_put(open_file);
|
||||
cifs_update_eof(cifsi, offset, bytes_written);
|
||||
|
||||
if (rc || bytes_written < bytes_to_write) {
|
||||
|
@ -800,7 +800,7 @@ set_via_filehandle:
|
||||
if (open_file == NULL)
|
||||
CIFSSMBClose(xid, pTcon, netfid);
|
||||
else
|
||||
atomic_dec(&open_file->wrtPending);
|
||||
cifsFileInfo_put(open_file);
|
||||
out:
|
||||
return rc;
|
||||
}
|
||||
@ -1635,7 +1635,7 @@ cifs_set_file_size(struct inode *inode, struct iattr *attrs,
|
||||
__u32 npid = open_file->pid;
|
||||
rc = CIFSSMBSetFileSize(xid, pTcon, attrs->ia_size, nfid,
|
||||
npid, false);
|
||||
atomic_dec(&open_file->wrtPending);
|
||||
cifsFileInfo_put(open_file);
|
||||
cFYI(1, ("SetFSize for attrs rc = %d", rc));
|
||||
if ((rc == -EINVAL) || (rc == -EOPNOTSUPP)) {
|
||||
unsigned int bytes_written;
|
||||
@ -1790,7 +1790,7 @@ cifs_setattr_unix(struct dentry *direntry, struct iattr *attrs)
|
||||
u16 nfid = open_file->netfid;
|
||||
u32 npid = open_file->pid;
|
||||
rc = CIFSSMBUnixSetFileInfo(xid, pTcon, args, nfid, npid);
|
||||
atomic_dec(&open_file->wrtPending);
|
||||
cifsFileInfo_put(open_file);
|
||||
} else {
|
||||
rc = CIFSSMBUnixSetPathInfo(xid, pTcon, full_path, args,
|
||||
cifs_sb->local_nls,
|
||||
|
@ -119,20 +119,19 @@ AllocOplockQEntry(struct inode *pinode, __u16 fid, struct cifsTconInfo *tcon)
|
||||
temp->pinode = pinode;
|
||||
temp->tcon = tcon;
|
||||
temp->netfid = fid;
|
||||
spin_lock(&GlobalMid_Lock);
|
||||
list_add_tail(&temp->qhead, &GlobalOplock_Q);
|
||||
spin_unlock(&GlobalMid_Lock);
|
||||
spin_lock(&cifs_oplock_lock);
|
||||
list_add_tail(&temp->qhead, &cifs_oplock_list);
|
||||
spin_unlock(&cifs_oplock_lock);
|
||||
}
|
||||
return temp;
|
||||
|
||||
}
|
||||
|
||||
void DeleteOplockQEntry(struct oplock_q_entry *oplockEntry)
|
||||
{
|
||||
spin_lock(&GlobalMid_Lock);
|
||||
spin_lock(&cifs_oplock_lock);
|
||||
/* should we check if list empty first? */
|
||||
list_del(&oplockEntry->qhead);
|
||||
spin_unlock(&GlobalMid_Lock);
|
||||
spin_unlock(&cifs_oplock_lock);
|
||||
kmem_cache_free(cifs_oplock_cachep, oplockEntry);
|
||||
}
|
||||
|
||||
@ -144,14 +143,14 @@ void DeleteTconOplockQEntries(struct cifsTconInfo *tcon)
|
||||
if (tcon == NULL)
|
||||
return;
|
||||
|
||||
spin_lock(&GlobalMid_Lock);
|
||||
list_for_each_entry(temp, &GlobalOplock_Q, qhead) {
|
||||
spin_lock(&cifs_oplock_lock);
|
||||
list_for_each_entry(temp, &cifs_oplock_list, qhead) {
|
||||
if ((temp->tcon) && (temp->tcon == tcon)) {
|
||||
list_del(&temp->qhead);
|
||||
kmem_cache_free(cifs_oplock_cachep, temp);
|
||||
}
|
||||
}
|
||||
spin_unlock(&GlobalMid_Lock);
|
||||
spin_unlock(&cifs_oplock_lock);
|
||||
}
|
||||
|
||||
static int
|
||||
|
Loading…
Reference in New Issue
Block a user