diff options
Diffstat (limited to 'fs/nfs/dir.c')
| -rw-r--r-- | fs/nfs/dir.c | 1015 |
1 files changed, 618 insertions, 397 deletions
diff --git a/fs/nfs/dir.c b/fs/nfs/dir.c index e257172d438..07ac3847e56 100644 --- a/fs/nfs/dir.c +++ b/fs/nfs/dir.c | |||
| @@ -33,11 +33,12 @@ | |||
| 33 | #include <linux/namei.h> | 33 | #include <linux/namei.h> |
| 34 | #include <linux/mount.h> | 34 | #include <linux/mount.h> |
| 35 | #include <linux/sched.h> | 35 | #include <linux/sched.h> |
| 36 | #include <linux/vmalloc.h> | ||
| 36 | 37 | ||
| 37 | #include "nfs4_fs.h" | ||
| 38 | #include "delegation.h" | 38 | #include "delegation.h" |
| 39 | #include "iostat.h" | 39 | #include "iostat.h" |
| 40 | #include "internal.h" | 40 | #include "internal.h" |
| 41 | #include "fscache.h" | ||
| 41 | 42 | ||
| 42 | /* #define NFS_DEBUG_VERBOSE 1 */ | 43 | /* #define NFS_DEBUG_VERBOSE 1 */ |
| 43 | 44 | ||
| @@ -55,6 +56,7 @@ static int nfs_rename(struct inode *, struct dentry *, | |||
| 55 | struct inode *, struct dentry *); | 56 | struct inode *, struct dentry *); |
| 56 | static int nfs_fsync_dir(struct file *, int); | 57 | static int nfs_fsync_dir(struct file *, int); |
| 57 | static loff_t nfs_llseek_dir(struct file *, loff_t, int); | 58 | static loff_t nfs_llseek_dir(struct file *, loff_t, int); |
| 59 | static int nfs_readdir_clear_array(struct page*, gfp_t); | ||
| 58 | 60 | ||
| 59 | const struct file_operations nfs_dir_operations = { | 61 | const struct file_operations nfs_dir_operations = { |
| 60 | .llseek = nfs_llseek_dir, | 62 | .llseek = nfs_llseek_dir, |
| @@ -80,6 +82,10 @@ const struct inode_operations nfs_dir_inode_operations = { | |||
| 80 | .setattr = nfs_setattr, | 82 | .setattr = nfs_setattr, |
| 81 | }; | 83 | }; |
| 82 | 84 | ||
| 85 | const struct address_space_operations nfs_dir_addr_space_ops = { | ||
| 86 | .releasepage = nfs_readdir_clear_array, | ||
| 87 | }; | ||
| 88 | |||
| 83 | #ifdef CONFIG_NFS_V3 | 89 | #ifdef CONFIG_NFS_V3 |
| 84 | const struct inode_operations nfs3_dir_inode_operations = { | 90 | const struct inode_operations nfs3_dir_inode_operations = { |
| 85 | .create = nfs_create, | 91 | .create = nfs_create, |
| @@ -104,8 +110,9 @@ const struct inode_operations nfs3_dir_inode_operations = { | |||
| 104 | #ifdef CONFIG_NFS_V4 | 110 | #ifdef CONFIG_NFS_V4 |
| 105 | 111 | ||
| 106 | static struct dentry *nfs_atomic_lookup(struct inode *, struct dentry *, struct nameidata *); | 112 | static struct dentry *nfs_atomic_lookup(struct inode *, struct dentry *, struct nameidata *); |
| 113 | static int nfs_open_create(struct inode *dir, struct dentry *dentry, int mode, struct nameidata *nd); | ||
| 107 | const struct inode_operations nfs4_dir_inode_operations = { | 114 | const struct inode_operations nfs4_dir_inode_operations = { |
| 108 | .create = nfs_create, | 115 | .create = nfs_open_create, |
| 109 | .lookup = nfs_atomic_lookup, | 116 | .lookup = nfs_atomic_lookup, |
| 110 | .link = nfs_link, | 117 | .link = nfs_link, |
| 111 | .unlink = nfs_unlink, | 118 | .unlink = nfs_unlink, |
| @@ -150,51 +157,197 @@ nfs_opendir(struct inode *inode, struct file *filp) | |||
| 150 | return res; | 157 | return res; |
| 151 | } | 158 | } |
| 152 | 159 | ||
| 153 | typedef __be32 * (*decode_dirent_t)(__be32 *, struct nfs_entry *, int); | 160 | struct nfs_cache_array_entry { |
| 161 | u64 cookie; | ||
| 162 | u64 ino; | ||
| 163 | struct qstr string; | ||
| 164 | }; | ||
| 165 | |||
| 166 | struct nfs_cache_array { | ||
| 167 | unsigned int size; | ||
| 168 | int eof_index; | ||
| 169 | u64 last_cookie; | ||
| 170 | struct nfs_cache_array_entry array[0]; | ||
| 171 | }; | ||
| 172 | |||
| 173 | #define MAX_READDIR_ARRAY ((PAGE_SIZE - sizeof(struct nfs_cache_array)) / sizeof(struct nfs_cache_array_entry)) | ||
| 174 | |||
| 175 | typedef __be32 * (*decode_dirent_t)(struct xdr_stream *, struct nfs_entry *, struct nfs_server *, int); | ||
| 154 | typedef struct { | 176 | typedef struct { |
| 155 | struct file *file; | 177 | struct file *file; |
| 156 | struct page *page; | 178 | struct page *page; |
| 157 | unsigned long page_index; | 179 | unsigned long page_index; |
| 158 | __be32 *ptr; | ||
| 159 | u64 *dir_cookie; | 180 | u64 *dir_cookie; |
| 160 | loff_t current_index; | 181 | loff_t current_index; |
| 161 | struct nfs_entry *entry; | ||
| 162 | decode_dirent_t decode; | 182 | decode_dirent_t decode; |
| 163 | int plus; | 183 | |
| 164 | unsigned long timestamp; | 184 | unsigned long timestamp; |
| 165 | unsigned long gencount; | 185 | unsigned long gencount; |
| 166 | int timestamp_valid; | 186 | unsigned int cache_entry_index; |
| 187 | unsigned int plus:1; | ||
| 188 | unsigned int eof:1; | ||
| 167 | } nfs_readdir_descriptor_t; | 189 | } nfs_readdir_descriptor_t; |
| 168 | 190 | ||
| 169 | /* Now we cache directories properly, by stuffing the dirent | 191 | /* |
| 170 | * data directly in the page cache. | 192 | * The caller is responsible for calling nfs_readdir_release_array(page) |
| 171 | * | ||
| 172 | * Inode invalidation due to refresh etc. takes care of | ||
| 173 | * _everything_, no sloppy entry flushing logic, no extraneous | ||
| 174 | * copying, network direct to page cache, the way it was meant | ||
| 175 | * to be. | ||
| 176 | * | ||
| 177 | * NOTE: Dirent information verification is done always by the | ||
| 178 | * page-in of the RPC reply, nowhere else, this simplies | ||
| 179 | * things substantially. | ||
| 180 | */ | 193 | */ |
| 181 | static | 194 | static |
| 182 | int nfs_readdir_filler(nfs_readdir_descriptor_t *desc, struct page *page) | 195 | struct nfs_cache_array *nfs_readdir_get_array(struct page *page) |
| 196 | { | ||
| 197 | if (page == NULL) | ||
| 198 | return ERR_PTR(-EIO); | ||
| 199 | return (struct nfs_cache_array *)kmap(page); | ||
| 200 | } | ||
| 201 | |||
| 202 | static | ||
| 203 | void nfs_readdir_release_array(struct page *page) | ||
| 204 | { | ||
| 205 | kunmap(page); | ||
| 206 | } | ||
| 207 | |||
| 208 | /* | ||
| 209 | * we are freeing strings created by nfs_add_to_readdir_array() | ||
| 210 | */ | ||
| 211 | static | ||
| 212 | int nfs_readdir_clear_array(struct page *page, gfp_t mask) | ||
| 213 | { | ||
| 214 | struct nfs_cache_array *array = nfs_readdir_get_array(page); | ||
| 215 | int i; | ||
| 216 | for (i = 0; i < array->size; i++) | ||
| 217 | kfree(array->array[i].string.name); | ||
| 218 | nfs_readdir_release_array(page); | ||
| 219 | return 0; | ||
| 220 | } | ||
| 221 | |||
| 222 | /* | ||
| 223 | * the caller is responsible for freeing qstr.name | ||
| 224 | * when called by nfs_readdir_add_to_array, the strings will be freed in | ||
| 225 | * nfs_clear_readdir_array() | ||
| 226 | */ | ||
| 227 | static | ||
| 228 | int nfs_readdir_make_qstr(struct qstr *string, const char *name, unsigned int len) | ||
| 229 | { | ||
| 230 | string->len = len; | ||
| 231 | string->name = kmemdup(name, len, GFP_KERNEL); | ||
| 232 | if (string->name == NULL) | ||
| 233 | return -ENOMEM; | ||
| 234 | string->hash = full_name_hash(name, len); | ||
| 235 | return 0; | ||
| 236 | } | ||
| 237 | |||
| 238 | static | ||
| 239 | int nfs_readdir_add_to_array(struct nfs_entry *entry, struct page *page) | ||
| 240 | { | ||
| 241 | struct nfs_cache_array *array = nfs_readdir_get_array(page); | ||
| 242 | struct nfs_cache_array_entry *cache_entry; | ||
| 243 | int ret; | ||
| 244 | |||
| 245 | if (IS_ERR(array)) | ||
| 246 | return PTR_ERR(array); | ||
| 247 | ret = -EIO; | ||
| 248 | if (array->size >= MAX_READDIR_ARRAY) | ||
| 249 | goto out; | ||
| 250 | |||
| 251 | cache_entry = &array->array[array->size]; | ||
| 252 | cache_entry->cookie = entry->prev_cookie; | ||
| 253 | cache_entry->ino = entry->ino; | ||
| 254 | ret = nfs_readdir_make_qstr(&cache_entry->string, entry->name, entry->len); | ||
| 255 | if (ret) | ||
| 256 | goto out; | ||
| 257 | array->last_cookie = entry->cookie; | ||
| 258 | if (entry->eof == 1) | ||
| 259 | array->eof_index = array->size; | ||
| 260 | array->size++; | ||
| 261 | out: | ||
| 262 | nfs_readdir_release_array(page); | ||
| 263 | return ret; | ||
| 264 | } | ||
| 265 | |||
| 266 | static | ||
| 267 | int nfs_readdir_search_for_pos(struct nfs_cache_array *array, nfs_readdir_descriptor_t *desc) | ||
| 268 | { | ||
| 269 | loff_t diff = desc->file->f_pos - desc->current_index; | ||
| 270 | unsigned int index; | ||
| 271 | |||
| 272 | if (diff < 0) | ||
| 273 | goto out_eof; | ||
| 274 | if (diff >= array->size) { | ||
| 275 | if (array->eof_index > 0) | ||
| 276 | goto out_eof; | ||
| 277 | desc->current_index += array->size; | ||
| 278 | return -EAGAIN; | ||
| 279 | } | ||
| 280 | |||
| 281 | index = (unsigned int)diff; | ||
| 282 | *desc->dir_cookie = array->array[index].cookie; | ||
| 283 | desc->cache_entry_index = index; | ||
| 284 | if (index == array->eof_index) | ||
| 285 | desc->eof = 1; | ||
| 286 | return 0; | ||
| 287 | out_eof: | ||
| 288 | desc->eof = 1; | ||
| 289 | return -EBADCOOKIE; | ||
| 290 | } | ||
| 291 | |||
| 292 | static | ||
| 293 | int nfs_readdir_search_for_cookie(struct nfs_cache_array *array, nfs_readdir_descriptor_t *desc) | ||
| 294 | { | ||
| 295 | int i; | ||
| 296 | int status = -EAGAIN; | ||
| 297 | |||
| 298 | for (i = 0; i < array->size; i++) { | ||
| 299 | if (i == array->eof_index) { | ||
| 300 | desc->eof = 1; | ||
| 301 | status = -EBADCOOKIE; | ||
| 302 | } | ||
| 303 | if (array->array[i].cookie == *desc->dir_cookie) { | ||
| 304 | desc->cache_entry_index = i; | ||
| 305 | status = 0; | ||
| 306 | break; | ||
| 307 | } | ||
| 308 | } | ||
| 309 | |||
| 310 | return status; | ||
| 311 | } | ||
| 312 | |||
| 313 | static | ||
| 314 | int nfs_readdir_search_array(nfs_readdir_descriptor_t *desc) | ||
| 315 | { | ||
| 316 | struct nfs_cache_array *array; | ||
| 317 | int status = -EBADCOOKIE; | ||
| 318 | |||
| 319 | if (desc->dir_cookie == NULL) | ||
| 320 | goto out; | ||
| 321 | |||
| 322 | array = nfs_readdir_get_array(desc->page); | ||
| 323 | if (IS_ERR(array)) { | ||
| 324 | status = PTR_ERR(array); | ||
| 325 | goto out; | ||
| 326 | } | ||
| 327 | |||
| 328 | if (*desc->dir_cookie == 0) | ||
| 329 | status = nfs_readdir_search_for_pos(array, desc); | ||
| 330 | else | ||
| 331 | status = nfs_readdir_search_for_cookie(array, desc); | ||
| 332 | |||
| 333 | nfs_readdir_release_array(desc->page); | ||
| 334 | out: | ||
| 335 | return status; | ||
| 336 | } | ||
| 337 | |||
| 338 | /* Fill a page with xdr information before transferring to the cache page */ | ||
| 339 | static | ||
| 340 | int nfs_readdir_xdr_filler(struct page **pages, nfs_readdir_descriptor_t *desc, | ||
| 341 | struct nfs_entry *entry, struct file *file, struct inode *inode) | ||
| 183 | { | 342 | { |
| 184 | struct file *file = desc->file; | ||
| 185 | struct inode *inode = file->f_path.dentry->d_inode; | ||
| 186 | struct rpc_cred *cred = nfs_file_cred(file); | 343 | struct rpc_cred *cred = nfs_file_cred(file); |
| 187 | unsigned long timestamp, gencount; | 344 | unsigned long timestamp, gencount; |
| 188 | int error; | 345 | int error; |
| 189 | 346 | ||
| 190 | dfprintk(DIRCACHE, "NFS: %s: reading cookie %Lu into page %lu\n", | ||
| 191 | __func__, (long long)desc->entry->cookie, | ||
| 192 | page->index); | ||
| 193 | |||
| 194 | again: | 347 | again: |
| 195 | timestamp = jiffies; | 348 | timestamp = jiffies; |
| 196 | gencount = nfs_inc_attr_generation_counter(); | 349 | gencount = nfs_inc_attr_generation_counter(); |
| 197 | error = NFS_PROTO(inode)->readdir(file->f_path.dentry, cred, desc->entry->cookie, page, | 350 | error = NFS_PROTO(inode)->readdir(file->f_path.dentry, cred, entry->cookie, pages, |
| 198 | NFS_SERVER(inode)->dtsize, desc->plus); | 351 | NFS_SERVER(inode)->dtsize, desc->plus); |
| 199 | if (error < 0) { | 352 | if (error < 0) { |
| 200 | /* We requested READDIRPLUS, but the server doesn't grok it */ | 353 | /* We requested READDIRPLUS, but the server doesn't grok it */ |
| @@ -208,190 +361,292 @@ int nfs_readdir_filler(nfs_readdir_descriptor_t *desc, struct page *page) | |||
| 208 | } | 361 | } |
| 209 | desc->timestamp = timestamp; | 362 | desc->timestamp = timestamp; |
| 210 | desc->gencount = gencount; | 363 | desc->gencount = gencount; |
| 211 | desc->timestamp_valid = 1; | 364 | error: |
| 212 | SetPageUptodate(page); | 365 | return error; |
| 213 | /* Ensure consistent page alignment of the data. | ||
| 214 | * Note: assumes we have exclusive access to this mapping either | ||
| 215 | * through inode->i_mutex or some other mechanism. | ||
| 216 | */ | ||
| 217 | if (invalidate_inode_pages2_range(inode->i_mapping, page->index + 1, -1) < 0) { | ||
| 218 | /* Should never happen */ | ||
| 219 | nfs_zap_mapping(inode, inode->i_mapping); | ||
| 220 | } | ||
| 221 | unlock_page(page); | ||
| 222 | return 0; | ||
| 223 | error: | ||
| 224 | unlock_page(page); | ||
| 225 | return -EIO; | ||
| 226 | } | 366 | } |
| 227 | 367 | ||
| 228 | static inline | 368 | /* Fill in an entry based on the xdr code stored in desc->page */ |
| 229 | int dir_decode(nfs_readdir_descriptor_t *desc) | 369 | static |
| 370 | int xdr_decode(nfs_readdir_descriptor_t *desc, struct nfs_entry *entry, struct xdr_stream *stream) | ||
| 230 | { | 371 | { |
| 231 | __be32 *p = desc->ptr; | 372 | __be32 *p = desc->decode(stream, entry, NFS_SERVER(desc->file->f_path.dentry->d_inode), desc->plus); |
| 232 | p = desc->decode(p, desc->entry, desc->plus); | ||
| 233 | if (IS_ERR(p)) | 373 | if (IS_ERR(p)) |
| 234 | return PTR_ERR(p); | 374 | return PTR_ERR(p); |
| 235 | desc->ptr = p; | 375 | |
| 236 | if (desc->timestamp_valid) { | 376 | entry->fattr->time_start = desc->timestamp; |
| 237 | desc->entry->fattr->time_start = desc->timestamp; | 377 | entry->fattr->gencount = desc->gencount; |
| 238 | desc->entry->fattr->gencount = desc->gencount; | ||
| 239 | } else | ||
| 240 | desc->entry->fattr->valid &= ~NFS_ATTR_FATTR; | ||
| 241 | return 0; | 378 | return 0; |
| 242 | } | 379 | } |
| 243 | 380 | ||
| 244 | static inline | 381 | static |
| 245 | void dir_page_release(nfs_readdir_descriptor_t *desc) | 382 | int nfs_same_file(struct dentry *dentry, struct nfs_entry *entry) |
| 246 | { | 383 | { |
| 247 | kunmap(desc->page); | 384 | struct nfs_inode *node; |
| 248 | page_cache_release(desc->page); | 385 | if (dentry->d_inode == NULL) |
| 249 | desc->page = NULL; | 386 | goto different; |
| 250 | desc->ptr = NULL; | 387 | node = NFS_I(dentry->d_inode); |
| 388 | if (node->fh.size != entry->fh->size) | ||
| 389 | goto different; | ||
| 390 | if (strncmp(node->fh.data, entry->fh->data, node->fh.size) != 0) | ||
| 391 | goto different; | ||
| 392 | return 1; | ||
| 393 | different: | ||
| 394 | return 0; | ||
| 251 | } | 395 | } |
| 252 | 396 | ||
| 253 | /* | 397 | static |
| 254 | * Given a pointer to a buffer that has already been filled by a call | 398 | void nfs_prime_dcache(struct dentry *parent, struct nfs_entry *entry) |
| 255 | * to readdir, find the next entry with cookie '*desc->dir_cookie'. | ||
| 256 | * | ||
| 257 | * If the end of the buffer has been reached, return -EAGAIN, if not, | ||
| 258 | * return the offset within the buffer of the next entry to be | ||
| 259 | * read. | ||
| 260 | */ | ||
| 261 | static inline | ||
| 262 | int find_dirent(nfs_readdir_descriptor_t *desc) | ||
| 263 | { | 399 | { |
| 264 | struct nfs_entry *entry = desc->entry; | 400 | struct qstr filename = { |
| 265 | int loop_count = 0, | 401 | .len = entry->len, |
| 266 | status; | 402 | .name = entry->name, |
| 403 | }; | ||
| 404 | struct dentry *dentry; | ||
| 405 | struct dentry *alias; | ||
| 406 | struct inode *dir = parent->d_inode; | ||
| 407 | struct inode *inode; | ||
| 267 | 408 | ||
| 268 | while((status = dir_decode(desc)) == 0) { | 409 | if (filename.name[0] == '.') { |
| 269 | dfprintk(DIRCACHE, "NFS: %s: examining cookie %Lu\n", | 410 | if (filename.len == 1) |
| 270 | __func__, (unsigned long long)entry->cookie); | 411 | return; |
| 271 | if (entry->prev_cookie == *desc->dir_cookie) | 412 | if (filename.len == 2 && filename.name[1] == '.') |
| 272 | break; | 413 | return; |
| 273 | if (loop_count++ > 200) { | 414 | } |
| 274 | loop_count = 0; | 415 | filename.hash = full_name_hash(filename.name, filename.len); |
| 275 | schedule(); | 416 | |
| 417 | dentry = d_lookup(parent, &filename); | ||
| 418 | if (dentry != NULL) { | ||
| 419 | if (nfs_same_file(dentry, entry)) { | ||
| 420 | nfs_refresh_inode(dentry->d_inode, entry->fattr); | ||
| 421 | goto out; | ||
| 422 | } else { | ||
| 423 | d_drop(dentry); | ||
| 424 | dput(dentry); | ||
| 276 | } | 425 | } |
| 277 | } | 426 | } |
| 278 | return status; | 427 | |
| 428 | dentry = d_alloc(parent, &filename); | ||
| 429 | if (dentry == NULL) | ||
| 430 | return; | ||
| 431 | |||
| 432 | dentry->d_op = NFS_PROTO(dir)->dentry_ops; | ||
| 433 | inode = nfs_fhget(dentry->d_sb, entry->fh, entry->fattr); | ||
| 434 | if (IS_ERR(inode)) | ||
| 435 | goto out; | ||
| 436 | |||
| 437 | alias = d_materialise_unique(dentry, inode); | ||
| 438 | if (IS_ERR(alias)) | ||
| 439 | goto out; | ||
| 440 | else if (alias) { | ||
| 441 | nfs_set_verifier(alias, nfs_save_change_attribute(dir)); | ||
| 442 | dput(alias); | ||
| 443 | } else | ||
| 444 | nfs_set_verifier(dentry, nfs_save_change_attribute(dir)); | ||
| 445 | |||
| 446 | out: | ||
| 447 | dput(dentry); | ||
| 448 | } | ||
| 449 | |||
| 450 | /* Perform conversion from xdr to cache array */ | ||
| 451 | static | ||
| 452 | void nfs_readdir_page_filler(nfs_readdir_descriptor_t *desc, struct nfs_entry *entry, | ||
| 453 | void *xdr_page, struct page *page, unsigned int buflen) | ||
| 454 | { | ||
| 455 | struct xdr_stream stream; | ||
| 456 | struct xdr_buf buf; | ||
| 457 | __be32 *ptr = xdr_page; | ||
| 458 | int status; | ||
| 459 | struct nfs_cache_array *array; | ||
| 460 | |||
| 461 | buf.head->iov_base = xdr_page; | ||
| 462 | buf.head->iov_len = buflen; | ||
| 463 | buf.tail->iov_len = 0; | ||
| 464 | buf.page_base = 0; | ||
| 465 | buf.page_len = 0; | ||
| 466 | buf.buflen = buf.head->iov_len; | ||
| 467 | buf.len = buf.head->iov_len; | ||
| 468 | |||
| 469 | xdr_init_decode(&stream, &buf, ptr); | ||
| 470 | |||
| 471 | |||
| 472 | do { | ||
| 473 | status = xdr_decode(desc, entry, &stream); | ||
| 474 | if (status != 0) | ||
| 475 | break; | ||
| 476 | |||
| 477 | if (nfs_readdir_add_to_array(entry, page) == -1) | ||
| 478 | break; | ||
| 479 | if (desc->plus == 1) | ||
| 480 | nfs_prime_dcache(desc->file->f_path.dentry, entry); | ||
| 481 | } while (!entry->eof); | ||
| 482 | |||
| 483 | if (status == -EBADCOOKIE && entry->eof) { | ||
| 484 | array = nfs_readdir_get_array(page); | ||
| 485 | array->eof_index = array->size - 1; | ||
| 486 | status = 0; | ||
| 487 | nfs_readdir_release_array(page); | ||
| 488 | } | ||
| 489 | } | ||
| 490 | |||
| 491 | static | ||
| 492 | void nfs_readdir_free_pagearray(struct page **pages, unsigned int npages) | ||
| 493 | { | ||
| 494 | unsigned int i; | ||
| 495 | for (i = 0; i < npages; i++) | ||
| 496 | put_page(pages[i]); | ||
| 497 | } | ||
| 498 | |||
| 499 | static | ||
| 500 | void nfs_readdir_free_large_page(void *ptr, struct page **pages, | ||
| 501 | unsigned int npages) | ||
| 502 | { | ||
| 503 | vm_unmap_ram(ptr, npages); | ||
| 504 | nfs_readdir_free_pagearray(pages, npages); | ||
| 279 | } | 505 | } |
| 280 | 506 | ||
| 281 | /* | 507 | /* |
| 282 | * Given a pointer to a buffer that has already been filled by a call | 508 | * nfs_readdir_large_page will allocate pages that must be freed with a call |
| 283 | * to readdir, find the entry at offset 'desc->file->f_pos'. | 509 | * to nfs_readdir_free_large_page |
| 284 | * | ||
| 285 | * If the end of the buffer has been reached, return -EAGAIN, if not, | ||
| 286 | * return the offset within the buffer of the next entry to be | ||
| 287 | * read. | ||
| 288 | */ | 510 | */ |
| 289 | static inline | 511 | static |
| 290 | int find_dirent_index(nfs_readdir_descriptor_t *desc) | 512 | void *nfs_readdir_large_page(struct page **pages, unsigned int npages) |
| 291 | { | 513 | { |
| 292 | struct nfs_entry *entry = desc->entry; | 514 | void *ptr; |
| 293 | int loop_count = 0, | 515 | unsigned int i; |
| 294 | status; | 516 | |
| 517 | for (i = 0; i < npages; i++) { | ||
| 518 | struct page *page = alloc_page(GFP_KERNEL); | ||
| 519 | if (page == NULL) | ||
| 520 | goto out_freepages; | ||
| 521 | pages[i] = page; | ||
| 522 | } | ||
| 295 | 523 | ||
| 296 | for(;;) { | 524 | ptr = vm_map_ram(pages, npages, 0, PAGE_KERNEL); |
| 297 | status = dir_decode(desc); | 525 | if (!IS_ERR_OR_NULL(ptr)) |
| 298 | if (status) | 526 | return ptr; |
| 299 | break; | 527 | out_freepages: |
| 528 | nfs_readdir_free_pagearray(pages, i); | ||
| 529 | return NULL; | ||
| 530 | } | ||
| 531 | |||
| 532 | static | ||
| 533 | int nfs_readdir_xdr_to_array(nfs_readdir_descriptor_t *desc, struct page *page, struct inode *inode) | ||
| 534 | { | ||
| 535 | struct page *pages[NFS_MAX_READDIR_PAGES]; | ||
| 536 | void *pages_ptr = NULL; | ||
| 537 | struct nfs_entry entry; | ||
| 538 | struct file *file = desc->file; | ||
| 539 | struct nfs_cache_array *array; | ||
| 540 | int status = 0; | ||
| 541 | unsigned int array_size = ARRAY_SIZE(pages); | ||
| 542 | |||
| 543 | entry.prev_cookie = 0; | ||
| 544 | entry.cookie = *desc->dir_cookie; | ||
| 545 | entry.eof = 0; | ||
| 546 | entry.fh = nfs_alloc_fhandle(); | ||
| 547 | entry.fattr = nfs_alloc_fattr(); | ||
| 548 | if (entry.fh == NULL || entry.fattr == NULL) | ||
| 549 | goto out; | ||
| 300 | 550 | ||
| 301 | dfprintk(DIRCACHE, "NFS: found cookie %Lu at index %Ld\n", | 551 | array = nfs_readdir_get_array(page); |
| 302 | (unsigned long long)entry->cookie, desc->current_index); | 552 | memset(array, 0, sizeof(struct nfs_cache_array)); |
| 553 | array->eof_index = -1; | ||
| 303 | 554 | ||
| 304 | if (desc->file->f_pos == desc->current_index) { | 555 | pages_ptr = nfs_readdir_large_page(pages, array_size); |
| 305 | *desc->dir_cookie = entry->cookie; | 556 | if (!pages_ptr) |
| 557 | goto out_release_array; | ||
| 558 | do { | ||
| 559 | status = nfs_readdir_xdr_filler(pages, desc, &entry, file, inode); | ||
| 560 | |||
| 561 | if (status < 0) | ||
| 306 | break; | 562 | break; |
| 307 | } | 563 | nfs_readdir_page_filler(desc, &entry, pages_ptr, page, array_size * PAGE_SIZE); |
| 308 | desc->current_index++; | 564 | } while (array->eof_index < 0 && array->size < MAX_READDIR_ARRAY); |
| 309 | if (loop_count++ > 200) { | 565 | |
| 310 | loop_count = 0; | 566 | nfs_readdir_free_large_page(pages_ptr, pages, array_size); |
| 311 | schedule(); | 567 | out_release_array: |
| 312 | } | 568 | nfs_readdir_release_array(page); |
| 313 | } | 569 | out: |
| 570 | nfs_free_fattr(entry.fattr); | ||
| 571 | nfs_free_fhandle(entry.fh); | ||
| 314 | return status; | 572 | return status; |
| 315 | } | 573 | } |
| 316 | 574 | ||
| 317 | /* | 575 | /* |
| 318 | * Find the given page, and call find_dirent() or find_dirent_index in | 576 | * Now we cache directories properly, by converting xdr information |
| 319 | * order to try to return the next entry. | 577 | * to an array that can be used for lookups later. This results in |
| 578 | * fewer cache pages, since we can store more information on each page. | ||
| 579 | * We only need to convert from xdr once so future lookups are much simpler | ||
| 320 | */ | 580 | */ |
| 321 | static inline | 581 | static |
| 322 | int find_dirent_page(nfs_readdir_descriptor_t *desc) | 582 | int nfs_readdir_filler(nfs_readdir_descriptor_t *desc, struct page* page) |
| 323 | { | 583 | { |
| 324 | struct inode *inode = desc->file->f_path.dentry->d_inode; | 584 | struct inode *inode = desc->file->f_path.dentry->d_inode; |
| 325 | struct page *page; | ||
| 326 | int status; | ||
| 327 | 585 | ||
| 328 | dfprintk(DIRCACHE, "NFS: %s: searching page %ld for target %Lu\n", | 586 | if (nfs_readdir_xdr_to_array(desc, page, inode) < 0) |
| 329 | __func__, desc->page_index, | 587 | goto error; |
| 330 | (long long) *desc->dir_cookie); | 588 | SetPageUptodate(page); |
| 331 | 589 | ||
| 332 | /* If we find the page in the page_cache, we cannot be sure | 590 | if (invalidate_inode_pages2_range(inode->i_mapping, page->index + 1, -1) < 0) { |
| 333 | * how fresh the data is, so we will ignore readdir_plus attributes. | 591 | /* Should never happen */ |
| 334 | */ | 592 | nfs_zap_mapping(inode, inode->i_mapping); |
| 335 | desc->timestamp_valid = 0; | ||
| 336 | page = read_cache_page(inode->i_mapping, desc->page_index, | ||
| 337 | (filler_t *)nfs_readdir_filler, desc); | ||
| 338 | if (IS_ERR(page)) { | ||
| 339 | status = PTR_ERR(page); | ||
| 340 | goto out; | ||
| 341 | } | 593 | } |
| 594 | unlock_page(page); | ||
| 595 | return 0; | ||
| 596 | error: | ||
| 597 | unlock_page(page); | ||
| 598 | return -EIO; | ||
| 599 | } | ||
| 342 | 600 | ||
| 343 | /* NOTE: Someone else may have changed the READDIRPLUS flag */ | 601 | static |
| 344 | desc->page = page; | 602 | void cache_page_release(nfs_readdir_descriptor_t *desc) |
| 345 | desc->ptr = kmap(page); /* matching kunmap in nfs_do_filldir */ | 603 | { |
| 346 | if (*desc->dir_cookie != 0) | 604 | page_cache_release(desc->page); |
| 347 | status = find_dirent(desc); | 605 | desc->page = NULL; |
| 348 | else | 606 | } |
| 349 | status = find_dirent_index(desc); | 607 | |
| 350 | if (status < 0) | 608 | static |
| 351 | dir_page_release(desc); | 609 | struct page *get_cache_page(nfs_readdir_descriptor_t *desc) |
| 352 | out: | 610 | { |
| 353 | dfprintk(DIRCACHE, "NFS: %s: returns %d\n", __func__, status); | 611 | struct page *page; |
| 354 | return status; | 612 | page = read_cache_page(desc->file->f_path.dentry->d_inode->i_mapping, |
| 613 | desc->page_index, (filler_t *)nfs_readdir_filler, desc); | ||
| 614 | if (IS_ERR(page)) | ||
| 615 | desc->eof = 1; | ||
| 616 | return page; | ||
| 355 | } | 617 | } |
| 356 | 618 | ||
| 357 | /* | 619 | /* |
| 358 | * Recurse through the page cache pages, and return a | 620 | * Returns 0 if desc->dir_cookie was found on page desc->page_index |
| 359 | * filled nfs_entry structure of the next directory entry if possible. | ||
| 360 | * | ||
| 361 | * The target for the search is '*desc->dir_cookie' if non-0, | ||
| 362 | * 'desc->file->f_pos' otherwise | ||
| 363 | */ | 621 | */ |
| 622 | static | ||
| 623 | int find_cache_page(nfs_readdir_descriptor_t *desc) | ||
| 624 | { | ||
| 625 | int res; | ||
| 626 | |||
| 627 | desc->page = get_cache_page(desc); | ||
| 628 | if (IS_ERR(desc->page)) | ||
| 629 | return PTR_ERR(desc->page); | ||
| 630 | |||
| 631 | res = nfs_readdir_search_array(desc); | ||
| 632 | if (res == 0) | ||
| 633 | return 0; | ||
| 634 | cache_page_release(desc); | ||
| 635 | return res; | ||
| 636 | } | ||
| 637 | |||
| 638 | /* Search for desc->dir_cookie from the beginning of the page cache */ | ||
| 364 | static inline | 639 | static inline |
| 365 | int readdir_search_pagecache(nfs_readdir_descriptor_t *desc) | 640 | int readdir_search_pagecache(nfs_readdir_descriptor_t *desc) |
| 366 | { | 641 | { |
| 367 | int loop_count = 0; | 642 | int res = -EAGAIN; |
| 368 | int res; | ||
| 369 | |||
| 370 | /* Always search-by-index from the beginning of the cache */ | ||
| 371 | if (*desc->dir_cookie == 0) { | ||
| 372 | dfprintk(DIRCACHE, "NFS: readdir_search_pagecache() searching for offset %Ld\n", | ||
| 373 | (long long)desc->file->f_pos); | ||
| 374 | desc->page_index = 0; | ||
| 375 | desc->entry->cookie = desc->entry->prev_cookie = 0; | ||
| 376 | desc->entry->eof = 0; | ||
| 377 | desc->current_index = 0; | ||
| 378 | } else | ||
| 379 | dfprintk(DIRCACHE, "NFS: readdir_search_pagecache() searching for cookie %Lu\n", | ||
| 380 | (unsigned long long)*desc->dir_cookie); | ||
| 381 | 643 | ||
| 382 | for (;;) { | 644 | while (1) { |
| 383 | res = find_dirent_page(desc); | 645 | res = find_cache_page(desc); |
| 384 | if (res != -EAGAIN) | 646 | if (res != -EAGAIN) |
| 385 | break; | 647 | break; |
| 386 | /* Align to beginning of next page */ | 648 | desc->page_index++; |
| 387 | desc->page_index ++; | ||
| 388 | if (loop_count++ > 200) { | ||
| 389 | loop_count = 0; | ||
| 390 | schedule(); | ||
| 391 | } | ||
| 392 | } | 649 | } |
| 393 | |||
| 394 | dfprintk(DIRCACHE, "NFS: %s: returns %d\n", __func__, res); | ||
| 395 | return res; | 650 | return res; |
| 396 | } | 651 | } |
| 397 | 652 | ||
| @@ -400,8 +655,6 @@ static inline unsigned int dt_type(struct inode *inode) | |||
| 400 | return (inode->i_mode >> 12) & 15; | 655 | return (inode->i_mode >> 12) & 15; |
| 401 | } | 656 | } |
| 402 | 657 | ||
| 403 | static struct dentry *nfs_readdir_lookup(nfs_readdir_descriptor_t *desc); | ||
| 404 | |||
| 405 | /* | 658 | /* |
| 406 | * Once we've found the start of the dirent within a page: fill 'er up... | 659 | * Once we've found the start of the dirent within a page: fill 'er up... |
| 407 | */ | 660 | */ |
| @@ -410,49 +663,36 @@ int nfs_do_filldir(nfs_readdir_descriptor_t *desc, void *dirent, | |||
| 410 | filldir_t filldir) | 663 | filldir_t filldir) |
| 411 | { | 664 | { |
| 412 | struct file *file = desc->file; | 665 | struct file *file = desc->file; |
| 413 | struct nfs_entry *entry = desc->entry; | 666 | int i = 0; |
| 414 | struct dentry *dentry = NULL; | 667 | int res = 0; |
| 415 | u64 fileid; | 668 | struct nfs_cache_array *array = NULL; |
| 416 | int loop_count = 0, | 669 | unsigned int d_type = DT_UNKNOWN; |
| 417 | res; | 670 | struct dentry *dentry = NULL; |
| 418 | |||
| 419 | dfprintk(DIRCACHE, "NFS: nfs_do_filldir() filling starting @ cookie %Lu\n", | ||
| 420 | (unsigned long long)entry->cookie); | ||
| 421 | |||
| 422 | for(;;) { | ||
| 423 | unsigned d_type = DT_UNKNOWN; | ||
| 424 | /* Note: entry->prev_cookie contains the cookie for | ||
| 425 | * retrieving the current dirent on the server */ | ||
| 426 | fileid = entry->ino; | ||
| 427 | |||
| 428 | /* Get a dentry if we have one */ | ||
| 429 | if (dentry != NULL) | ||
| 430 | dput(dentry); | ||
| 431 | dentry = nfs_readdir_lookup(desc); | ||
| 432 | 671 | ||
| 433 | /* Use readdirplus info */ | 672 | array = nfs_readdir_get_array(desc->page); |
| 434 | if (dentry != NULL && dentry->d_inode != NULL) { | ||
| 435 | d_type = dt_type(dentry->d_inode); | ||
| 436 | fileid = NFS_FILEID(dentry->d_inode); | ||
| 437 | } | ||
| 438 | 673 | ||
| 439 | res = filldir(dirent, entry->name, entry->len, | 674 | for (i = desc->cache_entry_index; i < array->size; i++) { |
| 440 | file->f_pos, nfs_compat_user_ino64(fileid), | 675 | d_type = DT_UNKNOWN; |
| 441 | d_type); | 676 | |
| 677 | res = filldir(dirent, array->array[i].string.name, | ||
| 678 | array->array[i].string.len, file->f_pos, | ||
| 679 | nfs_compat_user_ino64(array->array[i].ino), d_type); | ||
| 442 | if (res < 0) | 680 | if (res < 0) |
| 443 | break; | 681 | break; |
| 444 | file->f_pos++; | 682 | file->f_pos++; |
| 445 | *desc->dir_cookie = entry->cookie; | 683 | desc->cache_entry_index = i; |
| 446 | if (dir_decode(desc) != 0) { | 684 | if (i < (array->size-1)) |
| 447 | desc->page_index ++; | 685 | *desc->dir_cookie = array->array[i+1].cookie; |
| 686 | else | ||
| 687 | *desc->dir_cookie = array->last_cookie; | ||
| 688 | if (i == array->eof_index) { | ||
| 689 | desc->eof = 1; | ||
| 448 | break; | 690 | break; |
| 449 | } | 691 | } |
| 450 | if (loop_count++ > 200) { | ||
| 451 | loop_count = 0; | ||
| 452 | schedule(); | ||
| 453 | } | ||
| 454 | } | 692 | } |
| 455 | dir_page_release(desc); | 693 | |
| 694 | nfs_readdir_release_array(desc->page); | ||
| 695 | cache_page_release(desc); | ||
| 456 | if (dentry != NULL) | 696 | if (dentry != NULL) |
| 457 | dput(dentry); | 697 | dput(dentry); |
| 458 | dfprintk(DIRCACHE, "NFS: nfs_do_filldir() filling ended @ cookie %Lu; returning = %d\n", | 698 | dfprintk(DIRCACHE, "NFS: nfs_do_filldir() filling ended @ cookie %Lu; returning = %d\n", |
| @@ -476,12 +716,9 @@ static inline | |||
| 476 | int uncached_readdir(nfs_readdir_descriptor_t *desc, void *dirent, | 716 | int uncached_readdir(nfs_readdir_descriptor_t *desc, void *dirent, |
| 477 | filldir_t filldir) | 717 | filldir_t filldir) |
| 478 | { | 718 | { |
| 479 | struct file *file = desc->file; | ||
| 480 | struct inode *inode = file->f_path.dentry->d_inode; | ||
| 481 | struct rpc_cred *cred = nfs_file_cred(file); | ||
| 482 | struct page *page = NULL; | 719 | struct page *page = NULL; |
| 483 | int status; | 720 | int status; |
| 484 | unsigned long timestamp, gencount; | 721 | struct inode *inode = desc->file->f_path.dentry->d_inode; |
| 485 | 722 | ||
| 486 | dfprintk(DIRCACHE, "NFS: uncached_readdir() searching for cookie %Lu\n", | 723 | dfprintk(DIRCACHE, "NFS: uncached_readdir() searching for cookie %Lu\n", |
| 487 | (unsigned long long)*desc->dir_cookie); | 724 | (unsigned long long)*desc->dir_cookie); |
| @@ -491,38 +728,22 @@ int uncached_readdir(nfs_readdir_descriptor_t *desc, void *dirent, | |||
| 491 | status = -ENOMEM; | 728 | status = -ENOMEM; |
| 492 | goto out; | 729 | goto out; |
| 493 | } | 730 | } |
| 494 | timestamp = jiffies; | 731 | |
| 495 | gencount = nfs_inc_attr_generation_counter(); | 732 | if (nfs_readdir_xdr_to_array(desc, page, inode) == -1) { |
| 496 | status = NFS_PROTO(inode)->readdir(file->f_path.dentry, cred, | ||
| 497 | *desc->dir_cookie, page, | ||
| 498 | NFS_SERVER(inode)->dtsize, | ||
| 499 | desc->plus); | ||
| 500 | desc->page = page; | ||
| 501 | desc->ptr = kmap(page); /* matching kunmap in nfs_do_filldir */ | ||
| 502 | if (status >= 0) { | ||
| 503 | desc->timestamp = timestamp; | ||
| 504 | desc->gencount = gencount; | ||
| 505 | desc->timestamp_valid = 1; | ||
| 506 | if ((status = dir_decode(desc)) == 0) | ||
| 507 | desc->entry->prev_cookie = *desc->dir_cookie; | ||
| 508 | } else | ||
| 509 | status = -EIO; | 733 | status = -EIO; |
| 510 | if (status < 0) | ||
| 511 | goto out_release; | 734 | goto out_release; |
| 735 | } | ||
| 512 | 736 | ||
| 737 | desc->page_index = 0; | ||
| 738 | desc->page = page; | ||
| 513 | status = nfs_do_filldir(desc, dirent, filldir); | 739 | status = nfs_do_filldir(desc, dirent, filldir); |
| 514 | 740 | ||
| 515 | /* Reset read descriptor so it searches the page cache from | ||
| 516 | * the start upon the next call to readdir_search_pagecache() */ | ||
| 517 | desc->page_index = 0; | ||
| 518 | desc->entry->cookie = desc->entry->prev_cookie = 0; | ||
| 519 | desc->entry->eof = 0; | ||
| 520 | out: | 741 | out: |
| 521 | dfprintk(DIRCACHE, "NFS: %s: returns %d\n", | 742 | dfprintk(DIRCACHE, "NFS: %s: returns %d\n", |
| 522 | __func__, status); | 743 | __func__, status); |
| 523 | return status; | 744 | return status; |
| 524 | out_release: | 745 | out_release: |
| 525 | dir_page_release(desc); | 746 | cache_page_release(desc); |
| 526 | goto out; | 747 | goto out; |
| 527 | } | 748 | } |
| 528 | 749 | ||
| @@ -536,7 +757,6 @@ static int nfs_readdir(struct file *filp, void *dirent, filldir_t filldir) | |||
| 536 | struct inode *inode = dentry->d_inode; | 757 | struct inode *inode = dentry->d_inode; |
| 537 | nfs_readdir_descriptor_t my_desc, | 758 | nfs_readdir_descriptor_t my_desc, |
| 538 | *desc = &my_desc; | 759 | *desc = &my_desc; |
| 539 | struct nfs_entry my_entry; | ||
| 540 | int res = -ENOMEM; | 760 | int res = -ENOMEM; |
| 541 | 761 | ||
| 542 | dfprintk(FILE, "NFS: readdir(%s/%s) starting at cookie %llu\n", | 762 | dfprintk(FILE, "NFS: readdir(%s/%s) starting at cookie %llu\n", |
| @@ -557,26 +777,17 @@ static int nfs_readdir(struct file *filp, void *dirent, filldir_t filldir) | |||
| 557 | desc->decode = NFS_PROTO(inode)->decode_dirent; | 777 | desc->decode = NFS_PROTO(inode)->decode_dirent; |
| 558 | desc->plus = NFS_USE_READDIRPLUS(inode); | 778 | desc->plus = NFS_USE_READDIRPLUS(inode); |
| 559 | 779 | ||
| 560 | my_entry.cookie = my_entry.prev_cookie = 0; | ||
| 561 | my_entry.eof = 0; | ||
| 562 | my_entry.fh = nfs_alloc_fhandle(); | ||
| 563 | my_entry.fattr = nfs_alloc_fattr(); | ||
| 564 | if (my_entry.fh == NULL || my_entry.fattr == NULL) | ||
| 565 | goto out_alloc_failed; | ||
| 566 | |||
| 567 | desc->entry = &my_entry; | ||
| 568 | |||
| 569 | nfs_block_sillyrename(dentry); | 780 | nfs_block_sillyrename(dentry); |
| 570 | res = nfs_revalidate_mapping(inode, filp->f_mapping); | 781 | res = nfs_revalidate_mapping(inode, filp->f_mapping); |
| 571 | if (res < 0) | 782 | if (res < 0) |
| 572 | goto out; | 783 | goto out; |
| 573 | 784 | ||
| 574 | while(!desc->entry->eof) { | 785 | while (desc->eof != 1) { |
| 575 | res = readdir_search_pagecache(desc); | 786 | res = readdir_search_pagecache(desc); |
| 576 | 787 | ||
| 577 | if (res == -EBADCOOKIE) { | 788 | if (res == -EBADCOOKIE) { |
| 578 | /* This means either end of directory */ | 789 | /* This means either end of directory */ |
| 579 | if (*desc->dir_cookie && desc->entry->cookie != *desc->dir_cookie) { | 790 | if (*desc->dir_cookie && desc->eof == 0) { |
| 580 | /* Or that the server has 'lost' a cookie */ | 791 | /* Or that the server has 'lost' a cookie */ |
| 581 | res = uncached_readdir(desc, dirent, filldir); | 792 | res = uncached_readdir(desc, dirent, filldir); |
| 582 | if (res >= 0) | 793 | if (res >= 0) |
| @@ -588,8 +799,9 @@ static int nfs_readdir(struct file *filp, void *dirent, filldir_t filldir) | |||
| 588 | if (res == -ETOOSMALL && desc->plus) { | 799 | if (res == -ETOOSMALL && desc->plus) { |
| 589 | clear_bit(NFS_INO_ADVISE_RDPLUS, &NFS_I(inode)->flags); | 800 | clear_bit(NFS_INO_ADVISE_RDPLUS, &NFS_I(inode)->flags); |
| 590 | nfs_zap_caches(inode); | 801 | nfs_zap_caches(inode); |
| 802 | desc->page_index = 0; | ||
| 591 | desc->plus = 0; | 803 | desc->plus = 0; |
| 592 | desc->entry->eof = 0; | 804 | desc->eof = 0; |
| 593 | continue; | 805 | continue; |
| 594 | } | 806 | } |
| 595 | if (res < 0) | 807 | if (res < 0) |
| @@ -605,9 +817,6 @@ out: | |||
| 605 | nfs_unblock_sillyrename(dentry); | 817 | nfs_unblock_sillyrename(dentry); |
| 606 | if (res > 0) | 818 | if (res > 0) |
| 607 | res = 0; | 819 | res = 0; |
| 608 | out_alloc_failed: | ||
| 609 | nfs_free_fattr(my_entry.fattr); | ||
| 610 | nfs_free_fhandle(my_entry.fh); | ||
| 611 | dfprintk(FILE, "NFS: readdir(%s/%s) returns %d\n", | 820 | dfprintk(FILE, "NFS: readdir(%s/%s) returns %d\n", |
| 612 | dentry->d_parent->d_name.name, dentry->d_name.name, | 821 | dentry->d_parent->d_name.name, dentry->d_name.name, |
| 613 | res); | 822 | res); |
| @@ -1029,10 +1238,63 @@ static int is_atomic_open(struct nameidata *nd) | |||
| 1029 | return 1; | 1238 | return 1; |
| 1030 | } | 1239 | } |
| 1031 | 1240 | ||
| 1241 | static struct nfs_open_context *nameidata_to_nfs_open_context(struct dentry *dentry, struct nameidata *nd) | ||
| 1242 | { | ||
| 1243 | struct path path = { | ||
| 1244 | .mnt = nd->path.mnt, | ||
| 1245 | .dentry = dentry, | ||
| 1246 | }; | ||
| 1247 | struct nfs_open_context *ctx; | ||
| 1248 | struct rpc_cred *cred; | ||
| 1249 | fmode_t fmode = nd->intent.open.flags & (FMODE_READ | FMODE_WRITE | FMODE_EXEC); | ||
| 1250 | |||
| 1251 | cred = rpc_lookup_cred(); | ||
| 1252 | if (IS_ERR(cred)) | ||
| 1253 | return ERR_CAST(cred); | ||
| 1254 | ctx = alloc_nfs_open_context(&path, cred, fmode); | ||
| 1255 | put_rpccred(cred); | ||
| 1256 | if (ctx == NULL) | ||
| 1257 | return ERR_PTR(-ENOMEM); | ||
| 1258 | return ctx; | ||
| 1259 | } | ||
| 1260 | |||
| 1261 | static int do_open(struct inode *inode, struct file *filp) | ||
| 1262 | { | ||
| 1263 | nfs_fscache_set_inode_cookie(inode, filp); | ||
| 1264 | return 0; | ||
| 1265 | } | ||
| 1266 | |||
| 1267 | static int nfs_intent_set_file(struct nameidata *nd, struct nfs_open_context *ctx) | ||
| 1268 | { | ||
| 1269 | struct file *filp; | ||
| 1270 | int ret = 0; | ||
| 1271 | |||
| 1272 | /* If the open_intent is for execute, we have an extra check to make */ | ||
| 1273 | if (ctx->mode & FMODE_EXEC) { | ||
| 1274 | ret = nfs_may_open(ctx->path.dentry->d_inode, | ||
| 1275 | ctx->cred, | ||
| 1276 | nd->intent.open.flags); | ||
| 1277 | if (ret < 0) | ||
| 1278 | goto out; | ||
| 1279 | } | ||
| 1280 | filp = lookup_instantiate_filp(nd, ctx->path.dentry, do_open); | ||
| 1281 | if (IS_ERR(filp)) | ||
| 1282 | ret = PTR_ERR(filp); | ||
| 1283 | else | ||
| 1284 | nfs_file_set_open_context(filp, ctx); | ||
| 1285 | out: | ||
| 1286 | put_nfs_open_context(ctx); | ||
| 1287 | return ret; | ||
| 1288 | } | ||
| 1289 | |||
| 1032 | static struct dentry *nfs_atomic_lookup(struct inode *dir, struct dentry *dentry, struct nameidata *nd) | 1290 | static struct dentry *nfs_atomic_lookup(struct inode *dir, struct dentry *dentry, struct nameidata *nd) |
| 1033 | { | 1291 | { |
| 1292 | struct nfs_open_context *ctx; | ||
| 1293 | struct iattr attr; | ||
| 1034 | struct dentry *res = NULL; | 1294 | struct dentry *res = NULL; |
| 1035 | int error; | 1295 | struct inode *inode; |
| 1296 | int open_flags; | ||
| 1297 | int err; | ||
| 1036 | 1298 | ||
| 1037 | dfprintk(VFS, "NFS: atomic_lookup(%s/%ld), %s\n", | 1299 | dfprintk(VFS, "NFS: atomic_lookup(%s/%ld), %s\n", |
| 1038 | dir->i_sb->s_id, dir->i_ino, dentry->d_name.name); | 1300 | dir->i_sb->s_id, dir->i_ino, dentry->d_name.name); |
| @@ -1054,13 +1316,32 @@ static struct dentry *nfs_atomic_lookup(struct inode *dir, struct dentry *dentry | |||
| 1054 | goto out; | 1316 | goto out; |
| 1055 | } | 1317 | } |
| 1056 | 1318 | ||
| 1319 | ctx = nameidata_to_nfs_open_context(dentry, nd); | ||
| 1320 | res = ERR_CAST(ctx); | ||
| 1321 | if (IS_ERR(ctx)) | ||
| 1322 | goto out; | ||
| 1323 | |||
| 1324 | open_flags = nd->intent.open.flags; | ||
| 1325 | if (nd->flags & LOOKUP_CREATE) { | ||
| 1326 | attr.ia_mode = nd->intent.open.create_mode; | ||
| 1327 | attr.ia_valid = ATTR_MODE; | ||
| 1328 | if (!IS_POSIXACL(dir)) | ||
| 1329 | attr.ia_mode &= ~current_umask(); | ||
| 1330 | } else { | ||
| 1331 | open_flags &= ~(O_EXCL | O_CREAT); | ||
| 1332 | attr.ia_valid = 0; | ||
| 1333 | } | ||
| 1334 | |||
| 1057 | /* Open the file on the server */ | 1335 | /* Open the file on the server */ |
| 1058 | res = nfs4_atomic_open(dir, dentry, nd); | 1336 | nfs_block_sillyrename(dentry->d_parent); |
| 1059 | if (IS_ERR(res)) { | 1337 | inode = NFS_PROTO(dir)->open_context(dir, ctx, open_flags, &attr); |
| 1060 | error = PTR_ERR(res); | 1338 | if (IS_ERR(inode)) { |
| 1061 | switch (error) { | 1339 | nfs_unblock_sillyrename(dentry->d_parent); |
| 1340 | put_nfs_open_context(ctx); | ||
| 1341 | switch (PTR_ERR(inode)) { | ||
| 1062 | /* Make a negative dentry */ | 1342 | /* Make a negative dentry */ |
| 1063 | case -ENOENT: | 1343 | case -ENOENT: |
| 1344 | d_add(dentry, NULL); | ||
| 1064 | res = NULL; | 1345 | res = NULL; |
| 1065 | goto out; | 1346 | goto out; |
| 1066 | /* This turned out not to be a regular file */ | 1347 | /* This turned out not to be a regular file */ |
| @@ -1072,11 +1353,25 @@ static struct dentry *nfs_atomic_lookup(struct inode *dir, struct dentry *dentry | |||
| 1072 | goto no_open; | 1353 | goto no_open; |
| 1073 | /* case -EINVAL: */ | 1354 | /* case -EINVAL: */ |
| 1074 | default: | 1355 | default: |
| 1356 | res = ERR_CAST(inode); | ||
| 1075 | goto out; | 1357 | goto out; |
| 1076 | } | 1358 | } |
| 1077 | } else if (res != NULL) | 1359 | } |
| 1360 | res = d_add_unique(dentry, inode); | ||
| 1361 | nfs_unblock_sillyrename(dentry->d_parent); | ||
| 1362 | if (res != NULL) { | ||
| 1363 | dput(ctx->path.dentry); | ||
| 1364 | ctx->path.dentry = dget(res); | ||
| 1078 | dentry = res; | 1365 | dentry = res; |
| 1366 | } | ||
| 1367 | err = nfs_intent_set_file(nd, ctx); | ||
| 1368 | if (err < 0) { | ||
| 1369 | if (res != NULL) | ||
| 1370 | dput(res); | ||
| 1371 | return ERR_PTR(err); | ||
| 1372 | } | ||
| 1079 | out: | 1373 | out: |
| 1374 | nfs_set_verifier(dentry, nfs_save_change_attribute(dir)); | ||
| 1080 | return res; | 1375 | return res; |
| 1081 | no_open: | 1376 | no_open: |
| 1082 | return nfs_lookup(dir, dentry, nd); | 1377 | return nfs_lookup(dir, dentry, nd); |
| @@ -1087,12 +1382,15 @@ static int nfs_open_revalidate(struct dentry *dentry, struct nameidata *nd) | |||
| 1087 | struct dentry *parent = NULL; | 1382 | struct dentry *parent = NULL; |
| 1088 | struct inode *inode = dentry->d_inode; | 1383 | struct inode *inode = dentry->d_inode; |
| 1089 | struct inode *dir; | 1384 | struct inode *dir; |
| 1385 | struct nfs_open_context *ctx; | ||
| 1090 | int openflags, ret = 0; | 1386 | int openflags, ret = 0; |
| 1091 | 1387 | ||
| 1092 | if (!is_atomic_open(nd) || d_mountpoint(dentry)) | 1388 | if (!is_atomic_open(nd) || d_mountpoint(dentry)) |
| 1093 | goto no_open; | 1389 | goto no_open; |
| 1390 | |||
| 1094 | parent = dget_parent(dentry); | 1391 | parent = dget_parent(dentry); |
| 1095 | dir = parent->d_inode; | 1392 | dir = parent->d_inode; |
| 1393 | |||
| 1096 | /* We can't create new files in nfs_open_revalidate(), so we | 1394 | /* We can't create new files in nfs_open_revalidate(), so we |
| 1097 | * optimize away revalidation of negative dentries. | 1395 | * optimize away revalidation of negative dentries. |
| 1098 | */ | 1396 | */ |
| @@ -1112,99 +1410,96 @@ static int nfs_open_revalidate(struct dentry *dentry, struct nameidata *nd) | |||
| 1112 | /* We can't create new files, or truncate existing ones here */ | 1410 | /* We can't create new files, or truncate existing ones here */ |
| 1113 | openflags &= ~(O_CREAT|O_EXCL|O_TRUNC); | 1411 | openflags &= ~(O_CREAT|O_EXCL|O_TRUNC); |
| 1114 | 1412 | ||
| 1413 | ctx = nameidata_to_nfs_open_context(dentry, nd); | ||
| 1414 | ret = PTR_ERR(ctx); | ||
| 1415 | if (IS_ERR(ctx)) | ||
| 1416 | goto out; | ||
| 1115 | /* | 1417 | /* |
| 1116 | * Note: we're not holding inode->i_mutex and so may be racing with | 1418 | * Note: we're not holding inode->i_mutex and so may be racing with |
| 1117 | * operations that change the directory. We therefore save the | 1419 | * operations that change the directory. We therefore save the |
| 1118 | * change attribute *before* we do the RPC call. | 1420 | * change attribute *before* we do the RPC call. |
| 1119 | */ | 1421 | */ |
| 1120 | ret = nfs4_open_revalidate(dir, dentry, openflags, nd); | 1422 | inode = NFS_PROTO(dir)->open_context(dir, ctx, openflags, NULL); |
| 1423 | if (IS_ERR(inode)) { | ||
| 1424 | ret = PTR_ERR(inode); | ||
| 1425 | switch (ret) { | ||
| 1426 | case -EPERM: | ||
| 1427 | case -EACCES: | ||
| 1428 | case -EDQUOT: | ||
| 1429 | case -ENOSPC: | ||
| 1430 | case -EROFS: | ||
| 1431 | goto out_put_ctx; | ||
| 1432 | default: | ||
| 1433 | goto out_drop; | ||
| 1434 | } | ||
| 1435 | } | ||
| 1436 | iput(inode); | ||
| 1437 | if (inode != dentry->d_inode) | ||
| 1438 | goto out_drop; | ||
| 1439 | |||
| 1440 | nfs_set_verifier(dentry, nfs_save_change_attribute(dir)); | ||
| 1441 | ret = nfs_intent_set_file(nd, ctx); | ||
| 1442 | if (ret >= 0) | ||
| 1443 | ret = 1; | ||
| 1121 | out: | 1444 | out: |
| 1122 | dput(parent); | 1445 | dput(parent); |
| 1123 | if (!ret) | ||
| 1124 | d_drop(dentry); | ||
| 1125 | return ret; | 1446 | return ret; |
| 1447 | out_drop: | ||
| 1448 | d_drop(dentry); | ||
| 1449 | ret = 0; | ||
| 1450 | out_put_ctx: | ||
| 1451 | put_nfs_open_context(ctx); | ||
| 1452 | goto out; | ||
| 1453 | |||
| 1126 | no_open_dput: | 1454 | no_open_dput: |
| 1127 | dput(parent); | 1455 | dput(parent); |
| 1128 | no_open: | 1456 | no_open: |
| 1129 | return nfs_lookup_revalidate(dentry, nd); | 1457 | return nfs_lookup_revalidate(dentry, nd); |
| 1130 | } | 1458 | } |
| 1131 | #endif /* CONFIG_NFSV4 */ | ||
| 1132 | 1459 | ||
| 1133 | static struct dentry *nfs_readdir_lookup(nfs_readdir_descriptor_t *desc) | 1460 | static int nfs_open_create(struct inode *dir, struct dentry *dentry, int mode, |
| 1461 | struct nameidata *nd) | ||
| 1134 | { | 1462 | { |
| 1135 | struct dentry *parent = desc->file->f_path.dentry; | 1463 | struct nfs_open_context *ctx = NULL; |
| 1136 | struct inode *dir = parent->d_inode; | 1464 | struct iattr attr; |
| 1137 | struct nfs_entry *entry = desc->entry; | 1465 | int error; |
| 1138 | struct dentry *dentry, *alias; | 1466 | int open_flags = 0; |
| 1139 | struct qstr name = { | ||
| 1140 | .name = entry->name, | ||
| 1141 | .len = entry->len, | ||
| 1142 | }; | ||
| 1143 | struct inode *inode; | ||
| 1144 | unsigned long verf = nfs_save_change_attribute(dir); | ||
| 1145 | 1467 | ||
| 1146 | switch (name.len) { | 1468 | dfprintk(VFS, "NFS: create(%s/%ld), %s\n", |
| 1147 | case 2: | 1469 | dir->i_sb->s_id, dir->i_ino, dentry->d_name.name); |
| 1148 | if (name.name[0] == '.' && name.name[1] == '.') | ||
| 1149 | return dget_parent(parent); | ||
| 1150 | break; | ||
| 1151 | case 1: | ||
| 1152 | if (name.name[0] == '.') | ||
| 1153 | return dget(parent); | ||
| 1154 | } | ||
| 1155 | 1470 | ||
| 1156 | spin_lock(&dir->i_lock); | 1471 | attr.ia_mode = mode; |
| 1157 | if (NFS_I(dir)->cache_validity & NFS_INO_INVALID_DATA) { | 1472 | attr.ia_valid = ATTR_MODE; |
| 1158 | spin_unlock(&dir->i_lock); | ||
| 1159 | return NULL; | ||
| 1160 | } | ||
| 1161 | spin_unlock(&dir->i_lock); | ||
| 1162 | 1473 | ||
| 1163 | name.hash = full_name_hash(name.name, name.len); | 1474 | if ((nd->flags & LOOKUP_CREATE) != 0) { |
| 1164 | dentry = d_lookup(parent, &name); | 1475 | open_flags = nd->intent.open.flags; |
| 1165 | if (dentry != NULL) { | ||
| 1166 | /* Is this a positive dentry that matches the readdir info? */ | ||
| 1167 | if (dentry->d_inode != NULL && | ||
| 1168 | (NFS_FILEID(dentry->d_inode) == entry->ino || | ||
| 1169 | d_mountpoint(dentry))) { | ||
| 1170 | if (!desc->plus || entry->fh->size == 0) | ||
| 1171 | return dentry; | ||
| 1172 | if (nfs_compare_fh(NFS_FH(dentry->d_inode), | ||
| 1173 | entry->fh) == 0) | ||
| 1174 | goto out_renew; | ||
| 1175 | } | ||
| 1176 | /* No, so d_drop to allow one to be created */ | ||
| 1177 | d_drop(dentry); | ||
| 1178 | dput(dentry); | ||
| 1179 | } | ||
| 1180 | if (!desc->plus || !(entry->fattr->valid & NFS_ATTR_FATTR)) | ||
| 1181 | return NULL; | ||
| 1182 | if (name.len > NFS_SERVER(dir)->namelen) | ||
| 1183 | return NULL; | ||
| 1184 | /* Note: caller is already holding the dir->i_mutex! */ | ||
| 1185 | dentry = d_alloc(parent, &name); | ||
| 1186 | if (dentry == NULL) | ||
| 1187 | return NULL; | ||
| 1188 | dentry->d_op = NFS_PROTO(dir)->dentry_ops; | ||
| 1189 | inode = nfs_fhget(dentry->d_sb, entry->fh, entry->fattr); | ||
| 1190 | if (IS_ERR(inode)) { | ||
| 1191 | dput(dentry); | ||
| 1192 | return NULL; | ||
| 1193 | } | ||
| 1194 | 1476 | ||
| 1195 | alias = d_materialise_unique(dentry, inode); | 1477 | ctx = nameidata_to_nfs_open_context(dentry, nd); |
| 1196 | if (alias != NULL) { | 1478 | error = PTR_ERR(ctx); |
| 1197 | dput(dentry); | 1479 | if (IS_ERR(ctx)) |
| 1198 | if (IS_ERR(alias)) | 1480 | goto out_err_drop; |
| 1199 | return NULL; | ||
| 1200 | dentry = alias; | ||
| 1201 | } | 1481 | } |
| 1202 | 1482 | ||
| 1203 | out_renew: | 1483 | error = NFS_PROTO(dir)->create(dir, dentry, &attr, open_flags, ctx); |
| 1204 | nfs_set_verifier(dentry, verf); | 1484 | if (error != 0) |
| 1205 | return dentry; | 1485 | goto out_put_ctx; |
| 1486 | if (ctx != NULL) { | ||
| 1487 | error = nfs_intent_set_file(nd, ctx); | ||
| 1488 | if (error < 0) | ||
| 1489 | goto out_err; | ||
| 1490 | } | ||
| 1491 | return 0; | ||
| 1492 | out_put_ctx: | ||
| 1493 | if (ctx != NULL) | ||
| 1494 | put_nfs_open_context(ctx); | ||
| 1495 | out_err_drop: | ||
| 1496 | d_drop(dentry); | ||
| 1497 | out_err: | ||
| 1498 | return error; | ||
| 1206 | } | 1499 | } |
| 1207 | 1500 | ||
| 1501 | #endif /* CONFIG_NFSV4 */ | ||
| 1502 | |||
| 1208 | /* | 1503 | /* |
| 1209 | * Code common to create, mkdir, and mknod. | 1504 | * Code common to create, mkdir, and mknod. |
| 1210 | */ | 1505 | */ |
| @@ -1258,7 +1553,6 @@ static int nfs_create(struct inode *dir, struct dentry *dentry, int mode, | |||
| 1258 | { | 1553 | { |
| 1259 | struct iattr attr; | 1554 | struct iattr attr; |
| 1260 | int error; | 1555 | int error; |
| 1261 | int open_flags = 0; | ||
| 1262 | 1556 | ||
| 1263 | dfprintk(VFS, "NFS: create(%s/%ld), %s\n", | 1557 | dfprintk(VFS, "NFS: create(%s/%ld), %s\n", |
| 1264 | dir->i_sb->s_id, dir->i_ino, dentry->d_name.name); | 1558 | dir->i_sb->s_id, dir->i_ino, dentry->d_name.name); |
| @@ -1266,10 +1560,7 @@ static int nfs_create(struct inode *dir, struct dentry *dentry, int mode, | |||
| 1266 | attr.ia_mode = mode; | 1560 | attr.ia_mode = mode; |
| 1267 | attr.ia_valid = ATTR_MODE; | 1561 | attr.ia_valid = ATTR_MODE; |
| 1268 | 1562 | ||
| 1269 | if ((nd->flags & LOOKUP_CREATE) != 0) | 1563 | error = NFS_PROTO(dir)->create(dir, dentry, &attr, 0, NULL); |
| 1270 | open_flags = nd->intent.open.flags; | ||
| 1271 | |||
| 1272 | error = NFS_PROTO(dir)->create(dir, dentry, &attr, open_flags, nd); | ||
| 1273 | if (error != 0) | 1564 | if (error != 0) |
| 1274 | goto out_err; | 1565 | goto out_err; |
| 1275 | return 0; | 1566 | return 0; |
| @@ -1351,76 +1642,6 @@ static int nfs_rmdir(struct inode *dir, struct dentry *dentry) | |||
| 1351 | return error; | 1642 | return error; |
| 1352 | } | 1643 | } |
| 1353 | 1644 | ||
| 1354 | static int nfs_sillyrename(struct inode *dir, struct dentry *dentry) | ||
| 1355 | { | ||
| 1356 | static unsigned int sillycounter; | ||
| 1357 | const int fileidsize = sizeof(NFS_FILEID(dentry->d_inode))*2; | ||
| 1358 | const int countersize = sizeof(sillycounter)*2; | ||
| 1359 | const int slen = sizeof(".nfs")+fileidsize+countersize-1; | ||
| 1360 | char silly[slen+1]; | ||
| 1361 | struct qstr qsilly; | ||
| 1362 | struct dentry *sdentry; | ||
| 1363 | int error = -EIO; | ||
| 1364 | |||
| 1365 | dfprintk(VFS, "NFS: silly-rename(%s/%s, ct=%d)\n", | ||
| 1366 | dentry->d_parent->d_name.name, dentry->d_name.name, | ||
| 1367 | atomic_read(&dentry->d_count)); | ||
| 1368 | nfs_inc_stats(dir, NFSIOS_SILLYRENAME); | ||
| 1369 | |||
| 1370 | /* | ||
| 1371 | * We don't allow a dentry to be silly-renamed twice. | ||
| 1372 | */ | ||
| 1373 | error = -EBUSY; | ||
| 1374 | if (dentry->d_flags & DCACHE_NFSFS_RENAMED) | ||
| 1375 | goto out; | ||
| 1376 | |||
| 1377 | sprintf(silly, ".nfs%*.*Lx", | ||
| 1378 | fileidsize, fileidsize, | ||
| 1379 | (unsigned long long)NFS_FILEID(dentry->d_inode)); | ||
| 1380 | |||
| 1381 | /* Return delegation in anticipation of the rename */ | ||
| 1382 | nfs_inode_return_delegation(dentry->d_inode); | ||
| 1383 | |||
| 1384 | sdentry = NULL; | ||
| 1385 | do { | ||
| 1386 | char *suffix = silly + slen - countersize; | ||
| 1387 | |||
| 1388 | dput(sdentry); | ||
| 1389 | sillycounter++; | ||
| 1390 | sprintf(suffix, "%*.*x", countersize, countersize, sillycounter); | ||
| 1391 | |||
| 1392 | dfprintk(VFS, "NFS: trying to rename %s to %s\n", | ||
| 1393 | dentry->d_name.name, silly); | ||
| 1394 | |||
| 1395 | sdentry = lookup_one_len(silly, dentry->d_parent, slen); | ||
| 1396 | /* | ||
| 1397 | * N.B. Better to return EBUSY here ... it could be | ||
| 1398 | * dangerous to delete the file while it's in use. | ||
| 1399 | */ | ||
| 1400 | if (IS_ERR(sdentry)) | ||
| 1401 | goto out; | ||
| 1402 | } while(sdentry->d_inode != NULL); /* need negative lookup */ | ||
| 1403 | |||
| 1404 | qsilly.name = silly; | ||
| 1405 | qsilly.len = strlen(silly); | ||
| 1406 | if (dentry->d_inode) { | ||
| 1407 | error = NFS_PROTO(dir)->rename(dir, &dentry->d_name, | ||
| 1408 | dir, &qsilly); | ||
| 1409 | nfs_mark_for_revalidate(dentry->d_inode); | ||
| 1410 | } else | ||
| 1411 | error = NFS_PROTO(dir)->rename(dir, &dentry->d_name, | ||
| 1412 | dir, &qsilly); | ||
| 1413 | if (!error) { | ||
| 1414 | nfs_set_verifier(dentry, nfs_save_change_attribute(dir)); | ||
| 1415 | d_move(dentry, sdentry); | ||
| 1416 | error = nfs_async_unlink(dir, dentry); | ||
| 1417 | /* If we return 0 we don't unlink */ | ||
| 1418 | } | ||
| 1419 | dput(sdentry); | ||
| 1420 | out: | ||
| 1421 | return error; | ||
| 1422 | } | ||
| 1423 | |||
| 1424 | /* | 1645 | /* |
| 1425 | * Remove a file after making sure there are no pending writes, | 1646 | * Remove a file after making sure there are no pending writes, |
| 1426 | * and after checking that the file has only one user. | 1647 | * and after checking that the file has only one user. |
| @@ -1580,7 +1801,7 @@ nfs_link(struct dentry *old_dentry, struct inode *dir, struct dentry *dentry) | |||
| 1580 | d_drop(dentry); | 1801 | d_drop(dentry); |
| 1581 | error = NFS_PROTO(dir)->link(inode, dir, &dentry->d_name); | 1802 | error = NFS_PROTO(dir)->link(inode, dir, &dentry->d_name); |
| 1582 | if (error == 0) { | 1803 | if (error == 0) { |
| 1583 | atomic_inc(&inode->i_count); | 1804 | ihold(inode); |
| 1584 | d_add(dentry, inode); | 1805 | d_add(dentry, inode); |
| 1585 | } | 1806 | } |
| 1586 | return error; | 1807 | return error; |
| @@ -1711,14 +1932,14 @@ static void nfs_access_free_list(struct list_head *head) | |||
| 1711 | int nfs_access_cache_shrinker(struct shrinker *shrink, int nr_to_scan, gfp_t gfp_mask) | 1932 | int nfs_access_cache_shrinker(struct shrinker *shrink, int nr_to_scan, gfp_t gfp_mask) |
| 1712 | { | 1933 | { |
| 1713 | LIST_HEAD(head); | 1934 | LIST_HEAD(head); |
| 1714 | struct nfs_inode *nfsi; | 1935 | struct nfs_inode *nfsi, *next; |
| 1715 | struct nfs_access_entry *cache; | 1936 | struct nfs_access_entry *cache; |
| 1716 | 1937 | ||
| 1717 | if ((gfp_mask & GFP_KERNEL) != GFP_KERNEL) | 1938 | if ((gfp_mask & GFP_KERNEL) != GFP_KERNEL) |
| 1718 | return (nr_to_scan == 0) ? 0 : -1; | 1939 | return (nr_to_scan == 0) ? 0 : -1; |
| 1719 | 1940 | ||
| 1720 | spin_lock(&nfs_access_lru_lock); | 1941 | spin_lock(&nfs_access_lru_lock); |
| 1721 | list_for_each_entry(nfsi, &nfs_access_lru_list, access_cache_inode_lru) { | 1942 | list_for_each_entry_safe(nfsi, next, &nfs_access_lru_list, access_cache_inode_lru) { |
| 1722 | struct inode *inode; | 1943 | struct inode *inode; |
| 1723 | 1944 | ||
| 1724 | if (nr_to_scan-- == 0) | 1945 | if (nr_to_scan-- == 0) |
