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
This commit is contained in:
commit
9f6632d629
@ -1,3 +1,10 @@
|
|||||||
|
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 @@
|
|||||||
#
|
#
|
||||||
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
|
||||||
|
16
fs/cifs/TODO
16
fs/cifs/TODO
@ -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
|
|||||||
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
|
|||||||
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
|
|||||||
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,
|
||||||
|
@ -1,7 +1,7 @@
|
|||||||
/*
|
/*
|
||||||
* 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 @@
|
|||||||
|
|
||||||
#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;
|
|||||||
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,
|
|||||||
|
|
||||||
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;
|
|||||||
/* 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 */
|
|||||||
*/
|
*/
|
||||||
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 @@
|
|||||||
*/
|
*/
|
||||||
#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);
|
|||||||
#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 @@ setPermsRetry:
|
|||||||
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 @@
|
|||||||
#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 */
|
||||||
|
52
fs/cifs/export.c
Normal file
52
fs/cifs/export.c
Normal file
@ -0,0 +1,52 @@
|
|||||||
|
/*
|
||||||
|
* 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 */
|
||||||
|
|
111
fs/cifs/file.c
111
fs/cifs/file.c
@ -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,
|
|||||||
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,
|
|||||||
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,
|
|||||||
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,
|
|||||||
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;
|
||||||
cFYI(1, ("prepare write for page %p from %d to %d",page,from,to));
|
loff_t offset;
|
||||||
if (!PageUptodate(page)) {
|
|
||||||
/* if (to - from != PAGE_CACHE_SIZE) {
|
|
||||||
void *kaddr = kmap_atomic(page, KM_USER0);
|
|
||||||
memset(kaddr, 0, from);
|
|
||||||
memset(kaddr + to, 0, PAGE_CACHE_SIZE - to);
|
|
||||||
flush_dcache_page(page);
|
|
||||||
kunmap_atomic(kaddr, 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);
|
|
||||||
|
|
||||||
/* might as well read a page, it is fast enough */
|
cFYI(1, ("prepare write for page %p from %d to %d",page,from,to));
|
||||||
if ((file->f_flags & O_ACCMODE) != O_WRONLY) {
|
if (PageUptodate(page))
|
||||||
rc = cifs_readpage_worker(file, page, &offset);
|
return 0;
|
||||||
} else {
|
|
||||||
/* should we try using another file handle if there is one -
|
/* If we are writing a full page it will be up to date,
|
||||||
how would we lock it to prevent close of that handle
|
no need to read from the server */
|
||||||
racing with this read?
|
if ((to == PAGE_CACHE_SIZE) && (from == 0)) {
|
||||||
In any case this will be written out by commit_write */
|
SetPageUptodate(page);
|
||||||
}
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
/* BB should we pass any errors back?
|
offset = (loff_t)page->index << PAGE_CACHE_SHIFT;
|
||||||
e.g. if we do not have read access to the file */
|
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);
|
||||||
|
if (to < PAGE_CACHE_SIZE)
|
||||||
|
memset(kaddr + to, 0, PAGE_CACHE_SIZE - to);
|
||||||
|
flush_dcache_page(page);
|
||||||
|
kunmap_atomic(kaddr, KM_USER0);
|
||||||
|
SetPageUptodate(page);
|
||||||
|
} else if ((file->f_flags & O_ACCMODE) != O_WRONLY) {
|
||||||
|
/* might as well read a page, it is fast enough */
|
||||||
|
rc = cifs_readpage_worker(file, page, &offset);
|
||||||
|
} else {
|
||||||
|
/* we could try using another file handle if there is one -
|
||||||
|
but how would we lock it to prevent close of that handle
|
||||||
|
racing with this read? In any case
|
||||||
|
this will be written out by commit_write so is fine */
|
||||||
|
}
|
||||||
|
|
||||||
|
/* we do not need to pass errors back
|
||||||
|
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,
|
|||||||
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,
|
|||||||
/* 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,
|
|||||||
/* 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,
|
|||||||
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)
|
|||||||
|
|
||||||
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)
|
|||||||
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)
|
|||||||
*/
|
*/
|
||||||
|
|
||||||
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 @@ cifs_setattr_exit:
|
|||||||
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 @@
|
|||||||
*
|
*
|
||||||
* 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,
|
|||||||
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,
|
|||||||
/* 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,
|
|||||||
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,
|
|||||||
/* 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,
|
|||||||
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,
|
|||||||
}
|
}
|
||||||
|
|
||||||
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,
|
|||||||
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,
|
|||||||
}
|
}
|
||||||
|
|
||||||
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);
|
||||||
|
Loading…
Reference in New Issue
Block a user