diff options
author | Jeff Layton <jlayton@redhat.com> | 2009-06-25 00:56:52 -0400 |
---|---|---|
committer | Steve French <sfrench@us.ibm.com> | 2009-07-01 17:26:42 -0400 |
commit | cc0bad7552308e8905d6ea56e6b7811fa67e716d (patch) | |
tree | c02a91f13a502f444330b91b36ab12f55f352268 /fs/cifs/readdir.c | |
parent | d960eea974f5e500c0dcb95a934239cc1f481cfd (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.c | 253 |
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 | */ | ||
70 | static struct dentry * | ||
71 | cifs_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 */ |
68 | static int | 117 | static 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 | ||
302 | static 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 | ||
937 | out: | ||
1011 | dput(tmp_dentry); | 938 | dput(tmp_dentry); |
1012 | return rc; | 939 | return rc; |
1013 | } | 940 | } |