[CIFS] Use posix open on file open when server supports it

Signed-off-by: Steve French <sfrench@us.ibm.com>
This commit is contained in:
Steve French 2009-03-03 18:00:34 +00:00
parent fcc7c09d94
commit 276a74a483

View File

@ -124,6 +124,80 @@ static inline int cifs_get_disposition(unsigned int flags)
return FILE_OPEN; return FILE_OPEN;
} }
/* all arguments to this function must be checked for validity in caller */
static inline int cifs_posix_open_inode_helper(struct inode *inode,
struct file *file, struct cifsInodeInfo *pCifsInode,
struct cifsFileInfo *pCifsFile, int oplock, u16 netfid)
{
struct cifs_sb_info *cifs_sb = CIFS_SB(inode->i_sb);
/* struct timespec temp; */ /* BB REMOVEME BB */
file->private_data = kmalloc(sizeof(struct cifsFileInfo), GFP_KERNEL);
if (file->private_data == NULL)
return -ENOMEM;
pCifsFile = cifs_init_private(file->private_data, inode, file, netfid);
write_lock(&GlobalSMBSeslock);
list_add(&pCifsFile->tlist, &cifs_sb->tcon->openFileList);
pCifsInode = CIFS_I(file->f_path.dentry->d_inode);
if (pCifsInode == NULL) {
write_unlock(&GlobalSMBSeslock);
return -EINVAL;
}
/* want handles we can use to read with first
in the list so we do not have to walk the
list to search for one in write_begin */
if ((file->f_flags & O_ACCMODE) == O_WRONLY) {
list_add_tail(&pCifsFile->flist,
&pCifsInode->openFileList);
} else {
list_add(&pCifsFile->flist,
&pCifsInode->openFileList);
}
if (pCifsInode->clientCanCacheRead) {
/* we have the inode open somewhere else
no need to discard cache data */
goto psx_client_can_cache;
}
/* BB FIXME need to fix this check to move it earlier into posix_open
BB fIX following section BB FIXME */
/* if not oplocked, invalidate inode pages if mtime or file
size changed */
/* temp = cifs_NTtimeToUnix(le64_to_cpu(buf->LastWriteTime));
if (timespec_equal(&file->f_path.dentry->d_inode->i_mtime, &temp) &&
(file->f_path.dentry->d_inode->i_size ==
(loff_t)le64_to_cpu(buf->EndOfFile))) {
cFYI(1, ("inode unchanged on server"));
} else {
if (file->f_path.dentry->d_inode->i_mapping) {
rc = filemap_write_and_wait(file->f_path.dentry->d_inode->i_mapping);
if (rc != 0)
CIFS_I(file->f_path.dentry->d_inode)->write_behind_rc = rc;
}
cFYI(1, ("invalidating remote inode since open detected it "
"changed"));
invalidate_remote_inode(file->f_path.dentry->d_inode);
} */
psx_client_can_cache:
if ((oplock & 0xF) == OPLOCK_EXCLUSIVE) {
pCifsInode->clientCanCacheAll = true;
pCifsInode->clientCanCacheRead = true;
cFYI(1, ("Exclusive Oplock granted on inode %p",
file->f_path.dentry->d_inode));
} else if ((oplock & 0xF) == OPLOCK_READ)
pCifsInode->clientCanCacheRead = true;
/* will have to change the unlock if we reenable the
filemap_fdatawrite (which does not seem necessary */
write_unlock(&GlobalSMBSeslock);
return 0;
}
/* all arguments to this function must be checked for validity in caller */ /* all arguments to this function must be checked for validity in caller */
static inline int cifs_open_inode_helper(struct inode *inode, struct file *file, static inline int cifs_open_inode_helper(struct inode *inode, struct file *file,
struct cifsInodeInfo *pCifsInode, struct cifsFileInfo *pCifsFile, struct cifsInodeInfo *pCifsInode, struct cifsFileInfo *pCifsFile,
@ -195,7 +269,7 @@ int cifs_open(struct inode *inode, struct file *file)
int rc = -EACCES; int rc = -EACCES;
int xid, oplock; int xid, oplock;
struct cifs_sb_info *cifs_sb; struct cifs_sb_info *cifs_sb;
struct cifsTconInfo *pTcon; struct cifsTconInfo *tcon;
struct cifsFileInfo *pCifsFile; struct cifsFileInfo *pCifsFile;
struct cifsInodeInfo *pCifsInode; struct cifsInodeInfo *pCifsInode;
struct list_head *tmp; struct list_head *tmp;
@ -208,7 +282,7 @@ int cifs_open(struct inode *inode, struct file *file)
xid = GetXid(); xid = GetXid();
cifs_sb = CIFS_SB(inode->i_sb); cifs_sb = CIFS_SB(inode->i_sb);
pTcon = cifs_sb->tcon; tcon = cifs_sb->tcon;
if (file->f_flags & O_CREAT) { if (file->f_flags & O_CREAT) {
/* search inode for this file and fill in file->private_data */ /* search inode for this file and fill in file->private_data */
@ -248,6 +322,35 @@ int cifs_open(struct inode *inode, struct file *file)
cFYI(1, ("inode = 0x%p file flags are 0x%x for %s", cFYI(1, ("inode = 0x%p file flags are 0x%x for %s",
inode, file->f_flags, full_path)); inode, file->f_flags, full_path));
if (oplockEnabled)
oplock = REQ_OPLOCK;
else
oplock = 0;
if (tcon->unix_ext && (tcon->ses->capabilities & CAP_UNIX) &&
(CIFS_UNIX_POSIX_PATH_OPS_CAP &
le64_to_cpu(tcon->fsUnixInfo.Capability))) {
int oflags = (int) cifs_posix_convert_flags(file->f_flags);
/* can not refresh inode info since size could be stale */
rc = cifs_posix_open(full_path, &inode, inode->i_sb,
cifs_sb->mnt_file_mode /* ignored */,
oflags, &oplock, &netfid, xid);
if (rc == 0) {
cFYI(1, ("posix open succeeded"));
/* no need for special case handling of setting mode
on read only files needed here */
cifs_posix_open_inode_helper(inode, file, pCifsInode,
pCifsFile, oplock, netfid);
goto out;
} else if ((rc != -EIO) && (rc != -EREMOTE) &&
(rc != -EOPNOTSUPP)) /* path not found or net err */
goto out;
/* fallthrough to retry open the old way on operation
not supported or DFS errors */
}
desiredAccess = cifs_convert_flags(file->f_flags); desiredAccess = cifs_convert_flags(file->f_flags);
/********************************************************************* /*********************************************************************
@ -276,11 +379,6 @@ int cifs_open(struct inode *inode, struct file *file)
disposition = cifs_get_disposition(file->f_flags); disposition = cifs_get_disposition(file->f_flags);
if (oplockEnabled)
oplock = REQ_OPLOCK;
else
oplock = 0;
/* BB pass O_SYNC flag through on file attributes .. BB */ /* BB pass O_SYNC flag through on file attributes .. BB */
/* Also refresh inode by passing in file_info buf returned by SMBOpen /* Also refresh inode by passing in file_info buf returned by SMBOpen
@ -297,7 +395,7 @@ int cifs_open(struct inode *inode, struct file *file)
} }
if (cifs_sb->tcon->ses->capabilities & CAP_NT_SMBS) if (cifs_sb->tcon->ses->capabilities & CAP_NT_SMBS)
rc = CIFSSMBOpen(xid, pTcon, full_path, disposition, rc = CIFSSMBOpen(xid, tcon, full_path, disposition,
desiredAccess, CREATE_NOT_DIR, &netfid, &oplock, buf, desiredAccess, CREATE_NOT_DIR, &netfid, &oplock, buf,
cifs_sb->local_nls, cifs_sb->mnt_cifs_flags cifs_sb->local_nls, cifs_sb->mnt_cifs_flags
& CIFS_MOUNT_MAP_SPECIAL_CHR); & CIFS_MOUNT_MAP_SPECIAL_CHR);
@ -306,7 +404,7 @@ int cifs_open(struct inode *inode, struct file *file)
if (rc == -EIO) { if (rc == -EIO) {
/* Old server, try legacy style OpenX */ /* Old server, try legacy style OpenX */
rc = SMBLegacyOpen(xid, pTcon, full_path, disposition, rc = SMBLegacyOpen(xid, tcon, full_path, disposition,
desiredAccess, CREATE_NOT_DIR, &netfid, &oplock, buf, desiredAccess, CREATE_NOT_DIR, &netfid, &oplock, buf,
cifs_sb->local_nls, cifs_sb->mnt_cifs_flags cifs_sb->local_nls, cifs_sb->mnt_cifs_flags
& CIFS_MOUNT_MAP_SPECIAL_CHR); & CIFS_MOUNT_MAP_SPECIAL_CHR);
@ -323,12 +421,12 @@ int cifs_open(struct inode *inode, struct file *file)
} }
pCifsFile = cifs_init_private(file->private_data, inode, file, netfid); pCifsFile = cifs_init_private(file->private_data, inode, file, netfid);
write_lock(&GlobalSMBSeslock); write_lock(&GlobalSMBSeslock);
list_add(&pCifsFile->tlist, &pTcon->openFileList); list_add(&pCifsFile->tlist, &tcon->openFileList);
pCifsInode = CIFS_I(file->f_path.dentry->d_inode); pCifsInode = CIFS_I(file->f_path.dentry->d_inode);
if (pCifsInode) { if (pCifsInode) {
rc = cifs_open_inode_helper(inode, file, pCifsInode, rc = cifs_open_inode_helper(inode, file, pCifsInode,
pCifsFile, pTcon, pCifsFile, tcon,
&oplock, buf, full_path, xid); &oplock, buf, full_path, xid);
} else { } else {
write_unlock(&GlobalSMBSeslock); write_unlock(&GlobalSMBSeslock);
@ -337,7 +435,7 @@ int cifs_open(struct inode *inode, struct file *file)
if (oplock & CIFS_CREATE_ACTION) { if (oplock & CIFS_CREATE_ACTION) {
/* time to set mode which we can not set earlier due to /* time to set mode which we can not set earlier due to
problems creating new read-only files */ problems creating new read-only files */
if (pTcon->unix_ext) { if (tcon->unix_ext) {
struct cifs_unix_set_info_args args = { struct cifs_unix_set_info_args args = {
.mode = inode->i_mode, .mode = inode->i_mode,
.uid = NO_CHANGE_64, .uid = NO_CHANGE_64,
@ -347,7 +445,7 @@ int cifs_open(struct inode *inode, struct file *file)
.mtime = NO_CHANGE_64, .mtime = NO_CHANGE_64,
.device = 0, .device = 0,
}; };
CIFSSMBUnixSetInfo(xid, pTcon, full_path, &args, CIFSSMBUnixSetInfo(xid, tcon, full_path, &args,
cifs_sb->local_nls, cifs_sb->local_nls,
cifs_sb->mnt_cifs_flags & cifs_sb->mnt_cifs_flags &
CIFS_MOUNT_MAP_SPECIAL_CHR); CIFS_MOUNT_MAP_SPECIAL_CHR);