From 8b94bcb923dff923a5a5b7c6f890702a54cb19cf Mon Sep 17 00:00:00 2001 From: Steve French Date: Fri, 11 Nov 2005 11:41:00 -0800 Subject: [CIFS] Fix CIFS "nobrl" mount option so does not disable sending brl requests for all mounts just that particular mount. Found by Arjan Vand de Ven Signed-off-by: Steve French --- fs/cifs/cifsfs.c | 40 ++++++++++++++++++++++++++++++++++++++++ fs/cifs/cifsfs.h | 2 ++ fs/cifs/inode.c | 40 +++++++++++++++++++++++++--------------- fs/cifs/readdir.c | 10 ++++++++-- 4 files changed, 75 insertions(+), 17 deletions(-) diff --git a/fs/cifs/cifsfs.c b/fs/cifs/cifsfs.c index 682b0235ad9a17..1433455c61eafa 100644 --- a/fs/cifs/cifsfs.c +++ b/fs/cifs/cifsfs.c @@ -635,6 +635,46 @@ struct file_operations cifs_file_direct_ops = { .dir_notify = cifs_dir_notify, #endif /* CONFIG_CIFS_EXPERIMENTAL */ }; +struct file_operations cifs_file_nobrl_ops = { + .read = cifs_read_wrapper, + .write = cifs_write_wrapper, + .open = cifs_open, + .release = cifs_close, + .fsync = cifs_fsync, + .flush = cifs_flush, + .mmap = cifs_file_mmap, + .sendfile = generic_file_sendfile, +#ifdef CONFIG_CIFS_POSIX + .ioctl = cifs_ioctl, +#endif /* CONFIG_CIFS_POSIX */ + +#ifdef CONFIG_CIFS_EXPERIMENTAL + .readv = generic_file_readv, + .writev = generic_file_writev, + .aio_read = generic_file_aio_read, + .aio_write = generic_file_aio_write, + .dir_notify = cifs_dir_notify, +#endif /* CONFIG_CIFS_EXPERIMENTAL */ +}; + +struct file_operations cifs_file_direct_nobrl_ops = { + /* no mmap, no aio, no readv - + BB reevaluate whether they can be done with directio, no cache */ + .read = cifs_user_read, + .write = cifs_user_write, + .open = cifs_open, + .release = cifs_close, + .fsync = cifs_fsync, + .flush = cifs_flush, + .sendfile = generic_file_sendfile, /* BB removeme BB */ +#ifdef CONFIG_CIFS_POSIX + .ioctl = cifs_ioctl, +#endif /* CONFIG_CIFS_POSIX */ + +#ifdef CONFIG_CIFS_EXPERIMENTAL + .dir_notify = cifs_dir_notify, +#endif /* CONFIG_CIFS_EXPERIMENTAL */ +}; struct file_operations cifs_dir_ops = { .readdir = cifs_readdir, diff --git a/fs/cifs/cifsfs.h b/fs/cifs/cifsfs.h index 1223fa81dbd269..9ec40e0e54fc4e 100644 --- a/fs/cifs/cifsfs.h +++ b/fs/cifs/cifsfs.h @@ -63,6 +63,8 @@ extern struct inode_operations cifs_symlink_inode_ops; /* Functions related to files and directories */ extern struct file_operations cifs_file_ops; extern struct file_operations cifs_file_direct_ops; /* if directio mount */ +extern struct file_operations cifs_file_nobrl_ops; +extern struct file_operations cifs_file_direct_nobrl_ops; /* if directio mount */ extern int cifs_open(struct inode *inode, struct file *file); extern int cifs_close(struct inode *inode, struct file *file); extern int cifs_closedir(struct inode *inode, struct file *file); diff --git a/fs/cifs/inode.c b/fs/cifs/inode.c index 923d071163b276..941b247fceb024 100644 --- a/fs/cifs/inode.c +++ b/fs/cifs/inode.c @@ -155,34 +155,39 @@ int cifs_get_inode_info_unix(struct inode **pinode, } if (num_of_bytes < end_of_file) - cFYI(1, ("allocation size less than end of file ")); + cFYI(1, ("allocation size less than end of file")); cFYI(1, ("Size %ld and blocks %ld", (unsigned long) inode->i_size, inode->i_blocks)); if (S_ISREG(inode->i_mode)) { - cFYI(1, (" File inode ")); + cFYI(1, ("File inode")); inode->i_op = &cifs_file_inode_ops; - if (cifs_sb->mnt_cifs_flags & CIFS_MOUNT_DIRECT_IO) - inode->i_fop = &cifs_file_direct_ops; - else + if (cifs_sb->mnt_cifs_flags & CIFS_MOUNT_DIRECT_IO) { + if (cifs_sb->mnt_cifs_flags & CIFS_MOUNT_NO_BRL) + inode->i_fop = + &cifs_file_direct_nobrl_ops; + else + inode->i_fop = &cifs_file_direct_ops; + } else if(cifs_sb->mnt_cifs_flags & CIFS_MOUNT_NO_BRL) + inode->i_fop = &cifs_file_nobrl_ops; + else /* not direct, send byte range locks */ inode->i_fop = &cifs_file_ops; - if(cifs_sb->mnt_cifs_flags & CIFS_MOUNT_NO_BRL) - inode->i_fop->lock = NULL; + inode->i_data.a_ops = &cifs_addr_ops; /* check if server can support readpages */ if(pTcon->ses->server->maxBuf < 4096 + MAX_CIFS_HDR_SIZE) inode->i_data.a_ops->readpages = NULL; } else if (S_ISDIR(inode->i_mode)) { - cFYI(1, (" Directory inode")); + cFYI(1, ("Directory inode")); inode->i_op = &cifs_dir_inode_ops; inode->i_fop = &cifs_dir_ops; } else if (S_ISLNK(inode->i_mode)) { - cFYI(1, (" Symbolic Link inode ")); + cFYI(1, ("Symbolic Link inode")); inode->i_op = &cifs_symlink_inode_ops; /* tmp_inode->i_fop = */ /* do not need to set to anything */ } else { - cFYI(1, (" Init special inode ")); + cFYI(1, ("Init special inode")); init_special_inode(inode, inode->i_mode, inode->i_rdev); } @@ -379,12 +384,17 @@ int cifs_get_inode_info(struct inode **pinode, if (S_ISREG(inode->i_mode)) { cFYI(1, (" File inode ")); inode->i_op = &cifs_file_inode_ops; - if (cifs_sb->mnt_cifs_flags & CIFS_MOUNT_DIRECT_IO) - inode->i_fop = &cifs_file_direct_ops; - else + if (cifs_sb->mnt_cifs_flags & CIFS_MOUNT_DIRECT_IO) { + if (cifs_sb->mnt_cifs_flags & CIFS_MOUNT_NO_BRL) + inode->i_fop = + &cifs_file_direct_nobrl_ops; + else + inode->i_fop = &cifs_file_direct_ops; + } else if(cifs_sb->mnt_cifs_flags & CIFS_MOUNT_NO_BRL) + inode->i_fop = &cifs_file_nobrl_ops; + else /* not direct, send byte range locks */ inode->i_fop = &cifs_file_ops; - if(cifs_sb->mnt_cifs_flags & CIFS_MOUNT_NO_BRL) - inode->i_fop->lock = NULL; + inode->i_data.a_ops = &cifs_addr_ops; if(pTcon->ses->server->maxBuf < 4096 + MAX_CIFS_HDR_SIZE) diff --git a/fs/cifs/readdir.c b/fs/cifs/readdir.c index a86bd1c076021b..fc615670f4b8b7 100644 --- a/fs/cifs/readdir.c +++ b/fs/cifs/readdir.c @@ -193,8 +193,14 @@ static void fill_in_inode(struct inode *tmp_inode, if (S_ISREG(tmp_inode->i_mode)) { cFYI(1, ("File inode")); tmp_inode->i_op = &cifs_file_inode_ops; - if(cifs_sb->mnt_cifs_flags & CIFS_MOUNT_DIRECT_IO) - tmp_inode->i_fop = &cifs_file_direct_ops; + if(cifs_sb->mnt_cifs_flags & CIFS_MOUNT_DIRECT_IO) { + if(cifs_sb->mnt_cifs_flags & CIFS_MOUNT_NO_BRL) + tmp_inode->i_fop = &cifs_file_direct_nobrl_ops; + else + tmp_inode->i_fop = &cifs_file_direct_ops; + + } else if(cifs_sb->mnt_cifs_flags & CIFS_MOUNT_NO_BRL) + tmp_inode->i_fop = &cifs_file_nobrl_ops; else tmp_inode->i_fop = &cifs_file_ops; if(cifs_sb->mnt_cifs_flags & CIFS_MOUNT_NO_BRL) -- cgit 1.2.3-korg From e89dc9209692293434da45ec31826a55becb91c0 Mon Sep 17 00:00:00 2001 From: Steve French Date: Fri, 11 Nov 2005 15:18:19 -0800 Subject: [CIFS] Cleanup sparse warnings for unicode little endian casts Following Shaggy's suggestion, do a better job on the unicode string handling routines in cifs in specifying that the wchar_t are really little endian widechars (__le16). Signed-off-by: Steve French --- fs/cifs/cifs_unicode.c | 13 ++++---- fs/cifs/cifs_unicode.h | 6 ++-- fs/cifs/cifsencrypt.c | 2 +- fs/cifs/cifssmb.c | 12 +++---- fs/cifs/connect.c | 91 +++++++++++++++++++++++--------------------------- fs/cifs/misc.c | 2 +- fs/cifs/readdir.c | 2 +- 7 files changed, 60 insertions(+), 68 deletions(-) diff --git a/fs/cifs/cifs_unicode.c b/fs/cifs/cifs_unicode.c index 4e12053f0806be..d2b12825594426 100644 --- a/fs/cifs/cifs_unicode.c +++ b/fs/cifs/cifs_unicode.c @@ -1,7 +1,7 @@ /* * fs/cifs/cifs_unicode.c * - * Copyright (c) International Business Machines Corp., 2000,2002 + * Copyright (c) International Business Machines Corp., 2000,2005 * Modified by Steve French (sfrench@us.ibm.com) * * This program is free software; you can redistribute it and/or modify @@ -31,7 +31,7 @@ * */ int -cifs_strfromUCS_le(char *to, const wchar_t * from, /* LITTLE ENDIAN */ +cifs_strfromUCS_le(char *to, const __le16 * from, int len, const struct nls_table *codepage) { int i; @@ -60,25 +60,26 @@ cifs_strfromUCS_le(char *to, const wchar_t * from, /* LITTLE ENDIAN */ * */ int -cifs_strtoUCS(wchar_t * to, const char *from, int len, +cifs_strtoUCS(__le16 * to, const char *from, int len, const struct nls_table *codepage) { int charlen; int i; + wchar_t * wchar_to = (wchar_t *)to; /* needed to quiet sparse */ for (i = 0; len && *from; i++, from += charlen, len -= charlen) { /* works for 2.4.0 kernel or later */ - charlen = codepage->char2uni(from, len, &to[i]); + charlen = codepage->char2uni(from, len, &wchar_to[i]); if (charlen < 1) { cERROR(1, ("cifs_strtoUCS: char2uni returned %d", charlen)); /* A question mark */ - to[i] = (wchar_t)cpu_to_le16(0x003f); + to[i] = cpu_to_le16(0x003f); charlen = 1; } else - to[i] = (wchar_t)cpu_to_le16(to[i]); + to[i] = cpu_to_le16(wchar_to[i]); } diff --git a/fs/cifs/cifs_unicode.h b/fs/cifs/cifs_unicode.h index da8dde9652751b..39e5b970325f6a 100644 --- a/fs/cifs/cifs_unicode.h +++ b/fs/cifs/cifs_unicode.h @@ -5,7 +5,7 @@ * Convert a unicode character to upper or lower case using * compressed tables. * - * Copyright (c) International Business Machines Corp., 2000,2002 + * Copyright (c) International Business Machines Corp., 2000,2005555555555555555555555555555555555555555555555555555555 * * This program is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by @@ -59,8 +59,8 @@ extern struct UniCaseRange UniLowerRange[]; #endif /* UNIUPR_NOLOWER */ #ifdef __KERNEL__ -int cifs_strfromUCS_le(char *, const wchar_t *, int, const struct nls_table *); -int cifs_strtoUCS(wchar_t *, const char *, int, const struct nls_table *); +int cifs_strfromUCS_le(char *, const __le16 *, int, const struct nls_table *); +int cifs_strtoUCS(__le16 *, const char *, int, const struct nls_table *); #endif /* diff --git a/fs/cifs/cifsencrypt.c b/fs/cifs/cifsencrypt.c index 1959c7c4b185b4..fe2bb7c4c9121c 100644 --- a/fs/cifs/cifsencrypt.c +++ b/fs/cifs/cifsencrypt.c @@ -149,7 +149,7 @@ int CalcNTLMv2_partial_mac_key(struct cifsSesInfo * ses, struct nls_table * nls_ char temp_hash[16]; struct HMACMD5Context ctx; char * ucase_buf; - wchar_t * unicode_buf; + __le16 * unicode_buf; unsigned int i,user_name_len,dom_name_len; if(ses == NULL) diff --git a/fs/cifs/cifssmb.c b/fs/cifs/cifssmb.c index a53c596e1082fe..8dbd8c2c0e3bf2 100644 --- a/fs/cifs/cifssmb.c +++ b/fs/cifs/cifssmb.c @@ -1553,7 +1553,7 @@ createSymLinkRetry: if (pSMB->hdr.Flags2 & SMBFLG2_UNICODE) { name_len = - cifs_strtoUCS((wchar_t *) pSMB->FileName, fromName, PATH_MAX + cifs_strtoUCS((__le16 *) pSMB->FileName, fromName, PATH_MAX /* find define for this maxpathcomponent */ , nls_codepage); name_len++; /* trailing null */ @@ -1577,7 +1577,7 @@ createSymLinkRetry: data_offset = (char *) (&pSMB->hdr.Protocol) + offset; if (pSMB->hdr.Flags2 & SMBFLG2_UNICODE) { name_len_target = - cifs_strtoUCS((wchar_t *) data_offset, toName, PATH_MAX + cifs_strtoUCS((__le16 *) data_offset, toName, PATH_MAX /* find define for this maxpathcomponent */ , nls_codepage); name_len_target++; /* trailing null */ @@ -1803,7 +1803,7 @@ querySymLinkRetry: if (pSMB->hdr.Flags2 & SMBFLG2_UNICODE) { name_len = - cifs_strtoUCS((wchar_t *) pSMB->FileName, searchName, PATH_MAX + cifs_strtoUCS((__le16 *) pSMB->FileName, searchName, PATH_MAX /* find define for this maxpathcomponent */ , nls_codepage); name_len++; /* trailing null */ @@ -1860,7 +1860,7 @@ querySymLinkRetry: min_t(const int, buflen,count) / 2); /* BB FIXME investigate remapping reserved chars here */ cifs_strfromUCS_le(symlinkinfo, - (wchar_t *) ((char *)&pSMBr->hdr.Protocol + + (__le16 *) ((char *)&pSMBr->hdr.Protocol + data_offset), name_len, nls_codepage); } else { @@ -1951,7 +1951,7 @@ CIFSSMBQueryReparseLinkInfo(const int xid, struct cifsTconInfo *tcon, reparse_buf->TargetNameOffset), min(buflen/2, reparse_buf->TargetNameLen / 2)); cifs_strfromUCS_le(symlinkinfo, - (wchar_t *) (reparse_buf->LinkNamesBuf + + (__le16 *) (reparse_buf->LinkNamesBuf + reparse_buf->TargetNameOffset), name_len, nls_codepage); } else { /* ASCII names */ @@ -3203,7 +3203,7 @@ getDFSRetry: temp = ((char *)referrals) + le16_to_cpu(referrals->DfsPathOffset); if (pSMBr->hdr.Flags2 & SMBFLG2_UNICODE) { cifs_strfromUCS_le(*targetUNCs, - (wchar_t *) temp, name_len, nls_codepage); + (__le16 *) temp, name_len, nls_codepage); } else { strncpy(*targetUNCs,temp,name_len); } diff --git a/fs/cifs/connect.c b/fs/cifs/connect.c index 2cb620716bc146..c467de8576105b 100644 --- a/fs/cifs/connect.c +++ b/fs/cifs/connect.c @@ -1986,32 +1986,32 @@ CIFSSessSetup(unsigned int xid, struct cifsSesInfo *ses, bytes_returned = 0; /* skill null user */ else bytes_returned = - cifs_strtoUCS((wchar_t *) bcc_ptr, user, 100, + cifs_strtoUCS((__le16 *) bcc_ptr, user, 100, nls_codepage); /* convert number of 16 bit words to bytes */ bcc_ptr += 2 * bytes_returned; bcc_ptr += 2; /* trailing null */ if (domain == NULL) bytes_returned = - cifs_strtoUCS((wchar_t *) bcc_ptr, + cifs_strtoUCS((__le16 *) bcc_ptr, "CIFS_LINUX_DOM", 32, nls_codepage); else bytes_returned = - cifs_strtoUCS((wchar_t *) bcc_ptr, domain, 64, + cifs_strtoUCS((__le16 *) bcc_ptr, domain, 64, nls_codepage); bcc_ptr += 2 * bytes_returned; bcc_ptr += 2; bytes_returned = - cifs_strtoUCS((wchar_t *) bcc_ptr, "Linux version ", + cifs_strtoUCS((__le16 *) bcc_ptr, "Linux version ", 32, nls_codepage); bcc_ptr += 2 * bytes_returned; bytes_returned = - cifs_strtoUCS((wchar_t *) bcc_ptr, system_utsname.release, + cifs_strtoUCS((__le16 *) bcc_ptr, system_utsname.release, 32, nls_codepage); bcc_ptr += 2 * bytes_returned; bcc_ptr += 2; bytes_returned = - cifs_strtoUCS((wchar_t *) bcc_ptr, CIFS_NETWORK_OPSYS, + cifs_strtoUCS((__le16 *) bcc_ptr, CIFS_NETWORK_OPSYS, 64, nls_codepage); bcc_ptr += 2 * bytes_returned; bcc_ptr += 2; @@ -2081,7 +2081,7 @@ CIFSSessSetup(unsigned int xid, struct cifsSesInfo *ses, if(ses->serverOS == NULL) goto sesssetup_nomem; cifs_strfromUCS_le(ses->serverOS, - (wchar_t *)bcc_ptr, len,nls_codepage); + (__le16 *)bcc_ptr, len,nls_codepage); bcc_ptr += 2 * (len + 1); remaining_words -= len + 1; ses->serverOS[2 * len] = 0; @@ -2093,7 +2093,7 @@ CIFSSessSetup(unsigned int xid, struct cifsSesInfo *ses, if(ses->serverNOS == NULL) goto sesssetup_nomem; cifs_strfromUCS_le(ses->serverNOS, - (wchar_t *)bcc_ptr,len,nls_codepage); + (__le16 *)bcc_ptr,len,nls_codepage); bcc_ptr += 2 * (len + 1); ses->serverNOS[2 * len] = 0; ses->serverNOS[1 + (2 * len)] = 0; @@ -2111,7 +2111,7 @@ CIFSSessSetup(unsigned int xid, struct cifsSesInfo *ses, if(ses->serverDomain == NULL) goto sesssetup_nomem; cifs_strfromUCS_le(ses->serverDomain, - (wchar_t *)bcc_ptr,len,nls_codepage); + (__le16 *)bcc_ptr,len,nls_codepage); bcc_ptr += 2 * (len + 1); ses->serverDomain[2*len] = 0; ses->serverDomain[1+(2*len)] = 0; @@ -2255,30 +2255,30 @@ CIFSSpnegoSessSetup(unsigned int xid, struct cifsSesInfo *ses, bcc_ptr++; } bytes_returned = - cifs_strtoUCS((wchar_t *) bcc_ptr, user, 100, nls_codepage); + cifs_strtoUCS((__le16 *) bcc_ptr, user, 100, nls_codepage); bcc_ptr += 2 * bytes_returned; /* convert num of 16 bit words to bytes */ bcc_ptr += 2; /* trailing null */ if (domain == NULL) bytes_returned = - cifs_strtoUCS((wchar_t *) bcc_ptr, + cifs_strtoUCS((__le16 *) bcc_ptr, "CIFS_LINUX_DOM", 32, nls_codepage); else bytes_returned = - cifs_strtoUCS((wchar_t *) bcc_ptr, domain, 64, + cifs_strtoUCS((__le16 *) bcc_ptr, domain, 64, nls_codepage); bcc_ptr += 2 * bytes_returned; bcc_ptr += 2; bytes_returned = - cifs_strtoUCS((wchar_t *) bcc_ptr, "Linux version ", + cifs_strtoUCS((__le16 *) bcc_ptr, "Linux version ", 32, nls_codepage); bcc_ptr += 2 * bytes_returned; bytes_returned = - cifs_strtoUCS((wchar_t *) bcc_ptr, system_utsname.release, 32, + cifs_strtoUCS((__le16 *) bcc_ptr, system_utsname.release, 32, nls_codepage); bcc_ptr += 2 * bytes_returned; bcc_ptr += 2; bytes_returned = - cifs_strtoUCS((wchar_t *) bcc_ptr, CIFS_NETWORK_OPSYS, + cifs_strtoUCS((__le16 *) bcc_ptr, CIFS_NETWORK_OPSYS, 64, nls_codepage); bcc_ptr += 2 * bytes_returned; bcc_ptr += 2; @@ -2357,7 +2357,7 @@ CIFSSpnegoSessSetup(unsigned int xid, struct cifsSesInfo *ses, ses->serverOS = kzalloc(2 * (len + 1), GFP_KERNEL); cifs_strfromUCS_le(ses->serverOS, - (wchar_t *) + (__le16 *) bcc_ptr, len, nls_codepage); bcc_ptr += 2 * (len + 1); @@ -2372,7 +2372,7 @@ CIFSSpnegoSessSetup(unsigned int xid, struct cifsSesInfo *ses, kzalloc(2 * (len + 1), GFP_KERNEL); cifs_strfromUCS_le(ses->serverNOS, - (wchar_t *)bcc_ptr, + (__le16 *)bcc_ptr, len, nls_codepage); bcc_ptr += 2 * (len + 1); @@ -2384,9 +2384,8 @@ CIFSSpnegoSessSetup(unsigned int xid, struct cifsSesInfo *ses, /* last string is not always null terminated (for e.g. for Windows XP & 2000) */ ses->serverDomain = kzalloc(2*(len+1),GFP_KERNEL); cifs_strfromUCS_le(ses->serverDomain, - (wchar_t *)bcc_ptr, - len, - nls_codepage); + (__le16 *)bcc_ptr, + len, nls_codepage); bcc_ptr += 2*(len+1); ses->serverDomain[2*len] = 0; ses->serverDomain[1+(2*len)] = 0; @@ -2560,16 +2559,16 @@ CIFSNTLMSSPNegotiateSessSetup(unsigned int xid, } bytes_returned = - cifs_strtoUCS((wchar_t *) bcc_ptr, "Linux version ", + cifs_strtoUCS((__le16 *) bcc_ptr, "Linux version ", 32, nls_codepage); bcc_ptr += 2 * bytes_returned; bytes_returned = - cifs_strtoUCS((wchar_t *) bcc_ptr, system_utsname.release, 32, + cifs_strtoUCS((__le16 *) bcc_ptr, system_utsname.release, 32, nls_codepage); bcc_ptr += 2 * bytes_returned; bcc_ptr += 2; /* null terminate Linux version */ bytes_returned = - cifs_strtoUCS((wchar_t *) bcc_ptr, CIFS_NETWORK_OPSYS, + cifs_strtoUCS((__le16 *) bcc_ptr, CIFS_NETWORK_OPSYS, 64, nls_codepage); bcc_ptr += 2 * bytes_returned; *(bcc_ptr + 1) = 0; @@ -2673,7 +2672,7 @@ CIFSNTLMSSPNegotiateSessSetup(unsigned int xid, ses->serverOS = kzalloc(2 * (len + 1), GFP_KERNEL); cifs_strfromUCS_le(ses->serverOS, - (wchar_t *) + (__le16 *) bcc_ptr, len, nls_codepage); bcc_ptr += 2 * (len + 1); @@ -2690,7 +2689,7 @@ CIFSNTLMSSPNegotiateSessSetup(unsigned int xid, GFP_KERNEL); cifs_strfromUCS_le(ses-> serverNOS, - (wchar_t *) + (__le16 *) bcc_ptr, len, nls_codepage); @@ -2708,23 +2707,15 @@ CIFSNTLMSSPNegotiateSessSetup(unsigned int xid, 1), GFP_KERNEL); cifs_strfromUCS_le - (ses-> - serverDomain, - (wchar_t *) - bcc_ptr, len, - nls_codepage); + (ses->serverDomain, + (__le16 *)bcc_ptr, + len, nls_codepage); bcc_ptr += 2 * (len + 1); - ses-> - serverDomain[2 - * len] + ses->serverDomain[2*len] = 0; - ses-> - serverDomain[1 - + - (2 - * - len)] + ses->serverDomain + [1 + (2 * len)] = 0; } /* else no more room so create dummy domain string */ else @@ -2903,7 +2894,7 @@ CIFSNTLMSSPAuthSessSetup(unsigned int xid, struct cifsSesInfo *ses, SecurityBlob->DomainName.MaximumLength = 0; } else { __u16 len = - cifs_strtoUCS((wchar_t *) bcc_ptr, domain, 64, + cifs_strtoUCS((__le16 *) bcc_ptr, domain, 64, nls_codepage); len *= 2; SecurityBlob->DomainName.MaximumLength = @@ -2921,7 +2912,7 @@ CIFSNTLMSSPAuthSessSetup(unsigned int xid, struct cifsSesInfo *ses, SecurityBlob->UserName.MaximumLength = 0; } else { __u16 len = - cifs_strtoUCS((wchar_t *) bcc_ptr, user, 64, + cifs_strtoUCS((__le16 *) bcc_ptr, user, 64, nls_codepage); len *= 2; SecurityBlob->UserName.MaximumLength = @@ -2934,7 +2925,7 @@ CIFSNTLMSSPAuthSessSetup(unsigned int xid, struct cifsSesInfo *ses, cpu_to_le16(len); } - /* SecurityBlob->WorkstationName.Length = cifs_strtoUCS((wchar_t *) bcc_ptr, "AMACHINE",64, nls_codepage); + /* SecurityBlob->WorkstationName.Length = cifs_strtoUCS((__le16 *) bcc_ptr, "AMACHINE",64, nls_codepage); SecurityBlob->WorkstationName.Length *= 2; SecurityBlob->WorkstationName.MaximumLength = cpu_to_le16(SecurityBlob->WorkstationName.Length); SecurityBlob->WorkstationName.Buffer = cpu_to_le32(SecurityBlobLength); @@ -2947,16 +2938,16 @@ CIFSNTLMSSPAuthSessSetup(unsigned int xid, struct cifsSesInfo *ses, bcc_ptr++; } bytes_returned = - cifs_strtoUCS((wchar_t *) bcc_ptr, "Linux version ", + cifs_strtoUCS((__le16 *) bcc_ptr, "Linux version ", 32, nls_codepage); bcc_ptr += 2 * bytes_returned; bytes_returned = - cifs_strtoUCS((wchar_t *) bcc_ptr, system_utsname.release, 32, + cifs_strtoUCS((__le16 *) bcc_ptr, system_utsname.release, 32, nls_codepage); bcc_ptr += 2 * bytes_returned; bcc_ptr += 2; /* null term version string */ bytes_returned = - cifs_strtoUCS((wchar_t *) bcc_ptr, CIFS_NETWORK_OPSYS, + cifs_strtoUCS((__le16 *) bcc_ptr, CIFS_NETWORK_OPSYS, 64, nls_codepage); bcc_ptr += 2 * bytes_returned; *(bcc_ptr + 1) = 0; @@ -3069,7 +3060,7 @@ CIFSNTLMSSPAuthSessSetup(unsigned int xid, struct cifsSesInfo *ses, ses->serverOS = kzalloc(2 * (len + 1), GFP_KERNEL); cifs_strfromUCS_le(ses->serverOS, - (wchar_t *) + (__le16 *) bcc_ptr, len, nls_codepage); bcc_ptr += 2 * (len + 1); @@ -3086,7 +3077,7 @@ CIFSNTLMSSPAuthSessSetup(unsigned int xid, struct cifsSesInfo *ses, GFP_KERNEL); cifs_strfromUCS_le(ses-> serverNOS, - (wchar_t *) + (__le16 *) bcc_ptr, len, nls_codepage); @@ -3105,7 +3096,7 @@ CIFSNTLMSSPAuthSessSetup(unsigned int xid, struct cifsSesInfo *ses, cifs_strfromUCS_le (ses-> serverDomain, - (wchar_t *) + (__le16 *) bcc_ptr, len, nls_codepage); bcc_ptr += @@ -3227,7 +3218,7 @@ CIFSTCon(unsigned int xid, struct cifsSesInfo *ses, if (ses->capabilities & CAP_UNICODE) { smb_buffer->Flags2 |= SMBFLG2_UNICODE; length = - cifs_strtoUCS((wchar_t *) bcc_ptr, tree, 100, nls_codepage); + cifs_strtoUCS((__le16 *) bcc_ptr, tree, 100, nls_codepage); bcc_ptr += 2 * length; /* convert num of 16 bit words to bytes */ bcc_ptr += 2; /* skip trailing null */ } else { /* ASCII */ @@ -3263,7 +3254,7 @@ CIFSTCon(unsigned int xid, struct cifsSesInfo *ses, tcon->nativeFileSystem = kzalloc(length + 2, GFP_KERNEL); cifs_strfromUCS_le(tcon->nativeFileSystem, - (wchar_t *) bcc_ptr, + (__le16 *) bcc_ptr, length, nls_codepage); bcc_ptr += 2 * length; bcc_ptr[0] = 0; /* null terminate the string */ diff --git a/fs/cifs/misc.c b/fs/cifs/misc.c index 34a06692e4fa94..ca27a82c54cdb6 100644 --- a/fs/cifs/misc.c +++ b/fs/cifs/misc.c @@ -678,7 +678,7 @@ cifsConvertToUCS(__le16 * target, const char *source, int maxlen, __u16 temp; if(!mapChars) - return cifs_strtoUCS((wchar_t *) target, source, PATH_MAX, cp); + return cifs_strtoUCS(target, source, PATH_MAX, cp); for(i = 0, j = 0; i < maxlen; j++) { src_char = source[i]; diff --git a/fs/cifs/readdir.c b/fs/cifs/readdir.c index fc615670f4b8b7..9b7e0ff9584b35 100644 --- a/fs/cifs/readdir.c +++ b/fs/cifs/readdir.c @@ -705,7 +705,7 @@ static int cifs_get_name_from_search_buf(struct qstr *pqst, (__le16 *)filename, len/2, nlt); else pqst->len = cifs_strfromUCS_le((char *)pqst->name, - (wchar_t *)filename,len/2,nlt); + (__le16 *)filename,len/2,nlt); } else { pqst->name = filename; pqst->len = len; -- cgit 1.2.3-korg From d6e2f2a4c892e4d131ab4fa5d212546c47dd3c40 Mon Sep 17 00:00:00 2001 From: Steve French Date: Tue, 15 Nov 2005 16:43:39 -0800 Subject: [CIFS] Recognize properly symlinks and char/blk devices (not just FIFOs) created by SFU (part 1 of 2). Signed-off-by: Steve French --- fs/cifs/CHANGES | 2 ++ fs/cifs/inode.c | 74 +++++++++++++++++++++++++++++++++++++++++++++++++-------- 2 files changed, 66 insertions(+), 10 deletions(-) diff --git a/fs/cifs/CHANGES b/fs/cifs/CHANGES index eab3750cf30485..289e4079c96bf9 100644 --- a/fs/cifs/CHANGES +++ b/fs/cifs/CHANGES @@ -3,6 +3,8 @@ Version 1.39 Defer close of a file handle slightly if pending writes depend on that file handle (this reduces the EBADF bad file handle errors that can be logged under heavy stress on writes). Modify cifs Kconfig options to expose CONFIG_CIFS_STATS2 +Fix SFU style symlinks and mknod needed for servers which do not support the CIFS +Unix Extensions. Version 1.38 ------------ diff --git a/fs/cifs/inode.c b/fs/cifs/inode.c index 941b247fceb024..ba9eae56d01190 100644 --- a/fs/cifs/inode.c +++ b/fs/cifs/inode.c @@ -97,9 +97,9 @@ int cifs_get_inode_info_unix(struct inode **pinode, inode = *pinode; cifsInfo = CIFS_I(inode); - cFYI(1, (" Old time %ld ", cifsInfo->time)); + cFYI(1, ("Old time %ld ", cifsInfo->time)); cifsInfo->time = jiffies; - cFYI(1, (" New time %ld ", cifsInfo->time)); + cFYI(1, ("New time %ld ", cifsInfo->time)); /* this is ok to set on every inode revalidate */ atomic_set(&cifsInfo->inUse,1); @@ -195,6 +195,55 @@ int cifs_get_inode_info_unix(struct inode **pinode, return rc; } +static int decode_sfu_inode(struct inode * inode, __u64 size, + const unsigned char *path, + struct cifs_sb_info *cifs_sb, int xid) +{ + int rc; + int oplock = FALSE; + __u16 netfid; + struct cifsTconInfo *pTcon = cifs_sb->tcon; + char buf[8]; + unsigned int bytes_read; + char * pbuf; + + pbuf = buf; + + if(size == 0) { + inode->i_mode |= S_IFIFO; + return 0; + } else if (size < 8) { + return -EINVAL; /* EOPNOTSUPP? */ + } + + rc = CIFSSMBOpen(xid, pTcon, path, FILE_OPEN, GENERIC_READ, + CREATE_NOT_DIR, &netfid, &oplock, NULL, + cifs_sb->local_nls, + cifs_sb->mnt_cifs_flags & + CIFS_MOUNT_MAP_SPECIAL_CHR); + if (rc==0) { + /* Read header */ + rc = CIFSSMBRead(xid, pTcon, + netfid, + 8 /* length */, 0 /* offset */, + &bytes_read, &pbuf); + if((rc == 0) && (bytes_read == 8)) { + /* if memcmp(IntxCHR\000, pbuf, 8) + else if memcmp(IntxBLK\000, pbuf, 8) + else if memcmp(IntxLNK\001, pbuf, 8) */ + } + + CIFSSMBClose(xid, pTcon, netfid); + + + /* inode->i_rdev = MKDEV(le64_to_cpu(DevMajor), + le64_to_cpu(DevMinor) & MINORMASK);*/ +/* inode->i_mode |= S_IFBLK; */ + } + return rc; + +} + int cifs_get_inode_info(struct inode **pinode, const unsigned char *search_path, FILE_ALL_INFO *pfindData, struct super_block *sb, int xid) @@ -207,7 +256,7 @@ int cifs_get_inode_info(struct inode **pinode, char *buf = NULL; pTcon = cifs_sb->tcon; - cFYI(1,("Getting info on %s ", search_path)); + cFYI(1,("Getting info on %s", search_path)); if ((pfindData == NULL) && (*pinode != NULL)) { if (CIFS_I(*pinode)->clientCanCacheRead) { @@ -345,10 +394,15 @@ int cifs_get_inode_info(struct inode **pinode, (pfindData->EndOfFile == 0)) { inode->i_mode = cifs_sb->mnt_file_mode; inode->i_mode |= S_IFIFO; -/* BB Finish for SFU style symlinks and devies */ -/* } else if ((cifs_sb->mnt_cifs_flags & CIFS_MOUNT_UNX_EMUL) && - (cifsInfo->cifsAttrs & ATTR_SYSTEM) && ) */ - +/* BB Finish for SFU style symlinks and devices */ + } else if ((cifs_sb->mnt_cifs_flags & CIFS_MOUNT_UNX_EMUL) && + (cifsInfo->cifsAttrs & ATTR_SYSTEM)) { + if (decode_sfu_inode(inode, + le64_to_cpu(pfindData->EndOfFile), + search_path, + cifs_sb, xid)) { + cFYI(1,("Unrecognized sfu inode type")); + } } else { inode->i_mode |= S_IFREG; /* treat the dos attribute of read-only as read-only @@ -382,7 +436,7 @@ int cifs_get_inode_info(struct inode **pinode, } if (S_ISREG(inode->i_mode)) { - cFYI(1, (" File inode ")); + cFYI(1, ("File inode")); inode->i_op = &cifs_file_inode_ops; if (cifs_sb->mnt_cifs_flags & CIFS_MOUNT_DIRECT_IO) { if (cifs_sb->mnt_cifs_flags & CIFS_MOUNT_NO_BRL) @@ -400,11 +454,11 @@ int cifs_get_inode_info(struct inode **pinode, 4096 + MAX_CIFS_HDR_SIZE) inode->i_data.a_ops->readpages = NULL; } else if (S_ISDIR(inode->i_mode)) { - cFYI(1, (" Directory inode ")); + cFYI(1, ("Directory inode")); inode->i_op = &cifs_dir_inode_ops; inode->i_fop = &cifs_dir_ops; } else if (S_ISLNK(inode->i_mode)) { - cFYI(1, (" Symbolic Link inode ")); + cFYI(1, ("Symbolic Link inode")); inode->i_op = &cifs_symlink_inode_ops; } else { init_special_inode(inode, inode->i_mode, -- cgit 1.2.3-korg From ff7feac9638e162263463edaeb342b4f3b1ce90e Mon Sep 17 00:00:00 2001 From: Steve French Date: Tue, 15 Nov 2005 16:45:16 -0800 Subject: [CIFS] Fix endian errors (setfacl/getfacl failures) in handling ACLs (and a ppc64 compiler warning) Signed-off-by: Dave Kleikamp Signed-off-by: Steve French --- fs/cifs/cifssmb.c | 31 +++++++++++++++++-------------- 1 file changed, 17 insertions(+), 14 deletions(-) diff --git a/fs/cifs/cifssmb.c b/fs/cifs/cifssmb.c index 8dbd8c2c0e3bf2..d179b0c3eee45e 100644 --- a/fs/cifs/cifssmb.c +++ b/fs/cifs/cifssmb.c @@ -1142,7 +1142,9 @@ CIFSSMBWrite2(const int xid, struct cifsTconInfo *tcon, int bytes_returned, wct; int smb_hdr_len; - cFYI(1,("write2 at %lld %d bytes",offset,count)); /* BB removeme BB */ + /* BB removeme BB */ + cFYI(1,("write2 at %lld %d bytes", (long long)offset, count)); + if(tcon->ses->capabilities & CAP_LARGE_FILES) wct = 14; else @@ -1983,9 +1985,9 @@ qreparse_out: static void cifs_convert_ace(posix_acl_xattr_entry * ace, struct cifs_posix_ace * cifs_ace) { /* u8 cifs fields do not need le conversion */ - ace->e_perm = (__u16)cifs_ace->cifs_e_perm; - ace->e_tag = (__u16)cifs_ace->cifs_e_tag; - ace->e_id = (__u32)le64_to_cpu(cifs_ace->cifs_uid); + ace->e_perm = cpu_to_le16(cifs_ace->cifs_e_perm); + ace->e_tag = cpu_to_le16(cifs_ace->cifs_e_tag); + ace->e_id = cpu_to_le32(le64_to_cpu(cifs_ace->cifs_uid)); /* cFYI(1,("perm %d tag %d id %d",ace->e_perm,ace->e_tag,ace->e_id)); */ return; @@ -2037,7 +2039,7 @@ static int cifs_copy_posix_acl(char * trgt,char * src, const int buflen, } else if(size > buflen) { return -ERANGE; } else /* buffer big enough */ { - local_acl->a_version = POSIX_ACL_XATTR_VERSION; + local_acl->a_version = cpu_to_le32(POSIX_ACL_XATTR_VERSION); for(i = 0;i < count ;i++) { cifs_convert_ace(&local_acl->a_entries[i],pACE); pACE ++; @@ -2051,14 +2053,14 @@ static __u16 convert_ace_to_cifs_ace(struct cifs_posix_ace * cifs_ace, { __u16 rc = 0; /* 0 = ACL converted ok */ - cifs_ace->cifs_e_perm = (__u8)cpu_to_le16(local_ace->e_perm); - cifs_ace->cifs_e_tag = (__u8)cpu_to_le16(local_ace->e_tag); + cifs_ace->cifs_e_perm = le16_to_cpu(local_ace->e_perm); + cifs_ace->cifs_e_tag = le16_to_cpu(local_ace->e_tag); /* BB is there a better way to handle the large uid? */ - if(local_ace->e_id == -1) { + if(local_ace->e_id == cpu_to_le32(-1)) { /* Probably no need to le convert -1 on any arch but can not hurt */ cifs_ace->cifs_uid = cpu_to_le64(-1); } else - cifs_ace->cifs_uid = (__u64)cpu_to_le32(local_ace->e_id); + cifs_ace->cifs_uid = cpu_to_le64(le32_to_cpu(local_ace->e_id)); /*cFYI(1,("perm %d tag %d id %d",ace->e_perm,ace->e_tag,ace->e_id));*/ return rc; } @@ -2078,16 +2080,17 @@ static __u16 ACL_to_cifs_posix(char * parm_data,const char * pACL,const int bufl count = posix_acl_xattr_count((size_t)buflen); cFYI(1,("setting acl with %d entries from buf of length %d and version of %d", - count,buflen,local_acl->a_version)); - if(local_acl->a_version != 2) { - cFYI(1,("unknown POSIX ACL version %d",local_acl->a_version)); + count, buflen, le32_to_cpu(local_acl->a_version))); + if(le32_to_cpu(local_acl->a_version) != 2) { + cFYI(1,("unknown POSIX ACL version %d", + le32_to_cpu(local_acl->a_version))); return 0; } cifs_acl->version = cpu_to_le16(1); if(acl_type == ACL_TYPE_ACCESS) - cifs_acl->access_entry_count = count; + cifs_acl->access_entry_count = cpu_to_le16(count); else if(acl_type == ACL_TYPE_DEFAULT) - cifs_acl->default_entry_count = count; + cifs_acl->default_entry_count = cpu_to_le16(count); else { cFYI(1,("unknown ACL type %d",acl_type)); return 0; -- cgit 1.2.3-korg From 0f2b27c438cb593717dde8ee0fc05e0874eabbb6 Mon Sep 17 00:00:00 2001 From: Steve French Date: Wed, 16 Nov 2005 14:25:50 -0800 Subject: [CIFS] Fix sparse warnings on smb bcc (byte count) Signed-off-by: Dave Kleikamp Signed-off-by: Steve French --- fs/cifs/CHANGES | 2 +- fs/cifs/transport.c | 4 ++-- 2 files changed, 3 insertions(+), 3 deletions(-) diff --git a/fs/cifs/CHANGES b/fs/cifs/CHANGES index 289e4079c96bf9..6bded10c0d507c 100644 --- a/fs/cifs/CHANGES +++ b/fs/cifs/CHANGES @@ -4,7 +4,7 @@ Defer close of a file handle slightly if pending writes depend on that file hand (this reduces the EBADF bad file handle errors that can be logged under heavy stress on writes). Modify cifs Kconfig options to expose CONFIG_CIFS_STATS2 Fix SFU style symlinks and mknod needed for servers which do not support the CIFS -Unix Extensions. +Unix Extensions. Fix setfacl/getfacl on bigendian. Version 1.38 ------------ diff --git a/fs/cifs/transport.c b/fs/cifs/transport.c index 981ea0d8b9cdaa..41a9659c16bc69 100644 --- a/fs/cifs/transport.c +++ b/fs/cifs/transport.c @@ -522,7 +522,7 @@ SendReceive2(const unsigned int xid, struct cifsSesInfo *ses, sizeof (struct smb_hdr) - 4 /* do not count RFC1001 header */ + (2 * in_buf->WordCount) + 2 /* bcc */ ) - BCC(in_buf) = le16_to_cpu(BCC(in_buf)); + BCC(in_buf) = le16_to_cpu(BCC_LE(in_buf)); } else { rc = -EIO; cFYI(1,("Bad MID state?")); @@ -786,7 +786,7 @@ SendReceive(const unsigned int xid, struct cifsSesInfo *ses, sizeof (struct smb_hdr) - 4 /* do not count RFC1001 header */ + (2 * out_buf->WordCount) + 2 /* bcc */ ) - BCC(out_buf) = le16_to_cpu(BCC(out_buf)); + BCC(out_buf) = le16_to_cpu(BCC_LE(out_buf)); } else { rc = -EIO; cERROR(1,("Bad MID state? ")); -- cgit 1.2.3-korg From 9e294f1c4d4a5fc0068fcb21f5809ff6e88e49bc Mon Sep 17 00:00:00 2001 From: Steve French Date: Thu, 17 Nov 2005 16:59:21 -0800 Subject: [CIFS] Recognize properly symlinks and char/blk devices (not just FIFOs) created by SFU (part 2 of 2). Thanks to Martin Koeppe for useful analysis. Signed-off-by: Steve French --- fs/cifs/inode.c | 48 ++++++++++++++++++++++++++++++++++++++++++++---- 1 file changed, 44 insertions(+), 4 deletions(-) diff --git a/fs/cifs/inode.c b/fs/cifs/inode.c index ba9eae56d01190..93dd705577bcaf 100644 --- a/fs/cifs/inode.c +++ b/fs/cifs/inode.c @@ -228,9 +228,20 @@ static int decode_sfu_inode(struct inode * inode, __u64 size, 8 /* length */, 0 /* offset */, &bytes_read, &pbuf); if((rc == 0) && (bytes_read == 8)) { - /* if memcmp(IntxCHR\000, pbuf, 8) - else if memcmp(IntxBLK\000, pbuf, 8) - else if memcmp(IntxLNK\001, pbuf, 8) */ + cERROR(1,("intx %s" ,pbuf)); + if(memcmp("IntxBLK", pbuf, 8) == 0) { + cFYI(1,("Block device")); + inode->i_mode = S_IFBLK; + } else if(memcmp("IntxCHR", pbuf, 8) == 0) { + cFYI(1,("Char device")); + inode->i_mode = S_IFCHR; + } else if(memcmp("IntxLNK", pbuf, 7) == 0) { + cFYI(1,("Symlink")); + inode->i_mode = S_IFLNK; + } else + inode->i_mode = S_IFREG; /* then it is a file */ + rc = -EOPNOTSUPP; /* or some unknown SFU type */ + } CIFSSMBClose(xid, pTcon, netfid); @@ -244,6 +255,32 @@ static int decode_sfu_inode(struct inode * inode, __u64 size, } +#define SFBITS_MASK (S_ISVTX | S_ISGID | S_ISUID) /* SETFILEBITS valid bits */ + +static int get_sfu_uid_mode(struct inode * inode, + const unsigned char *path, + struct cifs_sb_info *cifs_sb, int xid) +{ + ssize_t rc; + char ea_value[4]; + __u32 mode; + + rc = CIFSSMBQueryEA(xid, cifs_sb->tcon, path, "SETFILEBITS", + ea_value, 4 /* size of buf */, cifs_sb->local_nls, + cifs_sb->mnt_cifs_flags & CIFS_MOUNT_MAP_SPECIAL_CHR); + if(rc < 0) + return (int)rc; + else if (rc > 3) { + mode = le32_to_cpu(*((__le32 *)ea_value)); + inode->i_mode = (mode & SFBITS_MASK) | inode->i_mode; + cFYI(1,("special mode bits 0%o", mode)); + return 0; + } else { + return 0; + } + +} + int cifs_get_inode_info(struct inode **pinode, const unsigned char *search_path, FILE_ALL_INFO *pfindData, struct super_block *sb, int xid) @@ -427,7 +464,10 @@ int cifs_get_inode_info(struct inode **pinode, /* BB fill in uid and gid here? with help from winbind? or retrieve from NTFS stream extended attribute */ - if (atomic_read(&cifsInfo->inUse) == 0) { + if(cifs_sb->mnt_cifs_flags & CIFS_MOUNT_UNX_EMUL) { + /* fill in uid, gid, mode from server ACL */ + get_sfu_uid_mode(inode, search_path, cifs_sb, xid); + } else if (atomic_read(&cifsInfo->inUse) == 0) { inode->i_uid = cifs_sb->mnt_uid; inode->i_gid = cifs_sb->mnt_gid; /* set so we do not keep refreshing these fields with -- cgit 1.2.3-korg From 87c89dd7330735d70cc9912483f6f4c7bc3ff19c Mon Sep 17 00:00:00 2001 From: Steve French Date: Thu, 17 Nov 2005 17:03:00 -0800 Subject: [CIFS] Vectored and async i/o turned on and correct the writev and aio_write to flush properly. This is Christoph's patch merged with the new nobrl file operations Signed-off-by: Dave Kleikamp From: Christoph Hellwig - support vectored and async aio ops unconditionally - this is above the pagecache and transparent to the fs - remove cifs_read_wrapper. it was only doing silly checks and calling generic_file_write in all cases. - use do_sync_read/do_sync_write as read/write operations. They call ->readv/->writev which we now always implemente. - add the filemap_fdatawrite calls to writev/aio_write which were missing previously compared to plain write. no idea what the point behind them is, but let's be consistent at least.. Signed-off-by: Christoph Hellwig Signed-off-by: Steven French Signed-off-by: Andrew Morton --- fs/cifs/cifsfs.c | 117 +++++++++++++++++++++---------------------------------- 1 file changed, 45 insertions(+), 72 deletions(-) diff --git a/fs/cifs/cifsfs.c b/fs/cifs/cifsfs.c index 1433455c61eafa..51548ed2e9cce8 100644 --- a/fs/cifs/cifsfs.c +++ b/fs/cifs/cifsfs.c @@ -483,57 +483,30 @@ cifs_get_sb(struct file_system_type *fs_type, return sb; } -static ssize_t -cifs_read_wrapper(struct file * file, char __user *read_data, size_t read_size, - loff_t * poffset) +static ssize_t cifs_file_writev(struct file *file, const struct iovec *iov, + unsigned long nr_segs, loff_t *ppos) { - if(file->f_dentry == NULL) - return -EIO; - else if(file->f_dentry->d_inode == NULL) - return -EIO; - - cFYI(1,("In read_wrapper size %zd at %lld",read_size,*poffset)); + struct inode *inode = file->f_dentry->d_inode; + ssize_t written; - if(CIFS_I(file->f_dentry->d_inode)->clientCanCacheRead) { - return generic_file_read(file,read_data,read_size,poffset); - } else { - /* BB do we need to lock inode from here until after invalidate? */ -/* if(file->f_dentry->d_inode->i_mapping) { - filemap_fdatawrite(file->f_dentry->d_inode->i_mapping); - filemap_fdatawait(file->f_dentry->d_inode->i_mapping); - }*/ -/* cifs_revalidate(file->f_dentry);*/ /* BB fixme */ - - /* BB we should make timer configurable - perhaps - by simply calling cifs_revalidate here */ - /* invalidate_remote_inode(file->f_dentry->d_inode);*/ - return generic_file_read(file,read_data,read_size,poffset); - } + written = generic_file_writev(file, iov, nr_segs, ppos); + if (!CIFS_I(inode)->clientCanCacheAll) + filemap_fdatawrite(inode->i_mapping); + return written; } -static ssize_t -cifs_write_wrapper(struct file * file, const char __user *write_data, - size_t write_size, loff_t * poffset) +static ssize_t cifs_file_aio_write(struct kiocb *iocb, const char __user *buf, + size_t count, loff_t pos) { + struct inode *inode = iocb->ki_filp->f_dentry->d_inode; ssize_t written; - if(file->f_dentry == NULL) - return -EIO; - else if(file->f_dentry->d_inode == NULL) - return -EIO; - - cFYI(1,("In write_wrapper size %zd at %lld",write_size,*poffset)); - - written = generic_file_write(file,write_data,write_size,poffset); - if(!CIFS_I(file->f_dentry->d_inode)->clientCanCacheAll) { - if(file->f_dentry->d_inode->i_mapping) { - filemap_fdatawrite(file->f_dentry->d_inode->i_mapping); - } - } + written = generic_file_aio_write(iocb, buf, count, pos); + if (!CIFS_I(inode)->clientCanCacheAll) + filemap_fdatawrite(inode->i_mapping); return written; } - static struct file_system_type cifs_fs_type = { .owner = THIS_MODULE, .name = "cifs", @@ -594,8 +567,12 @@ struct inode_operations cifs_symlink_inode_ops = { }; struct file_operations cifs_file_ops = { - .read = cifs_read_wrapper, - .write = cifs_write_wrapper, + .read = do_sync_read, + .write = do_sync_write, + .readv = generic_file_readv, + .writev = cifs_file_writev, + .aio_read = generic_file_aio_read, + .aio_write = cifs_file_aio_write, .open = cifs_open, .release = cifs_close, .lock = cifs_lock, @@ -608,10 +585,6 @@ struct file_operations cifs_file_ops = { #endif /* CONFIG_CIFS_POSIX */ #ifdef CONFIG_CIFS_EXPERIMENTAL - .readv = generic_file_readv, - .writev = generic_file_writev, - .aio_read = generic_file_aio_read, - .aio_write = generic_file_aio_write, .dir_notify = cifs_dir_notify, #endif /* CONFIG_CIFS_EXPERIMENTAL */ }; @@ -636,43 +609,43 @@ struct file_operations cifs_file_direct_ops = { #endif /* CONFIG_CIFS_EXPERIMENTAL */ }; struct file_operations cifs_file_nobrl_ops = { - .read = cifs_read_wrapper, - .write = cifs_write_wrapper, - .open = cifs_open, - .release = cifs_close, - .fsync = cifs_fsync, - .flush = cifs_flush, - .mmap = cifs_file_mmap, - .sendfile = generic_file_sendfile, + .read = do_sync_read, + .write = do_sync_write, + .readv = generic_file_readv, + .writev = cifs_file_writev, + .aio_read = generic_file_aio_read, + .aio_write = cifs_file_aio_write, + .open = cifs_open, + .release = cifs_close, + .fsync = cifs_fsync, + .flush = cifs_flush, + .mmap = cifs_file_mmap, + .sendfile = generic_file_sendfile, #ifdef CONFIG_CIFS_POSIX - .ioctl = cifs_ioctl, + .ioctl = cifs_ioctl, #endif /* CONFIG_CIFS_POSIX */ #ifdef CONFIG_CIFS_EXPERIMENTAL - .readv = generic_file_readv, - .writev = generic_file_writev, - .aio_read = generic_file_aio_read, - .aio_write = generic_file_aio_write, - .dir_notify = cifs_dir_notify, + .dir_notify = cifs_dir_notify, #endif /* CONFIG_CIFS_EXPERIMENTAL */ }; struct file_operations cifs_file_direct_nobrl_ops = { - /* no mmap, no aio, no readv - - BB reevaluate whether they can be done with directio, no cache */ - .read = cifs_user_read, - .write = cifs_user_write, - .open = cifs_open, - .release = cifs_close, - .fsync = cifs_fsync, - .flush = cifs_flush, - .sendfile = generic_file_sendfile, /* BB removeme BB */ + /* no mmap, no aio, no readv - + BB reevaluate whether they can be done with directio, no cache */ + .read = cifs_user_read, + .write = cifs_user_write, + .open = cifs_open, + .release = cifs_close, + .fsync = cifs_fsync, + .flush = cifs_flush, + .sendfile = generic_file_sendfile, /* BB removeme BB */ #ifdef CONFIG_CIFS_POSIX - .ioctl = cifs_ioctl, + .ioctl = cifs_ioctl, #endif /* CONFIG_CIFS_POSIX */ #ifdef CONFIG_CIFS_EXPERIMENTAL - .dir_notify = cifs_dir_notify, + .dir_notify = cifs_dir_notify, #endif /* CONFIG_CIFS_EXPERIMENTAL */ }; -- cgit 1.2.3-korg From 3020a1f58c564e3060ec908c0c4f1b74a12e4280 Mon Sep 17 00:00:00 2001 From: Steve French Date: Fri, 18 Nov 2005 11:31:10 -0800 Subject: [CIFS] Fix scheduling while atomic when pending writes at file close time Fix the case in which readdir reset file type when SFU mount option specified. Also fix sfu related functions to not request EAs (xattrs) when not configured in Kconfig Signed-off-by: Steve French --- fs/cifs/inode.c | 47 +++++++++++++++++++++++++++++++---------------- fs/cifs/readdir.c | 31 +++++++++++++++++++++++++------ 2 files changed, 56 insertions(+), 22 deletions(-) diff --git a/fs/cifs/inode.c b/fs/cifs/inode.c index 93dd705577bcaf..ffc7305841b3c2 100644 --- a/fs/cifs/inode.c +++ b/fs/cifs/inode.c @@ -41,7 +41,7 @@ int cifs_get_inode_info_unix(struct inode **pinode, char *tmp_path; pTcon = cifs_sb->tcon; - cFYI(1, (" Getting info on %s ", search_path)); + cFYI(1, ("Getting info on %s ", search_path)); /* could have done a find first instead but this returns more info */ rc = CIFSSMBUnixQPathInfo(xid, pTcon, search_path, &findData, cifs_sb->local_nls, cifs_sb->mnt_cifs_flags & @@ -111,6 +111,9 @@ int cifs_get_inode_info_unix(struct inode **pinode, inode->i_ctime = cifs_NTtimeToUnix(le64_to_cpu(findData.LastStatusChange)); inode->i_mode = le64_to_cpu(findData.Permissions); + /* since we set the inode type below we need to mask off + to avoid strange results if bits set above */ + inode->i_mode &= ~S_IFMT; if (type == UNIX_FILE) { inode->i_mode |= S_IFREG; } else if (type == UNIX_SYMLINK) { @@ -129,6 +132,10 @@ int cifs_get_inode_info_unix(struct inode **pinode, inode->i_mode |= S_IFIFO; } else if (type == UNIX_SOCKET) { inode->i_mode |= S_IFSOCK; + } else { + /* safest to call it a file if we do not know */ + inode->i_mode |= S_IFREG; + cFYI(1,("unknown type %d",type)); } inode->i_uid = le64_to_cpu(findData.Uid); inode->i_gid = le64_to_cpu(findData.Gid); @@ -228,20 +235,19 @@ static int decode_sfu_inode(struct inode * inode, __u64 size, 8 /* length */, 0 /* offset */, &bytes_read, &pbuf); if((rc == 0) && (bytes_read == 8)) { - cERROR(1,("intx %s" ,pbuf)); if(memcmp("IntxBLK", pbuf, 8) == 0) { cFYI(1,("Block device")); - inode->i_mode = S_IFBLK; + inode->i_mode |= S_IFBLK; } else if(memcmp("IntxCHR", pbuf, 8) == 0) { cFYI(1,("Char device")); - inode->i_mode = S_IFCHR; + inode->i_mode |= S_IFCHR; } else if(memcmp("IntxLNK", pbuf, 7) == 0) { cFYI(1,("Symlink")); - inode->i_mode = S_IFLNK; - } else - inode->i_mode = S_IFREG; /* then it is a file */ - rc = -EOPNOTSUPP; /* or some unknown SFU type */ - + inode->i_mode |= S_IFLNK; + } + } else { + inode->i_mode |= S_IFREG; /* then it is a file */ + rc = -EOPNOTSUPP; /* or some unknown SFU type */ } CIFSSMBClose(xid, pTcon, netfid); @@ -261,6 +267,7 @@ static int get_sfu_uid_mode(struct inode * inode, const unsigned char *path, struct cifs_sb_info *cifs_sb, int xid) { +#ifdef CONFIG_CIFS_XATTR ssize_t rc; char ea_value[4]; __u32 mode; @@ -272,12 +279,17 @@ static int get_sfu_uid_mode(struct inode * inode, return (int)rc; else if (rc > 3) { mode = le32_to_cpu(*((__le32 *)ea_value)); + cFYI(1,("special bits 0%o org mode 0%o", mode, inode->i_mode)); inode->i_mode = (mode & SFBITS_MASK) | inode->i_mode; cFYI(1,("special mode bits 0%o", mode)); return 0; } else { return 0; } +#else + return -EOPNOTSUPP; +#endif + } @@ -394,9 +406,9 @@ int cifs_get_inode_info(struct inode **pinode, inode = *pinode; cifsInfo = CIFS_I(inode); cifsInfo->cifsAttrs = attr; - cFYI(1, (" Old time %ld ", cifsInfo->time)); + cFYI(1, ("Old time %ld ", cifsInfo->time)); cifsInfo->time = jiffies; - cFYI(1, (" New time %ld ", cifsInfo->time)); + cFYI(1, ("New time %ld ", cifsInfo->time)); /* blksize needs to be multiple of two. So safer to default to blksize and blkbits set in superblock so 2**blkbits and blksize @@ -410,13 +422,15 @@ int cifs_get_inode_info(struct inode **pinode, cifs_NTtimeToUnix(le64_to_cpu(pfindData->LastWriteTime)); inode->i_ctime = cifs_NTtimeToUnix(le64_to_cpu(pfindData->ChangeTime)); - cFYI(0, (" Attributes came in as 0x%x ", attr)); + cFYI(0, ("Attributes came in as 0x%x ", attr)); /* set default mode. will override for dirs below */ if (atomic_read(&cifsInfo->inUse) == 0) /* new inode, can safely set these fields */ inode->i_mode = cifs_sb->mnt_file_mode; - + else /* since we set the inode type below we need to mask off + to avoid strange results if type changes and both get orred in */ + inode->i_mode &= ~S_IFMT; /* if (attr & ATTR_REPARSE) */ /* We no longer handle these as symlinks because we could not follow them due to the absolute path with drive letter */ @@ -440,6 +454,7 @@ int cifs_get_inode_info(struct inode **pinode, cifs_sb, xid)) { cFYI(1,("Unrecognized sfu inode type")); } + cFYI(1,("sfu mode 0%o",inode->i_mode)); } else { inode->i_mode |= S_IFREG; /* treat the dos attribute of read-only as read-only @@ -535,7 +550,7 @@ int cifs_unlink(struct inode *inode, struct dentry *direntry) struct cifsInodeInfo *cifsInode; FILE_BASIC_INFO *pinfo_buf; - cFYI(1, (" cifs_unlink, inode = 0x%p with ", inode)); + cFYI(1, ("cifs_unlink, inode = 0x%p with ", inode)); xid = GetXid(); @@ -755,7 +770,7 @@ int cifs_rmdir(struct inode *inode, struct dentry *direntry) char *full_path = NULL; struct cifsInodeInfo *cifsInode; - cFYI(1, (" cifs_rmdir, inode = 0x%p with ", inode)); + cFYI(1, ("cifs_rmdir, inode = 0x%p with ", inode)); xid = GetXid(); @@ -1074,7 +1089,7 @@ int cifs_setattr(struct dentry *direntry, struct iattr *attrs) xid = GetXid(); - cFYI(1, (" In cifs_setattr, name = %s attrs->iavalid 0x%x ", + cFYI(1, ("In cifs_setattr, name = %s attrs->iavalid 0x%x ", direntry->d_name.name, attrs->ia_valid)); cifs_sb = CIFS_SB(direntry->d_inode->i_sb); pTcon = cifs_sb->tcon; diff --git a/fs/cifs/readdir.c b/fs/cifs/readdir.c index 9b7e0ff9584b35..9bdaaecae36f68 100644 --- a/fs/cifs/readdir.c +++ b/fs/cifs/readdir.c @@ -142,6 +142,11 @@ static void fill_in_inode(struct inode *tmp_inode, tmp_inode->i_gid = cifs_sb->mnt_gid; /* set default mode. will override for dirs below */ tmp_inode->i_mode = cifs_sb->mnt_file_mode; + } else { + /* mask off the type bits since it gets set + below and we do not want to get two type + bits set */ + tmp_inode->i_mode &= ~S_IFMT; } if (attr & ATTR_DIRECTORY) { @@ -152,12 +157,18 @@ static void fill_in_inode(struct inode *tmp_inode, } tmp_inode->i_mode |= S_IFDIR; } else if ((cifs_sb->mnt_cifs_flags & CIFS_MOUNT_UNX_EMUL) && - (attr & ATTR_SYSTEM) && (end_of_file == 0)) { - *pobject_type = DT_FIFO; - tmp_inode->i_mode |= S_IFIFO; -/* BB Finish for SFU style symlinks and devies */ -/* } else if ((cifs_sb->mnt_cifs_flags & CIFS_MOUNT_UNX_EMUL) && - (attr & ATTR_SYSTEM) && ) { */ + (attr & ATTR_SYSTEM)) { + if (end_of_file == 0) { + *pobject_type = DT_FIFO; + tmp_inode->i_mode |= S_IFIFO; + } else { + /* rather than get the type here, we mark the + inode as needing revalidate and get the real type + (blk vs chr vs. symlink) later ie in lookup */ + *pobject_type = DT_REG; + tmp_inode->i_mode |= S_IFREG; + cifsInfo->time = 0; + } /* we no longer mark these because we could not follow them */ /* } else if (attr & ATTR_REPARSE) { *pobject_type = DT_LNK; @@ -264,6 +275,9 @@ static void unix_fill_in_inode(struct inode *tmp_inode, cifs_NTtimeToUnix(le64_to_cpu(pfindData->LastStatusChange)); tmp_inode->i_mode = le64_to_cpu(pfindData->Permissions); + /* since we set the inode type below we need to mask off type + to avoid strange results if bits above were corrupt */ + tmp_inode->i_mode &= ~S_IFMT; if (type == UNIX_FILE) { *pobject_type = DT_REG; tmp_inode->i_mode |= S_IFREG; @@ -289,6 +303,11 @@ static void unix_fill_in_inode(struct inode *tmp_inode, } else if (type == UNIX_SOCKET) { *pobject_type = DT_SOCK; tmp_inode->i_mode |= S_IFSOCK; + } else { + /* safest to just call it a file */ + *pobject_type = DT_REG; + tmp_inode->i_mode |= S_IFREG; + cFYI(1,("unknown inode type %d",type)); } tmp_inode->i_uid = le64_to_cpu(pfindData->Uid); -- cgit 1.2.3-korg From c119b87d596cdd99ac20095ae2ae90b525418605 Mon Sep 17 00:00:00 2001 From: Steve French Date: Fri, 18 Nov 2005 12:27:27 -0800 Subject: [CIFS] Missing part of previous patch Signed-off-by: Steve French --- fs/cifs/file.c | 2 ++ fs/cifs/inode.c | 1 + 2 files changed, 3 insertions(+) diff --git a/fs/cifs/file.c b/fs/cifs/file.c index da4f5e10b3cc0f..14a1c72ced92e1 100644 --- a/fs/cifs/file.c +++ b/fs/cifs/file.c @@ -489,8 +489,10 @@ int cifs_close(struct inode *inode, struct file *file) the struct would be in each open file, but this should give enough time to clear the socket */ + write_unlock(&file->f_owner.lock); cERROR(1,("close with pending writes")); msleep(timeout); + write_lock(&file->f_owner.lock); timeout *= 4; } write_unlock(&file->f_owner.lock); diff --git a/fs/cifs/inode.c b/fs/cifs/inode.c index ffc7305841b3c2..f0586c0d7bdbb0 100644 --- a/fs/cifs/inode.c +++ b/fs/cifs/inode.c @@ -279,6 +279,7 @@ static int get_sfu_uid_mode(struct inode * inode, return (int)rc; else if (rc > 3) { mode = le32_to_cpu(*((__le32 *)ea_value)); + inode->i_mode &= ~SFBITS_MASK; cFYI(1,("special bits 0%o org mode 0%o", mode, inode->i_mode)); inode->i_mode = (mode & SFBITS_MASK) | inode->i_mode; cFYI(1,("special mode bits 0%o", mode)); -- cgit 1.2.3-korg From 86c96b4bb70dac67d6815e09a0949427d439b280 Mon Sep 17 00:00:00 2001 From: Steve French Date: Fri, 18 Nov 2005 20:25:31 -0800 Subject: [CIFS] Fix mknod of block and chardev over SFU mounts Signed-off-by: Steve French --- fs/cifs/cifspdu.h | 10 +++++++++- fs/cifs/dir.c | 32 ++++++++++++++++++++++++++++++-- fs/cifs/inode.c | 33 +++++++++++++++++++++++---------- 3 files changed, 62 insertions(+), 13 deletions(-) diff --git a/fs/cifs/cifspdu.h b/fs/cifs/cifspdu.h index 48a05b9df7eb5f..33e1859fd2f67c 100644 --- a/fs/cifs/cifspdu.h +++ b/fs/cifs/cifspdu.h @@ -603,7 +603,9 @@ typedef struct smb_com_logoff_andx_rsp { __u16 ByteCount; } __attribute__((packed)) LOGOFF_ANDX_RSP; -typedef union smb_com_tree_disconnect { /* as an altetnative can use flag on tree_connect PDU to effect disconnect *//* probably the simplest SMB PDU */ +typedef union smb_com_tree_disconnect { /* as an altetnative can use flag on + tree_connect PDU to effect disconnect */ + /* tdis is probably simplest SMB PDU */ struct { struct smb_hdr hdr; /* wct = 0 */ __u16 ByteCount; /* bcc = 0 */ @@ -2025,6 +2027,12 @@ typedef struct { } __attribute__((packed)) FILE_BOTH_DIRECTORY_INFO; /* level 0x104 FF response data area */ +struct win_dev { + unsigned char type[8]; /* IntxCHR or IntxBLK */ + __le64 major; + __le64 minor; +} __attribute__((packed)); + struct gea { unsigned char name_len; char name[1]; diff --git a/fs/cifs/dir.c b/fs/cifs/dir.c index 8dfe717a332aba..16b21522e8fe1b 100644 --- a/fs/cifs/dir.c +++ b/fs/cifs/dir.c @@ -292,7 +292,8 @@ cifs_create_out: return rc; } -int cifs_mknod(struct inode *inode, struct dentry *direntry, int mode, dev_t device_number) +int cifs_mknod(struct inode *inode, struct dentry *direntry, int mode, + dev_t device_number) { int rc = -EPERM; int xid; @@ -368,7 +369,34 @@ int cifs_mknod(struct inode *inode, struct dentry *direntry, int mode, dev_t dev if(!rc) { /* BB Do not bother to decode buf since no - local inode yet to put timestamps in */ + local inode yet to put timestamps in, + but we can reuse it safely */ + int bytes_written; + struct win_dev *pdev; + pdev = (struct win_dev *)buf; + if(S_ISCHR(mode)) { + memcpy(pdev->type, "IntxCHR", 8); + pdev->major = + cpu_to_le64(MAJOR(device_number)); + pdev->minor = + cpu_to_le64(MINOR(device_number)); + rc = CIFSSMBWrite(xid, pTcon, + fileHandle, + sizeof(struct win_dev), + 0, &bytes_written, (char *)pdev, + NULL, 0); + } else if(S_ISBLK(mode)) { + memcpy(pdev->type, "IntxBLK", 8); + pdev->major = + cpu_to_le64(MAJOR(device_number)); + pdev->minor = + cpu_to_le64(MINOR(device_number)); + rc = CIFSSMBWrite(xid, pTcon, + fileHandle, + sizeof(struct win_dev), + 0, &bytes_written, (char *)pdev, + NULL, 0); + } /* else if(S_ISFIFO */ CIFSSMBClose(xid, pTcon, fileHandle); d_drop(direntry); } diff --git a/fs/cifs/inode.c b/fs/cifs/inode.c index f0586c0d7bdbb0..d7b85dfb0df308 100644 --- a/fs/cifs/inode.c +++ b/fs/cifs/inode.c @@ -210,7 +210,7 @@ static int decode_sfu_inode(struct inode * inode, __u64 size, int oplock = FALSE; __u16 netfid; struct cifsTconInfo *pTcon = cifs_sb->tcon; - char buf[8]; + char buf[24]; unsigned int bytes_read; char * pbuf; @@ -232,30 +232,43 @@ static int decode_sfu_inode(struct inode * inode, __u64 size, /* Read header */ rc = CIFSSMBRead(xid, pTcon, netfid, - 8 /* length */, 0 /* offset */, + 24 /* length */, 0 /* offset */, &bytes_read, &pbuf); - if((rc == 0) && (bytes_read == 8)) { + if((rc == 0) && (bytes_read >= 8)) { if(memcmp("IntxBLK", pbuf, 8) == 0) { cFYI(1,("Block device")); inode->i_mode |= S_IFBLK; + if(bytes_read == 24) { + /* we have enough to decode dev num */ + __u64 mjr; /* major */ + __u64 mnr; /* minor */ + mjr = le64_to_cpu(*(__le64 *)(pbuf+8)); + mnr = le64_to_cpu(*(__le64 *)(pbuf+16)); + inode->i_rdev = MKDEV(mjr, mnr); + } } else if(memcmp("IntxCHR", pbuf, 8) == 0) { cFYI(1,("Char device")); inode->i_mode |= S_IFCHR; + if(bytes_read == 24) { + /* we have enough to decode dev num */ + __u64 mjr; /* major */ + __u64 mnr; /* minor */ + mjr = le64_to_cpu(*(__le64 *)(pbuf+8)); + mnr = le64_to_cpu(*(__le64 *)(pbuf+16)); + inode->i_rdev = MKDEV(mjr, mnr); + } } else if(memcmp("IntxLNK", pbuf, 7) == 0) { cFYI(1,("Symlink")); inode->i_mode |= S_IFLNK; - } + } else { + inode->i_mode |= S_IFREG; /* file? */ + rc = -EOPNOTSUPP; + } } else { inode->i_mode |= S_IFREG; /* then it is a file */ rc = -EOPNOTSUPP; /* or some unknown SFU type */ } - CIFSSMBClose(xid, pTcon, netfid); - - - /* inode->i_rdev = MKDEV(le64_to_cpu(DevMajor), - le64_to_cpu(DevMinor) & MINORMASK);*/ -/* inode->i_mode |= S_IFBLK; */ } return rc; -- cgit 1.2.3-korg From cdbce9c87e4ebd186389919b95e49592ec35dae6 Mon Sep 17 00:00:00 2001 From: Steve French Date: Sat, 19 Nov 2005 21:04:52 -0800 Subject: [CIFS] Fix setattr of mode only (e.g. in some chmod cases) to Windows so it does not return EACCESS (unless server really returns that). Signed-off-by: Steve French --- fs/cifs/inode.c | 1 + 1 file changed, 1 insertion(+) diff --git a/fs/cifs/inode.c b/fs/cifs/inode.c index d7b85dfb0df308..05b525812adb5b 100644 --- a/fs/cifs/inode.c +++ b/fs/cifs/inode.c @@ -1219,6 +1219,7 @@ int cifs_setattr(struct dentry *direntry, struct iattr *attrs) cifs_sb->mnt_cifs_flags & CIFS_MOUNT_MAP_SPECIAL_CHR); else if (attrs->ia_valid & ATTR_MODE) { + rc = 0; if ((mode & S_IWUGO) == 0) /* not writeable */ { if ((cifsInode->cifsAttrs & ATTR_READONLY) == 0) time_buf.Attributes = -- cgit 1.2.3-korg