Merge git://git.kernel.org/pub/scm/linux/kernel/git/sfrench/cifs-2.6
* git://git.kernel.org/pub/scm/linux/kernel/git/sfrench/cifs-2.6:
[CIFS] statfs for cifs unix extensions no longer experimental
[CIFS] New POSIX locking code not setting rc properly to zero on successful
[CIFS] Support deep tree mounts (e.g. mounts to //server/share/path)
diff --git a/fs/cifs/CHANGES b/fs/cifs/CHANGES
index 0feb3bd..1eb9a2e 100644
--- a/fs/cifs/CHANGES
+++ b/fs/cifs/CHANGES
@@ -1,3 +1,7 @@
+Version 1.46
+------------
+Support deep tree mounts. Better support OS/2, Win9x (DOS) time stamps.
+
Version 1.45
------------
Do not time out lockw calls when using posix extensions. Do not
@@ -6,7 +10,8 @@
(lock cancel now works, and unlock of merged range works even
to Windows servers now). Fix oops on mount to lanman servers
(win9x, os/2 etc.) when null password. Do not send listxattr
-(SMB to query all EAs) if nouser_xattr specified.
+(SMB to query all EAs) if nouser_xattr specified. Fix SE Linux
+problem (instantiate inodes/dentries in right order for readdir).
Version 1.44
------------
diff --git a/fs/cifs/cifs_fs_sb.h b/fs/cifs/cifs_fs_sb.h
index ad58eb0..fd1e52e 100644
--- a/fs/cifs/cifs_fs_sb.h
+++ b/fs/cifs/cifs_fs_sb.h
@@ -40,5 +40,7 @@
mode_t mnt_file_mode;
mode_t mnt_dir_mode;
int mnt_cifs_flags;
+ int prepathlen;
+ char * prepath;
};
#endif /* _CIFS_FS_SB_H */
diff --git a/fs/cifs/cifsfs.c b/fs/cifs/cifsfs.c
index 3cd7500..c3ef1c0 100644
--- a/fs/cifs/cifsfs.c
+++ b/fs/cifs/cifsfs.c
@@ -189,7 +189,6 @@
buf->f_files = 0; /* undefined */
buf->f_ffree = 0; /* unlimited */
-#ifdef CONFIG_CIFS_EXPERIMENTAL
/* BB we could add a second check for a QFS Unix capability bit */
/* BB FIXME check CIFS_POSIX_EXTENSIONS Unix cap first FIXME BB */
if ((pTcon->ses->capabilities & CAP_UNIX) && (CIFS_POSIX_EXTENSIONS &
@@ -199,7 +198,6 @@
/* Only need to call the old QFSInfo if failed
on newer one */
if(rc)
-#endif /* CIFS_EXPERIMENTAL */
rc = CIFSSMBQFSInfo(xid, pTcon, buf);
/* Old Windows servers do not support level 103, retry with level
diff --git a/fs/cifs/cifsfs.h b/fs/cifs/cifsfs.h
index 39ee8ef..bea875d 100644
--- a/fs/cifs/cifsfs.h
+++ b/fs/cifs/cifsfs.h
@@ -100,5 +100,5 @@
extern ssize_t cifs_listxattr(struct dentry *, char *, size_t);
extern int cifs_ioctl (struct inode * inode, struct file * filep,
unsigned int command, unsigned long arg);
-#define CIFS_VERSION "1.45"
+#define CIFS_VERSION "1.46"
#endif /* _CIFSFS_H */
diff --git a/fs/cifs/cifspdu.h b/fs/cifs/cifspdu.h
index 8623902..81df2bf 100644
--- a/fs/cifs/cifspdu.h
+++ b/fs/cifs/cifspdu.h
@@ -1344,6 +1344,7 @@
#define SMB_QUERY_ATTR_FLAGS 0x206 /* append,immutable etc. */
#define SMB_QUERY_POSIX_PERMISSION 0x207
#define SMB_QUERY_POSIX_LOCK 0x208
+/* #define SMB_POSIX_OPEN 0x209 */
#define SMB_QUERY_FILE_INTERNAL_INFO 0x3ee
#define SMB_QUERY_FILE_ACCESS_INFO 0x3f0
#define SMB_QUERY_FILE_NAME_INFO2 0x3f1 /* 0x30 bytes */
@@ -1363,6 +1364,7 @@
#define SMB_SET_XATTR 0x205
#define SMB_SET_ATTR_FLAGS 0x206 /* append, immutable etc. */
#define SMB_SET_POSIX_LOCK 0x208
+#define SMB_POSIX_OPEN 0x209
#define SMB_SET_FILE_BASIC_INFO2 0x3ec
#define SMB_SET_FILE_RENAME_INFORMATION 0x3f2 /* BB check if qpathinfo level too */
#define SMB_FILE_ALL_INFO2 0x3fa
diff --git a/fs/cifs/connect.c b/fs/cifs/connect.c
index 5d394c7..0e9ba0b 100644
--- a/fs/cifs/connect.c
+++ b/fs/cifs/connect.c
@@ -89,6 +89,7 @@
unsigned int wsize;
unsigned int sockopt;
unsigned short int port;
+ char * prepath;
};
static int ipv4_connect(struct sockaddr_in *psin_server,
@@ -993,6 +994,28 @@
printk(KERN_WARNING "CIFS: domain name too long\n");
return 1;
}
+ } else if (strnicmp(data, "prefixpath", 10) == 0) {
+ if (!value || !*value) {
+ printk(KERN_WARNING
+ "CIFS: invalid path prefix\n");
+ return 1; /* needs_arg; */
+ }
+ if ((temp_len = strnlen(value, 1024)) < 1024) {
+ if(value[0] != '/')
+ temp_len++; /* missing leading slash */
+ vol->prepath = kmalloc(temp_len+1,GFP_KERNEL);
+ if(vol->prepath == NULL)
+ return 1;
+ if(value[0] != '/') {
+ vol->prepath[0] = '/';
+ strcpy(vol->prepath+1,value);
+ } else
+ strcpy(vol->prepath,value);
+ cFYI(1,("prefix path %s",vol->prepath));
+ } else {
+ printk(KERN_WARNING "CIFS: prefix too long\n");
+ return 1;
+ }
} else if (strnicmp(data, "iocharset", 9) == 0) {
if (!value || !*value) {
printk(KERN_WARNING "CIFS: invalid iocharset specified\n");
@@ -1605,6 +1628,7 @@
if (cifs_parse_mount_options(mount_data, devname, &volume_info)) {
kfree(volume_info.UNC);
kfree(volume_info.password);
+ kfree(volume_info.prepath);
FreeXid(xid);
return -EINVAL;
}
@@ -1619,6 +1643,7 @@
locations such as env variables and files on disk */
kfree(volume_info.UNC);
kfree(volume_info.password);
+ kfree(volume_info.prepath);
FreeXid(xid);
return -EINVAL;
}
@@ -1639,6 +1664,7 @@
/* we failed translating address */
kfree(volume_info.UNC);
kfree(volume_info.password);
+ kfree(volume_info.prepath);
FreeXid(xid);
return -EINVAL;
}
@@ -1651,6 +1677,7 @@
cERROR(1,("Connecting to DFS root not implemented yet"));
kfree(volume_info.UNC);
kfree(volume_info.password);
+ kfree(volume_info.prepath);
FreeXid(xid);
return -EINVAL;
} else /* which servers DFS root would we conect to */ {
@@ -1658,6 +1685,7 @@
("CIFS mount error: No UNC path (e.g. -o unc=//192.168.1.100/public) specified"));
kfree(volume_info.UNC);
kfree(volume_info.password);
+ kfree(volume_info.prepath);
FreeXid(xid);
return -EINVAL;
}
@@ -1672,6 +1700,7 @@
cERROR(1,("CIFS mount error: iocharset %s not found",volume_info.iocharset));
kfree(volume_info.UNC);
kfree(volume_info.password);
+ kfree(volume_info.prepath);
FreeXid(xid);
return -ELIBACC;
}
@@ -1688,6 +1717,7 @@
else {
kfree(volume_info.UNC);
kfree(volume_info.password);
+ kfree(volume_info.prepath);
FreeXid(xid);
return -EINVAL;
}
@@ -1710,6 +1740,7 @@
sock_release(csocket);
kfree(volume_info.UNC);
kfree(volume_info.password);
+ kfree(volume_info.prepath);
FreeXid(xid);
return rc;
}
@@ -1720,6 +1751,7 @@
sock_release(csocket);
kfree(volume_info.UNC);
kfree(volume_info.password);
+ kfree(volume_info.prepath);
FreeXid(xid);
return rc;
} else {
@@ -1744,6 +1776,7 @@
sock_release(csocket);
kfree(volume_info.UNC);
kfree(volume_info.password);
+ kfree(volume_info.prepath);
FreeXid(xid);
return rc;
}
@@ -1831,6 +1864,14 @@
/* Windows ME may prefer this */
cFYI(1,("readsize set to minimum 2048"));
}
+ /* calculate prepath */
+ cifs_sb->prepath = volume_info.prepath;
+ if(cifs_sb->prepath) {
+ cifs_sb->prepathlen = strlen(cifs_sb->prepath);
+ cifs_sb->prepath[0] = CIFS_DIR_SEP(cifs_sb);
+ volume_info.prepath = NULL;
+ } else
+ cifs_sb->prepathlen = 0;
cifs_sb->mnt_uid = volume_info.linux_uid;
cifs_sb->mnt_gid = volume_info.linux_gid;
cifs_sb->mnt_file_mode = volume_info.file_mode;
@@ -2008,6 +2049,7 @@
the password ptr is put in the new session structure (in which case the
password will be freed at unmount time) */
kfree(volume_info.UNC);
+ kfree(volume_info.prepath);
FreeXid(xid);
return rc;
}
@@ -3195,6 +3237,7 @@
int xid;
struct cifsSesInfo *ses = NULL;
struct task_struct *cifsd_task;
+ char * tmp;
xid = GetXid();
@@ -3228,6 +3271,10 @@
}
cifs_sb->tcon = NULL;
+ tmp = cifs_sb->prepath;
+ cifs_sb->prepathlen = 0;
+ cifs_sb->prepath = NULL;
+ kfree(tmp);
if (ses)
schedule_timeout_interruptible(msecs_to_jiffies(500));
if (ses)
diff --git a/fs/cifs/dir.c b/fs/cifs/dir.c
index 914239d5..66b825a 100644
--- a/fs/cifs/dir.c
+++ b/fs/cifs/dir.c
@@ -46,7 +46,8 @@
build_path_from_dentry(struct dentry *direntry)
{
struct dentry *temp;
- int namelen = 0;
+ int namelen;
+ int pplen;
char *full_path;
char dirsep;
@@ -56,7 +57,9 @@
when the server crashed */
dirsep = CIFS_DIR_SEP(CIFS_SB(direntry->d_sb));
+ pplen = CIFS_SB(direntry->d_sb)->prepathlen;
cifs_bp_rename_retry:
+ namelen = pplen;
for (temp = direntry; !IS_ROOT(temp);) {
namelen += (1 + temp->d_name.len);
temp = temp->d_parent;
@@ -70,7 +73,6 @@
if(full_path == NULL)
return full_path;
full_path[namelen] = 0; /* trailing null */
-
for (temp = direntry; !IS_ROOT(temp);) {
namelen -= 1 + temp->d_name.len;
if (namelen < 0) {
@@ -79,7 +81,7 @@
full_path[namelen] = dirsep;
strncpy(full_path + namelen + 1, temp->d_name.name,
temp->d_name.len);
- cFYI(0, (" name: %s ", full_path + namelen));
+ cFYI(0, ("name: %s", full_path + namelen));
}
temp = temp->d_parent;
if(temp == NULL) {
@@ -88,18 +90,23 @@
return NULL;
}
}
- if (namelen != 0) {
+ if (namelen != pplen) {
cERROR(1,
- ("We did not end path lookup where we expected namelen is %d",
+ ("did not end path lookup where expected namelen is %d",
namelen));
- /* presumably this is only possible if we were racing with a rename
+ /* presumably this is only possible if racing with a rename
of one of the parent directories (we can not lock the dentries
above us to prevent this, but retrying should be harmless) */
kfree(full_path);
- namelen = 0;
goto cifs_bp_rename_retry;
}
-
+ /* DIR_SEP already set for byte 0 / vs \ but not for
+ subsequent slashes in prepath which currently must
+ be entered the right way - not sure if there is an alternative
+ since the '\' is a valid posix character so we can not switch
+ those safely to '/' if any are found in the middle of the prepath */
+ /* BB test paths to Windows with '/' in the midst of prepath */
+ strncpy(full_path,CIFS_SB(direntry->d_sb)->prepath,pplen);
return full_path;
}
diff --git a/fs/cifs/file.c b/fs/cifs/file.c
index e9c5ba9..ddb012a 100644
--- a/fs/cifs/file.c
+++ b/fs/cifs/file.c
@@ -752,6 +752,7 @@
int stored_rc = 0;
struct cifsLockInfo *li, *tmp;
+ rc = 0;
down(&fid->lock_sem);
list_for_each_entry_safe(li, tmp, &fid->llist, llist) {
if (pfLock->fl_start <= li->offset &&
@@ -766,7 +767,7 @@
kfree(li);
}
}
- up(&fid->lock_sem);
+ up(&fid->lock_sem);
}
}
diff --git a/fs/cifs/xattr.c b/fs/cifs/xattr.c
index 067648b..18fcec1 100644
--- a/fs/cifs/xattr.c
+++ b/fs/cifs/xattr.c
@@ -269,7 +269,7 @@
rc = CIFSSMBGetCIFSACL(xid, pTcon, fid,
ea_value, buf_size,
ACL_TYPE_ACCESS);
- CIFSSMBClose(xid, pTcon, fid)
+ CIFSSMBClose(xid, pTcon, fid);
}
} */ /* BB enable after fixing up return data */