diff options
Diffstat (limited to 'fs/cifs')
-rw-r--r-- | fs/cifs/CHANGES | 10 | ||||
-rw-r--r-- | fs/cifs/README | 25 | ||||
-rw-r--r-- | fs/cifs/cifs_dfs_ref.c | 12 | ||||
-rw-r--r-- | fs/cifs/cifs_spnego.c | 2 | ||||
-rw-r--r-- | fs/cifs/cifs_unicode.c | 2 | ||||
-rw-r--r-- | fs/cifs/cifsacl.c | 4 | ||||
-rw-r--r-- | fs/cifs/cifsencrypt.c | 1 | ||||
-rw-r--r-- | fs/cifs/cifsfs.c | 26 | ||||
-rw-r--r-- | fs/cifs/cifsfs.h | 2 | ||||
-rw-r--r-- | fs/cifs/cifsglob.h | 21 | ||||
-rw-r--r-- | fs/cifs/cifssmb.c | 316 | ||||
-rw-r--r-- | fs/cifs/connect.c | 112 | ||||
-rw-r--r-- | fs/cifs/dir.c | 2 | ||||
-rw-r--r-- | fs/cifs/file.c | 43 | ||||
-rw-r--r-- | fs/cifs/inode.c | 15 | ||||
-rw-r--r-- | fs/cifs/transport.c | 17 |
16 files changed, 305 insertions, 305 deletions
diff --git a/fs/cifs/CHANGES b/fs/cifs/CHANGES index 92888aa90749..145540a316ab 100644 --- a/fs/cifs/CHANGES +++ b/fs/cifs/CHANGES | |||
@@ -1,3 +1,13 @@ | |||
1 | Version 1.60 | ||
2 | ------------- | ||
3 | Fix memory leak in reconnect. Fix oops in DFS mount error path. | ||
4 | Set s_maxbytes to smaller (the max that vfs can handle) so that | ||
5 | sendfile will now work over cifs mounts again. Add noforcegid | ||
6 | and noforceuid mount parameters. Fix small mem leak when using | ||
7 | ntlmv2. Fix 2nd mount to same server but with different port to | ||
8 | be allowed (rather than reusing the 1st port) - only when the | ||
9 | user explicitly overrides the port on the 2nd mount. | ||
10 | |||
1 | Version 1.59 | 11 | Version 1.59 |
2 | ------------ | 12 | ------------ |
3 | Client uses server inode numbers (which are persistent) rather than | 13 | Client uses server inode numbers (which are persistent) rather than |
diff --git a/fs/cifs/README b/fs/cifs/README index ad92921dbde4..79c1a93400be 100644 --- a/fs/cifs/README +++ b/fs/cifs/README | |||
@@ -262,11 +262,11 @@ A partial list of the supported mount options follows: | |||
262 | mount. | 262 | mount. |
263 | domain Set the SMB/CIFS workgroup name prepended to the | 263 | domain Set the SMB/CIFS workgroup name prepended to the |
264 | username during CIFS session establishment | 264 | username during CIFS session establishment |
265 | forceuid Set the default uid for inodes based on the uid | 265 | forceuid Set the default uid for inodes to the uid |
266 | passed in. For mounts to servers | 266 | passed in on mount. For mounts to servers |
267 | which do support the CIFS Unix extensions, such as a | 267 | which do support the CIFS Unix extensions, such as a |
268 | properly configured Samba server, the server provides | 268 | properly configured Samba server, the server provides |
269 | the uid, gid and mode so this parameter should not be | 269 | the uid, gid and mode so this parameter should not be |
270 | specified unless the server and clients uid and gid | 270 | specified unless the server and clients uid and gid |
271 | numbering differ. If the server and client are in the | 271 | numbering differ. If the server and client are in the |
272 | same domain (e.g. running winbind or nss_ldap) and | 272 | same domain (e.g. running winbind or nss_ldap) and |
@@ -278,11 +278,7 @@ A partial list of the supported mount options follows: | |||
278 | of existing files will be the uid (gid) of the person | 278 | of existing files will be the uid (gid) of the person |
279 | who executed the mount (root, except when mount.cifs | 279 | who executed the mount (root, except when mount.cifs |
280 | is configured setuid for user mounts) unless the "uid=" | 280 | is configured setuid for user mounts) unless the "uid=" |
281 | (gid) mount option is specified. For the uid (gid) of newly | 281 | (gid) mount option is specified. Also note that permission |
282 | created files and directories, ie files created since | ||
283 | the last mount of the server share, the expected uid | ||
284 | (gid) is cached as long as the inode remains in | ||
285 | memory on the client. Also note that permission | ||
286 | checks (authorization checks) on accesses to a file occur | 282 | checks (authorization checks) on accesses to a file occur |
287 | at the server, but there are cases in which an administrator | 283 | at the server, but there are cases in which an administrator |
288 | may want to restrict at the client as well. For those | 284 | may want to restrict at the client as well. For those |
@@ -290,12 +286,15 @@ A partial list of the supported mount options follows: | |||
290 | (such as Windows), permissions can also be checked at the | 286 | (such as Windows), permissions can also be checked at the |
291 | client, and a crude form of client side permission checking | 287 | client, and a crude form of client side permission checking |
292 | can be enabled by specifying file_mode and dir_mode on | 288 | can be enabled by specifying file_mode and dir_mode on |
293 | the client. Note that the mount.cifs helper must be | 289 | the client. (default) |
294 | at version 1.10 or higher to support specifying the uid | 290 | forcegid (similar to above but for the groupid instead of uid) (default) |
295 | (or gid) in non-numeric form. | 291 | noforceuid Fill in file owner information (uid) by requesting it from |
296 | forcegid (similar to above but for the groupid instead of uid) | 292 | the server if possible. With this option, the value given in |
293 | the uid= option (on mount) will only be used if the server | ||
294 | can not support returning uids on inodes. | ||
295 | noforcegid (similar to above but for the group owner, gid, instead of uid) | ||
297 | uid Set the default uid for inodes, and indicate to the | 296 | uid Set the default uid for inodes, and indicate to the |
298 | cifs kernel driver which local user mounted . If the server | 297 | cifs kernel driver which local user mounted. If the server |
299 | supports the unix extensions the default uid is | 298 | supports the unix extensions the default uid is |
300 | not used to fill in the owner fields of inodes (files) | 299 | not used to fill in the owner fields of inodes (files) |
301 | unless the "forceuid" parameter is specified. | 300 | unless the "forceuid" parameter is specified. |
diff --git a/fs/cifs/cifs_dfs_ref.c b/fs/cifs/cifs_dfs_ref.c index 3bb11be8b6a8..606912d8f2a8 100644 --- a/fs/cifs/cifs_dfs_ref.c +++ b/fs/cifs/cifs_dfs_ref.c | |||
@@ -55,7 +55,7 @@ void cifs_dfs_release_automount_timer(void) | |||
55 | * i.e. strips from UNC trailing path that is not part of share | 55 | * i.e. strips from UNC trailing path that is not part of share |
56 | * name and fixup missing '\' in the begining of DFS node refferal | 56 | * name and fixup missing '\' in the begining of DFS node refferal |
57 | * if neccessary. | 57 | * if neccessary. |
58 | * Returns pointer to share name on success or NULL on error. | 58 | * Returns pointer to share name on success or ERR_PTR on error. |
59 | * Caller is responsible for freeing returned string. | 59 | * Caller is responsible for freeing returned string. |
60 | */ | 60 | */ |
61 | static char *cifs_get_share_name(const char *node_name) | 61 | static char *cifs_get_share_name(const char *node_name) |
@@ -68,7 +68,7 @@ static char *cifs_get_share_name(const char *node_name) | |||
68 | UNC = kmalloc(len+2 /*for term null and additional \ if it's missed */, | 68 | UNC = kmalloc(len+2 /*for term null and additional \ if it's missed */, |
69 | GFP_KERNEL); | 69 | GFP_KERNEL); |
70 | if (!UNC) | 70 | if (!UNC) |
71 | return NULL; | 71 | return ERR_PTR(-ENOMEM); |
72 | 72 | ||
73 | /* get share name and server name */ | 73 | /* get share name and server name */ |
74 | if (node_name[1] != '\\') { | 74 | if (node_name[1] != '\\') { |
@@ -87,7 +87,7 @@ static char *cifs_get_share_name(const char *node_name) | |||
87 | cERROR(1, ("%s: no server name end in node name: %s", | 87 | cERROR(1, ("%s: no server name end in node name: %s", |
88 | __func__, node_name)); | 88 | __func__, node_name)); |
89 | kfree(UNC); | 89 | kfree(UNC); |
90 | return NULL; | 90 | return ERR_PTR(-EINVAL); |
91 | } | 91 | } |
92 | 92 | ||
93 | /* find sharename end */ | 93 | /* find sharename end */ |
@@ -133,6 +133,12 @@ char *cifs_compose_mount_options(const char *sb_mountdata, | |||
133 | return ERR_PTR(-EINVAL); | 133 | return ERR_PTR(-EINVAL); |
134 | 134 | ||
135 | *devname = cifs_get_share_name(ref->node_name); | 135 | *devname = cifs_get_share_name(ref->node_name); |
136 | if (IS_ERR(*devname)) { | ||
137 | rc = PTR_ERR(*devname); | ||
138 | *devname = NULL; | ||
139 | goto compose_mount_options_err; | ||
140 | } | ||
141 | |||
136 | rc = dns_resolve_server_name_to_ip(*devname, &srvIP); | 142 | rc = dns_resolve_server_name_to_ip(*devname, &srvIP); |
137 | if (rc != 0) { | 143 | if (rc != 0) { |
138 | cERROR(1, ("%s: Failed to resolve server part of %s to IP: %d", | 144 | cERROR(1, ("%s: Failed to resolve server part of %s to IP: %d", |
diff --git a/fs/cifs/cifs_spnego.c b/fs/cifs/cifs_spnego.c index 051caecf7d67..8ec7736ce954 100644 --- a/fs/cifs/cifs_spnego.c +++ b/fs/cifs/cifs_spnego.c | |||
@@ -125,7 +125,7 @@ cifs_get_spnego_key(struct cifsSesInfo *sesInfo) | |||
125 | if (server->addr.sockAddr.sin_family == AF_INET) | 125 | if (server->addr.sockAddr.sin_family == AF_INET) |
126 | sprintf(dp, "ip4=%pI4", &server->addr.sockAddr.sin_addr); | 126 | sprintf(dp, "ip4=%pI4", &server->addr.sockAddr.sin_addr); |
127 | else if (server->addr.sockAddr.sin_family == AF_INET6) | 127 | else if (server->addr.sockAddr.sin_family == AF_INET6) |
128 | sprintf(dp, "ip6=%pi6", &server->addr.sockAddr6.sin6_addr); | 128 | sprintf(dp, "ip6=%pI6", &server->addr.sockAddr6.sin6_addr); |
129 | else | 129 | else |
130 | goto out; | 130 | goto out; |
131 | 131 | ||
diff --git a/fs/cifs/cifs_unicode.c b/fs/cifs/cifs_unicode.c index 60e3c4253de0..714a542cbafc 100644 --- a/fs/cifs/cifs_unicode.c +++ b/fs/cifs/cifs_unicode.c | |||
@@ -44,7 +44,7 @@ cifs_ucs2_bytes(const __le16 *from, int maxbytes, | |||
44 | int maxwords = maxbytes / 2; | 44 | int maxwords = maxbytes / 2; |
45 | char tmp[NLS_MAX_CHARSET_SIZE]; | 45 | char tmp[NLS_MAX_CHARSET_SIZE]; |
46 | 46 | ||
47 | for (i = 0; from[i] && i < maxwords; i++) { | 47 | for (i = 0; i < maxwords && from[i]; i++) { |
48 | charlen = codepage->uni2char(le16_to_cpu(from[i]), tmp, | 48 | charlen = codepage->uni2char(le16_to_cpu(from[i]), tmp, |
49 | NLS_MAX_CHARSET_SIZE); | 49 | NLS_MAX_CHARSET_SIZE); |
50 | if (charlen > 0) | 50 | if (charlen > 0) |
diff --git a/fs/cifs/cifsacl.c b/fs/cifs/cifsacl.c index 6941c22398a6..7dfe0842a6f6 100644 --- a/fs/cifs/cifsacl.c +++ b/fs/cifs/cifsacl.c | |||
@@ -607,7 +607,7 @@ static struct cifs_ntsd *get_cifs_acl(struct cifs_sb_info *cifs_sb, | |||
607 | return get_cifs_acl_by_path(cifs_sb, path, pacllen); | 607 | return get_cifs_acl_by_path(cifs_sb, path, pacllen); |
608 | 608 | ||
609 | pntsd = get_cifs_acl_by_fid(cifs_sb, open_file->netfid, pacllen); | 609 | pntsd = get_cifs_acl_by_fid(cifs_sb, open_file->netfid, pacllen); |
610 | atomic_dec(&open_file->wrtPending); | 610 | cifsFileInfo_put(open_file); |
611 | return pntsd; | 611 | return pntsd; |
612 | } | 612 | } |
613 | 613 | ||
@@ -665,7 +665,7 @@ static int set_cifs_acl(struct cifs_ntsd *pnntsd, __u32 acllen, | |||
665 | return set_cifs_acl_by_path(cifs_sb, path, pnntsd, acllen); | 665 | return set_cifs_acl_by_path(cifs_sb, path, pnntsd, acllen); |
666 | 666 | ||
667 | rc = set_cifs_acl_by_fid(cifs_sb, open_file->netfid, pnntsd, acllen); | 667 | rc = set_cifs_acl_by_fid(cifs_sb, open_file->netfid, pnntsd, acllen); |
668 | atomic_dec(&open_file->wrtPending); | 668 | cifsFileInfo_put(open_file); |
669 | return rc; | 669 | return rc; |
670 | } | 670 | } |
671 | 671 | ||
diff --git a/fs/cifs/cifsencrypt.c b/fs/cifs/cifsencrypt.c index 7c9809523f42..7efe1745494d 100644 --- a/fs/cifs/cifsencrypt.c +++ b/fs/cifs/cifsencrypt.c | |||
@@ -373,6 +373,7 @@ calc_exit_2: | |||
373 | compare with the NTLM example */ | 373 | compare with the NTLM example */ |
374 | hmac_md5_final(ses->server->ntlmv2_hash, pctxt); | 374 | hmac_md5_final(ses->server->ntlmv2_hash, pctxt); |
375 | 375 | ||
376 | kfree(pctxt); | ||
376 | return rc; | 377 | return rc; |
377 | } | 378 | } |
378 | 379 | ||
diff --git a/fs/cifs/cifsfs.c b/fs/cifs/cifsfs.c index 44f30504b82d..3610e9958b4c 100644 --- a/fs/cifs/cifsfs.c +++ b/fs/cifs/cifsfs.c | |||
@@ -361,13 +361,10 @@ cifs_show_address(struct seq_file *s, struct TCP_Server_Info *server) | |||
361 | static int | 361 | static int |
362 | cifs_show_options(struct seq_file *s, struct vfsmount *m) | 362 | cifs_show_options(struct seq_file *s, struct vfsmount *m) |
363 | { | 363 | { |
364 | struct cifs_sb_info *cifs_sb; | 364 | struct cifs_sb_info *cifs_sb = CIFS_SB(m->mnt_sb); |
365 | struct cifsTconInfo *tcon; | 365 | struct cifsTconInfo *tcon = cifs_sb->tcon; |
366 | |||
367 | cifs_sb = CIFS_SB(m->mnt_sb); | ||
368 | tcon = cifs_sb->tcon; | ||
369 | 366 | ||
370 | seq_printf(s, ",unc=%s", cifs_sb->tcon->treeName); | 367 | seq_printf(s, ",unc=%s", tcon->treeName); |
371 | if (tcon->ses->userName) | 368 | if (tcon->ses->userName) |
372 | seq_printf(s, ",username=%s", tcon->ses->userName); | 369 | seq_printf(s, ",username=%s", tcon->ses->userName); |
373 | if (tcon->ses->domainName) | 370 | if (tcon->ses->domainName) |
@@ -376,10 +373,14 @@ cifs_show_options(struct seq_file *s, struct vfsmount *m) | |||
376 | seq_printf(s, ",uid=%d", cifs_sb->mnt_uid); | 373 | seq_printf(s, ",uid=%d", cifs_sb->mnt_uid); |
377 | if (cifs_sb->mnt_cifs_flags & CIFS_MOUNT_OVERR_UID) | 374 | if (cifs_sb->mnt_cifs_flags & CIFS_MOUNT_OVERR_UID) |
378 | seq_printf(s, ",forceuid"); | 375 | seq_printf(s, ",forceuid"); |
376 | else | ||
377 | seq_printf(s, ",noforceuid"); | ||
379 | 378 | ||
380 | seq_printf(s, ",gid=%d", cifs_sb->mnt_gid); | 379 | seq_printf(s, ",gid=%d", cifs_sb->mnt_gid); |
381 | if (cifs_sb->mnt_cifs_flags & CIFS_MOUNT_OVERR_GID) | 380 | if (cifs_sb->mnt_cifs_flags & CIFS_MOUNT_OVERR_GID) |
382 | seq_printf(s, ",forcegid"); | 381 | seq_printf(s, ",forcegid"); |
382 | else | ||
383 | seq_printf(s, ",noforcegid"); | ||
383 | 384 | ||
384 | cifs_show_address(s, tcon->ses->server); | 385 | cifs_show_address(s, tcon->ses->server); |
385 | 386 | ||
@@ -985,19 +986,19 @@ static int cifs_oplock_thread(void *dummyarg) | |||
985 | if (try_to_freeze()) | 986 | if (try_to_freeze()) |
986 | continue; | 987 | continue; |
987 | 988 | ||
988 | spin_lock(&GlobalMid_Lock); | 989 | spin_lock(&cifs_oplock_lock); |
989 | if (list_empty(&GlobalOplock_Q)) { | 990 | if (list_empty(&cifs_oplock_list)) { |
990 | spin_unlock(&GlobalMid_Lock); | 991 | spin_unlock(&cifs_oplock_lock); |
991 | set_current_state(TASK_INTERRUPTIBLE); | 992 | set_current_state(TASK_INTERRUPTIBLE); |
992 | schedule_timeout(39*HZ); | 993 | schedule_timeout(39*HZ); |
993 | } else { | 994 | } else { |
994 | oplock_item = list_entry(GlobalOplock_Q.next, | 995 | oplock_item = list_entry(cifs_oplock_list.next, |
995 | struct oplock_q_entry, qhead); | 996 | struct oplock_q_entry, qhead); |
996 | cFYI(1, ("found oplock item to write out")); | 997 | cFYI(1, ("found oplock item to write out")); |
997 | pTcon = oplock_item->tcon; | 998 | pTcon = oplock_item->tcon; |
998 | inode = oplock_item->pinode; | 999 | inode = oplock_item->pinode; |
999 | netfid = oplock_item->netfid; | 1000 | netfid = oplock_item->netfid; |
1000 | spin_unlock(&GlobalMid_Lock); | 1001 | spin_unlock(&cifs_oplock_lock); |
1001 | DeleteOplockQEntry(oplock_item); | 1002 | DeleteOplockQEntry(oplock_item); |
1002 | /* can not grab inode sem here since it would | 1003 | /* can not grab inode sem here since it would |
1003 | deadlock when oplock received on delete | 1004 | deadlock when oplock received on delete |
@@ -1054,7 +1055,7 @@ init_cifs(void) | |||
1054 | int rc = 0; | 1055 | int rc = 0; |
1055 | cifs_proc_init(); | 1056 | cifs_proc_init(); |
1056 | INIT_LIST_HEAD(&cifs_tcp_ses_list); | 1057 | INIT_LIST_HEAD(&cifs_tcp_ses_list); |
1057 | INIT_LIST_HEAD(&GlobalOplock_Q); | 1058 | INIT_LIST_HEAD(&cifs_oplock_list); |
1058 | #ifdef CONFIG_CIFS_EXPERIMENTAL | 1059 | #ifdef CONFIG_CIFS_EXPERIMENTAL |
1059 | INIT_LIST_HEAD(&GlobalDnotifyReqList); | 1060 | INIT_LIST_HEAD(&GlobalDnotifyReqList); |
1060 | INIT_LIST_HEAD(&GlobalDnotifyRsp_Q); | 1061 | INIT_LIST_HEAD(&GlobalDnotifyRsp_Q); |
@@ -1083,6 +1084,7 @@ init_cifs(void) | |||
1083 | rwlock_init(&GlobalSMBSeslock); | 1084 | rwlock_init(&GlobalSMBSeslock); |
1084 | rwlock_init(&cifs_tcp_ses_lock); | 1085 | rwlock_init(&cifs_tcp_ses_lock); |
1085 | spin_lock_init(&GlobalMid_Lock); | 1086 | spin_lock_init(&GlobalMid_Lock); |
1087 | spin_lock_init(&cifs_oplock_lock); | ||
1086 | 1088 | ||
1087 | if (cifs_max_pending < 2) { | 1089 | if (cifs_max_pending < 2) { |
1088 | cifs_max_pending = 2; | 1090 | cifs_max_pending = 2; |
diff --git a/fs/cifs/cifsfs.h b/fs/cifs/cifsfs.h index 6c170948300d..094325e3f714 100644 --- a/fs/cifs/cifsfs.h +++ b/fs/cifs/cifsfs.h | |||
@@ -113,5 +113,5 @@ extern long cifs_ioctl(struct file *filep, unsigned int cmd, unsigned long arg); | |||
113 | extern const struct export_operations cifs_export_ops; | 113 | extern const struct export_operations cifs_export_ops; |
114 | #endif /* EXPERIMENTAL */ | 114 | #endif /* EXPERIMENTAL */ |
115 | 115 | ||
116 | #define CIFS_VERSION "1.60" | 116 | #define CIFS_VERSION "1.61" |
117 | #endif /* _CIFSFS_H */ | 117 | #endif /* _CIFSFS_H */ |
diff --git a/fs/cifs/cifsglob.h b/fs/cifs/cifsglob.h index 6084d6379c03..6cfc81a32703 100644 --- a/fs/cifs/cifsglob.h +++ b/fs/cifs/cifsglob.h | |||
@@ -351,11 +351,24 @@ struct cifsFileInfo { | |||
351 | bool closePend:1; /* file is marked to close */ | 351 | bool closePend:1; /* file is marked to close */ |
352 | bool invalidHandle:1; /* file closed via session abend */ | 352 | bool invalidHandle:1; /* file closed via session abend */ |
353 | bool messageMode:1; /* for pipes: message vs byte mode */ | 353 | bool messageMode:1; /* for pipes: message vs byte mode */ |
354 | atomic_t wrtPending; /* handle in use - defer close */ | 354 | atomic_t count; /* reference count */ |
355 | struct mutex fh_mutex; /* prevents reopen race after dead ses*/ | 355 | struct mutex fh_mutex; /* prevents reopen race after dead ses*/ |
356 | struct cifs_search_info srch_inf; | 356 | struct cifs_search_info srch_inf; |
357 | }; | 357 | }; |
358 | 358 | ||
359 | /* Take a reference on the file private data */ | ||
360 | static inline void cifsFileInfo_get(struct cifsFileInfo *cifs_file) | ||
361 | { | ||
362 | atomic_inc(&cifs_file->count); | ||
363 | } | ||
364 | |||
365 | /* Release a reference on the file private data */ | ||
366 | static inline void cifsFileInfo_put(struct cifsFileInfo *cifs_file) | ||
367 | { | ||
368 | if (atomic_dec_and_test(&cifs_file->count)) | ||
369 | kfree(cifs_file); | ||
370 | } | ||
371 | |||
359 | /* | 372 | /* |
360 | * One of these for each file inode | 373 | * One of these for each file inode |
361 | */ | 374 | */ |
@@ -656,7 +669,11 @@ GLOBAL_EXTERN rwlock_t cifs_tcp_ses_lock; | |||
656 | */ | 669 | */ |
657 | GLOBAL_EXTERN rwlock_t GlobalSMBSeslock; | 670 | GLOBAL_EXTERN rwlock_t GlobalSMBSeslock; |
658 | 671 | ||
659 | GLOBAL_EXTERN struct list_head GlobalOplock_Q; | 672 | /* Global list of oplocks */ |
673 | GLOBAL_EXTERN struct list_head cifs_oplock_list; | ||
674 | |||
675 | /* Protects the cifs_oplock_list */ | ||
676 | GLOBAL_EXTERN spinlock_t cifs_oplock_lock; | ||
660 | 677 | ||
661 | /* Outstanding dir notify requests */ | 678 | /* Outstanding dir notify requests */ |
662 | GLOBAL_EXTERN struct list_head GlobalDnotifyReqList; | 679 | GLOBAL_EXTERN struct list_head GlobalDnotifyReqList; |
diff --git a/fs/cifs/cifssmb.c b/fs/cifs/cifssmb.c index 1866bc2927d4..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 | ||
@@ -3961,6 +3895,10 @@ parse_DFS_referrals(TRANSACTION2_GET_DFS_REFER_RSP *pSMBr, | |||
3961 | if (is_unicode) { | 3895 | if (is_unicode) { |
3962 | __le16 *tmp = kmalloc(strlen(searchName)*2 + 2, | 3896 | __le16 *tmp = kmalloc(strlen(searchName)*2 + 2, |
3963 | GFP_KERNEL); | 3897 | GFP_KERNEL); |
3898 | if (tmp == NULL) { | ||
3899 | rc = -ENOMEM; | ||
3900 | goto parse_DFS_referrals_exit; | ||
3901 | } | ||
3964 | cifsConvertToUCS((__le16 *) tmp, searchName, | 3902 | cifsConvertToUCS((__le16 *) tmp, searchName, |
3965 | PATH_MAX, nls_codepage, remap); | 3903 | PATH_MAX, nls_codepage, remap); |
3966 | node->path_consumed = cifs_ucs2_bytes(tmp, | 3904 | node->path_consumed = cifs_ucs2_bytes(tmp, |
diff --git a/fs/cifs/connect.c b/fs/cifs/connect.c index 9bb5c8750736..d49682433c20 100644 --- a/fs/cifs/connect.c +++ b/fs/cifs/connect.c | |||
@@ -803,6 +803,10 @@ cifs_parse_mount_options(char *options, const char *devname, | |||
803 | char *data; | 803 | char *data; |
804 | unsigned int temp_len, i, j; | 804 | unsigned int temp_len, i, j; |
805 | char separator[2]; | 805 | char separator[2]; |
806 | short int override_uid = -1; | ||
807 | short int override_gid = -1; | ||
808 | bool uid_specified = false; | ||
809 | bool gid_specified = false; | ||
806 | 810 | ||
807 | separator[0] = ','; | 811 | separator[0] = ','; |
808 | separator[1] = 0; | 812 | separator[1] = 0; |
@@ -1093,18 +1097,20 @@ cifs_parse_mount_options(char *options, const char *devname, | |||
1093 | "too long.\n"); | 1097 | "too long.\n"); |
1094 | return 1; | 1098 | return 1; |
1095 | } | 1099 | } |
1096 | } else if (strnicmp(data, "uid", 3) == 0) { | 1100 | } else if (!strnicmp(data, "uid", 3) && value && *value) { |
1097 | if (value && *value) | 1101 | vol->linux_uid = simple_strtoul(value, &value, 0); |
1098 | vol->linux_uid = | 1102 | uid_specified = true; |
1099 | simple_strtoul(value, &value, 0); | 1103 | } else if (!strnicmp(data, "forceuid", 8)) { |
1100 | } else if (strnicmp(data, "forceuid", 8) == 0) { | 1104 | override_uid = 1; |
1101 | vol->override_uid = 1; | 1105 | } else if (!strnicmp(data, "noforceuid", 10)) { |
1102 | } else if (strnicmp(data, "gid", 3) == 0) { | 1106 | override_uid = 0; |
1103 | if (value && *value) | 1107 | } else if (!strnicmp(data, "gid", 3) && value && *value) { |
1104 | vol->linux_gid = | 1108 | vol->linux_gid = simple_strtoul(value, &value, 0); |
1105 | simple_strtoul(value, &value, 0); | 1109 | gid_specified = true; |
1106 | } else if (strnicmp(data, "forcegid", 8) == 0) { | 1110 | } else if (!strnicmp(data, "forcegid", 8)) { |
1107 | vol->override_gid = 1; | 1111 | override_gid = 1; |
1112 | } else if (!strnicmp(data, "noforcegid", 10)) { | ||
1113 | override_gid = 0; | ||
1108 | } else if (strnicmp(data, "file_mode", 4) == 0) { | 1114 | } else if (strnicmp(data, "file_mode", 4) == 0) { |
1109 | if (value && *value) { | 1115 | if (value && *value) { |
1110 | vol->file_mode = | 1116 | vol->file_mode = |
@@ -1355,11 +1361,23 @@ cifs_parse_mount_options(char *options, const char *devname, | |||
1355 | if (vol->UNCip == NULL) | 1361 | if (vol->UNCip == NULL) |
1356 | vol->UNCip = &vol->UNC[2]; | 1362 | vol->UNCip = &vol->UNC[2]; |
1357 | 1363 | ||
1364 | if (uid_specified) | ||
1365 | vol->override_uid = override_uid; | ||
1366 | else if (override_uid == 1) | ||
1367 | printk(KERN_NOTICE "CIFS: ignoring forceuid mount option " | ||
1368 | "specified with no uid= option.\n"); | ||
1369 | |||
1370 | if (gid_specified) | ||
1371 | vol->override_gid = override_gid; | ||
1372 | else if (override_gid == 1) | ||
1373 | printk(KERN_NOTICE "CIFS: ignoring forcegid mount option " | ||
1374 | "specified with no gid= option.\n"); | ||
1375 | |||
1358 | return 0; | 1376 | return 0; |
1359 | } | 1377 | } |
1360 | 1378 | ||
1361 | static struct TCP_Server_Info * | 1379 | static struct TCP_Server_Info * |
1362 | cifs_find_tcp_session(struct sockaddr_storage *addr) | 1380 | cifs_find_tcp_session(struct sockaddr_storage *addr, unsigned short int port) |
1363 | { | 1381 | { |
1364 | struct list_head *tmp; | 1382 | struct list_head *tmp; |
1365 | struct TCP_Server_Info *server; | 1383 | struct TCP_Server_Info *server; |
@@ -1379,16 +1397,37 @@ cifs_find_tcp_session(struct sockaddr_storage *addr) | |||
1379 | if (server->tcpStatus == CifsNew) | 1397 | if (server->tcpStatus == CifsNew) |
1380 | continue; | 1398 | continue; |
1381 | 1399 | ||
1382 | if (addr->ss_family == AF_INET && | 1400 | switch (addr->ss_family) { |
1383 | (addr4->sin_addr.s_addr != | 1401 | case AF_INET: |
1384 | server->addr.sockAddr.sin_addr.s_addr)) | 1402 | if (addr4->sin_addr.s_addr == |
1385 | continue; | 1403 | server->addr.sockAddr.sin_addr.s_addr) { |
1386 | else if (addr->ss_family == AF_INET6 && | 1404 | addr4->sin_port = htons(port); |
1387 | (!ipv6_addr_equal(&server->addr.sockAddr6.sin6_addr, | 1405 | /* user overrode default port? */ |
1388 | &addr6->sin6_addr) || | 1406 | if (addr4->sin_port) { |
1389 | server->addr.sockAddr6.sin6_scope_id != | 1407 | if (addr4->sin_port != |
1390 | addr6->sin6_scope_id)) | 1408 | server->addr.sockAddr.sin_port) |
1391 | continue; | 1409 | continue; |
1410 | } | ||
1411 | break; | ||
1412 | } else | ||
1413 | continue; | ||
1414 | |||
1415 | case AF_INET6: | ||
1416 | if (ipv6_addr_equal(&addr6->sin6_addr, | ||
1417 | &server->addr.sockAddr6.sin6_addr) && | ||
1418 | (addr6->sin6_scope_id == | ||
1419 | server->addr.sockAddr6.sin6_scope_id)) { | ||
1420 | addr6->sin6_port = htons(port); | ||
1421 | /* user overrode default port? */ | ||
1422 | if (addr6->sin6_port) { | ||
1423 | if (addr6->sin6_port != | ||
1424 | server->addr.sockAddr6.sin6_port) | ||
1425 | continue; | ||
1426 | } | ||
1427 | break; | ||
1428 | } else | ||
1429 | continue; | ||
1430 | } | ||
1392 | 1431 | ||
1393 | ++server->srv_count; | 1432 | ++server->srv_count; |
1394 | write_unlock(&cifs_tcp_ses_lock); | 1433 | write_unlock(&cifs_tcp_ses_lock); |
@@ -1457,7 +1496,7 @@ cifs_get_tcp_session(struct smb_vol *volume_info) | |||
1457 | } | 1496 | } |
1458 | 1497 | ||
1459 | /* see if we already have a matching tcp_ses */ | 1498 | /* see if we already have a matching tcp_ses */ |
1460 | tcp_ses = cifs_find_tcp_session(&addr); | 1499 | tcp_ses = cifs_find_tcp_session(&addr, volume_info->port); |
1461 | if (tcp_ses) | 1500 | if (tcp_ses) |
1462 | return tcp_ses; | 1501 | return tcp_ses; |
1463 | 1502 | ||
@@ -2452,10 +2491,10 @@ try_mount_again: | |||
2452 | tcon->local_lease = volume_info->local_lease; | 2491 | tcon->local_lease = volume_info->local_lease; |
2453 | } | 2492 | } |
2454 | if (pSesInfo) { | 2493 | if (pSesInfo) { |
2455 | if (pSesInfo->capabilities & CAP_LARGE_FILES) { | 2494 | if (pSesInfo->capabilities & CAP_LARGE_FILES) |
2456 | sb->s_maxbytes = (u64) 1 << 63; | 2495 | sb->s_maxbytes = MAX_LFS_FILESIZE; |
2457 | } else | 2496 | else |
2458 | sb->s_maxbytes = (u64) 1 << 31; /* 2 GB */ | 2497 | sb->s_maxbytes = MAX_NON_LFS; |
2459 | } | 2498 | } |
2460 | 2499 | ||
2461 | /* BB FIXME fix time_gran to be larger for LANMAN sessions */ | 2500 | /* BB FIXME fix time_gran to be larger for LANMAN sessions */ |
@@ -2544,11 +2583,20 @@ remote_path_check: | |||
2544 | 2583 | ||
2545 | if (mount_data != mount_data_global) | 2584 | if (mount_data != mount_data_global) |
2546 | kfree(mount_data); | 2585 | kfree(mount_data); |
2586 | |||
2547 | mount_data = cifs_compose_mount_options( | 2587 | mount_data = cifs_compose_mount_options( |
2548 | cifs_sb->mountdata, full_path + 1, | 2588 | cifs_sb->mountdata, full_path + 1, |
2549 | referrals, &fake_devname); | 2589 | referrals, &fake_devname); |
2550 | kfree(fake_devname); | 2590 | |
2551 | free_dfs_info_array(referrals, num_referrals); | 2591 | free_dfs_info_array(referrals, num_referrals); |
2592 | kfree(fake_devname); | ||
2593 | kfree(full_path); | ||
2594 | |||
2595 | if (IS_ERR(mount_data)) { | ||
2596 | rc = PTR_ERR(mount_data); | ||
2597 | mount_data = NULL; | ||
2598 | goto mount_fail_check; | ||
2599 | } | ||
2552 | 2600 | ||
2553 | if (tcon) | 2601 | if (tcon) |
2554 | cifs_put_tcon(tcon); | 2602 | cifs_put_tcon(tcon); |
@@ -2556,8 +2604,6 @@ remote_path_check: | |||
2556 | cifs_put_smb_ses(pSesInfo); | 2604 | cifs_put_smb_ses(pSesInfo); |
2557 | 2605 | ||
2558 | cleanup_volume_info(&volume_info); | 2606 | cleanup_volume_info(&volume_info); |
2559 | FreeXid(xid); | ||
2560 | kfree(full_path); | ||
2561 | referral_walks_count++; | 2607 | referral_walks_count++; |
2562 | goto try_mount_again; | 2608 | goto try_mount_again; |
2563 | } | 2609 | } |
@@ -2611,9 +2657,9 @@ CIFSTCon(unsigned int xid, struct cifsSesInfo *ses, | |||
2611 | return -EIO; | 2657 | return -EIO; |
2612 | 2658 | ||
2613 | smb_buffer = cifs_buf_get(); | 2659 | smb_buffer = cifs_buf_get(); |
2614 | if (smb_buffer == NULL) { | 2660 | if (smb_buffer == NULL) |
2615 | return -ENOMEM; | 2661 | return -ENOMEM; |
2616 | } | 2662 | |
2617 | smb_buffer_response = smb_buffer; | 2663 | smb_buffer_response = smb_buffer; |
2618 | 2664 | ||
2619 | header_assemble(smb_buffer, SMB_COM_TREE_CONNECT_ANDX, | 2665 | header_assemble(smb_buffer, SMB_COM_TREE_CONNECT_ANDX, |
diff --git a/fs/cifs/dir.c b/fs/cifs/dir.c index 4326ffd90fa9..a6424cfc0121 100644 --- a/fs/cifs/dir.c +++ b/fs/cifs/dir.c | |||
@@ -153,7 +153,7 @@ cifs_fill_fileinfo(struct inode *newinode, __u16 fileHandle, | |||
153 | mutex_init(&pCifsFile->fh_mutex); | 153 | mutex_init(&pCifsFile->fh_mutex); |
154 | mutex_init(&pCifsFile->lock_mutex); | 154 | mutex_init(&pCifsFile->lock_mutex); |
155 | INIT_LIST_HEAD(&pCifsFile->llist); | 155 | INIT_LIST_HEAD(&pCifsFile->llist); |
156 | atomic_set(&pCifsFile->wrtPending, 0); | 156 | atomic_set(&pCifsFile->count, 1); |
157 | 157 | ||
158 | /* set the following in open now | 158 | /* set the following in open now |
159 | pCifsFile->pfile = file; */ | 159 | pCifsFile->pfile = file; */ |
diff --git a/fs/cifs/file.c b/fs/cifs/file.c index c34b7f8a217b..fa7beac8b80e 100644 --- a/fs/cifs/file.c +++ b/fs/cifs/file.c | |||
@@ -53,11 +53,9 @@ static inline struct cifsFileInfo *cifs_init_private( | |||
53 | private_data->pInode = inode; | 53 | private_data->pInode = inode; |
54 | private_data->invalidHandle = false; | 54 | private_data->invalidHandle = false; |
55 | private_data->closePend = false; | 55 | private_data->closePend = false; |
56 | /* we have to track num writers to the inode, since writepages | 56 | /* Initialize reference count to one. The private data is |
57 | does not tell us which handle the write is for so there can | 57 | freed on the release of the last reference */ |
58 | be a close (overlapping with write) of the filehandle that | 58 | atomic_set(&private_data->count, 1); |
59 | cifs_writepages chose to use */ | ||
60 | atomic_set(&private_data->wrtPending, 0); | ||
61 | 59 | ||
62 | return private_data; | 60 | return private_data; |
63 | } | 61 | } |
@@ -643,7 +641,7 @@ int cifs_close(struct inode *inode, struct file *file) | |||
643 | if (!pTcon->need_reconnect) { | 641 | if (!pTcon->need_reconnect) { |
644 | write_unlock(&GlobalSMBSeslock); | 642 | write_unlock(&GlobalSMBSeslock); |
645 | timeout = 2; | 643 | timeout = 2; |
646 | while ((atomic_read(&pSMBFile->wrtPending) != 0) | 644 | while ((atomic_read(&pSMBFile->count) != 1) |
647 | && (timeout <= 2048)) { | 645 | && (timeout <= 2048)) { |
648 | /* Give write a better chance to get to | 646 | /* Give write a better chance to get to |
649 | server ahead of the close. We do not | 647 | server ahead of the close. We do not |
@@ -657,8 +655,6 @@ int cifs_close(struct inode *inode, struct file *file) | |||
657 | msleep(timeout); | 655 | msleep(timeout); |
658 | timeout *= 4; | 656 | timeout *= 4; |
659 | } | 657 | } |
660 | if (atomic_read(&pSMBFile->wrtPending)) | ||
661 | cERROR(1, ("close with pending write")); | ||
662 | if (!pTcon->need_reconnect && | 658 | if (!pTcon->need_reconnect && |
663 | !pSMBFile->invalidHandle) | 659 | !pSMBFile->invalidHandle) |
664 | rc = CIFSSMBClose(xid, pTcon, | 660 | rc = CIFSSMBClose(xid, pTcon, |
@@ -681,24 +677,7 @@ int cifs_close(struct inode *inode, struct file *file) | |||
681 | list_del(&pSMBFile->flist); | 677 | list_del(&pSMBFile->flist); |
682 | list_del(&pSMBFile->tlist); | 678 | list_del(&pSMBFile->tlist); |
683 | write_unlock(&GlobalSMBSeslock); | 679 | write_unlock(&GlobalSMBSeslock); |
684 | timeout = 10; | 680 | cifsFileInfo_put(file->private_data); |
685 | /* We waited above to give the SMBWrite a chance to issue | ||
686 | on the wire (so we do not get SMBWrite returning EBADF | ||
687 | if writepages is racing with close. Note that writepages | ||
688 | does not specify a file handle, so it is possible for a file | ||
689 | to be opened twice, and the application close the "wrong" | ||
690 | file handle - in these cases we delay long enough to allow | ||
691 | the SMBWrite to get on the wire before the SMB Close. | ||
692 | We allow total wait here over 45 seconds, more than | ||
693 | oplock break time, and more than enough to allow any write | ||
694 | to complete on the server, or to time out on the client */ | ||
695 | while ((atomic_read(&pSMBFile->wrtPending) != 0) | ||
696 | && (timeout <= 50000)) { | ||
697 | cERROR(1, ("writes pending, delay free of handle")); | ||
698 | msleep(timeout); | ||
699 | timeout *= 8; | ||
700 | } | ||
701 | kfree(file->private_data); | ||
702 | file->private_data = NULL; | 681 | file->private_data = NULL; |
703 | } else | 682 | } else |
704 | rc = -EBADF; | 683 | rc = -EBADF; |
@@ -1236,7 +1215,7 @@ struct cifsFileInfo *find_readable_file(struct cifsInodeInfo *cifs_inode) | |||
1236 | if (!open_file->invalidHandle) { | 1215 | if (!open_file->invalidHandle) { |
1237 | /* found a good file */ | 1216 | /* found a good file */ |
1238 | /* lock it so it will not be closed on us */ | 1217 | /* lock it so it will not be closed on us */ |
1239 | atomic_inc(&open_file->wrtPending); | 1218 | cifsFileInfo_get(open_file); |
1240 | read_unlock(&GlobalSMBSeslock); | 1219 | read_unlock(&GlobalSMBSeslock); |
1241 | return open_file; | 1220 | return open_file; |
1242 | } /* else might as well continue, and look for | 1221 | } /* else might as well continue, and look for |
@@ -1276,7 +1255,7 @@ refind_writable: | |||
1276 | if (open_file->pfile && | 1255 | if (open_file->pfile && |
1277 | ((open_file->pfile->f_flags & O_RDWR) || | 1256 | ((open_file->pfile->f_flags & O_RDWR) || |
1278 | (open_file->pfile->f_flags & O_WRONLY))) { | 1257 | (open_file->pfile->f_flags & O_WRONLY))) { |
1279 | atomic_inc(&open_file->wrtPending); | 1258 | cifsFileInfo_get(open_file); |
1280 | 1259 | ||
1281 | if (!open_file->invalidHandle) { | 1260 | if (!open_file->invalidHandle) { |
1282 | /* found a good writable file */ | 1261 | /* found a good writable file */ |
@@ -1293,7 +1272,7 @@ refind_writable: | |||
1293 | else { /* start over in case this was deleted */ | 1272 | else { /* start over in case this was deleted */ |
1294 | /* since the list could be modified */ | 1273 | /* since the list could be modified */ |
1295 | read_lock(&GlobalSMBSeslock); | 1274 | read_lock(&GlobalSMBSeslock); |
1296 | atomic_dec(&open_file->wrtPending); | 1275 | cifsFileInfo_put(open_file); |
1297 | goto refind_writable; | 1276 | goto refind_writable; |
1298 | } | 1277 | } |
1299 | } | 1278 | } |
@@ -1309,7 +1288,7 @@ refind_writable: | |||
1309 | read_lock(&GlobalSMBSeslock); | 1288 | read_lock(&GlobalSMBSeslock); |
1310 | /* can not use this handle, no write | 1289 | /* can not use this handle, no write |
1311 | pending on this one after all */ | 1290 | pending on this one after all */ |
1312 | atomic_dec(&open_file->wrtPending); | 1291 | cifsFileInfo_put(open_file); |
1313 | 1292 | ||
1314 | if (open_file->closePend) /* list could have changed */ | 1293 | if (open_file->closePend) /* list could have changed */ |
1315 | goto refind_writable; | 1294 | goto refind_writable; |
@@ -1373,7 +1352,7 @@ static int cifs_partialpagewrite(struct page *page, unsigned from, unsigned to) | |||
1373 | if (open_file) { | 1352 | if (open_file) { |
1374 | bytes_written = cifs_write(open_file->pfile, write_data, | 1353 | bytes_written = cifs_write(open_file->pfile, write_data, |
1375 | to-from, &offset); | 1354 | to-from, &offset); |
1376 | atomic_dec(&open_file->wrtPending); | 1355 | cifsFileInfo_put(open_file); |
1377 | /* Does mm or vfs already set times? */ | 1356 | /* Does mm or vfs already set times? */ |
1378 | inode->i_atime = inode->i_mtime = current_fs_time(inode->i_sb); | 1357 | inode->i_atime = inode->i_mtime = current_fs_time(inode->i_sb); |
1379 | if ((bytes_written > 0) && (offset)) | 1358 | if ((bytes_written > 0) && (offset)) |
@@ -1562,7 +1541,7 @@ retry: | |||
1562 | bytes_to_write, offset, | 1541 | bytes_to_write, offset, |
1563 | &bytes_written, iov, n_iov, | 1542 | &bytes_written, iov, n_iov, |
1564 | long_op); | 1543 | long_op); |
1565 | atomic_dec(&open_file->wrtPending); | 1544 | cifsFileInfo_put(open_file); |
1566 | cifs_update_eof(cifsi, offset, bytes_written); | 1545 | cifs_update_eof(cifsi, offset, bytes_written); |
1567 | 1546 | ||
1568 | if (rc || bytes_written < bytes_to_write) { | 1547 | if (rc || bytes_written < bytes_to_write) { |
diff --git a/fs/cifs/inode.c b/fs/cifs/inode.c index 18afe57b2461..1f09c7619319 100644 --- a/fs/cifs/inode.c +++ b/fs/cifs/inode.c | |||
@@ -212,7 +212,7 @@ cifs_unix_basic_to_fattr(struct cifs_fattr *fattr, FILE_UNIX_BASIC_INFO *info, | |||
212 | * junction to the new submount (ie to setup the fake directory | 212 | * junction to the new submount (ie to setup the fake directory |
213 | * which represents a DFS referral). | 213 | * which represents a DFS referral). |
214 | */ | 214 | */ |
215 | void | 215 | static void |
216 | cifs_create_dfs_fattr(struct cifs_fattr *fattr, struct super_block *sb) | 216 | cifs_create_dfs_fattr(struct cifs_fattr *fattr, struct super_block *sb) |
217 | { | 217 | { |
218 | struct cifs_sb_info *cifs_sb = CIFS_SB(sb); | 218 | struct cifs_sb_info *cifs_sb = CIFS_SB(sb); |
@@ -388,7 +388,7 @@ static int cifs_sfu_mode(struct cifs_fattr *fattr, const unsigned char *path, | |||
388 | } | 388 | } |
389 | 389 | ||
390 | /* Fill a cifs_fattr struct with info from FILE_ALL_INFO */ | 390 | /* Fill a cifs_fattr struct with info from FILE_ALL_INFO */ |
391 | void | 391 | static void |
392 | cifs_all_info_to_fattr(struct cifs_fattr *fattr, FILE_ALL_INFO *info, | 392 | cifs_all_info_to_fattr(struct cifs_fattr *fattr, FILE_ALL_INFO *info, |
393 | struct cifs_sb_info *cifs_sb, bool adjust_tz) | 393 | struct cifs_sb_info *cifs_sb, bool adjust_tz) |
394 | { | 394 | { |
@@ -513,9 +513,12 @@ int cifs_get_inode_info(struct inode **pinode, | |||
513 | cifs_sb->mnt_cifs_flags & | 513 | cifs_sb->mnt_cifs_flags & |
514 | CIFS_MOUNT_MAP_SPECIAL_CHR); | 514 | CIFS_MOUNT_MAP_SPECIAL_CHR); |
515 | if (rc1) { | 515 | if (rc1) { |
516 | /* BB EOPNOSUPP disable SERVER_INUM? */ | ||
517 | cFYI(1, ("GetSrvInodeNum rc %d", rc1)); | 516 | cFYI(1, ("GetSrvInodeNum rc %d", rc1)); |
518 | fattr.cf_uniqueid = iunique(sb, ROOT_I); | 517 | fattr.cf_uniqueid = iunique(sb, ROOT_I); |
518 | /* disable serverino if call not supported */ | ||
519 | if (rc1 == -EINVAL) | ||
520 | cifs_sb->mnt_cifs_flags &= | ||
521 | ~CIFS_MOUNT_SERVER_INUM; | ||
519 | } | 522 | } |
520 | } else { | 523 | } else { |
521 | fattr.cf_uniqueid = iunique(sb, ROOT_I); | 524 | fattr.cf_uniqueid = iunique(sb, ROOT_I); |
@@ -797,7 +800,7 @@ set_via_filehandle: | |||
797 | if (open_file == NULL) | 800 | if (open_file == NULL) |
798 | CIFSSMBClose(xid, pTcon, netfid); | 801 | CIFSSMBClose(xid, pTcon, netfid); |
799 | else | 802 | else |
800 | atomic_dec(&open_file->wrtPending); | 803 | cifsFileInfo_put(open_file); |
801 | out: | 804 | out: |
802 | return rc; | 805 | return rc; |
803 | } | 806 | } |
@@ -1632,7 +1635,7 @@ cifs_set_file_size(struct inode *inode, struct iattr *attrs, | |||
1632 | __u32 npid = open_file->pid; | 1635 | __u32 npid = open_file->pid; |
1633 | rc = CIFSSMBSetFileSize(xid, pTcon, attrs->ia_size, nfid, | 1636 | rc = CIFSSMBSetFileSize(xid, pTcon, attrs->ia_size, nfid, |
1634 | npid, false); | 1637 | npid, false); |
1635 | atomic_dec(&open_file->wrtPending); | 1638 | cifsFileInfo_put(open_file); |
1636 | cFYI(1, ("SetFSize for attrs rc = %d", rc)); | 1639 | cFYI(1, ("SetFSize for attrs rc = %d", rc)); |
1637 | if ((rc == -EINVAL) || (rc == -EOPNOTSUPP)) { | 1640 | if ((rc == -EINVAL) || (rc == -EOPNOTSUPP)) { |
1638 | unsigned int bytes_written; | 1641 | unsigned int bytes_written; |
@@ -1787,7 +1790,7 @@ cifs_setattr_unix(struct dentry *direntry, struct iattr *attrs) | |||
1787 | u16 nfid = open_file->netfid; | 1790 | u16 nfid = open_file->netfid; |
1788 | u32 npid = open_file->pid; | 1791 | u32 npid = open_file->pid; |
1789 | rc = CIFSSMBUnixSetFileInfo(xid, pTcon, args, nfid, npid); | 1792 | rc = CIFSSMBUnixSetFileInfo(xid, pTcon, args, nfid, npid); |
1790 | atomic_dec(&open_file->wrtPending); | 1793 | cifsFileInfo_put(open_file); |
1791 | } else { | 1794 | } else { |
1792 | rc = CIFSSMBUnixSetPathInfo(xid, pTcon, full_path, args, | 1795 | rc = CIFSSMBUnixSetPathInfo(xid, pTcon, full_path, args, |
1793 | cifs_sb->local_nls, | 1796 | cifs_sb->local_nls, |
diff --git a/fs/cifs/transport.c b/fs/cifs/transport.c index 0ad3e2d116a6..1da4ab250eae 100644 --- a/fs/cifs/transport.c +++ b/fs/cifs/transport.c | |||
@@ -119,20 +119,19 @@ AllocOplockQEntry(struct inode *pinode, __u16 fid, struct cifsTconInfo *tcon) | |||
119 | temp->pinode = pinode; | 119 | temp->pinode = pinode; |
120 | temp->tcon = tcon; | 120 | temp->tcon = tcon; |
121 | temp->netfid = fid; | 121 | temp->netfid = fid; |
122 | spin_lock(&GlobalMid_Lock); | 122 | spin_lock(&cifs_oplock_lock); |
123 | list_add_tail(&temp->qhead, &GlobalOplock_Q); | 123 | list_add_tail(&temp->qhead, &cifs_oplock_list); |
124 | spin_unlock(&GlobalMid_Lock); | 124 | spin_unlock(&cifs_oplock_lock); |
125 | } | 125 | } |
126 | return temp; | 126 | return temp; |
127 | |||
128 | } | 127 | } |
129 | 128 | ||
130 | void DeleteOplockQEntry(struct oplock_q_entry *oplockEntry) | 129 | void DeleteOplockQEntry(struct oplock_q_entry *oplockEntry) |
131 | { | 130 | { |
132 | spin_lock(&GlobalMid_Lock); | 131 | spin_lock(&cifs_oplock_lock); |
133 | /* should we check if list empty first? */ | 132 | /* should we check if list empty first? */ |
134 | list_del(&oplockEntry->qhead); | 133 | list_del(&oplockEntry->qhead); |
135 | spin_unlock(&GlobalMid_Lock); | 134 | spin_unlock(&cifs_oplock_lock); |
136 | kmem_cache_free(cifs_oplock_cachep, oplockEntry); | 135 | kmem_cache_free(cifs_oplock_cachep, oplockEntry); |
137 | } | 136 | } |
138 | 137 | ||
@@ -144,14 +143,14 @@ void DeleteTconOplockQEntries(struct cifsTconInfo *tcon) | |||
144 | if (tcon == NULL) | 143 | if (tcon == NULL) |
145 | return; | 144 | return; |
146 | 145 | ||
147 | spin_lock(&GlobalMid_Lock); | 146 | spin_lock(&cifs_oplock_lock); |
148 | list_for_each_entry(temp, &GlobalOplock_Q, qhead) { | 147 | list_for_each_entry(temp, &cifs_oplock_list, qhead) { |
149 | if ((temp->tcon) && (temp->tcon == tcon)) { | 148 | if ((temp->tcon) && (temp->tcon == tcon)) { |
150 | list_del(&temp->qhead); | 149 | list_del(&temp->qhead); |
151 | kmem_cache_free(cifs_oplock_cachep, temp); | 150 | kmem_cache_free(cifs_oplock_cachep, temp); |
152 | } | 151 | } |
153 | } | 152 | } |
154 | spin_unlock(&GlobalMid_Lock); | 153 | spin_unlock(&cifs_oplock_lock); |
155 | } | 154 | } |
156 | 155 | ||
157 | static int | 156 | static int |