From f654bac2227adc5c6956405290eeb4f81f09e9ff Mon Sep 17 00:00:00 2001 From: Steve French Date: Thu, 28 Apr 2005 22:41:04 -0700 Subject: [PATCH] [PATCH] cifs: add support for chattr/lsattr in new CIFS POSIX extensions Signed-off-by: Steve French (sfrench@us.ibm.com) Signed-off-by: Linus Torvalds --- fs/cifs/CHANGES | 9 ++++- fs/cifs/cifsfs.h | 6 ++-- fs/cifs/cifspdu.h | 67 ++++++++++++++++++++++++++++++++--- fs/cifs/cifsproto.h | 4 ++- fs/cifs/cifssmb.c | 86 ++++++++++++++++++++++++++++++++++++++++++++- fs/cifs/ioctl.c | 52 +++++++++++++++++++++++++-- 6 files changed, 211 insertions(+), 13 deletions(-) diff --git a/fs/cifs/CHANGES b/fs/cifs/CHANGES index 5316c8dd6bff..7fd02697b12e 100644 --- a/fs/cifs/CHANGES +++ b/fs/cifs/CHANGES @@ -1,7 +1,14 @@ -Version 1.31 +Version 1.32 ------------ Fix oops in ls when Transact2 FindFirst (or FindNext) returns more than one transact response for an SMB request and search entry split across two frames. +Add support for lsattr (getting ext2/ext3/reiserfs attr flags from the server) +as new protocol extensions. Do not send Get/Set calls for POSIX ACLs +unless server explicitly claims to support them in CIFS Unix extensions +POSIX ACL capability bit. + +Version 1.31 +------------ Fix updates of DOS attributes and time fields so that files on NT4 servers do not get marked delete on close. Display sizes of cifs buffer pools in cifs stats. Fix oops in unmount when cifsd thread being killed by diff --git a/fs/cifs/cifsfs.h b/fs/cifs/cifsfs.h index 451f18af3206..e0e46f4bff97 100644 --- a/fs/cifs/cifsfs.h +++ b/fs/cifs/cifsfs.h @@ -91,8 +91,10 @@ extern int cifs_symlink(struct inode *inode, struct dentry *direntry, const char *symname); extern int cifs_removexattr(struct dentry *, const char *); extern int cifs_setxattr(struct dentry *, const char *, const void *, - size_t, int); + size_t, int); extern ssize_t cifs_getxattr(struct dentry *, const char *, void *, size_t); extern ssize_t cifs_listxattr(struct dentry *, char *, size_t); -#define CIFS_VERSION "1.31" +extern int cifs_ioctl (struct inode * inode, struct file * filep, + unsigned int command, unsigned long arg); +#define CIFS_VERSION "1.32" #endif /* _CIFSFS_H */ diff --git a/fs/cifs/cifspdu.h b/fs/cifs/cifspdu.h index bcd4a6136f08..085109d2b55e 100644 --- a/fs/cifs/cifspdu.h +++ b/fs/cifs/cifspdu.h @@ -762,6 +762,16 @@ typedef struct smb_com_lock_req { LOCKING_ANDX_RANGE Locks[1]; } LOCK_REQ; + +typedef struct cifs_posix_lock { + __le16 lock_type; /* 0 = Read, 1 = Write, 2 = Unlock */ + __le16 lock_flags; /* 1 = Wait (only valid for setlock) */ + __le32 pid; + __le64 start; + __le64 length; + /* BB what about additional owner info to identify network client */ +} CIFS_POSIX_LOCK; + typedef struct smb_com_lock_rsp { struct smb_hdr hdr; /* wct = 2 */ __u8 AndXCommand; @@ -1098,6 +1108,8 @@ struct smb_t2_rsp { #define SMB_QUERY_POSIX_ACL 0x204 #define SMB_QUERY_XATTR 0x205 #define SMB_QUERY_ATTR_FLAGS 0x206 /* append,immutable etc. */ +#define SMB_QUERY_POSIX_PERMISSION 0x207 +#define SMB_QUERY_POSIX_LOCK 0x208 #define SMB_QUERY_FILE_INTERNAL_INFO 0x3ee #define SMB_QUERY_FILE_ACCESS_INFO 0x3f0 #define SMB_QUERY_FILE_NAME_INFO2 0x3f1 /* 0x30 bytes */ @@ -1116,6 +1128,7 @@ struct smb_t2_rsp { #define SMB_SET_POSIX_ACL 0x204 #define SMB_SET_XATTR 0x205 #define SMB_SET_ATTR_FLAGS 0x206 /* append, immutable etc. */ +#define SMB_SET_POSIX_LOCK 0x208 #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 @@ -1237,9 +1250,27 @@ struct smb_com_transaction2_sfi_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 reserved - + present for infolevels > 100 */ }; +struct smb_t2_qfi_req { + struct smb_hdr hdr; + struct trans2_req t2; + __u8 Pad; + __u16 Pad1; + __u16 Fid; + __le16 InformationLevel; + __u16 Pad2; +}; + +struct smb_t2_qfi_rsp { + struct smb_hdr hdr; /* wct = 10 + SetupCount */ + struct trans2_resp t2; + __u16 ByteCount; + __u16 Reserved2; /* parameter word reserved - + present for infolevels > 100 */ +}; /* * Flags on T2 FINDFIRST and FINDNEXT @@ -1524,8 +1555,9 @@ typedef struct { } FILE_SYSTEM_UNIX_INFO; /* Unix extensions info, level 0x200 */ /* Linux/Unix extensions capability flags */ #define CIFS_UNIX_FCNTL_CAP 0x00000001 /* support for fcntl locks */ -#define CIFS_UNIX_POSIX_ACL_CAP 0x00000002 -#define CIFS_UNIX_XATTR_CAP 0x00000004 /*support for new namespace*/ +#define CIFS_UNIX_POSIX_ACL_CAP 0x00000002 /* support getfacl/setfacl */ +#define CIFS_UNIX_XATTR_CAP 0x00000004 /* support new namespace */ +#define CIFS_UNIX_EXTATTR_CAP 0x00000008 /* support chattr/chflag */ typedef struct { /* For undefined recommended transfer size return -1 in that field */ @@ -1971,15 +2003,40 @@ struct xsymlink { char path[1024]; }; -typedef struct { +typedef struct file_xattr_info { /* BB do we need another field for flags? BB */ __u32 xattr_name_len; __u32 xattr_value_len; char xattr_name[0]; /* followed by xattr_value[xattr_value_len], no pad */ -} FILE_XATTR_INFO; /* extended attribute, info level 205 */ +} FILE_XATTR_INFO; /* extended attribute, info level 0x205 */ +/* flags for chattr command */ +#define EXT_SECURE_DELETE 0x00000001 /* EXT3_SECRM_FL */ +#define EXT_ENABLE_UNDELETE 0x00000002 /* EXT3_UNRM_FL */ +/* Reserved for compress file 0x4 */ +#define EXT_SYNCHRONOUS 0x00000008 /* EXT3_SYNC_FL */ +#define EXT_IMMUTABLE_FL 0x00000010 /* EXT3_IMMUTABLE_FL */ +#define EXT_OPEN_APPEND_ONLY 0x00000020 /* EXT3_APPEND_FL */ +#define EXT_DO_NOT_BACKUP 0x00000040 /* EXT3_NODUMP_FL */ +#define EXT_NO_UPDATE_ATIME 0x00000080 /* EXT3_NOATIME_FL */ +/* 0x100 through 0x800 reserved for compression flags and are GET-ONLY */ +#define EXT_HASH_TREE_INDEXED_DIR 0x00001000 /* GET-ONLY EXT3_INDEX_FL */ +/* 0x2000 reserved for IMAGIC_FL */ +#define EXT_JOURNAL_THIS_FILE 0x00004000 /* GET-ONLY EXT3_JOURNAL_DATA_FL */ +/* 0x8000 reserved for EXT3_NOTAIL_FL */ +#define EXT_SYNCHRONOUS_DIR 0x00010000 /* EXT3_DIRSYNC_FL */ +#define EXT_TOPDIR 0x00020000 /* EXT3_TOPDIR_FL */ + +#define EXT_SET_MASK 0x000300FF +#define EXT_GET_MASK 0x0003DFFF + +typedef struct file_chattr_info { + __le64 mask; /* list of all possible attribute bits */ + __le64 mode; /* list of actual attribute bits on this inode */ +} FILE_CHATTR_INFO; /* ext attributes (chattr, chflags) level 0x206 */ + #endif #pragma pack() /* resume default structure packing */ diff --git a/fs/cifs/cifsproto.h b/fs/cifs/cifsproto.h index 787eef4d86d3..82ae59d7cf9d 100644 --- a/fs/cifs/cifsproto.h +++ b/fs/cifs/cifsproto.h @@ -264,6 +264,8 @@ extern int CIFSSMBSetPosixACL(const int xid, struct cifsTconInfo *tcon, const unsigned char *fileName, const char *local_acl, const int buflen, const int acl_type, const struct nls_table *nls_codepage); -int cifs_ioctl (struct inode * inode, struct file * filep, +extern int CIFSGetExtAttr(const int xid, struct cifsTconInfo *tcon, + const int netfid, __u64 * pExtAttrBits, __u64 *pMask); +extern int cifs_ioctl (struct inode * inode, struct file * filep, unsigned int command, unsigned long arg); #endif /* _CIFSPROTO_H */ diff --git a/fs/cifs/cifssmb.c b/fs/cifs/cifssmb.c index df6a619a6821..36d3c128a58b 100644 --- a/fs/cifs/cifssmb.c +++ b/fs/cifs/cifssmb.c @@ -2072,7 +2072,91 @@ CIFSSMBSetPosixACL(const int xid, struct cifsTconInfo *tcon, return rc; } -#endif +/* BB fix tabs in this function FIXME BB */ +int +CIFSGetExtAttr(const int xid, struct cifsTconInfo *tcon, + const int netfid, __u64 * pExtAttrBits, __u64 *pMask) +{ + int rc = 0; + struct smb_t2_qfi_req *pSMB = NULL; + struct smb_t2_qfi_rsp *pSMBr = NULL; + int bytes_returned; + __u16 params, byte_count; + + cFYI(1,("In GetExtAttr")); + if(tcon == NULL) + return -ENODEV; + +GetExtAttrRetry: + rc = smb_init(SMB_COM_TRANSACTION2, 15, tcon, (void **) &pSMB, + (void **) &pSMBr); + if (rc) + return rc; + + params = 2 /* level */ +2 /* fid */ + 2 /* rsrvd */; + pSMB->t2.TotalDataCount = 0; + pSMB->t2.MaxParameterCount = cpu_to_le16(2); + /* BB find exact max data count below from sess structure BB */ + pSMB->t2.MaxDataCount = cpu_to_le16(4000); + pSMB->t2.MaxSetupCount = 0; + pSMB->t2.Reserved = 0; + pSMB->t2.Flags = 0; + pSMB->t2.Timeout = 0; + pSMB->t2.Reserved2 = 0; + pSMB->t2.ParameterOffset = cpu_to_le16(offsetof( + struct smb_com_transaction2_qpi_req ,InformationLevel) - 4); + pSMB->t2.DataCount = 0; + pSMB->t2.DataOffset = 0; + pSMB->t2.SetupCount = 1; + pSMB->t2.Reserved3 = 0; + pSMB->t2.SubCommand = cpu_to_le16(TRANS2_QUERY_FILE_INFORMATION); + byte_count = params + 3 /* pad */ ; + pSMB->t2.TotalParameterCount = cpu_to_le16(params); + pSMB->t2.ParameterCount = pSMB->t2.TotalParameterCount; + pSMB->InformationLevel = cpu_to_le16(SMB_QUERY_ATTR_FLAGS); + pSMB->Pad1 = 0; + pSMB->Pad2 = 0; + pSMB->Fid = netfid; + pSMB->hdr.smb_buf_length += byte_count; + pSMB->t2.ByteCount = cpu_to_le16(byte_count); + + rc = SendReceive(xid, tcon->ses, (struct smb_hdr *) pSMB, + (struct smb_hdr *) pSMBr, &bytes_returned, 0); + if (rc) { + cFYI(1, ("error %d in GetExtAttr", rc)); + } else { + /* decode response */ + rc = validate_t2((struct smb_t2_rsp *)pSMBr); + if (rc || (pSMBr->ByteCount < 2)) + /* BB also check enough total bytes returned */ + /* If rc should we check for EOPNOSUPP and + disable the srvino flag? or in caller? */ + rc = -EIO; /* bad smb */ + else { + __u16 data_offset = le16_to_cpu(pSMBr->t2.DataOffset); + __u16 count = le16_to_cpu(pSMBr->t2.DataCount); + struct file_chattr_info * pfinfo; + /* BB Do we need a cast or hash here ? */ + if(count != 16) { + cFYI(1, ("Illegal size ret in GetExtAttr")); + rc = -EIO; + goto GetExtAttrOut; + } + pfinfo = (struct file_chattr_info *) + (data_offset + (char *) &pSMBr->hdr.Protocol); + *pExtAttrBits = le64_to_cpu(pfinfo->mode); + *pMask = le64_to_cpu(pfinfo->mask); + } + } +GetExtAttrOut: + cifs_buf_release(pSMB); + if (rc == -EAGAIN) + goto GetExtAttrRetry; + return rc; +} + + +#endif /* CONFIG_POSIX */ int CIFSSMBQPathInfo(const int xid, struct cifsTconInfo *tcon, diff --git a/fs/cifs/ioctl.c b/fs/cifs/ioctl.c index b4b8e201d428..7b84b2bb8c4a 100644 --- a/fs/cifs/ioctl.c +++ b/fs/cifs/ioctl.c @@ -20,6 +20,7 @@ * along with this library; if not, write to the Free Software * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA */ + #include #include #include "cifspdu.h" @@ -32,18 +33,63 @@ int cifs_ioctl (struct inode * inode, struct file * filep, { int rc = -ENOTTY; /* strange error - but the precedent */ #ifdef CONFIG_CIFS_POSIX + __u64 ExtAttrBits = 0; + __u64 ExtAttrMask = 0; + __u64 caps; +#endif /* CONFIG_CIFS_POSIX */ + int xid; + struct cifs_sb_info *cifs_sb; + struct cifsTconInfo *tcon; + struct cifsFileInfo *pSMBFile = + (struct cifsFileInfo *)filep->private_data; + + xid = GetXid(); + + cifs_sb = CIFS_SB(inode->i_sb); + tcon = cifs_sb->tcon; + if (pSMBFile == NULL) + goto cifs_ioctl_out; + +#ifdef CONFIG_CIFS_POSIX + if(tcon) + caps = le64_to_cpu(tcon->fsUnixInfo.Capability); + else { + rc = -EIO; + goto cifs_ioctl_out; + } + cFYI(1,("ioctl file %p cmd %u arg %lu",filep,command,arg)); switch(command) { case EXT2_IOC_GETFLAGS: - cFYI(1,("get flags not implemented yet")); - return -EOPNOTSUPP; + if(CIFS_UNIX_EXTATTR_CAP & caps) { + rc = CIFSGetExtAttr(xid, tcon, pSMBFile->netfid, + &ExtAttrBits, &ExtAttrMask); + if(rc == 0) + rc = put_user(ExtAttrBits & + EXT2_FL_USER_VISIBLE, + (int __user *)arg); + } + break; + case EXT2_IOC_SETFLAGS: + if(CIFS_UNIX_EXTATTR_CAP & caps) { + if(get_user(ExtAttrBits,(int __user *)arg)) { + rc = -EFAULT; + goto cifs_ioctl_out; + } + /* rc = CIFSGetExtAttr(xid, tcon, pSMBFile->netfid, + extAttrBits, &ExtAttrMask);*/ + + } cFYI(1,("set flags not implemented yet")); - return -EOPNOTSUPP; + break; default: cFYI(1,("unsupported ioctl")); return rc; } #endif /* CONFIG_CIFS_POSIX */ + +cifs_ioctl_out: + FreeXid(xid); return rc; }