aboutsummaryrefslogtreecommitdiffstats
path: root/fs/cifs/readdir.c
diff options
context:
space:
mode:
authorJeff Layton <jlayton@redhat.com>2009-06-25 00:56:52 -0400
committerSteve French <sfrench@us.ibm.com>2009-07-01 17:26:42 -0400
commitcc0bad7552308e8905d6ea56e6b7811fa67e716d (patch)
treec02a91f13a502f444330b91b36ab12f55f352268 /fs/cifs/readdir.c
parentd960eea974f5e500c0dcb95a934239cc1f481cfd (diff)
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>
Diffstat (limited to 'fs/cifs/readdir.c')
-rw-r--r--fs/cifs/readdir.c253
1 files changed, 90 insertions, 163 deletions
diff --git a/fs/cifs/readdir.c b/fs/cifs/readdir.c
index 86d0055dc529..231aa6953f83 100644
--- a/fs/cifs/readdir.c
+++ b/fs/cifs/readdir.c
@@ -63,6 +63,55 @@ static inline void dump_cifs_file_struct(struct file *file, char *label)
63} 63}
64#endif /* DEBUG2 */ 64#endif /* DEBUG2 */
65 65
66/*
67 * Find the dentry that matches "name". If there isn't one, create one. If it's
68 * a negative dentry or the uniqueid changed, then drop it and recreate it.
69 */
70static struct dentry *
71cifs_readdir_lookup(struct dentry *parent, struct qstr *name,
72 struct cifs_fattr *fattr)
73{
74 struct dentry *dentry, *alias;
75 struct inode *inode;
76 struct super_block *sb = parent->d_inode->i_sb;
77
78 cFYI(1, ("For %s", name->name));
79
80 dentry = d_lookup(parent, name);
81 if (dentry) {
82 /* FIXME: check for inode number changes? */
83 if (dentry->d_inode != NULL)
84 return dentry;
85 d_drop(dentry);
86 dput(dentry);
87 }
88
89 dentry = d_alloc(parent, name);
90 if (dentry == NULL)
91 return NULL;
92
93 inode = cifs_iget(sb, fattr);
94 if (!inode) {
95 dput(dentry);
96 return NULL;
97 }
98
99 if (CIFS_SB(sb)->tcon->nocase)
100 dentry->d_op = &cifs_ci_dentry_ops;
101 else
102 dentry->d_op = &cifs_dentry_ops;
103
104 alias = d_materialise_unique(dentry, inode);
105 if (alias != NULL) {
106 dput(dentry);
107 if (IS_ERR(alias))
108 return NULL;
109 dentry = alias;
110 }
111
112 return dentry;
113}
114
66/* Returns 1 if new inode created, 2 if both dentry and inode were */ 115/* Returns 1 if new inode created, 2 if both dentry and inode were */
67/* Might check in the future if inode number changed so we can rehash inode */ 116/* Might check in the future if inode number changed so we can rehash inode */
68static int 117static int
@@ -76,7 +125,6 @@ construct_dentry(struct qstr *qstring, struct file *file,
76 125
77 cFYI(1, ("For %s", qstring->name)); 126 cFYI(1, ("For %s", qstring->name));
78 127
79 qstring->hash = full_name_hash(qstring->name, qstring->len);
80 tmp_dentry = d_lookup(file->f_path.dentry, qstring); 128 tmp_dentry = d_lookup(file->f_path.dentry, qstring);
81 if (tmp_dentry) { 129 if (tmp_dentry) {
82 /* BB: overwrite old name? i.e. tmp_dentry->d_name and 130 /* 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,
299 } 347 }
300} 348}
301 349
302static void unix_fill_in_inode(struct inode *tmp_inode,
303 FILE_UNIX_INFO *pfindData, unsigned int *pobject_type, int isNewInode)
304{
305 loff_t local_size;
306 struct timespec local_mtime;
307
308 struct cifsInodeInfo *cifsInfo = CIFS_I(tmp_inode);
309 struct cifs_sb_info *cifs_sb = CIFS_SB(tmp_inode->i_sb);
310
311 __u32 type = le32_to_cpu(pfindData->Type);
312 __u64 num_of_bytes = le64_to_cpu(pfindData->NumOfBytes);
313 __u64 end_of_file = le64_to_cpu(pfindData->EndOfFile);
314 cifsInfo->time = jiffies;
315 atomic_inc(&cifsInfo->inUse);
316
317 /* save mtime and size */
318 local_mtime = tmp_inode->i_mtime;
319 local_size = tmp_inode->i_size;
320
321 tmp_inode->i_atime =
322 cifs_NTtimeToUnix(pfindData->LastAccessTime);
323 tmp_inode->i_mtime =
324 cifs_NTtimeToUnix(pfindData->LastModificationTime);
325 tmp_inode->i_ctime =
326 cifs_NTtimeToUnix(pfindData->LastStatusChange);
327
328 tmp_inode->i_mode = le64_to_cpu(pfindData->Permissions);
329 /* since we set the inode type below we need to mask off type
330 to avoid strange results if bits above were corrupt */
331 tmp_inode->i_mode &= ~S_IFMT;
332 if (type == UNIX_FILE) {
333 *pobject_type = DT_REG;
334 tmp_inode->i_mode |= S_IFREG;
335 } else if (type == UNIX_SYMLINK) {
336 *pobject_type = DT_LNK;
337 tmp_inode->i_mode |= S_IFLNK;
338 } else if (type == UNIX_DIR) {
339 *pobject_type = DT_DIR;
340 tmp_inode->i_mode |= S_IFDIR;
341 } else if (type == UNIX_CHARDEV) {
342 *pobject_type = DT_CHR;
343 tmp_inode->i_mode |= S_IFCHR;
344 tmp_inode->i_rdev = MKDEV(le64_to_cpu(pfindData->DevMajor),
345 le64_to_cpu(pfindData->DevMinor) & MINORMASK);
346 } else if (type == UNIX_BLOCKDEV) {
347 *pobject_type = DT_BLK;
348 tmp_inode->i_mode |= S_IFBLK;
349 tmp_inode->i_rdev = MKDEV(le64_to_cpu(pfindData->DevMajor),
350 le64_to_cpu(pfindData->DevMinor) & MINORMASK);
351 } else if (type == UNIX_FIFO) {
352 *pobject_type = DT_FIFO;
353 tmp_inode->i_mode |= S_IFIFO;
354 } else if (type == UNIX_SOCKET) {
355 *pobject_type = DT_SOCK;
356 tmp_inode->i_mode |= S_IFSOCK;
357 } else {
358 /* safest to just call it a file */
359 *pobject_type = DT_REG;
360 tmp_inode->i_mode |= S_IFREG;
361 cFYI(1, ("unknown inode type %d", type));
362 }
363
364 if (cifs_sb->mnt_cifs_flags & CIFS_MOUNT_OVERR_UID)
365 tmp_inode->i_uid = cifs_sb->mnt_uid;
366 else
367 tmp_inode->i_uid = le64_to_cpu(pfindData->Uid);
368 if (cifs_sb->mnt_cifs_flags & CIFS_MOUNT_OVERR_GID)
369 tmp_inode->i_gid = cifs_sb->mnt_gid;
370 else
371 tmp_inode->i_gid = le64_to_cpu(pfindData->Gid);
372 tmp_inode->i_nlink = le64_to_cpu(pfindData->Nlinks);
373
374 cifsInfo->server_eof = end_of_file;
375 spin_lock(&tmp_inode->i_lock);
376 if (is_size_safe_to_change(cifsInfo, end_of_file)) {
377 /* can not safely change the file size here if the
378 client is writing to it due to potential races */
379 i_size_write(tmp_inode, end_of_file);
380
381 /* 512 bytes (2**9) is the fake blocksize that must be used */
382 /* for this calculation, not the real blocksize */
383 tmp_inode->i_blocks = (512 - 1 + num_of_bytes) >> 9;
384 }
385 spin_unlock(&tmp_inode->i_lock);
386
387 if (S_ISREG(tmp_inode->i_mode)) {
388 cFYI(1, ("File inode"));
389 tmp_inode->i_op = &cifs_file_inode_ops;
390
391 if (cifs_sb->mnt_cifs_flags & CIFS_MOUNT_DIRECT_IO) {
392 if (cifs_sb->mnt_cifs_flags & CIFS_MOUNT_NO_BRL)
393 tmp_inode->i_fop = &cifs_file_direct_nobrl_ops;
394 else
395 tmp_inode->i_fop = &cifs_file_direct_ops;
396 } else if (cifs_sb->mnt_cifs_flags & CIFS_MOUNT_NO_BRL)
397 tmp_inode->i_fop = &cifs_file_nobrl_ops;
398 else
399 tmp_inode->i_fop = &cifs_file_ops;
400
401 if ((cifs_sb->tcon) && (cifs_sb->tcon->ses) &&
402 (cifs_sb->tcon->ses->server->maxBuf <
403 PAGE_CACHE_SIZE + MAX_CIFS_HDR_SIZE))
404 tmp_inode->i_data.a_ops = &cifs_addr_ops_smallbuf;
405 else
406 tmp_inode->i_data.a_ops = &cifs_addr_ops;
407
408 if (isNewInode)
409 return; /* No sense invalidating pages for new inode
410 since we have not started caching readahead
411 file data for it yet */
412
413 if (timespec_equal(&tmp_inode->i_mtime, &local_mtime) &&
414 (local_size == tmp_inode->i_size)) {
415 cFYI(1, ("inode exists but unchanged"));
416 } else {
417 /* file may have changed on server */
418 cFYI(1, ("invalidate inode, readdir detected change"));
419 invalidate_remote_inode(tmp_inode);
420 }
421 } else if (S_ISDIR(tmp_inode->i_mode)) {
422 cFYI(1, ("Directory inode"));
423 tmp_inode->i_op = &cifs_dir_inode_ops;
424 tmp_inode->i_fop = &cifs_dir_ops;
425 } else if (S_ISLNK(tmp_inode->i_mode)) {
426 cFYI(1, ("Symbolic Link inode"));
427 tmp_inode->i_op = &cifs_symlink_inode_ops;
428/* tmp_inode->i_fop = *//* do not need to set to anything */
429 } else {
430 cFYI(1, ("Special inode"));
431 init_special_inode(tmp_inode, tmp_inode->i_mode,
432 tmp_inode->i_rdev);
433 }
434}
435
436/* BB eventually need to add the following helper function to 350/* BB eventually need to add the following helper function to
437 resolve NT_STATUS_STOPPED_ON_SYMLINK return code when 351 resolve NT_STATUS_STOPPED_ON_SYMLINK return code when
438 we try to do FindFirst on (NTFS) directory symlinks */ 352 we try to do FindFirst on (NTFS) directory symlinks */
@@ -872,7 +786,7 @@ static int cifs_get_name_from_search_buf(struct qstr *pqst,
872 len = strnlen(filename, PATH_MAX); 786 len = strnlen(filename, PATH_MAX);
873 } 787 }
874 788
875 *pinum = le64_to_cpu(pFindData->UniqueId); 789 *pinum = le64_to_cpu(pFindData->basic.UniqueId);
876 } else if (level == SMB_FIND_FILE_DIRECTORY_INFO) { 790 } else if (level == SMB_FIND_FILE_DIRECTORY_INFO) {
877 FILE_DIRECTORY_INFO *pFindData = 791 FILE_DIRECTORY_INFO *pFindData =
878 (FILE_DIRECTORY_INFO *)current_entry; 792 (FILE_DIRECTORY_INFO *)current_entry;
@@ -934,9 +848,11 @@ static int cifs_filldir(char *pfindEntry, struct file *file, filldir_t filldir,
934 struct cifsFileInfo *pCifsF; 848 struct cifsFileInfo *pCifsF;
935 unsigned int obj_type; 849 unsigned int obj_type;
936 __u64 inum; 850 __u64 inum;
851 ino_t ino;
937 struct cifs_sb_info *cifs_sb; 852 struct cifs_sb_info *cifs_sb;
938 struct inode *tmp_inode; 853 struct inode *tmp_inode;
939 struct dentry *tmp_dentry; 854 struct dentry *tmp_dentry;
855 struct cifs_fattr fattr;
940 856
941 /* get filename and len into qstring */ 857 /* get filename and len into qstring */
942 /* get dentry */ 858 /* get dentry */
@@ -967,39 +883,49 @@ static int cifs_filldir(char *pfindEntry, struct file *file, filldir_t filldir,
967 return rc; 883 return rc;
968 884
969 /* only these two infolevels return valid inode numbers */ 885 /* only these two infolevels return valid inode numbers */
970 if (pCifsF->srch_inf.info_level == SMB_FIND_FILE_UNIX || 886 if (pCifsF->srch_inf.info_level == SMB_FIND_FILE_UNIX) {
971 pCifsF->srch_inf.info_level == SMB_FIND_FILE_ID_FULL_DIR_INFO) 887 cifs_unix_basic_to_fattr(&fattr,
972 rc = construct_dentry(&qstring, file, &tmp_inode, &tmp_dentry, 888 &((FILE_UNIX_INFO *) pfindEntry)->basic,
973 &inum); 889 cifs_sb);
974 else 890 tmp_dentry = cifs_readdir_lookup(file->f_dentry, &qstring,
975 rc = construct_dentry(&qstring, file, &tmp_inode, &tmp_dentry, 891 &fattr);
976 NULL); 892 obj_type = fattr.cf_dtype;
893 ino = cifs_uniqueid_to_ino_t(fattr.cf_uniqueid);
894 } else {
895 if (pCifsF->srch_inf.info_level ==
896 SMB_FIND_FILE_ID_FULL_DIR_INFO)
897 rc = construct_dentry(&qstring, file, &tmp_inode,
898 &tmp_dentry, &inum);
899 else
900 rc = construct_dentry(&qstring, file, &tmp_inode,
901 &tmp_dentry, NULL);
977 902
978 if ((tmp_inode == NULL) || (tmp_dentry == NULL)) 903 if ((tmp_inode == NULL) || (tmp_dentry == NULL)) {
979 return -ENOMEM; 904 rc = -ENOMEM;
905 goto out;
906 }
980 907
981 /* we pass in rc below, indicating whether it is a new inode, 908 /* we pass in rc below, indicating whether it is a new inode,
982 so we can figure out whether to invalidate the inode cached 909 * so we can figure out whether to invalidate the inode cached
983 data if the file has changed */ 910 * data if the file has changed
984 if (pCifsF->srch_inf.info_level == SMB_FIND_FILE_UNIX) 911 */
985 unix_fill_in_inode(tmp_inode, 912 if (pCifsF->srch_inf.info_level == SMB_FIND_FILE_INFO_STANDARD)
986 (FILE_UNIX_INFO *)pfindEntry, 913 fill_in_inode(tmp_inode, 0, pfindEntry, &obj_type, rc);
987 &obj_type, rc); 914 else
988 else if (pCifsF->srch_inf.info_level == SMB_FIND_FILE_INFO_STANDARD) 915 fill_in_inode(tmp_inode, 1, pfindEntry, &obj_type, rc);
989 fill_in_inode(tmp_inode, 0 /* old level 1 buffer type */,
990 pfindEntry, &obj_type, rc);
991 else
992 fill_in_inode(tmp_inode, 1 /* NT */, pfindEntry, &obj_type, rc);
993 916
994 if (rc) /* new inode - needs to be tied to dentry */ { 917 /* new inode - needs to be tied to dentry */
995 d_instantiate(tmp_dentry, tmp_inode); 918 if (rc) {
996 if (rc == 2) 919 d_instantiate(tmp_dentry, tmp_inode);
997 d_rehash(tmp_dentry); 920 if (rc == 2)
998 } 921 d_rehash(tmp_dentry);
922 }
999 923
924 ino = cifs_uniqueid_to_ino_t(tmp_inode->i_ino);
925 }
1000 926
1001 rc = filldir(direntry, qstring.name, qstring.len, file->f_pos, 927 rc = filldir(direntry, qstring.name, qstring.len, file->f_pos,
1002 tmp_inode->i_ino, obj_type); 928 ino, obj_type);
1003 if (rc) { 929 if (rc) {
1004 cFYI(1, ("filldir rc = %d", rc)); 930 cFYI(1, ("filldir rc = %d", rc));
1005 /* we can not return filldir errors to the caller 931 /* 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,
1008 rc = -EOVERFLOW; 934 rc = -EOVERFLOW;
1009 } 935 }
1010 936
937out:
1011 dput(tmp_dentry); 938 dput(tmp_dentry);
1012 return rc; 939 return rc;
1013} 940}