X-Git-Url: https://err.no/cgi-bin/gitweb.cgi?a=blobdiff_plain;f=fs%2Fcifs%2Freaddir.c;h=edb3b6eb34bc12fd5a35ee632488484d34e1b3fa;hb=92fe7b9ea8ef101bff3c75ade89b93b5f62a7955;hp=42310281871c2be2237eb5906aa1ad4f874ff13f;hpb=c27510c031cae15f84b90f28d6dc02c314d84cf8;p=linux-2.6 diff --git a/fs/cifs/readdir.c b/fs/cifs/readdir.c index 4231028187..edb3b6eb34 100644 --- a/fs/cifs/readdir.c +++ b/fs/cifs/readdir.c @@ -91,7 +91,10 @@ static int construct_dentry(struct qstr *qstring, struct file *file, } *ptmp_inode = new_inode(file->f_dentry->d_sb); - tmp_dentry->d_op = &cifs_dentry_ops; + if (pTcon->nocase) + tmp_dentry->d_op = &cifs_ci_dentry_ops; + else + tmp_dentry->d_op = &cifs_dentry_ops; if(*ptmp_inode == NULL) return rc; rc = 1; @@ -139,6 +142,11 @@ static void fill_in_inode(struct inode *tmp_inode, tmp_inode->i_gid = cifs_sb->mnt_gid; /* set default mode. will override for dirs below */ tmp_inode->i_mode = cifs_sb->mnt_file_mode; + } else { + /* mask off the type bits since it gets set + below and we do not want to get two type + bits set */ + tmp_inode->i_mode &= ~S_IFMT; } if (attr & ATTR_DIRECTORY) { @@ -148,6 +156,19 @@ static void fill_in_inode(struct inode *tmp_inode, tmp_inode->i_mode = cifs_sb->mnt_dir_mode; } tmp_inode->i_mode |= S_IFDIR; + } else if ((cifs_sb->mnt_cifs_flags & CIFS_MOUNT_UNX_EMUL) && + (attr & ATTR_SYSTEM)) { + if (end_of_file == 0) { + *pobject_type = DT_FIFO; + tmp_inode->i_mode |= S_IFIFO; + } else { + /* rather than get the type here, we mark the + inode as needing revalidate and get the real type + (blk vs chr vs. symlink) later ie in lookup */ + *pobject_type = DT_REG; + tmp_inode->i_mode |= S_IFREG; + cifsInfo->time = 0; + } /* we no longer mark these because we could not follow them */ /* } else if (attr & ATTR_REPARSE) { *pobject_type = DT_LNK; @@ -183,12 +204,22 @@ static void fill_in_inode(struct inode *tmp_inode, 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) - tmp_inode->i_fop = &cifs_file_direct_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; - tmp_inode->i_data.a_ops = &cifs_addr_ops; + tmp_inode->i_data.a_ops = &cifs_addr_ops; + if((cifs_sb->tcon) && (cifs_sb->tcon->ses) && + (cifs_sb->tcon->ses->server->maxBuf < + 4096 + MAX_CIFS_HDR_SIZE)) + tmp_inode->i_data.a_ops->readpages = NULL; if(isNewInode) return; /* No sense invalidating pages for new inode since have not started caching readahead file @@ -243,6 +274,9 @@ static void unix_fill_in_inode(struct inode *tmp_inode, cifs_NTtimeToUnix(le64_to_cpu(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; @@ -268,6 +302,11 @@ static void unix_fill_in_inode(struct inode *tmp_inode, } 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)); } tmp_inode->i_uid = le64_to_cpu(pfindData->Uid); @@ -287,11 +326,23 @@ static void unix_fill_in_inode(struct inode *tmp_inode, 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) - tmp_inode->i_fop = &cifs_file_direct_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; + tmp_inode->i_data.a_ops = &cifs_addr_ops; + if((cifs_sb->tcon) && (cifs_sb->tcon->ses) && + (cifs_sb->tcon->ses->server->maxBuf < + 4096 + MAX_CIFS_HDR_SIZE)) + tmp_inode->i_data.a_ops->readpages = NULL; if(isNewInode) return; /* No sense invalidating pages for new inode since we @@ -353,9 +404,9 @@ static int initiate_cifs_search(const int xid, struct file *file) if(pTcon == NULL) return -EINVAL; - down(&file->f_dentry->d_sb->s_vfs_rename_sem); - full_path = build_path_from_dentry(file->f_dentry, cifs_sb); - up(&file->f_dentry->d_sb->s_vfs_rename_sem); + mutex_lock(&file->f_dentry->d_sb->s_vfs_rename_mutex); + full_path = build_path_from_dentry(file->f_dentry); + mutex_unlock(&file->f_dentry->d_sb->s_vfs_rename_mutex); if(full_path == NULL) { return -ENOMEM; @@ -375,7 +426,8 @@ ffirst_retry: rc = CIFSFindFirst(xid, pTcon,full_path,cifs_sb->local_nls, &cifsFile->netfid, &cifsFile->srch_inf, - cifs_sb->mnt_cifs_flags & CIFS_MOUNT_MAP_SPECIAL_CHR, CIFS_DIR_SEP(cifs_sb)); + cifs_sb->mnt_cifs_flags & + CIFS_MOUNT_MAP_SPECIAL_CHR, CIFS_DIR_SEP(cifs_sb)); if(rc == 0) cifsFile->invalidHandle = FALSE; if((rc == -EOPNOTSUPP) && @@ -492,6 +544,30 @@ static int cifs_entry_is_dot(char *current_entry, struct cifsFileInfo *cfile) return rc; } +/* Check if directory that we are searching has changed so we can decide + whether we can use the cached search results from the previous search */ +static int is_dir_changed(struct file * file) +{ + struct inode * inode; + struct cifsInodeInfo *cifsInfo; + + if(file->f_dentry == NULL) + return 0; + + inode = file->f_dentry->d_inode; + + if(inode == NULL) + return 0; + + cifsInfo = CIFS_I(inode); + + if(cifsInfo->time == 0) + return 1; /* directory was changed, perhaps due to unlink */ + else + return 0; + +} + /* find the corresponding entry in the search */ /* Note that the SMB server returns search entries for . and .. which complicates logic here if we choose to parse for them and we do not @@ -508,7 +584,8 @@ static int find_cifs_entry(const int xid, struct cifsTconInfo *pTcon, struct cifsFileInfo * cifsFile = file->private_data; /* check if index in the buffer */ - if((cifsFile == NULL) || (ppCurrentEntry == NULL) || (num_to_ret == NULL)) + if((cifsFile == NULL) || (ppCurrentEntry == NULL) || + (num_to_ret == NULL)) return -ENOENT; *ppCurrentEntry = NULL; @@ -516,7 +593,9 @@ static int find_cifs_entry(const int xid, struct cifsTconInfo *pTcon, cifsFile->srch_inf.index_of_last_entry - cifsFile->srch_inf.entries_in_buffer; /* dump_cifs_file_struct(file, "In fce ");*/ - if(index_to_find < first_entry_in_buffer) { + if(((index_to_find < cifsFile->srch_inf.index_of_last_entry) && + is_dir_changed(file)) || + (index_to_find < first_entry_in_buffer)) { /* close and restart search */ cFYI(1,("search backing up - close and restart search")); cifsFile->invalidHandle = TRUE; @@ -550,7 +629,6 @@ static int find_cifs_entry(const int xid, struct cifsTconInfo *pTcon, char * end_of_smb = cifsFile->srch_inf.ntwrk_buf_start + smbCalcSize((struct smb_hdr *) cifsFile->srch_inf.ntwrk_buf_start); -/* dump_cifs_file_struct(file,"found entry in fce "); */ first_entry_in_buffer = cifsFile->srch_inf.index_of_last_entry - cifsFile->srch_inf.entries_in_buffer; pos_in_buf = index_to_find - first_entry_in_buffer; @@ -584,11 +662,10 @@ static int find_cifs_entry(const int xid, struct cifsTconInfo *pTcon, } if(pos_in_buf >= cifsFile->srch_inf.entries_in_buffer) { - cFYI(1,("can not return entries when pos_in_buf beyond last entry")); + cFYI(1,("can not return entries pos_in_buf beyond last entry")); *num_to_ret = 0; } else *num_to_ret = cifsFile->srch_inf.entries_in_buffer - pos_in_buf; -/* dump_cifs_file_struct(file, "end fce ");*/ return rc; } @@ -652,7 +729,7 @@ static int cifs_get_name_from_search_buf(struct qstr *pqst, (__le16 *)filename, len/2, nlt); else pqst->len = cifs_strfromUCS_le((char *)pqst->name, - (wchar_t *)filename,len/2,nlt); + (__le16 *)filename,len/2,nlt); } else { pqst->name = filename; pqst->len = len; @@ -808,15 +885,12 @@ int cifs_readdir(struct file *file, void *direntry, filldir_t filldir) FreeXid(xid); return -EIO; } -/* dump_cifs_file_struct(file, "Begin rdir "); */ cifs_sb = CIFS_SB(file->f_dentry->d_sb); pTcon = cifs_sb->tcon; if(pTcon == NULL) return -EINVAL; -/* cFYI(1,("readdir2 pos: %lld",file->f_pos)); */ - switch ((int) file->f_pos) { case 0: /*if (filldir(direntry, ".", 1, file->f_pos, @@ -869,7 +943,6 @@ int cifs_readdir(struct file *file, void *direntry, filldir_t filldir) cifsFile->search_resume_name = NULL; */ /* BB account for . and .. in f_pos as special case */ - /* dump_cifs_file_struct(file, "rdir after default ");*/ rc = find_cifs_entry(xid,pTcon, file, ¤t_entry,&num_to_fill); @@ -917,7 +990,6 @@ int cifs_readdir(struct file *file, void *direntry, filldir_t filldir) } /* end switch */ rddir2_exit: - /* dump_cifs_file_struct(file, "end rdir "); */ FreeXid(xid); return rc; }