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

Commit 75f12983 authored by Christoph Hellwig's avatar Christoph Hellwig Committed by Steve French
Browse files

[CIFS] consolidate duplicate code in posix/unix inode handling

parent e086fcea
Loading
Loading
Loading
Loading
+103 −176
Original line number Diff line number Diff line
@@ -69,6 +69,90 @@ static void cifs_set_ops(struct inode *inode)
	}
}

static void cifs_unix_info_to_inode(struct inode *inode,
		FILE_UNIX_BASIC_INFO *info, int force_uid_gid)
{
	struct cifs_sb_info *cifs_sb = CIFS_SB(inode->i_sb);
	struct cifsInodeInfo *cifsInfo = CIFS_I(inode);
	__u64 num_of_bytes = le64_to_cpu(info->NumOfBytes);
	__u64 end_of_file = le64_to_cpu(info->EndOfFile);

	inode->i_atime = cifs_NTtimeToUnix(le64_to_cpu(info->LastAccessTime));
	inode->i_mtime =
		cifs_NTtimeToUnix(le64_to_cpu(info->LastModificationTime));
	inode->i_ctime = cifs_NTtimeToUnix(le64_to_cpu(info->LastStatusChange));
	inode->i_mode = le64_to_cpu(info->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;
	switch (le32_to_cpu(info->Type)) {
	case UNIX_FILE:
		inode->i_mode |= S_IFREG;
		break;
	case UNIX_SYMLINK:
		inode->i_mode |= S_IFLNK;
		break;
	case UNIX_DIR:
		inode->i_mode |= S_IFDIR;
		break;
	case UNIX_CHARDEV:
		inode->i_mode |= S_IFCHR;
		inode->i_rdev = MKDEV(le64_to_cpu(info->DevMajor),
				      le64_to_cpu(info->DevMinor) & MINORMASK);
		break;
	case UNIX_BLOCKDEV:
		inode->i_mode |= S_IFBLK;
		inode->i_rdev = MKDEV(le64_to_cpu(info->DevMajor),
				      le64_to_cpu(info->DevMinor) & MINORMASK);
		break;
	case UNIX_FIFO:
		inode->i_mode |= S_IFIFO;
		break;
	case UNIX_SOCKET:
		inode->i_mode |= S_IFSOCK;
		break;
	default:
		/* safest to call it a file if we do not know */
		inode->i_mode |= S_IFREG;
		cFYI(1, ("unknown type %d", le32_to_cpu(info->Type)));
		break;
	}

	if ((cifs_sb->mnt_cifs_flags & CIFS_MOUNT_OVERR_UID) &&
	    !force_uid_gid)
		inode->i_uid = cifs_sb->mnt_uid;
	else
		inode->i_uid = le64_to_cpu(info->Uid);

	if ((cifs_sb->mnt_cifs_flags & CIFS_MOUNT_OVERR_GID) &&
	    !force_uid_gid)
		inode->i_gid = cifs_sb->mnt_gid;
	else
		inode->i_gid = le64_to_cpu(info->Gid);

	inode->i_nlink = le64_to_cpu(info->Nlinks);

	spin_lock(&inode->i_lock);
	if (is_size_safe_to_change(cifsInfo, end_of_file)) {
		/*
		 * We can not safely change the file size here if the client
		 * is writing to it due to potential races.
		 */
		i_size_write(inode, end_of_file);

		/*
		 * i_blocks is not related to (i_size / i_blksize),
		 * but instead 512 byte (2**9) size is required for
		 * calculating num blocks.
		 */
		inode->i_blocks = (512 - 1 + num_of_bytes) >> 9;
	}
	spin_unlock(&inode->i_lock);
}

int cifs_get_inode_info_unix(struct inode **pinode,
	const unsigned char *search_path, struct super_block *sb, int xid)
{
@@ -114,7 +198,6 @@ int cifs_get_inode_info_unix(struct inode **pinode,
		}
	} else {
		struct cifsInodeInfo *cifsInfo;
		__u32 type = le32_to_cpu(findData.Type);
		__u64 num_of_bytes = le64_to_cpu(findData.NumOfBytes);
		__u64 end_of_file = le64_to_cpu(findData.EndOfFile);

@@ -145,73 +228,8 @@ int cifs_get_inode_info_unix(struct inode **pinode,
		/* this is ok to set on every inode revalidate */
		atomic_set(&cifsInfo->inUse, 1);

		inode->i_atime =
		    cifs_NTtimeToUnix(le64_to_cpu(findData.LastAccessTime));
		inode->i_mtime =
		    cifs_NTtimeToUnix(le64_to_cpu
				(findData.LastModificationTime));
		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) {
			inode->i_mode |= S_IFLNK;
		} else if (type == UNIX_DIR) {
			inode->i_mode |= S_IFDIR;
		} else if (type == UNIX_CHARDEV) {
			inode->i_mode |= S_IFCHR;
			inode->i_rdev = MKDEV(le64_to_cpu(findData.DevMajor),
				le64_to_cpu(findData.DevMinor) & MINORMASK);
		} else if (type == UNIX_BLOCKDEV) {
			inode->i_mode |= S_IFBLK;
			inode->i_rdev = MKDEV(le64_to_cpu(findData.DevMajor),
				le64_to_cpu(findData.DevMinor) & MINORMASK);
		} else if (type == UNIX_FIFO) {
			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));
		}

		if (cifs_sb->mnt_cifs_flags & CIFS_MOUNT_OVERR_UID)
			inode->i_uid = cifs_sb->mnt_uid;
		else
			inode->i_uid = le64_to_cpu(findData.Uid);

		if (cifs_sb->mnt_cifs_flags & CIFS_MOUNT_OVERR_GID)
			inode->i_gid = cifs_sb->mnt_gid;
		else
			inode->i_gid = le64_to_cpu(findData.Gid);
		cifs_unix_info_to_inode(inode, &findData, 0);

		inode->i_nlink = le64_to_cpu(findData.Nlinks);

		spin_lock(&inode->i_lock);
		if (is_size_safe_to_change(cifsInfo, end_of_file)) {
		/* can not safely change the file size here if the
		   client is writing to it due to potential races */
			i_size_write(inode, end_of_file);

		/* blksize needs to be multiple of two. So safer to default to
		blksize and blkbits set in superblock so 2**blkbits and blksize
		will match rather than setting to:
		(pTcon->ses->server->maxBuf - MAX_CIFS_HDR_SIZE) & 0xFFFFFE00;*/

		/* This seems incredibly stupid but it turns out that i_blocks
		   is not related to (i_size / i_blksize), instead 512 byte size
		   is required for calculating num blocks */

		/* 512 bytes (2**9) is the fake blocksize that must be used */
		/* for this calculation */
			inode->i_blocks = (512 - 1 + num_of_bytes) >> 9;
		}
		spin_unlock(&inode->i_lock);

		if (num_of_bytes < end_of_file)
			cFYI(1, ("allocation size less than end of file"));
@@ -774,15 +792,10 @@ int cifs_unlink(struct inode *inode, struct dentry *direntry)
static void posix_fill_in_inode(struct inode *tmp_inode,
	FILE_UNIX_BASIC_INFO *pData, int *pobject_type, int isNewInode)
{
	struct cifsInodeInfo *cifsInfo = CIFS_I(tmp_inode);
	loff_t local_size;
	struct timespec local_mtime;

	struct cifsInodeInfo *cifsInfo = CIFS_I(tmp_inode);
	struct cifs_sb_info *cifs_sb = CIFS_SB(tmp_inode->i_sb);

	__u32 type = le32_to_cpu(pData->Type);
	__u64 num_of_bytes = le64_to_cpu(pData->NumOfBytes);
	__u64 end_of_file = le64_to_cpu(pData->EndOfFile);
	cifsInfo->time = jiffies;
	atomic_inc(&cifsInfo->inUse);

@@ -790,92 +803,19 @@ static void posix_fill_in_inode(struct inode *tmp_inode,
	local_mtime = tmp_inode->i_mtime;
	local_size  = tmp_inode->i_size;

	tmp_inode->i_atime =
	    cifs_NTtimeToUnix(le64_to_cpu(pData->LastAccessTime));
	tmp_inode->i_mtime =
	    cifs_NTtimeToUnix(le64_to_cpu(pData->LastModificationTime));
	tmp_inode->i_ctime =
	    cifs_NTtimeToUnix(le64_to_cpu(pData->LastStatusChange));

	tmp_inode->i_mode = le64_to_cpu(pData->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;
	} else if (type == UNIX_SYMLINK) {
		*pobject_type = DT_LNK;
		tmp_inode->i_mode |= S_IFLNK;
	} else if (type == UNIX_DIR) {
		*pobject_type = DT_DIR;
		tmp_inode->i_mode |= S_IFDIR;
	} else if (type == UNIX_CHARDEV) {
		*pobject_type = DT_CHR;
		tmp_inode->i_mode |= S_IFCHR;
		tmp_inode->i_rdev = MKDEV(le64_to_cpu(pData->DevMajor),
				le64_to_cpu(pData->DevMinor) & MINORMASK);
	} else if (type == UNIX_BLOCKDEV) {
		*pobject_type = DT_BLK;
		tmp_inode->i_mode |= S_IFBLK;
		tmp_inode->i_rdev = MKDEV(le64_to_cpu(pData->DevMajor),
				le64_to_cpu(pData->DevMinor) & MINORMASK);
	} else if (type == UNIX_FIFO) {
		*pobject_type = DT_FIFO;
		tmp_inode->i_mode |= S_IFIFO;
	} 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));
	}

	cFYI(DBG2, ("object type: %d", type));
	tmp_inode->i_uid = le64_to_cpu(pData->Uid);
	tmp_inode->i_gid = le64_to_cpu(pData->Gid);
	tmp_inode->i_nlink = le64_to_cpu(pData->Nlinks);

	spin_lock(&tmp_inode->i_lock);
	if (is_size_safe_to_change(cifsInfo, end_of_file)) {
		/* can not safely change the file size here if the
		client is writing to it due to potential races */
		i_size_write(tmp_inode, end_of_file);

	/* 512 bytes (2**9) is the fake blocksize that must be used */
	/* for this calculation, not the real blocksize */
		tmp_inode->i_blocks = (512 - 1 + num_of_bytes) >> 9;
	}
	spin_unlock(&tmp_inode->i_lock);

	if (S_ISREG(tmp_inode->i_mode)) {
		cFYI(1, ("File inode"));
		tmp_inode->i_op = &cifs_file_inode_ops;
	cifs_unix_info_to_inode(tmp_inode, pData, 1);
	cifs_set_ops(tmp_inode);

		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->tcon) && (cifs_sb->tcon->ses) &&
		   (cifs_sb->tcon->ses->server->maxBuf <
			PAGE_CACHE_SIZE + MAX_CIFS_HDR_SIZE))
			tmp_inode->i_data.a_ops = &cifs_addr_ops_smallbuf;
		else
			tmp_inode->i_data.a_ops = &cifs_addr_ops;
	if (!S_ISREG(tmp_inode->i_mode))
		return;

	/*
	 * No sense invalidating pages for new inode
	 * since we we have not started caching
	 * readahead file data yet.
	 */
	if (isNewInode)
			return; /* No sense invalidating pages for new inode
				   since we we have not started caching
				   readahead file data yet */
		return;

	if (timespec_equal(&tmp_inode->i_mtime, &local_mtime) &&
		(local_size == tmp_inode->i_size)) {
@@ -885,19 +825,6 @@ static void posix_fill_in_inode(struct inode *tmp_inode,
		cFYI(1, ("invalidate inode, readdir detected change"));
		invalidate_remote_inode(tmp_inode);
	}
	} else if (S_ISDIR(tmp_inode->i_mode)) {
		cFYI(1, ("Directory inode"));
		tmp_inode->i_op = &cifs_dir_inode_ops;
		tmp_inode->i_fop = &cifs_dir_ops;
	} else if (S_ISLNK(tmp_inode->i_mode)) {
		cFYI(1, ("Symbolic Link inode"));
		tmp_inode->i_op = &cifs_symlink_inode_ops;
/* tmp_inode->i_fop = *//* do not need to set to anything */
	} else {
		cFYI(1, ("Special inode"));
		init_special_inode(tmp_inode, tmp_inode->i_mode,
				   tmp_inode->i_rdev);
	}
}

int cifs_mkdir(struct inode *inode, struct dentry *direntry, int mode)