diff options
Diffstat (limited to 'fs/cifs')
-rw-r--r-- | fs/cifs/CHANGES | 9 | ||||
-rw-r--r-- | fs/cifs/README | 2 | ||||
-rw-r--r-- | fs/cifs/asn1.c | 2 | ||||
-rw-r--r-- | fs/cifs/cifs_dfs_ref.c | 6 | ||||
-rw-r--r-- | fs/cifs/cifs_fs_sb.h | 3 | ||||
-rw-r--r-- | fs/cifs/cifs_spnego.c | 1 | ||||
-rw-r--r-- | fs/cifs/cifs_unicode.c | 1 | ||||
-rw-r--r-- | fs/cifs/cifsacl.c | 1 | ||||
-rw-r--r-- | fs/cifs/cifsencrypt.c | 1 | ||||
-rw-r--r-- | fs/cifs/cifsfs.c | 17 | ||||
-rw-r--r-- | fs/cifs/cifsfs.h | 5 | ||||
-rw-r--r-- | fs/cifs/cifsglob.h | 8 | ||||
-rw-r--r-- | fs/cifs/cifspdu.h | 8 | ||||
-rw-r--r-- | fs/cifs/cifsproto.h | 13 | ||||
-rw-r--r-- | fs/cifs/cifssmb.c | 532 | ||||
-rw-r--r-- | fs/cifs/connect.c | 52 | ||||
-rw-r--r-- | fs/cifs/dir.c | 5 | ||||
-rw-r--r-- | fs/cifs/dns_resolve.c | 1 | ||||
-rw-r--r-- | fs/cifs/export.c | 2 | ||||
-rw-r--r-- | fs/cifs/file.c | 46 | ||||
-rw-r--r-- | fs/cifs/inode.c | 338 | ||||
-rw-r--r-- | fs/cifs/link.c | 1 | ||||
-rw-r--r-- | fs/cifs/misc.c | 2 | ||||
-rw-r--r-- | fs/cifs/readdir.c | 9 | ||||
-rw-r--r-- | fs/cifs/sess.c | 12 | ||||
-rw-r--r-- | fs/cifs/smbdes.c | 2 | ||||
-rw-r--r-- | fs/cifs/smbencrypt.c | 1 | ||||
-rw-r--r-- | fs/cifs/transport.c | 1 | ||||
-rw-r--r-- | fs/cifs/xattr.c | 9 |
29 files changed, 673 insertions, 417 deletions
diff --git a/fs/cifs/CHANGES b/fs/cifs/CHANGES index 094ea65afc85..bc0025cdd1c9 100644 --- a/fs/cifs/CHANGES +++ b/fs/cifs/CHANGES | |||
@@ -1,3 +1,8 @@ | |||
1 | Version 1.62 | ||
2 | ------------ | ||
3 | Add sockopt=TCP_NODELAY mount option. EA (xattr) routines hardened | ||
4 | to more strictly handle corrupt frames. | ||
5 | |||
1 | Version 1.61 | 6 | Version 1.61 |
2 | ------------ | 7 | ------------ |
3 | Fix append problem to Samba servers (files opened with O_APPEND could | 8 | Fix append problem to Samba servers (files opened with O_APPEND could |
@@ -5,7 +10,9 @@ have duplicated data). Fix oops in cifs_lookup. Workaround problem | |||
5 | mounting to OS/400 Netserve. Fix oops in cifs_get_tcp_session. | 10 | mounting to OS/400 Netserve. Fix oops in cifs_get_tcp_session. |
6 | Disable use of server inode numbers when server only | 11 | Disable use of server inode numbers when server only |
7 | partially supports them (e.g. for one server querying inode numbers on | 12 | partially supports them (e.g. for one server querying inode numbers on |
8 | FindFirst fails but QPathInfo queries works). | 13 | FindFirst fails but QPathInfo queries works). Fix oops with dfs in |
14 | cifs_put_smb_ses. Fix mmap to work on directio mounts (needed | ||
15 | for OpenOffice when on forcedirectio mount e.g.) | ||
9 | 16 | ||
10 | Version 1.60 | 17 | Version 1.60 |
11 | ------------- | 18 | ------------- |
diff --git a/fs/cifs/README b/fs/cifs/README index 79c1a93400be..a727b7cb075f 100644 --- a/fs/cifs/README +++ b/fs/cifs/README | |||
@@ -423,7 +423,7 @@ A partial list of the supported mount options follows: | |||
423 | source name to use to represent the client netbios machine | 423 | source name to use to represent the client netbios machine |
424 | name when doing the RFC1001 netbios session initialize. | 424 | name when doing the RFC1001 netbios session initialize. |
425 | direct Do not do inode data caching on files opened on this mount. | 425 | direct Do not do inode data caching on files opened on this mount. |
426 | This precludes mmaping files on this mount. In some cases | 426 | This precludes mmapping files on this mount. In some cases |
427 | with fast networks and little or no caching benefits on the | 427 | with fast networks and little or no caching benefits on the |
428 | client (e.g. when the application is doing large sequential | 428 | client (e.g. when the application is doing large sequential |
429 | reads bigger than page size without rereading the same data) | 429 | reads bigger than page size without rereading the same data) |
diff --git a/fs/cifs/asn1.c b/fs/cifs/asn1.c index 20692fbfdb24..a20bea598933 100644 --- a/fs/cifs/asn1.c +++ b/fs/cifs/asn1.c | |||
@@ -136,7 +136,7 @@ asn1_enum_decode(struct asn1_ctx *ctx, __le32 *val) | |||
136 | return 0; | 136 | return 0; |
137 | } | 137 | } |
138 | 138 | ||
139 | ch = *(ctx->pointer)++; /* ch has 0xa, ptr points to lenght octet */ | 139 | ch = *(ctx->pointer)++; /* ch has 0xa, ptr points to length octet */ |
140 | if ((ch) == ASN1_ENUM) /* if ch value is ENUM, 0xa */ | 140 | if ((ch) == ASN1_ENUM) /* if ch value is ENUM, 0xa */ |
141 | *val = *(++(ctx->pointer)); /* value has enum value */ | 141 | *val = *(++(ctx->pointer)); /* value has enum value */ |
142 | else | 142 | else |
diff --git a/fs/cifs/cifs_dfs_ref.c b/fs/cifs/cifs_dfs_ref.c index fea9e898c4ba..78e4d2a3a68b 100644 --- a/fs/cifs/cifs_dfs_ref.c +++ b/fs/cifs/cifs_dfs_ref.c | |||
@@ -15,6 +15,7 @@ | |||
15 | #include <linux/dcache.h> | 15 | #include <linux/dcache.h> |
16 | #include <linux/mount.h> | 16 | #include <linux/mount.h> |
17 | #include <linux/namei.h> | 17 | #include <linux/namei.h> |
18 | #include <linux/slab.h> | ||
18 | #include <linux/vfs.h> | 19 | #include <linux/vfs.h> |
19 | #include <linux/fs.h> | 20 | #include <linux/fs.h> |
20 | #include "cifsglob.h" | 21 | #include "cifsglob.h" |
@@ -54,7 +55,7 @@ void cifs_dfs_release_automount_timer(void) | |||
54 | * Extracts sharename form full UNC. | 55 | * Extracts sharename form full UNC. |
55 | * i.e. strips from UNC trailing path that is not part of share | 56 | * 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 | 57 | * name and fixup missing '\' in the begining of DFS node refferal |
57 | * if neccessary. | 58 | * if necessary. |
58 | * Returns pointer to share name on success or ERR_PTR on error. | 59 | * Returns pointer to share name on success or ERR_PTR on error. |
59 | * Caller is responsible for freeing returned string. | 60 | * Caller is responsible for freeing returned string. |
60 | */ | 61 | */ |
@@ -269,7 +270,7 @@ static int add_mount_helper(struct vfsmount *newmnt, struct nameidata *nd, | |||
269 | int err; | 270 | int err; |
270 | 271 | ||
271 | mntget(newmnt); | 272 | mntget(newmnt); |
272 | err = do_add_mount(newmnt, &nd->path, nd->path.mnt->mnt_flags, mntlist); | 273 | err = do_add_mount(newmnt, &nd->path, nd->path.mnt->mnt_flags | MNT_SHRINKABLE, mntlist); |
273 | switch (err) { | 274 | switch (err) { |
274 | case 0: | 275 | case 0: |
275 | path_put(&nd->path); | 276 | path_put(&nd->path); |
@@ -371,7 +372,6 @@ cifs_dfs_follow_mountpoint(struct dentry *dentry, struct nameidata *nd) | |||
371 | if (IS_ERR(mnt)) | 372 | if (IS_ERR(mnt)) |
372 | goto out_err; | 373 | goto out_err; |
373 | 374 | ||
374 | nd->path.mnt->mnt_flags |= MNT_SHRINKABLE; | ||
375 | rc = add_mount_helper(mnt, nd, &cifs_dfs_automount_list); | 375 | rc = add_mount_helper(mnt, nd, &cifs_dfs_automount_list); |
376 | 376 | ||
377 | out: | 377 | out: |
diff --git a/fs/cifs/cifs_fs_sb.h b/fs/cifs/cifs_fs_sb.h index 4797787c6a44..246a167cb913 100644 --- a/fs/cifs/cifs_fs_sb.h +++ b/fs/cifs/cifs_fs_sb.h | |||
@@ -18,6 +18,8 @@ | |||
18 | #ifndef _CIFS_FS_SB_H | 18 | #ifndef _CIFS_FS_SB_H |
19 | #define _CIFS_FS_SB_H | 19 | #define _CIFS_FS_SB_H |
20 | 20 | ||
21 | #include <linux/backing-dev.h> | ||
22 | |||
21 | #define CIFS_MOUNT_NO_PERM 1 /* do not do client vfs_perm check */ | 23 | #define CIFS_MOUNT_NO_PERM 1 /* do not do client vfs_perm check */ |
22 | #define CIFS_MOUNT_SET_UID 2 /* set current's euid in create etc. */ | 24 | #define CIFS_MOUNT_SET_UID 2 /* set current's euid in create etc. */ |
23 | #define CIFS_MOUNT_SERVER_INUM 4 /* inode numbers from uniqueid from server */ | 25 | #define CIFS_MOUNT_SERVER_INUM 4 /* inode numbers from uniqueid from server */ |
@@ -50,5 +52,6 @@ struct cifs_sb_info { | |||
50 | #ifdef CONFIG_CIFS_DFS_UPCALL | 52 | #ifdef CONFIG_CIFS_DFS_UPCALL |
51 | char *mountdata; /* mount options received at mount time */ | 53 | char *mountdata; /* mount options received at mount time */ |
52 | #endif | 54 | #endif |
55 | struct backing_dev_info bdi; | ||
53 | }; | 56 | }; |
54 | #endif /* _CIFS_FS_SB_H */ | 57 | #endif /* _CIFS_FS_SB_H */ |
diff --git a/fs/cifs/cifs_spnego.c b/fs/cifs/cifs_spnego.c index 8ec7736ce954..310d12f69a92 100644 --- a/fs/cifs/cifs_spnego.c +++ b/fs/cifs/cifs_spnego.c | |||
@@ -20,6 +20,7 @@ | |||
20 | */ | 20 | */ |
21 | 21 | ||
22 | #include <linux/list.h> | 22 | #include <linux/list.h> |
23 | #include <linux/slab.h> | ||
23 | #include <linux/string.h> | 24 | #include <linux/string.h> |
24 | #include <keys/user-type.h> | 25 | #include <keys/user-type.h> |
25 | #include <linux/key-type.h> | 26 | #include <linux/key-type.h> |
diff --git a/fs/cifs/cifs_unicode.c b/fs/cifs/cifs_unicode.c index 714a542cbafc..d07676bd76d2 100644 --- a/fs/cifs/cifs_unicode.c +++ b/fs/cifs/cifs_unicode.c | |||
@@ -19,6 +19,7 @@ | |||
19 | * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA | 19 | * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA |
20 | */ | 20 | */ |
21 | #include <linux/fs.h> | 21 | #include <linux/fs.h> |
22 | #include <linux/slab.h> | ||
22 | #include "cifs_unicode.h" | 23 | #include "cifs_unicode.h" |
23 | #include "cifs_uniupr.h" | 24 | #include "cifs_uniupr.h" |
24 | #include "cifspdu.h" | 25 | #include "cifspdu.h" |
diff --git a/fs/cifs/cifsacl.c b/fs/cifs/cifsacl.c index 7dfe0842a6f6..9b716d044bbd 100644 --- a/fs/cifs/cifsacl.c +++ b/fs/cifs/cifsacl.c | |||
@@ -22,6 +22,7 @@ | |||
22 | */ | 22 | */ |
23 | 23 | ||
24 | #include <linux/fs.h> | 24 | #include <linux/fs.h> |
25 | #include <linux/slab.h> | ||
25 | #include "cifspdu.h" | 26 | #include "cifspdu.h" |
26 | #include "cifsglob.h" | 27 | #include "cifsglob.h" |
27 | #include "cifsacl.h" | 28 | #include "cifsacl.h" |
diff --git a/fs/cifs/cifsencrypt.c b/fs/cifs/cifsencrypt.c index 7efe1745494d..fbe986430d0c 100644 --- a/fs/cifs/cifsencrypt.c +++ b/fs/cifs/cifsencrypt.c | |||
@@ -20,6 +20,7 @@ | |||
20 | */ | 20 | */ |
21 | 21 | ||
22 | #include <linux/fs.h> | 22 | #include <linux/fs.h> |
23 | #include <linux/slab.h> | ||
23 | #include "cifspdu.h" | 24 | #include "cifspdu.h" |
24 | #include "cifsglob.h" | 25 | #include "cifsglob.h" |
25 | #include "cifs_debug.h" | 26 | #include "cifs_debug.h" |
diff --git a/fs/cifs/cifsfs.c b/fs/cifs/cifsfs.c index 29f1da761bbf..ad235d604a0b 100644 --- a/fs/cifs/cifsfs.c +++ b/fs/cifs/cifsfs.c | |||
@@ -103,6 +103,12 @@ cifs_read_super(struct super_block *sb, void *data, | |||
103 | if (cifs_sb == NULL) | 103 | if (cifs_sb == NULL) |
104 | return -ENOMEM; | 104 | return -ENOMEM; |
105 | 105 | ||
106 | rc = bdi_setup_and_register(&cifs_sb->bdi, "cifs", BDI_CAP_MAP_COPY); | ||
107 | if (rc) { | ||
108 | kfree(cifs_sb); | ||
109 | return rc; | ||
110 | } | ||
111 | |||
106 | #ifdef CONFIG_CIFS_DFS_UPCALL | 112 | #ifdef CONFIG_CIFS_DFS_UPCALL |
107 | /* copy mount params to sb for use in submounts */ | 113 | /* copy mount params to sb for use in submounts */ |
108 | /* BB: should we move this after the mount so we | 114 | /* BB: should we move this after the mount so we |
@@ -115,6 +121,7 @@ cifs_read_super(struct super_block *sb, void *data, | |||
115 | int len = strlen(data); | 121 | int len = strlen(data); |
116 | cifs_sb->mountdata = kzalloc(len + 1, GFP_KERNEL); | 122 | cifs_sb->mountdata = kzalloc(len + 1, GFP_KERNEL); |
117 | if (cifs_sb->mountdata == NULL) { | 123 | if (cifs_sb->mountdata == NULL) { |
124 | bdi_destroy(&cifs_sb->bdi); | ||
118 | kfree(sb->s_fs_info); | 125 | kfree(sb->s_fs_info); |
119 | sb->s_fs_info = NULL; | 126 | sb->s_fs_info = NULL; |
120 | return -ENOMEM; | 127 | return -ENOMEM; |
@@ -135,6 +142,7 @@ cifs_read_super(struct super_block *sb, void *data, | |||
135 | 142 | ||
136 | sb->s_magic = CIFS_MAGIC_NUMBER; | 143 | sb->s_magic = CIFS_MAGIC_NUMBER; |
137 | sb->s_op = &cifs_super_ops; | 144 | sb->s_op = &cifs_super_ops; |
145 | sb->s_bdi = &cifs_sb->bdi; | ||
138 | /* if (cifs_sb->tcon->ses->server->maxBuf > MAX_CIFS_HDR_SIZE + 512) | 146 | /* if (cifs_sb->tcon->ses->server->maxBuf > MAX_CIFS_HDR_SIZE + 512) |
139 | sb->s_blocksize = | 147 | sb->s_blocksize = |
140 | cifs_sb->tcon->ses->server->maxBuf - MAX_CIFS_HDR_SIZE; */ | 148 | cifs_sb->tcon->ses->server->maxBuf - MAX_CIFS_HDR_SIZE; */ |
@@ -183,6 +191,7 @@ out_mount_failed: | |||
183 | } | 191 | } |
184 | #endif | 192 | #endif |
185 | unload_nls(cifs_sb->local_nls); | 193 | unload_nls(cifs_sb->local_nls); |
194 | bdi_destroy(&cifs_sb->bdi); | ||
186 | kfree(cifs_sb); | 195 | kfree(cifs_sb); |
187 | } | 196 | } |
188 | return rc; | 197 | return rc; |
@@ -214,6 +223,7 @@ cifs_put_super(struct super_block *sb) | |||
214 | #endif | 223 | #endif |
215 | 224 | ||
216 | unload_nls(cifs_sb->local_nls); | 225 | unload_nls(cifs_sb->local_nls); |
226 | bdi_destroy(&cifs_sb->bdi); | ||
217 | kfree(cifs_sb); | 227 | kfree(cifs_sb); |
218 | 228 | ||
219 | unlock_kernel(); | 229 | unlock_kernel(); |
@@ -312,6 +322,7 @@ cifs_alloc_inode(struct super_block *sb) | |||
312 | cifs_inode->clientCanCacheRead = false; | 322 | cifs_inode->clientCanCacheRead = false; |
313 | cifs_inode->clientCanCacheAll = false; | 323 | cifs_inode->clientCanCacheAll = false; |
314 | cifs_inode->delete_pending = false; | 324 | cifs_inode->delete_pending = false; |
325 | cifs_inode->invalid_mapping = false; | ||
315 | cifs_inode->vfs_inode.i_blkbits = 14; /* 2**14 = CIFS_MAX_MSGSIZE */ | 326 | cifs_inode->vfs_inode.i_blkbits = 14; /* 2**14 = CIFS_MAX_MSGSIZE */ |
316 | cifs_inode->server_eof = 0; | 327 | cifs_inode->server_eof = 0; |
317 | 328 | ||
@@ -638,7 +649,7 @@ static loff_t cifs_llseek(struct file *file, loff_t offset, int origin) | |||
638 | setting the revalidate time to zero */ | 649 | setting the revalidate time to zero */ |
639 | CIFS_I(file->f_path.dentry->d_inode)->time = 0; | 650 | CIFS_I(file->f_path.dentry->d_inode)->time = 0; |
640 | 651 | ||
641 | retval = cifs_revalidate(file->f_path.dentry); | 652 | retval = cifs_revalidate_file(file); |
642 | if (retval < 0) | 653 | if (retval < 0) |
643 | return (loff_t)retval; | 654 | return (loff_t)retval; |
644 | } | 655 | } |
@@ -758,7 +769,7 @@ const struct file_operations cifs_file_ops = { | |||
758 | }; | 769 | }; |
759 | 770 | ||
760 | const struct file_operations cifs_file_direct_ops = { | 771 | const struct file_operations cifs_file_direct_ops = { |
761 | /* no mmap, no aio, no readv - | 772 | /* no aio, no readv - |
762 | BB reevaluate whether they can be done with directio, no cache */ | 773 | BB reevaluate whether they can be done with directio, no cache */ |
763 | .read = cifs_user_read, | 774 | .read = cifs_user_read, |
764 | .write = cifs_user_write, | 775 | .write = cifs_user_write, |
@@ -767,6 +778,7 @@ const struct file_operations cifs_file_direct_ops = { | |||
767 | .lock = cifs_lock, | 778 | .lock = cifs_lock, |
768 | .fsync = cifs_fsync, | 779 | .fsync = cifs_fsync, |
769 | .flush = cifs_flush, | 780 | .flush = cifs_flush, |
781 | .mmap = cifs_file_mmap, | ||
770 | .splice_read = generic_file_splice_read, | 782 | .splice_read = generic_file_splice_read, |
771 | #ifdef CONFIG_CIFS_POSIX | 783 | #ifdef CONFIG_CIFS_POSIX |
772 | .unlocked_ioctl = cifs_ioctl, | 784 | .unlocked_ioctl = cifs_ioctl, |
@@ -806,6 +818,7 @@ const struct file_operations cifs_file_direct_nobrl_ops = { | |||
806 | .release = cifs_close, | 818 | .release = cifs_close, |
807 | .fsync = cifs_fsync, | 819 | .fsync = cifs_fsync, |
808 | .flush = cifs_flush, | 820 | .flush = cifs_flush, |
821 | .mmap = cifs_file_mmap, | ||
809 | .splice_read = generic_file_splice_read, | 822 | .splice_read = generic_file_splice_read, |
810 | #ifdef CONFIG_CIFS_POSIX | 823 | #ifdef CONFIG_CIFS_POSIX |
811 | .unlocked_ioctl = cifs_ioctl, | 824 | .unlocked_ioctl = cifs_ioctl, |
diff --git a/fs/cifs/cifsfs.h b/fs/cifs/cifsfs.h index ac2b24c192f8..7aa57ecdc437 100644 --- a/fs/cifs/cifsfs.h +++ b/fs/cifs/cifsfs.h | |||
@@ -61,7 +61,8 @@ extern int cifs_mkdir(struct inode *, struct dentry *, int); | |||
61 | extern int cifs_rmdir(struct inode *, struct dentry *); | 61 | extern int cifs_rmdir(struct inode *, struct dentry *); |
62 | extern int cifs_rename(struct inode *, struct dentry *, struct inode *, | 62 | extern int cifs_rename(struct inode *, struct dentry *, struct inode *, |
63 | struct dentry *); | 63 | struct dentry *); |
64 | extern int cifs_revalidate(struct dentry *); | 64 | extern int cifs_revalidate_file(struct file *filp); |
65 | extern int cifs_revalidate_dentry(struct dentry *); | ||
65 | extern int cifs_getattr(struct vfsmount *, struct dentry *, struct kstat *); | 66 | extern int cifs_getattr(struct vfsmount *, struct dentry *, struct kstat *); |
66 | extern int cifs_setattr(struct dentry *, struct iattr *); | 67 | extern int cifs_setattr(struct dentry *, struct iattr *); |
67 | 68 | ||
@@ -113,5 +114,5 @@ extern long cifs_ioctl(struct file *filep, unsigned int cmd, unsigned long arg); | |||
113 | extern const struct export_operations cifs_export_ops; | 114 | extern const struct export_operations cifs_export_ops; |
114 | #endif /* EXPERIMENTAL */ | 115 | #endif /* EXPERIMENTAL */ |
115 | 116 | ||
116 | #define CIFS_VERSION "1.61" | 117 | #define CIFS_VERSION "1.62" |
117 | #endif /* _CIFSFS_H */ | 118 | #endif /* _CIFSFS_H */ |
diff --git a/fs/cifs/cifsglob.h b/fs/cifs/cifsglob.h index 5d0fde18039c..0c2fd17439c8 100644 --- a/fs/cifs/cifsglob.h +++ b/fs/cifs/cifsglob.h | |||
@@ -18,6 +18,7 @@ | |||
18 | */ | 18 | */ |
19 | #include <linux/in.h> | 19 | #include <linux/in.h> |
20 | #include <linux/in6.h> | 20 | #include <linux/in6.h> |
21 | #include <linux/slab.h> | ||
21 | #include <linux/slow-work.h> | 22 | #include <linux/slow-work.h> |
22 | #include "cifs_fs_sb.h" | 23 | #include "cifs_fs_sb.h" |
23 | #include "cifsacl.h" | 24 | #include "cifsacl.h" |
@@ -39,7 +40,7 @@ | |||
39 | 40 | ||
40 | /* | 41 | /* |
41 | * MAX_REQ is the maximum number of requests that WE will send | 42 | * MAX_REQ is the maximum number of requests that WE will send |
42 | * on one socket concurently. It also matches the most common | 43 | * on one socket concurrently. It also matches the most common |
43 | * value of max multiplex returned by servers. We may | 44 | * value of max multiplex returned by servers. We may |
44 | * eventually want to use the negotiated value (in case | 45 | * eventually want to use the negotiated value (in case |
45 | * future servers can handle more) when we are more confident that | 46 | * future servers can handle more) when we are more confident that |
@@ -149,6 +150,7 @@ struct TCP_Server_Info { | |||
149 | bool svlocal:1; /* local server or remote */ | 150 | bool svlocal:1; /* local server or remote */ |
150 | bool noblocksnd; /* use blocking sendmsg */ | 151 | bool noblocksnd; /* use blocking sendmsg */ |
151 | bool noautotune; /* do not autotune send buf sizes */ | 152 | bool noautotune; /* do not autotune send buf sizes */ |
153 | bool tcp_nodelay; | ||
152 | atomic_t inFlight; /* number of requests on the wire to server */ | 154 | atomic_t inFlight; /* number of requests on the wire to server */ |
153 | #ifdef CONFIG_CIFS_STATS2 | 155 | #ifdef CONFIG_CIFS_STATS2 |
154 | atomic_t inSend; /* requests trying to send */ | 156 | atomic_t inSend; /* requests trying to send */ |
@@ -204,7 +206,7 @@ struct cifsUidInfo { | |||
204 | struct cifsSesInfo { | 206 | struct cifsSesInfo { |
205 | struct list_head smb_ses_list; | 207 | struct list_head smb_ses_list; |
206 | struct list_head tcon_list; | 208 | struct list_head tcon_list; |
207 | struct semaphore sesSem; | 209 | struct mutex session_mutex; |
208 | #if 0 | 210 | #if 0 |
209 | struct cifsUidInfo *uidInfo; /* pointer to user info */ | 211 | struct cifsUidInfo *uidInfo; /* pointer to user info */ |
210 | #endif | 212 | #endif |
@@ -388,6 +390,7 @@ struct cifsInodeInfo { | |||
388 | bool clientCanCacheRead:1; /* read oplock */ | 390 | bool clientCanCacheRead:1; /* read oplock */ |
389 | bool clientCanCacheAll:1; /* read and writebehind oplock */ | 391 | bool clientCanCacheAll:1; /* read and writebehind oplock */ |
390 | bool delete_pending:1; /* DELETE_ON_CLOSE is set */ | 392 | bool delete_pending:1; /* DELETE_ON_CLOSE is set */ |
393 | bool invalid_mapping:1; /* pagecache is invalid */ | ||
391 | u64 server_eof; /* current file size on server */ | 394 | u64 server_eof; /* current file size on server */ |
392 | u64 uniqueid; /* server inode number */ | 395 | u64 uniqueid; /* server inode number */ |
393 | struct inode vfs_inode; | 396 | struct inode vfs_inode; |
@@ -499,6 +502,7 @@ struct dfs_info3_param { | |||
499 | #define CIFS_FATTR_DFS_REFERRAL 0x1 | 502 | #define CIFS_FATTR_DFS_REFERRAL 0x1 |
500 | #define CIFS_FATTR_DELETE_PENDING 0x2 | 503 | #define CIFS_FATTR_DELETE_PENDING 0x2 |
501 | #define CIFS_FATTR_NEED_REVAL 0x4 | 504 | #define CIFS_FATTR_NEED_REVAL 0x4 |
505 | #define CIFS_FATTR_INO_COLLISION 0x8 | ||
502 | 506 | ||
503 | struct cifs_fattr { | 507 | struct cifs_fattr { |
504 | u32 cf_flags; | 508 | u32 cf_flags; |
diff --git a/fs/cifs/cifspdu.h b/fs/cifs/cifspdu.h index 2d07f890a842..14d036d8db11 100644 --- a/fs/cifs/cifspdu.h +++ b/fs/cifs/cifspdu.h | |||
@@ -415,10 +415,10 @@ struct smb_hdr { | |||
415 | __u8 WordCount; | 415 | __u8 WordCount; |
416 | } __attribute__((packed)); | 416 | } __attribute__((packed)); |
417 | /* given a pointer to an smb_hdr retrieve the value of byte count */ | 417 | /* given a pointer to an smb_hdr retrieve the value of byte count */ |
418 | #define BCC(smb_var) (*(__u16 *)((char *)smb_var + sizeof(struct smb_hdr) + (2 * smb_var->WordCount))) | 418 | #define BCC(smb_var) (*(__u16 *)((char *)(smb_var) + sizeof(struct smb_hdr) + (2 * (smb_var)->WordCount))) |
419 | #define BCC_LE(smb_var) (*(__le16 *)((char *)smb_var + sizeof(struct smb_hdr) + (2 * smb_var->WordCount))) | 419 | #define BCC_LE(smb_var) (*(__le16 *)((char *)(smb_var) + sizeof(struct smb_hdr) + (2 * (smb_var)->WordCount))) |
420 | /* given a pointer to an smb_hdr retrieve the pointer to the byte area */ | 420 | /* given a pointer to an smb_hdr retrieve the pointer to the byte area */ |
421 | #define pByteArea(smb_var) ((unsigned char *)smb_var + sizeof(struct smb_hdr) + (2 * smb_var->WordCount) + 2) | 421 | #define pByteArea(smb_var) ((unsigned char *)(smb_var) + sizeof(struct smb_hdr) + (2 * (smb_var)->WordCount) + 2) |
422 | 422 | ||
423 | /* | 423 | /* |
424 | * Computer Name Length (since Netbios name was length 16 with last byte 0x20) | 424 | * Computer Name Length (since Netbios name was length 16 with last byte 0x20) |
@@ -1227,7 +1227,7 @@ typedef struct smb_com_setattr_rsp { | |||
1227 | /* empty wct response to setattr */ | 1227 | /* empty wct response to setattr */ |
1228 | 1228 | ||
1229 | /*******************************************************/ | 1229 | /*******************************************************/ |
1230 | /* NT Transact structure defintions follow */ | 1230 | /* NT Transact structure definitions follow */ |
1231 | /* Currently only ioctl, acl (get security descriptor) */ | 1231 | /* Currently only ioctl, acl (get security descriptor) */ |
1232 | /* and notify are implemented */ | 1232 | /* and notify are implemented */ |
1233 | /*******************************************************/ | 1233 | /*******************************************************/ |
diff --git a/fs/cifs/cifsproto.h b/fs/cifs/cifsproto.h index 5646727e33f5..39e47f46dea5 100644 --- a/fs/cifs/cifsproto.h +++ b/fs/cifs/cifsproto.h | |||
@@ -104,10 +104,12 @@ extern void cifs_fattr_to_inode(struct inode *inode, struct cifs_fattr *fattr); | |||
104 | extern struct inode *cifs_iget(struct super_block *sb, | 104 | extern struct inode *cifs_iget(struct super_block *sb, |
105 | struct cifs_fattr *fattr); | 105 | struct cifs_fattr *fattr); |
106 | 106 | ||
107 | extern int cifs_get_file_info(struct file *filp); | ||
107 | extern int cifs_get_inode_info(struct inode **pinode, | 108 | extern int cifs_get_inode_info(struct inode **pinode, |
108 | const unsigned char *search_path, | 109 | const unsigned char *search_path, |
109 | FILE_ALL_INFO *pfile_info, | 110 | FILE_ALL_INFO *pfile_info, |
110 | struct super_block *sb, int xid, const __u16 *pfid); | 111 | struct super_block *sb, int xid, const __u16 *pfid); |
112 | extern int cifs_get_file_info_unix(struct file *filp); | ||
111 | extern int cifs_get_inode_info_unix(struct inode **pinode, | 113 | extern int cifs_get_inode_info_unix(struct inode **pinode, |
112 | const unsigned char *search_path, | 114 | const unsigned char *search_path, |
113 | struct super_block *sb, int xid); | 115 | struct super_block *sb, int xid); |
@@ -142,6 +144,8 @@ extern int CIFSFindNext(const int xid, struct cifsTconInfo *tcon, | |||
142 | extern int CIFSFindClose(const int, struct cifsTconInfo *tcon, | 144 | extern int CIFSFindClose(const int, struct cifsTconInfo *tcon, |
143 | const __u16 search_handle); | 145 | const __u16 search_handle); |
144 | 146 | ||
147 | extern int CIFSSMBQFileInfo(const int xid, struct cifsTconInfo *tcon, | ||
148 | u16 netfid, FILE_ALL_INFO *pFindData); | ||
145 | extern int CIFSSMBQPathInfo(const int xid, struct cifsTconInfo *tcon, | 149 | extern int CIFSSMBQPathInfo(const int xid, struct cifsTconInfo *tcon, |
146 | const unsigned char *searchName, | 150 | const unsigned char *searchName, |
147 | FILE_ALL_INFO *findData, | 151 | FILE_ALL_INFO *findData, |
@@ -152,6 +156,8 @@ extern int SMBQueryInformation(const int xid, struct cifsTconInfo *tcon, | |||
152 | FILE_ALL_INFO *findData, | 156 | FILE_ALL_INFO *findData, |
153 | const struct nls_table *nls_codepage, int remap); | 157 | const struct nls_table *nls_codepage, int remap); |
154 | 158 | ||
159 | extern int CIFSSMBUnixQFileInfo(const int xid, struct cifsTconInfo *tcon, | ||
160 | u16 netfid, FILE_UNIX_BASIC_INFO *pFindData); | ||
155 | extern int CIFSSMBUnixQPathInfo(const int xid, | 161 | extern int CIFSSMBUnixQPathInfo(const int xid, |
156 | struct cifsTconInfo *tcon, | 162 | struct cifsTconInfo *tcon, |
157 | const unsigned char *searchName, | 163 | const unsigned char *searchName, |
@@ -363,13 +369,10 @@ extern int CIFSSMBNotify(const int xid, struct cifsTconInfo *tcon, | |||
363 | __u32 filter, struct file *file, int multishot, | 369 | __u32 filter, struct file *file, int multishot, |
364 | const struct nls_table *nls_codepage); | 370 | const struct nls_table *nls_codepage); |
365 | extern ssize_t CIFSSMBQAllEAs(const int xid, struct cifsTconInfo *tcon, | 371 | extern ssize_t CIFSSMBQAllEAs(const int xid, struct cifsTconInfo *tcon, |
366 | const unsigned char *searchName, char *EAData, | 372 | const unsigned char *searchName, |
373 | const unsigned char *ea_name, char *EAData, | ||
367 | size_t bufsize, const struct nls_table *nls_codepage, | 374 | size_t bufsize, const struct nls_table *nls_codepage, |
368 | int remap_special_chars); | 375 | int remap_special_chars); |
369 | extern ssize_t CIFSSMBQueryEA(const int xid, struct cifsTconInfo *tcon, | ||
370 | const unsigned char *searchName, const unsigned char *ea_name, | ||
371 | unsigned char *ea_value, size_t buf_size, | ||
372 | const struct nls_table *nls_codepage, int remap_special_chars); | ||
373 | extern int CIFSSMBSetEA(const int xid, struct cifsTconInfo *tcon, | 376 | extern int CIFSSMBSetEA(const int xid, struct cifsTconInfo *tcon, |
374 | const char *fileName, const char *ea_name, | 377 | const char *fileName, const char *ea_name, |
375 | const void *ea_value, const __u16 ea_value_len, | 378 | const void *ea_value, const __u16 ea_value_len, |
diff --git a/fs/cifs/cifssmb.c b/fs/cifs/cifssmb.c index 941441d3e386..5d3f29fef532 100644 --- a/fs/cifs/cifssmb.c +++ b/fs/cifs/cifssmb.c | |||
@@ -30,6 +30,7 @@ | |||
30 | #include <linux/fs.h> | 30 | #include <linux/fs.h> |
31 | #include <linux/kernel.h> | 31 | #include <linux/kernel.h> |
32 | #include <linux/vfs.h> | 32 | #include <linux/vfs.h> |
33 | #include <linux/slab.h> | ||
33 | #include <linux/posix_acl_xattr.h> | 34 | #include <linux/posix_acl_xattr.h> |
34 | #include <asm/uaccess.h> | 35 | #include <asm/uaccess.h> |
35 | #include "cifspdu.h" | 36 | #include "cifspdu.h" |
@@ -170,19 +171,19 @@ cifs_reconnect_tcon(struct cifsTconInfo *tcon, int smb_command) | |||
170 | * need to prevent multiple threads trying to simultaneously | 171 | * need to prevent multiple threads trying to simultaneously |
171 | * reconnect the same SMB session | 172 | * reconnect the same SMB session |
172 | */ | 173 | */ |
173 | down(&ses->sesSem); | 174 | mutex_lock(&ses->session_mutex); |
174 | if (ses->need_reconnect) | 175 | if (ses->need_reconnect) |
175 | rc = cifs_setup_session(0, ses, nls_codepage); | 176 | rc = cifs_setup_session(0, ses, nls_codepage); |
176 | 177 | ||
177 | /* do we need to reconnect tcon? */ | 178 | /* do we need to reconnect tcon? */ |
178 | if (rc || !tcon->need_reconnect) { | 179 | if (rc || !tcon->need_reconnect) { |
179 | up(&ses->sesSem); | 180 | mutex_unlock(&ses->session_mutex); |
180 | goto out; | 181 | goto out; |
181 | } | 182 | } |
182 | 183 | ||
183 | mark_open_files_invalid(tcon); | 184 | mark_open_files_invalid(tcon); |
184 | rc = CIFSTCon(0, ses, tcon->treeName, tcon, nls_codepage); | 185 | rc = CIFSTCon(0, ses, tcon->treeName, tcon, nls_codepage); |
185 | up(&ses->sesSem); | 186 | mutex_unlock(&ses->session_mutex); |
186 | cFYI(1, ("reconnect tcon rc = %d", rc)); | 187 | cFYI(1, ("reconnect tcon rc = %d", rc)); |
187 | 188 | ||
188 | if (rc) | 189 | if (rc) |
@@ -500,7 +501,7 @@ CIFSSMBNegotiate(unsigned int xid, struct cifsSesInfo *ses) | |||
500 | } else if (pSMBr->hdr.WordCount == 13) { | 501 | } else if (pSMBr->hdr.WordCount == 13) { |
501 | cERROR(1, ("mount failed, cifs module not built " | 502 | cERROR(1, ("mount failed, cifs module not built " |
502 | "with CIFS_WEAK_PW_HASH support")); | 503 | "with CIFS_WEAK_PW_HASH support")); |
503 | rc = -EOPNOTSUPP; | 504 | rc = -EOPNOTSUPP; |
504 | #endif /* WEAK_PW_HASH */ | 505 | #endif /* WEAK_PW_HASH */ |
505 | goto neg_err_exit; | 506 | goto neg_err_exit; |
506 | } else if (pSMBr->hdr.WordCount != 17) { | 507 | } else if (pSMBr->hdr.WordCount != 17) { |
@@ -700,13 +701,13 @@ CIFSSMBLogoff(const int xid, struct cifsSesInfo *ses) | |||
700 | if (!ses || !ses->server) | 701 | if (!ses || !ses->server) |
701 | return -EIO; | 702 | return -EIO; |
702 | 703 | ||
703 | down(&ses->sesSem); | 704 | mutex_lock(&ses->session_mutex); |
704 | if (ses->need_reconnect) | 705 | if (ses->need_reconnect) |
705 | goto session_already_dead; /* no need to send SMBlogoff if uid | 706 | goto session_already_dead; /* no need to send SMBlogoff if uid |
706 | already closed due to reconnect */ | 707 | already closed due to reconnect */ |
707 | rc = small_smb_init(SMB_COM_LOGOFF_ANDX, 2, NULL, (void **)&pSMB); | 708 | rc = small_smb_init(SMB_COM_LOGOFF_ANDX, 2, NULL, (void **)&pSMB); |
708 | if (rc) { | 709 | if (rc) { |
709 | up(&ses->sesSem); | 710 | mutex_unlock(&ses->session_mutex); |
710 | return rc; | 711 | return rc; |
711 | } | 712 | } |
712 | 713 | ||
@@ -721,7 +722,7 @@ CIFSSMBLogoff(const int xid, struct cifsSesInfo *ses) | |||
721 | pSMB->AndXCommand = 0xFF; | 722 | pSMB->AndXCommand = 0xFF; |
722 | rc = SendReceiveNoRsp(xid, ses, (struct smb_hdr *) pSMB, 0); | 723 | rc = SendReceiveNoRsp(xid, ses, (struct smb_hdr *) pSMB, 0); |
723 | session_already_dead: | 724 | session_already_dead: |
724 | up(&ses->sesSem); | 725 | mutex_unlock(&ses->session_mutex); |
725 | 726 | ||
726 | /* if session dead then we do not need to do ulogoff, | 727 | /* if session dead then we do not need to do ulogoff, |
727 | since server closed smb session, no sense reporting | 728 | since server closed smb session, no sense reporting |
@@ -1430,6 +1431,8 @@ CIFSSMBWrite(const int xid, struct cifsTconInfo *tcon, | |||
1430 | __u32 bytes_sent; | 1431 | __u32 bytes_sent; |
1431 | __u16 byte_count; | 1432 | __u16 byte_count; |
1432 | 1433 | ||
1434 | *nbytes = 0; | ||
1435 | |||
1433 | /* cFYI(1, ("write at %lld %d bytes", offset, count));*/ | 1436 | /* cFYI(1, ("write at %lld %d bytes", offset, count));*/ |
1434 | if (tcon->ses == NULL) | 1437 | if (tcon->ses == NULL) |
1435 | return -ECONNABORTED; | 1438 | return -ECONNABORTED; |
@@ -1512,11 +1515,18 @@ CIFSSMBWrite(const int xid, struct cifsTconInfo *tcon, | |||
1512 | cifs_stats_inc(&tcon->num_writes); | 1515 | cifs_stats_inc(&tcon->num_writes); |
1513 | if (rc) { | 1516 | if (rc) { |
1514 | cFYI(1, ("Send error in write = %d", rc)); | 1517 | cFYI(1, ("Send error in write = %d", rc)); |
1515 | *nbytes = 0; | ||
1516 | } else { | 1518 | } else { |
1517 | *nbytes = le16_to_cpu(pSMBr->CountHigh); | 1519 | *nbytes = le16_to_cpu(pSMBr->CountHigh); |
1518 | *nbytes = (*nbytes) << 16; | 1520 | *nbytes = (*nbytes) << 16; |
1519 | *nbytes += le16_to_cpu(pSMBr->Count); | 1521 | *nbytes += le16_to_cpu(pSMBr->Count); |
1522 | |||
1523 | /* | ||
1524 | * Mask off high 16 bits when bytes written as returned by the | ||
1525 | * server is greater than bytes requested by the client. Some | ||
1526 | * OS/2 servers are known to set incorrect CountHigh values. | ||
1527 | */ | ||
1528 | if (*nbytes > count) | ||
1529 | *nbytes &= 0xFFFF; | ||
1520 | } | 1530 | } |
1521 | 1531 | ||
1522 | cifs_buf_release(pSMB); | 1532 | cifs_buf_release(pSMB); |
@@ -1605,6 +1615,14 @@ CIFSSMBWrite2(const int xid, struct cifsTconInfo *tcon, | |||
1605 | *nbytes = le16_to_cpu(pSMBr->CountHigh); | 1615 | *nbytes = le16_to_cpu(pSMBr->CountHigh); |
1606 | *nbytes = (*nbytes) << 16; | 1616 | *nbytes = (*nbytes) << 16; |
1607 | *nbytes += le16_to_cpu(pSMBr->Count); | 1617 | *nbytes += le16_to_cpu(pSMBr->Count); |
1618 | |||
1619 | /* | ||
1620 | * Mask off high 16 bits when bytes written as returned by the | ||
1621 | * server is greater than bytes requested by the client. OS/2 | ||
1622 | * servers are known to set incorrect CountHigh values. | ||
1623 | */ | ||
1624 | if (*nbytes > count) | ||
1625 | *nbytes &= 0xFFFF; | ||
1608 | } | 1626 | } |
1609 | 1627 | ||
1610 | /* cifs_small_buf_release(pSMB); */ /* Freed earlier now in SendReceive2 */ | 1628 | /* cifs_small_buf_release(pSMB); */ /* Freed earlier now in SendReceive2 */ |
@@ -1793,8 +1811,21 @@ CIFSSMBPosixLock(const int xid, struct cifsTconInfo *tcon, | |||
1793 | } | 1811 | } |
1794 | parm_data = (struct cifs_posix_lock *) | 1812 | parm_data = (struct cifs_posix_lock *) |
1795 | ((char *)&pSMBr->hdr.Protocol + data_offset); | 1813 | ((char *)&pSMBr->hdr.Protocol + data_offset); |
1796 | if (parm_data->lock_type == cpu_to_le16(CIFS_UNLCK)) | 1814 | if (parm_data->lock_type == __constant_cpu_to_le16(CIFS_UNLCK)) |
1797 | pLockData->fl_type = F_UNLCK; | 1815 | pLockData->fl_type = F_UNLCK; |
1816 | else { | ||
1817 | if (parm_data->lock_type == | ||
1818 | __constant_cpu_to_le16(CIFS_RDLCK)) | ||
1819 | pLockData->fl_type = F_RDLCK; | ||
1820 | else if (parm_data->lock_type == | ||
1821 | __constant_cpu_to_le16(CIFS_WRLCK)) | ||
1822 | pLockData->fl_type = F_WRLCK; | ||
1823 | |||
1824 | pLockData->fl_start = parm_data->start; | ||
1825 | pLockData->fl_end = parm_data->start + | ||
1826 | parm_data->length - 1; | ||
1827 | pLockData->fl_pid = parm_data->pid; | ||
1828 | } | ||
1798 | } | 1829 | } |
1799 | 1830 | ||
1800 | plk_err_exit: | 1831 | plk_err_exit: |
@@ -3230,8 +3261,72 @@ QInfRetry: | |||
3230 | return rc; | 3261 | return rc; |
3231 | } | 3262 | } |
3232 | 3263 | ||
3264 | int | ||
3265 | CIFSSMBQFileInfo(const int xid, struct cifsTconInfo *tcon, | ||
3266 | u16 netfid, FILE_ALL_INFO *pFindData) | ||
3267 | { | ||
3268 | struct smb_t2_qfi_req *pSMB = NULL; | ||
3269 | struct smb_t2_qfi_rsp *pSMBr = NULL; | ||
3270 | int rc = 0; | ||
3271 | int bytes_returned; | ||
3272 | __u16 params, byte_count; | ||
3273 | |||
3274 | QFileInfoRetry: | ||
3275 | rc = smb_init(SMB_COM_TRANSACTION2, 15, tcon, (void **) &pSMB, | ||
3276 | (void **) &pSMBr); | ||
3277 | if (rc) | ||
3278 | return rc; | ||
3279 | |||
3280 | params = 2 /* level */ + 2 /* fid */; | ||
3281 | pSMB->t2.TotalDataCount = 0; | ||
3282 | pSMB->t2.MaxParameterCount = cpu_to_le16(4); | ||
3283 | /* BB find exact max data count below from sess structure BB */ | ||
3284 | pSMB->t2.MaxDataCount = cpu_to_le16(CIFSMaxBufSize); | ||
3285 | pSMB->t2.MaxSetupCount = 0; | ||
3286 | pSMB->t2.Reserved = 0; | ||
3287 | pSMB->t2.Flags = 0; | ||
3288 | pSMB->t2.Timeout = 0; | ||
3289 | pSMB->t2.Reserved2 = 0; | ||
3290 | pSMB->t2.ParameterOffset = cpu_to_le16(offsetof(struct smb_t2_qfi_req, | ||
3291 | Fid) - 4); | ||
3292 | pSMB->t2.DataCount = 0; | ||
3293 | pSMB->t2.DataOffset = 0; | ||
3294 | pSMB->t2.SetupCount = 1; | ||
3295 | pSMB->t2.Reserved3 = 0; | ||
3296 | pSMB->t2.SubCommand = cpu_to_le16(TRANS2_QUERY_FILE_INFORMATION); | ||
3297 | byte_count = params + 1 /* pad */ ; | ||
3298 | pSMB->t2.TotalParameterCount = cpu_to_le16(params); | ||
3299 | pSMB->t2.ParameterCount = pSMB->t2.TotalParameterCount; | ||
3300 | pSMB->InformationLevel = cpu_to_le16(SMB_QUERY_FILE_ALL_INFO); | ||
3301 | pSMB->Pad = 0; | ||
3302 | pSMB->Fid = netfid; | ||
3303 | pSMB->hdr.smb_buf_length += byte_count; | ||
3304 | |||
3305 | rc = SendReceive(xid, tcon->ses, (struct smb_hdr *) pSMB, | ||
3306 | (struct smb_hdr *) pSMBr, &bytes_returned, 0); | ||
3307 | if (rc) { | ||
3308 | cFYI(1, ("Send error in QPathInfo = %d", rc)); | ||
3309 | } else { /* decode response */ | ||
3310 | rc = validate_t2((struct smb_t2_rsp *)pSMBr); | ||
3233 | 3311 | ||
3312 | if (rc) /* BB add auto retry on EOPNOTSUPP? */ | ||
3313 | rc = -EIO; | ||
3314 | else if (pSMBr->ByteCount < 40) | ||
3315 | rc = -EIO; /* bad smb */ | ||
3316 | else if (pFindData) { | ||
3317 | __u16 data_offset = le16_to_cpu(pSMBr->t2.DataOffset); | ||
3318 | memcpy((char *) pFindData, | ||
3319 | (char *) &pSMBr->hdr.Protocol + | ||
3320 | data_offset, sizeof(FILE_ALL_INFO)); | ||
3321 | } else | ||
3322 | rc = -ENOMEM; | ||
3323 | } | ||
3324 | cifs_buf_release(pSMB); | ||
3325 | if (rc == -EAGAIN) | ||
3326 | goto QFileInfoRetry; | ||
3234 | 3327 | ||
3328 | return rc; | ||
3329 | } | ||
3235 | 3330 | ||
3236 | int | 3331 | int |
3237 | CIFSSMBQPathInfo(const int xid, struct cifsTconInfo *tcon, | 3332 | CIFSSMBQPathInfo(const int xid, struct cifsTconInfo *tcon, |
@@ -3335,6 +3430,75 @@ QPathInfoRetry: | |||
3335 | } | 3430 | } |
3336 | 3431 | ||
3337 | int | 3432 | int |
3433 | CIFSSMBUnixQFileInfo(const int xid, struct cifsTconInfo *tcon, | ||
3434 | u16 netfid, FILE_UNIX_BASIC_INFO *pFindData) | ||
3435 | { | ||
3436 | struct smb_t2_qfi_req *pSMB = NULL; | ||
3437 | struct smb_t2_qfi_rsp *pSMBr = NULL; | ||
3438 | int rc = 0; | ||
3439 | int bytes_returned; | ||
3440 | __u16 params, byte_count; | ||
3441 | |||
3442 | UnixQFileInfoRetry: | ||
3443 | rc = smb_init(SMB_COM_TRANSACTION2, 15, tcon, (void **) &pSMB, | ||
3444 | (void **) &pSMBr); | ||
3445 | if (rc) | ||
3446 | return rc; | ||
3447 | |||
3448 | params = 2 /* level */ + 2 /* fid */; | ||
3449 | pSMB->t2.TotalDataCount = 0; | ||
3450 | pSMB->t2.MaxParameterCount = cpu_to_le16(4); | ||
3451 | /* BB find exact max data count below from sess structure BB */ | ||
3452 | pSMB->t2.MaxDataCount = cpu_to_le16(CIFSMaxBufSize); | ||
3453 | pSMB->t2.MaxSetupCount = 0; | ||
3454 | pSMB->t2.Reserved = 0; | ||
3455 | pSMB->t2.Flags = 0; | ||
3456 | pSMB->t2.Timeout = 0; | ||
3457 | pSMB->t2.Reserved2 = 0; | ||
3458 | pSMB->t2.ParameterOffset = cpu_to_le16(offsetof(struct smb_t2_qfi_req, | ||
3459 | Fid) - 4); | ||
3460 | pSMB->t2.DataCount = 0; | ||
3461 | pSMB->t2.DataOffset = 0; | ||
3462 | pSMB->t2.SetupCount = 1; | ||
3463 | pSMB->t2.Reserved3 = 0; | ||
3464 | pSMB->t2.SubCommand = cpu_to_le16(TRANS2_QUERY_FILE_INFORMATION); | ||
3465 | byte_count = params + 1 /* pad */ ; | ||
3466 | pSMB->t2.TotalParameterCount = cpu_to_le16(params); | ||
3467 | pSMB->t2.ParameterCount = pSMB->t2.TotalParameterCount; | ||
3468 | pSMB->InformationLevel = cpu_to_le16(SMB_QUERY_FILE_UNIX_BASIC); | ||
3469 | pSMB->Pad = 0; | ||
3470 | pSMB->Fid = netfid; | ||
3471 | pSMB->hdr.smb_buf_length += byte_count; | ||
3472 | |||
3473 | rc = SendReceive(xid, tcon->ses, (struct smb_hdr *) pSMB, | ||
3474 | (struct smb_hdr *) pSMBr, &bytes_returned, 0); | ||
3475 | if (rc) { | ||
3476 | cFYI(1, ("Send error in QPathInfo = %d", rc)); | ||
3477 | } else { /* decode response */ | ||
3478 | rc = validate_t2((struct smb_t2_rsp *)pSMBr); | ||
3479 | |||
3480 | if (rc || (pSMBr->ByteCount < sizeof(FILE_UNIX_BASIC_INFO))) { | ||
3481 | cERROR(1, ("Malformed FILE_UNIX_BASIC_INFO response.\n" | ||
3482 | "Unix Extensions can be disabled on mount " | ||
3483 | "by specifying the nosfu mount option.")); | ||
3484 | rc = -EIO; /* bad smb */ | ||
3485 | } else { | ||
3486 | __u16 data_offset = le16_to_cpu(pSMBr->t2.DataOffset); | ||
3487 | memcpy((char *) pFindData, | ||
3488 | (char *) &pSMBr->hdr.Protocol + | ||
3489 | data_offset, | ||
3490 | sizeof(FILE_UNIX_BASIC_INFO)); | ||
3491 | } | ||
3492 | } | ||
3493 | |||
3494 | cifs_buf_release(pSMB); | ||
3495 | if (rc == -EAGAIN) | ||
3496 | goto UnixQFileInfoRetry; | ||
3497 | |||
3498 | return rc; | ||
3499 | } | ||
3500 | |||
3501 | int | ||
3338 | CIFSSMBUnixQPathInfo(const int xid, struct cifsTconInfo *tcon, | 3502 | CIFSSMBUnixQPathInfo(const int xid, struct cifsTconInfo *tcon, |
3339 | const unsigned char *searchName, | 3503 | const unsigned char *searchName, |
3340 | FILE_UNIX_BASIC_INFO *pFindData, | 3504 | FILE_UNIX_BASIC_INFO *pFindData, |
@@ -3886,7 +4050,7 @@ parse_DFS_referrals(TRANSACTION2_GET_DFS_REFER_RSP *pSMBr, | |||
3886 | goto parse_DFS_referrals_exit; | 4050 | goto parse_DFS_referrals_exit; |
3887 | } | 4051 | } |
3888 | 4052 | ||
3889 | /* collect neccessary data from referrals */ | 4053 | /* collect necessary data from referrals */ |
3890 | for (i = 0; i < *num_of_nodes; i++) { | 4054 | for (i = 0; i < *num_of_nodes; i++) { |
3891 | char *temp; | 4055 | char *temp; |
3892 | int max_len; | 4056 | int max_len; |
@@ -5269,22 +5433,34 @@ int CIFSSMBNotify(const int xid, struct cifsTconInfo *tcon, | |||
5269 | cifs_buf_release(pSMB); | 5433 | cifs_buf_release(pSMB); |
5270 | return rc; | 5434 | return rc; |
5271 | } | 5435 | } |
5436 | |||
5272 | #ifdef CONFIG_CIFS_XATTR | 5437 | #ifdef CONFIG_CIFS_XATTR |
5438 | /* | ||
5439 | * Do a path-based QUERY_ALL_EAS call and parse the result. This is a common | ||
5440 | * function used by listxattr and getxattr type calls. When ea_name is set, | ||
5441 | * it looks for that attribute name and stuffs that value into the EAData | ||
5442 | * buffer. When ea_name is NULL, it stuffs a list of attribute names into the | ||
5443 | * buffer. In both cases, the return value is either the length of the | ||
5444 | * resulting data or a negative error code. If EAData is a NULL pointer then | ||
5445 | * the data isn't copied to it, but the length is returned. | ||
5446 | */ | ||
5273 | ssize_t | 5447 | ssize_t |
5274 | CIFSSMBQAllEAs(const int xid, struct cifsTconInfo *tcon, | 5448 | CIFSSMBQAllEAs(const int xid, struct cifsTconInfo *tcon, |
5275 | const unsigned char *searchName, | 5449 | const unsigned char *searchName, const unsigned char *ea_name, |
5276 | char *EAData, size_t buf_size, | 5450 | char *EAData, size_t buf_size, |
5277 | const struct nls_table *nls_codepage, int remap) | 5451 | const struct nls_table *nls_codepage, int remap) |
5278 | { | 5452 | { |
5279 | /* BB assumes one setup word */ | 5453 | /* BB assumes one setup word */ |
5280 | TRANSACTION2_QPI_REQ *pSMB = NULL; | 5454 | TRANSACTION2_QPI_REQ *pSMB = NULL; |
5281 | TRANSACTION2_QPI_RSP *pSMBr = NULL; | 5455 | TRANSACTION2_QPI_RSP *pSMBr = NULL; |
5282 | int rc = 0; | 5456 | int rc = 0; |
5283 | int bytes_returned; | 5457 | int bytes_returned; |
5284 | int name_len; | 5458 | int list_len; |
5459 | struct fealist *ea_response_data; | ||
5285 | struct fea *temp_fea; | 5460 | struct fea *temp_fea; |
5286 | char *temp_ptr; | 5461 | char *temp_ptr; |
5287 | __u16 params, byte_count; | 5462 | char *end_of_smb; |
5463 | __u16 params, byte_count, data_offset; | ||
5288 | 5464 | ||
5289 | cFYI(1, ("In Query All EAs path %s", searchName)); | 5465 | cFYI(1, ("In Query All EAs path %s", searchName)); |
5290 | QAllEAsRetry: | 5466 | QAllEAsRetry: |
@@ -5294,22 +5470,22 @@ QAllEAsRetry: | |||
5294 | return rc; | 5470 | return rc; |
5295 | 5471 | ||
5296 | if (pSMB->hdr.Flags2 & SMBFLG2_UNICODE) { | 5472 | if (pSMB->hdr.Flags2 & SMBFLG2_UNICODE) { |
5297 | name_len = | 5473 | list_len = |
5298 | cifsConvertToUCS((__le16 *) pSMB->FileName, searchName, | 5474 | cifsConvertToUCS((__le16 *) pSMB->FileName, searchName, |
5299 | PATH_MAX, nls_codepage, remap); | 5475 | PATH_MAX, nls_codepage, remap); |
5300 | name_len++; /* trailing null */ | 5476 | list_len++; /* trailing null */ |
5301 | name_len *= 2; | 5477 | list_len *= 2; |
5302 | } else { /* BB improve the check for buffer overruns BB */ | 5478 | } else { /* BB improve the check for buffer overruns BB */ |
5303 | name_len = strnlen(searchName, PATH_MAX); | 5479 | list_len = strnlen(searchName, PATH_MAX); |
5304 | name_len++; /* trailing null */ | 5480 | list_len++; /* trailing null */ |
5305 | strncpy(pSMB->FileName, searchName, name_len); | 5481 | strncpy(pSMB->FileName, searchName, list_len); |
5306 | } | 5482 | } |
5307 | 5483 | ||
5308 | params = 2 /* level */ + 4 /* reserved */ + name_len /* includes NUL */; | 5484 | params = 2 /* level */ + 4 /* reserved */ + list_len /* includes NUL */; |
5309 | pSMB->TotalDataCount = 0; | 5485 | pSMB->TotalDataCount = 0; |
5310 | pSMB->MaxParameterCount = cpu_to_le16(2); | 5486 | pSMB->MaxParameterCount = cpu_to_le16(2); |
5311 | /* BB find exact max SMB PDU from sess structure BB */ | 5487 | /* BB find exact max SMB PDU from sess structure BB */ |
5312 | pSMB->MaxDataCount = cpu_to_le16(4000); | 5488 | pSMB->MaxDataCount = cpu_to_le16(CIFSMaxBufSize); |
5313 | pSMB->MaxSetupCount = 0; | 5489 | pSMB->MaxSetupCount = 0; |
5314 | pSMB->Reserved = 0; | 5490 | pSMB->Reserved = 0; |
5315 | pSMB->Flags = 0; | 5491 | pSMB->Flags = 0; |
@@ -5334,237 +5510,117 @@ QAllEAsRetry: | |||
5334 | (struct smb_hdr *) pSMBr, &bytes_returned, 0); | 5510 | (struct smb_hdr *) pSMBr, &bytes_returned, 0); |
5335 | if (rc) { | 5511 | if (rc) { |
5336 | cFYI(1, ("Send error in QueryAllEAs = %d", rc)); | 5512 | cFYI(1, ("Send error in QueryAllEAs = %d", rc)); |
5337 | } else { /* decode response */ | 5513 | goto QAllEAsOut; |
5338 | rc = validate_t2((struct smb_t2_rsp *)pSMBr); | 5514 | } |
5339 | 5515 | ||
5340 | /* BB also check enough total bytes returned */ | 5516 | |
5341 | /* BB we need to improve the validity checking | 5517 | /* BB also check enough total bytes returned */ |
5342 | of these trans2 responses */ | 5518 | /* BB we need to improve the validity checking |
5343 | if (rc || (pSMBr->ByteCount < 4)) | 5519 | of these trans2 responses */ |
5344 | rc = -EIO; /* bad smb */ | 5520 | |
5345 | /* else if (pFindData){ | 5521 | rc = validate_t2((struct smb_t2_rsp *)pSMBr); |
5346 | memcpy((char *) pFindData, | 5522 | if (rc || (pSMBr->ByteCount < 4)) { |
5347 | (char *) &pSMBr->hdr.Protocol + | 5523 | rc = -EIO; /* bad smb */ |
5348 | data_offset, kl); | 5524 | goto QAllEAsOut; |
5349 | }*/ else { | ||
5350 | /* check that length of list is not more than bcc */ | ||
5351 | /* check that each entry does not go beyond length | ||
5352 | of list */ | ||
5353 | /* check that each element of each entry does not | ||
5354 | go beyond end of list */ | ||
5355 | __u16 data_offset = le16_to_cpu(pSMBr->t2.DataOffset); | ||
5356 | struct fealist *ea_response_data; | ||
5357 | rc = 0; | ||
5358 | /* validate_trans2_offsets() */ | ||
5359 | /* BB check if start of smb + data_offset > &bcc+ bcc */ | ||
5360 | ea_response_data = (struct fealist *) | ||
5361 | (((char *) &pSMBr->hdr.Protocol) + | ||
5362 | data_offset); | ||
5363 | name_len = le32_to_cpu(ea_response_data->list_len); | ||
5364 | cFYI(1, ("ea length %d", name_len)); | ||
5365 | if (name_len <= 8) { | ||
5366 | /* returned EA size zeroed at top of function */ | ||
5367 | cFYI(1, ("empty EA list returned from server")); | ||
5368 | } else { | ||
5369 | /* account for ea list len */ | ||
5370 | name_len -= 4; | ||
5371 | temp_fea = ea_response_data->list; | ||
5372 | temp_ptr = (char *)temp_fea; | ||
5373 | while (name_len > 0) { | ||
5374 | __u16 value_len; | ||
5375 | name_len -= 4; | ||
5376 | temp_ptr += 4; | ||
5377 | rc += temp_fea->name_len; | ||
5378 | /* account for prefix user. and trailing null */ | ||
5379 | rc = rc + 5 + 1; | ||
5380 | if (rc < (int)buf_size) { | ||
5381 | memcpy(EAData, "user.", 5); | ||
5382 | EAData += 5; | ||
5383 | memcpy(EAData, temp_ptr, | ||
5384 | temp_fea->name_len); | ||
5385 | EAData += temp_fea->name_len; | ||
5386 | /* null terminate name */ | ||
5387 | *EAData = 0; | ||
5388 | EAData = EAData + 1; | ||
5389 | } else if (buf_size == 0) { | ||
5390 | /* skip copy - calc size only */ | ||
5391 | } else { | ||
5392 | /* stop before overrun buffer */ | ||
5393 | rc = -ERANGE; | ||
5394 | break; | ||
5395 | } | ||
5396 | name_len -= temp_fea->name_len; | ||
5397 | temp_ptr += temp_fea->name_len; | ||
5398 | /* account for trailing null */ | ||
5399 | name_len--; | ||
5400 | temp_ptr++; | ||
5401 | value_len = | ||
5402 | le16_to_cpu(temp_fea->value_len); | ||
5403 | name_len -= value_len; | ||
5404 | temp_ptr += value_len; | ||
5405 | /* BB check that temp_ptr is still | ||
5406 | within the SMB BB*/ | ||
5407 | |||
5408 | /* no trailing null to account for | ||
5409 | in value len */ | ||
5410 | /* go on to next EA */ | ||
5411 | temp_fea = (struct fea *)temp_ptr; | ||
5412 | } | ||
5413 | } | ||
5414 | } | ||
5415 | } | 5525 | } |
5416 | cifs_buf_release(pSMB); | ||
5417 | if (rc == -EAGAIN) | ||
5418 | goto QAllEAsRetry; | ||
5419 | 5526 | ||
5420 | return (ssize_t)rc; | 5527 | /* check that length of list is not more than bcc */ |
5421 | } | 5528 | /* check that each entry does not go beyond length |
5529 | of list */ | ||
5530 | /* check that each element of each entry does not | ||
5531 | go beyond end of list */ | ||
5532 | /* validate_trans2_offsets() */ | ||
5533 | /* BB check if start of smb + data_offset > &bcc+ bcc */ | ||
5422 | 5534 | ||
5423 | ssize_t CIFSSMBQueryEA(const int xid, struct cifsTconInfo *tcon, | 5535 | data_offset = le16_to_cpu(pSMBr->t2.DataOffset); |
5424 | const unsigned char *searchName, const unsigned char *ea_name, | 5536 | ea_response_data = (struct fealist *) |
5425 | unsigned char *ea_value, size_t buf_size, | 5537 | (((char *) &pSMBr->hdr.Protocol) + data_offset); |
5426 | const struct nls_table *nls_codepage, int remap) | ||
5427 | { | ||
5428 | TRANSACTION2_QPI_REQ *pSMB = NULL; | ||
5429 | TRANSACTION2_QPI_RSP *pSMBr = NULL; | ||
5430 | int rc = 0; | ||
5431 | int bytes_returned; | ||
5432 | int name_len; | ||
5433 | struct fea *temp_fea; | ||
5434 | char *temp_ptr; | ||
5435 | __u16 params, byte_count; | ||
5436 | 5538 | ||
5437 | cFYI(1, ("In Query EA path %s", searchName)); | 5539 | list_len = le32_to_cpu(ea_response_data->list_len); |
5438 | QEARetry: | 5540 | cFYI(1, ("ea length %d", list_len)); |
5439 | rc = smb_init(SMB_COM_TRANSACTION2, 15, tcon, (void **) &pSMB, | 5541 | if (list_len <= 8) { |
5440 | (void **) &pSMBr); | 5542 | cFYI(1, ("empty EA list returned from server")); |
5441 | if (rc) | 5543 | goto QAllEAsOut; |
5442 | return rc; | 5544 | } |
5443 | 5545 | ||
5444 | if (pSMB->hdr.Flags2 & SMBFLG2_UNICODE) { | 5546 | /* make sure list_len doesn't go past end of SMB */ |
5445 | name_len = | 5547 | end_of_smb = (char *)pByteArea(&pSMBr->hdr) + BCC(&pSMBr->hdr); |
5446 | cifsConvertToUCS((__le16 *) pSMB->FileName, searchName, | 5548 | if ((char *)ea_response_data + list_len > end_of_smb) { |
5447 | PATH_MAX, nls_codepage, remap); | 5549 | cFYI(1, ("EA list appears to go beyond SMB")); |
5448 | name_len++; /* trailing null */ | 5550 | rc = -EIO; |
5449 | name_len *= 2; | 5551 | goto QAllEAsOut; |
5450 | } else { /* BB improve the check for buffer overruns BB */ | ||
5451 | name_len = strnlen(searchName, PATH_MAX); | ||
5452 | name_len++; /* trailing null */ | ||
5453 | strncpy(pSMB->FileName, searchName, name_len); | ||
5454 | } | 5552 | } |
5455 | 5553 | ||
5456 | params = 2 /* level */ + 4 /* reserved */ + name_len /* includes NUL */; | 5554 | /* account for ea list len */ |
5457 | pSMB->TotalDataCount = 0; | 5555 | list_len -= 4; |
5458 | pSMB->MaxParameterCount = cpu_to_le16(2); | 5556 | temp_fea = ea_response_data->list; |
5459 | /* BB find exact max SMB PDU from sess structure BB */ | 5557 | temp_ptr = (char *)temp_fea; |
5460 | pSMB->MaxDataCount = cpu_to_le16(4000); | 5558 | while (list_len > 0) { |
5461 | pSMB->MaxSetupCount = 0; | 5559 | unsigned int name_len; |
5462 | pSMB->Reserved = 0; | 5560 | __u16 value_len; |
5463 | pSMB->Flags = 0; | 5561 | |
5464 | pSMB->Timeout = 0; | 5562 | list_len -= 4; |
5465 | pSMB->Reserved2 = 0; | 5563 | temp_ptr += 4; |
5466 | pSMB->ParameterOffset = cpu_to_le16(offsetof( | 5564 | /* make sure we can read name_len and value_len */ |
5467 | struct smb_com_transaction2_qpi_req, InformationLevel) - 4); | 5565 | if (list_len < 0) { |
5468 | pSMB->DataCount = 0; | 5566 | cFYI(1, ("EA entry goes beyond length of list")); |
5469 | pSMB->DataOffset = 0; | 5567 | rc = -EIO; |
5470 | pSMB->SetupCount = 1; | 5568 | goto QAllEAsOut; |
5471 | pSMB->Reserved3 = 0; | 5569 | } |
5472 | pSMB->SubCommand = cpu_to_le16(TRANS2_QUERY_PATH_INFORMATION); | ||
5473 | byte_count = params + 1 /* pad */ ; | ||
5474 | pSMB->TotalParameterCount = cpu_to_le16(params); | ||
5475 | pSMB->ParameterCount = pSMB->TotalParameterCount; | ||
5476 | pSMB->InformationLevel = cpu_to_le16(SMB_INFO_QUERY_ALL_EAS); | ||
5477 | pSMB->Reserved4 = 0; | ||
5478 | pSMB->hdr.smb_buf_length += byte_count; | ||
5479 | pSMB->ByteCount = cpu_to_le16(byte_count); | ||
5480 | 5570 | ||
5481 | rc = SendReceive(xid, tcon->ses, (struct smb_hdr *) pSMB, | 5571 | name_len = temp_fea->name_len; |
5482 | (struct smb_hdr *) pSMBr, &bytes_returned, 0); | 5572 | value_len = le16_to_cpu(temp_fea->value_len); |
5483 | if (rc) { | 5573 | list_len -= name_len + 1 + value_len; |
5484 | cFYI(1, ("Send error in Query EA = %d", rc)); | 5574 | if (list_len < 0) { |
5485 | } else { /* decode response */ | 5575 | cFYI(1, ("EA entry goes beyond length of list")); |
5486 | rc = validate_t2((struct smb_t2_rsp *)pSMBr); | 5576 | rc = -EIO; |
5577 | goto QAllEAsOut; | ||
5578 | } | ||
5487 | 5579 | ||
5488 | /* BB also check enough total bytes returned */ | 5580 | if (ea_name) { |
5489 | /* BB we need to improve the validity checking | 5581 | if (strncmp(ea_name, temp_ptr, name_len) == 0) { |
5490 | of these trans2 responses */ | 5582 | temp_ptr += name_len + 1; |
5491 | if (rc || (pSMBr->ByteCount < 4)) | 5583 | rc = value_len; |
5492 | rc = -EIO; /* bad smb */ | 5584 | if (buf_size == 0) |
5493 | /* else if (pFindData){ | 5585 | goto QAllEAsOut; |
5494 | memcpy((char *) pFindData, | 5586 | if ((size_t)value_len > buf_size) { |
5495 | (char *) &pSMBr->hdr.Protocol + | 5587 | rc = -ERANGE; |
5496 | data_offset, kl); | 5588 | goto QAllEAsOut; |
5497 | }*/ else { | ||
5498 | /* check that length of list is not more than bcc */ | ||
5499 | /* check that each entry does not go beyond length | ||
5500 | of list */ | ||
5501 | /* check that each element of each entry does not | ||
5502 | go beyond end of list */ | ||
5503 | __u16 data_offset = le16_to_cpu(pSMBr->t2.DataOffset); | ||
5504 | struct fealist *ea_response_data; | ||
5505 | rc = -ENODATA; | ||
5506 | /* validate_trans2_offsets() */ | ||
5507 | /* BB check if start of smb + data_offset > &bcc+ bcc*/ | ||
5508 | ea_response_data = (struct fealist *) | ||
5509 | (((char *) &pSMBr->hdr.Protocol) + | ||
5510 | data_offset); | ||
5511 | name_len = le32_to_cpu(ea_response_data->list_len); | ||
5512 | cFYI(1, ("ea length %d", name_len)); | ||
5513 | if (name_len <= 8) { | ||
5514 | /* returned EA size zeroed at top of function */ | ||
5515 | cFYI(1, ("empty EA list returned from server")); | ||
5516 | } else { | ||
5517 | /* account for ea list len */ | ||
5518 | name_len -= 4; | ||
5519 | temp_fea = ea_response_data->list; | ||
5520 | temp_ptr = (char *)temp_fea; | ||
5521 | /* loop through checking if we have a matching | ||
5522 | name and then return the associated value */ | ||
5523 | while (name_len > 0) { | ||
5524 | __u16 value_len; | ||
5525 | name_len -= 4; | ||
5526 | temp_ptr += 4; | ||
5527 | value_len = | ||
5528 | le16_to_cpu(temp_fea->value_len); | ||
5529 | /* BB validate that value_len falls within SMB, | ||
5530 | even though maximum for name_len is 255 */ | ||
5531 | if (memcmp(temp_fea->name, ea_name, | ||
5532 | temp_fea->name_len) == 0) { | ||
5533 | /* found a match */ | ||
5534 | rc = value_len; | ||
5535 | /* account for prefix user. and trailing null */ | ||
5536 | if (rc <= (int)buf_size) { | ||
5537 | memcpy(ea_value, | ||
5538 | temp_fea->name+temp_fea->name_len+1, | ||
5539 | rc); | ||
5540 | /* ea values, unlike ea | ||
5541 | names, are not null | ||
5542 | terminated */ | ||
5543 | } else if (buf_size == 0) { | ||
5544 | /* skip copy - calc size only */ | ||
5545 | } else { | ||
5546 | /* stop before overrun buffer */ | ||
5547 | rc = -ERANGE; | ||
5548 | } | ||
5549 | break; | ||
5550 | } | ||
5551 | name_len -= temp_fea->name_len; | ||
5552 | temp_ptr += temp_fea->name_len; | ||
5553 | /* account for trailing null */ | ||
5554 | name_len--; | ||
5555 | temp_ptr++; | ||
5556 | name_len -= value_len; | ||
5557 | temp_ptr += value_len; | ||
5558 | /* No trailing null to account for in | ||
5559 | value_len. Go on to next EA */ | ||
5560 | temp_fea = (struct fea *)temp_ptr; | ||
5561 | } | 5589 | } |
5590 | memcpy(EAData, temp_ptr, value_len); | ||
5591 | goto QAllEAsOut; | ||
5592 | } | ||
5593 | } else { | ||
5594 | /* account for prefix user. and trailing null */ | ||
5595 | rc += (5 + 1 + name_len); | ||
5596 | if (rc < (int) buf_size) { | ||
5597 | memcpy(EAData, "user.", 5); | ||
5598 | EAData += 5; | ||
5599 | memcpy(EAData, temp_ptr, name_len); | ||
5600 | EAData += name_len; | ||
5601 | /* null terminate name */ | ||
5602 | *EAData = 0; | ||
5603 | ++EAData; | ||
5604 | } else if (buf_size == 0) { | ||
5605 | /* skip copy - calc size only */ | ||
5606 | } else { | ||
5607 | /* stop before overrun buffer */ | ||
5608 | rc = -ERANGE; | ||
5609 | break; | ||
5562 | } | 5610 | } |
5563 | } | 5611 | } |
5612 | temp_ptr += name_len + 1 + value_len; | ||
5613 | temp_fea = (struct fea *)temp_ptr; | ||
5564 | } | 5614 | } |
5615 | |||
5616 | /* didn't find the named attribute */ | ||
5617 | if (ea_name) | ||
5618 | rc = -ENODATA; | ||
5619 | |||
5620 | QAllEAsOut: | ||
5565 | cifs_buf_release(pSMB); | 5621 | cifs_buf_release(pSMB); |
5566 | if (rc == -EAGAIN) | 5622 | if (rc == -EAGAIN) |
5567 | goto QEARetry; | 5623 | goto QAllEAsRetry; |
5568 | 5624 | ||
5569 | return (ssize_t)rc; | 5625 | return (ssize_t)rc; |
5570 | } | 5626 | } |
diff --git a/fs/cifs/connect.c b/fs/cifs/connect.c index 63ea83ff687f..d9566bf8f917 100644 --- a/fs/cifs/connect.c +++ b/fs/cifs/connect.c | |||
@@ -23,6 +23,7 @@ | |||
23 | #include <linux/string.h> | 23 | #include <linux/string.h> |
24 | #include <linux/list.h> | 24 | #include <linux/list.h> |
25 | #include <linux/wait.h> | 25 | #include <linux/wait.h> |
26 | #include <linux/slab.h> | ||
26 | #include <linux/pagemap.h> | 27 | #include <linux/pagemap.h> |
27 | #include <linux/ctype.h> | 28 | #include <linux/ctype.h> |
28 | #include <linux/utsname.h> | 29 | #include <linux/utsname.h> |
@@ -98,7 +99,7 @@ struct smb_vol { | |||
98 | bool nostrictsync:1; /* do not force expensive SMBflush on every sync */ | 99 | bool nostrictsync:1; /* do not force expensive SMBflush on every sync */ |
99 | unsigned int rsize; | 100 | unsigned int rsize; |
100 | unsigned int wsize; | 101 | unsigned int wsize; |
101 | unsigned int sockopt; | 102 | bool sockopt_tcp_nodelay:1; |
102 | unsigned short int port; | 103 | unsigned short int port; |
103 | char *prepath; | 104 | char *prepath; |
104 | }; | 105 | }; |
@@ -1142,9 +1143,11 @@ cifs_parse_mount_options(char *options, const char *devname, | |||
1142 | simple_strtoul(value, &value, 0); | 1143 | simple_strtoul(value, &value, 0); |
1143 | } | 1144 | } |
1144 | } else if (strnicmp(data, "sockopt", 5) == 0) { | 1145 | } else if (strnicmp(data, "sockopt", 5) == 0) { |
1145 | if (value && *value) { | 1146 | if (!value || !*value) { |
1146 | vol->sockopt = | 1147 | cERROR(1, ("no socket option specified")); |
1147 | simple_strtoul(value, &value, 0); | 1148 | continue; |
1149 | } else if (strnicmp(value, "TCP_NODELAY", 11) == 0) { | ||
1150 | vol->sockopt_tcp_nodelay = 1; | ||
1148 | } | 1151 | } |
1149 | } else if (strnicmp(data, "netbiosname", 4) == 0) { | 1152 | } else if (strnicmp(data, "netbiosname", 4) == 0) { |
1150 | if (!value || !*value || (*value == ' ')) { | 1153 | if (!value || !*value || (*value == ' ')) { |
@@ -1514,6 +1517,7 @@ cifs_get_tcp_session(struct smb_vol *volume_info) | |||
1514 | 1517 | ||
1515 | tcp_ses->noblocksnd = volume_info->noblocksnd; | 1518 | tcp_ses->noblocksnd = volume_info->noblocksnd; |
1516 | tcp_ses->noautotune = volume_info->noautotune; | 1519 | tcp_ses->noautotune = volume_info->noautotune; |
1520 | tcp_ses->tcp_nodelay = volume_info->sockopt_tcp_nodelay; | ||
1517 | atomic_set(&tcp_ses->inFlight, 0); | 1521 | atomic_set(&tcp_ses->inFlight, 0); |
1518 | init_waitqueue_head(&tcp_ses->response_q); | 1522 | init_waitqueue_head(&tcp_ses->response_q); |
1519 | init_waitqueue_head(&tcp_ses->request_q); | 1523 | init_waitqueue_head(&tcp_ses->request_q); |
@@ -1764,6 +1768,7 @@ static int | |||
1764 | ipv4_connect(struct TCP_Server_Info *server) | 1768 | ipv4_connect(struct TCP_Server_Info *server) |
1765 | { | 1769 | { |
1766 | int rc = 0; | 1770 | int rc = 0; |
1771 | int val; | ||
1767 | bool connected = false; | 1772 | bool connected = false; |
1768 | __be16 orig_port = 0; | 1773 | __be16 orig_port = 0; |
1769 | struct socket *socket = server->ssocket; | 1774 | struct socket *socket = server->ssocket; |
@@ -1845,6 +1850,14 @@ ipv4_connect(struct TCP_Server_Info *server) | |||
1845 | socket->sk->sk_rcvbuf = 140 * 1024; | 1850 | socket->sk->sk_rcvbuf = 140 * 1024; |
1846 | } | 1851 | } |
1847 | 1852 | ||
1853 | if (server->tcp_nodelay) { | ||
1854 | val = 1; | ||
1855 | rc = kernel_setsockopt(socket, SOL_TCP, TCP_NODELAY, | ||
1856 | (char *)&val, sizeof(val)); | ||
1857 | if (rc) | ||
1858 | cFYI(1, ("set TCP_NODELAY socket option error %d", rc)); | ||
1859 | } | ||
1860 | |||
1848 | cFYI(1, ("sndbuf %d rcvbuf %d rcvtimeo 0x%lx", | 1861 | cFYI(1, ("sndbuf %d rcvbuf %d rcvtimeo 0x%lx", |
1849 | socket->sk->sk_sndbuf, | 1862 | socket->sk->sk_sndbuf, |
1850 | socket->sk->sk_rcvbuf, socket->sk->sk_rcvtimeo)); | 1863 | socket->sk->sk_rcvbuf, socket->sk->sk_rcvtimeo)); |
@@ -1916,6 +1929,7 @@ static int | |||
1916 | ipv6_connect(struct TCP_Server_Info *server) | 1929 | ipv6_connect(struct TCP_Server_Info *server) |
1917 | { | 1930 | { |
1918 | int rc = 0; | 1931 | int rc = 0; |
1932 | int val; | ||
1919 | bool connected = false; | 1933 | bool connected = false; |
1920 | __be16 orig_port = 0; | 1934 | __be16 orig_port = 0; |
1921 | struct socket *socket = server->ssocket; | 1935 | struct socket *socket = server->ssocket; |
@@ -1987,6 +2001,15 @@ ipv6_connect(struct TCP_Server_Info *server) | |||
1987 | */ | 2001 | */ |
1988 | socket->sk->sk_rcvtimeo = 7 * HZ; | 2002 | socket->sk->sk_rcvtimeo = 7 * HZ; |
1989 | socket->sk->sk_sndtimeo = 5 * HZ; | 2003 | socket->sk->sk_sndtimeo = 5 * HZ; |
2004 | |||
2005 | if (server->tcp_nodelay) { | ||
2006 | val = 1; | ||
2007 | rc = kernel_setsockopt(socket, SOL_TCP, TCP_NODELAY, | ||
2008 | (char *)&val, sizeof(val)); | ||
2009 | if (rc) | ||
2010 | cFYI(1, ("set TCP_NODELAY socket option error %d", rc)); | ||
2011 | } | ||
2012 | |||
1990 | server->ssocket = socket; | 2013 | server->ssocket = socket; |
1991 | 2014 | ||
1992 | return rc; | 2015 | return rc; |
@@ -2287,12 +2310,12 @@ int | |||
2287 | cifs_mount(struct super_block *sb, struct cifs_sb_info *cifs_sb, | 2310 | cifs_mount(struct super_block *sb, struct cifs_sb_info *cifs_sb, |
2288 | char *mount_data_global, const char *devname) | 2311 | char *mount_data_global, const char *devname) |
2289 | { | 2312 | { |
2290 | int rc = 0; | 2313 | int rc; |
2291 | int xid; | 2314 | int xid; |
2292 | struct smb_vol *volume_info; | 2315 | struct smb_vol *volume_info; |
2293 | struct cifsSesInfo *pSesInfo = NULL; | 2316 | struct cifsSesInfo *pSesInfo; |
2294 | struct cifsTconInfo *tcon = NULL; | 2317 | struct cifsTconInfo *tcon; |
2295 | struct TCP_Server_Info *srvTcp = NULL; | 2318 | struct TCP_Server_Info *srvTcp; |
2296 | char *full_path; | 2319 | char *full_path; |
2297 | char *mount_data = mount_data_global; | 2320 | char *mount_data = mount_data_global; |
2298 | #ifdef CONFIG_CIFS_DFS_UPCALL | 2321 | #ifdef CONFIG_CIFS_DFS_UPCALL |
@@ -2301,6 +2324,10 @@ cifs_mount(struct super_block *sb, struct cifs_sb_info *cifs_sb, | |||
2301 | int referral_walks_count = 0; | 2324 | int referral_walks_count = 0; |
2302 | try_mount_again: | 2325 | try_mount_again: |
2303 | #endif | 2326 | #endif |
2327 | rc = 0; | ||
2328 | tcon = NULL; | ||
2329 | pSesInfo = NULL; | ||
2330 | srvTcp = NULL; | ||
2304 | full_path = NULL; | 2331 | full_path = NULL; |
2305 | 2332 | ||
2306 | xid = GetXid(); | 2333 | xid = GetXid(); |
@@ -2362,13 +2389,13 @@ try_mount_again: | |||
2362 | */ | 2389 | */ |
2363 | cifs_put_tcp_session(srvTcp); | 2390 | cifs_put_tcp_session(srvTcp); |
2364 | 2391 | ||
2365 | down(&pSesInfo->sesSem); | 2392 | mutex_lock(&pSesInfo->session_mutex); |
2366 | if (pSesInfo->need_reconnect) { | 2393 | if (pSesInfo->need_reconnect) { |
2367 | cFYI(1, ("Session needs reconnect")); | 2394 | cFYI(1, ("Session needs reconnect")); |
2368 | rc = cifs_setup_session(xid, pSesInfo, | 2395 | rc = cifs_setup_session(xid, pSesInfo, |
2369 | cifs_sb->local_nls); | 2396 | cifs_sb->local_nls); |
2370 | } | 2397 | } |
2371 | up(&pSesInfo->sesSem); | 2398 | mutex_unlock(&pSesInfo->session_mutex); |
2372 | } else if (!rc) { | 2399 | } else if (!rc) { |
2373 | cFYI(1, ("Existing smb sess not found")); | 2400 | cFYI(1, ("Existing smb sess not found")); |
2374 | pSesInfo = sesInfoAlloc(); | 2401 | pSesInfo = sesInfoAlloc(); |
@@ -2411,12 +2438,12 @@ try_mount_again: | |||
2411 | } | 2438 | } |
2412 | pSesInfo->linux_uid = volume_info->linux_uid; | 2439 | pSesInfo->linux_uid = volume_info->linux_uid; |
2413 | pSesInfo->overrideSecFlg = volume_info->secFlg; | 2440 | pSesInfo->overrideSecFlg = volume_info->secFlg; |
2414 | down(&pSesInfo->sesSem); | 2441 | mutex_lock(&pSesInfo->session_mutex); |
2415 | 2442 | ||
2416 | /* BB FIXME need to pass vol->secFlgs BB */ | 2443 | /* BB FIXME need to pass vol->secFlgs BB */ |
2417 | rc = cifs_setup_session(xid, pSesInfo, | 2444 | rc = cifs_setup_session(xid, pSesInfo, |
2418 | cifs_sb->local_nls); | 2445 | cifs_sb->local_nls); |
2419 | up(&pSesInfo->sesSem); | 2446 | mutex_unlock(&pSesInfo->session_mutex); |
2420 | } | 2447 | } |
2421 | 2448 | ||
2422 | /* search for existing tcon to this server share */ | 2449 | /* search for existing tcon to this server share */ |
@@ -2597,6 +2624,7 @@ remote_path_check: | |||
2597 | 2624 | ||
2598 | cleanup_volume_info(&volume_info); | 2625 | cleanup_volume_info(&volume_info); |
2599 | referral_walks_count++; | 2626 | referral_walks_count++; |
2627 | FreeXid(xid); | ||
2600 | goto try_mount_again; | 2628 | goto try_mount_again; |
2601 | } | 2629 | } |
2602 | #else /* No DFS support, return error on mount */ | 2630 | #else /* No DFS support, return error on mount */ |
diff --git a/fs/cifs/dir.c b/fs/cifs/dir.c index 1f42f772865a..e9f7ecc2714b 100644 --- a/fs/cifs/dir.c +++ b/fs/cifs/dir.c | |||
@@ -214,7 +214,8 @@ int cifs_posix_open(char *full_path, struct inode **pinode, | |||
214 | posix_flags |= SMB_O_EXCL; | 214 | posix_flags |= SMB_O_EXCL; |
215 | if (oflags & O_TRUNC) | 215 | if (oflags & O_TRUNC) |
216 | posix_flags |= SMB_O_TRUNC; | 216 | posix_flags |= SMB_O_TRUNC; |
217 | if (oflags & O_SYNC) | 217 | /* be safe and imply O_SYNC for O_DSYNC */ |
218 | if (oflags & O_DSYNC) | ||
218 | posix_flags |= SMB_O_SYNC; | 219 | posix_flags |= SMB_O_SYNC; |
219 | if (oflags & O_DIRECTORY) | 220 | if (oflags & O_DIRECTORY) |
220 | posix_flags |= SMB_O_DIRECTORY; | 221 | posix_flags |= SMB_O_DIRECTORY; |
@@ -738,7 +739,7 @@ cifs_d_revalidate(struct dentry *direntry, struct nameidata *nd) | |||
738 | int isValid = 1; | 739 | int isValid = 1; |
739 | 740 | ||
740 | if (direntry->d_inode) { | 741 | if (direntry->d_inode) { |
741 | if (cifs_revalidate(direntry)) | 742 | if (cifs_revalidate_dentry(direntry)) |
742 | return 0; | 743 | return 0; |
743 | } else { | 744 | } else { |
744 | cFYI(1, ("neg dentry 0x%p name = %s", | 745 | cFYI(1, ("neg dentry 0x%p name = %s", |
diff --git a/fs/cifs/dns_resolve.c b/fs/cifs/dns_resolve.c index 87948147d7ec..6f8a0e3fb25b 100644 --- a/fs/cifs/dns_resolve.c +++ b/fs/cifs/dns_resolve.c | |||
@@ -23,6 +23,7 @@ | |||
23 | * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA | 23 | * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA |
24 | */ | 24 | */ |
25 | 25 | ||
26 | #include <linux/slab.h> | ||
26 | #include <keys/user-type.h> | 27 | #include <keys/user-type.h> |
27 | #include "dns_resolve.h" | 28 | #include "dns_resolve.h" |
28 | #include "cifsglob.h" | 29 | #include "cifsglob.h" |
diff --git a/fs/cifs/export.c b/fs/cifs/export.c index 75949d6a5f1b..6177f7cca16a 100644 --- a/fs/cifs/export.c +++ b/fs/cifs/export.c | |||
@@ -24,7 +24,7 @@ | |||
24 | */ | 24 | */ |
25 | 25 | ||
26 | /* | 26 | /* |
27 | * See Documentation/filesystems/Exporting | 27 | * See Documentation/filesystems/nfs/Exporting |
28 | * and examples in fs/exportfs | 28 | * and examples in fs/exportfs |
29 | * | 29 | * |
30 | * Since cifs is a network file system, an "fsid" must be included for | 30 | * Since cifs is a network file system, an "fsid" must be included for |
diff --git a/fs/cifs/file.c b/fs/cifs/file.c index 429337eb7afe..9b11a8f56f3a 100644 --- a/fs/cifs/file.c +++ b/fs/cifs/file.c | |||
@@ -31,6 +31,7 @@ | |||
31 | #include <linux/task_io_accounting_ops.h> | 31 | #include <linux/task_io_accounting_ops.h> |
32 | #include <linux/delay.h> | 32 | #include <linux/delay.h> |
33 | #include <linux/mount.h> | 33 | #include <linux/mount.h> |
34 | #include <linux/slab.h> | ||
34 | #include <asm/div64.h> | 35 | #include <asm/div64.h> |
35 | #include "cifsfs.h" | 36 | #include "cifsfs.h" |
36 | #include "cifspdu.h" | 37 | #include "cifspdu.h" |
@@ -76,8 +77,10 @@ static inline fmode_t cifs_posix_convert_flags(unsigned int flags) | |||
76 | reopening a file. They had their effect on the original open */ | 77 | reopening a file. They had their effect on the original open */ |
77 | if (flags & O_APPEND) | 78 | if (flags & O_APPEND) |
78 | posix_flags |= (fmode_t)O_APPEND; | 79 | posix_flags |= (fmode_t)O_APPEND; |
79 | if (flags & O_SYNC) | 80 | if (flags & O_DSYNC) |
80 | posix_flags |= (fmode_t)O_SYNC; | 81 | posix_flags |= (fmode_t)O_DSYNC; |
82 | if (flags & __O_SYNC) | ||
83 | posix_flags |= (fmode_t)__O_SYNC; | ||
81 | if (flags & O_DIRECTORY) | 84 | if (flags & O_DIRECTORY) |
82 | posix_flags |= (fmode_t)O_DIRECTORY; | 85 | posix_flags |= (fmode_t)O_DIRECTORY; |
83 | if (flags & O_NOFOLLOW) | 86 | if (flags & O_NOFOLLOW) |
@@ -217,8 +220,8 @@ static inline int cifs_open_inode_helper(struct inode *inode, struct file *file, | |||
217 | cFYI(1, ("inode unchanged on server")); | 220 | cFYI(1, ("inode unchanged on server")); |
218 | } else { | 221 | } else { |
219 | if (file->f_path.dentry->d_inode->i_mapping) { | 222 | if (file->f_path.dentry->d_inode->i_mapping) { |
220 | /* BB no need to lock inode until after invalidate | 223 | /* BB no need to lock inode until after invalidate |
221 | since namei code should already have it locked? */ | 224 | since namei code should already have it locked? */ |
222 | rc = filemap_write_and_wait(file->f_path.dentry->d_inode->i_mapping); | 225 | rc = filemap_write_and_wait(file->f_path.dentry->d_inode->i_mapping); |
223 | if (rc != 0) | 226 | if (rc != 0) |
224 | CIFS_I(file->f_path.dentry->d_inode)->write_behind_rc = rc; | 227 | CIFS_I(file->f_path.dentry->d_inode)->write_behind_rc = rc; |
@@ -836,8 +839,32 @@ int cifs_lock(struct file *file, int cmd, struct file_lock *pfLock) | |||
836 | 839 | ||
837 | } else { | 840 | } else { |
838 | /* if rc == ERR_SHARING_VIOLATION ? */ | 841 | /* if rc == ERR_SHARING_VIOLATION ? */ |
839 | rc = 0; /* do not change lock type to unlock | 842 | rc = 0; |
840 | since range in use */ | 843 | |
844 | if (lockType & LOCKING_ANDX_SHARED_LOCK) { | ||
845 | pfLock->fl_type = F_WRLCK; | ||
846 | } else { | ||
847 | rc = CIFSSMBLock(xid, tcon, netfid, length, | ||
848 | pfLock->fl_start, 0, 1, | ||
849 | lockType | LOCKING_ANDX_SHARED_LOCK, | ||
850 | 0 /* wait flag */); | ||
851 | if (rc == 0) { | ||
852 | rc = CIFSSMBLock(xid, tcon, netfid, | ||
853 | length, pfLock->fl_start, 1, 0, | ||
854 | lockType | | ||
855 | LOCKING_ANDX_SHARED_LOCK, | ||
856 | 0 /* wait flag */); | ||
857 | pfLock->fl_type = F_RDLCK; | ||
858 | if (rc != 0) | ||
859 | cERROR(1, ("Error unlocking " | ||
860 | "previously locked range %d " | ||
861 | "during test of lock", rc)); | ||
862 | rc = 0; | ||
863 | } else { | ||
864 | pfLock->fl_type = F_WRLCK; | ||
865 | rc = 0; | ||
866 | } | ||
867 | } | ||
841 | } | 868 | } |
842 | 869 | ||
843 | FreeXid(xid); | 870 | FreeXid(xid); |
@@ -1888,11 +1915,10 @@ static ssize_t cifs_read(struct file *file, char *read_data, size_t read_size, | |||
1888 | 1915 | ||
1889 | int cifs_file_mmap(struct file *file, struct vm_area_struct *vma) | 1916 | int cifs_file_mmap(struct file *file, struct vm_area_struct *vma) |
1890 | { | 1917 | { |
1891 | struct dentry *dentry = file->f_path.dentry; | ||
1892 | int rc, xid; | 1918 | int rc, xid; |
1893 | 1919 | ||
1894 | xid = GetXid(); | 1920 | xid = GetXid(); |
1895 | rc = cifs_revalidate(dentry); | 1921 | rc = cifs_revalidate_file(file); |
1896 | if (rc) { | 1922 | if (rc) { |
1897 | cFYI(1, ("Validation prior to mmap failed, error=%d", rc)); | 1923 | cFYI(1, ("Validation prior to mmap failed, error=%d", rc)); |
1898 | FreeXid(xid); | 1924 | FreeXid(xid); |
@@ -2287,9 +2313,9 @@ cifs_oplock_break(struct slow_work *work) | |||
2287 | if (inode && S_ISREG(inode->i_mode)) { | 2313 | if (inode && S_ISREG(inode->i_mode)) { |
2288 | #ifdef CONFIG_CIFS_EXPERIMENTAL | 2314 | #ifdef CONFIG_CIFS_EXPERIMENTAL |
2289 | if (cinode->clientCanCacheAll == 0) | 2315 | if (cinode->clientCanCacheAll == 0) |
2290 | break_lease(inode, FMODE_READ); | 2316 | break_lease(inode, O_RDONLY); |
2291 | else if (cinode->clientCanCacheRead == 0) | 2317 | else if (cinode->clientCanCacheRead == 0) |
2292 | break_lease(inode, FMODE_WRITE); | 2318 | break_lease(inode, O_WRONLY); |
2293 | #endif | 2319 | #endif |
2294 | rc = filemap_fdatawrite(inode->i_mapping); | 2320 | rc = filemap_fdatawrite(inode->i_mapping); |
2295 | if (cinode->clientCanCacheRead == 0) { | 2321 | if (cinode->clientCanCacheRead == 0) { |
diff --git a/fs/cifs/inode.c b/fs/cifs/inode.c index cababd8a52df..29b9ea244c81 100644 --- a/fs/cifs/inode.c +++ b/fs/cifs/inode.c | |||
@@ -20,6 +20,7 @@ | |||
20 | */ | 20 | */ |
21 | #include <linux/fs.h> | 21 | #include <linux/fs.h> |
22 | #include <linux/stat.h> | 22 | #include <linux/stat.h> |
23 | #include <linux/slab.h> | ||
23 | #include <linux/pagemap.h> | 24 | #include <linux/pagemap.h> |
24 | #include <asm/div64.h> | 25 | #include <asm/div64.h> |
25 | #include "cifsfs.h" | 26 | #include "cifsfs.h" |
@@ -77,6 +78,41 @@ static void cifs_set_ops(struct inode *inode, const bool is_dfs_referral) | |||
77 | } | 78 | } |
78 | } | 79 | } |
79 | 80 | ||
81 | /* check inode attributes against fattr. If they don't match, tag the | ||
82 | * inode for cache invalidation | ||
83 | */ | ||
84 | static void | ||
85 | cifs_revalidate_cache(struct inode *inode, struct cifs_fattr *fattr) | ||
86 | { | ||
87 | struct cifsInodeInfo *cifs_i = CIFS_I(inode); | ||
88 | |||
89 | cFYI(1, ("%s: revalidating inode %llu", __func__, cifs_i->uniqueid)); | ||
90 | |||
91 | if (inode->i_state & I_NEW) { | ||
92 | cFYI(1, ("%s: inode %llu is new", __func__, cifs_i->uniqueid)); | ||
93 | return; | ||
94 | } | ||
95 | |||
96 | /* don't bother with revalidation if we have an oplock */ | ||
97 | if (cifs_i->clientCanCacheRead) { | ||
98 | cFYI(1, ("%s: inode %llu is oplocked", __func__, | ||
99 | cifs_i->uniqueid)); | ||
100 | return; | ||
101 | } | ||
102 | |||
103 | /* revalidate if mtime or size have changed */ | ||
104 | if (timespec_equal(&inode->i_mtime, &fattr->cf_mtime) && | ||
105 | cifs_i->server_eof == fattr->cf_eof) { | ||
106 | cFYI(1, ("%s: inode %llu is unchanged", __func__, | ||
107 | cifs_i->uniqueid)); | ||
108 | return; | ||
109 | } | ||
110 | |||
111 | cFYI(1, ("%s: invalidating inode %llu mapping", __func__, | ||
112 | cifs_i->uniqueid)); | ||
113 | cifs_i->invalid_mapping = true; | ||
114 | } | ||
115 | |||
80 | /* populate an inode with info from a cifs_fattr struct */ | 116 | /* populate an inode with info from a cifs_fattr struct */ |
81 | void | 117 | void |
82 | cifs_fattr_to_inode(struct inode *inode, struct cifs_fattr *fattr) | 118 | cifs_fattr_to_inode(struct inode *inode, struct cifs_fattr *fattr) |
@@ -85,6 +121,8 @@ cifs_fattr_to_inode(struct inode *inode, struct cifs_fattr *fattr) | |||
85 | struct cifs_sb_info *cifs_sb = CIFS_SB(inode->i_sb); | 121 | struct cifs_sb_info *cifs_sb = CIFS_SB(inode->i_sb); |
86 | unsigned long oldtime = cifs_i->time; | 122 | unsigned long oldtime = cifs_i->time; |
87 | 123 | ||
124 | cifs_revalidate_cache(inode, fattr); | ||
125 | |||
88 | inode->i_atime = fattr->cf_atime; | 126 | inode->i_atime = fattr->cf_atime; |
89 | inode->i_mtime = fattr->cf_mtime; | 127 | inode->i_mtime = fattr->cf_mtime; |
90 | inode->i_ctime = fattr->cf_ctime; | 128 | inode->i_ctime = fattr->cf_ctime; |
@@ -111,6 +149,7 @@ cifs_fattr_to_inode(struct inode *inode, struct cifs_fattr *fattr) | |||
111 | 149 | ||
112 | cifs_i->delete_pending = fattr->cf_flags & CIFS_FATTR_DELETE_PENDING; | 150 | cifs_i->delete_pending = fattr->cf_flags & CIFS_FATTR_DELETE_PENDING; |
113 | 151 | ||
152 | cifs_i->server_eof = fattr->cf_eof; | ||
114 | /* | 153 | /* |
115 | * Can't safely change the file size here if the client is writing to | 154 | * Can't safely change the file size here if the client is writing to |
116 | * it due to potential races. | 155 | * it due to potential races. |
@@ -230,6 +269,31 @@ cifs_create_dfs_fattr(struct cifs_fattr *fattr, struct super_block *sb) | |||
230 | fattr->cf_flags |= CIFS_FATTR_DFS_REFERRAL; | 269 | fattr->cf_flags |= CIFS_FATTR_DFS_REFERRAL; |
231 | } | 270 | } |
232 | 271 | ||
272 | int cifs_get_file_info_unix(struct file *filp) | ||
273 | { | ||
274 | int rc; | ||
275 | int xid; | ||
276 | FILE_UNIX_BASIC_INFO find_data; | ||
277 | struct cifs_fattr fattr; | ||
278 | struct inode *inode = filp->f_path.dentry->d_inode; | ||
279 | struct cifs_sb_info *cifs_sb = CIFS_SB(inode->i_sb); | ||
280 | struct cifsTconInfo *tcon = cifs_sb->tcon; | ||
281 | struct cifsFileInfo *cfile = (struct cifsFileInfo *) filp->private_data; | ||
282 | |||
283 | xid = GetXid(); | ||
284 | rc = CIFSSMBUnixQFileInfo(xid, tcon, cfile->netfid, &find_data); | ||
285 | if (!rc) { | ||
286 | cifs_unix_basic_to_fattr(&fattr, &find_data, cifs_sb); | ||
287 | } else if (rc == -EREMOTE) { | ||
288 | cifs_create_dfs_fattr(&fattr, inode->i_sb); | ||
289 | rc = 0; | ||
290 | } | ||
291 | |||
292 | cifs_fattr_to_inode(inode, &fattr); | ||
293 | FreeXid(xid); | ||
294 | return rc; | ||
295 | } | ||
296 | |||
233 | int cifs_get_inode_info_unix(struct inode **pinode, | 297 | int cifs_get_inode_info_unix(struct inode **pinode, |
234 | const unsigned char *full_path, | 298 | const unsigned char *full_path, |
235 | struct super_block *sb, int xid) | 299 | struct super_block *sb, int xid) |
@@ -366,7 +430,7 @@ static int cifs_sfu_mode(struct cifs_fattr *fattr, const unsigned char *path, | |||
366 | char ea_value[4]; | 430 | char ea_value[4]; |
367 | __u32 mode; | 431 | __u32 mode; |
368 | 432 | ||
369 | rc = CIFSSMBQueryEA(xid, cifs_sb->tcon, path, "SETFILEBITS", | 433 | rc = CIFSSMBQAllEAs(xid, cifs_sb->tcon, path, "SETFILEBITS", |
370 | ea_value, 4 /* size of buf */, cifs_sb->local_nls, | 434 | ea_value, 4 /* size of buf */, cifs_sb->local_nls, |
371 | cifs_sb->mnt_cifs_flags & | 435 | cifs_sb->mnt_cifs_flags & |
372 | CIFS_MOUNT_MAP_SPECIAL_CHR); | 436 | CIFS_MOUNT_MAP_SPECIAL_CHR); |
@@ -431,6 +495,47 @@ cifs_all_info_to_fattr(struct cifs_fattr *fattr, FILE_ALL_INFO *info, | |||
431 | fattr->cf_gid = cifs_sb->mnt_gid; | 495 | fattr->cf_gid = cifs_sb->mnt_gid; |
432 | } | 496 | } |
433 | 497 | ||
498 | int cifs_get_file_info(struct file *filp) | ||
499 | { | ||
500 | int rc; | ||
501 | int xid; | ||
502 | FILE_ALL_INFO find_data; | ||
503 | struct cifs_fattr fattr; | ||
504 | struct inode *inode = filp->f_path.dentry->d_inode; | ||
505 | struct cifs_sb_info *cifs_sb = CIFS_SB(inode->i_sb); | ||
506 | struct cifsTconInfo *tcon = cifs_sb->tcon; | ||
507 | struct cifsFileInfo *cfile = (struct cifsFileInfo *) filp->private_data; | ||
508 | |||
509 | xid = GetXid(); | ||
510 | rc = CIFSSMBQFileInfo(xid, tcon, cfile->netfid, &find_data); | ||
511 | if (rc == -EOPNOTSUPP || rc == -EINVAL) { | ||
512 | /* | ||
513 | * FIXME: legacy server -- fall back to path-based call? | ||
514 | * for now, just skip revalidating and mark inode for | ||
515 | * immediate reval. | ||
516 | */ | ||
517 | rc = 0; | ||
518 | CIFS_I(inode)->time = 0; | ||
519 | goto cgfi_exit; | ||
520 | } else if (rc == -EREMOTE) { | ||
521 | cifs_create_dfs_fattr(&fattr, inode->i_sb); | ||
522 | rc = 0; | ||
523 | } else if (rc) | ||
524 | goto cgfi_exit; | ||
525 | |||
526 | /* | ||
527 | * don't bother with SFU junk here -- just mark inode as needing | ||
528 | * revalidation. | ||
529 | */ | ||
530 | cifs_all_info_to_fattr(&fattr, &find_data, cifs_sb, false); | ||
531 | fattr.cf_uniqueid = CIFS_I(inode)->uniqueid; | ||
532 | fattr.cf_flags |= CIFS_FATTR_NEED_REVAL; | ||
533 | cifs_fattr_to_inode(inode, &fattr); | ||
534 | cgfi_exit: | ||
535 | FreeXid(xid); | ||
536 | return rc; | ||
537 | } | ||
538 | |||
434 | int cifs_get_inode_info(struct inode **pinode, | 539 | int cifs_get_inode_info(struct inode **pinode, |
435 | const unsigned char *full_path, FILE_ALL_INFO *pfindData, | 540 | const unsigned char *full_path, FILE_ALL_INFO *pfindData, |
436 | struct super_block *sb, int xid, const __u16 *pfid) | 541 | struct super_block *sb, int xid, const __u16 *pfid) |
@@ -610,6 +715,16 @@ cifs_find_inode(struct inode *inode, void *opaque) | |||
610 | if (CIFS_I(inode)->uniqueid != fattr->cf_uniqueid) | 715 | if (CIFS_I(inode)->uniqueid != fattr->cf_uniqueid) |
611 | return 0; | 716 | return 0; |
612 | 717 | ||
718 | /* | ||
719 | * uh oh -- it's a directory. We can't use it since hardlinked dirs are | ||
720 | * verboten. Disable serverino and return it as if it were found, the | ||
721 | * caller can discard it, generate a uniqueid and retry the find | ||
722 | */ | ||
723 | if (S_ISDIR(inode->i_mode) && !list_empty(&inode->i_dentry)) { | ||
724 | fattr->cf_flags |= CIFS_FATTR_INO_COLLISION; | ||
725 | cifs_autodisable_serverino(CIFS_SB(inode->i_sb)); | ||
726 | } | ||
727 | |||
613 | return 1; | 728 | return 1; |
614 | } | 729 | } |
615 | 730 | ||
@@ -629,15 +744,22 @@ cifs_iget(struct super_block *sb, struct cifs_fattr *fattr) | |||
629 | unsigned long hash; | 744 | unsigned long hash; |
630 | struct inode *inode; | 745 | struct inode *inode; |
631 | 746 | ||
747 | retry_iget5_locked: | ||
632 | cFYI(1, ("looking for uniqueid=%llu", fattr->cf_uniqueid)); | 748 | cFYI(1, ("looking for uniqueid=%llu", fattr->cf_uniqueid)); |
633 | 749 | ||
634 | /* hash down to 32-bits on 32-bit arch */ | 750 | /* hash down to 32-bits on 32-bit arch */ |
635 | hash = cifs_uniqueid_to_ino_t(fattr->cf_uniqueid); | 751 | hash = cifs_uniqueid_to_ino_t(fattr->cf_uniqueid); |
636 | 752 | ||
637 | inode = iget5_locked(sb, hash, cifs_find_inode, cifs_init_inode, fattr); | 753 | inode = iget5_locked(sb, hash, cifs_find_inode, cifs_init_inode, fattr); |
638 | |||
639 | /* we have fattrs in hand, update the inode */ | ||
640 | if (inode) { | 754 | if (inode) { |
755 | /* was there a problematic inode number collision? */ | ||
756 | if (fattr->cf_flags & CIFS_FATTR_INO_COLLISION) { | ||
757 | iput(inode); | ||
758 | fattr->cf_uniqueid = iunique(sb, ROOT_I); | ||
759 | fattr->cf_flags &= ~CIFS_FATTR_INO_COLLISION; | ||
760 | goto retry_iget5_locked; | ||
761 | } | ||
762 | |||
641 | cifs_fattr_to_inode(inode, fattr); | 763 | cifs_fattr_to_inode(inode, fattr); |
642 | if (sb->s_flags & MS_NOATIME) | 764 | if (sb->s_flags & MS_NOATIME) |
643 | inode->i_flags |= S_NOATIME | S_NOCMTIME; | 765 | inode->i_flags |= S_NOATIME | S_NOCMTIME; |
@@ -914,8 +1036,8 @@ undo_setattr: | |||
914 | /* | 1036 | /* |
915 | * If dentry->d_inode is null (usually meaning the cached dentry | 1037 | * If dentry->d_inode is null (usually meaning the cached dentry |
916 | * is a negative dentry) then we would attempt a standard SMB delete, but | 1038 | * is a negative dentry) then we would attempt a standard SMB delete, but |
917 | * if that fails we can not attempt the fall back mechanisms on EACESS | 1039 | * if that fails we can not attempt the fall back mechanisms on EACCESS |
918 | * but will return the EACESS to the caller. Note that the VFS does not call | 1040 | * but will return the EACCESS to the caller. Note that the VFS does not call |
919 | * unlink on negative dentries currently. | 1041 | * unlink on negative dentries currently. |
920 | */ | 1042 | */ |
921 | int cifs_unlink(struct inode *dir, struct dentry *dentry) | 1043 | int cifs_unlink(struct inode *dir, struct dentry *dentry) |
@@ -1388,135 +1510,103 @@ cifs_rename_exit: | |||
1388 | return rc; | 1510 | return rc; |
1389 | } | 1511 | } |
1390 | 1512 | ||
1391 | int cifs_revalidate(struct dentry *direntry) | 1513 | static bool |
1514 | cifs_inode_needs_reval(struct inode *inode) | ||
1392 | { | 1515 | { |
1393 | int xid; | 1516 | struct cifsInodeInfo *cifs_i = CIFS_I(inode); |
1394 | int rc = 0, wbrc = 0; | ||
1395 | char *full_path; | ||
1396 | struct cifs_sb_info *cifs_sb; | ||
1397 | struct cifsInodeInfo *cifsInode; | ||
1398 | loff_t local_size; | ||
1399 | struct timespec local_mtime; | ||
1400 | bool invalidate_inode = false; | ||
1401 | 1517 | ||
1402 | if (direntry->d_inode == NULL) | 1518 | if (cifs_i->clientCanCacheRead) |
1403 | return -ENOENT; | 1519 | return false; |
1404 | 1520 | ||
1405 | cifsInode = CIFS_I(direntry->d_inode); | 1521 | if (!lookupCacheEnabled) |
1522 | return true; | ||
1406 | 1523 | ||
1407 | if (cifsInode == NULL) | 1524 | if (cifs_i->time == 0) |
1408 | return -ENOENT; | 1525 | return true; |
1409 | 1526 | ||
1410 | /* no sense revalidating inode info on file that no one can write */ | 1527 | /* FIXME: the actimeo should be tunable */ |
1411 | if (CIFS_I(direntry->d_inode)->clientCanCacheRead) | 1528 | if (time_after_eq(jiffies, cifs_i->time + HZ)) |
1412 | return rc; | 1529 | return true; |
1530 | |||
1531 | return false; | ||
1532 | } | ||
1533 | |||
1534 | /* check invalid_mapping flag and zap the cache if it's set */ | ||
1535 | static void | ||
1536 | cifs_invalidate_mapping(struct inode *inode) | ||
1537 | { | ||
1538 | int rc; | ||
1539 | struct cifsInodeInfo *cifs_i = CIFS_I(inode); | ||
1540 | |||
1541 | cifs_i->invalid_mapping = false; | ||
1542 | |||
1543 | /* write back any cached data */ | ||
1544 | if (inode->i_mapping && inode->i_mapping->nrpages != 0) { | ||
1545 | rc = filemap_write_and_wait(inode->i_mapping); | ||
1546 | if (rc) | ||
1547 | cifs_i->write_behind_rc = rc; | ||
1548 | } | ||
1549 | invalidate_remote_inode(inode); | ||
1550 | } | ||
1551 | |||
1552 | int cifs_revalidate_file(struct file *filp) | ||
1553 | { | ||
1554 | int rc = 0; | ||
1555 | struct inode *inode = filp->f_path.dentry->d_inode; | ||
1556 | |||
1557 | if (!cifs_inode_needs_reval(inode)) | ||
1558 | goto check_inval; | ||
1559 | |||
1560 | if (CIFS_SB(inode->i_sb)->tcon->unix_ext) | ||
1561 | rc = cifs_get_file_info_unix(filp); | ||
1562 | else | ||
1563 | rc = cifs_get_file_info(filp); | ||
1564 | |||
1565 | check_inval: | ||
1566 | if (CIFS_I(inode)->invalid_mapping) | ||
1567 | cifs_invalidate_mapping(inode); | ||
1568 | |||
1569 | return rc; | ||
1570 | } | ||
1571 | |||
1572 | /* revalidate a dentry's inode attributes */ | ||
1573 | int cifs_revalidate_dentry(struct dentry *dentry) | ||
1574 | { | ||
1575 | int xid; | ||
1576 | int rc = 0; | ||
1577 | char *full_path = NULL; | ||
1578 | struct inode *inode = dentry->d_inode; | ||
1579 | struct super_block *sb = dentry->d_sb; | ||
1580 | |||
1581 | if (inode == NULL) | ||
1582 | return -ENOENT; | ||
1413 | 1583 | ||
1414 | xid = GetXid(); | 1584 | xid = GetXid(); |
1415 | 1585 | ||
1416 | cifs_sb = CIFS_SB(direntry->d_sb); | 1586 | if (!cifs_inode_needs_reval(inode)) |
1587 | goto check_inval; | ||
1417 | 1588 | ||
1418 | /* can not safely grab the rename sem here if rename calls revalidate | 1589 | /* can not safely grab the rename sem here if rename calls revalidate |
1419 | since that would deadlock */ | 1590 | since that would deadlock */ |
1420 | full_path = build_path_from_dentry(direntry); | 1591 | full_path = build_path_from_dentry(dentry); |
1421 | if (full_path == NULL) { | 1592 | if (full_path == NULL) { |
1422 | rc = -ENOMEM; | 1593 | rc = -ENOMEM; |
1423 | FreeXid(xid); | 1594 | goto check_inval; |
1424 | return rc; | ||
1425 | } | ||
1426 | cFYI(1, ("Revalidate: %s inode 0x%p count %d dentry: 0x%p d_time %ld " | ||
1427 | "jiffies %ld", full_path, direntry->d_inode, | ||
1428 | direntry->d_inode->i_count.counter, direntry, | ||
1429 | direntry->d_time, jiffies)); | ||
1430 | |||
1431 | if (cifsInode->time == 0) { | ||
1432 | /* was set to zero previously to force revalidate */ | ||
1433 | } else if (time_before(jiffies, cifsInode->time + HZ) && | ||
1434 | lookupCacheEnabled) { | ||
1435 | if ((S_ISREG(direntry->d_inode->i_mode) == 0) || | ||
1436 | (direntry->d_inode->i_nlink == 1)) { | ||
1437 | kfree(full_path); | ||
1438 | FreeXid(xid); | ||
1439 | return rc; | ||
1440 | } else { | ||
1441 | cFYI(1, ("Have to revalidate file due to hardlinks")); | ||
1442 | } | ||
1443 | } | ||
1444 | |||
1445 | /* save mtime and size */ | ||
1446 | local_mtime = direntry->d_inode->i_mtime; | ||
1447 | local_size = direntry->d_inode->i_size; | ||
1448 | |||
1449 | if (cifs_sb->tcon->unix_ext) { | ||
1450 | rc = cifs_get_inode_info_unix(&direntry->d_inode, full_path, | ||
1451 | direntry->d_sb, xid); | ||
1452 | if (rc) { | ||
1453 | cFYI(1, ("error on getting revalidate info %d", rc)); | ||
1454 | /* if (rc != -ENOENT) | ||
1455 | rc = 0; */ /* BB should we cache info on | ||
1456 | certain errors? */ | ||
1457 | } | ||
1458 | } else { | ||
1459 | rc = cifs_get_inode_info(&direntry->d_inode, full_path, NULL, | ||
1460 | direntry->d_sb, xid, NULL); | ||
1461 | if (rc) { | ||
1462 | cFYI(1, ("error on getting revalidate info %d", rc)); | ||
1463 | /* if (rc != -ENOENT) | ||
1464 | rc = 0; */ /* BB should we cache info on | ||
1465 | certain errors? */ | ||
1466 | } | ||
1467 | } | 1595 | } |
1468 | /* should we remap certain errors, access denied?, to zero */ | ||
1469 | 1596 | ||
1470 | /* if not oplocked, we invalidate inode pages if mtime or file size | 1597 | cFYI(1, ("Revalidate: %s inode 0x%p count %d dentry: 0x%p d_time %ld " |
1471 | had changed on server */ | 1598 | "jiffies %ld", full_path, inode, inode->i_count.counter, |
1599 | dentry, dentry->d_time, jiffies)); | ||
1472 | 1600 | ||
1473 | if (timespec_equal(&local_mtime, &direntry->d_inode->i_mtime) && | 1601 | if (CIFS_SB(sb)->tcon->unix_ext) |
1474 | (local_size == direntry->d_inode->i_size)) { | 1602 | rc = cifs_get_inode_info_unix(&inode, full_path, sb, xid); |
1475 | cFYI(1, ("cifs_revalidate - inode unchanged")); | 1603 | else |
1476 | } else { | 1604 | rc = cifs_get_inode_info(&inode, full_path, NULL, sb, |
1477 | /* file may have changed on server */ | 1605 | xid, NULL); |
1478 | if (cifsInode->clientCanCacheRead) { | ||
1479 | /* no need to invalidate inode pages since we were the | ||
1480 | only ones who could have modified the file and the | ||
1481 | server copy is staler than ours */ | ||
1482 | } else { | ||
1483 | invalidate_inode = true; | ||
1484 | } | ||
1485 | } | ||
1486 | 1606 | ||
1487 | /* can not grab this sem since kernel filesys locking documentation | 1607 | check_inval: |
1488 | indicates i_mutex may be taken by the kernel on lookup and rename | 1608 | if (CIFS_I(inode)->invalid_mapping) |
1489 | which could deadlock if we grab the i_mutex here as well */ | 1609 | cifs_invalidate_mapping(inode); |
1490 | /* mutex_lock(&direntry->d_inode->i_mutex);*/ | ||
1491 | /* need to write out dirty pages here */ | ||
1492 | if (direntry->d_inode->i_mapping) { | ||
1493 | /* do we need to lock inode until after invalidate completes | ||
1494 | below? */ | ||
1495 | wbrc = filemap_fdatawrite(direntry->d_inode->i_mapping); | ||
1496 | if (wbrc) | ||
1497 | CIFS_I(direntry->d_inode)->write_behind_rc = wbrc; | ||
1498 | } | ||
1499 | if (invalidate_inode) { | ||
1500 | /* shrink_dcache not necessary now that cifs dentry ops | ||
1501 | are exported for negative dentries */ | ||
1502 | /* if (S_ISDIR(direntry->d_inode->i_mode)) | ||
1503 | shrink_dcache_parent(direntry); */ | ||
1504 | if (S_ISREG(direntry->d_inode->i_mode)) { | ||
1505 | if (direntry->d_inode->i_mapping) { | ||
1506 | wbrc = filemap_fdatawait(direntry->d_inode->i_mapping); | ||
1507 | if (wbrc) | ||
1508 | CIFS_I(direntry->d_inode)->write_behind_rc = wbrc; | ||
1509 | } | ||
1510 | /* may eventually have to do this for open files too */ | ||
1511 | if (list_empty(&(cifsInode->openFileList))) { | ||
1512 | /* changed on server - flush read ahead pages */ | ||
1513 | cFYI(1, ("Invalidating read ahead data on " | ||
1514 | "closed file")); | ||
1515 | invalidate_remote_inode(direntry->d_inode); | ||
1516 | } | ||
1517 | } | ||
1518 | } | ||
1519 | /* mutex_unlock(&direntry->d_inode->i_mutex); */ | ||
1520 | 1610 | ||
1521 | kfree(full_path); | 1611 | kfree(full_path); |
1522 | FreeXid(xid); | 1612 | FreeXid(xid); |
@@ -1526,7 +1616,7 @@ int cifs_revalidate(struct dentry *direntry) | |||
1526 | int cifs_getattr(struct vfsmount *mnt, struct dentry *dentry, | 1616 | int cifs_getattr(struct vfsmount *mnt, struct dentry *dentry, |
1527 | struct kstat *stat) | 1617 | struct kstat *stat) |
1528 | { | 1618 | { |
1529 | int err = cifs_revalidate(dentry); | 1619 | int err = cifs_revalidate_dentry(dentry); |
1530 | if (!err) { | 1620 | if (!err) { |
1531 | generic_fillattr(dentry->d_inode, stat); | 1621 | generic_fillattr(dentry->d_inode, stat); |
1532 | stat->blksize = CIFS_MAX_MSGSIZE; | 1622 | stat->blksize = CIFS_MAX_MSGSIZE; |
@@ -1762,8 +1852,18 @@ cifs_setattr_unix(struct dentry *direntry, struct iattr *attrs) | |||
1762 | CIFS_MOUNT_MAP_SPECIAL_CHR); | 1852 | CIFS_MOUNT_MAP_SPECIAL_CHR); |
1763 | } | 1853 | } |
1764 | 1854 | ||
1765 | if (!rc) | 1855 | if (!rc) { |
1766 | rc = inode_setattr(inode, attrs); | 1856 | rc = inode_setattr(inode, attrs); |
1857 | |||
1858 | /* force revalidate when any of these times are set since some | ||
1859 | of the fs types (eg ext3, fat) do not have fine enough | ||
1860 | time granularity to match protocol, and we do not have a | ||
1861 | a way (yet) to query the server fs's time granularity (and | ||
1862 | whether it rounds times down). | ||
1863 | */ | ||
1864 | if (!rc && (attrs->ia_valid & (ATTR_MTIME | ATTR_CTIME))) | ||
1865 | cifsInode->time = 0; | ||
1866 | } | ||
1767 | out: | 1867 | out: |
1768 | kfree(args); | 1868 | kfree(args); |
1769 | kfree(full_path); | 1869 | kfree(full_path); |
diff --git a/fs/cifs/link.c b/fs/cifs/link.c index fc1e0487eaee..c1a9d4236a8c 100644 --- a/fs/cifs/link.c +++ b/fs/cifs/link.c | |||
@@ -20,6 +20,7 @@ | |||
20 | */ | 20 | */ |
21 | #include <linux/fs.h> | 21 | #include <linux/fs.h> |
22 | #include <linux/stat.h> | 22 | #include <linux/stat.h> |
23 | #include <linux/slab.h> | ||
23 | #include <linux/namei.h> | 24 | #include <linux/namei.h> |
24 | #include "cifsfs.h" | 25 | #include "cifsfs.h" |
25 | #include "cifspdu.h" | 26 | #include "cifspdu.h" |
diff --git a/fs/cifs/misc.c b/fs/cifs/misc.c index d27d4ec6579b..d1474996a812 100644 --- a/fs/cifs/misc.c +++ b/fs/cifs/misc.c | |||
@@ -79,7 +79,7 @@ sesInfoAlloc(void) | |||
79 | ++ret_buf->ses_count; | 79 | ++ret_buf->ses_count; |
80 | INIT_LIST_HEAD(&ret_buf->smb_ses_list); | 80 | INIT_LIST_HEAD(&ret_buf->smb_ses_list); |
81 | INIT_LIST_HEAD(&ret_buf->tcon_list); | 81 | INIT_LIST_HEAD(&ret_buf->tcon_list); |
82 | init_MUTEX(&ret_buf->sesSem); | 82 | mutex_init(&ret_buf->session_mutex); |
83 | } | 83 | } |
84 | return ret_buf; | 84 | return ret_buf; |
85 | } | 85 | } |
diff --git a/fs/cifs/readdir.c b/fs/cifs/readdir.c index f84062f9a985..18e0bc1fb593 100644 --- a/fs/cifs/readdir.c +++ b/fs/cifs/readdir.c | |||
@@ -22,6 +22,7 @@ | |||
22 | */ | 22 | */ |
23 | #include <linux/fs.h> | 23 | #include <linux/fs.h> |
24 | #include <linux/pagemap.h> | 24 | #include <linux/pagemap.h> |
25 | #include <linux/slab.h> | ||
25 | #include <linux/stat.h> | 26 | #include <linux/stat.h> |
26 | #include "cifspdu.h" | 27 | #include "cifspdu.h" |
27 | #include "cifsglob.h" | 28 | #include "cifsglob.h" |
@@ -77,6 +78,11 @@ cifs_readdir_lookup(struct dentry *parent, struct qstr *name, | |||
77 | 78 | ||
78 | cFYI(1, ("For %s", name->name)); | 79 | cFYI(1, ("For %s", name->name)); |
79 | 80 | ||
81 | if (parent->d_op && parent->d_op->d_hash) | ||
82 | parent->d_op->d_hash(parent, name); | ||
83 | else | ||
84 | name->hash = full_name_hash(name->name, name->len); | ||
85 | |||
80 | dentry = d_lookup(parent, name); | 86 | dentry = d_lookup(parent, name); |
81 | if (dentry) { | 87 | if (dentry) { |
82 | /* FIXME: check for inode number changes? */ | 88 | /* FIXME: check for inode number changes? */ |
@@ -666,12 +672,11 @@ static int cifs_get_name_from_search_buf(struct qstr *pqst, | |||
666 | min(len, max_len), nlt, | 672 | min(len, max_len), nlt, |
667 | cifs_sb->mnt_cifs_flags & | 673 | cifs_sb->mnt_cifs_flags & |
668 | CIFS_MOUNT_MAP_SPECIAL_CHR); | 674 | CIFS_MOUNT_MAP_SPECIAL_CHR); |
675 | pqst->len -= nls_nullsize(nlt); | ||
669 | } else { | 676 | } else { |
670 | pqst->name = filename; | 677 | pqst->name = filename; |
671 | pqst->len = len; | 678 | pqst->len = len; |
672 | } | 679 | } |
673 | pqst->hash = full_name_hash(pqst->name, pqst->len); | ||
674 | /* cFYI(1, ("filldir on %s",pqst->name)); */ | ||
675 | return rc; | 680 | return rc; |
676 | } | 681 | } |
677 | 682 | ||
diff --git a/fs/cifs/sess.c b/fs/cifs/sess.c index 7085a6275c4c..7c3fd7463f44 100644 --- a/fs/cifs/sess.c +++ b/fs/cifs/sess.c | |||
@@ -29,6 +29,7 @@ | |||
29 | #include "ntlmssp.h" | 29 | #include "ntlmssp.h" |
30 | #include "nterr.h" | 30 | #include "nterr.h" |
31 | #include <linux/utsname.h> | 31 | #include <linux/utsname.h> |
32 | #include <linux/slab.h> | ||
32 | #include "cifs_spnego.h" | 33 | #include "cifs_spnego.h" |
33 | 34 | ||
34 | extern void SMBNTencrypt(unsigned char *passwd, unsigned char *c8, | 35 | extern void SMBNTencrypt(unsigned char *passwd, unsigned char *c8, |
@@ -223,9 +224,9 @@ static void unicode_ssetup_strings(char **pbcc_area, struct cifsSesInfo *ses, | |||
223 | /* null user mount */ | 224 | /* null user mount */ |
224 | *bcc_ptr = 0; | 225 | *bcc_ptr = 0; |
225 | *(bcc_ptr+1) = 0; | 226 | *(bcc_ptr+1) = 0; |
226 | } else { /* 300 should be long enough for any conceivable user name */ | 227 | } else { |
227 | bytes_ret = cifs_strtoUCS((__le16 *) bcc_ptr, ses->userName, | 228 | bytes_ret = cifs_strtoUCS((__le16 *) bcc_ptr, ses->userName, |
228 | 300, nls_cp); | 229 | MAX_USERNAME_SIZE, nls_cp); |
229 | } | 230 | } |
230 | bcc_ptr += 2 * bytes_ret; | 231 | bcc_ptr += 2 * bytes_ret; |
231 | bcc_ptr += 2; /* account for null termination */ | 232 | bcc_ptr += 2; /* account for null termination */ |
@@ -246,11 +247,10 @@ static void ascii_ssetup_strings(char **pbcc_area, struct cifsSesInfo *ses, | |||
246 | /* copy user */ | 247 | /* copy user */ |
247 | if (ses->userName == NULL) { | 248 | if (ses->userName == NULL) { |
248 | /* BB what about null user mounts - check that we do this BB */ | 249 | /* BB what about null user mounts - check that we do this BB */ |
249 | } else { /* 300 should be long enough for any conceivable user name */ | 250 | } else { |
250 | strncpy(bcc_ptr, ses->userName, 300); | 251 | strncpy(bcc_ptr, ses->userName, MAX_USERNAME_SIZE); |
251 | } | 252 | } |
252 | /* BB improve check for overflow */ | 253 | bcc_ptr += strnlen(ses->userName, MAX_USERNAME_SIZE); |
253 | bcc_ptr += strnlen(ses->userName, 300); | ||
254 | *bcc_ptr = 0; | 254 | *bcc_ptr = 0; |
255 | bcc_ptr++; /* account for null termination */ | 255 | bcc_ptr++; /* account for null termination */ |
256 | 256 | ||
diff --git a/fs/cifs/smbdes.c b/fs/cifs/smbdes.c index 224a1f478966..b6b6dcb500bf 100644 --- a/fs/cifs/smbdes.c +++ b/fs/cifs/smbdes.c | |||
@@ -371,7 +371,7 @@ E_P24(unsigned char *p21, const unsigned char *c8, unsigned char *p24) | |||
371 | smbhash(p24 + 16, c8, p21 + 14, 1); | 371 | smbhash(p24 + 16, c8, p21 + 14, 1); |
372 | } | 372 | } |
373 | 373 | ||
374 | #if 0 /* currently unsued */ | 374 | #if 0 /* currently unused */ |
375 | static void | 375 | static void |
376 | D_P16(unsigned char *p14, unsigned char *in, unsigned char *out) | 376 | D_P16(unsigned char *p14, unsigned char *in, unsigned char *out) |
377 | { | 377 | { |
diff --git a/fs/cifs/smbencrypt.c b/fs/cifs/smbencrypt.c index 93fb09a99c69..192ea51af20f 100644 --- a/fs/cifs/smbencrypt.c +++ b/fs/cifs/smbencrypt.c | |||
@@ -24,6 +24,7 @@ | |||
24 | */ | 24 | */ |
25 | 25 | ||
26 | #include <linux/module.h> | 26 | #include <linux/module.h> |
27 | #include <linux/slab.h> | ||
27 | #include <linux/fs.h> | 28 | #include <linux/fs.h> |
28 | #include <linux/string.h> | 29 | #include <linux/string.h> |
29 | #include <linux/kernel.h> | 30 | #include <linux/kernel.h> |
diff --git a/fs/cifs/transport.c b/fs/cifs/transport.c index 07b8e71544ee..ad081fe7eb18 100644 --- a/fs/cifs/transport.c +++ b/fs/cifs/transport.c | |||
@@ -22,6 +22,7 @@ | |||
22 | 22 | ||
23 | #include <linux/fs.h> | 23 | #include <linux/fs.h> |
24 | #include <linux/list.h> | 24 | #include <linux/list.h> |
25 | #include <linux/gfp.h> | ||
25 | #include <linux/wait.h> | 26 | #include <linux/wait.h> |
26 | #include <linux/net.h> | 27 | #include <linux/net.h> |
27 | #include <linux/delay.h> | 28 | #include <linux/delay.h> |
diff --git a/fs/cifs/xattr.c b/fs/cifs/xattr.c index a75afa3dd9e1..f555ce077d4f 100644 --- a/fs/cifs/xattr.c +++ b/fs/cifs/xattr.c | |||
@@ -21,6 +21,7 @@ | |||
21 | 21 | ||
22 | #include <linux/fs.h> | 22 | #include <linux/fs.h> |
23 | #include <linux/posix_acl_xattr.h> | 23 | #include <linux/posix_acl_xattr.h> |
24 | #include <linux/slab.h> | ||
24 | #include "cifsfs.h" | 25 | #include "cifsfs.h" |
25 | #include "cifspdu.h" | 26 | #include "cifspdu.h" |
26 | #include "cifsglob.h" | 27 | #include "cifsglob.h" |
@@ -244,7 +245,7 @@ ssize_t cifs_getxattr(struct dentry *direntry, const char *ea_name, | |||
244 | /* revalidate/getattr then populate from inode */ | 245 | /* revalidate/getattr then populate from inode */ |
245 | } /* BB add else when above is implemented */ | 246 | } /* BB add else when above is implemented */ |
246 | ea_name += 5; /* skip past user. prefix */ | 247 | ea_name += 5; /* skip past user. prefix */ |
247 | rc = CIFSSMBQueryEA(xid, pTcon, full_path, ea_name, ea_value, | 248 | rc = CIFSSMBQAllEAs(xid, pTcon, full_path, ea_name, ea_value, |
248 | buf_size, cifs_sb->local_nls, | 249 | buf_size, cifs_sb->local_nls, |
249 | cifs_sb->mnt_cifs_flags & CIFS_MOUNT_MAP_SPECIAL_CHR); | 250 | cifs_sb->mnt_cifs_flags & CIFS_MOUNT_MAP_SPECIAL_CHR); |
250 | } else if (strncmp(ea_name, CIFS_XATTR_OS2_PREFIX, 4) == 0) { | 251 | } else if (strncmp(ea_name, CIFS_XATTR_OS2_PREFIX, 4) == 0) { |
@@ -252,7 +253,7 @@ ssize_t cifs_getxattr(struct dentry *direntry, const char *ea_name, | |||
252 | goto get_ea_exit; | 253 | goto get_ea_exit; |
253 | 254 | ||
254 | ea_name += 4; /* skip past os2. prefix */ | 255 | ea_name += 4; /* skip past os2. prefix */ |
255 | rc = CIFSSMBQueryEA(xid, pTcon, full_path, ea_name, ea_value, | 256 | rc = CIFSSMBQAllEAs(xid, pTcon, full_path, ea_name, ea_value, |
256 | buf_size, cifs_sb->local_nls, | 257 | buf_size, cifs_sb->local_nls, |
257 | cifs_sb->mnt_cifs_flags & CIFS_MOUNT_MAP_SPECIAL_CHR); | 258 | cifs_sb->mnt_cifs_flags & CIFS_MOUNT_MAP_SPECIAL_CHR); |
258 | } else if (strncmp(ea_name, POSIX_ACL_XATTR_ACCESS, | 259 | } else if (strncmp(ea_name, POSIX_ACL_XATTR_ACCESS, |
@@ -364,8 +365,8 @@ ssize_t cifs_listxattr(struct dentry *direntry, char *data, size_t buf_size) | |||
364 | /* if proc/fs/cifs/streamstoxattr is set then | 365 | /* if proc/fs/cifs/streamstoxattr is set then |
365 | search server for EAs or streams to | 366 | search server for EAs or streams to |
366 | returns as xattrs */ | 367 | returns as xattrs */ |
367 | rc = CIFSSMBQAllEAs(xid, pTcon, full_path, data, buf_size, | 368 | rc = CIFSSMBQAllEAs(xid, pTcon, full_path, NULL, data, |
368 | cifs_sb->local_nls, | 369 | buf_size, cifs_sb->local_nls, |
369 | cifs_sb->mnt_cifs_flags & | 370 | cifs_sb->mnt_cifs_flags & |
370 | CIFS_MOUNT_MAP_SPECIAL_CHR); | 371 | CIFS_MOUNT_MAP_SPECIAL_CHR); |
371 | 372 | ||