summaryrefslogtreecommitdiff
path: root/fs
diff options
context:
space:
mode:
authorTrond Myklebust <Trond.Myklebust@netapp.com>2007-02-14 09:02:32 +0300
committerTrond Myklebust <Trond.Myklebust@netapp.com>2007-02-14 09:02:32 +0300
commitac98695d6c1508b724f246f38ce57fb4e3cec356 (patch)
tree189969a3689b9b83eaf39314a7942cc781ff836b /fs
parentd9bc125caf592b7d081021f32ce5b717efdf70c8 (diff)
parent93bbad8fe13a25dcf7f3bc628a71d1a7642ae61b (diff)
downloadlinux-ac98695d6c1508b724f246f38ce57fb4e3cec356.tar.xz
Merge branch 'master' of /home/trondmy/kernel/linux-2.6/
Diffstat (limited to 'fs')
-rw-r--r--fs/Kconfig29
-rw-r--r--fs/cifs/CHANGES9
-rw-r--r--fs/cifs/TODO8
-rw-r--r--fs/cifs/cifsfs.h2
-rw-r--r--fs/cifs/cifspdu.h84
-rw-r--r--fs/cifs/cifsproto.h5
-rw-r--r--fs/cifs/cifssmb.c16
-rw-r--r--fs/cifs/connect.c130
-rw-r--r--fs/cifs/file.c5
-rw-r--r--fs/cifs/inode.c6
-rw-r--r--fs/cifs/readdir.c6
-rw-r--r--fs/dcache.c150
12 files changed, 273 insertions, 177 deletions
diff --git a/fs/Kconfig b/fs/Kconfig
index 488521ed9e9b..a722b5a3f752 100644
--- a/fs/Kconfig
+++ b/fs/Kconfig
@@ -1864,20 +1864,14 @@ config CIFS
file servers such as Windows 2000 (including Windows 2003, NT 4
and Windows XP) as well by Samba (which provides excellent CIFS
server support for Linux and many other operating systems). Limited
- support for Windows ME and similar servers is provided as well.
- You must use the smbfs client filesystem to access older SMB servers
- such as OS/2 and DOS.
+ support for OS/2 and Windows ME and similar servers is provided as well.
The intent of the cifs module is to provide an advanced
- network file system client for mounting to CIFS compliant servers,
+ network file system client for mounting to CIFS compliant servers,
including support for dfs (hierarchical name space), secure per-user
session establishment, safe distributed caching (oplock), optional
- packet signing, Unicode and other internationalization improvements,
- and optional Winbind (nsswitch) integration. You do not need to enable
- cifs if running only a (Samba) server. It is possible to enable both
- smbfs and cifs (e.g. if you are using CIFS for accessing Windows 2003
- and Samba 3 servers, and smbfs for accessing old servers). If you need
- to mount to Samba or Windows from this machine, say Y.
+ packet signing, Unicode and other internationalization improvements.
+ If you need to mount to Samba or Windows from this machine, say Y.
config CIFS_STATS
bool "CIFS statistics"
@@ -1970,14 +1964,13 @@ config CIFS_EXPERIMENTAL
depends on CIFS && EXPERIMENTAL
help
Enables cifs features under testing. These features are
- experimental and currently include support for writepages
- (multipage writebehind performance improvements) and directory
- change notification ie fcntl(F_DNOTIFY) as well as some security
- improvements. Some also depend on setting at runtime the
- pseudo-file /proc/fs/cifs/Experimental (which is disabled by
- default). See the file fs/cifs/README for more details.
-
- If unsure, say N.
+ experimental and currently include DFS support and directory
+ change notification ie fcntl(F_DNOTIFY), as well as the upcall
+ mechanism which will be used for Kerberos session negotiation
+ and uid remapping. Some of these features also may depend on
+ setting a value of 1 to the pseudo-file /proc/fs/cifs/Experimental
+ (which is disabled by default). See the file fs/cifs/README
+ for more details. If unsure, say N.
config CIFS_UPCALL
bool "Kerberos/SPNEGO advanced session setup (EXPERIMENTAL)"
diff --git a/fs/cifs/CHANGES b/fs/cifs/CHANGES
index 85e3850bf2c9..5fe13593b57f 100644
--- a/fs/cifs/CHANGES
+++ b/fs/cifs/CHANGES
@@ -1,8 +1,15 @@
Version 1.47
------------
Fix oops in list_del during mount caused by unaligned string.
+Fix file corruption which could occur on some large file
+copies caused by writepages page i/o completion bug.
Seek to SEEK_END forces check for update of file size for non-cached
-files.
+files. Allow file size to be updated on remote extend of locally open,
+non-cached file. Fix reconnect to newer Samba servers (or other servers
+which support the CIFS Unix/POSIX extensions) so that we again tell the
+server the Unix/POSIX cifs capabilities which we support (SetFSInfo).
+Add experimental support for new POSIX Open/Mkdir (which returns
+stat information on the open, and allows setting the mode).
Version 1.46
------------
diff --git a/fs/cifs/TODO b/fs/cifs/TODO
index fc34c74ec4be..68372946dc92 100644
--- a/fs/cifs/TODO
+++ b/fs/cifs/TODO
@@ -128,3 +128,11 @@ negotiated size) and send larger write sizes to modern servers.
4) More exhaustively test against less common servers. More testing
against Windows 9x, Windows ME servers.
+
+DOS attrs - returned as pseudo-xattr in Samba format (check VFAT and NTFS for this too)
+
+mount check for unmatched uids - and uid override
+
+Add mount option for Linux extension disable per mount, and partial disable per mount (uid off, symlink/fifo/mknod on but what about posix acls?)
+
+Free threads at umount --force that are stuck on the sesSem
diff --git a/fs/cifs/cifsfs.h b/fs/cifs/cifsfs.h
index 01ae24af9cfd..c97c08eb481a 100644
--- a/fs/cifs/cifsfs.h
+++ b/fs/cifs/cifsfs.h
@@ -100,5 +100,5 @@ extern ssize_t cifs_getxattr(struct dentry *, const char *, void *, size_t);
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.47"
+#define CIFS_VERSION "1.48"
#endif /* _CIFSFS_H */
diff --git a/fs/cifs/cifspdu.h b/fs/cifs/cifspdu.h
index 068ef51edbf7..7d9505491b16 100644
--- a/fs/cifs/cifspdu.h
+++ b/fs/cifs/cifspdu.h
@@ -1,7 +1,7 @@
/*
* fs/cifs/cifspdu.h
*
- * Copyright (c) International Business Machines Corp., 2002,2005
+ * Copyright (c) International Business Machines Corp., 2002,2007
* Author(s): Steve French (sfrench@us.ibm.com)
*
* This library is free software; you can redistribute it and/or modify
@@ -544,7 +544,8 @@ typedef union smb_com_session_setup_andx {
/* unsigned char * NativeOS; */
/* unsigned char * NativeLanMan; */
/* unsigned char * PrimaryDomain; */
- } __attribute__((packed)) resp; /* NTLM response with or without extended sec*/
+ } __attribute__((packed)) resp; /* NTLM response
+ (with or without extended sec) */
struct { /* request format */
struct smb_hdr hdr; /* wct = 10 */
@@ -795,6 +796,8 @@ typedef struct smb_com_openx_rsp {
__u16 ByteCount;
} __attribute__((packed)) OPENX_RSP;
+/* For encoding of POSIX Open Request - see trans2 function 0x209 data struct */
+
/* Legacy write request for older servers */
typedef struct smb_com_writex_req {
struct smb_hdr hdr; /* wct = 12 */
@@ -1352,11 +1355,13 @@ struct smb_t2_rsp {
#define SMB_QUERY_FILE_UNIX_BASIC 0x200
#define SMB_QUERY_FILE_UNIX_LINK 0x201
#define SMB_QUERY_POSIX_ACL 0x204
-#define SMB_QUERY_XATTR 0x205
+#define SMB_QUERY_XATTR 0x205 /* e.g. system EA name space */
#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_POSIX_OPEN 0x209 */
+/* #define SMB_POSIX_UNLINK 0x20a */
+#define SMB_QUERY_FILE__UNIX_INFO2 0x20b
#define SMB_QUERY_FILE_INTERNAL_INFO 0x3ee
#define SMB_QUERY_FILE_ACCESS_INFO 0x3f0
#define SMB_QUERY_FILE_NAME_INFO2 0x3f1 /* 0x30 bytes */
@@ -1377,8 +1382,10 @@ struct smb_t2_rsp {
#define SMB_SET_ATTR_FLAGS 0x206 /* append, immutable etc. */
#define SMB_SET_POSIX_LOCK 0x208
#define SMB_POSIX_OPEN 0x209
+#define SMB_POSIX_UNLINK 0x20a
+#define SMB_SET_FILE_UNIX_INFO2
#define SMB_SET_FILE_BASIC_INFO2 0x3ec
-#define SMB_SET_FILE_RENAME_INFORMATION 0x3f2 /* BB check if qpathinfo level too */
+#define SMB_SET_FILE_RENAME_INFORMATION 0x3f2 /* BB check if qpathinfo too */
#define SMB_FILE_ALL_INFO2 0x3fa
#define SMB_SET_FILE_ALLOCATION_INFO2 0x3fb
#define SMB_SET_FILE_END_OF_FILE_INFO2 0x3fc
@@ -1428,7 +1435,7 @@ typedef struct smb_com_transaction2_qpi_rsp {
struct smb_hdr hdr; /* wct = 10 + SetupCount */
struct trans2_resp t2;
__u16 ByteCount;
- __u16 Reserved2; /* parameter word reserved - present for infolevels > 100 */
+ __u16 Reserved2; /* parameter word is present for infolevels > 100 */
} __attribute__((packed)) TRANSACTION2_QPI_RSP;
typedef struct smb_com_transaction2_spi_req {
@@ -1461,7 +1468,7 @@ typedef struct smb_com_transaction2_spi_rsp {
struct smb_hdr hdr; /* wct = 10 + SetupCount */
struct trans2_resp t2;
__u16 ByteCount;
- __u16 Reserved2; /* parameter word reserved - present for infolevels > 100 */
+ __u16 Reserved2; /* parameter word is present for infolevels > 100 */
} __attribute__((packed)) TRANSACTION2_SPI_RSP;
struct set_file_rename {
@@ -1627,6 +1634,7 @@ typedef struct smb_com_transaction2_fnext_rsp_parms {
#define SMB_QUERY_FS_ATTRIBUTE_INFO 0x105
#define SMB_QUERY_CIFS_UNIX_INFO 0x200
#define SMB_QUERY_POSIX_FS_INFO 0x201
+#define SMB_QUERY_POSIX_WHO_AM_I 0x202
#define SMB_QUERY_LABEL_INFO 0x3ea
#define SMB_QUERY_FS_QUOTA_INFO 0x3ee
#define SMB_QUERY_FS_FULL_SIZE_INFO 0x3ef
@@ -1659,9 +1667,21 @@ typedef struct smb_com_transaction_qfsi_rsp {
struct smb_hdr hdr; /* wct = 10 + SetupCount */
struct trans2_resp t2;
__u16 ByteCount;
- __u8 Pad; /* may be three bytes *//* followed by data area */
+ __u8 Pad; /* may be three bytes? *//* followed by data area */
} __attribute__((packed)) TRANSACTION2_QFSI_RSP;
+typedef struct whoami_rsp_data { /* Query level 0x202 */
+ __u32 flags; /* 0 = Authenticated user 1 = GUEST */
+ __u32 mask; /* which flags bits server understands ie 0x0001 */
+ __u64 unix_user_id;
+ __u64 unix_user_gid;
+ __u32 number_of_supplementary_gids; /* may be zero */
+ __u32 number_of_sids; /* may be zero */
+ __u32 length_of_sid_array; /* in bytes - may be zero */
+ __u32 pad; /* reserved - MBZ */
+ /* __u64 gid_array[0]; */ /* may be empty */
+ /* __u8 * psid_list */ /* may be empty */
+} __attribute__((packed)) WHOAMI_RSP_DATA;
/* SETFSInfo Levels */
#define SMB_SET_CIFS_UNIX_INFO 0x200
@@ -1858,8 +1878,11 @@ typedef struct {
#define CIFS_UNIX_XATTR_CAP 0x00000004 /* support new namespace */
#define CIFS_UNIX_EXTATTR_CAP 0x00000008 /* support chattr/chflag */
#define CIFS_UNIX_POSIX_PATHNAMES_CAP 0x00000010 /* Allow POSIX path chars */
+#define CIFS_UNIX_POSIX_PATH_OPS_CAP 0x00000020 /* Allow new POSIX path based
+ calls including posix open
+ and posix unlink */
#ifdef CONFIG_CIFS_POSIX
-#define CIFS_UNIX_CAP_MASK 0x0000001b
+#define CIFS_UNIX_CAP_MASK 0x0000003b
#else
#define CIFS_UNIX_CAP_MASK 0x00000013
#endif /* CONFIG_CIFS_POSIX */
@@ -1946,7 +1969,7 @@ typedef struct { /* data block encoding of response to level 263 QPathInfo */
__le32 AlignmentRequirement;
__le32 FileNameLength;
char FileName[1];
-} __attribute__((packed)) FILE_ALL_INFO; /* level 0x107 QPathInfo */
+} __attribute__((packed)) FILE_ALL_INFO; /* level 0x107 QPathInfo */
/* defines for enumerating possible values of the Unix type field below */
#define UNIX_FILE 0
@@ -1970,11 +1993,11 @@ typedef struct {
__u64 UniqueId;
__le64 Permissions;
__le64 Nlinks;
-} __attribute__((packed)) FILE_UNIX_BASIC_INFO; /* level 0x200 QPathInfo */
+} __attribute__((packed)) FILE_UNIX_BASIC_INFO; /* level 0x200 QPathInfo */
typedef struct {
char LinkDest[1];
-} __attribute__((packed)) FILE_UNIX_LINK_INFO; /* level 0x201 QPathInfo */
+} __attribute__((packed)) FILE_UNIX_LINK_INFO; /* level 0x201 QPathInfo */
/* The following three structures are needed only for
setting time to NT4 and some older servers via
@@ -2011,7 +2034,7 @@ typedef struct {
__le64 ChangeTime;
__le32 Attributes;
__u32 Pad;
-} __attribute__((packed)) FILE_BASIC_INFO; /* size info, level 0x101 */
+} __attribute__((packed)) FILE_BASIC_INFO; /* size info, level 0x101 */
struct file_allocation_info {
__le64 AllocationSize; /* Note old Samba srvr rounds this up too much */
@@ -2020,7 +2043,7 @@ struct file_allocation_info {
struct file_end_of_file_info {
__le64 FileSize; /* offset to end of file */
-} __attribute__((packed)); /* size info, level 0x104 for set, 0x106 for query */
+} __attribute__((packed)); /* size info, level 0x104 for set, 0x106 for query */
struct file_alt_name_info {
__u8 alt_name[1];
@@ -2075,6 +2098,19 @@ struct cifs_posix_acl { /* access conrol list (ACL) */
/* end of POSIX ACL definitions */
+typedef struct {
+ __u32 OpenFlags; /* same as NT CreateX */
+ __u32 PosixOpenFlags;
+ __u32 Mode;
+ __u16 Level; /* reply level requested (see QPathInfo levels) */
+ __u16 Pad; /* reserved - MBZ */
+} __attribute__((packed)) OPEN_PSX_REQ; /* level 0x209 SetPathInfo data */
+
+typedef struct {
+ /* reply varies based on requested level */
+} __attribute__((packed)) OPEN_PSX_RSP; /* level 0x209 SetPathInfo data */
+
+
struct file_internal_info {
__u64 UniqueId; /* inode number */
} __attribute__((packed)); /* level 0x3ee */
@@ -2238,7 +2274,8 @@ struct data_blob {
1) PosixCreateX - to set and return the mode, inode#, device info and
perhaps add a CreateDevice - to create Pipes and other special .inodes
Also note POSIX open flags
- 2) Close - to return the last write time to do cache across close more safely
+ 2) Close - to return the last write time to do cache across close
+ more safely
3) FindFirst return unique inode number - what about resume key, two
forms short (matches readdir) and full (enough info to cache inodes)
4) Mkdir - set mode
@@ -2273,7 +2310,8 @@ struct data_blob {
TRANSACTION2 (18 cases)
SMB_SET_FILE_END_OF_FILE_INFO2 SMB_SET_PATH_END_OF_FILE_INFO2
(BB verify that never need to set allocation size)
- SMB_SET_FILE_BASIC_INFO2 (setting times - BB can it be done via Unix ext?)
+ SMB_SET_FILE_BASIC_INFO2 (setting times - BB can it be done via
+ Unix ext?)
COPY (note support for copy across directories) - FUTURE, OPTIONAL
setting/getting OS/2 EAs - FUTURE (BB can this handle
@@ -2293,13 +2331,13 @@ struct data_blob {
T2 QUERY_PATH_INFO (SMB_QUERY_FILE_UNIX_BASIC) - BB check for missing inode fields
Actually need QUERY_FILE_UNIX_INFO since has inode num
BB what about a) blksize/blkbits/blocks
- b) i_version
- c) i_rdev
- d) notify mask?
- e) generation
- f) size_seqcount
+ b) i_version
+ c) i_rdev
+ d) notify mask?
+ e) generation
+ f) size_seqcount
T2 FIND_FIRST/FIND_NEXT FIND_FILE_UNIX
- TRANS2_GET_DFS_REFERRAL - OPTIONAL but recommended
+ TRANS2_GET_DFS_REFERRAL - OPTIONAL but recommended
T2_QFS_INFO QueryDevice/AttributeInfo - OPTIONAL
@@ -2338,7 +2376,7 @@ typedef struct file_xattr_info {
__u32 xattr_value_len;
char xattr_name[0];
/* followed by xattr_value[xattr_value_len], no pad */
-} __attribute__((packed)) FILE_XATTR_INFO; /* extended attribute, info level 0x205 */
+} __attribute__((packed)) FILE_XATTR_INFO; /* extended attribute, info level 0x205 */
/* flags for chattr command */
diff --git a/fs/cifs/cifsproto.h b/fs/cifs/cifsproto.h
index f1f8225102f0..6148b82170c4 100644
--- a/fs/cifs/cifsproto.h
+++ b/fs/cifs/cifsproto.h
@@ -23,6 +23,7 @@
#include <linux/nls.h>
struct statfs;
+struct smb_vol;
/*
*****************************************************************
@@ -57,7 +58,7 @@ extern int SendReceiveBlockingLock(const unsigned int /* xid */ ,
int * /* bytes returned */);
extern int checkSMB(struct smb_hdr *smb, __u16 mid, unsigned int length);
extern int is_valid_oplock_break(struct smb_hdr *smb, struct TCP_Server_Info *);
-extern int is_size_safe_to_change(struct cifsInodeInfo *);
+extern int is_size_safe_to_change(struct cifsInodeInfo *, __u64 eof);
extern struct cifsFileInfo *find_writable_file(struct cifsInodeInfo *);
extern unsigned int smbCalcSize(struct smb_hdr *ptr);
extern unsigned int smbCalcSize_LE(struct smb_hdr *ptr);
@@ -147,6 +148,8 @@ extern int get_dfs_path(int xid, struct cifsSesInfo *pSesInfo,
unsigned int *pnum_referrals,
unsigned char ** preferrals,
int remap);
+extern void reset_cifs_unix_caps(int xid, struct cifsTconInfo *tcon,
+ struct super_block * sb, struct smb_vol * vol);
extern int CIFSSMBQFSInfo(const int xid, struct cifsTconInfo *tcon,
struct kstatfs *FSData);
extern int SMBOldQFSInfo(const int xid, struct cifsTconInfo *tcon,
diff --git a/fs/cifs/cifssmb.c b/fs/cifs/cifssmb.c
index 472e33e0f3cf..b8e91470c27f 100644
--- a/fs/cifs/cifssmb.c
+++ b/fs/cifs/cifssmb.c
@@ -158,9 +158,15 @@ small_smb_init(int smb_command, int wct, struct cifsTconInfo *tcon,
nls_codepage);
if(!rc && (tcon->tidStatus == CifsNeedReconnect)) {
mark_open_files_invalid(tcon);
- rc = CIFSTCon(0, tcon->ses, tcon->treeName, tcon
- , nls_codepage);
+ rc = CIFSTCon(0, tcon->ses, tcon->treeName,
+ tcon, nls_codepage);
up(&tcon->ses->sesSem);
+ /* tell server which Unix caps we support */
+ if (tcon->ses->capabilities & CAP_UNIX)
+ reset_cifs_unix_caps(0 /* no xid */,
+ tcon,
+ NULL /* we do not know sb */,
+ NULL /* no vol info */);
/* BB FIXME add code to check if wsize needs
update due to negotiated smb buffer size
shrinking */
@@ -298,6 +304,12 @@ smb_init(int smb_command, int wct, struct cifsTconInfo *tcon,
rc = CIFSTCon(0, tcon->ses, tcon->treeName,
tcon, nls_codepage);
up(&tcon->ses->sesSem);
+ /* tell server which Unix caps we support */
+ if (tcon->ses->capabilities & CAP_UNIX)
+ reset_cifs_unix_caps(0 /* no xid */,
+ tcon,
+ NULL /* do not know sb */,
+ NULL /* no vol info */);
/* BB FIXME add code to check if wsize needs
update due to negotiated smb buffer size
shrinking */
diff --git a/fs/cifs/connect.c b/fs/cifs/connect.c
index 2caca06b4bae..20ba7dcc9959 100644
--- a/fs/cifs/connect.c
+++ b/fs/cifs/connect.c
@@ -1613,6 +1613,76 @@ ipv6_connect(struct sockaddr_in6 *psin_server, struct socket **csocket)
return rc;
}
+void reset_cifs_unix_caps(int xid, struct cifsTconInfo * tcon,
+ struct super_block * sb, struct smb_vol * vol_info)
+{
+ /* if we are reconnecting then should we check to see if
+ * any requested capabilities changed locally e.g. via
+ * remount but we can not do much about it here
+ * if they have (even if we could detect it by the following)
+ * Perhaps we could add a backpointer to array of sb from tcon
+ * or if we change to make all sb to same share the same
+ * sb as NFS - then we only have one backpointer to sb.
+ * What if we wanted to mount the server share twice once with
+ * and once without posixacls or posix paths? */
+ __u64 saved_cap = le64_to_cpu(tcon->fsUnixInfo.Capability);
+
+
+ if(!CIFSSMBQFSUnixInfo(xid, tcon)) {
+ __u64 cap = le64_to_cpu(tcon->fsUnixInfo.Capability);
+
+ /* check for reconnect case in which we do not
+ want to change the mount behavior if we can avoid it */
+ if(vol_info == NULL) {
+ /* turn off POSIX ACL and PATHNAMES if not set
+ originally at mount time */
+ if ((saved_cap & CIFS_UNIX_POSIX_ACL_CAP) == 0)
+ cap &= ~CIFS_UNIX_POSIX_ACL_CAP;
+ if ((saved_cap & CIFS_UNIX_POSIX_PATHNAMES_CAP) == 0)
+ cap &= ~CIFS_UNIX_POSIX_PATHNAMES_CAP;
+
+
+
+
+ }
+
+ cap &= CIFS_UNIX_CAP_MASK;
+ if(vol_info && vol_info->no_psx_acl)
+ cap &= ~CIFS_UNIX_POSIX_ACL_CAP;
+ else if(CIFS_UNIX_POSIX_ACL_CAP & cap) {
+ cFYI(1,("negotiated posix acl support"));
+ if(sb)
+ sb->s_flags |= MS_POSIXACL;
+ }
+
+ if(vol_info && vol_info->posix_paths == 0)
+ cap &= ~CIFS_UNIX_POSIX_PATHNAMES_CAP;
+ else if(cap & CIFS_UNIX_POSIX_PATHNAMES_CAP) {
+ cFYI(1,("negotiate posix pathnames"));
+ if(sb)
+ CIFS_SB(sb)->mnt_cifs_flags |=
+ CIFS_MOUNT_POSIX_PATHS;
+ }
+
+ cFYI(1,("Negotiate caps 0x%x",(int)cap));
+#ifdef CONFIG_CIFS_DEBUG2
+ if(cap & CIFS_UNIX_FCNTL_CAP)
+ cFYI(1,("FCNTL cap"));
+ if(cap & CIFS_UNIX_EXTATTR_CAP)
+ cFYI(1,("EXTATTR cap"));
+ if(cap & CIFS_UNIX_POSIX_PATHNAMES_CAP)
+ cFYI(1,("POSIX path cap"));
+ if(cap & CIFS_UNIX_XATTR_CAP)
+ cFYI(1,("XATTR cap"));
+ if(cap & CIFS_UNIX_POSIX_ACL_CAP)
+ cFYI(1,("POSIX ACL cap"));
+#endif /* CIFS_DEBUG2 */
+ if (CIFSSMBSetFSUnixInfo(xid, tcon, cap)) {
+ cFYI(1,("setting capabilities failed"));
+ }
+ }
+}
+
int
cifs_mount(struct super_block *sb, struct cifs_sb_info *cifs_sb,
char *mount_data, const char *devname)
@@ -1928,20 +1998,25 @@ cifs_mount(struct super_block *sb, struct cifs_sb_info *cifs_sb,
if (tcon == NULL)
rc = -ENOMEM;
else {
- /* check for null share name ie connect to dfs root */
+ /* check for null share name ie connecting to
+ * dfs root */
- /* BB check if this works for exactly length three strings */
+ /* BB check if this works for exactly length
+ * three strings */
if ((strchr(volume_info.UNC + 3, '\\') == NULL)
&& (strchr(volume_info.UNC + 3, '/') ==
NULL)) {
rc = connect_to_dfs_path(xid, pSesInfo,
- "", cifs_sb->local_nls,
- cifs_sb->mnt_cifs_flags &
- CIFS_MOUNT_MAP_SPECIAL_CHR);
+ "", cifs_sb->local_nls,
+ cifs_sb->mnt_cifs_flags &
+ CIFS_MOUNT_MAP_SPECIAL_CHR);
kfree(volume_info.UNC);
FreeXid(xid);
return -ENODEV;
} else {
+ /* BB Do we need to wrap sesSem around
+ * this TCon call and Unix SetFS as
+ * we do on SessSetup and reconnect? */
rc = CIFSTCon(xid, pSesInfo,
volume_info.UNC,
tcon, cifs_sb->local_nls);
@@ -1962,6 +2037,7 @@ cifs_mount(struct super_block *sb, struct cifs_sb_info *cifs_sb,
sb->s_maxbytes = (u64) 1 << 31; /* 2 GB */
}
+ /* BB FIXME fix time_gran to be larger for LANMAN sessions */
sb->s_time_gran = 100;
/* on error free sesinfo and tcon struct if needed */
@@ -2006,45 +2082,11 @@ cifs_mount(struct super_block *sb, struct cifs_sb_info *cifs_sb,
/* do not care if following two calls succeed - informational */
CIFSSMBQFSDeviceInfo(xid, tcon);
CIFSSMBQFSAttributeInfo(xid, tcon);
-
- if (tcon->ses->capabilities & CAP_UNIX) {
- if(!CIFSSMBQFSUnixInfo(xid, tcon)) {
- __u64 cap =
- le64_to_cpu(tcon->fsUnixInfo.Capability);
- cap &= CIFS_UNIX_CAP_MASK;
- if(volume_info.no_psx_acl)
- cap &= ~CIFS_UNIX_POSIX_ACL_CAP;
- else if(CIFS_UNIX_POSIX_ACL_CAP & cap) {
- cFYI(1,("negotiated posix acl support"));
- sb->s_flags |= MS_POSIXACL;
- }
-
- if(volume_info.posix_paths == 0)
- cap &= ~CIFS_UNIX_POSIX_PATHNAMES_CAP;
- else if(cap & CIFS_UNIX_POSIX_PATHNAMES_CAP) {
- cFYI(1,("negotiate posix pathnames"));
- cifs_sb->mnt_cifs_flags |=
- CIFS_MOUNT_POSIX_PATHS;
- }
-
- cFYI(1,("Negotiate caps 0x%x",(int)cap));
-#ifdef CONFIG_CIFS_DEBUG2
- if(cap & CIFS_UNIX_FCNTL_CAP)
- cFYI(1,("FCNTL cap"));
- if(cap & CIFS_UNIX_EXTATTR_CAP)
- cFYI(1,("EXTATTR cap"));
- if(cap & CIFS_UNIX_POSIX_PATHNAMES_CAP)
- cFYI(1,("POSIX path cap"));
- if(cap & CIFS_UNIX_XATTR_CAP)
- cFYI(1,("XATTR cap"));
- if(cap & CIFS_UNIX_POSIX_ACL_CAP)
- cFYI(1,("POSIX ACL cap"));
-#endif /* CIFS_DEBUG2 */
- if (CIFSSMBSetFSUnixInfo(xid, tcon, cap)) {
- cFYI(1,("setting capabilities failed"));
- }
- }
- }
+
+ /* tell server which Unix caps we support */
+ if (tcon->ses->capabilities & CAP_UNIX)
+ reset_cifs_unix_caps(xid, tcon, sb, &volume_info);
+
if (!(tcon->ses->capabilities & CAP_LARGE_WRITE_X))
cifs_sb->wsize = min(cifs_sb->wsize,
(tcon->ses->server->maxBuf -
diff --git a/fs/cifs/file.c b/fs/cifs/file.c
index e9dcf5ee29a2..07ff9351e9ee 100644
--- a/fs/cifs/file.c
+++ b/fs/cifs/file.c
@@ -1954,7 +1954,7 @@ static int cifs_readpage(struct file *file, struct page *page)
refreshing the inode only on increases in the file size
but this is tricky to do without racing with writebehind
page caching in the current Linux kernel design */
-int is_size_safe_to_change(struct cifsInodeInfo *cifsInode)
+int is_size_safe_to_change(struct cifsInodeInfo *cifsInode, __u64 end_of_file)
{
struct cifsFileInfo *open_file = NULL;
@@ -1976,6 +1976,9 @@ int is_size_safe_to_change(struct cifsInodeInfo *cifsInode)
return 1;
}
+ if(i_size_read(&cifsInode->vfs_inode) < end_of_file)
+ return 1;
+
return 0;
} else
return 1;
diff --git a/fs/cifs/inode.c b/fs/cifs/inode.c
index c4fa91b8b62f..3f5bc83dc3d1 100644
--- a/fs/cifs/inode.c
+++ b/fs/cifs/inode.c
@@ -140,7 +140,7 @@ int cifs_get_inode_info_unix(struct inode **pinode,
inode->i_gid = le64_to_cpu(findData.Gid);
inode->i_nlink = le64_to_cpu(findData.Nlinks);
- if (is_size_safe_to_change(cifsInfo)) {
+ if (is_size_safe_to_change(cifsInfo, end_of_file)) {
/* can not safely change the file size here if the
client is writing to it due to potential races */
@@ -491,8 +491,8 @@ int cifs_get_inode_info(struct inode **pinode,
/* BB add code here -
validate if device or weird share or device type? */
}
- if (is_size_safe_to_change(cifsInfo)) {
- /* can not safely change the file size here if the
+ if (is_size_safe_to_change(cifsInfo, le64_to_cpu(pfindData->EndOfFile))) {
+ /* can not safely shrink the file size here if the
client is writing to it due to potential races */
i_size_write(inode,le64_to_cpu(pfindData->EndOfFile));
diff --git a/fs/cifs/readdir.c b/fs/cifs/readdir.c
index 782940be550f..c6220bd27165 100644
--- a/fs/cifs/readdir.c
+++ b/fs/cifs/readdir.c
@@ -222,7 +222,7 @@ static void fill_in_inode(struct inode *tmp_inode, int new_buf_type,
atomic_set(&cifsInfo->inUse, 1);
}
- if (is_size_safe_to_change(cifsInfo)) {
+ if (is_size_safe_to_change(cifsInfo, end_of_file)) {
/* can not safely change the file size here if the
client is writing to it due to potential races */
i_size_write(tmp_inode, end_of_file);
@@ -351,10 +351,10 @@ static void unix_fill_in_inode(struct inode *tmp_inode,
tmp_inode->i_gid = le64_to_cpu(pfindData->Gid);
tmp_inode->i_nlink = le64_to_cpu(pfindData->Nlinks);
- if (is_size_safe_to_change(cifsInfo)) {
+ if (is_size_safe_to_change(cifsInfo, end_of_file)) {
/* can not safely change the file size here if the
client is writing to it due to potential races */
- i_size_write(tmp_inode,end_of_file);
+ i_size_write(tmp_inode, end_of_file);
/* 512 bytes (2**9) is the fake blocksize that must be used */
/* for this calculation, not the real blocksize */
diff --git a/fs/dcache.c b/fs/dcache.c
index b5f613932912..d68631f18df1 100644
--- a/fs/dcache.c
+++ b/fs/dcache.c
@@ -1739,41 +1739,45 @@ shouldnt_be_hashed:
* @rootmnt: vfsmnt to which the root dentry belongs
* @buffer: buffer to return value in
* @buflen: buffer length
- * @fail_deleted: what to return for deleted files
*
- * Convert a dentry into an ASCII path name. If the entry has been deleted,
- * then if @fail_deleted is true, ERR_PTR(-ENOENT) is returned. Otherwise,
- * the the string " (deleted)" is appended. Note that this is ambiguous.
+ * Convert a dentry into an ASCII path name. If the entry has been deleted
+ * the string " (deleted)" is appended. Note that this is ambiguous.
*
- * Returns the buffer or an error code.
+ * Returns the buffer or an error code if the path was too long.
+ *
+ * "buflen" should be positive. Caller holds the dcache_lock.
*/
-static char *__d_path(struct dentry *dentry, struct vfsmount *vfsmnt,
- struct dentry *root, struct vfsmount *rootmnt,
- char *buffer, int buflen, int fail_deleted)
+static char * __d_path( struct dentry *dentry, struct vfsmount *vfsmnt,
+ struct dentry *root, struct vfsmount *rootmnt,
+ char *buffer, int buflen)
{
- int namelen, is_slash;
-
- if (buflen < 2)
- return ERR_PTR(-ENAMETOOLONG);
- buffer += --buflen;
- *buffer = '\0';
+ char * end = buffer+buflen;
+ char * retval;
+ int namelen;
- spin_lock(&dcache_lock);
+ *--end = '\0';
+ buflen--;
if (!IS_ROOT(dentry) && d_unhashed(dentry)) {
- if (fail_deleted) {
- buffer = ERR_PTR(-ENOENT);
- goto out;
- }
- if (buflen < 10)
- goto Elong;
buflen -= 10;
- buffer -= 10;
- memcpy(buffer, " (deleted)", 10);
+ end -= 10;
+ if (buflen < 0)
+ goto Elong;
+ memcpy(end, " (deleted)", 10);
}
- while (dentry != root || vfsmnt != rootmnt) {
+
+ if (buflen < 1)
+ goto Elong;
+ /* Get '/' right */
+ retval = end-1;
+ *retval = '/';
+
+ for (;;) {
struct dentry * parent;
+ if (dentry == root && vfsmnt == rootmnt)
+ break;
if (dentry == vfsmnt->mnt_root || IS_ROOT(dentry)) {
+ /* Global root? */
spin_lock(&vfsmount_lock);
if (vfsmnt->mnt_parent == vfsmnt) {
spin_unlock(&vfsmount_lock);
@@ -1787,60 +1791,33 @@ static char *__d_path(struct dentry *dentry, struct vfsmount *vfsmnt,
parent = dentry->d_parent;
prefetch(parent);
namelen = dentry->d_name.len;
- if (buflen <= namelen)
- goto Elong;
buflen -= namelen + 1;
- buffer -= namelen;
- memcpy(buffer, dentry->d_name.name, namelen);
- *--buffer = '/';
+ if (buflen < 0)
+ goto Elong;
+ end -= namelen;
+ memcpy(end, dentry->d_name.name, namelen);
+ *--end = '/';
+ retval = end;
dentry = parent;
}
- /* Get '/' right */
- if (*buffer != '/')
- *--buffer = '/';
-out:
- spin_unlock(&dcache_lock);
- return buffer;
+ return retval;
global_root:
- /*
- * We went past the (vfsmount, dentry) we were looking for and have
- * either hit a root dentry, a lazily unmounted dentry, an
- * unconnected dentry, or the file is on a pseudo filesystem.
- */
namelen = dentry->d_name.len;
- is_slash = (namelen == 1 && *dentry->d_name.name == '/');
- if (is_slash || (dentry->d_sb->s_flags & MS_NOUSER)) {
- /*
- * Make sure we won't return a pathname starting with '/'.
- *
- * Historically, we also glue together the root dentry and
- * remaining name for pseudo filesystems like pipefs, which
- * have the MS_NOUSER flag set. This results in pathnames
- * like "pipe:[439336]".
- */
- if (*buffer == '/') {
- buffer++;
- buflen++;
- }
- if (is_slash)
- goto out;
- }
- if (buflen < namelen)
+ buflen -= namelen;
+ if (buflen < 0)
goto Elong;
- buffer -= namelen;
- memcpy(buffer, dentry->d_name.name, namelen);
- goto out;
-
+ retval -= namelen-1; /* hit the slash */
+ memcpy(retval, dentry->d_name.name, namelen);
+ return retval;
Elong:
- buffer = ERR_PTR(-ENAMETOOLONG);
- goto out;
+ return ERR_PTR(-ENAMETOOLONG);
}
/* write full pathname into buffer and return start of pathname */
-char *d_path(struct dentry *dentry, struct vfsmount *vfsmnt, char *buf,
- int buflen)
+char * d_path(struct dentry *dentry, struct vfsmount *vfsmnt,
+ char *buf, int buflen)
{
char *res;
struct vfsmount *rootmnt;
@@ -1850,7 +1827,9 @@ char *d_path(struct dentry *dentry, struct vfsmount *vfsmnt, char *buf,
rootmnt = mntget(current->fs->rootmnt);
root = dget(current->fs->root);
read_unlock(&current->fs->lock);
- res = __d_path(dentry, vfsmnt, root, rootmnt, buf, buflen, 0);
+ spin_lock(&dcache_lock);
+ res = __d_path(dentry, vfsmnt, root, rootmnt, buf, buflen);
+ spin_unlock(&dcache_lock);
dput(root);
mntput(rootmnt);
return res;
@@ -1876,10 +1855,10 @@ char *d_path(struct dentry *dentry, struct vfsmount *vfsmnt, char *buf,
*/
asmlinkage long sys_getcwd(char __user *buf, unsigned long size)
{
- int error, len;
+ int error;
struct vfsmount *pwdmnt, *rootmnt;
struct dentry *pwd, *root;
- char *page = (char *) __get_free_page(GFP_USER), *cwd;
+ char *page = (char *) __get_free_page(GFP_USER);
if (!page)
return -ENOMEM;
@@ -1891,18 +1870,29 @@ asmlinkage long sys_getcwd(char __user *buf, unsigned long size)
root = dget(current->fs->root);
read_unlock(&current->fs->lock);
- cwd = __d_path(pwd, pwdmnt, root, rootmnt, page, PAGE_SIZE, 1);
- error = PTR_ERR(cwd);
- if (IS_ERR(cwd))
- goto out;
+ error = -ENOENT;
+ /* Has the current directory has been unlinked? */
+ spin_lock(&dcache_lock);
+ if (pwd->d_parent == pwd || !d_unhashed(pwd)) {
+ unsigned long len;
+ char * cwd;
- error = -ERANGE;
- len = PAGE_SIZE + page - cwd;
- if (len <= size) {
- error = len;
- if (copy_to_user(buf, cwd, len))
- error = -EFAULT;
- }
+ cwd = __d_path(pwd, pwdmnt, root, rootmnt, page, PAGE_SIZE);
+ spin_unlock(&dcache_lock);
+
+ error = PTR_ERR(cwd);
+ if (IS_ERR(cwd))
+ goto out;
+
+ error = -ERANGE;
+ len = PAGE_SIZE + page - cwd;
+ if (len <= size) {
+ error = len;
+ if (copy_to_user(buf, cwd, len))
+ error = -EFAULT;
+ }
+ } else
+ spin_unlock(&dcache_lock);
out:
dput(pwd);