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

Commit cc0bad75 authored by Jeff Layton's avatar Jeff Layton Committed by Steve French
Browse files

cifs: add new cifs_iget function and convert unix codepath to use it



cifs: add new cifs_iget function and convert unix codepath to use it

In order to unify some codepaths, introduce a common cifs_fattr struct
for storing inode attributes. The different codepaths (unix, legacy,
normal, etc...) can fill out this struct with inode info. It can then be
passed as an arg to a common set of routines to get and update inodes.

Add a new cifs_iget function that uses iget5_locked to identify inodes.
This will compare inodes based on the uniqueid value in a cifs_fattr
struct.

Rather than filling out an already-created inode, have
cifs_get_inode_info_unix instead fill out cifs_fattr and hand that off
to cifs_iget. cifs_iget can then properly look for hardlinked inodes.

On the readdir side, add a new cifs_readdir_lookup function that spawns
populated dentries. Redefine FILE_UNIX_INFO so that it's basically a
FILE_UNIX_BASIC_INFO that has a few fields wrapped around it. This
allows us to more easily use the same function for filling out the fattr
as the non-readdir codepath.

With this, we should then have proper hardlink detection and can
eventually get rid of some nasty CIFS-specific hacks for handing them.

Signed-off-by: default avatarJeff Layton <jlayton@redhat.com>
Reviewed-by: default avatarChristoph Hellwig <hch@lst.de>
Signed-off-by: default avatarSteve French <sfrench@us.ibm.com>
parent d960eea9
Loading
Loading
Loading
Loading
+13 −0
Original line number Diff line number Diff line
@@ -24,6 +24,19 @@

#define ROOT_I 2

/*
 * ino_t is 32-bits on 32-bit arch. We have to squash the 64-bit value down
 * so that it will fit.
 */
static inline ino_t
cifs_uniqueid_to_ino_t(u64 fileid)
{
	ino_t ino = (ino_t) fileid;
	if (sizeof(ino_t) < sizeof(u64))
		ino ^= fileid >> (sizeof(u64)-sizeof(ino_t)) * 8;
	return ino;
}

extern struct file_system_type cifs_fs_type;
extern const struct address_space_operations cifs_addr_ops;
extern const struct address_space_operations cifs_addr_ops_smallbuf;
+25 −0
Original line number Diff line number Diff line
@@ -371,6 +371,7 @@ struct cifsInodeInfo {
	bool oplockPending:1;
	bool delete_pending:1;		/* DELETE_ON_CLOSE is set */
	u64  server_eof;		/* current file size on server */
	u64  uniqueid;			/* server inode number */
	struct inode vfs_inode;
};

@@ -472,6 +473,30 @@ struct dfs_info3_param {
	char *node_name;
};

/*
 * common struct for holding inode info when searching for or updating an
 * inode with new info
 */

#define CIFS_FATTR_DFS_REFERRAL		0x1

struct cifs_fattr {
	u32		cf_flags;
	u32		cf_cifsattrs;
	u64		cf_uniqueid;
	u64		cf_eof;
	u64		cf_bytes;
	uid_t		cf_uid;
	gid_t		cf_gid;
	umode_t		cf_mode;
	dev_t		cf_rdev;
	unsigned int	cf_nlink;
	unsigned int	cf_dtype;
	struct timespec	cf_atime;
	struct timespec	cf_mtime;
	struct timespec	cf_ctime;
};

static inline void free_dfs_info_param(struct dfs_info3_param *param)
{
	if (param) {
+1 −13
Original line number Diff line number Diff line
@@ -2328,19 +2328,7 @@ struct file_attrib_tag {
typedef struct {
	__le32 NextEntryOffset;
	__u32 ResumeKey; /* as with FileIndex - no need to convert */
	__le64 EndOfFile;
	__le64 NumOfBytes;
	__le64 LastStatusChange; /*SNIA specs DCE time for the 3 time fields */
	__le64 LastAccessTime;
	__le64 LastModificationTime;
	__le64 Uid;
	__le64 Gid;
	__le32 Type;
	__le64 DevMajor;
	__le64 DevMinor;
	__le64 UniqueId;
	__le64 Permissions;
	__le64 Nlinks;
	FILE_UNIX_BASIC_INFO basic;
	char FileName[1];
} __attribute__((packed)) FILE_UNIX_INFO; /* level 0x202 */

+7 −2
Original line number Diff line number Diff line
@@ -98,9 +98,14 @@ extern struct timespec cnvrtDosUnixTm(__le16 le_date, __le16 le_time,
extern int cifs_posix_open(char *full_path, struct inode **pinode,
			   struct super_block *sb, int mode, int oflags,
			   int *poplock, __u16 *pnetfid, int xid);
extern void posix_fill_in_inode(struct inode *tmp_inode,
				FILE_UNIX_BASIC_INFO *pData, int isNewInode);
extern void cifs_unix_basic_to_fattr(struct cifs_fattr *fattr,
				     FILE_UNIX_BASIC_INFO *info,
				     struct cifs_sb_info *cifs_sb);
extern void cifs_fattr_to_inode(struct inode *inode, struct cifs_fattr *fattr);
extern struct inode *cifs_new_inode(struct super_block *sb, __u64 *inum);
extern struct inode *cifs_iget(struct super_block *sb,
			       struct cifs_fattr *fattr);

extern int cifs_get_inode_info(struct inode **pinode,
			const unsigned char *search_path,
			FILE_ALL_INFO *pfile_info,
+11 −11
Original line number Diff line number Diff line
@@ -188,6 +188,7 @@ int cifs_posix_open(char *full_path, struct inode **pinode,
	FILE_UNIX_BASIC_INFO *presp_data;
	__u32 posix_flags = 0;
	struct cifs_sb_info *cifs_sb = CIFS_SB(sb);
	struct cifs_fattr fattr;

	cFYI(1, ("posix open %s", full_path));

@@ -236,22 +237,21 @@ int cifs_posix_open(char *full_path, struct inode **pinode,
	if (presp_data->Type == cpu_to_le32(-1))
		goto posix_open_ret; /* open ok, caller does qpathinfo */

	/* get new inode and set it up */
	if (!pinode)
		goto posix_open_ret; /* caller does not need info */

	if (*pinode == NULL) {
		__u64 unique_id = le64_to_cpu(presp_data->UniqueId);
		*pinode = cifs_new_inode(sb, &unique_id);
	}
	/* else an inode was passed in. Update its info, don't create one */
	cifs_unix_basic_to_fattr(&fattr, presp_data, cifs_sb);

	/* We do not need to close the file if new_inode fails since
	   the caller will retry qpathinfo as long as inode is null */
	if (*pinode == NULL)
	/* get new inode and set it up */
	if (*pinode == NULL) {
		*pinode = cifs_iget(sb, &fattr);
		if (!*pinode) {
			rc = -ENOMEM;
			goto posix_open_ret;

	posix_fill_in_inode(*pinode, presp_data, 1);
		}
	} else {
		cifs_fattr_to_inode(*pinode, &fattr);
	}

	cifs_fill_fileinfo(*pinode, *pnetfid, cifs_sb->tcon, write_only);

Loading