Commit 9f6632d6 authored by Linus Torvalds's avatar Linus Torvalds

Merge git://git.kernel.org/pub/scm/linux/kernel/git/sfrench/cifs-2.6

* git://git.kernel.org/pub/scm/linux/kernel/git/sfrench/cifs-2.6:
  [CIFS] cifs_prepare_write was incorrectly rereading page in some cases
  [CIFS] Fix set file size to zero when doing chmod to Samba 3.0.26pre
  [CIFS] Remove some unused functions/declarations
  [CIFS] New file for previous commit
  [CIFS] cifs export operations
  [CIFS] small piece missing from previous patch
  [CIFS] Fix locking problem around some cifs uses of i_size write
parents 8328258e 8a236264
Verison 1.48
------------
Fix mtime bouncing around from local idea of last write times to remote time.
Fix hang (in i_size_read) when simultaneous size update of same remote file
on smp system corrupts sequence number. Do not reread unnecessarily partial page
(which we are about to overwrite anyway) when writing out file opened rw.
Version 1.47 Version 1.47
------------ ------------
Fix oops in list_del during mount caused by unaligned string. Fix oops in list_del during mount caused by unaligned string.
......
...@@ -3,4 +3,4 @@ ...@@ -3,4 +3,4 @@
# #
obj-$(CONFIG_CIFS) += cifs.o obj-$(CONFIG_CIFS) += cifs.o
cifs-objs := cifsfs.o cifssmb.o cifs_debug.o connect.o dir.o file.o inode.o link.o misc.o netmisc.o smbdes.o smbencrypt.o transport.o asn1.o md4.o md5.o cifs_unicode.o nterr.o xattr.o cifsencrypt.o fcntl.o readdir.o ioctl.o sess.o cifs-objs := cifsfs.o cifssmb.o cifs_debug.o connect.o dir.o file.o inode.o link.o misc.o netmisc.o smbdes.o smbencrypt.o transport.o asn1.o md4.o md5.o cifs_unicode.o nterr.o xattr.o cifsencrypt.o fcntl.o readdir.o ioctl.o sess.o export.o
...@@ -18,7 +18,9 @@ better) ...@@ -18,7 +18,9 @@ better)
d) Kerberos/SPNEGO session setup support - (started) d) Kerberos/SPNEGO session setup support - (started)
e) NTLMv2 authentication (mostly implemented) e) NTLMv2 authentication (mostly implemented - double check
that NTLMv2 signing works, also need to cleanup now unneeded SessSetup code in
fs/cifs/connect.c)
f) MD5-HMAC signing SMB PDUs when SPNEGO style SessionSetup f) MD5-HMAC signing SMB PDUs when SPNEGO style SessionSetup
used (Kerberos or NTLMSSP). Signing alreadyimplemented for NTLM used (Kerberos or NTLMSSP). Signing alreadyimplemented for NTLM
...@@ -88,11 +90,12 @@ w) Finish up the dos time conversion routines needed to return old server ...@@ -88,11 +90,12 @@ w) Finish up the dos time conversion routines needed to return old server
time to the client (default time, of now or time 0 is used now for these time to the client (default time, of now or time 0 is used now for these
very old servers) very old servers)
x) Add support for OS/2 (LANMAN 1.2 and LANMAN2.1 based SMB servers) x) In support for OS/2 (LANMAN 1.2 and LANMAN2.1 based SMB servers)
need to add ability to set time to server (utimes command)
y) Finish testing of Windows 9x/Windows ME server support (started). y) Finish testing of Windows 9x/Windows ME server support (started).
KNOWN BUGS (updated April 29, 2005) KNOWN BUGS (updated February 26, 2007)
==================================== ====================================
See http://bugzilla.samba.org - search on product "CifsVFS" for See http://bugzilla.samba.org - search on product "CifsVFS" for
current bug list. current bug list.
...@@ -107,11 +110,6 @@ but recognizes them ...@@ -107,11 +110,6 @@ but recognizes them
succeed but still return access denied (appears to be Windows succeed but still return access denied (appears to be Windows
server not cifs client problem) and has not been reproduced recently. server not cifs client problem) and has not been reproduced recently.
NTFS partitions do not have this problem. NTFS partitions do not have this problem.
4) debug connectathon lock test case 10 which fails against
Samba (may be unmappable due to POSIX to Windows lock model
differences but worth investigating). Also debug Samba to
see why lock test case 7 takes longer to complete to Samba
than to Windows.
Misc testing to do Misc testing to do
================== ==================
...@@ -119,7 +117,7 @@ Misc testing to do ...@@ -119,7 +117,7 @@ Misc testing to do
types. Try nested symlinks (8 deep). Return max path name in stat -f information types. Try nested symlinks (8 deep). Return max path name in stat -f information
2) Modify file portion of ltp so it can run against a mounted network 2) Modify file portion of ltp so it can run against a mounted network
share and run it against cifs vfs. share and run it against cifs vfs in automated fashion.
3) Additional performance testing and optimization using iozone and similar - 3) Additional performance testing and optimization using iozone and similar -
there are some easy changes that can be done to parallelize sequential writes, there are some easy changes that can be done to parallelize sequential writes,
......
/* /*
* fs/cifs/cifsfs.c * fs/cifs/cifsfs.c
* *
* Copyright (C) International Business Machines Corp., 2002,2004 * Copyright (C) International Business Machines Corp., 2002,2007
* Author(s): Steve French (sfrench@us.ibm.com) * Author(s): Steve French (sfrench@us.ibm.com)
* *
* Common Internet FileSystem (CIFS) client * Common Internet FileSystem (CIFS) client
...@@ -47,7 +47,11 @@ ...@@ -47,7 +47,11 @@
#ifdef CONFIG_CIFS_QUOTA #ifdef CONFIG_CIFS_QUOTA
static struct quotactl_ops cifs_quotactl_ops; static struct quotactl_ops cifs_quotactl_ops;
#endif #endif /* QUOTA */
#ifdef CONFIG_CIFS_EXPERIMENTAL
extern struct export_operations cifs_export_ops;
#endif /* EXPERIMENTAL */
int cifsFYI = 0; int cifsFYI = 0;
int cifsERROR = 1; int cifsERROR = 1;
...@@ -62,8 +66,8 @@ unsigned int extended_security = CIFSSEC_DEF; ...@@ -62,8 +66,8 @@ unsigned int extended_security = CIFSSEC_DEF;
unsigned int sign_CIFS_PDUs = 1; unsigned int sign_CIFS_PDUs = 1;
extern struct task_struct * oplockThread; /* remove sparse warning */ extern struct task_struct * oplockThread; /* remove sparse warning */
struct task_struct * oplockThread = NULL; struct task_struct * oplockThread = NULL;
extern struct task_struct * dnotifyThread; /* remove sparse warning */ /* extern struct task_struct * dnotifyThread; remove sparse warning */
struct task_struct * dnotifyThread = NULL; static struct task_struct * dnotifyThread = NULL;
static const struct super_operations cifs_super_ops; static const struct super_operations cifs_super_ops;
unsigned int CIFSMaxBufSize = CIFS_MAX_MSGSIZE; unsigned int CIFSMaxBufSize = CIFS_MAX_MSGSIZE;
module_param(CIFSMaxBufSize, int, 0); module_param(CIFSMaxBufSize, int, 0);
...@@ -110,6 +114,10 @@ cifs_read_super(struct super_block *sb, void *data, ...@@ -110,6 +114,10 @@ cifs_read_super(struct super_block *sb, void *data,
sb->s_magic = CIFS_MAGIC_NUMBER; sb->s_magic = CIFS_MAGIC_NUMBER;
sb->s_op = &cifs_super_ops; sb->s_op = &cifs_super_ops;
#ifdef CONFIG_CIFS_EXPERIMENTAL
if(experimEnabled != 0)
sb->s_export_op = &cifs_export_ops;
#endif /* EXPERIMENTAL */
/* if(cifs_sb->tcon->ses->server->maxBuf > MAX_CIFS_HDR_SIZE + 512) /* if(cifs_sb->tcon->ses->server->maxBuf > MAX_CIFS_HDR_SIZE + 512)
sb->s_blocksize = cifs_sb->tcon->ses->server->maxBuf - MAX_CIFS_HDR_SIZE; */ sb->s_blocksize = cifs_sb->tcon->ses->server->maxBuf - MAX_CIFS_HDR_SIZE; */
#ifdef CONFIG_CIFS_QUOTA #ifdef CONFIG_CIFS_QUOTA
......
...@@ -38,8 +38,8 @@ extern const struct address_space_operations cifs_addr_ops_smallbuf; ...@@ -38,8 +38,8 @@ extern const struct address_space_operations cifs_addr_ops_smallbuf;
/* Functions related to super block operations */ /* Functions related to super block operations */
/* extern const struct super_operations cifs_super_ops;*/ /* extern const struct super_operations cifs_super_ops;*/
extern void cifs_read_inode(struct inode *); extern void cifs_read_inode(struct inode *);
extern void cifs_delete_inode(struct inode *); /*extern void cifs_delete_inode(struct inode *);*/ /* BB not needed yet */
/* extern void cifs_write_inode(struct inode *); *//* BB not needed yet */ /* extern void cifs_write_inode(struct inode *); */ /* BB not needed yet */
/* Functions related to inodes */ /* Functions related to inodes */
extern const struct inode_operations cifs_dir_inode_ops; extern const struct inode_operations cifs_dir_inode_ops;
......
...@@ -525,15 +525,17 @@ require use of the stronger protocol */ ...@@ -525,15 +525,17 @@ require use of the stronger protocol */
*/ */
GLOBAL_EXTERN struct smbUidInfo *GlobalUidList[UID_HASH]; GLOBAL_EXTERN struct smbUidInfo *GlobalUidList[UID_HASH];
GLOBAL_EXTERN struct list_head GlobalServerList; /* BB not implemented yet */ /* GLOBAL_EXTERN struct list_head GlobalServerList; BB not implemented yet */
GLOBAL_EXTERN struct list_head GlobalSMBSessionList; GLOBAL_EXTERN struct list_head GlobalSMBSessionList;
GLOBAL_EXTERN struct list_head GlobalTreeConnectionList; GLOBAL_EXTERN struct list_head GlobalTreeConnectionList;
GLOBAL_EXTERN rwlock_t GlobalSMBSeslock; /* protects list inserts on 3 above */ GLOBAL_EXTERN rwlock_t GlobalSMBSeslock; /* protects list inserts on 3 above */
GLOBAL_EXTERN struct list_head GlobalOplock_Q; GLOBAL_EXTERN struct list_head GlobalOplock_Q;
GLOBAL_EXTERN struct list_head GlobalDnotifyReqList; /* Outstanding dir notify requests */ /* Outstanding dir notify requests */
GLOBAL_EXTERN struct list_head GlobalDnotifyRsp_Q;/* DirNotify response queue */ GLOBAL_EXTERN struct list_head GlobalDnotifyReqList;
/* DirNotify response queue */
GLOBAL_EXTERN struct list_head GlobalDnotifyRsp_Q;
/* /*
* Global transaction id (XID) information * Global transaction id (XID) information
......
...@@ -220,6 +220,9 @@ ...@@ -220,6 +220,9 @@
*/ */
#define CIFS_NO_HANDLE 0xFFFF #define CIFS_NO_HANDLE 0xFFFF
#define NO_CHANGE_64 0xFFFFFFFFFFFFFFFFULL
#define NO_CHANGE_32 0xFFFFFFFFUL
/* IPC$ in ASCII */ /* IPC$ in ASCII */
#define CIFS_IPC_RESOURCE "\x49\x50\x43\x24" #define CIFS_IPC_RESOURCE "\x49\x50\x43\x24"
......
...@@ -43,7 +43,7 @@ extern void _FreeXid(unsigned int); ...@@ -43,7 +43,7 @@ extern void _FreeXid(unsigned int);
#define FreeXid(curr_xid) {_FreeXid(curr_xid); cFYI(1,("CIFS VFS: leaving %s (xid = %d) rc = %d",__FUNCTION__,curr_xid,(int)rc));} #define FreeXid(curr_xid) {_FreeXid(curr_xid); cFYI(1,("CIFS VFS: leaving %s (xid = %d) rc = %d",__FUNCTION__,curr_xid,(int)rc));}
extern char *build_path_from_dentry(struct dentry *); extern char *build_path_from_dentry(struct dentry *);
extern char *build_wildcard_path_from_dentry(struct dentry *direntry); extern char *build_wildcard_path_from_dentry(struct dentry *direntry);
extern void renew_parental_timestamps(struct dentry *direntry); /* extern void renew_parental_timestamps(struct dentry *direntry);*/
extern int SendReceive(const unsigned int /* xid */ , struct cifsSesInfo *, extern int SendReceive(const unsigned int /* xid */ , struct cifsSesInfo *,
struct smb_hdr * /* input */ , struct smb_hdr * /* input */ ,
struct smb_hdr * /* out */ , struct smb_hdr * /* out */ ,
......
...@@ -4803,6 +4803,16 @@ CIFSSMBUnixSetPerms(const int xid, struct cifsTconInfo *tcon, ...@@ -4803,6 +4803,16 @@ CIFSSMBUnixSetPerms(const int xid, struct cifsTconInfo *tcon,
pSMB->InformationLevel = cpu_to_le16(SMB_SET_FILE_UNIX_BASIC); pSMB->InformationLevel = cpu_to_le16(SMB_SET_FILE_UNIX_BASIC);
pSMB->Reserved4 = 0; pSMB->Reserved4 = 0;
pSMB->hdr.smb_buf_length += byte_count; pSMB->hdr.smb_buf_length += byte_count;
/* Samba server ignores set of file size to zero due to bugs in some
older clients, but we should be precise - we use SetFileSize to
set file size and do not want to truncate file size to zero
accidently as happened on one Samba server beta by putting
zero instead of -1 here */
data_offset->EndOfFile = NO_CHANGE_64;
data_offset->NumOfBytes = NO_CHANGE_64;
data_offset->LastStatusChange = NO_CHANGE_64;
data_offset->LastAccessTime = NO_CHANGE_64;
data_offset->LastModificationTime = NO_CHANGE_64;
data_offset->Uid = cpu_to_le64(uid); data_offset->Uid = cpu_to_le64(uid);
data_offset->Gid = cpu_to_le64(gid); data_offset->Gid = cpu_to_le64(gid);
/* better to leave device as zero when it is */ /* better to leave device as zero when it is */
......
...@@ -31,7 +31,7 @@ ...@@ -31,7 +31,7 @@
#include "cifs_debug.h" #include "cifs_debug.h"
#include "cifs_fs_sb.h" #include "cifs_fs_sb.h"
void static void
renew_parental_timestamps(struct dentry *direntry) renew_parental_timestamps(struct dentry *direntry)
{ {
/* BB check if there is a way to get the kernel to do this or if we really need this */ /* BB check if there is a way to get the kernel to do this or if we really need this */
......
/*
* fs/cifs/export.c
*
* Copyright (C) International Business Machines Corp., 2007
* Author(s): Steve French (sfrench@us.ibm.com)
*
* Common Internet FileSystem (CIFS) client
*
* Operations related to support for exporting files via NFSD
*
* This library is free software; you can redistribute it and/or modify
* it under the terms of the GNU Lesser General Public License as published
* by the Free Software Foundation; either version 2.1 of the License, or
* (at your option) any later version.
*
* This library is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See
* the GNU Lesser General Public License for more details.
*
* You should have received a copy of the GNU Lesser General Public License
* along with this library; if not, write to the Free Software
* Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
*/
/*
* See Documentation/filesystems/Exporting
* and examples in fs/exportfs
*/
#include <linux/fs.h>
#ifdef CONFIG_CIFS_EXPERIMENTAL
static struct dentry *cifs_get_parent(struct dentry *dentry)
{
/* BB need to add code here eventually to enable export via NFSD */
return ERR_PTR(-EACCES);
}
struct export_operations cifs_export_ops = {
.get_parent = cifs_get_parent,
/* Following five export operations are unneeded so far and can default */
/* .get_dentry =
.get_name =
.find_exported_dentry =
.decode_fh =
.encode_fs = */
};
#endif /* EXPERIMENTAL */
...@@ -879,18 +879,19 @@ ssize_t cifs_user_write(struct file *file, const char __user *write_data, ...@@ -879,18 +879,19 @@ ssize_t cifs_user_write(struct file *file, const char __user *write_data,
cifs_stats_bytes_written(pTcon, total_written); cifs_stats_bytes_written(pTcon, total_written);
/* since the write may have blocked check these pointers again */ /* since the write may have blocked check these pointers again */
if (file->f_path.dentry) { if ((file->f_path.dentry) && (file->f_path.dentry->d_inode)) {
if (file->f_path.dentry->d_inode) { struct inode *inode = file->f_path.dentry->d_inode;
struct inode *inode = file->f_path.dentry->d_inode; /* Do not update local mtime - server will set its actual value on write
inode->i_ctime = inode->i_mtime = * inode->i_ctime = inode->i_mtime =
current_fs_time(inode->i_sb); * current_fs_time(inode->i_sb);*/
if (total_written > 0) { if (total_written > 0) {
if (*poffset > file->f_path.dentry->d_inode->i_size) spin_lock(&inode->i_lock);
i_size_write(file->f_path.dentry->d_inode, if (*poffset > file->f_path.dentry->d_inode->i_size)
i_size_write(file->f_path.dentry->d_inode,
*poffset); *poffset);
} spin_unlock(&inode->i_lock);
mark_inode_dirty_sync(file->f_path.dentry->d_inode);
} }
mark_inode_dirty_sync(file->f_path.dentry->d_inode);
} }
FreeXid(xid); FreeXid(xid);
return total_written; return total_written;
...@@ -1012,18 +1013,18 @@ static ssize_t cifs_write(struct file *file, const char *write_data, ...@@ -1012,18 +1013,18 @@ static ssize_t cifs_write(struct file *file, const char *write_data,
cifs_stats_bytes_written(pTcon, total_written); cifs_stats_bytes_written(pTcon, total_written);
/* since the write may have blocked check these pointers again */ /* since the write may have blocked check these pointers again */
if (file->f_path.dentry) { if ((file->f_path.dentry) && (file->f_path.dentry->d_inode)) {
if (file->f_path.dentry->d_inode) {
/*BB We could make this contingent on superblock ATIME flag too */ /*BB We could make this contingent on superblock ATIME flag too */
/* file->f_path.dentry->d_inode->i_ctime = /* file->f_path.dentry->d_inode->i_ctime =
file->f_path.dentry->d_inode->i_mtime = CURRENT_TIME;*/ file->f_path.dentry->d_inode->i_mtime = CURRENT_TIME;*/
if (total_written > 0) { if (total_written > 0) {
if (*poffset > file->f_path.dentry->d_inode->i_size) spin_lock(&file->f_path.dentry->d_inode->i_lock);
i_size_write(file->f_path.dentry->d_inode, if (*poffset > file->f_path.dentry->d_inode->i_size)
*poffset); i_size_write(file->f_path.dentry->d_inode,
} *poffset);
mark_inode_dirty_sync(file->f_path.dentry->d_inode); spin_unlock(&file->f_path.dentry->d_inode->i_lock);
} }
mark_inode_dirty_sync(file->f_path.dentry->d_inode);
} }
FreeXid(xid); FreeXid(xid);
return total_written; return total_written;
...@@ -1400,6 +1401,7 @@ static int cifs_commit_write(struct file *file, struct page *page, ...@@ -1400,6 +1401,7 @@ static int cifs_commit_write(struct file *file, struct page *page,
xid = GetXid(); xid = GetXid();
cFYI(1, ("commit write for page %p up to position %lld for %d", cFYI(1, ("commit write for page %p up to position %lld for %d",
page, position, to)); page, position, to));
spin_lock(&inode->i_lock);
if (position > inode->i_size) { if (position > inode->i_size) {
i_size_write(inode, position); i_size_write(inode, position);
/* if (file->private_data == NULL) { /* if (file->private_data == NULL) {
...@@ -1429,6 +1431,7 @@ static int cifs_commit_write(struct file *file, struct page *page, ...@@ -1429,6 +1431,7 @@ static int cifs_commit_write(struct file *file, struct page *page,
cFYI(1, (" SetEOF (commit write) rc = %d", rc)); cFYI(1, (" SetEOF (commit write) rc = %d", rc));
} */ } */
} }
spin_unlock(&inode->i_lock);
if (!PageUptodate(page)) { if (!PageUptodate(page)) {
position = ((loff_t)page->index << PAGE_CACHE_SHIFT) + offset; position = ((loff_t)page->index << PAGE_CACHE_SHIFT) + offset;
/* can not rely on (or let) writepage write this data */ /* can not rely on (or let) writepage write this data */
...@@ -1989,34 +1992,52 @@ static int cifs_prepare_write(struct file *file, struct page *page, ...@@ -1989,34 +1992,52 @@ static int cifs_prepare_write(struct file *file, struct page *page,
unsigned from, unsigned to) unsigned from, unsigned to)
{ {
int rc = 0; int rc = 0;
loff_t offset = (loff_t)page->index << PAGE_CACHE_SHIFT; loff_t i_size;
loff_t offset;
cFYI(1, ("prepare write for page %p from %d to %d",page,from,to)); cFYI(1, ("prepare write for page %p from %d to %d",page,from,to));
if (!PageUptodate(page)) { if (PageUptodate(page))
/* if (to - from != PAGE_CACHE_SIZE) { return 0;
void *kaddr = kmap_atomic(page, KM_USER0);
/* If we are writing a full page it will be up to date,
no need to read from the server */
if ((to == PAGE_CACHE_SIZE) && (from == 0)) {
SetPageUptodate(page);
return 0;
}
offset = (loff_t)page->index << PAGE_CACHE_SHIFT;
i_size = i_size_read(page->mapping->host);
if ((offset >= i_size) ||
((from == 0) && (offset + to) >= i_size)) {
/*
* We don't need to read data beyond the end of the file.
* zero it, and set the page uptodate
*/
void *kaddr = kmap_atomic(page, KM_USER0);
if (from)
memset(kaddr, 0, from); memset(kaddr, 0, from);
if (to < PAGE_CACHE_SIZE)
memset(kaddr + to, 0, PAGE_CACHE_SIZE - to); memset(kaddr + to, 0, PAGE_CACHE_SIZE - to);
flush_dcache_page(page); flush_dcache_page(page);
kunmap_atomic(kaddr, KM_USER0); kunmap_atomic(kaddr, KM_USER0);
} */ SetPageUptodate(page);
/* If we are writing a full page it will be up to date, } else if ((file->f_flags & O_ACCMODE) != O_WRONLY) {
no need to read from the server */
if ((to == PAGE_CACHE_SIZE) && (from == 0))
SetPageUptodate(page);
/* might as well read a page, it is fast enough */ /* might as well read a page, it is fast enough */
if ((file->f_flags & O_ACCMODE) != O_WRONLY) { rc = cifs_readpage_worker(file, page, &offset);
rc = cifs_readpage_worker(file, page, &offset); } else {
} else { /* we could try using another file handle if there is one -
/* should we try using another file handle if there is one - but how would we lock it to prevent close of that handle
how would we lock it to prevent close of that handle racing with this read? In any case
racing with this read? this will be written out by commit_write so is fine */
In any case this will be written out by commit_write */
}
} }
/* BB should we pass any errors back? /* we do not need to pass errors back
e.g. if we do not have read access to the file */ e.g. if we do not have read access to the file
because cifs_commit_write will do the right thing. -- shaggy */
return 0; return 0;
} }
......
...@@ -143,10 +143,10 @@ int cifs_get_inode_info_unix(struct inode **pinode, ...@@ -143,10 +143,10 @@ int cifs_get_inode_info_unix(struct inode **pinode,
inode->i_gid = le64_to_cpu(findData.Gid); inode->i_gid = le64_to_cpu(findData.Gid);
inode->i_nlink = le64_to_cpu(findData.Nlinks); inode->i_nlink = le64_to_cpu(findData.Nlinks);
spin_lock(&inode->i_lock);
if (is_size_safe_to_change(cifsInfo, end_of_file)) { if (is_size_safe_to_change(cifsInfo, end_of_file)) {
/* can not safely change the file size here if the /* can not safely change the file size here if the
client is writing to it due to potential races */ client is writing to it due to potential races */
i_size_write(inode, end_of_file); i_size_write(inode, end_of_file);
/* blksize needs to be multiple of two. So safer to default to /* blksize needs to be multiple of two. So safer to default to
...@@ -162,6 +162,7 @@ int cifs_get_inode_info_unix(struct inode **pinode, ...@@ -162,6 +162,7 @@ int cifs_get_inode_info_unix(struct inode **pinode,
/* for this calculation */ /* for this calculation */
inode->i_blocks = (512 - 1 + num_of_bytes) >> 9; inode->i_blocks = (512 - 1 + num_of_bytes) >> 9;
} }
spin_unlock(&inode->i_lock);
if (num_of_bytes < end_of_file) 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"));
...@@ -496,6 +497,8 @@ int cifs_get_inode_info(struct inode **pinode, ...@@ -496,6 +497,8 @@ int cifs_get_inode_info(struct inode **pinode,
/* BB add code here - /* BB add code here -
validate if device or weird share or device type? */ validate if device or weird share or device type? */
} }
spin_lock(&inode->i_lock);
if (is_size_safe_to_change(cifsInfo, le64_to_cpu(pfindData->EndOfFile))) { if (is_size_safe_to_change(cifsInfo, le64_to_cpu(pfindData->EndOfFile))) {
/* can not safely shrink the file size here if the /* can not safely shrink the file size here if the
client is writing to it due to potential races */ client is writing to it due to potential races */
...@@ -506,6 +509,7 @@ int cifs_get_inode_info(struct inode **pinode, ...@@ -506,6 +509,7 @@ int cifs_get_inode_info(struct inode **pinode,
inode->i_blocks = (512 - 1 + le64_to_cpu( inode->i_blocks = (512 - 1 + le64_to_cpu(
pfindData->AllocationSize)) >> 9; pfindData->AllocationSize)) >> 9;
} }
spin_unlock(&inode->i_lock);
inode->i_nlink = le32_to_cpu(pfindData->NumberOfLinks); inode->i_nlink = le32_to_cpu(pfindData->NumberOfLinks);
...@@ -834,8 +838,10 @@ int cifs_rmdir(struct inode *inode, struct dentry *direntry) ...@@ -834,8 +838,10 @@ int cifs_rmdir(struct inode *inode, struct dentry *direntry)
if (!rc) { if (!rc) {
drop_nlink(inode); drop_nlink(inode);
spin_lock(&direntry->d_inode->i_lock);
i_size_write(direntry->d_inode,0); i_size_write(direntry->d_inode,0);
clear_nlink(direntry->d_inode); clear_nlink(direntry->d_inode);
spin_unlock(&direntry->d_inode->i_lock);
} }
cifsInode = CIFS_I(direntry->d_inode); cifsInode = CIFS_I(direntry->d_inode);
...@@ -1128,6 +1134,52 @@ static int cifs_truncate_page(struct address_space *mapping, loff_t from) ...@@ -1128,6 +1134,52 @@ static int cifs_truncate_page(struct address_space *mapping, loff_t from)
return rc; return rc;
} }
static int cifs_vmtruncate(struct inode * inode, loff_t offset)
{
struct address_space *mapping = inode->i_mapping;
unsigned long limit;
spin_lock(&inode->i_lock);
if (inode->i_size < offset)
goto do_expand;
/*
* truncation of in-use swapfiles is disallowed - it would cause
* subsequent swapout to scribble on the now-freed blocks.
*/
if (IS_SWAPFILE(inode)) {
spin_unlock(&inode->i_lock);
goto out_busy;
}
i_size_write(inode, offset);
spin_unlock(&inode->i_lock);
unmap_mapping_range(mapping, offset + PAGE_SIZE - 1, 0, 1);
truncate_inode_pages(mapping, offset);
goto out_truncate;
do_expand:
limit = current->signal->rlim[RLIMIT_FSIZE].rlim_cur;
if (limit != RLIM_INFINITY && offset > limit) {
spin_unlock(&inode->i_lock);
goto out_sig;
}
if (offset > inode->i_sb->s_maxbytes) {
spin_unlock(&inode->i_lock);
goto out_big;
}
i_size_write(inode, offset);
spin_unlock(&inode->i_lock);
out_truncate:
if (inode->i_op && inode->i_op->truncate)
inode->i_op->truncate(inode);
return 0;
out_sig:
send_sig(SIGXFSZ, current, 0);
out_big:
return -EFBIG;
out_busy:
return -ETXTBSY;
}
int cifs_setattr(struct dentry *direntry, struct iattr *attrs) int cifs_setattr(struct dentry *direntry, struct iattr *attrs)
{ {
int xid; int xid;
...@@ -1244,7 +1296,7 @@ int cifs_setattr(struct dentry *direntry, struct iattr *attrs) ...@@ -1244,7 +1296,7 @@ int cifs_setattr(struct dentry *direntry, struct iattr *attrs)
*/ */
if (rc == 0) { if (rc == 0) {
rc = vmtruncate(direntry->d_inode, attrs->ia_size); rc = cifs_vmtruncate(direntry->d_inode, attrs->ia_size);
cifs_truncate_page(direntry->d_inode->i_mapping, cifs_truncate_page(direntry->d_inode->i_mapping,
direntry->d_inode->i_size); direntry->d_inode->i_size);
} else } else
...@@ -1379,9 +1431,11 @@ int cifs_setattr(struct dentry *direntry, struct iattr *attrs) ...@@ -1379,9 +1431,11 @@ int cifs_setattr(struct dentry *direntry, struct iattr *attrs)
return rc; return rc;
} }
#if 0
void cifs_delete_inode(struct inode *inode) void cifs_delete_inode(struct inode *inode)
{ {
cFYI(1, ("In cifs_delete_inode, inode = 0x%p", inode)); cFYI(1, ("In cifs_delete_inode, inode = 0x%p", inode));
/* may have to add back in if and when safe distributed caching of /* may have to add back in if and when safe distributed caching of
directories added e.g. via FindNotify */ directories added e.g. via FindNotify */
} }
#endif
...@@ -3,7 +3,7 @@ ...@@ -3,7 +3,7 @@
* *
* Directory search handling * Directory search handling
* *
* Copyright (C) International Business Machines Corp., 2004, 2005 * Copyright (C) International Business Machines Corp., 2004, 2007
* Author(s): Steve French (sfrench@us.ibm.com) * Author(s): Steve French (sfrench@us.ibm.com)
* *
* This library is free software; you can redistribute it and/or modify * This library is free software; you can redistribute it and/or modify
...@@ -226,6 +226,7 @@ static void fill_in_inode(struct inode *tmp_inode, int new_buf_type, ...@@ -226,6 +226,7 @@ static void fill_in_inode(struct inode *tmp_inode, int new_buf_type,
atomic_set(&cifsInfo->inUse, 1); atomic_set(&cifsInfo->inUse, 1);
} }
spin_lock(&tmp_inode->i_lock);
if (is_size_safe_to_change(cifsInfo, end_of_file)) { if (is_size_safe_to_change(cifsInfo, end_of_file)) {
/* can not safely change the file size here if the /* can not safely change the file size here if the
client is writing to it due to potential races */ client is writing to it due to potential races */
...@@ -235,6 +236,7 @@ static void fill_in_inode(struct inode *tmp_inode, int new_buf_type, ...@@ -235,6 +236,7 @@ static void fill_in_inode(struct inode *tmp_inode, int new_buf_type,
/* for this calculation, even though the reported blocksize is larger */ /* for this calculation, even though the reported blocksize is larger */
tmp_inode->i_blocks = (512 - 1 + allocation_size) >> 9; tmp_inode->i_blocks = (512 - 1 + allocation_size) >> 9;
} }
spin_unlock(&tmp_inode->i_lock);
if (allocation_size < end_of_file) if (allocation_size < end_of_file)
cFYI(1, ("May be sparse file, allocation less than file size")); cFYI(1, ("May be sparse file, allocation less than file size"));
...@@ -355,6 +357,7 @@ static void unix_fill_in_inode(struct inode *tmp_inode, ...@@ -355,6 +357,7 @@ static void unix_fill_in_inode(struct inode *tmp_inode,
tmp_inode->i_gid = le64_to_cpu(pfindData->Gid); tmp_inode->i_gid = le64_to_cpu(pfindData->Gid);
tmp_inode->i_nlink = le64_to_cpu(pfindData->Nlinks); tmp_inode->i_nlink = le64_to_cpu(pfindData->Nlinks);
spin_lock(&tmp_inode->i_lock);
if (is_size_safe_to_change(cifsInfo, end_of_file)) { if (is_size_safe_to_change(cifsInfo, end_of_file)) {
/* can not safely change the file size here if the /* can not safely change the file size here if the
client is writing to it due to potential races */ client is writing to it due to potential races */
...@@ -364,6 +367,7 @@ static void unix_fill_in_inode(struct inode *tmp_inode, ...@@ -364,6 +367,7 @@ static void unix_fill_in_inode(struct inode *tmp_inode,
/* for this calculation, not the real blocksize */ /* for this calculation, not the real blocksize */
tmp_inode->i_blocks = (512 - 1 + num_of_bytes) >> 9; tmp_inode->i_blocks = (512 - 1 + num_of_bytes) >> 9;
} }
spin_unlock(&tmp_inode->i_lock);
if (S_ISREG(tmp_inode->i_mode)) { if (S_ISREG(tmp_inode->i_mode)) {
cFYI(1, ("File inode")); cFYI(1, ("File inode"));
......
...@@ -499,7 +499,7 @@ SendReceive2(const unsigned int xid, struct cifsSesInfo *ses, ...@@ -499,7 +499,7 @@ SendReceive2(const unsigned int xid, struct cifsSesInfo *ses,
due to last connection to this server being unmounted */ due to last connection to this server being unmounted */
if (signal_pending(current)) { if (signal_pending(current)) {
/* if signal pending do not hold up user for full smb timeout /* if signal pending do not hold up user for full smb timeout
but we still give response a change to complete */ but we still give response a chance to complete */
timeout = 2 * HZ; timeout = 2 * HZ;
} }
...@@ -587,7 +587,6 @@ SendReceive2(const unsigned int xid, struct cifsSesInfo *ses, ...@@ -587,7 +587,6 @@ SendReceive2(const unsigned int xid, struct cifsSesInfo *ses,
} }
out: out:
DeleteMidQEntry(midQ); DeleteMidQEntry(midQ);
atomic_dec(&ses->server->inFlight); atomic_dec(&ses->server->inFlight);
wake_up(&ses->server->request_q); wake_up(&ses->server->request_q);
...@@ -681,7 +680,7 @@ SendReceive(const unsigned int xid, struct cifsSesInfo *ses, ...@@ -681,7 +680,7 @@ SendReceive(const unsigned int xid, struct cifsSesInfo *ses,
due to last connection to this server being unmounted */ due to last connection to this server being unmounted */
if (signal_pending(current)) { if (signal_pending(current)) {
/* if signal pending do not hold up user for full smb timeout /* if signal pending do not hold up user for full smb timeout
but we still give response a change to complete */ but we still give response a chance to complete */
timeout = 2 * HZ; timeout = 2 * HZ;
} }
...@@ -765,7 +764,6 @@ SendReceive(const unsigned int xid, struct cifsSesInfo *ses, ...@@ -765,7 +764,6 @@ SendReceive(const unsigned int xid, struct cifsSesInfo *ses,
} }
out: out:
DeleteMidQEntry(midQ); DeleteMidQEntry(midQ);
atomic_dec(&ses->server->inFlight); atomic_dec(&ses->server->inFlight);
wake_up(&ses->server->request_q); wake_up(&ses->server->request_q);
......
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment