+int
+smb311_posix_get_inode_info(struct inode **inode,
+ const char *full_path,
+ struct super_block *sb, unsigned int xid)
+{
+ struct cifs_tcon *tcon;
+ struct TCP_Server_Info *server;
+ struct tcon_link *tlink;
+ struct cifs_sb_info *cifs_sb = CIFS_SB(sb);
+ bool adjust_tz = false;
+ struct cifs_fattr fattr = {0};
+ bool symlink = false;
+ struct smb311_posix_qinfo *data = NULL;
+ int rc = 0;
+ int tmprc = 0;
+
+ tlink = cifs_sb_tlink(cifs_sb);
+ if (IS_ERR(tlink))
+ return PTR_ERR(tlink);
+ tcon = tlink_tcon(tlink);
+ server = tcon->ses->server;
+
+ /*
+ * 1. Fetch file metadata
+ */
+
+ if (is_inode_cache_good(*inode)) {
+ cifs_dbg(FYI, "No need to revalidate cached inode sizes\n");
+ goto out;
+ }
+ data = kmalloc(sizeof(struct smb311_posix_qinfo), GFP_KERNEL);
+ if (!data) {
+ rc = -ENOMEM;
+ goto out;
+ }
+
+ rc = smb311_posix_query_path_info(xid, tcon, cifs_sb,
+ full_path, data,
+ &adjust_tz, &symlink);
+
+ /*
+ * 2. Convert it to internal cifs metadata (fattr)
+ */
+
+ switch (rc) {
+ case 0:
+ smb311_posix_info_to_fattr(&fattr, data, sb, adjust_tz, symlink);
+ break;
+ case -EREMOTE:
+ /* DFS link, no metadata available on this server */
+ cifs_create_dfs_fattr(&fattr, sb);
+ rc = 0;
+ break;
+ case -EACCES:
+ /*
+ * For SMB2 and later the backup intent flag
+ * is already sent if needed on open and there
+ * is no path based FindFirst operation to use
+ * to retry with so nothing we can do, bail out
+ */
+ goto out;
+ default:
+ cifs_dbg(FYI, "%s: unhandled err rc %d\n", __func__, rc);
+ goto out;
+ }
+
+
+ /*
+ * 4. Tweak fattr based on mount options
+ */
+
+ /* check for Minshall+French symlinks */
+ if (cifs_sb->mnt_cifs_flags & CIFS_MOUNT_MF_SYMLINKS) {
+ tmprc = check_mf_symlink(xid, tcon, cifs_sb, &fattr,
+ full_path);
+ if (tmprc)
+ cifs_dbg(FYI, "check_mf_symlink: %d\n", tmprc);
+ }
+
+ /*
+ * 5. Update inode with final fattr data
+ */
+
+ if (!*inode) {
+ *inode = cifs_iget(sb, &fattr);
+ if (!*inode)
+ rc = -ENOMEM;
+ } else {
+ /* we already have inode, update it */
+
+ /* if uniqueid is different, return error */
+ if (unlikely(cifs_sb->mnt_cifs_flags & CIFS_MOUNT_SERVER_INUM &&
+ CIFS_I(*inode)->uniqueid != fattr.cf_uniqueid)) {
+ CIFS_I(*inode)->time = 0; /* force reval */
+ rc = -ESTALE;
+ goto out;
+ }
+
+ /* if filetype is different, return error */
+ if (unlikely(((*inode)->i_mode & S_IFMT) !=
+ (fattr.cf_mode & S_IFMT))) {
+ CIFS_I(*inode)->time = 0; /* force reval */
+ rc = -ESTALE;
+ goto out;
+ }
+
+ cifs_fattr_to_inode(*inode, &fattr);
+ }
+out:
+ cifs_put_tlink(tlink);
+ kfree(data);
+ return rc;
+}
+
+