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: Jeff Layton <jlayton@redhat.com> Reviewed-by: Christoph Hellwig <hch@lst.de> Signed-off-by: Steve French <sfrench@us.ibm.com>
This commit is contained in:
Родитель
d960eea974
Коммит
cc0bad7552
|
@ -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;
|
||||
|
|
|
@ -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) {
|
||||
|
|
|
@ -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 */
|
||||
|
||||
|
|
|
@ -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,
|
||||
|
|
|
@ -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 */
|
||||
|
||||
cifs_unix_basic_to_fattr(&fattr, presp_data, cifs_sb);
|
||||
|
||||
/* get new inode and set it up */
|
||||
if (*pinode == NULL) {
|
||||
__u64 unique_id = le64_to_cpu(presp_data->UniqueId);
|
||||
*pinode = cifs_new_inode(sb, &unique_id);
|
||||
*pinode = cifs_iget(sb, &fattr);
|
||||
if (!*pinode) {
|
||||
rc = -ENOMEM;
|
||||
goto posix_open_ret;
|
||||
}
|
||||
} else {
|
||||
cifs_fattr_to_inode(*pinode, &fattr);
|
||||
}
|
||||
/* else an inode was passed in. Update its info, don't create one */
|
||||
|
||||
/* 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)
|
||||
goto posix_open_ret;
|
||||
|
||||
posix_fill_in_inode(*pinode, presp_data, 1);
|
||||
|
||||
cifs_fill_fileinfo(*pinode, *pnetfid, cifs_sb->tcon, write_only);
|
||||
|
||||
|
|
416
fs/cifs/inode.c
416
fs/cifs/inode.c
|
@ -77,127 +77,146 @@ static void cifs_set_ops(struct inode *inode, const bool is_dfs_referral)
|
|||
}
|
||||
}
|
||||
|
||||
static void cifs_unix_info_to_inode(struct inode *inode,
|
||||
FILE_UNIX_BASIC_INFO *info, int force_uid_gid)
|
||||
/* populate an inode with info from a cifs_fattr struct */
|
||||
void
|
||||
cifs_fattr_to_inode(struct inode *inode, struct cifs_fattr *fattr)
|
||||
{
|
||||
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);
|
||||
struct cifsInodeInfo *cifs_i = CIFS_I(inode);
|
||||
unsigned long now = jiffies;
|
||||
|
||||
inode->i_atime = cifs_NTtimeToUnix(info->LastAccessTime);
|
||||
inode->i_mtime =
|
||||
cifs_NTtimeToUnix(info->LastModificationTime);
|
||||
inode->i_ctime = cifs_NTtimeToUnix(info->LastStatusChange);
|
||||
inode->i_mode = le64_to_cpu(info->Permissions);
|
||||
inode->i_atime = fattr->cf_atime;
|
||||
inode->i_mtime = fattr->cf_mtime;
|
||||
inode->i_ctime = fattr->cf_ctime;
|
||||
inode->i_mode = fattr->cf_mode;
|
||||
inode->i_rdev = fattr->cf_rdev;
|
||||
inode->i_nlink = fattr->cf_nlink;
|
||||
inode->i_uid = fattr->cf_uid;
|
||||
inode->i_gid = fattr->cf_gid;
|
||||
|
||||
cifs_i->cifsAttrs = fattr->cf_cifsattrs;
|
||||
cifs_i->uniqueid = fattr->cf_uniqueid;
|
||||
|
||||
cFYI(1, ("inode 0x%p old_time=%ld new_time=%ld", inode,
|
||||
cifs_i->time, now));
|
||||
cifs_i->time = now;
|
||||
|
||||
/*
|
||||
* Since we set the inode type below we need to mask off
|
||||
* to avoid strange results if bits set above.
|
||||
* Can't safely change the file size here if the client is writing to
|
||||
* it due to potential races.
|
||||
*/
|
||||
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);
|
||||
|
||||
cifsInfo->server_eof = end_of_file;
|
||||
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);
|
||||
if (is_size_safe_to_change(cifs_i, fattr->cf_eof)) {
|
||||
i_size_write(inode, fattr->cf_eof);
|
||||
|
||||
/*
|
||||
* 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;
|
||||
inode->i_blocks = (512 - 1 + fattr->cf_bytes) >> 9;
|
||||
}
|
||||
spin_unlock(&inode->i_lock);
|
||||
|
||||
cifs_set_ops(inode, fattr->cf_flags & CIFS_FATTR_DFS_REFERRAL);
|
||||
}
|
||||
|
||||
/* Fill a cifs_fattr struct with info from FILE_UNIX_BASIC_INFO. */
|
||||
void
|
||||
cifs_unix_basic_to_fattr(struct cifs_fattr *fattr, FILE_UNIX_BASIC_INFO *info,
|
||||
struct cifs_sb_info *cifs_sb)
|
||||
{
|
||||
memset(fattr, 0, sizeof(*fattr));
|
||||
fattr->cf_uniqueid = le64_to_cpu(info->UniqueId);
|
||||
fattr->cf_bytes = le64_to_cpu(info->NumOfBytes);
|
||||
fattr->cf_eof = le64_to_cpu(info->EndOfFile);
|
||||
|
||||
fattr->cf_atime = cifs_NTtimeToUnix(info->LastAccessTime);
|
||||
fattr->cf_mtime = cifs_NTtimeToUnix(info->LastModificationTime);
|
||||
fattr->cf_ctime = cifs_NTtimeToUnix(info->LastStatusChange);
|
||||
fattr->cf_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.
|
||||
*/
|
||||
fattr->cf_mode &= ~S_IFMT;
|
||||
switch (le32_to_cpu(info->Type)) {
|
||||
case UNIX_FILE:
|
||||
fattr->cf_mode |= S_IFREG;
|
||||
fattr->cf_dtype = DT_REG;
|
||||
break;
|
||||
case UNIX_SYMLINK:
|
||||
fattr->cf_mode |= S_IFLNK;
|
||||
fattr->cf_dtype = DT_LNK;
|
||||
break;
|
||||
case UNIX_DIR:
|
||||
fattr->cf_mode |= S_IFDIR;
|
||||
fattr->cf_dtype = DT_DIR;
|
||||
break;
|
||||
case UNIX_CHARDEV:
|
||||
fattr->cf_mode |= S_IFCHR;
|
||||
fattr->cf_dtype = DT_CHR;
|
||||
fattr->cf_rdev = MKDEV(le64_to_cpu(info->DevMajor),
|
||||
le64_to_cpu(info->DevMinor) & MINORMASK);
|
||||
break;
|
||||
case UNIX_BLOCKDEV:
|
||||
fattr->cf_mode |= S_IFBLK;
|
||||
fattr->cf_dtype = DT_BLK;
|
||||
fattr->cf_rdev = MKDEV(le64_to_cpu(info->DevMajor),
|
||||
le64_to_cpu(info->DevMinor) & MINORMASK);
|
||||
break;
|
||||
case UNIX_FIFO:
|
||||
fattr->cf_mode |= S_IFIFO;
|
||||
fattr->cf_dtype = DT_FIFO;
|
||||
break;
|
||||
case UNIX_SOCKET:
|
||||
fattr->cf_mode |= S_IFSOCK;
|
||||
fattr->cf_dtype = DT_SOCK;
|
||||
break;
|
||||
default:
|
||||
/* safest to call it a file if we do not know */
|
||||
fattr->cf_mode |= S_IFREG;
|
||||
fattr->cf_dtype = DT_REG;
|
||||
cFYI(1, ("unknown type %d", le32_to_cpu(info->Type)));
|
||||
break;
|
||||
}
|
||||
|
||||
if (cifs_sb->mnt_cifs_flags & CIFS_MOUNT_OVERR_UID)
|
||||
fattr->cf_uid = cifs_sb->mnt_uid;
|
||||
else
|
||||
fattr->cf_uid = le64_to_cpu(info->Uid);
|
||||
|
||||
if (cifs_sb->mnt_cifs_flags & CIFS_MOUNT_OVERR_GID)
|
||||
fattr->cf_gid = cifs_sb->mnt_gid;
|
||||
else
|
||||
fattr->cf_gid = le64_to_cpu(info->Gid);
|
||||
|
||||
fattr->cf_nlink = le64_to_cpu(info->Nlinks);
|
||||
}
|
||||
|
||||
/*
|
||||
* Needed to setup inode data for the directory which is the
|
||||
* junction to the new submount (ie to setup the fake directory
|
||||
* which represents a DFS referral)
|
||||
* Fill a cifs_fattr struct with fake inode info.
|
||||
*
|
||||
* Needed to setup cifs_fattr data for the directory which is the
|
||||
* junction to the new submount (ie to setup the fake directory
|
||||
* which represents a DFS referral).
|
||||
*/
|
||||
static void fill_fake_finddataunix(FILE_UNIX_BASIC_INFO *pfnd_dat,
|
||||
struct super_block *sb)
|
||||
void
|
||||
cifs_create_dfs_fattr(struct cifs_fattr *fattr, struct super_block *sb)
|
||||
{
|
||||
struct inode *pinode = NULL;
|
||||
struct cifs_sb_info *cifs_sb = CIFS_SB(sb);
|
||||
|
||||
memset(pfnd_dat, 0, sizeof(FILE_UNIX_BASIC_INFO));
|
||||
cFYI(1, ("creating fake fattr for DFS referral"));
|
||||
|
||||
/* __le64 pfnd_dat->EndOfFile = cpu_to_le64(0);
|
||||
__le64 pfnd_dat->NumOfBytes = cpu_to_le64(0);
|
||||
__u64 UniqueId = 0; */
|
||||
pfnd_dat->LastStatusChange =
|
||||
cpu_to_le64(cifs_UnixTimeToNT(CURRENT_TIME));
|
||||
pfnd_dat->LastAccessTime =
|
||||
cpu_to_le64(cifs_UnixTimeToNT(CURRENT_TIME));
|
||||
pfnd_dat->LastModificationTime =
|
||||
cpu_to_le64(cifs_UnixTimeToNT(CURRENT_TIME));
|
||||
pfnd_dat->Type = cpu_to_le32(UNIX_DIR);
|
||||
pfnd_dat->Permissions = cpu_to_le64(S_IXUGO | S_IRWXU);
|
||||
pfnd_dat->Nlinks = cpu_to_le64(2);
|
||||
if (sb->s_root)
|
||||
pinode = sb->s_root->d_inode;
|
||||
if (pinode == NULL)
|
||||
return;
|
||||
|
||||
/* fill in default values for the remaining based on root
|
||||
inode since we can not query the server for this inode info */
|
||||
pfnd_dat->DevMajor = cpu_to_le64(MAJOR(pinode->i_rdev));
|
||||
pfnd_dat->DevMinor = cpu_to_le64(MINOR(pinode->i_rdev));
|
||||
pfnd_dat->Uid = cpu_to_le64(pinode->i_uid);
|
||||
pfnd_dat->Gid = cpu_to_le64(pinode->i_gid);
|
||||
memset(fattr, 0, sizeof(*fattr));
|
||||
fattr->cf_mode = S_IFDIR | S_IXUGO | S_IRWXU;
|
||||
fattr->cf_uid = cifs_sb->mnt_uid;
|
||||
fattr->cf_gid = cifs_sb->mnt_gid;
|
||||
fattr->cf_atime = CURRENT_TIME;
|
||||
fattr->cf_ctime = CURRENT_TIME;
|
||||
fattr->cf_mtime = CURRENT_TIME;
|
||||
fattr->cf_nlink = 2;
|
||||
fattr->cf_flags |= CIFS_FATTR_DFS_REFERRAL;
|
||||
}
|
||||
|
||||
/**
|
||||
|
@ -244,66 +263,42 @@ cifs_new_inode(struct super_block *sb, __u64 *inum)
|
|||
}
|
||||
|
||||
int cifs_get_inode_info_unix(struct inode **pinode,
|
||||
const unsigned char *full_path, struct super_block *sb, int xid)
|
||||
const unsigned char *full_path,
|
||||
struct super_block *sb, int xid)
|
||||
{
|
||||
int rc = 0;
|
||||
int rc;
|
||||
FILE_UNIX_BASIC_INFO find_data;
|
||||
struct cifsTconInfo *pTcon;
|
||||
struct inode *inode;
|
||||
struct cifs_fattr fattr;
|
||||
struct cifsTconInfo *tcon;
|
||||
struct cifs_sb_info *cifs_sb = CIFS_SB(sb);
|
||||
bool is_dfs_referral = false;
|
||||
struct cifsInodeInfo *cifsInfo;
|
||||
__u64 num_of_bytes;
|
||||
__u64 end_of_file;
|
||||
|
||||
pTcon = cifs_sb->tcon;
|
||||
tcon = cifs_sb->tcon;
|
||||
cFYI(1, ("Getting info on %s", full_path));
|
||||
|
||||
/* could have done a find first instead but this returns more info */
|
||||
rc = CIFSSMBUnixQPathInfo(xid, pTcon, full_path, &find_data,
|
||||
rc = CIFSSMBUnixQPathInfo(xid, tcon, full_path, &find_data,
|
||||
cifs_sb->local_nls, cifs_sb->mnt_cifs_flags &
|
||||
CIFS_MOUNT_MAP_SPECIAL_CHR);
|
||||
if (rc == -EREMOTE && !is_dfs_referral) {
|
||||
is_dfs_referral = true;
|
||||
cFYI(DBG2, ("DFS ref"));
|
||||
/* for DFS, server does not give us real inode data */
|
||||
fill_fake_finddataunix(&find_data, sb);
|
||||
|
||||
if (!rc) {
|
||||
cifs_unix_basic_to_fattr(&fattr, &find_data, cifs_sb);
|
||||
} else if (rc == -EREMOTE) {
|
||||
cifs_create_dfs_fattr(&fattr, sb);
|
||||
rc = 0;
|
||||
} else if (rc)
|
||||
goto cgiiu_exit;
|
||||
|
||||
num_of_bytes = le64_to_cpu(find_data.NumOfBytes);
|
||||
end_of_file = le64_to_cpu(find_data.EndOfFile);
|
||||
|
||||
/* get new inode */
|
||||
if (*pinode == NULL) {
|
||||
__u64 unique_id = le64_to_cpu(find_data.UniqueId);
|
||||
*pinode = cifs_new_inode(sb, &unique_id);
|
||||
if (*pinode == NULL) {
|
||||
rc = -ENOMEM;
|
||||
goto cgiiu_exit;
|
||||
}
|
||||
} else {
|
||||
return rc;
|
||||
}
|
||||
|
||||
inode = *pinode;
|
||||
cifsInfo = CIFS_I(inode);
|
||||
if (*pinode == NULL) {
|
||||
/* get new inode */
|
||||
*pinode = cifs_iget(sb, &fattr);
|
||||
if (!*pinode)
|
||||
rc = -ENOMEM;
|
||||
} else {
|
||||
/* we already have inode, update it */
|
||||
cifs_fattr_to_inode(*pinode, &fattr);
|
||||
}
|
||||
|
||||
cFYI(1, ("Old time %ld", cifsInfo->time));
|
||||
cifsInfo->time = jiffies;
|
||||
cFYI(1, ("New time %ld", cifsInfo->time));
|
||||
/* this is ok to set on every inode revalidate */
|
||||
atomic_set(&cifsInfo->inUse, 1);
|
||||
|
||||
cifs_unix_info_to_inode(inode, &find_data, 0);
|
||||
|
||||
if (num_of_bytes < end_of_file)
|
||||
cFYI(1, ("allocation size less than end of file"));
|
||||
cFYI(1, ("Size %ld and blocks %llu",
|
||||
(unsigned long) inode->i_size,
|
||||
(unsigned long long)inode->i_blocks));
|
||||
|
||||
cifs_set_ops(inode, is_dfs_referral);
|
||||
cgiiu_exit:
|
||||
return rc;
|
||||
}
|
||||
|
||||
|
@ -695,33 +690,85 @@ char *cifs_build_path_to_root(struct cifs_sb_info *cifs_sb)
|
|||
return full_path;
|
||||
}
|
||||
|
||||
static int
|
||||
cifs_find_inode(struct inode *inode, void *opaque)
|
||||
{
|
||||
struct cifs_fattr *fattr = (struct cifs_fattr *) opaque;
|
||||
|
||||
if (CIFS_I(inode)->uniqueid != fattr->cf_uniqueid)
|
||||
return 0;
|
||||
|
||||
return 1;
|
||||
}
|
||||
|
||||
static int
|
||||
cifs_init_inode(struct inode *inode, void *opaque)
|
||||
{
|
||||
struct cifs_fattr *fattr = (struct cifs_fattr *) opaque;
|
||||
|
||||
CIFS_I(inode)->uniqueid = fattr->cf_uniqueid;
|
||||
return 0;
|
||||
}
|
||||
|
||||
/* Given fattrs, get a corresponding inode */
|
||||
struct inode *
|
||||
cifs_iget(struct super_block *sb, struct cifs_fattr *fattr)
|
||||
{
|
||||
unsigned long hash;
|
||||
struct inode *inode;
|
||||
|
||||
cFYI(1, ("looking for uniqueid=%llu", fattr->cf_uniqueid));
|
||||
|
||||
/* hash down to 32-bits on 32-bit arch */
|
||||
hash = cifs_uniqueid_to_ino_t(fattr->cf_uniqueid);
|
||||
|
||||
inode = iget5_locked(sb, hash, cifs_find_inode, cifs_init_inode, fattr);
|
||||
|
||||
/* we have fattrs in hand, update the inode */
|
||||
if (inode) {
|
||||
cifs_fattr_to_inode(inode, fattr);
|
||||
if (sb->s_flags & MS_NOATIME)
|
||||
inode->i_flags |= S_NOATIME | S_NOCMTIME;
|
||||
if (inode->i_state & I_NEW) {
|
||||
inode->i_ino = hash;
|
||||
unlock_new_inode(inode);
|
||||
}
|
||||
}
|
||||
|
||||
return inode;
|
||||
}
|
||||
|
||||
/* gets root inode */
|
||||
struct inode *cifs_root_iget(struct super_block *sb, unsigned long ino)
|
||||
{
|
||||
int xid;
|
||||
struct cifs_sb_info *cifs_sb;
|
||||
struct inode *inode;
|
||||
struct inode *inode = NULL;
|
||||
long rc;
|
||||
char *full_path;
|
||||
|
||||
inode = iget_locked(sb, ino);
|
||||
if (!inode)
|
||||
return ERR_PTR(-ENOMEM);
|
||||
if (!(inode->i_state & I_NEW))
|
||||
return inode;
|
||||
|
||||
cifs_sb = CIFS_SB(inode->i_sb);
|
||||
cifs_sb = CIFS_SB(sb);
|
||||
full_path = cifs_build_path_to_root(cifs_sb);
|
||||
if (full_path == NULL)
|
||||
return ERR_PTR(-ENOMEM);
|
||||
|
||||
xid = GetXid();
|
||||
if (cifs_sb->tcon->unix_ext)
|
||||
rc = cifs_get_inode_info_unix(&inode, full_path, inode->i_sb,
|
||||
xid);
|
||||
else
|
||||
if (cifs_sb->tcon->unix_ext) {
|
||||
rc = cifs_get_inode_info_unix(&inode, full_path, sb, xid);
|
||||
if (!inode)
|
||||
return ERR_PTR(-ENOMEM);
|
||||
} else {
|
||||
inode = iget_locked(sb, ino);
|
||||
if (!inode)
|
||||
return ERR_PTR(-ENOMEM);
|
||||
if (!(inode->i_state & I_NEW))
|
||||
return inode;
|
||||
|
||||
rc = cifs_get_inode_info(&inode, full_path, NULL, inode->i_sb,
|
||||
xid, NULL);
|
||||
unlock_new_inode(inode);
|
||||
}
|
||||
|
||||
if (rc && cifs_sb->tcon->ipc) {
|
||||
cFYI(1, ("ipc connection - fake read inode"));
|
||||
inode->i_mode |= S_IFDIR;
|
||||
|
@ -737,7 +784,6 @@ struct inode *cifs_root_iget(struct super_block *sb, unsigned long ino)
|
|||
return ERR_PTR(rc);
|
||||
}
|
||||
|
||||
unlock_new_inode(inode);
|
||||
|
||||
kfree(full_path);
|
||||
/* can not call macro FreeXid here since in a void func
|
||||
|
@ -1063,44 +1109,6 @@ out_reval:
|
|||
return rc;
|
||||
}
|
||||
|
||||
void posix_fill_in_inode(struct inode *tmp_inode,
|
||||
FILE_UNIX_BASIC_INFO *pData, int isNewInode)
|
||||
{
|
||||
struct cifsInodeInfo *cifsInfo = CIFS_I(tmp_inode);
|
||||
loff_t local_size;
|
||||
struct timespec local_mtime;
|
||||
|
||||
cifsInfo->time = jiffies;
|
||||
atomic_inc(&cifsInfo->inUse);
|
||||
|
||||
/* save mtime and size */
|
||||
local_mtime = tmp_inode->i_mtime;
|
||||
local_size = tmp_inode->i_size;
|
||||
|
||||
cifs_unix_info_to_inode(tmp_inode, pData, 1);
|
||||
cifs_set_ops(tmp_inode, false);
|
||||
|
||||
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;
|
||||
|
||||
if (timespec_equal(&tmp_inode->i_mtime, &local_mtime) &&
|
||||
(local_size == tmp_inode->i_size)) {
|
||||
cFYI(1, ("inode exists but unchanged"));
|
||||
} else {
|
||||
/* file may have changed on server */
|
||||
cFYI(1, ("invalidate inode, readdir detected change"));
|
||||
invalidate_remote_inode(tmp_inode);
|
||||
}
|
||||
}
|
||||
|
||||
int cifs_mkdir(struct inode *inode, struct dentry *direntry, int mode)
|
||||
{
|
||||
int rc = 0, tmprc;
|
||||
|
@ -1109,6 +1117,7 @@ int cifs_mkdir(struct inode *inode, struct dentry *direntry, int mode)
|
|||
struct cifsTconInfo *pTcon;
|
||||
char *full_path = NULL;
|
||||
struct inode *newinode = NULL;
|
||||
struct cifs_fattr fattr;
|
||||
|
||||
cFYI(1, ("In cifs_mkdir, mode = 0x%x inode = 0x%p", mode, inode));
|
||||
|
||||
|
@ -1148,7 +1157,6 @@ int cifs_mkdir(struct inode *inode, struct dentry *direntry, int mode)
|
|||
cFYI(1, ("posix mkdir returned 0x%x", rc));
|
||||
d_drop(direntry);
|
||||
} else {
|
||||
__u64 unique_id;
|
||||
if (pInfo->Type == cpu_to_le32(-1)) {
|
||||
/* no return info, go query for it */
|
||||
kfree(pInfo);
|
||||
|
@ -1162,20 +1170,15 @@ int cifs_mkdir(struct inode *inode, struct dentry *direntry, int mode)
|
|||
else
|
||||
direntry->d_op = &cifs_dentry_ops;
|
||||
|
||||
unique_id = le64_to_cpu(pInfo->UniqueId);
|
||||
newinode = cifs_new_inode(inode->i_sb, &unique_id);
|
||||
if (newinode == NULL) {
|
||||
cifs_unix_basic_to_fattr(&fattr, pInfo, cifs_sb);
|
||||
newinode = cifs_iget(inode->i_sb, &fattr);
|
||||
if (!newinode) {
|
||||
kfree(pInfo);
|
||||
goto mkdir_get_info;
|
||||
}
|
||||
|
||||
newinode->i_nlink = 2;
|
||||
d_instantiate(direntry, newinode);
|
||||
|
||||
/* we already checked in POSIXCreate whether
|
||||
frame was long enough */
|
||||
posix_fill_in_inode(direntry->d_inode,
|
||||
pInfo, 1 /* NewInode */);
|
||||
#ifdef CONFIG_CIFS_DEBUG2
|
||||
cFYI(1, ("instantiated dentry %p %s to inode %p",
|
||||
direntry, direntry->d_name.name, newinode));
|
||||
|
@ -1622,6 +1625,7 @@ int cifs_getattr(struct vfsmount *mnt, struct dentry *dentry,
|
|||
if (!err) {
|
||||
generic_fillattr(dentry->d_inode, stat);
|
||||
stat->blksize = CIFS_MAX_MSGSIZE;
|
||||
stat->ino = CIFS_I(dentry->d_inode)->uniqueid;
|
||||
}
|
||||
return err;
|
||||
}
|
||||
|
|
|
@ -63,6 +63,55 @@ static inline void dump_cifs_file_struct(struct file *file, char *label)
|
|||
}
|
||||
#endif /* DEBUG2 */
|
||||
|
||||
/*
|
||||
* Find the dentry that matches "name". If there isn't one, create one. If it's
|
||||
* a negative dentry or the uniqueid changed, then drop it and recreate it.
|
||||
*/
|
||||
static struct dentry *
|
||||
cifs_readdir_lookup(struct dentry *parent, struct qstr *name,
|
||||
struct cifs_fattr *fattr)
|
||||
{
|
||||
struct dentry *dentry, *alias;
|
||||
struct inode *inode;
|
||||
struct super_block *sb = parent->d_inode->i_sb;
|
||||
|
||||
cFYI(1, ("For %s", name->name));
|
||||
|
||||
dentry = d_lookup(parent, name);
|
||||
if (dentry) {
|
||||
/* FIXME: check for inode number changes? */
|
||||
if (dentry->d_inode != NULL)
|
||||
return dentry;
|
||||
d_drop(dentry);
|
||||
dput(dentry);
|
||||
}
|
||||
|
||||
dentry = d_alloc(parent, name);
|
||||
if (dentry == NULL)
|
||||
return NULL;
|
||||
|
||||
inode = cifs_iget(sb, fattr);
|
||||
if (!inode) {
|
||||
dput(dentry);
|
||||
return NULL;
|
||||
}
|
||||
|
||||
if (CIFS_SB(sb)->tcon->nocase)
|
||||
dentry->d_op = &cifs_ci_dentry_ops;
|
||||
else
|
||||
dentry->d_op = &cifs_dentry_ops;
|
||||
|
||||
alias = d_materialise_unique(dentry, inode);
|
||||
if (alias != NULL) {
|
||||
dput(dentry);
|
||||
if (IS_ERR(alias))
|
||||
return NULL;
|
||||
dentry = alias;
|
||||
}
|
||||
|
||||
return dentry;
|
||||
}
|
||||
|
||||
/* Returns 1 if new inode created, 2 if both dentry and inode were */
|
||||
/* Might check in the future if inode number changed so we can rehash inode */
|
||||
static int
|
||||
|
@ -76,7 +125,6 @@ construct_dentry(struct qstr *qstring, struct file *file,
|
|||
|
||||
cFYI(1, ("For %s", qstring->name));
|
||||
|
||||
qstring->hash = full_name_hash(qstring->name, qstring->len);
|
||||
tmp_dentry = d_lookup(file->f_path.dentry, qstring);
|
||||
if (tmp_dentry) {
|
||||
/* BB: overwrite old name? i.e. tmp_dentry->d_name and
|
||||
|
@ -299,140 +347,6 @@ static void fill_in_inode(struct inode *tmp_inode, int new_buf_type,
|
|||
}
|
||||
}
|
||||
|
||||
static void unix_fill_in_inode(struct inode *tmp_inode,
|
||||
FILE_UNIX_INFO *pfindData, unsigned int *pobject_type, int isNewInode)
|
||||
{
|
||||
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(pfindData->Type);
|
||||
__u64 num_of_bytes = le64_to_cpu(pfindData->NumOfBytes);
|
||||
__u64 end_of_file = le64_to_cpu(pfindData->EndOfFile);
|
||||
cifsInfo->time = jiffies;
|
||||
atomic_inc(&cifsInfo->inUse);
|
||||
|
||||
/* save mtime and size */
|
||||
local_mtime = tmp_inode->i_mtime;
|
||||
local_size = tmp_inode->i_size;
|
||||
|
||||
tmp_inode->i_atime =
|
||||
cifs_NTtimeToUnix(pfindData->LastAccessTime);
|
||||
tmp_inode->i_mtime =
|
||||
cifs_NTtimeToUnix(pfindData->LastModificationTime);
|
||||
tmp_inode->i_ctime =
|
||||
cifs_NTtimeToUnix(pfindData->LastStatusChange);
|
||||
|
||||
tmp_inode->i_mode = le64_to_cpu(pfindData->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(pfindData->DevMajor),
|
||||
le64_to_cpu(pfindData->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(pfindData->DevMajor),
|
||||
le64_to_cpu(pfindData->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));
|
||||
}
|
||||
|
||||
if (cifs_sb->mnt_cifs_flags & CIFS_MOUNT_OVERR_UID)
|
||||
tmp_inode->i_uid = cifs_sb->mnt_uid;
|
||||
else
|
||||
tmp_inode->i_uid = le64_to_cpu(pfindData->Uid);
|
||||
if (cifs_sb->mnt_cifs_flags & CIFS_MOUNT_OVERR_GID)
|
||||
tmp_inode->i_gid = cifs_sb->mnt_gid;
|
||||
else
|
||||
tmp_inode->i_gid = le64_to_cpu(pfindData->Gid);
|
||||
tmp_inode->i_nlink = le64_to_cpu(pfindData->Nlinks);
|
||||
|
||||
cifsInfo->server_eof = end_of_file;
|
||||
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;
|
||||
|
||||
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 (isNewInode)
|
||||
return; /* No sense invalidating pages for new inode
|
||||
since we have not started caching readahead
|
||||
file data for it yet */
|
||||
|
||||
if (timespec_equal(&tmp_inode->i_mtime, &local_mtime) &&
|
||||
(local_size == tmp_inode->i_size)) {
|
||||
cFYI(1, ("inode exists but unchanged"));
|
||||
} else {
|
||||
/* file may have changed on server */
|
||||
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);
|
||||
}
|
||||
}
|
||||
|
||||
/* BB eventually need to add the following helper function to
|
||||
resolve NT_STATUS_STOPPED_ON_SYMLINK return code when
|
||||
we try to do FindFirst on (NTFS) directory symlinks */
|
||||
|
@ -872,7 +786,7 @@ static int cifs_get_name_from_search_buf(struct qstr *pqst,
|
|||
len = strnlen(filename, PATH_MAX);
|
||||
}
|
||||
|
||||
*pinum = le64_to_cpu(pFindData->UniqueId);
|
||||
*pinum = le64_to_cpu(pFindData->basic.UniqueId);
|
||||
} else if (level == SMB_FIND_FILE_DIRECTORY_INFO) {
|
||||
FILE_DIRECTORY_INFO *pFindData =
|
||||
(FILE_DIRECTORY_INFO *)current_entry;
|
||||
|
@ -934,9 +848,11 @@ static int cifs_filldir(char *pfindEntry, struct file *file, filldir_t filldir,
|
|||
struct cifsFileInfo *pCifsF;
|
||||
unsigned int obj_type;
|
||||
__u64 inum;
|
||||
ino_t ino;
|
||||
struct cifs_sb_info *cifs_sb;
|
||||
struct inode *tmp_inode;
|
||||
struct dentry *tmp_dentry;
|
||||
struct cifs_fattr fattr;
|
||||
|
||||
/* get filename and len into qstring */
|
||||
/* get dentry */
|
||||
|
@ -967,39 +883,49 @@ static int cifs_filldir(char *pfindEntry, struct file *file, filldir_t filldir,
|
|||
return rc;
|
||||
|
||||
/* only these two infolevels return valid inode numbers */
|
||||
if (pCifsF->srch_inf.info_level == SMB_FIND_FILE_UNIX ||
|
||||
pCifsF->srch_inf.info_level == SMB_FIND_FILE_ID_FULL_DIR_INFO)
|
||||
rc = construct_dentry(&qstring, file, &tmp_inode, &tmp_dentry,
|
||||
&inum);
|
||||
else
|
||||
rc = construct_dentry(&qstring, file, &tmp_inode, &tmp_dentry,
|
||||
NULL);
|
||||
if (pCifsF->srch_inf.info_level == SMB_FIND_FILE_UNIX) {
|
||||
cifs_unix_basic_to_fattr(&fattr,
|
||||
&((FILE_UNIX_INFO *) pfindEntry)->basic,
|
||||
cifs_sb);
|
||||
tmp_dentry = cifs_readdir_lookup(file->f_dentry, &qstring,
|
||||
&fattr);
|
||||
obj_type = fattr.cf_dtype;
|
||||
ino = cifs_uniqueid_to_ino_t(fattr.cf_uniqueid);
|
||||
} else {
|
||||
if (pCifsF->srch_inf.info_level ==
|
||||
SMB_FIND_FILE_ID_FULL_DIR_INFO)
|
||||
rc = construct_dentry(&qstring, file, &tmp_inode,
|
||||
&tmp_dentry, &inum);
|
||||
else
|
||||
rc = construct_dentry(&qstring, file, &tmp_inode,
|
||||
&tmp_dentry, NULL);
|
||||
|
||||
if ((tmp_inode == NULL) || (tmp_dentry == NULL))
|
||||
return -ENOMEM;
|
||||
if ((tmp_inode == NULL) || (tmp_dentry == NULL)) {
|
||||
rc = -ENOMEM;
|
||||
goto out;
|
||||
}
|
||||
|
||||
/* we pass in rc below, indicating whether it is a new inode,
|
||||
so we can figure out whether to invalidate the inode cached
|
||||
data if the file has changed */
|
||||
if (pCifsF->srch_inf.info_level == SMB_FIND_FILE_UNIX)
|
||||
unix_fill_in_inode(tmp_inode,
|
||||
(FILE_UNIX_INFO *)pfindEntry,
|
||||
&obj_type, rc);
|
||||
else if (pCifsF->srch_inf.info_level == SMB_FIND_FILE_INFO_STANDARD)
|
||||
fill_in_inode(tmp_inode, 0 /* old level 1 buffer type */,
|
||||
pfindEntry, &obj_type, rc);
|
||||
else
|
||||
fill_in_inode(tmp_inode, 1 /* NT */, pfindEntry, &obj_type, rc);
|
||||
/* we pass in rc below, indicating whether it is a new inode,
|
||||
* so we can figure out whether to invalidate the inode cached
|
||||
* data if the file has changed
|
||||
*/
|
||||
if (pCifsF->srch_inf.info_level == SMB_FIND_FILE_INFO_STANDARD)
|
||||
fill_in_inode(tmp_inode, 0, pfindEntry, &obj_type, rc);
|
||||
else
|
||||
fill_in_inode(tmp_inode, 1, pfindEntry, &obj_type, rc);
|
||||
|
||||
if (rc) /* new inode - needs to be tied to dentry */ {
|
||||
d_instantiate(tmp_dentry, tmp_inode);
|
||||
if (rc == 2)
|
||||
d_rehash(tmp_dentry);
|
||||
/* new inode - needs to be tied to dentry */
|
||||
if (rc) {
|
||||
d_instantiate(tmp_dentry, tmp_inode);
|
||||
if (rc == 2)
|
||||
d_rehash(tmp_dentry);
|
||||
}
|
||||
|
||||
ino = cifs_uniqueid_to_ino_t(tmp_inode->i_ino);
|
||||
}
|
||||
|
||||
|
||||
rc = filldir(direntry, qstring.name, qstring.len, file->f_pos,
|
||||
tmp_inode->i_ino, obj_type);
|
||||
ino, obj_type);
|
||||
if (rc) {
|
||||
cFYI(1, ("filldir rc = %d", rc));
|
||||
/* we can not return filldir errors to the caller
|
||||
|
@ -1008,6 +934,7 @@ static int cifs_filldir(char *pfindEntry, struct file *file, filldir_t filldir,
|
|||
rc = -EOVERFLOW;
|
||||
}
|
||||
|
||||
out:
|
||||
dput(tmp_dentry);
|
||||
return rc;
|
||||
}
|
||||
|
|
Загрузка…
Ссылка в новой задаче