Donate to e Foundation | Murena handsets with /e/OS | Own a part of Murena! Learn more

Commit 276a74a4 authored by Steve French's avatar Steve French
Browse files

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



Signed-off-by: default avatarSteve French <sfrench@us.ibm.com>
parent fcc7c09d
Loading
Loading
Loading
Loading
+111 −13
Original line number Diff line number Diff line
@@ -124,6 +124,80 @@ static inline int cifs_get_disposition(unsigned int flags)
		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 */
static inline int cifs_open_inode_helper(struct inode *inode, struct file *file,
	struct cifsInodeInfo *pCifsInode, struct cifsFileInfo *pCifsFile,
@@ -195,7 +269,7 @@ int cifs_open(struct inode *inode, struct file *file)
	int rc = -EACCES;
	int xid, oplock;
	struct cifs_sb_info *cifs_sb;
	struct cifsTconInfo *pTcon;
	struct cifsTconInfo *tcon;
	struct cifsFileInfo *pCifsFile;
	struct cifsInodeInfo *pCifsInode;
	struct list_head *tmp;
@@ -208,7 +282,7 @@ int cifs_open(struct inode *inode, struct file *file)
	xid = GetXid();

	cifs_sb = CIFS_SB(inode->i_sb);
	pTcon = cifs_sb->tcon;
	tcon = cifs_sb->tcon;

	if (file->f_flags & O_CREAT) {
		/* 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",
		 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);

/*********************************************************************
@@ -276,11 +379,6 @@ int cifs_open(struct inode *inode, struct file *file)

	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 */

	/* 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)
		rc = CIFSSMBOpen(xid, pTcon, full_path, disposition,
		rc = CIFSSMBOpen(xid, tcon, full_path, disposition,
			 desiredAccess, CREATE_NOT_DIR, &netfid, &oplock, buf,
			 cifs_sb->local_nls, cifs_sb->mnt_cifs_flags
				 & CIFS_MOUNT_MAP_SPECIAL_CHR);
@@ -306,7 +404,7 @@ int cifs_open(struct inode *inode, struct file *file)

	if (rc == -EIO) {
		/* 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,
			cifs_sb->local_nls, cifs_sb->mnt_cifs_flags
				& 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);
	write_lock(&GlobalSMBSeslock);
	list_add(&pCifsFile->tlist, &pTcon->openFileList);
	list_add(&pCifsFile->tlist, &tcon->openFileList);

	pCifsInode = CIFS_I(file->f_path.dentry->d_inode);
	if (pCifsInode) {
		rc = cifs_open_inode_helper(inode, file, pCifsInode,
					    pCifsFile, pTcon,
					    pCifsFile, tcon,
					    &oplock, buf, full_path, xid);
	} else {
		write_unlock(&GlobalSMBSeslock);
@@ -337,7 +435,7 @@ int cifs_open(struct inode *inode, struct file *file)
	if (oplock & CIFS_CREATE_ACTION) {
		/* time to set mode which we can not set earlier due to
		   problems creating new read-only files */
		if (pTcon->unix_ext) {
		if (tcon->unix_ext) {
			struct cifs_unix_set_info_args args = {
				.mode	= inode->i_mode,
				.uid	= NO_CHANGE_64,
@@ -347,7 +445,7 @@ int cifs_open(struct inode *inode, struct file *file)
				.mtime	= NO_CHANGE_64,
				.device	= 0,
			};
			CIFSSMBUnixSetInfo(xid, pTcon, full_path, &args,
			CIFSSMBUnixSetInfo(xid, tcon, full_path, &args,
					    cifs_sb->local_nls,
					    cifs_sb->mnt_cifs_flags &
						CIFS_MOUNT_MAP_SPECIAL_CHR);