| Start/ | End/ | |||
| True | False | - | Line | Source |
| 1 | /* | |||
| 2 | * linux/fs/nfs/dir.c | |||
| 3 | * | |||
| 4 | * Copyright (C) 1992 Rick Sladkey | |||
| 5 | * | |||
| 6 | * nfs directory handling functions | |||
| 7 | * | |||
| 8 | * 10 Apr 1996 Added silly rename for unlink --okir | |||
| 9 | * 28 Sep 1996 Improved directory cache --okir | |||
| 10 | * 23 Aug 1997 Claus Heine claus@momo.math.rwth-aachen.de | |||
| 11 | * Re-implemented silly rename for unlink, newly implemented | |||
| 12 | * silly rename for nfs_rename() following the suggestions | |||
| 13 | * of Olaf Kirch (okir) found in this file. | |||
| 14 | * Following Linus comments on my original hack, this version | |||
| 15 | * depends only on the dcache stuff and doesn't touch the inode | |||
| 16 | * layer (iput() and friends). | |||
| 17 | * 6 Jun 1999 Cache readdir lookups in the page cache. -DaveM | |||
| 18 | */ | |||
| 19 | ||||
| 20 | #include <linux/time.h> | |||
| 21 | #include <linux/errno.h> | |||
| 22 | #include <linux/stat.h> | |||
| 23 | #include <linux/fcntl.h> | |||
| 24 | #include <linux/string.h> | |||
| 25 | #include <linux/kernel.h> | |||
| 26 | #include <linux/slab.h> | |||
| 27 | #include <linux/mm.h> | |||
| 28 | #include <linux/sunrpc/clnt.h> | |||
| 29 | #include <linux/nfs_fs.h> | |||
| 30 | #include <linux/nfs_mount.h> | |||
| 31 | #include <linux/pagemap.h> | |||
| 32 | #include <linux/smp_lock.h> | |||
| 33 | #include <linux/namei.h> | |||
| 34 | ||||
| 35 | #include "nfs4_fs.h" | |||
| 36 | #include "delegation.h" | |||
| 37 | ||||
| 38 | #define NFS_PARANOIA 1 | |||
| 39 | /* #define NFS_DEBUG_VERBOSE 1 */ | |||
| 40 | ||||
| 41 | static int nfs_opendir(struct inode *, struct file *); | |||
| 42 | static int nfs_readdir(struct file *, void *, filldir_t); | |||
| 43 | static struct dentry *nfs_lookup(struct inode *, struct dentry *, struct nameidata *); | |||
| 44 | static int nfs_create(struct inode *, struct dentry *, int, struct nameidata *); | |||
| 45 | static int nfs_mkdir(struct inode *, struct dentry *, int); | |||
| 46 | static int nfs_rmdir(struct inode *, struct dentry *); | |||
| 47 | static int nfs_unlink(struct inode *, struct dentry *); | |||
| 48 | static int nfs_symlink(struct inode *, struct dentry *, const char *); | |||
| 49 | static int nfs_link(struct dentry *, struct inode *, struct dentry *); | |||
| 50 | static int nfs_mknod(struct inode *, struct dentry *, int, dev_t); | |||
| 51 | static int nfs_rename(struct inode *, struct dentry *, | |||
| 52 | struct inode *, struct dentry *); | |||
| 53 | static int nfs_fsync_dir(struct file *, struct dentry *, int); | |||
| 54 | static loff_t nfs_llseek_dir(struct file *, loff_t, int); | |||
| 55 | ||||
| 56 | struct file_operations nfs_dir_operations = { | |||
| 57 | .llseek = nfs_llseek_dir, | |||
| 58 | .read = generic_read_dir, | |||
| 59 | .readdir = nfs_readdir, | |||
| 60 | .open = nfs_opendir, | |||
| 61 | .release = nfs_release, | |||
| 62 | .fsync = nfs_fsync_dir, | |||
| 63 | }; | |||
| 64 | ||||
| 65 | struct inode_operations nfs_dir_inode_operations = { | |||
| 66 | .create = nfs_create, | |||
| 67 | .lookup = nfs_lookup, | |||
| 68 | .link = nfs_link, | |||
| 69 | .unlink = nfs_unlink, | |||
| 70 | .symlink = nfs_symlink, | |||
| 71 | .mkdir = nfs_mkdir, | |||
| 72 | .rmdir = nfs_rmdir, | |||
| 73 | .mknod = nfs_mknod, | |||
| 74 | .rename = nfs_rename, | |||
| 75 | .permission = nfs_permission, | |||
| 76 | .getattr = nfs_getattr, | |||
| 77 | .setattr = nfs_setattr, | |||
| 78 | }; | |||
| 79 | ||||
| 80 | #ifdef CONFIG_NFS_V3 | |||
| 81 | struct inode_operations nfs3_dir_inode_operations = { | |||
| 82 | .create = nfs_create, | |||
| 83 | .lookup = nfs_lookup, | |||
| 84 | .link = nfs_link, | |||
| 85 | .unlink = nfs_unlink, | |||
| 86 | .symlink = nfs_symlink, | |||
| 87 | .mkdir = nfs_mkdir, | |||
| 88 | .rmdir = nfs_rmdir, | |||
| 89 | .mknod = nfs_mknod, | |||
| 90 | .rename = nfs_rename, | |||
| 91 | .permission = nfs_permission, | |||
| 92 | .getattr = nfs_getattr, | |||
| 93 | .setattr = nfs_setattr, | |||
| 94 | .listxattr = nfs3_listxattr, | |||
| 95 | .getxattr = nfs3_getxattr, | |||
| 96 | .setxattr = nfs3_setxattr, | |||
| 97 | .removexattr = nfs3_removexattr, | |||
| 98 | }; | |||
| 99 | #endif /* CONFIG_NFS_V3 */ | |||
| 100 | ||||
| 101 | #ifdef CONFIG_NFS_V4 | |||
| 102 | ||||
| 103 | static struct dentry *nfs_atomic_lookup(struct inode *, struct dentry *, struct nameidata *); | |||
| 104 | struct inode_operations nfs4_dir_inode_operations = { | |||
| 105 | .create = nfs_create, | |||
| 106 | .lookup = nfs_atomic_lookup, | |||
| 107 | .link = nfs_link, | |||
| 108 | .unlink = nfs_unlink, | |||
| 109 | .symlink = nfs_symlink, | |||
| 110 | .mkdir = nfs_mkdir, | |||
| 111 | .rmdir = nfs_rmdir, | |||
| 112 | .mknod = nfs_mknod, | |||
| 113 | .rename = nfs_rename, | |||
| 114 | .permission = nfs_permission, | |||
| 115 | .getattr = nfs_getattr, | |||
| 116 | .setattr = nfs_setattr, | |||
| 117 | .getxattr = nfs4_getxattr, | |||
| 118 | .setxattr = nfs4_setxattr, | |||
| 119 | .listxattr = nfs4_listxattr, | |||
| 120 | }; | |||
| 121 | ||||
| 122 | #endif /* CONFIG_NFS_V4 */ | |||
| 123 | ||||
| 124 | /* | |||
| 125 | * Open file | |||
| 126 | */ | |||
| 127 | static int | |||
| 0 | 0 | - | 128 | nfs_opendir(struct inode *inode, struct file *filp) |
| 129 | { | |||
| 130 | int res = 0; | |||
| 131 | ||||
| 132 | lock_kernel(); | |||
| 0 | 0 | - | 132 | do-while (0) |
| 133 | /* Call generic open code in order to cache credentials */ | |||
| 0 | 0 | - | 134 | if (!res) |
| 135 | res = nfs_open(inode, filp); | |||
| 136 | unlock_kernel(); | |||
| 0 | 0 | - | 136 | do-while (0) |
| 0 | - | 137 | return res; | |
| 138 | } | |||
| 139 | ||||
| 140 | typedef u32 * (*decode_dirent_t)(u32 *, struct nfs_entry *, int); | |||
| 141 | typedef struct { | |||
| 142 | struct file *file; | |||
| 143 | struct page *page; | |||
| 144 | unsigned long page_index; | |||
| 145 | u32 *ptr; | |||
| 146 | u64 *dir_cookie; | |||
| 147 | loff_t current_index; | |||
| 148 | struct nfs_entry *entry; | |||
| 149 | decode_dirent_t decode; | |||
| 150 | int plus; | |||
| 151 | int error; | |||
| 152 | } nfs_readdir_descriptor_t; | |||
| 153 | ||||
| 154 | /* Now we cache directories properly, by stuffing the dirent | |||
| 155 | * data directly in the page cache. | |||
| 156 | * | |||
| 157 | * Inode invalidation due to refresh etc. takes care of | |||
| 158 | * _everything_, no sloppy entry flushing logic, no extraneous | |||
| 159 | * copying, network direct to page cache, the way it was meant | |||
| 160 | * to be. | |||
| 161 | * | |||
| 162 | * NOTE: Dirent information verification is done always by the | |||
| 163 | * page-in of the RPC reply, nowhere else, this simplies | |||
| 164 | * things substantially. | |||
| 165 | */ | |||
| 166 | static | |||
| 0 | 0 | - | 167 | int nfs_readdir_filler(nfs_readdir_descriptor_t *desc, struct page *page) |
| 168 | { | |||
| 169 | struct file *file = desc->file; | |||
| 170 | struct inode *inode = file->f_dentry->d_inode; | |||
| 171 | struct rpc_cred *cred = nfs_file_cred(file); | |||
| 172 | unsigned long timestamp; | |||
| 173 | int error; | |||
| 174 | ||||
| 175 | dfprintk(VFS, "NFS: nfs_readdir_filler() reading cookie %Lu into page %lu.\n", (long long)desc->entry->cookie, page->index); | |||
| 0 | 0 | - | 175 | if (__builtin_expect ( ! ! ( nfs_debug & 0x0.. |
| 0 | 0 | - | 175 | do-while (0) |
| 176 | ||||
| 177 | again: | |||
| 178 | timestamp = jiffies; | |||
| 179 | error = NFS_PROTO(inode)->readdir(file->f_dentry, cred, desc->entry->cookie, page, | |||
| 180 | NFS_SERVER(inode)->dtsize, desc->plus); | |||
| 0 | 0 | - | 181 | if (error < 0) { |
| 182 | /* We requested READDIRPLUS, but the server doesn't grok it */ | |||
| 0 | 0 | - | 183 | if (error == -ENOTSUPP && desc->plus) { |
| 0 | - | 183 | T && T | |
| 0 | - | 183 | T && F | |
| 0 | - | 183 | F && _ | |
| 184 | NFS_SERVER(inode)->caps &= ~NFS_CAP_READDIRPLUS; | |||
| 185 | clear_bit(NFS_INO_ADVISE_RDPLUS, &NFS_FLAGS(inode)); | |||
| 186 | desc->plus = 0; | |||
| 0 | - | 187 | goto again; | |
| 188 | } | |||
| 0 | - | 189 | goto error; | |
| 190 | } | |||
| 191 | SetPageUptodate(page); | |||
| 192 | spin_lock(&inode->i_lock); | |||
| 192 | do | |||
| 0 | 0 | - | 192 | do-while (0) |
| 0 | 0 | - | 192 | do-while (0) |
| 193 | NFS_I(inode)->cache_validity |= NFS_INO_INVALID_ATIME; | |||
| 194 | spin_unlock(&inode->i_lock); | |||
| 194 | do | |||
| 0 | 0 | - | 194 | do-while (0) |
| 0 | 0 | - | 194 | do-while (0) |
| 195 | /* Ensure consistent page alignment of the data. | |||
| 196 | * Note: assumes we have exclusive access to this mapping either | |||
| 197 | * through inode->i_mutex or some other mechanism. | |||
| 198 | */ | |||
| 0 | 0 | - | 199 | if (page->index == 0) |
| 200 | invalidate_inode_pages2_range(inode->i_mapping, PAGE_CACHE_SIZE, -1); | |||
| 201 | unlock_page(page); | |||
| 0 | - | 202 | return 0; | |
| 203 | error: | |||
| 204 | SetPageError(page); | |||
| 205 | unlock_page(page); | |||
| 206 | nfs_zap_caches(inode); | |||
| 207 | desc->error = error; | |||
| 0 | - | 208 | return -EIO; | |
| 209 | } | |||
| 210 | ||||
| 211 | static inline | |||
| 0 | 0 | - | 212 | int dir_decode(nfs_readdir_descriptor_t *desc) |
| 213 | { | |||
| 214 | u32 *p = desc->ptr; | |||
| 215 | p = desc->decode(p, desc->entry, desc->plus); | |||
| 0 | 0 | - | 216 | if (IS_ERR(p)) |
| 0 | - | 217 | return PTR_ERR(p); | |
| 218 | desc->ptr = p; | |||
| 0 | - | 219 | return 0; | |
| 220 | } | |||
| 221 | ||||
| 222 | static inline | |||
| 0 | 0 | - | 223 | void dir_page_release(nfs_readdir_descriptor_t *desc) |
| 224 | { | |||
| 225 | kunmap(desc->page); | |||
| 0 | 0 | - | 225 | do-while (0) |
| 226 | page_cache_release(desc->page); | |||
| 227 | desc->page = NULL; | |||
| 228 | desc->ptr = NULL; | |||
| 229 | } | |||
| 230 | ||||
| 231 | /* | |||
| 232 | * Given a pointer to a buffer that has already been filled by a call | |||
| 233 | * to readdir, find the next entry with cookie '*desc->dir_cookie'. | |||
| 234 | * | |||
| 235 | * If the end of the buffer has been reached, return -EAGAIN, if not, | |||
| 236 | * return the offset within the buffer of the next entry to be | |||
| 237 | * read. | |||
| 238 | */ | |||
| 239 | static inline | |||
| 0 | 0 | - | 240 | int find_dirent(nfs_readdir_descriptor_t *desc) |
| 241 | { | |||
| 242 | struct nfs_entry *entry = desc->entry; | |||
| 243 | int loop_count = 0, | |||
| 244 | status; | |||
| 245 | ||||
| 0 | 0 | - | 246 | while((status = dir_decode(desc)) == 0) { |
| 247 | dfprintk(VFS, "NFS: found cookie %Lu\n", (unsigned long long)entry->cookie); | |||
| 0 | 0 | - | 247 | if (__builtin_expect ( ! ! ( nfs_debug & 0.. |
| 0 | 0 | - | 247 | do-while (0) |
| 0 | 0 | - | 248 | if (entry->prev_cookie == *desc->dir_cookie) |
| 0 | - | 249 | break; | |
| 0 | 0 | - | 250 | if (loop_count++ > 200) { |
| 251 | loop_count = 0; | |||
| 252 | schedule(); | |||
| 253 | } | |||
| 254 | } | |||
| 255 | dfprintk(VFS, "NFS: find_dirent() returns %d\n", status); | |||
| 0 | 0 | - | 255 | if (__builtin_expect ( ! ! ( nfs_debug & 0x0.. |
| 0 | 0 | - | 255 | do-while (0) |
| 0 | - | 256 | return status; | |
| 257 | } | |||
| 258 | ||||
| 259 | /* | |||
| 260 | * Given a pointer to a buffer that has already been filled by a call | |||
| 261 | * to readdir, find the entry at offset 'desc->file->f_pos'. | |||
| 262 | * | |||
| 263 | * If the end of the buffer has been reached, return -EAGAIN, if not, | |||
| 264 | * return the offset within the buffer of the next entry to be | |||
| 265 | * read. | |||
| 266 | */ | |||
| 267 | static inline | |||
| 0 | 0 | - | 268 | int find_dirent_index(nfs_readdir_descriptor_t *desc) |
| 269 | { | |||
| 270 | struct nfs_entry *entry = desc->entry; | |||
| 271 | int loop_count = 0, | |||
| 272 | status; | |||
| 273 | ||||
| 0 | 0 | - | 274 | for(;;) { |
| 275 | status = dir_decode(desc); | |||
| 0 | 0 | - | 276 | if (status) |
| 0 | - | 277 | break; | |
| 278 | ||||
| 279 | dfprintk(VFS, "NFS: found cookie %Lu at index %Ld\n", (unsigned long long)entry->cookie, desc->current_index); | |||
| 0 | 0 | - | 279 | if (__builtin_expect ( ! ! ( nfs_debug & 0.. |
| 0 | 0 | - | 279 | do-while (0) |
| 280 | ||||
| 0 | 0 | - | 281 | if (desc->file->f_pos == desc->current_index) { |
| 282 | *desc->dir_cookie = entry->cookie; | |||
| 0 | - | 283 | break; | |
| 284 | } | |||
| 285 | desc->current_index++; | |||
| 0 | 0 | - | 286 | if (loop_count++ > 200) { |
| 287 | loop_count = 0; | |||
| 288 | schedule(); | |||
| 289 | } | |||
| 290 | } | |||
| 291 | dfprintk(VFS, "NFS: find_dirent_index() returns %d\n", status); | |||
| 0 | 0 | - | 291 | if (__builtin_expect ( ! ! ( nfs_debug & 0x0.. |
| 0 | 0 | - | 291 | do-while (0) |
| 0 | - | 292 | return status; | |
| 293 | } | |||
| 294 | ||||
| 295 | /* | |||
| 296 | * Find the given page, and call find_dirent() or find_dirent_index in | |||
| 297 | * order to try to return the next entry. | |||
| 298 | */ | |||
| 299 | static inline | |||
| 0 | 0 | - | 300 | int find_dirent_page(nfs_readdir_descriptor_t *desc) |
| 301 | { | |||
| 302 | struct inode *inode = desc->file->f_dentry->d_inode; | |||
| 303 | struct page *page; | |||
| 304 | int status; | |||
| 305 | ||||
| 306 | dfprintk(VFS, "NFS: find_dirent_page() searching directory page %ld\n", desc->page_index); | |||
| 0 | 0 | - | 306 | if (__builtin_expect ( ! ! ( nfs_debug & 0x0.. |
| 0 | 0 | - | 306 | do-while (0) |
| 307 | ||||
| 308 | page = read_cache_page(inode->i_mapping, desc->page_index, | |||
| 309 | (filler_t *)nfs_readdir_filler, desc); | |||
| 0 | 0 | - | 310 | if (IS_ERR(page)) { |
| 311 | status = PTR_ERR(page); | |||
| 0 | - | 312 | goto out; | |
| 313 | } | |||
| 0 | 0 | - | 314 | if (!PageUptodate(page)) |
| 0 | 0 | - | 314 | ternary-?: __builtin_constant_p ( 3 ) |
| 0 | - | 315 | goto read_error; | |
| 316 | ||||
| 317 | /* NOTE: Someone else may have changed the READDIRPLUS flag */ | |||
| 318 | desc->page = page; | |||
| 319 | desc->ptr = kmap(page); /* matching kunmap in nfs_do_filldir */ | |||
| 0 | 0 | - | 320 | if (*desc->dir_cookie != 0) |
| 321 | status = find_dirent(desc); | |||
| 322 | else | |||
| 323 | status = find_dirent_index(desc); | |||
| 0 | 0 | - | 324 | if (status < 0) |
| 325 | dir_page_release(desc); | |||
| 326 | out: | |||
| 327 | dfprintk(VFS, "NFS: find_dirent_page() returns %d\n", status); | |||
| 0 | 0 | - | 327 | if (__builtin_expect ( ! ! ( nfs_debug & 0x0.. |
| 0 | 0 | - | 327 | do-while (0) |
| 0 | - | 328 | return status; | |
| 329 | read_error: | |||
| 330 | page_cache_release(page); | |||
| 0 | - | 331 | return -EIO; | |
| 332 | } | |||
| 333 | ||||
| 334 | /* | |||
| 335 | * Recurse through the page cache pages, and return a | |||
| 336 | * filled nfs_entry structure of the next directory entry if possible. | |||
| 337 | * | |||
| 338 | * The target for the search is '*desc->dir_cookie' if non-0, | |||
| 339 | * 'desc->file->f_pos' otherwise | |||
| 340 | */ | |||
| 341 | static inline | |||
| 0 | 0 | - | 342 | int readdir_search_pagecache(nfs_readdir_descriptor_t *desc) |
| 343 | { | |||
| 344 | int loop_count = 0; | |||
| 345 | int res; | |||
| 346 | ||||
| 347 | /* Always search-by-index from the beginning of the cache */ | |||
| 0 | 0 | - | 348 | if (*desc->dir_cookie == 0) { |
| 349 | dfprintk(VFS, "NFS: readdir_search_pagecache() searching for offset %Ld\n", (long long)desc->file->f_pos); | |||
| 0 | 0 | - | 349 | if (__builtin_expect ( ! ! ( nfs_debug & 0.. |
| 0 | 0 | - | 349 | do-while (0) |
| 350 | desc->page_index = 0; | |||
| 351 | desc->entry->cookie = desc->entry->prev_cookie = 0; | |||
| 352 | desc->entry->eof = 0; | |||
| 353 | desc->current_index = 0; | |||
| 354 | } else | |||
| 355 | dfprintk(VFS, "NFS: readdir_search_pagecache() searching for cookie %Lu\n", (unsigned long long)*desc->dir_cookie); | |||
| 0 | 0 | - | 355 | if (__builtin_expect ( ! ! ( nfs_debug & 0.. |
| 0 | 0 | - | 355 | do-while (0) |
| 356 | ||||
| 0 | 0 | - | 357 | for (;;) { |
| 358 | res = find_dirent_page(desc); | |||
| 0 | 0 | - | 359 | if (res != -EAGAIN) |
| 0 | - | 360 | break; | |
| 361 | /* Align to beginning of next page */ | |||
| 362 | desc->page_index ++; | |||
| 0 | 0 | - | 363 | if (loop_count++ > 200) { |
| 364 | loop_count = 0; | |||
| 365 | schedule(); | |||
| 366 | } | |||
| 367 | } | |||
| 368 | dfprintk(VFS, "NFS: readdir_search_pagecache() returned %d\n", res); | |||
| 0 | 0 | - | 368 | if (__builtin_expect ( ! ! ( nfs_debug & 0x0.. |
| 0 | 0 | - | 368 | do-while (0) |
| 0 | - | 369 | return res; | |
| 370 | } | |||
| 371 | ||||
| 0 | 0 | - | 372 | static inline unsigned int dt_type(struct inode *inode) |
| 373 | { | |||
| 0 | - | 374 | return (inode->i_mode >> 12) & 15; | |
| 375 | } | |||
| 376 | ||||
| 377 | static struct dentry *nfs_readdir_lookup(nfs_readdir_descriptor_t *desc); | |||
| 378 | ||||
| 379 | /* | |||
| 380 | * Once we've found the start of the dirent within a page: fill 'er up... | |||
| 381 | */ | |||
| 382 | static | |||
| 0 | 0 | - | 383 | int nfs_do_filldir(nfs_readdir_descriptor_t *desc, void *dirent, |
| 384 | filldir_t filldir) | |||
| 385 | { | |||
| 386 | struct file *file = desc->file; | |||
| 387 | struct nfs_entry *entry = desc->entry; | |||
| 388 | struct dentry *dentry = NULL; | |||
| 389 | unsigned long fileid; | |||
| 390 | int loop_count = 0, | |||
| 391 | res; | |||
| 392 | ||||
| 393 | dfprintk(VFS, "NFS: nfs_do_filldir() filling starting @ cookie %Lu\n", (long long)entry->cookie); | |||
| 0 | 0 | - | 393 | if (__builtin_expect ( ! ! ( nfs_debug & 0x0.. |
| 0 | 0 | - | 393 | do-while (0) |
| 394 | ||||
| 0 | 0 | - | 395 | for(;;) { |
| 396 | unsigned d_type = DT_UNKNOWN; | |||
| 397 | /* Note: entry->prev_cookie contains the cookie for | |||
| 398 | * retrieving the current dirent on the server */ | |||
| 399 | fileid = nfs_fileid_to_ino_t(entry->ino); | |||
| 400 | ||||
| 401 | /* Get a dentry if we have one */ | |||
| 0 | 0 | - | 402 | if (dentry != NULL) |
| 403 | dput(dentry); | |||
| 404 | dentry = nfs_readdir_lookup(desc); | |||
| 405 | ||||
| 406 | /* Use readdirplus info */ | |||
| 0 | 0 | - | 407 | if (dentry != NULL && dentry->d_inode != NULL) { |
| 0 | - | 407 | T && T | |
| 0 | - | 407 | T && F | |
| 0 | - | 407 | F && _ | |
| 408 | d_type = dt_type(dentry->d_inode); | |||
| 409 | fileid = dentry->d_inode->i_ino; | |||
| 410 | } | |||
| 411 | ||||
| 412 | res = filldir(dirent, entry->name, entry->len, | |||
| 413 | file->f_pos, fileid, d_type); | |||
| 0 | 0 | - | 414 | if (res < 0) |
| 0 | - | 415 | break; | |
| 416 | file->f_pos++; | |||
| 417 | *desc->dir_cookie = entry->cookie; | |||
| 0 | 0 | - | 418 | if (dir_decode(desc) != 0) { |
| 419 | desc->page_index ++; | |||
| 0 | - | 420 | break; | |
| 421 | } | |||
| 0 | 0 | - | 422 | if (loop_count++ > 200) { |
| 423 | loop_count = 0; | |||
| 424 | schedule(); | |||
| 425 | } | |||
| 426 | } | |||
| 427 | dir_page_release(desc); | |||
| 0 | 0 | - | 428 | if (dentry != NULL) |
| 429 | dput(dentry); | |||
| 430 | dfprintk(VFS, "NFS: nfs_do_filldir() filling ended @ cookie %Lu; returning = %d\n", (unsigned long long)*desc->dir_cookie, res); | |||
| 0 | 0 | - | 430 | if (__builtin_expect ( ! ! ( nfs_debug & 0x0.. |
| 0 | 0 | - | 430 | do-while (0) |
| 0 | - | 431 | return res; | |
| 432 | } | |||
| 433 | ||||
| 434 | /* | |||
| 435 | * If we cannot find a cookie in our cache, we suspect that this is | |||
| 436 | * because it points to a deleted file, so we ask the server to return | |||
| 437 | * whatever it thinks is the next entry. We then feed this to filldir. | |||
| 438 | * If all goes well, we should then be able to find our way round the | |||
| 439 | * cache on the next call to readdir_search_pagecache(); | |||
| 440 | * | |||
| 441 | * NOTE: we cannot add the anonymous page to the pagecache because | |||
| 442 | * the data it contains might not be page aligned. Besides, | |||
| 443 | * we should already have a complete representation of the | |||
| 444 | * directory in the page cache by the time we get here. | |||
| 445 | */ | |||
| 446 | static inline | |||
| 0 | 0 | - | 447 | int uncached_readdir(nfs_readdir_descriptor_t *desc, void *dirent, |
| 448 | filldir_t filldir) | |||
| 449 | { | |||
| 450 | struct file *file = desc->file; | |||
| 451 | struct inode *inode = file->f_dentry->d_inode; | |||
| 452 | struct rpc_cred *cred = nfs_file_cred(file); | |||
| 453 | struct page *page = NULL; | |||
| 454 | int status; | |||
| 455 | ||||
| 456 | dfprintk(VFS, "NFS: uncached_readdir() searching for cookie %Lu\n", (unsigned long long)*desc->dir_cookie); | |||
| 0 | 0 | - | 456 | if (__builtin_expect ( ! ! ( nfs_debug & 0x0.. |
| 0 | 0 | - | 456 | do-while (0) |
| 457 | ||||
| 458 | page = alloc_page(GFP_HIGHUSER); | |||
| 0 | 0 | - | 459 | if (!page) { |
| 460 | status = -ENOMEM; | |||
| 0 | - | 461 | goto out; | |
| 462 | } | |||
| 463 | desc->error = NFS_PROTO(inode)->readdir(file->f_dentry, cred, *desc->dir_cookie, | |||
| 464 | page, | |||
| 465 | NFS_SERVER(inode)->dtsize, | |||
| 466 | desc->plus); | |||
| 467 | spin_lock(&inode->i_lock); | |||
| 467 | do | |||
| 0 | 0 | - | 467 | do-while (0) |
| 0 | 0 | - | 467 | do-while (0) |
| 468 | NFS_I(inode)->cache_validity |= NFS_INO_INVALID_ATIME; | |||
| 469 | spin_unlock(&inode->i_lock); | |||
| 469 | do | |||
| 0 | 0 | - | 469 | do-while (0) |
| 0 | 0 | - | 469 | do-while (0) |
| 470 | desc->page = page; | |||
| 471 | desc->ptr = kmap(page); /* matching kunmap in nfs_do_filldir */ | |||
| 0 | 0 | - | 472 | if (desc->error >= 0) { |
| 0 | 0 | - | 473 | if ((status = dir_decode(desc)) == 0) |
| 474 | desc->entry->prev_cookie = *desc->dir_cookie; | |||
| 475 | } else | |||
| 476 | status = -EIO; | |||
| 0 | 0 | - | 477 | if (status < 0) |
| 0 | - | 478< | ||