Blame view
fs/nfs/dir.c
59.1 KB
1da177e4c Linux-2.6.12-rc2 |
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 |
/* * linux/fs/nfs/dir.c * * Copyright (C) 1992 Rick Sladkey * * nfs directory handling functions * * 10 Apr 1996 Added silly rename for unlink --okir * 28 Sep 1996 Improved directory cache --okir * 23 Aug 1997 Claus Heine claus@momo.math.rwth-aachen.de * Re-implemented silly rename for unlink, newly implemented * silly rename for nfs_rename() following the suggestions * of Olaf Kirch (okir) found in this file. * Following Linus comments on my original hack, this version * depends only on the dcache stuff and doesn't touch the inode * layer (iput() and friends). * 6 Jun 1999 Cache readdir lookups in the page cache. -DaveM */ #include <linux/time.h> #include <linux/errno.h> #include <linux/stat.h> #include <linux/fcntl.h> #include <linux/string.h> #include <linux/kernel.h> #include <linux/slab.h> #include <linux/mm.h> #include <linux/sunrpc/clnt.h> #include <linux/nfs_fs.h> #include <linux/nfs_mount.h> #include <linux/pagemap.h> |
873101b33 NFS: copy symlink... |
32 |
#include <linux/pagevec.h> |
1da177e4c Linux-2.6.12-rc2 |
33 |
#include <linux/namei.h> |
54ceac451 NFS: Share NFS su... |
34 |
#include <linux/mount.h> |
e8edc6e03 Detach sched.h fr... |
35 |
#include <linux/sched.h> |
04e4bd1c6 nfs: Ignore kmeml... |
36 |
#include <linux/kmemleak.h> |
64c2ce8b7 nfsv4: Switch to ... |
37 |
#include <linux/xattr.h> |
1da177e4c Linux-2.6.12-rc2 |
38 39 |
#include "delegation.h" |
91d5b4702 NFS: add I/O perf... |
40 |
#include "iostat.h" |
4c30d56ed NFS: fs/nfs/dir.c... |
41 |
#include "internal.h" |
cd9a1c0e5 NFSv4: Clean up n... |
42 |
#include "fscache.h" |
1da177e4c Linux-2.6.12-rc2 |
43 |
|
1da177e4c Linux-2.6.12-rc2 |
44 45 46 |
/* #define NFS_DEBUG_VERBOSE 1 */ static int nfs_opendir(struct inode *, struct file *); |
480c2006e NFS: Create nfs_o... |
47 |
static int nfs_closedir(struct inode *, struct file *); |
1da177e4c Linux-2.6.12-rc2 |
48 49 |
static int nfs_readdir(struct file *, void *, filldir_t); static struct dentry *nfs_lookup(struct inode *, struct dentry *, struct nameidata *); |
4acdaf27e switch ->create()... |
50 |
static int nfs_create(struct inode *, struct dentry *, umode_t, struct nameidata *); |
18bb1db3e switch vfs_mkdir(... |
51 |
static int nfs_mkdir(struct inode *, struct dentry *, umode_t); |
1da177e4c Linux-2.6.12-rc2 |
52 53 54 55 |
static int nfs_rmdir(struct inode *, struct dentry *); static int nfs_unlink(struct inode *, struct dentry *); static int nfs_symlink(struct inode *, struct dentry *, const char *); static int nfs_link(struct dentry *, struct inode *, struct dentry *); |
1a67aafb5 switch ->mknod() ... |
56 |
static int nfs_mknod(struct inode *, struct dentry *, umode_t, dev_t); |
1da177e4c Linux-2.6.12-rc2 |
57 58 |
static int nfs_rename(struct inode *, struct dentry *, struct inode *, struct dentry *); |
02c24a821 fs: push i_mutex ... |
59 |
static int nfs_fsync_dir(struct file *, loff_t, loff_t, int); |
f0dd2136d [PATCH] NFS: Clea... |
60 |
static loff_t nfs_llseek_dir(struct file *, loff_t, int); |
11de3b11e NFS: Fix a memory... |
61 |
static void nfs_readdir_clear_array(struct page*); |
1da177e4c Linux-2.6.12-rc2 |
62 |
|
4b6f5d20b [PATCH] Make most... |
63 |
const struct file_operations nfs_dir_operations = { |
f0dd2136d [PATCH] NFS: Clea... |
64 |
.llseek = nfs_llseek_dir, |
1da177e4c Linux-2.6.12-rc2 |
65 66 67 |
.read = generic_read_dir, .readdir = nfs_readdir, .open = nfs_opendir, |
480c2006e NFS: Create nfs_o... |
68 |
.release = nfs_closedir, |
1da177e4c Linux-2.6.12-rc2 |
69 70 |
.fsync = nfs_fsync_dir, }; |
92e1d5be9 [PATCH] mark stru... |
71 |
const struct inode_operations nfs_dir_inode_operations = { |
1da177e4c Linux-2.6.12-rc2 |
72 73 74 75 76 77 78 79 80 81 82 83 84 |
.create = nfs_create, .lookup = nfs_lookup, .link = nfs_link, .unlink = nfs_unlink, .symlink = nfs_symlink, .mkdir = nfs_mkdir, .rmdir = nfs_rmdir, .mknod = nfs_mknod, .rename = nfs_rename, .permission = nfs_permission, .getattr = nfs_getattr, .setattr = nfs_setattr, }; |
11de3b11e NFS: Fix a memory... |
85 86 |
const struct address_space_operations nfs_dir_aops = { .freepage = nfs_readdir_clear_array, |
d1bacf9eb NFS: add readdir ... |
87 |
}; |
b7fa0554c [PATCH] NFS: Add ... |
88 |
#ifdef CONFIG_NFS_V3 |
92e1d5be9 [PATCH] mark stru... |
89 |
const struct inode_operations nfs3_dir_inode_operations = { |
b7fa0554c [PATCH] NFS: Add ... |
90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 |
.create = nfs_create, .lookup = nfs_lookup, .link = nfs_link, .unlink = nfs_unlink, .symlink = nfs_symlink, .mkdir = nfs_mkdir, .rmdir = nfs_rmdir, .mknod = nfs_mknod, .rename = nfs_rename, .permission = nfs_permission, .getattr = nfs_getattr, .setattr = nfs_setattr, .listxattr = nfs3_listxattr, .getxattr = nfs3_getxattr, .setxattr = nfs3_setxattr, .removexattr = nfs3_removexattr, }; #endif /* CONFIG_NFS_V3 */ |
1da177e4c Linux-2.6.12-rc2 |
108 109 110 |
#ifdef CONFIG_NFS_V4 static struct dentry *nfs_atomic_lookup(struct inode *, struct dentry *, struct nameidata *); |
4acdaf27e switch ->create()... |
111 |
static int nfs_open_create(struct inode *dir, struct dentry *dentry, umode_t mode, struct nameidata *nd); |
92e1d5be9 [PATCH] mark stru... |
112 |
const struct inode_operations nfs4_dir_inode_operations = { |
c0204fd2b NFS: Clean up nfs... |
113 |
.create = nfs_open_create, |
1da177e4c Linux-2.6.12-rc2 |
114 115 116 117 118 119 120 121 122 123 124 |
.lookup = nfs_atomic_lookup, .link = nfs_link, .unlink = nfs_unlink, .symlink = nfs_symlink, .mkdir = nfs_mkdir, .rmdir = nfs_rmdir, .mknod = nfs_mknod, .rename = nfs_rename, .permission = nfs_permission, .getattr = nfs_getattr, .setattr = nfs_setattr, |
64c2ce8b7 nfsv4: Switch to ... |
125 126 127 128 |
.getxattr = generic_getxattr, .setxattr = generic_setxattr, .listxattr = generic_listxattr, .removexattr = generic_removexattr, |
1da177e4c Linux-2.6.12-rc2 |
129 130 131 |
}; #endif /* CONFIG_NFS_V4 */ |
0c0308066 NFS: Fix spurious... |
132 |
static struct nfs_open_dir_context *alloc_nfs_open_dir_context(struct inode *dir, struct rpc_cred *cred) |
480c2006e NFS: Create nfs_o... |
133 134 135 136 |
{ struct nfs_open_dir_context *ctx; ctx = kmalloc(sizeof(*ctx), GFP_KERNEL); if (ctx != NULL) { |
8ef2ce3e1 NFS: Detect loops... |
137 |
ctx->duped = 0; |
0c0308066 NFS: Fix spurious... |
138 |
ctx->attr_gencount = NFS_I(dir)->attr_gencount; |
480c2006e NFS: Create nfs_o... |
139 |
ctx->dir_cookie = 0; |
8ef2ce3e1 NFS: Detect loops... |
140 |
ctx->dup_cookie = 0; |
480c2006e NFS: Create nfs_o... |
141 |
ctx->cred = get_rpccred(cred); |
0c0308066 NFS: Fix spurious... |
142 143 144 |
return ctx; } return ERR_PTR(-ENOMEM); |
480c2006e NFS: Create nfs_o... |
145 146 147 148 149 150 151 |
} static void put_nfs_open_dir_context(struct nfs_open_dir_context *ctx) { put_rpccred(ctx->cred); kfree(ctx); } |
1da177e4c Linux-2.6.12-rc2 |
152 153 154 155 156 157 |
/* * Open file */ static int nfs_opendir(struct inode *inode, struct file *filp) { |
480c2006e NFS: Create nfs_o... |
158 159 160 |
int res = 0; struct nfs_open_dir_context *ctx; struct rpc_cred *cred; |
1da177e4c Linux-2.6.12-rc2 |
161 |
|
6da24bc9c NFS: Use NFSDBG_F... |
162 163 |
dfprintk(FILE, "NFS: open dir(%s/%s) ", |
cc0dd2d10 NFS: Make nfs_ope... |
164 165 166 167 |
filp->f_path.dentry->d_parent->d_name.name, filp->f_path.dentry->d_name.name); nfs_inc_stats(inode, NFSIOS_VFSOPEN); |
1e7cb3dc1 NFS: directory tr... |
168 |
|
480c2006e NFS: Create nfs_o... |
169 170 171 |
cred = rpc_lookup_cred(); if (IS_ERR(cred)) return PTR_ERR(cred); |
0c0308066 NFS: Fix spurious... |
172 |
ctx = alloc_nfs_open_dir_context(inode, cred); |
480c2006e NFS: Create nfs_o... |
173 174 175 176 177 |
if (IS_ERR(ctx)) { res = PTR_ERR(ctx); goto out; } filp->private_data = ctx; |
f5a73672d NFS: allow close-... |
178 179 180 181 182 183 184 |
if (filp->f_path.dentry == filp->f_path.mnt->mnt_root) { /* This is a mountpoint, so d_revalidate will never * have been called, so we need to refresh the * inode (for close-open consistency) ourselves. */ __nfs_revalidate_inode(NFS_SERVER(inode), inode); } |
480c2006e NFS: Create nfs_o... |
185 186 |
out: put_rpccred(cred); |
1da177e4c Linux-2.6.12-rc2 |
187 188 |
return res; } |
480c2006e NFS: Create nfs_o... |
189 190 191 192 193 194 |
static int nfs_closedir(struct inode *inode, struct file *filp) { put_nfs_open_dir_context(filp->private_data); return 0; } |
d1bacf9eb NFS: add readdir ... |
195 196 197 198 |
struct nfs_cache_array_entry { u64 cookie; u64 ino; struct qstr string; |
0b26a0bf6 NFS: Ensure we re... |
199 |
unsigned char d_type; |
d1bacf9eb NFS: add readdir ... |
200 201 202 203 204 205 206 207 |
}; struct nfs_cache_array { unsigned int size; int eof_index; u64 last_cookie; struct nfs_cache_array_entry array[0]; }; |
573c4e1ef NFS: Simplify ->d... |
208 |
typedef int (*decode_dirent_t)(struct xdr_stream *, struct nfs_entry *, int); |
1da177e4c Linux-2.6.12-rc2 |
209 210 211 212 |
typedef struct { struct file *file; struct page *page; unsigned long page_index; |
f0dd2136d [PATCH] NFS: Clea... |
213 |
u64 *dir_cookie; |
0aded708d NFS: Ensure we us... |
214 |
u64 last_cookie; |
f0dd2136d [PATCH] NFS: Clea... |
215 |
loff_t current_index; |
1da177e4c Linux-2.6.12-rc2 |
216 |
decode_dirent_t decode; |
d1bacf9eb NFS: add readdir ... |
217 |
|
1f4eab7e7 NFS: Set meaningf... |
218 |
unsigned long timestamp; |
4704f0e27 NFS: Fix the reso... |
219 |
unsigned long gencount; |
d1bacf9eb NFS: add readdir ... |
220 221 222 |
unsigned int cache_entry_index; unsigned int plus:1; unsigned int eof:1; |
1da177e4c Linux-2.6.12-rc2 |
223 |
} nfs_readdir_descriptor_t; |
d1bacf9eb NFS: add readdir ... |
224 225 |
/* * The caller is responsible for calling nfs_readdir_release_array(page) |
1da177e4c Linux-2.6.12-rc2 |
226 227 |
*/ static |
d1bacf9eb NFS: add readdir ... |
228 229 |
struct nfs_cache_array *nfs_readdir_get_array(struct page *page) { |
8cd51a0cc NFS: Fix a couple... |
230 |
void *ptr; |
d1bacf9eb NFS: add readdir ... |
231 232 |
if (page == NULL) return ERR_PTR(-EIO); |
8cd51a0cc NFS: Fix a couple... |
233 234 235 236 |
ptr = kmap(page); if (ptr == NULL) return ERR_PTR(-ENOMEM); return ptr; |
d1bacf9eb NFS: add readdir ... |
237 238 239 240 241 242 243 244 245 246 247 248 |
} static void nfs_readdir_release_array(struct page *page) { kunmap(page); } /* * we are freeing strings created by nfs_add_to_readdir_array() */ static |
11de3b11e NFS: Fix a memory... |
249 |
void nfs_readdir_clear_array(struct page *page) |
d1bacf9eb NFS: add readdir ... |
250 |
{ |
11de3b11e NFS: Fix a memory... |
251 |
struct nfs_cache_array *array; |
d1bacf9eb NFS: add readdir ... |
252 |
int i; |
8cd51a0cc NFS: Fix a couple... |
253 |
|
11de3b11e NFS: Fix a memory... |
254 |
array = kmap_atomic(page, KM_USER0); |
d1bacf9eb NFS: add readdir ... |
255 256 |
for (i = 0; i < array->size; i++) kfree(array->array[i].string.name); |
11de3b11e NFS: Fix a memory... |
257 |
kunmap_atomic(array, KM_USER0); |
d1bacf9eb NFS: add readdir ... |
258 259 260 261 262 263 264 265 |
} /* * the caller is responsible for freeing qstr.name * when called by nfs_readdir_add_to_array, the strings will be freed in * nfs_clear_readdir_array() */ static |
4a201d6e3 NFS: Ensure we ch... |
266 |
int nfs_readdir_make_qstr(struct qstr *string, const char *name, unsigned int len) |
d1bacf9eb NFS: add readdir ... |
267 268 269 |
{ string->len = len; string->name = kmemdup(name, len, GFP_KERNEL); |
4a201d6e3 NFS: Ensure we ch... |
270 271 |
if (string->name == NULL) return -ENOMEM; |
04e4bd1c6 nfs: Ignore kmeml... |
272 273 274 275 276 |
/* * Avoid a kmemleak false positive. The pointer to the name is stored * in a page cache page which kmemleak does not scan. */ kmemleak_not_leak(string->name); |
4a201d6e3 NFS: Ensure we ch... |
277 278 |
string->hash = full_name_hash(name, len); return 0; |
d1bacf9eb NFS: add readdir ... |
279 280 281 282 283 284 |
} static int nfs_readdir_add_to_array(struct nfs_entry *entry, struct page *page) { struct nfs_cache_array *array = nfs_readdir_get_array(page); |
4a201d6e3 NFS: Ensure we ch... |
285 286 |
struct nfs_cache_array_entry *cache_entry; int ret; |
d1bacf9eb NFS: add readdir ... |
287 288 |
if (IS_ERR(array)) return PTR_ERR(array); |
3020093f5 NFS: Correct the ... |
289 290 291 292 |
cache_entry = &array->array[array->size]; /* Check that this entry lies within the page bounds */ |
8cd51a0cc NFS: Fix a couple... |
293 |
ret = -ENOSPC; |
3020093f5 NFS: Correct the ... |
294 |
if ((char *)&cache_entry[1] - (char *)page_address(page) > PAGE_SIZE) |
4a201d6e3 NFS: Ensure we ch... |
295 |
goto out; |
d1bacf9eb NFS: add readdir ... |
296 |
|
4a201d6e3 NFS: Ensure we ch... |
297 298 |
cache_entry->cookie = entry->prev_cookie; cache_entry->ino = entry->ino; |
0b26a0bf6 NFS: Ensure we re... |
299 |
cache_entry->d_type = entry->d_type; |
4a201d6e3 NFS: Ensure we ch... |
300 301 302 |
ret = nfs_readdir_make_qstr(&cache_entry->string, entry->name, entry->len); if (ret) goto out; |
d1bacf9eb NFS: add readdir ... |
303 |
array->last_cookie = entry->cookie; |
8cd51a0cc NFS: Fix a couple... |
304 |
array->size++; |
47c716cbf NFS: Readdir clea... |
305 |
if (entry->eof != 0) |
d1bacf9eb NFS: add readdir ... |
306 |
array->eof_index = array->size; |
4a201d6e3 NFS: Ensure we ch... |
307 |
out: |
d1bacf9eb NFS: add readdir ... |
308 |
nfs_readdir_release_array(page); |
4a201d6e3 NFS: Ensure we ch... |
309 |
return ret; |
d1bacf9eb NFS: add readdir ... |
310 311 312 313 314 315 316 317 318 319 320 |
} static int nfs_readdir_search_for_pos(struct nfs_cache_array *array, nfs_readdir_descriptor_t *desc) { loff_t diff = desc->file->f_pos - desc->current_index; unsigned int index; if (diff < 0) goto out_eof; if (diff >= array->size) { |
8cd51a0cc NFS: Fix a couple... |
321 |
if (array->eof_index >= 0) |
d1bacf9eb NFS: add readdir ... |
322 |
goto out_eof; |
d1bacf9eb NFS: add readdir ... |
323 324 325 326 327 328 |
return -EAGAIN; } index = (unsigned int)diff; *desc->dir_cookie = array->array[index].cookie; desc->cache_entry_index = index; |
d1bacf9eb NFS: add readdir ... |
329 330 331 332 333 334 335 336 337 338 |
return 0; out_eof: desc->eof = 1; return -EBADCOOKIE; } static int nfs_readdir_search_for_cookie(struct nfs_cache_array *array, nfs_readdir_descriptor_t *desc) { int i; |
8ef2ce3e1 NFS: Detect loops... |
339 |
loff_t new_pos; |
d1bacf9eb NFS: add readdir ... |
340 341 342 |
int status = -EAGAIN; for (i = 0; i < array->size; i++) { |
d1bacf9eb NFS: add readdir ... |
343 |
if (array->array[i].cookie == *desc->dir_cookie) { |
0c0308066 NFS: Fix spurious... |
344 345 |
struct nfs_inode *nfsi = NFS_I(desc->file->f_path.dentry->d_inode); struct nfs_open_dir_context *ctx = desc->file->private_data; |
8ef2ce3e1 NFS: Detect loops... |
346 |
new_pos = desc->current_index + i; |
0c0308066 NFS: Fix spurious... |
347 348 349 350 351 352 353 354 355 356 |
if (ctx->attr_gencount != nfsi->attr_gencount || (nfsi->cache_validity & (NFS_INO_INVALID_ATTR|NFS_INO_INVALID_DATA))) { ctx->duped = 0; ctx->attr_gencount = nfsi->attr_gencount; } else if (new_pos < desc->file->f_pos) { if (ctx->duped > 0 && ctx->dup_cookie == *desc->dir_cookie) { if (printk_ratelimit()) { pr_notice("NFS: directory %s/%s contains a readdir loop." "Please contact your server vendor. " |
374e4e3ec Additional readdi... |
357 358 |
"The file: %s has duplicate cookie %llu ", |
0c0308066 NFS: Fix spurious... |
359 360 |
desc->file->f_dentry->d_parent->d_name.name, desc->file->f_dentry->d_name.name, |
374e4e3ec Additional readdi... |
361 |
array->array[i].string.name, |
0c0308066 NFS: Fix spurious... |
362 363 364 365 366 |
*desc->dir_cookie); } status = -ELOOP; goto out; } |
8ef2ce3e1 NFS: Detect loops... |
367 |
ctx->dup_cookie = *desc->dir_cookie; |
0c0308066 NFS: Fix spurious... |
368 |
ctx->duped = -1; |
8ef2ce3e1 NFS: Detect loops... |
369 370 |
} desc->file->f_pos = new_pos; |
d1bacf9eb NFS: add readdir ... |
371 |
desc->cache_entry_index = i; |
47c716cbf NFS: Readdir clea... |
372 |
return 0; |
d1bacf9eb NFS: add readdir ... |
373 374 |
} } |
47c716cbf NFS: Readdir clea... |
375 |
if (array->eof_index >= 0) { |
8cd51a0cc NFS: Fix a couple... |
376 |
status = -EBADCOOKIE; |
18fb5fe40 NFS: nfs_readdir_... |
377 378 |
if (*desc->dir_cookie == array->last_cookie) desc->eof = 1; |
8cd51a0cc NFS: Fix a couple... |
379 |
} |
0c0308066 NFS: Fix spurious... |
380 |
out: |
d1bacf9eb NFS: add readdir ... |
381 382 383 384 385 386 387 |
return status; } static int nfs_readdir_search_array(nfs_readdir_descriptor_t *desc) { struct nfs_cache_array *array; |
47c716cbf NFS: Readdir clea... |
388 |
int status; |
d1bacf9eb NFS: add readdir ... |
389 390 391 392 393 394 395 396 397 398 399 |
array = nfs_readdir_get_array(desc->page); if (IS_ERR(array)) { status = PTR_ERR(array); goto out; } if (*desc->dir_cookie == 0) status = nfs_readdir_search_for_pos(array, desc); else status = nfs_readdir_search_for_cookie(array, desc); |
47c716cbf NFS: Readdir clea... |
400 |
if (status == -EAGAIN) { |
0aded708d NFS: Ensure we us... |
401 |
desc->last_cookie = array->last_cookie; |
e47c085af NFS: Ensure that ... |
402 |
desc->current_index += array->size; |
47c716cbf NFS: Readdir clea... |
403 404 |
desc->page_index++; } |
d1bacf9eb NFS: add readdir ... |
405 406 407 408 409 410 411 |
nfs_readdir_release_array(desc->page); out: return status; } /* Fill a page with xdr information before transferring to the cache page */ static |
56e4ebf87 NFS: readdir with... |
412 |
int nfs_readdir_xdr_filler(struct page **pages, nfs_readdir_descriptor_t *desc, |
d1bacf9eb NFS: add readdir ... |
413 |
struct nfs_entry *entry, struct file *file, struct inode *inode) |
1da177e4c Linux-2.6.12-rc2 |
414 |
{ |
480c2006e NFS: Create nfs_o... |
415 416 |
struct nfs_open_dir_context *ctx = file->private_data; struct rpc_cred *cred = ctx->cred; |
4704f0e27 NFS: Fix the reso... |
417 |
unsigned long timestamp, gencount; |
1da177e4c Linux-2.6.12-rc2 |
418 |
int error; |
1da177e4c Linux-2.6.12-rc2 |
419 420 |
again: timestamp = jiffies; |
4704f0e27 NFS: Fix the reso... |
421 |
gencount = nfs_inc_attr_generation_counter(); |
56e4ebf87 NFS: readdir with... |
422 |
error = NFS_PROTO(inode)->readdir(file->f_path.dentry, cred, entry->cookie, pages, |
1da177e4c Linux-2.6.12-rc2 |
423 424 425 426 427 |
NFS_SERVER(inode)->dtsize, desc->plus); if (error < 0) { /* We requested READDIRPLUS, but the server doesn't grok it */ if (error == -ENOTSUPP && desc->plus) { NFS_SERVER(inode)->caps &= ~NFS_CAP_READDIRPLUS; |
3a10c30ac nfs: obliterate N... |
428 |
clear_bit(NFS_INO_ADVISE_RDPLUS, &NFS_I(inode)->flags); |
1da177e4c Linux-2.6.12-rc2 |
429 430 431 432 433 |
desc->plus = 0; goto again; } goto error; } |
1f4eab7e7 NFS: Set meaningf... |
434 |
desc->timestamp = timestamp; |
4704f0e27 NFS: Fix the reso... |
435 |
desc->gencount = gencount; |
d1bacf9eb NFS: add readdir ... |
436 437 |
error: return error; |
1da177e4c Linux-2.6.12-rc2 |
438 |
} |
573c4e1ef NFS: Simplify ->d... |
439 440 |
static int xdr_decode(nfs_readdir_descriptor_t *desc, struct nfs_entry *entry, struct xdr_stream *xdr) |
1da177e4c Linux-2.6.12-rc2 |
441 |
{ |
573c4e1ef NFS: Simplify ->d... |
442 |
int error; |
1da177e4c Linux-2.6.12-rc2 |
443 |
|
573c4e1ef NFS: Simplify ->d... |
444 445 446 |
error = desc->decode(xdr, entry, desc->plus); if (error) return error; |
d1bacf9eb NFS: add readdir ... |
447 448 449 |
entry->fattr->time_start = desc->timestamp; entry->fattr->gencount = desc->gencount; return 0; |
1da177e4c Linux-2.6.12-rc2 |
450 |
} |
d39ab9de3 NFS: re-add readd... |
451 452 453 |
static int nfs_same_file(struct dentry *dentry, struct nfs_entry *entry) { |
d39ab9de3 NFS: re-add readd... |
454 455 |
if (dentry->d_inode == NULL) goto different; |
37a09f074 NFS: Fix a readdi... |
456 |
if (nfs_compare_fh(entry->fh, NFS_FH(dentry->d_inode)) != 0) |
d39ab9de3 NFS: re-add readd... |
457 458 459 460 461 462 463 464 465 |
goto different; return 1; different: return 0; } static void nfs_prime_dcache(struct dentry *parent, struct nfs_entry *entry) { |
4a201d6e3 NFS: Ensure we ch... |
466 467 468 469 470 471 |
struct qstr filename = { .len = entry->len, .name = entry->name, }; struct dentry *dentry; struct dentry *alias; |
d39ab9de3 NFS: re-add readd... |
472 473 |
struct inode *dir = parent->d_inode; struct inode *inode; |
4a201d6e3 NFS: Ensure we ch... |
474 475 476 477 478 479 480 |
if (filename.name[0] == '.') { if (filename.len == 1) return; if (filename.len == 2 && filename.name[1] == '.') return; } filename.hash = full_name_hash(filename.name, filename.len); |
d39ab9de3 NFS: re-add readd... |
481 |
|
4a201d6e3 NFS: Ensure we ch... |
482 |
dentry = d_lookup(parent, &filename); |
d39ab9de3 NFS: re-add readd... |
483 484 485 486 487 488 489 490 491 492 493 |
if (dentry != NULL) { if (nfs_same_file(dentry, entry)) { nfs_refresh_inode(dentry->d_inode, entry->fattr); goto out; } else { d_drop(dentry); dput(dentry); } } dentry = d_alloc(parent, &filename); |
4a201d6e3 NFS: Ensure we ch... |
494 495 |
if (dentry == NULL) return; |
d39ab9de3 NFS: re-add readd... |
496 497 498 499 500 501 502 503 504 505 506 507 508 509 510 |
inode = nfs_fhget(dentry->d_sb, entry->fh, entry->fattr); if (IS_ERR(inode)) goto out; alias = d_materialise_unique(dentry, inode); if (IS_ERR(alias)) goto out; else if (alias) { nfs_set_verifier(alias, nfs_save_change_attribute(dir)); dput(alias); } else nfs_set_verifier(dentry, nfs_save_change_attribute(dir)); out: dput(dentry); |
d39ab9de3 NFS: re-add readd... |
511 |
} |
d1bacf9eb NFS: add readdir ... |
512 513 |
/* Perform conversion from xdr to cache array */ static |
8cd51a0cc NFS: Fix a couple... |
514 |
int nfs_readdir_page_filler(nfs_readdir_descriptor_t *desc, struct nfs_entry *entry, |
6650239a4 NFS: Don't use vm... |
515 |
struct page **xdr_pages, struct page *page, unsigned int buflen) |
1da177e4c Linux-2.6.12-rc2 |
516 |
{ |
babddc72a NFS: decode_diren... |
517 |
struct xdr_stream stream; |
f7da7a129 SUNRPC: introduce... |
518 |
struct xdr_buf buf; |
6650239a4 NFS: Don't use vm... |
519 |
struct page *scratch; |
994243808 NFS: check xdr_de... |
520 |
struct nfs_cache_array *array; |
5c346854d NFS: Assume eof i... |
521 522 |
unsigned int count = 0; int status; |
babddc72a NFS: decode_diren... |
523 |
|
6650239a4 NFS: Don't use vm... |
524 525 526 |
scratch = alloc_page(GFP_KERNEL); if (scratch == NULL) return -ENOMEM; |
babddc72a NFS: decode_diren... |
527 |
|
f7da7a129 SUNRPC: introduce... |
528 |
xdr_init_decode_pages(&stream, &buf, xdr_pages, buflen); |
6650239a4 NFS: Don't use vm... |
529 |
xdr_set_scratch_buffer(&stream, page_address(scratch), PAGE_SIZE); |
994243808 NFS: check xdr_de... |
530 531 532 |
do { status = xdr_decode(desc, entry, &stream); |
8cd51a0cc NFS: Fix a couple... |
533 534 535 |
if (status != 0) { if (status == -EAGAIN) status = 0; |
994243808 NFS: check xdr_de... |
536 |
break; |
8cd51a0cc NFS: Fix a couple... |
537 |
} |
994243808 NFS: check xdr_de... |
538 |
|
5c346854d NFS: Assume eof i... |
539 |
count++; |
47c716cbf NFS: Readdir clea... |
540 |
if (desc->plus != 0) |
d39ab9de3 NFS: re-add readd... |
541 |
nfs_prime_dcache(desc->file->f_path.dentry, entry); |
8cd51a0cc NFS: Fix a couple... |
542 543 544 545 |
status = nfs_readdir_add_to_array(entry, page); if (status != 0) break; |
994243808 NFS: check xdr_de... |
546 |
} while (!entry->eof); |
47c716cbf NFS: Readdir clea... |
547 |
if (count == 0 || (status == -EBADCOOKIE && entry->eof != 0)) { |
994243808 NFS: check xdr_de... |
548 |
array = nfs_readdir_get_array(page); |
8cd51a0cc NFS: Fix a couple... |
549 550 551 552 |
if (!IS_ERR(array)) { array->eof_index = array->size; status = 0; nfs_readdir_release_array(page); |
5c346854d NFS: Assume eof i... |
553 554 |
} else status = PTR_ERR(array); |
1da177e4c Linux-2.6.12-rc2 |
555 |
} |
6650239a4 NFS: Don't use vm... |
556 557 |
put_page(scratch); |
8cd51a0cc NFS: Fix a couple... |
558 |
return status; |
56e4ebf87 NFS: readdir with... |
559 560 561 562 563 564 565 566 567 568 569 570 571 572 |
} static void nfs_readdir_free_pagearray(struct page **pages, unsigned int npages) { unsigned int i; for (i = 0; i < npages; i++) put_page(pages[i]); } static void nfs_readdir_free_large_page(void *ptr, struct page **pages, unsigned int npages) { |
56e4ebf87 NFS: readdir with... |
573 574 575 576 577 578 579 580 |
nfs_readdir_free_pagearray(pages, npages); } /* * nfs_readdir_large_page will allocate pages that must be freed with a call * to nfs_readdir_free_large_page */ static |
6650239a4 NFS: Don't use vm... |
581 |
int nfs_readdir_large_page(struct page **pages, unsigned int npages) |
56e4ebf87 NFS: readdir with... |
582 |
{ |
56e4ebf87 NFS: readdir with... |
583 584 585 586 587 588 589 590 |
unsigned int i; for (i = 0; i < npages; i++) { struct page *page = alloc_page(GFP_KERNEL); if (page == NULL) goto out_freepages; pages[i] = page; } |
6650239a4 NFS: Don't use vm... |
591 |
return 0; |
56e4ebf87 NFS: readdir with... |
592 |
|
56e4ebf87 NFS: readdir with... |
593 594 |
out_freepages: nfs_readdir_free_pagearray(pages, i); |
6650239a4 NFS: Don't use vm... |
595 |
return -ENOMEM; |
1da177e4c Linux-2.6.12-rc2 |
596 |
} |
d1bacf9eb NFS: add readdir ... |
597 598 |
static int nfs_readdir_xdr_to_array(nfs_readdir_descriptor_t *desc, struct page *page, struct inode *inode) |
00a926422 [PATCH] NFS: Hide... |
599 |
{ |
56e4ebf87 NFS: readdir with... |
600 601 |
struct page *pages[NFS_MAX_READDIR_PAGES]; void *pages_ptr = NULL; |
d1bacf9eb NFS: add readdir ... |
602 603 604 |
struct nfs_entry entry; struct file *file = desc->file; struct nfs_cache_array *array; |
8cd51a0cc NFS: Fix a couple... |
605 |
int status = -ENOMEM; |
56e4ebf87 NFS: readdir with... |
606 |
unsigned int array_size = ARRAY_SIZE(pages); |
d1bacf9eb NFS: add readdir ... |
607 608 |
entry.prev_cookie = 0; |
0aded708d NFS: Ensure we us... |
609 |
entry.cookie = desc->last_cookie; |
d1bacf9eb NFS: add readdir ... |
610 611 612 |
entry.eof = 0; entry.fh = nfs_alloc_fhandle(); entry.fattr = nfs_alloc_fattr(); |
573c4e1ef NFS: Simplify ->d... |
613 |
entry.server = NFS_SERVER(inode); |
d1bacf9eb NFS: add readdir ... |
614 615 |
if (entry.fh == NULL || entry.fattr == NULL) goto out; |
00a926422 [PATCH] NFS: Hide... |
616 |
|
d1bacf9eb NFS: add readdir ... |
617 |
array = nfs_readdir_get_array(page); |
8cd51a0cc NFS: Fix a couple... |
618 619 620 621 |
if (IS_ERR(array)) { status = PTR_ERR(array); goto out; } |
d1bacf9eb NFS: add readdir ... |
622 623 |
memset(array, 0, sizeof(struct nfs_cache_array)); array->eof_index = -1; |
00a926422 [PATCH] NFS: Hide... |
624 |
|
6650239a4 NFS: Don't use vm... |
625 626 |
status = nfs_readdir_large_page(pages, array_size); if (status < 0) |
d1bacf9eb NFS: add readdir ... |
627 628 |
goto out_release_array; do { |
ac3961282 NFS: readdir shou... |
629 |
unsigned int pglen; |
56e4ebf87 NFS: readdir with... |
630 |
status = nfs_readdir_xdr_filler(pages, desc, &entry, file, inode); |
babddc72a NFS: decode_diren... |
631 |
|
d1bacf9eb NFS: add readdir ... |
632 |
if (status < 0) |
00a926422 [PATCH] NFS: Hide... |
633 |
break; |
ac3961282 NFS: readdir shou... |
634 |
pglen = status; |
6650239a4 NFS: Don't use vm... |
635 |
status = nfs_readdir_page_filler(desc, &entry, pages, page, pglen); |
8cd51a0cc NFS: Fix a couple... |
636 637 638 639 640 641 |
if (status < 0) { if (status == -ENOSPC) status = 0; break; } } while (array->eof_index < 0); |
d1bacf9eb NFS: add readdir ... |
642 |
|
56e4ebf87 NFS: readdir with... |
643 |
nfs_readdir_free_large_page(pages_ptr, pages, array_size); |
d1bacf9eb NFS: add readdir ... |
644 645 646 647 648 |
out_release_array: nfs_readdir_release_array(page); out: nfs_free_fattr(entry.fattr); nfs_free_fhandle(entry.fh); |
00a926422 [PATCH] NFS: Hide... |
649 650 651 652 |
return status; } /* |
d1bacf9eb NFS: add readdir ... |
653 654 655 656 |
* Now we cache directories properly, by converting xdr information * to an array that can be used for lookups later. This results in * fewer cache pages, since we can store more information on each page. * We only need to convert from xdr once so future lookups are much simpler |
1da177e4c Linux-2.6.12-rc2 |
657 |
*/ |
d1bacf9eb NFS: add readdir ... |
658 659 |
static int nfs_readdir_filler(nfs_readdir_descriptor_t *desc, struct page* page) |
1da177e4c Linux-2.6.12-rc2 |
660 |
{ |
01cce933d [PATCH] nfs: chan... |
661 |
struct inode *inode = desc->file->f_path.dentry->d_inode; |
8cd51a0cc NFS: Fix a couple... |
662 |
int ret; |
1da177e4c Linux-2.6.12-rc2 |
663 |
|
8cd51a0cc NFS: Fix a couple... |
664 665 |
ret = nfs_readdir_xdr_to_array(desc, page, inode); if (ret < 0) |
d1bacf9eb NFS: add readdir ... |
666 667 |
goto error; SetPageUptodate(page); |
1da177e4c Linux-2.6.12-rc2 |
668 |
|
d1bacf9eb NFS: add readdir ... |
669 670 671 |
if (invalidate_inode_pages2_range(inode->i_mapping, page->index + 1, -1) < 0) { /* Should never happen */ nfs_zap_mapping(inode, inode->i_mapping); |
1da177e4c Linux-2.6.12-rc2 |
672 |
} |
d1bacf9eb NFS: add readdir ... |
673 674 675 676 |
unlock_page(page); return 0; error: unlock_page(page); |
8cd51a0cc NFS: Fix a couple... |
677 |
return ret; |
d1bacf9eb NFS: add readdir ... |
678 |
} |
1da177e4c Linux-2.6.12-rc2 |
679 |
|
d1bacf9eb NFS: add readdir ... |
680 681 682 |
static void cache_page_release(nfs_readdir_descriptor_t *desc) { |
11de3b11e NFS: Fix a memory... |
683 684 |
if (!desc->page->mapping) nfs_readdir_clear_array(desc->page); |
d1bacf9eb NFS: add readdir ... |
685 686 687 688 689 690 691 |
page_cache_release(desc->page); desc->page = NULL; } static struct page *get_cache_page(nfs_readdir_descriptor_t *desc) { |
8cd51a0cc NFS: Fix a couple... |
692 |
return read_cache_page(desc->file->f_path.dentry->d_inode->i_mapping, |
d1bacf9eb NFS: add readdir ... |
693 |
desc->page_index, (filler_t *)nfs_readdir_filler, desc); |
1da177e4c Linux-2.6.12-rc2 |
694 695 696 |
} /* |
d1bacf9eb NFS: add readdir ... |
697 |
* Returns 0 if desc->dir_cookie was found on page desc->page_index |
1da177e4c Linux-2.6.12-rc2 |
698 |
*/ |
d1bacf9eb NFS: add readdir ... |
699 700 701 702 703 704 705 706 707 708 |
static int find_cache_page(nfs_readdir_descriptor_t *desc) { int res; desc->page = get_cache_page(desc); if (IS_ERR(desc->page)) return PTR_ERR(desc->page); res = nfs_readdir_search_array(desc); |
47c716cbf NFS: Readdir clea... |
709 710 |
if (res != 0) cache_page_release(desc); |
d1bacf9eb NFS: add readdir ... |
711 712 713 714 |
return res; } /* Search for desc->dir_cookie from the beginning of the page cache */ |
1da177e4c Linux-2.6.12-rc2 |
715 716 717 |
static inline int readdir_search_pagecache(nfs_readdir_descriptor_t *desc) { |
8cd51a0cc NFS: Fix a couple... |
718 |
int res; |
d1bacf9eb NFS: add readdir ... |
719 |
|
0aded708d NFS: Ensure we us... |
720 |
if (desc->page_index == 0) { |
8cd51a0cc NFS: Fix a couple... |
721 |
desc->current_index = 0; |
0aded708d NFS: Ensure we us... |
722 723 |
desc->last_cookie = 0; } |
47c716cbf NFS: Readdir clea... |
724 |
do { |
d1bacf9eb NFS: add readdir ... |
725 |
res = find_cache_page(desc); |
47c716cbf NFS: Readdir clea... |
726 |
} while (res == -EAGAIN); |
1da177e4c Linux-2.6.12-rc2 |
727 728 |
return res; } |
1da177e4c Linux-2.6.12-rc2 |
729 730 731 732 733 734 735 736 |
/* * Once we've found the start of the dirent within a page: fill 'er up... */ static int nfs_do_filldir(nfs_readdir_descriptor_t *desc, void *dirent, filldir_t filldir) { struct file *file = desc->file; |
d1bacf9eb NFS: add readdir ... |
737 738 739 |
int i = 0; int res = 0; struct nfs_cache_array *array = NULL; |
8ef2ce3e1 NFS: Detect loops... |
740 |
struct nfs_open_dir_context *ctx = file->private_data; |
d1bacf9eb NFS: add readdir ... |
741 |
array = nfs_readdir_get_array(desc->page); |
e7c58e974 NFS: Fix a page l... |
742 743 744 745 |
if (IS_ERR(array)) { res = PTR_ERR(array); goto out; } |
d1bacf9eb NFS: add readdir ... |
746 747 |
for (i = desc->cache_entry_index; i < array->size; i++) { |
ece0b4233 NFS: Don't ignore... |
748 |
struct nfs_cache_array_entry *ent; |
1da177e4c Linux-2.6.12-rc2 |
749 |
|
ece0b4233 NFS: Don't ignore... |
750 751 |
ent = &array->array[i]; if (filldir(dirent, ent->string.name, ent->string.len, |
0b26a0bf6 NFS: Ensure we re... |
752 753 |
file->f_pos, nfs_compat_user_ino64(ent->ino), ent->d_type) < 0) { |
ece0b4233 NFS: Don't ignore... |
754 |
desc->eof = 1; |
1da177e4c Linux-2.6.12-rc2 |
755 |
break; |
ece0b4233 NFS: Don't ignore... |
756 |
} |
00a926422 [PATCH] NFS: Hide... |
757 |
file->f_pos++; |
d1bacf9eb NFS: add readdir ... |
758 759 760 761 |
if (i < (array->size-1)) *desc->dir_cookie = array->array[i+1].cookie; else *desc->dir_cookie = array->last_cookie; |
0c0308066 NFS: Fix spurious... |
762 763 |
if (ctx->duped != 0) ctx->duped = 1; |
1da177e4c Linux-2.6.12-rc2 |
764 |
} |
47c716cbf NFS: Readdir clea... |
765 |
if (array->eof_index >= 0) |
8cd51a0cc NFS: Fix a couple... |
766 |
desc->eof = 1; |
d1bacf9eb NFS: add readdir ... |
767 768 |
nfs_readdir_release_array(desc->page); |
e7c58e974 NFS: Fix a page l... |
769 |
out: |
d1bacf9eb NFS: add readdir ... |
770 |
cache_page_release(desc); |
1e7cb3dc1 NFS: directory tr... |
771 772 773 |
dfprintk(DIRCACHE, "NFS: nfs_do_filldir() filling ended @ cookie %Lu; returning = %d ", (unsigned long long)*desc->dir_cookie, res); |
1da177e4c Linux-2.6.12-rc2 |
774 775 776 777 778 779 780 781 782 783 784 785 786 787 788 789 790 791 792 |
return res; } /* * If we cannot find a cookie in our cache, we suspect that this is * because it points to a deleted file, so we ask the server to return * whatever it thinks is the next entry. We then feed this to filldir. * If all goes well, we should then be able to find our way round the * cache on the next call to readdir_search_pagecache(); * * NOTE: we cannot add the anonymous page to the pagecache because * the data it contains might not be page aligned. Besides, * we should already have a complete representation of the * directory in the page cache by the time we get here. */ static inline int uncached_readdir(nfs_readdir_descriptor_t *desc, void *dirent, filldir_t filldir) { |
1da177e4c Linux-2.6.12-rc2 |
793 794 |
struct page *page = NULL; int status; |
d1bacf9eb NFS: add readdir ... |
795 |
struct inode *inode = desc->file->f_path.dentry->d_inode; |
0c0308066 NFS: Fix spurious... |
796 |
struct nfs_open_dir_context *ctx = desc->file->private_data; |
1da177e4c Linux-2.6.12-rc2 |
797 |
|
1e7cb3dc1 NFS: directory tr... |
798 799 800 |
dfprintk(DIRCACHE, "NFS: uncached_readdir() searching for cookie %Lu ", (unsigned long long)*desc->dir_cookie); |
1da177e4c Linux-2.6.12-rc2 |
801 802 803 804 805 806 |
page = alloc_page(GFP_HIGHUSER); if (!page) { status = -ENOMEM; goto out; } |
d1bacf9eb NFS: add readdir ... |
807 |
|
7a8e1dc34 NFS: Fix a page l... |
808 |
desc->page_index = 0; |
0aded708d NFS: Ensure we us... |
809 |
desc->last_cookie = *desc->dir_cookie; |
7a8e1dc34 NFS: Fix a page l... |
810 |
desc->page = page; |
0c0308066 NFS: Fix spurious... |
811 |
ctx->duped = 0; |
7a8e1dc34 NFS: Fix a page l... |
812 |
|
85f8607e1 NFS: Fix the erro... |
813 814 |
status = nfs_readdir_xdr_to_array(desc, page, inode); if (status < 0) |
1da177e4c Linux-2.6.12-rc2 |
815 816 817 |
goto out_release; status = nfs_do_filldir(desc, dirent, filldir); |
1da177e4c Linux-2.6.12-rc2 |
818 |
out: |
1e7cb3dc1 NFS: directory tr... |
819 820 |
dfprintk(DIRCACHE, "NFS: %s: returns %d ", |
3110ff804 nfs: replace rema... |
821 |
__func__, status); |
1da177e4c Linux-2.6.12-rc2 |
822 823 |
return status; out_release: |
d1bacf9eb NFS: add readdir ... |
824 |
cache_page_release(desc); |
1da177e4c Linux-2.6.12-rc2 |
825 826 |
goto out; } |
00a926422 [PATCH] NFS: Hide... |
827 828 829 |
/* The file offset position represents the dirent entry number. A last cookie cache takes care of the common case of reading the whole directory. |
1da177e4c Linux-2.6.12-rc2 |
830 831 832 |
*/ static int nfs_readdir(struct file *filp, void *dirent, filldir_t filldir) { |
01cce933d [PATCH] nfs: chan... |
833 |
struct dentry *dentry = filp->f_path.dentry; |
1da177e4c Linux-2.6.12-rc2 |
834 835 836 |
struct inode *inode = dentry->d_inode; nfs_readdir_descriptor_t my_desc, *desc = &my_desc; |
480c2006e NFS: Create nfs_o... |
837 |
struct nfs_open_dir_context *dir_ctx = filp->private_data; |
47c716cbf NFS: Readdir clea... |
838 |
int res; |
1da177e4c Linux-2.6.12-rc2 |
839 |
|
6da24bc9c NFS: Use NFSDBG_F... |
840 841 |
dfprintk(FILE, "NFS: readdir(%s/%s) starting at cookie %llu ", |
1e7cb3dc1 NFS: directory tr... |
842 843 |
dentry->d_parent->d_name.name, dentry->d_name.name, (long long)filp->f_pos); |
91d5b4702 NFS: add I/O perf... |
844 |
nfs_inc_stats(inode, NFSIOS_VFSGETDENTS); |
1da177e4c Linux-2.6.12-rc2 |
845 |
/* |
00a926422 [PATCH] NFS: Hide... |
846 |
* filp->f_pos points to the dirent entry number. |
f0dd2136d [PATCH] NFS: Clea... |
847 |
* *desc->dir_cookie has the cookie for the next entry. We have |
00a926422 [PATCH] NFS: Hide... |
848 849 |
* to either find the entry with the appropriate number or * revalidate the cookie. |
1da177e4c Linux-2.6.12-rc2 |
850 851 852 853 |
*/ memset(desc, 0, sizeof(*desc)); desc->file = filp; |
480c2006e NFS: Create nfs_o... |
854 |
desc->dir_cookie = &dir_ctx->dir_cookie; |
1da177e4c Linux-2.6.12-rc2 |
855 856 |
desc->decode = NFS_PROTO(inode)->decode_dirent; desc->plus = NFS_USE_READDIRPLUS(inode); |
565277f63 NFS: Fix a race i... |
857 |
nfs_block_sillyrename(dentry); |
1cda707d5 NFS: Remove requi... |
858 |
res = nfs_revalidate_mapping(inode, filp->f_mapping); |
fccca7fc6 NFS: Fix a sillyr... |
859 860 |
if (res < 0) goto out; |
47c716cbf NFS: Readdir clea... |
861 |
do { |
1da177e4c Linux-2.6.12-rc2 |
862 |
res = readdir_search_pagecache(desc); |
00a926422 [PATCH] NFS: Hide... |
863 |
|
1da177e4c Linux-2.6.12-rc2 |
864 |
if (res == -EBADCOOKIE) { |
ece0b4233 NFS: Don't ignore... |
865 |
res = 0; |
1da177e4c Linux-2.6.12-rc2 |
866 |
/* This means either end of directory */ |
d1bacf9eb NFS: add readdir ... |
867 |
if (*desc->dir_cookie && desc->eof == 0) { |
1da177e4c Linux-2.6.12-rc2 |
868 869 |
/* Or that the server has 'lost' a cookie */ res = uncached_readdir(desc, dirent, filldir); |
ece0b4233 NFS: Don't ignore... |
870 |
if (res == 0) |
1da177e4c Linux-2.6.12-rc2 |
871 872 |
continue; } |
1da177e4c Linux-2.6.12-rc2 |
873 874 875 |
break; } if (res == -ETOOSMALL && desc->plus) { |
3a10c30ac nfs: obliterate N... |
876 |
clear_bit(NFS_INO_ADVISE_RDPLUS, &NFS_I(inode)->flags); |
1da177e4c Linux-2.6.12-rc2 |
877 |
nfs_zap_caches(inode); |
baf57a09e NFS: Optimise the... |
878 |
desc->page_index = 0; |
1da177e4c Linux-2.6.12-rc2 |
879 |
desc->plus = 0; |
d1bacf9eb NFS: add readdir ... |
880 |
desc->eof = 0; |
1da177e4c Linux-2.6.12-rc2 |
881 882 883 884 885 886 |
continue; } if (res < 0) break; res = nfs_do_filldir(desc, dirent, filldir); |
ece0b4233 NFS: Don't ignore... |
887 |
if (res < 0) |
1da177e4c Linux-2.6.12-rc2 |
888 |
break; |
47c716cbf NFS: Readdir clea... |
889 |
} while (!desc->eof); |
fccca7fc6 NFS: Fix a sillyr... |
890 |
out: |
565277f63 NFS: Fix a race i... |
891 |
nfs_unblock_sillyrename(dentry); |
1e7cb3dc1 NFS: directory tr... |
892 893 |
if (res > 0) res = 0; |
aa49b4cf7 NFS: Reduce stack... |
894 895 |
dfprintk(FILE, "NFS: readdir(%s/%s) returns %d ", |
1e7cb3dc1 NFS: directory tr... |
896 897 898 |
dentry->d_parent->d_name.name, dentry->d_name.name, res); return res; |
1da177e4c Linux-2.6.12-rc2 |
899 |
} |
10afec908 NFS: Fix some 'sp... |
900 |
static loff_t nfs_llseek_dir(struct file *filp, loff_t offset, int origin) |
f0dd2136d [PATCH] NFS: Clea... |
901 |
{ |
b84e06c58 NFS: Make nfs_lls... |
902 903 |
struct dentry *dentry = filp->f_path.dentry; struct inode *inode = dentry->d_inode; |
480c2006e NFS: Create nfs_o... |
904 |
struct nfs_open_dir_context *dir_ctx = filp->private_data; |
b84e06c58 NFS: Make nfs_lls... |
905 |
|
6da24bc9c NFS: Use NFSDBG_F... |
906 907 |
dfprintk(FILE, "NFS: llseek dir(%s/%s, %lld, %d) ", |
b84e06c58 NFS: Make nfs_lls... |
908 909 910 911 912 |
dentry->d_parent->d_name.name, dentry->d_name.name, offset, origin); mutex_lock(&inode->i_mutex); |
f0dd2136d [PATCH] NFS: Clea... |
913 914 915 916 917 918 919 920 921 922 923 924 |
switch (origin) { case 1: offset += filp->f_pos; case 0: if (offset >= 0) break; default: offset = -EINVAL; goto out; } if (offset != filp->f_pos) { filp->f_pos = offset; |
480c2006e NFS: Create nfs_o... |
925 |
dir_ctx->dir_cookie = 0; |
8ef2ce3e1 NFS: Detect loops... |
926 |
dir_ctx->duped = 0; |
f0dd2136d [PATCH] NFS: Clea... |
927 928 |
} out: |
b84e06c58 NFS: Make nfs_lls... |
929 |
mutex_unlock(&inode->i_mutex); |
f0dd2136d [PATCH] NFS: Clea... |
930 931 |
return offset; } |
1da177e4c Linux-2.6.12-rc2 |
932 933 934 935 |
/* * All directory operations under NFS are synchronous, so fsync() * is a dummy operation. */ |
02c24a821 fs: push i_mutex ... |
936 937 |
static int nfs_fsync_dir(struct file *filp, loff_t start, loff_t end, int datasync) |
1da177e4c Linux-2.6.12-rc2 |
938 |
{ |
7ea808591 drop unused dentr... |
939 |
struct dentry *dentry = filp->f_path.dentry; |
02c24a821 fs: push i_mutex ... |
940 |
struct inode *inode = dentry->d_inode; |
7ea808591 drop unused dentr... |
941 |
|
6da24bc9c NFS: Use NFSDBG_F... |
942 943 |
dfprintk(FILE, "NFS: fsync dir(%s/%s) datasync %d ", |
1e7cb3dc1 NFS: directory tr... |
944 945 |
dentry->d_parent->d_name.name, dentry->d_name.name, datasync); |
02c24a821 fs: push i_mutex ... |
946 |
mutex_lock(&inode->i_mutex); |
549177863 NFS: Make nfs_fsy... |
947 |
nfs_inc_stats(dentry->d_inode, NFSIOS_VFSFSYNC); |
02c24a821 fs: push i_mutex ... |
948 |
mutex_unlock(&inode->i_mutex); |
1da177e4c Linux-2.6.12-rc2 |
949 950 |
return 0; } |
bfc69a456 NFS: define a fun... |
951 952 953 954 955 956 957 958 959 960 961 962 |
/** * nfs_force_lookup_revalidate - Mark the directory as having changed * @dir - pointer to directory inode * * This forces the revalidation code in nfs_lookup_revalidate() to do a * full lookup on all child dentries of 'dir' whenever a change occurs * on the server that might have invalidated our dcache. * * The caller should be holding dir->i_lock */ void nfs_force_lookup_revalidate(struct inode *dir) { |
011935a0a NFS: Fix a resolu... |
963 |
NFS_I(dir)->cache_change_attribute++; |
bfc69a456 NFS: define a fun... |
964 |
} |
1da177e4c Linux-2.6.12-rc2 |
965 966 967 968 969 |
/* * A check for whether or not the parent directory has changed. * In the case it has, we assume that the dentries are untrustworthy * and may need to be looked up again. */ |
c79ba787c NFS: Dont clobber... |
970 |
static int nfs_check_verifier(struct inode *dir, struct dentry *dentry) |
1da177e4c Linux-2.6.12-rc2 |
971 972 973 |
{ if (IS_ROOT(dentry)) return 1; |
4eec952e4 NFS: Add options ... |
974 975 |
if (NFS_SERVER(dir)->flags & NFS_MOUNT_LOOKUP_CACHE_NONE) return 0; |
f2c77f4e6 NFS: Optimise nfs... |
976 977 978 979 980 981 982 983 |
if (!nfs_verify_change_attribute(dir, dentry->d_time)) return 0; /* Revalidate nfsi->cache_change_attribute before we declare a match */ if (nfs_revalidate_inode(NFS_SERVER(dir), dir) < 0) return 0; if (!nfs_verify_change_attribute(dir, dentry->d_time)) return 0; return 1; |
1da177e4c Linux-2.6.12-rc2 |
984 |
} |
1da177e4c Linux-2.6.12-rc2 |
985 |
/* |
1d6757fbf [PATCH] NFS: Fix ... |
986 987 988 |
* Return the intent data that applies to this particular path component * * Note that the current set of intents only apply to the very last |
8aeb376ca nfs: LOOKUP_{OPEN... |
989 990 |
* component of the path and none of them is set before that last * component. |
1d6757fbf [PATCH] NFS: Fix ... |
991 |
*/ |
34286d666 fs: rcu-walk awar... |
992 993 |
static inline unsigned int nfs_lookup_check_intent(struct nameidata *nd, unsigned int mask) |
1d6757fbf [PATCH] NFS: Fix ... |
994 |
{ |
1d6757fbf [PATCH] NFS: Fix ... |
995 996 997 998 |
return nd->flags & mask; } /* |
a12802cab NFS: Be strict ab... |
999 1000 1001 1002 1003 1004 1005 |
* Use intent information to check whether or not we're going to do * an O_EXCL create using this path component. */ static int nfs_is_exclusive_create(struct inode *dir, struct nameidata *nd) { if (NFS_PROTO(dir)->version == 2) return 0; |
3516586a4 [PATCH] make O_EX... |
1006 |
return nd && nfs_lookup_check_intent(nd, LOOKUP_EXCL); |
a12802cab NFS: Be strict ab... |
1007 1008 1009 |
} /* |
1d6757fbf [PATCH] NFS: Fix ... |
1010 1011 1012 1013 1014 1015 1016 |
* Inode and filehandle revalidation for lookups. * * We force revalidation in the cases where the VFS sets LOOKUP_REVAL, * or if the intent information indicates that we're about to open this * particular file and the "nocto" mount flag is not set. * */ |
1da177e4c Linux-2.6.12-rc2 |
1017 1018 1019 1020 |
static inline int nfs_lookup_verify_inode(struct inode *inode, struct nameidata *nd) { struct nfs_server *server = NFS_SERVER(inode); |
36d43a437 NFS: Use d_automo... |
1021 |
if (IS_AUTOMOUNT(inode)) |
4e99a1ff3 NFS: Fix dentry r... |
1022 |
return 0; |
1da177e4c Linux-2.6.12-rc2 |
1023 |
if (nd != NULL) { |
1da177e4c Linux-2.6.12-rc2 |
1024 |
/* VFS wants an on-the-wire revalidation */ |
1d6757fbf [PATCH] NFS: Fix ... |
1025 |
if (nd->flags & LOOKUP_REVAL) |
1da177e4c Linux-2.6.12-rc2 |
1026 1027 |
goto out_force; /* This is an open(2) */ |
1d6757fbf [PATCH] NFS: Fix ... |
1028 |
if (nfs_lookup_check_intent(nd, LOOKUP_OPEN) != 0 && |
4e0641a7a NFS: Optimise awa... |
1029 1030 1031 |
!(server->flags & NFS_MOUNT_NOCTO) && (S_ISREG(inode->i_mode) || S_ISDIR(inode->i_mode))) |
1da177e4c Linux-2.6.12-rc2 |
1032 |
goto out_force; |
4f48af458 NFS: Simplify fil... |
1033 |
return 0; |
1da177e4c Linux-2.6.12-rc2 |
1034 1035 1036 1037 1038 1039 1040 1041 1042 1043 1044 1045 1046 1047 1048 1049 1050 |
} return nfs_revalidate_inode(server, inode); out_force: return __nfs_revalidate_inode(server, inode); } /* * We judge how long we want to trust negative * dentries by looking at the parent inode mtime. * * If parent mtime has changed, we revalidate, else we wait for a * period corresponding to the parent's attribute cache timeout value. */ static inline int nfs_neg_need_reval(struct inode *dir, struct dentry *dentry, struct nameidata *nd) { |
1da177e4c Linux-2.6.12-rc2 |
1051 |
/* Don't revalidate a negative dentry if we're creating a new file */ |
1d6757fbf [PATCH] NFS: Fix ... |
1052 |
if (nd != NULL && nfs_lookup_check_intent(nd, LOOKUP_CREATE) != 0) |
1da177e4c Linux-2.6.12-rc2 |
1053 |
return 0; |
4eec952e4 NFS: Add options ... |
1054 1055 |
if (NFS_SERVER(dir)->flags & NFS_MOUNT_LOOKUP_CACHE_NONEG) return 1; |
1da177e4c Linux-2.6.12-rc2 |
1056 1057 1058 1059 1060 1061 1062 1063 1064 1065 1066 1067 1068 1069 |
return !nfs_check_verifier(dir, dentry); } /* * This is called every time the dcache has a lookup hit, * and we should check whether we can really trust that * lookup. * * NOTE! The hit can be a negative hit too, don't assume * we have an inode! * * If the parent directory is seen to have changed, we throw out the * cached dentry and do a new lookup. */ |
34286d666 fs: rcu-walk awar... |
1070 |
static int nfs_lookup_revalidate(struct dentry *dentry, struct nameidata *nd) |
1da177e4c Linux-2.6.12-rc2 |
1071 1072 1073 1074 |
{ struct inode *dir; struct inode *inode; struct dentry *parent; |
e1fb4d05d NFS: Reduce the s... |
1075 1076 |
struct nfs_fh *fhandle = NULL; struct nfs_fattr *fattr = NULL; |
1da177e4c Linux-2.6.12-rc2 |
1077 |
int error; |
1da177e4c Linux-2.6.12-rc2 |
1078 |
|
34286d666 fs: rcu-walk awar... |
1079 1080 |
if (nd->flags & LOOKUP_RCU) return -ECHILD; |
1da177e4c Linux-2.6.12-rc2 |
1081 |
parent = dget_parent(dentry); |
1da177e4c Linux-2.6.12-rc2 |
1082 |
dir = parent->d_inode; |
91d5b4702 NFS: add I/O perf... |
1083 |
nfs_inc_stats(dir, NFSIOS_DENTRYREVALIDATE); |
1da177e4c Linux-2.6.12-rc2 |
1084 1085 1086 1087 1088 1089 1090 1091 1092 |
inode = dentry->d_inode; if (!inode) { if (nfs_neg_need_reval(dir, dentry, nd)) goto out_bad; goto out_valid; } if (is_bad_inode(inode)) { |
1e7cb3dc1 NFS: directory tr... |
1093 1094 |
dfprintk(LOOKUPCACHE, "%s: %s/%s has dud inode ", |
3110ff804 nfs: replace rema... |
1095 |
__func__, dentry->d_parent->d_name.name, |
1e7cb3dc1 NFS: directory tr... |
1096 |
dentry->d_name.name); |
1da177e4c Linux-2.6.12-rc2 |
1097 1098 |
goto out_bad; } |
15860ab1d NFSv4: Ensure tha... |
1099 1100 |
if (nfs_have_delegation(inode, FMODE_READ)) goto out_set_verifier; |
1da177e4c Linux-2.6.12-rc2 |
1101 |
/* Force a full look up iff the parent directory has changed */ |
a12802cab NFS: Be strict ab... |
1102 |
if (!nfs_is_exclusive_create(dir, nd) && nfs_check_verifier(dir, dentry)) { |
1da177e4c Linux-2.6.12-rc2 |
1103 1104 1105 1106 1107 1108 1109 |
if (nfs_lookup_verify_inode(inode, nd)) goto out_zap_parent; goto out_valid; } if (NFS_STALE(inode)) goto out_bad; |
e1fb4d05d NFS: Reduce the s... |
1110 1111 1112 1113 1114 |
error = -ENOMEM; fhandle = nfs_alloc_fhandle(); fattr = nfs_alloc_fattr(); if (fhandle == NULL || fattr == NULL) goto out_error; |
7c5130588 NFS: lookup suppo... |
1115 |
error = NFS_PROTO(dir)->lookup(NFS_SERVER(dir)->client, dir, &dentry->d_name, fhandle, fattr); |
1da177e4c Linux-2.6.12-rc2 |
1116 1117 |
if (error) goto out_bad; |
e1fb4d05d NFS: Reduce the s... |
1118 |
if (nfs_compare_fh(NFS_FH(inode), fhandle)) |
1da177e4c Linux-2.6.12-rc2 |
1119 |
goto out_bad; |
e1fb4d05d NFS: Reduce the s... |
1120 |
if ((error = nfs_refresh_inode(inode, fattr)) != 0) |
1da177e4c Linux-2.6.12-rc2 |
1121 |
goto out_bad; |
e1fb4d05d NFS: Reduce the s... |
1122 1123 |
nfs_free_fattr(fattr); nfs_free_fhandle(fhandle); |
15860ab1d NFSv4: Ensure tha... |
1124 |
out_set_verifier: |
cf8ba45e0 NFS: don't cache ... |
1125 |
nfs_set_verifier(dentry, nfs_save_change_attribute(dir)); |
1da177e4c Linux-2.6.12-rc2 |
1126 |
out_valid: |
1da177e4c Linux-2.6.12-rc2 |
1127 |
dput(parent); |
1e7cb3dc1 NFS: directory tr... |
1128 1129 |
dfprintk(LOOKUPCACHE, "NFS: %s(%s/%s) is valid ", |
3110ff804 nfs: replace rema... |
1130 |
__func__, dentry->d_parent->d_name.name, |
1e7cb3dc1 NFS: directory tr... |
1131 |
dentry->d_name.name); |
1da177e4c Linux-2.6.12-rc2 |
1132 1133 1134 1135 |
return 1; out_zap_parent: nfs_zap_caches(dir); out_bad: |
a1643a92f NFS: NFS_CACHEINV... |
1136 |
nfs_mark_for_revalidate(dir); |
1da177e4c Linux-2.6.12-rc2 |
1137 1138 1139 1140 1141 1142 |
if (inode && S_ISDIR(inode->i_mode)) { /* Purge readdir caches. */ nfs_zap_caches(inode); /* If we have submounts, don't unhash ! */ if (have_submounts(dentry)) goto out_valid; |
d9e80b7de nfs d_revalidate(... |
1143 1144 |
if (dentry->d_flags & DCACHE_DISCONNECTED) goto out_valid; |
1da177e4c Linux-2.6.12-rc2 |
1145 1146 1147 |
shrink_dcache_parent(dentry); } d_drop(dentry); |
e1fb4d05d NFS: Reduce the s... |
1148 1149 |
nfs_free_fattr(fattr); nfs_free_fhandle(fhandle); |
1da177e4c Linux-2.6.12-rc2 |
1150 |
dput(parent); |
1e7cb3dc1 NFS: directory tr... |
1151 1152 |
dfprintk(LOOKUPCACHE, "NFS: %s(%s/%s) is invalid ", |
3110ff804 nfs: replace rema... |
1153 |
__func__, dentry->d_parent->d_name.name, |
1e7cb3dc1 NFS: directory tr... |
1154 |
dentry->d_name.name); |
1da177e4c Linux-2.6.12-rc2 |
1155 |
return 0; |
e1fb4d05d NFS: Reduce the s... |
1156 1157 1158 1159 1160 1161 1162 1163 1164 |
out_error: nfs_free_fattr(fattr); nfs_free_fhandle(fhandle); dput(parent); dfprintk(LOOKUPCACHE, "NFS: %s(%s/%s) lookup returned error %d ", __func__, dentry->d_parent->d_name.name, dentry->d_name.name, error); return error; |
1da177e4c Linux-2.6.12-rc2 |
1165 1166 1167 1168 1169 |
} /* * This is called from dput() when d_count is going to 0. */ |
fe15ce446 fs: change d_dele... |
1170 |
static int nfs_dentry_delete(const struct dentry *dentry) |
1da177e4c Linux-2.6.12-rc2 |
1171 1172 1173 1174 1175 |
{ dfprintk(VFS, "NFS: dentry_delete(%s/%s, %x) ", dentry->d_parent->d_name.name, dentry->d_name.name, dentry->d_flags); |
77f111929 NFS: Ensure that ... |
1176 1177 1178 |
/* Unhash any dentry with a stale inode */ if (dentry->d_inode != NULL && NFS_STALE(dentry->d_inode)) return 1; |
1da177e4c Linux-2.6.12-rc2 |
1179 1180 1181 1182 1183 1184 1185 1186 1187 1188 1189 1190 |
if (dentry->d_flags & DCACHE_NFSFS_RENAMED) { /* Unhash it, so that ->d_iput() would be called */ return 1; } if (!(dentry->d_sb->s_flags & MS_ACTIVE)) { /* Unhash it, so that ancestors of killed async unlink * files will be cleaned up during umount */ return 1; } return 0; } |
1b83d7070 NFS: Protect inod... |
1191 1192 1193 1194 1195 1196 1197 |
static void nfs_drop_nlink(struct inode *inode) { spin_lock(&inode->i_lock); if (inode->i_nlink > 0) drop_nlink(inode); spin_unlock(&inode->i_lock); } |
1da177e4c Linux-2.6.12-rc2 |
1198 1199 1200 1201 1202 1203 |
/* * Called when the dentry loses inode. * We use it to clean up silly-renamed files. */ static void nfs_dentry_iput(struct dentry *dentry, struct inode *inode) { |
83672d392 NFS: Fix director... |
1204 1205 1206 |
if (S_ISDIR(inode->i_mode)) /* drop any readdir cache as it could easily be old */ NFS_I(inode)->cache_validity |= NFS_INO_INVALID_DATA; |
1da177e4c Linux-2.6.12-rc2 |
1207 |
if (dentry->d_flags & DCACHE_NFSFS_RENAMED) { |
9a53c3a78 [PATCH] r/o bind ... |
1208 |
drop_nlink(inode); |
e4eff1a62 SUNRPC: Clean up ... |
1209 |
nfs_complete_unlink(dentry, inode); |
1da177e4c Linux-2.6.12-rc2 |
1210 |
} |
1da177e4c Linux-2.6.12-rc2 |
1211 1212 |
iput(inode); } |
b1942c5f8 nfs: store devnam... |
1213 1214 1215 1216 1217 1218 1219 1220 1221 1222 |
static void nfs_d_release(struct dentry *dentry) { /* free cached devname value, if it survived that far */ if (unlikely(dentry->d_fsdata)) { if (dentry->d_flags & DCACHE_NFSFS_RENAMED) WARN_ON(1); else kfree(dentry->d_fsdata); } } |
f786aa90e constify dentry_o... |
1223 |
const struct dentry_operations nfs_dentry_operations = { |
1da177e4c Linux-2.6.12-rc2 |
1224 1225 1226 |
.d_revalidate = nfs_lookup_revalidate, .d_delete = nfs_dentry_delete, .d_iput = nfs_dentry_iput, |
36d43a437 NFS: Use d_automo... |
1227 |
.d_automount = nfs_d_automount, |
b1942c5f8 nfs: store devnam... |
1228 |
.d_release = nfs_d_release, |
1da177e4c Linux-2.6.12-rc2 |
1229 |
}; |
1da177e4c Linux-2.6.12-rc2 |
1230 1231 1232 |
static struct dentry *nfs_lookup(struct inode *dir, struct dentry * dentry, struct nameidata *nd) { struct dentry *res; |
565277f63 NFS: Fix a race i... |
1233 |
struct dentry *parent; |
1da177e4c Linux-2.6.12-rc2 |
1234 |
struct inode *inode = NULL; |
e1fb4d05d NFS: Reduce the s... |
1235 1236 |
struct nfs_fh *fhandle = NULL; struct nfs_fattr *fattr = NULL; |
1da177e4c Linux-2.6.12-rc2 |
1237 |
int error; |
1da177e4c Linux-2.6.12-rc2 |
1238 1239 1240 1241 |
dfprintk(VFS, "NFS: lookup(%s/%s) ", dentry->d_parent->d_name.name, dentry->d_name.name); |
91d5b4702 NFS: add I/O perf... |
1242 |
nfs_inc_stats(dir, NFSIOS_VFSLOOKUP); |
1da177e4c Linux-2.6.12-rc2 |
1243 1244 1245 1246 |
res = ERR_PTR(-ENAMETOOLONG); if (dentry->d_name.len > NFS_SERVER(dir)->namelen) goto out; |
fd6840714 NFS: nfs_lookup -... |
1247 1248 1249 1250 1251 1252 1253 |
/* * If we're doing an exclusive create, optimize away the lookup * but don't hash the dentry. */ if (nfs_is_exclusive_create(dir, nd)) { d_instantiate(dentry, NULL); res = NULL; |
fc0f684c2 NFS: Remove BKL f... |
1254 |
goto out; |
fd6840714 NFS: nfs_lookup -... |
1255 |
} |
1da177e4c Linux-2.6.12-rc2 |
1256 |
|
e1fb4d05d NFS: Reduce the s... |
1257 1258 1259 1260 1261 |
res = ERR_PTR(-ENOMEM); fhandle = nfs_alloc_fhandle(); fattr = nfs_alloc_fattr(); if (fhandle == NULL || fattr == NULL) goto out; |
565277f63 NFS: Fix a race i... |
1262 1263 1264 |
parent = dentry->d_parent; /* Protect against concurrent sillydeletes */ nfs_block_sillyrename(parent); |
7c5130588 NFS: lookup suppo... |
1265 |
error = NFS_PROTO(dir)->lookup(NFS_SERVER(dir)->client, dir, &dentry->d_name, fhandle, fattr); |
1da177e4c Linux-2.6.12-rc2 |
1266 1267 1268 1269 |
if (error == -ENOENT) goto no_entry; if (error < 0) { res = ERR_PTR(error); |
565277f63 NFS: Fix a race i... |
1270 |
goto out_unblock_sillyrename; |
1da177e4c Linux-2.6.12-rc2 |
1271 |
} |
e1fb4d05d NFS: Reduce the s... |
1272 |
inode = nfs_fhget(dentry->d_sb, fhandle, fattr); |
bf0c84f16 NFS: use ERR_CAST() |
1273 |
res = ERR_CAST(inode); |
03f28e3a2 NFS: Make nfs_fhg... |
1274 |
if (IS_ERR(res)) |
565277f63 NFS: Fix a race i... |
1275 |
goto out_unblock_sillyrename; |
54ceac451 NFS: Share NFS su... |
1276 |
|
1da177e4c Linux-2.6.12-rc2 |
1277 |
no_entry: |
54ceac451 NFS: Share NFS su... |
1278 |
res = d_materialise_unique(dentry, inode); |
9eaef27b3 [PATCH] VFS: Make... |
1279 1280 |
if (res != NULL) { if (IS_ERR(res)) |
565277f63 NFS: Fix a race i... |
1281 |
goto out_unblock_sillyrename; |
1da177e4c Linux-2.6.12-rc2 |
1282 |
dentry = res; |
9eaef27b3 [PATCH] VFS: Make... |
1283 |
} |
1da177e4c Linux-2.6.12-rc2 |
1284 |
nfs_set_verifier(dentry, nfs_save_change_attribute(dir)); |
565277f63 NFS: Fix a race i... |
1285 1286 |
out_unblock_sillyrename: nfs_unblock_sillyrename(parent); |
1da177e4c Linux-2.6.12-rc2 |
1287 |
out: |
e1fb4d05d NFS: Reduce the s... |
1288 1289 |
nfs_free_fattr(fattr); nfs_free_fhandle(fhandle); |
1da177e4c Linux-2.6.12-rc2 |
1290 1291 1292 1293 1294 |
return res; } #ifdef CONFIG_NFS_V4 static int nfs_open_revalidate(struct dentry *, struct nameidata *); |
f786aa90e constify dentry_o... |
1295 |
const struct dentry_operations nfs4_dentry_operations = { |
1da177e4c Linux-2.6.12-rc2 |
1296 1297 1298 |
.d_revalidate = nfs_open_revalidate, .d_delete = nfs_dentry_delete, .d_iput = nfs_dentry_iput, |
36d43a437 NFS: Use d_automo... |
1299 |
.d_automount = nfs_d_automount, |
b1942c5f8 nfs: store devnam... |
1300 |
.d_release = nfs_d_release, |
1da177e4c Linux-2.6.12-rc2 |
1301 |
}; |
1d6757fbf [PATCH] NFS: Fix ... |
1302 1303 1304 1305 |
/* * Use intent information to determine whether we need to substitute * the NFSv4-style stateful OPEN for the LOOKUP call */ |
5584c3063 NFSv4: Clean up i... |
1306 |
static int is_atomic_open(struct nameidata *nd) |
1da177e4c Linux-2.6.12-rc2 |
1307 |
{ |
1d6757fbf [PATCH] NFS: Fix ... |
1308 |
if (nd == NULL || nfs_lookup_check_intent(nd, LOOKUP_OPEN) == 0) |
1da177e4c Linux-2.6.12-rc2 |
1309 1310 1311 1312 1313 |
return 0; /* NFS does not (yet) have a stateful open for directories */ if (nd->flags & LOOKUP_DIRECTORY) return 0; /* Are we trying to write to a read only partition? */ |
2c463e954 [PATCH] r/o bind ... |
1314 |
if (__mnt_is_readonly(nd->path.mnt) && |
8a5e929dd don't translitera... |
1315 |
(nd->intent.open.flags & (O_CREAT|O_TRUNC|O_ACCMODE))) |
1da177e4c Linux-2.6.12-rc2 |
1316 1317 1318 |
return 0; return 1; } |
8a5e929dd don't translitera... |
1319 1320 1321 1322 1323 1324 1325 1326 1327 |
static fmode_t flags_to_mode(int flags) { fmode_t res = (__force fmode_t)flags & FMODE_EXEC; if ((flags & O_ACCMODE) != O_WRONLY) res |= FMODE_READ; if ((flags & O_ACCMODE) != O_RDONLY) res |= FMODE_WRITE; return res; } |
511415980 nameidata_to_nfs_... |
1328 |
static struct nfs_open_context *create_nfs_open_context(struct dentry *dentry, int open_flags) |
cd9a1c0e5 NFSv4: Clean up n... |
1329 |
{ |
5ede7b1cf pull manipulation... |
1330 |
return alloc_nfs_open_context(dentry, flags_to_mode(open_flags)); |
cd9a1c0e5 NFSv4: Clean up n... |
1331 1332 1333 1334 1335 1336 1337 1338 1339 1340 1341 1342 1343 1344 1345 |
} static int do_open(struct inode *inode, struct file *filp) { nfs_fscache_set_inode_cookie(inode, filp); return 0; } static int nfs_intent_set_file(struct nameidata *nd, struct nfs_open_context *ctx) { struct file *filp; int ret = 0; /* If the open_intent is for execute, we have an extra check to make */ if (ctx->mode & FMODE_EXEC) { |
3d4ff43d8 nfs_open_context ... |
1346 |
ret = nfs_may_open(ctx->dentry->d_inode, |
cd9a1c0e5 NFSv4: Clean up n... |
1347 1348 1349 1350 1351 |
ctx->cred, nd->intent.open.flags); if (ret < 0) goto out; } |
3d4ff43d8 nfs_open_context ... |
1352 |
filp = lookup_instantiate_filp(nd, ctx->dentry, do_open); |
cd9a1c0e5 NFSv4: Clean up n... |
1353 1354 1355 1356 1357 1358 1359 1360 |
if (IS_ERR(filp)) ret = PTR_ERR(filp); else nfs_file_set_open_context(filp, ctx); out: put_nfs_open_context(ctx); return ret; } |
1da177e4c Linux-2.6.12-rc2 |
1361 1362 |
static struct dentry *nfs_atomic_lookup(struct inode *dir, struct dentry *dentry, struct nameidata *nd) { |
cd9a1c0e5 NFSv4: Clean up n... |
1363 1364 |
struct nfs_open_context *ctx; struct iattr attr; |
1da177e4c Linux-2.6.12-rc2 |
1365 |
struct dentry *res = NULL; |
f46e0bd34 NFSv4: Further mi... |
1366 |
struct inode *inode; |
cd9a1c0e5 NFSv4: Clean up n... |
1367 |
int open_flags; |
898f635c4 NFSv4: Don't igno... |
1368 |
int err; |
1da177e4c Linux-2.6.12-rc2 |
1369 |
|
1e7cb3dc1 NFS: directory tr... |
1370 1371 1372 |
dfprintk(VFS, "NFS: atomic_lookup(%s/%ld), %s ", dir->i_sb->s_id, dir->i_ino, dentry->d_name.name); |
1da177e4c Linux-2.6.12-rc2 |
1373 |
/* Check that we are indeed trying to open this file */ |
5584c3063 NFSv4: Clean up i... |
1374 |
if (!is_atomic_open(nd)) |
1da177e4c Linux-2.6.12-rc2 |
1375 1376 1377 1378 1379 1380 |
goto no_open; if (dentry->d_name.len > NFS_SERVER(dir)->namelen) { res = ERR_PTR(-ENAMETOOLONG); goto out; } |
1da177e4c Linux-2.6.12-rc2 |
1381 |
|
d4d9cdcb4 NFS: Don't hash t... |
1382 1383 |
/* Let vfs_create() deal with O_EXCL. Instantiate, but don't hash * the dentry. */ |
3516586a4 [PATCH] make O_EX... |
1384 |
if (nd->flags & LOOKUP_EXCL) { |
d4d9cdcb4 NFS: Don't hash t... |
1385 |
d_instantiate(dentry, NULL); |
02a913a73 NFSv4: Eliminate ... |
1386 1387 |
goto out; } |
1da177e4c Linux-2.6.12-rc2 |
1388 |
|
511415980 nameidata_to_nfs_... |
1389 1390 1391 |
open_flags = nd->intent.open.flags; ctx = create_nfs_open_context(dentry, open_flags); |
cd9a1c0e5 NFSv4: Clean up n... |
1392 1393 1394 |
res = ERR_CAST(ctx); if (IS_ERR(ctx)) goto out; |
cd9a1c0e5 NFSv4: Clean up n... |
1395 1396 1397 |
if (nd->flags & LOOKUP_CREATE) { attr.ia_mode = nd->intent.open.create_mode; attr.ia_valid = ATTR_MODE; |
a8a5da996 nfs: Set MS_POSIX... |
1398 |
attr.ia_mode &= ~current_umask(); |
cd9a1c0e5 NFSv4: Clean up n... |
1399 |
} else { |
898f635c4 NFSv4: Don't igno... |
1400 |
open_flags &= ~(O_EXCL | O_CREAT); |
cd9a1c0e5 NFSv4: Clean up n... |
1401 |
attr.ia_valid = 0; |
cd9a1c0e5 NFSv4: Clean up n... |
1402 |
} |
1da177e4c Linux-2.6.12-rc2 |
1403 |
/* Open the file on the server */ |
f46e0bd34 NFSv4: Further mi... |
1404 |
nfs_block_sillyrename(dentry->d_parent); |
2b484297e NFS: Add an 'open... |
1405 |
inode = NFS_PROTO(dir)->open_context(dir, ctx, open_flags, &attr); |
f46e0bd34 NFSv4: Further mi... |
1406 1407 |
if (IS_ERR(inode)) { nfs_unblock_sillyrename(dentry->d_parent); |
cd9a1c0e5 NFSv4: Clean up n... |
1408 |
put_nfs_open_context(ctx); |
f46e0bd34 NFSv4: Further mi... |
1409 |
switch (PTR_ERR(inode)) { |
1da177e4c Linux-2.6.12-rc2 |
1410 1411 |
/* Make a negative dentry */ case -ENOENT: |
f46e0bd34 NFSv4: Further mi... |
1412 |
d_add(dentry, NULL); |
02a913a73 NFSv4: Eliminate ... |
1413 1414 |
res = NULL; goto out; |
1da177e4c Linux-2.6.12-rc2 |
1415 |
/* This turned out not to be a regular file */ |
1788ea6e3 nfs: when attempt... |
1416 |
case -EISDIR: |
6f926b5ba [NFS]: Check that... |
1417 1418 |
case -ENOTDIR: goto no_open; |
1da177e4c Linux-2.6.12-rc2 |
1419 1420 1421 |
case -ELOOP: if (!(nd->intent.open.flags & O_NOFOLLOW)) goto no_open; |
1da177e4c Linux-2.6.12-rc2 |
1422 1423 |
/* case -EINVAL: */ default: |
f46e0bd34 NFSv4: Further mi... |
1424 |
res = ERR_CAST(inode); |
1da177e4c Linux-2.6.12-rc2 |
1425 1426 |
goto out; } |
cd9a1c0e5 NFSv4: Clean up n... |
1427 |
} |
f46e0bd34 NFSv4: Further mi... |
1428 |
res = d_add_unique(dentry, inode); |
898f635c4 NFSv4: Don't igno... |
1429 |
nfs_unblock_sillyrename(dentry->d_parent); |
f46e0bd34 NFSv4: Further mi... |
1430 |
if (res != NULL) { |
3d4ff43d8 nfs_open_context ... |
1431 1432 |
dput(ctx->dentry); ctx->dentry = dget(res); |
1da177e4c Linux-2.6.12-rc2 |
1433 |
dentry = res; |
f46e0bd34 NFSv4: Further mi... |
1434 |
} |
898f635c4 NFSv4: Don't igno... |
1435 1436 1437 1438 1439 1440 |
err = nfs_intent_set_file(nd, ctx); if (err < 0) { if (res != NULL) dput(res); return ERR_PTR(err); } |
1da177e4c Linux-2.6.12-rc2 |
1441 |
out: |
f46e0bd34 NFSv4: Further mi... |
1442 |
nfs_set_verifier(dentry, nfs_save_change_attribute(dir)); |
1da177e4c Linux-2.6.12-rc2 |
1443 1444 1445 1446 1447 1448 1449 1450 |
return res; no_open: return nfs_lookup(dir, dentry, nd); } static int nfs_open_revalidate(struct dentry *dentry, struct nameidata *nd) { struct dentry *parent = NULL; |
657e94b67 nfs: add missing ... |
1451 |
struct inode *inode; |
1da177e4c Linux-2.6.12-rc2 |
1452 |
struct inode *dir; |
b8d4caddd NFSv4: Clean up n... |
1453 |
struct nfs_open_context *ctx; |
1da177e4c Linux-2.6.12-rc2 |
1454 |
int openflags, ret = 0; |
657e94b67 nfs: add missing ... |
1455 1456 1457 1458 |
if (nd->flags & LOOKUP_RCU) return -ECHILD; inode = dentry->d_inode; |
1f063d2cd NFSv4: Don't atte... |
1459 |
if (!is_atomic_open(nd) || d_mountpoint(dentry)) |
5584c3063 NFSv4: Clean up i... |
1460 |
goto no_open; |
2b484297e NFS: Add an 'open... |
1461 |
|
1da177e4c Linux-2.6.12-rc2 |
1462 1463 |
parent = dget_parent(dentry); dir = parent->d_inode; |
2b484297e NFS: Add an 'open... |
1464 |
|
1da177e4c Linux-2.6.12-rc2 |
1465 1466 1467 |
/* We can't create new files in nfs_open_revalidate(), so we * optimize away revalidation of negative dentries. */ |
216d5d068 NFSv4: Use NFSv2/... |
1468 1469 1470 |
if (inode == NULL) { if (!nfs_neg_need_reval(dir, dentry, nd)) ret = 1; |
1da177e4c Linux-2.6.12-rc2 |
1471 |
goto out; |
216d5d068 NFSv4: Use NFSv2/... |
1472 |
} |
1da177e4c Linux-2.6.12-rc2 |
1473 1474 |
/* NFS only supports OPEN on regular files */ if (!S_ISREG(inode->i_mode)) |
5584c3063 NFSv4: Clean up i... |
1475 |
goto no_open_dput; |
1da177e4c Linux-2.6.12-rc2 |
1476 1477 1478 |
openflags = nd->intent.open.flags; /* We cannot do exclusive creation on a positive dentry */ if ((openflags & (O_CREAT|O_EXCL)) == (O_CREAT|O_EXCL)) |
5584c3063 NFSv4: Clean up i... |
1479 |
goto no_open_dput; |
1da177e4c Linux-2.6.12-rc2 |
1480 |
/* We can't create new files, or truncate existing ones here */ |
0a377cff9 NFS: Fix an Oops ... |
1481 |
openflags &= ~(O_CREAT|O_EXCL|O_TRUNC); |
1da177e4c Linux-2.6.12-rc2 |
1482 |
|
511415980 nameidata_to_nfs_... |
1483 |
ctx = create_nfs_open_context(dentry, openflags); |
b8d4caddd NFSv4: Clean up n... |
1484 1485 1486 |
ret = PTR_ERR(ctx); if (IS_ERR(ctx)) goto out; |
1da177e4c Linux-2.6.12-rc2 |
1487 |
/* |
1b1dcc1b5 [PATCH] mutex sub... |
1488 |
* Note: we're not holding inode->i_mutex and so may be racing with |
1da177e4c Linux-2.6.12-rc2 |
1489 1490 1491 |
* operations that change the directory. We therefore save the * change attribute *before* we do the RPC call. */ |
2b484297e NFS: Add an 'open... |
1492 |
inode = NFS_PROTO(dir)->open_context(dir, ctx, openflags, NULL); |
535918f14 NFSv4: Further cl... |
1493 1494 1495 1496 1497 1498 1499 1500 1501 1502 1503 1504 1505 1506 |
if (IS_ERR(inode)) { ret = PTR_ERR(inode); switch (ret) { case -EPERM: case -EACCES: case -EDQUOT: case -ENOSPC: case -EROFS: goto out_put_ctx; default: goto out_drop; } } iput(inode); |
898f635c4 NFSv4: Don't igno... |
1507 |
if (inode != dentry->d_inode) |
535918f14 NFSv4: Further cl... |
1508 |
goto out_drop; |
898f635c4 NFSv4: Don't igno... |
1509 1510 1511 1512 1513 |
nfs_set_verifier(dentry, nfs_save_change_attribute(dir)); ret = nfs_intent_set_file(nd, ctx); if (ret >= 0) ret = 1; |
1da177e4c Linux-2.6.12-rc2 |
1514 1515 |
out: dput(parent); |
1da177e4c Linux-2.6.12-rc2 |
1516 |
return ret; |
535918f14 NFSv4: Further cl... |
1517 1518 1519 1520 1521 1522 |
out_drop: d_drop(dentry); ret = 0; out_put_ctx: put_nfs_open_context(ctx); goto out; |
5584c3063 NFSv4: Clean up i... |
1523 |
no_open_dput: |
1da177e4c Linux-2.6.12-rc2 |
1524 |
dput(parent); |
5584c3063 NFSv4: Clean up i... |
1525 |
no_open: |
1da177e4c Linux-2.6.12-rc2 |
1526 1527 |
return nfs_lookup_revalidate(dentry, nd); } |
c0204fd2b NFS: Clean up nfs... |
1528 |
|
4acdaf27e switch ->create()... |
1529 1530 |
static int nfs_open_create(struct inode *dir, struct dentry *dentry, umode_t mode, struct nameidata *nd) |
c0204fd2b NFS: Clean up nfs... |
1531 1532 1533 1534 |
{ struct nfs_open_context *ctx = NULL; struct iattr attr; int error; |
8a5e929dd don't translitera... |
1535 |
int open_flags = O_CREAT|O_EXCL; |
c0204fd2b NFS: Clean up nfs... |
1536 1537 1538 1539 1540 1541 1542 |
dfprintk(VFS, "NFS: create(%s/%ld), %s ", dir->i_sb->s_id, dir->i_ino, dentry->d_name.name); attr.ia_mode = mode; attr.ia_valid = ATTR_MODE; |
dd7dd556e no need to check ... |
1543 |
if (nd) |
c0204fd2b NFS: Clean up nfs... |
1544 |
open_flags = nd->intent.open.flags; |
f7c85868f fix mknod() on nf... |
1545 1546 1547 1548 |
ctx = create_nfs_open_context(dentry, open_flags); error = PTR_ERR(ctx); if (IS_ERR(ctx)) goto out_err_drop; |
c0204fd2b NFS: Clean up nfs... |
1549 1550 1551 1552 |
error = NFS_PROTO(dir)->create(dir, dentry, &attr, open_flags, ctx); if (error != 0) goto out_put_ctx; |
dd7dd556e no need to check ... |
1553 |
if (nd) { |
898f635c4 NFSv4: Don't igno... |
1554 1555 1556 |
error = nfs_intent_set_file(nd, ctx); if (error < 0) goto out_err; |
f7c85868f fix mknod() on nf... |
1557 1558 |
} else { put_nfs_open_context(ctx); |
898f635c4 NFSv4: Don't igno... |
1559 |
} |
c0204fd2b NFS: Clean up nfs... |
1560 1561 |
return 0; out_put_ctx: |
f7c85868f fix mknod() on nf... |
1562 |
put_nfs_open_context(ctx); |
898f635c4 NFSv4: Don't igno... |
1563 |
out_err_drop: |
c0204fd2b NFS: Clean up nfs... |
1564 |
d_drop(dentry); |
898f635c4 NFSv4: Don't igno... |
1565 |
out_err: |
c0204fd2b NFS: Clean up nfs... |
1566 1567 |
return error; } |
1da177e4c Linux-2.6.12-rc2 |
1568 |
#endif /* CONFIG_NFSV4 */ |
1da177e4c Linux-2.6.12-rc2 |
1569 1570 1571 1572 1573 1574 |
/* * Code common to create, mkdir, and mknod. */ int nfs_instantiate(struct dentry *dentry, struct nfs_fh *fhandle, struct nfs_fattr *fattr) { |
fab728e15 NFS: Ensure nfs_i... |
1575 1576 |
struct dentry *parent = dget_parent(dentry); struct inode *dir = parent->d_inode; |
1da177e4c Linux-2.6.12-rc2 |
1577 1578 |
struct inode *inode; int error = -EACCES; |
fab728e15 NFS: Ensure nfs_i... |
1579 |
d_drop(dentry); |
1da177e4c Linux-2.6.12-rc2 |
1580 1581 |
/* We may have been initialized further down */ if (dentry->d_inode) |
fab728e15 NFS: Ensure nfs_i... |
1582 |
goto out; |
1da177e4c Linux-2.6.12-rc2 |
1583 |
if (fhandle->size == 0) { |
7c5130588 NFS: lookup suppo... |
1584 |
error = NFS_PROTO(dir)->lookup(NFS_SERVER(dir)->client, dir, &dentry->d_name, fhandle, fattr); |
1da177e4c Linux-2.6.12-rc2 |
1585 |
if (error) |
fab728e15 NFS: Ensure nfs_i... |
1586 |
goto out_error; |
1da177e4c Linux-2.6.12-rc2 |
1587 |
} |
5724ab378 NFS: nfs_instanti... |
1588 |
nfs_set_verifier(dentry, nfs_save_change_attribute(dir)); |
1da177e4c Linux-2.6.12-rc2 |
1589 1590 |
if (!(fattr->valid & NFS_ATTR_FATTR)) { struct nfs_server *server = NFS_SB(dentry->d_sb); |
8fa5c000d NFS: Move rpc_ops... |
1591 |
error = server->nfs_client->rpc_ops->getattr(server, fhandle, fattr); |
1da177e4c Linux-2.6.12-rc2 |
1592 |
if (error < 0) |
fab728e15 NFS: Ensure nfs_i... |
1593 |
goto out_error; |
1da177e4c Linux-2.6.12-rc2 |
1594 |
} |
1da177e4c Linux-2.6.12-rc2 |
1595 |
inode = nfs_fhget(dentry->d_sb, fhandle, fattr); |
03f28e3a2 NFS: Make nfs_fhg... |
1596 1597 |
error = PTR_ERR(inode); if (IS_ERR(inode)) |
fab728e15 NFS: Ensure nfs_i... |
1598 1599 1600 1601 |
goto out_error; d_add(dentry, inode); out: dput(parent); |
1da177e4c Linux-2.6.12-rc2 |
1602 |
return 0; |
fab728e15 NFS: Ensure nfs_i... |
1603 1604 1605 1606 |
out_error: nfs_mark_for_revalidate(dir); dput(parent); return error; |
1da177e4c Linux-2.6.12-rc2 |
1607 1608 1609 1610 1611 1612 1613 1614 |
} /* * Following a failed create operation, we drop the dentry rather * than retain a negative dentry. This avoids a problem in the event * that the operation succeeded on the server, but an error in the * reply path made it appear to have failed. */ |
4acdaf27e switch ->create()... |
1615 1616 |
static int nfs_create(struct inode *dir, struct dentry *dentry, umode_t mode, struct nameidata *nd) |
1da177e4c Linux-2.6.12-rc2 |
1617 1618 1619 |
{ struct iattr attr; int error; |
8a5e929dd don't translitera... |
1620 |
int open_flags = O_CREAT|O_EXCL; |
1da177e4c Linux-2.6.12-rc2 |
1621 |
|
1e7cb3dc1 NFS: directory tr... |
1622 1623 1624 |
dfprintk(VFS, "NFS: create(%s/%ld), %s ", dir->i_sb->s_id, dir->i_ino, dentry->d_name.name); |
1da177e4c Linux-2.6.12-rc2 |
1625 1626 1627 |
attr.ia_mode = mode; attr.ia_valid = ATTR_MODE; |
dd7dd556e no need to check ... |
1628 |
if (nd) |
8a0eebf66 NFS: Fix NFSv3 ex... |
1629 1630 1631 |
open_flags = nd->intent.open.flags; error = NFS_PROTO(dir)->create(dir, dentry, &attr, open_flags, NULL); |
1da177e4c Linux-2.6.12-rc2 |
1632 1633 |
if (error != 0) goto out_err; |
1da177e4c Linux-2.6.12-rc2 |
1634 1635 |
return 0; out_err: |
1da177e4c Linux-2.6.12-rc2 |
1636 1637 1638 1639 1640 1641 1642 1643 |
d_drop(dentry); return error; } /* * See comments for nfs_proc_create regarding failed operations. */ static int |
1a67aafb5 switch ->mknod() ... |
1644 |
nfs_mknod(struct inode *dir, struct dentry *dentry, umode_t mode, dev_t rdev) |
1da177e4c Linux-2.6.12-rc2 |
1645 1646 1647 |
{ struct iattr attr; int status; |
1e7cb3dc1 NFS: directory tr... |
1648 1649 1650 |
dfprintk(VFS, "NFS: mknod(%s/%ld), %s ", dir->i_sb->s_id, dir->i_ino, dentry->d_name.name); |
1da177e4c Linux-2.6.12-rc2 |
1651 1652 1653 1654 1655 1656 |
if (!new_valid_dev(rdev)) return -EINVAL; attr.ia_mode = mode; attr.ia_valid = ATTR_MODE; |
1da177e4c Linux-2.6.12-rc2 |
1657 |
status = NFS_PROTO(dir)->mknod(dir, dentry, &attr, rdev); |
1da177e4c Linux-2.6.12-rc2 |
1658 1659 |
if (status != 0) goto out_err; |
1da177e4c Linux-2.6.12-rc2 |
1660 1661 |
return 0; out_err: |
1da177e4c Linux-2.6.12-rc2 |
1662 1663 1664 1665 1666 1667 1668 |
d_drop(dentry); return status; } /* * See comments for nfs_proc_create regarding failed operations. */ |
18bb1db3e switch vfs_mkdir(... |
1669 |
static int nfs_mkdir(struct inode *dir, struct dentry *dentry, umode_t mode) |
1da177e4c Linux-2.6.12-rc2 |
1670 1671 1672 |
{ struct iattr attr; int error; |
1e7cb3dc1 NFS: directory tr... |
1673 1674 1675 |
dfprintk(VFS, "NFS: mkdir(%s/%ld), %s ", dir->i_sb->s_id, dir->i_ino, dentry->d_name.name); |
1da177e4c Linux-2.6.12-rc2 |
1676 1677 1678 |
attr.ia_valid = ATTR_MODE; attr.ia_mode = mode | S_IFDIR; |
1da177e4c Linux-2.6.12-rc2 |
1679 |
error = NFS_PROTO(dir)->mkdir(dir, dentry, &attr); |
1da177e4c Linux-2.6.12-rc2 |
1680 1681 |
if (error != 0) goto out_err; |
1da177e4c Linux-2.6.12-rc2 |
1682 1683 1684 |
return 0; out_err: d_drop(dentry); |
1da177e4c Linux-2.6.12-rc2 |
1685 1686 |
return error; } |
d45b9d8ba NFS: Handle -ENOE... |
1687 1688 1689 1690 1691 |
static void nfs_dentry_handle_enoent(struct dentry *dentry) { if (dentry->d_inode != NULL && !d_unhashed(dentry)) d_delete(dentry); } |
1da177e4c Linux-2.6.12-rc2 |
1692 1693 1694 |
static int nfs_rmdir(struct inode *dir, struct dentry *dentry) { int error; |
1e7cb3dc1 NFS: directory tr... |
1695 1696 1697 |
dfprintk(VFS, "NFS: rmdir(%s/%ld), %s ", dir->i_sb->s_id, dir->i_ino, dentry->d_name.name); |
1da177e4c Linux-2.6.12-rc2 |
1698 |
|
1da177e4c Linux-2.6.12-rc2 |
1699 1700 1701 |
error = NFS_PROTO(dir)->rmdir(dir, &dentry->d_name); /* Ensure the VFS deletes this inode */ if (error == 0 && dentry->d_inode != NULL) |
ce71ec368 [PATCH] r/o bind ... |
1702 |
clear_nlink(dentry->d_inode); |
d45b9d8ba NFS: Handle -ENOE... |
1703 1704 |
else if (error == -ENOENT) nfs_dentry_handle_enoent(dentry); |
1da177e4c Linux-2.6.12-rc2 |
1705 1706 1707 |
return error; } |
1da177e4c Linux-2.6.12-rc2 |
1708 1709 1710 1711 1712 1713 1714 1715 1716 1717 1718 1719 1720 1721 1722 1723 1724 1725 1726 1727 1728 1729 |
/* * Remove a file after making sure there are no pending writes, * and after checking that the file has only one user. * * We invalidate the attribute cache and free the inode prior to the operation * to avoid possible races if the server reuses the inode. */ static int nfs_safe_remove(struct dentry *dentry) { struct inode *dir = dentry->d_parent->d_inode; struct inode *inode = dentry->d_inode; int error = -EBUSY; dfprintk(VFS, "NFS: safe_remove(%s/%s) ", dentry->d_parent->d_name.name, dentry->d_name.name); /* If the dentry was sillyrenamed, we simply call d_delete() */ if (dentry->d_flags & DCACHE_NFSFS_RENAMED) { error = 0; goto out; } |
1da177e4c Linux-2.6.12-rc2 |
1730 |
if (inode != NULL) { |
cae7a073a NFSv4: Return del... |
1731 |
nfs_inode_return_delegation(inode); |
1da177e4c Linux-2.6.12-rc2 |
1732 1733 1734 |
error = NFS_PROTO(dir)->remove(dir, &dentry->d_name); /* The VFS may want to delete this inode */ if (error == 0) |
1b83d7070 NFS: Protect inod... |
1735 |
nfs_drop_nlink(inode); |
5ba7cc480 NFS: Fix post-op ... |
1736 |
nfs_mark_for_revalidate(inode); |
1da177e4c Linux-2.6.12-rc2 |
1737 1738 |
} else error = NFS_PROTO(dir)->remove(dir, &dentry->d_name); |
d45b9d8ba NFS: Handle -ENOE... |
1739 1740 |
if (error == -ENOENT) nfs_dentry_handle_enoent(dentry); |
1da177e4c Linux-2.6.12-rc2 |
1741 1742 1743 1744 1745 1746 1747 1748 1749 1750 1751 1752 1753 1754 1755 1756 1757 |
out: return error; } /* We do silly rename. In case sillyrename() returns -EBUSY, the inode * belongs to an active ".nfs..." file and we return -EBUSY. * * If sillyrename() returns 0, we do nothing, otherwise we unlink. */ static int nfs_unlink(struct inode *dir, struct dentry *dentry) { int error; int need_rehash = 0; dfprintk(VFS, "NFS: unlink(%s/%ld, %s) ", dir->i_sb->s_id, dir->i_ino, dentry->d_name.name); |
1da177e4c Linux-2.6.12-rc2 |
1758 |
spin_lock(&dentry->d_lock); |
b7ab39f63 fs: dcache scale ... |
1759 |
if (dentry->d_count > 1) { |
1da177e4c Linux-2.6.12-rc2 |
1760 |
spin_unlock(&dentry->d_lock); |
ccfeb5062 NFS: Fix up "rm -... |
1761 1762 |
/* Start asynchronous writeout of the inode */ write_inode_now(dentry->d_inode, 0); |
1da177e4c Linux-2.6.12-rc2 |
1763 |
error = nfs_sillyrename(dir, dentry); |
1da177e4c Linux-2.6.12-rc2 |
1764 1765 1766 1767 1768 1769 1770 |
return error; } if (!d_unhashed(dentry)) { __d_drop(dentry); need_rehash = 1; } spin_unlock(&dentry->d_lock); |
1da177e4c Linux-2.6.12-rc2 |
1771 |
error = nfs_safe_remove(dentry); |
d45b9d8ba NFS: Handle -ENOE... |
1772 |
if (!error || error == -ENOENT) { |
1da177e4c Linux-2.6.12-rc2 |
1773 1774 1775 |
nfs_set_verifier(dentry, nfs_save_change_attribute(dir)); } else if (need_rehash) d_rehash(dentry); |
1da177e4c Linux-2.6.12-rc2 |
1776 1777 |
return error; } |
873101b33 NFS: copy symlink... |
1778 1779 1780 1781 1782 1783 1784 1785 1786 1787 1788 1789 1790 1791 1792 1793 |
/* * To create a symbolic link, most file systems instantiate a new inode, * add a page to it containing the path, then write it out to the disk * using prepare_write/commit_write. * * Unfortunately the NFS client can't create the in-core inode first * because it needs a file handle to create an in-core inode (see * fs/nfs/inode.c:nfs_fhget). We only have a file handle *after* the * symlink request has completed on the server. * * So instead we allocate a raw page, copy the symname into it, then do * the SYMLINK request with the page as the buffer. If it succeeds, we * now have a new file handle and can instantiate an in-core NFS inode * and move the raw page into its mapping. */ static int nfs_symlink(struct inode *dir, struct dentry *dentry, const char *symname) |
1da177e4c Linux-2.6.12-rc2 |
1794 |
{ |
873101b33 NFS: copy symlink... |
1795 1796 1797 |
struct pagevec lru_pvec; struct page *page; char *kaddr; |
1da177e4c Linux-2.6.12-rc2 |
1798 |
struct iattr attr; |
873101b33 NFS: copy symlink... |
1799 |
unsigned int pathlen = strlen(symname); |
1da177e4c Linux-2.6.12-rc2 |
1800 1801 1802 1803 1804 |
int error; dfprintk(VFS, "NFS: symlink(%s/%ld, %s, %s) ", dir->i_sb->s_id, dir->i_ino, dentry->d_name.name, symname); |
873101b33 NFS: copy symlink... |
1805 1806 |
if (pathlen > PAGE_SIZE) return -ENAMETOOLONG; |
1da177e4c Linux-2.6.12-rc2 |
1807 |
|
873101b33 NFS: copy symlink... |
1808 1809 |
attr.ia_mode = S_IFLNK | S_IRWXUGO; attr.ia_valid = ATTR_MODE; |
1da177e4c Linux-2.6.12-rc2 |
1810 |
|
83d93f222 NFS: Use GFP_HIGH... |
1811 |
page = alloc_page(GFP_HIGHUSER); |
76566991f NFS: Remove BKL f... |
1812 |
if (!page) |
873101b33 NFS: copy symlink... |
1813 |
return -ENOMEM; |
873101b33 NFS: copy symlink... |
1814 1815 1816 1817 1818 1819 |
kaddr = kmap_atomic(page, KM_USER0); memcpy(kaddr, symname, pathlen); if (pathlen < PAGE_SIZE) memset(kaddr + pathlen, 0, PAGE_SIZE - pathlen); kunmap_atomic(kaddr, KM_USER0); |
94a6d7532 NFS: Use cached p... |
1820 |
error = NFS_PROTO(dir)->symlink(dir, dentry, page, pathlen, &attr); |
873101b33 NFS: copy symlink... |
1821 1822 1823 1824 1825 |
if (error != 0) { dfprintk(VFS, "NFS: symlink(%s/%ld, %s, %s) error %d ", dir->i_sb->s_id, dir->i_ino, dentry->d_name.name, symname, error); |
1da177e4c Linux-2.6.12-rc2 |
1826 |
d_drop(dentry); |
873101b33 NFS: copy symlink... |
1827 |
__free_page(page); |
873101b33 NFS: copy symlink... |
1828 1829 1830 1831 1832 1833 1834 1835 1836 1837 |
return error; } /* * No big deal if we can't add this page to the page cache here. * READLINK will get the missing page from the server if needed. */ pagevec_init(&lru_pvec, 0); if (!add_to_page_cache(page, dentry->d_inode->i_mapping, 0, GFP_KERNEL)) { |
39cf8a137 [PATCH] NFS: fix ... |
1838 |
pagevec_add(&lru_pvec, page); |
4f98a2fee vmscan: split LRU... |
1839 |
pagevec_lru_add_file(&lru_pvec); |
873101b33 NFS: copy symlink... |
1840 1841 1842 1843 |
SetPageUptodate(page); unlock_page(page); } else __free_page(page); |
873101b33 NFS: copy symlink... |
1844 |
return 0; |
1da177e4c Linux-2.6.12-rc2 |
1845 1846 1847 1848 1849 1850 1851 1852 1853 1854 1855 1856 |
} static int nfs_link(struct dentry *old_dentry, struct inode *dir, struct dentry *dentry) { struct inode *inode = old_dentry->d_inode; int error; dfprintk(VFS, "NFS: link(%s/%s -> %s/%s) ", old_dentry->d_parent->d_name.name, old_dentry->d_name.name, dentry->d_parent->d_name.name, dentry->d_name.name); |
9a3936aac NFSv4: The link()... |
1857 |
nfs_inode_return_delegation(inode); |
9697d2342 NFS: Ensure that ... |
1858 |
d_drop(dentry); |
1da177e4c Linux-2.6.12-rc2 |
1859 |
error = NFS_PROTO(dir)->link(inode, dir, &dentry->d_name); |
cf8095561 NFS: Ensure that ... |
1860 |
if (error == 0) { |
7de9c6ee3 new helper: ihold() |
1861 |
ihold(inode); |
9697d2342 NFS: Ensure that ... |
1862 |
d_add(dentry, inode); |
cf8095561 NFS: Ensure that ... |
1863 |
} |
1da177e4c Linux-2.6.12-rc2 |
1864 1865 1866 1867 1868 1869 1870 1871 1872 1873 1874 1875 1876 1877 1878 1879 1880 1881 1882 1883 1884 1885 1886 1887 1888 1889 1890 1891 1892 1893 1894 1895 1896 1897 |
return error; } /* * RENAME * FIXME: Some nfsds, like the Linux user space nfsd, may generate a * different file handle for the same inode after a rename (e.g. when * moving to a different directory). A fail-safe method to do so would * be to look up old_dir/old_name, create a link to new_dir/new_name and * rename the old file using the sillyrename stuff. This way, the original * file in old_dir will go away when the last process iput()s the inode. * * FIXED. * * It actually works quite well. One needs to have the possibility for * at least one ".nfs..." file in each directory the file ever gets * moved or linked to which happens automagically with the new * implementation that only depends on the dcache stuff instead of * using the inode layer * * Unfortunately, things are a little more complicated than indicated * above. For a cross-directory move, we want to make sure we can get * rid of the old inode after the operation. This means there must be * no pending writes (if it's a file), and the use count must be 1. * If these conditions are met, we can drop the dentries before doing * the rename. */ static int nfs_rename(struct inode *old_dir, struct dentry *old_dentry, struct inode *new_dir, struct dentry *new_dentry) { struct inode *old_inode = old_dentry->d_inode; struct inode *new_inode = new_dentry->d_inode; struct dentry *dentry = NULL, *rehash = NULL; int error = -EBUSY; |
1da177e4c Linux-2.6.12-rc2 |
1898 1899 1900 1901 |
dfprintk(VFS, "NFS: rename(%s/%s -> %s/%s, ct=%d) ", old_dentry->d_parent->d_name.name, old_dentry->d_name.name, new_dentry->d_parent->d_name.name, new_dentry->d_name.name, |
b7ab39f63 fs: dcache scale ... |
1902 |
new_dentry->d_count); |
1da177e4c Linux-2.6.12-rc2 |
1903 1904 |
/* |
28f79a1a6 nfs: fix comments... |
1905 1906 1907 1908 |
* For non-directories, check whether the target is busy and if so, * make a copy of the dentry and then do a silly-rename. If the * silly-rename succeeds, the copied dentry is hashed and becomes * the new target. |
1da177e4c Linux-2.6.12-rc2 |
1909 |
*/ |
27226104e nfs: dont unhash ... |
1910 1911 1912 1913 1914 1915 1916 1917 1918 |
if (new_inode && !S_ISDIR(new_inode->i_mode)) { /* * To prevent any new references to the target during the * rename, we unhash the dentry in advance. */ if (!d_unhashed(new_dentry)) { d_drop(new_dentry); rehash = new_dentry; } |
1da177e4c Linux-2.6.12-rc2 |
1919 |
|
b7ab39f63 fs: dcache scale ... |
1920 |
if (new_dentry->d_count > 2) { |
27226104e nfs: dont unhash ... |
1921 1922 1923 1924 1925 1926 1927 1928 1929 1930 |
int err; /* copy the target dentry's name */ dentry = d_alloc(new_dentry->d_parent, &new_dentry->d_name); if (!dentry) goto out; /* silly-rename the existing target ... */ err = nfs_sillyrename(new_dir, new_dentry); |
24e93025e nfs: clean up sil... |
1931 |
if (err) |
27226104e nfs: dont unhash ... |
1932 |
goto out; |
24e93025e nfs: clean up sil... |
1933 1934 |
new_dentry = dentry; |
56335936d nfs: fix oops in ... |
1935 |
rehash = NULL; |
24e93025e nfs: clean up sil... |
1936 |
new_inode = NULL; |
27226104e nfs: dont unhash ... |
1937 |
} |
b1e4adf4e NFS: Fix the noti... |
1938 |
} |
1da177e4c Linux-2.6.12-rc2 |
1939 |
|
cae7a073a NFSv4: Return del... |
1940 |
nfs_inode_return_delegation(old_inode); |
b1e4adf4e NFS: Fix the noti... |
1941 |
if (new_inode != NULL) |
24174119c NFSv4: Ensure tha... |
1942 |
nfs_inode_return_delegation(new_inode); |
1da177e4c Linux-2.6.12-rc2 |
1943 |
|
1da177e4c Linux-2.6.12-rc2 |
1944 1945 |
error = NFS_PROTO(old_dir)->rename(old_dir, &old_dentry->d_name, new_dir, &new_dentry->d_name); |
5ba7cc480 NFS: Fix post-op ... |
1946 |
nfs_mark_for_revalidate(old_inode); |
1da177e4c Linux-2.6.12-rc2 |
1947 1948 1949 1950 |
out: if (rehash) d_rehash(rehash); if (!error) { |
b1e4adf4e NFS: Fix the noti... |
1951 1952 |
if (new_inode != NULL) nfs_drop_nlink(new_inode); |
349457ccf [PATCH] Allow fil... |
1953 |
d_move(old_dentry, new_dentry); |
8fb559f87 NFS: Eliminate nf... |
1954 1955 |
nfs_set_verifier(new_dentry, nfs_save_change_attribute(new_dir)); |
d45b9d8ba NFS: Handle -ENOE... |
1956 1957 |
} else if (error == -ENOENT) nfs_dentry_handle_enoent(old_dentry); |
1da177e4c Linux-2.6.12-rc2 |
1958 1959 1960 1961 |
/* new dentry created? */ if (dentry) dput(dentry); |
1da177e4c Linux-2.6.12-rc2 |
1962 1963 |
return error; } |
cfcea3e8c NFS: Add a global... |
1964 1965 1966 |
static DEFINE_SPINLOCK(nfs_access_lru_lock); static LIST_HEAD(nfs_access_lru_list); static atomic_long_t nfs_access_nr_entries; |
1c3c07e9f NFS: Add a new AC... |
1967 1968 1969 1970 |
static void nfs_access_free_entry(struct nfs_access_entry *entry) { put_rpccred(entry->cred); kfree(entry); |
cfcea3e8c NFS: Add a global... |
1971 1972 1973 |
smp_mb__before_atomic_dec(); atomic_long_dec(&nfs_access_nr_entries); smp_mb__after_atomic_dec(); |
1c3c07e9f NFS: Add a new AC... |
1974 |
} |
1a81bb8a1 NFS: Clean up nfs... |
1975 1976 1977 1978 1979 1980 1981 1982 1983 1984 |
static void nfs_access_free_list(struct list_head *head) { struct nfs_access_entry *cache; while (!list_empty(head)) { cache = list_entry(head->next, struct nfs_access_entry, lru); list_del(&cache->lru); nfs_access_free_entry(cache); } } |
1495f230f vmscan: change sh... |
1985 1986 |
int nfs_access_cache_shrinker(struct shrinker *shrink, struct shrink_control *sc) |
979df72e6 NFS: Add an ACCES... |
1987 1988 |
{ LIST_HEAD(head); |
aa510da5b NFS: We must use ... |
1989 |
struct nfs_inode *nfsi, *next; |
979df72e6 NFS: Add an ACCES... |
1990 |
struct nfs_access_entry *cache; |
1495f230f vmscan: change sh... |
1991 1992 |
int nr_to_scan = sc->nr_to_scan; gfp_t gfp_mask = sc->gfp_mask; |
979df72e6 NFS: Add an ACCES... |
1993 |
|
61d5eb298 NFS: Don't run nf... |
1994 1995 |
if ((gfp_mask & GFP_KERNEL) != GFP_KERNEL) return (nr_to_scan == 0) ? 0 : -1; |
9c7e7e233 NFS: Don't call i... |
1996 |
|
a50f7951a NFS: Fix an Oops ... |
1997 |
spin_lock(&nfs_access_lru_lock); |
aa510da5b NFS: We must use ... |
1998 |
list_for_each_entry_safe(nfsi, next, &nfs_access_lru_list, access_cache_inode_lru) { |
979df72e6 NFS: Add an ACCES... |
1999 2000 2001 2002 |
struct inode *inode; if (nr_to_scan-- == 0) break; |
9c7e7e233 NFS: Don't call i... |
2003 |
inode = &nfsi->vfs_inode; |
979df72e6 NFS: Add an ACCES... |
2004 2005 2006 2007 2008 2009 2010 2011 2012 2013 2014 2015 2016 |
spin_lock(&inode->i_lock); if (list_empty(&nfsi->access_cache_entry_lru)) goto remove_lru_entry; cache = list_entry(nfsi->access_cache_entry_lru.next, struct nfs_access_entry, lru); list_move(&cache->lru, &head); rb_erase(&cache->rb_node, &nfsi->access_cache); if (!list_empty(&nfsi->access_cache_entry_lru)) list_move_tail(&nfsi->access_cache_inode_lru, &nfs_access_lru_list); else { remove_lru_entry: list_del_init(&nfsi->access_cache_inode_lru); |
9c7e7e233 NFS: Don't call i... |
2017 |
smp_mb__before_clear_bit(); |
979df72e6 NFS: Add an ACCES... |
2018 |
clear_bit(NFS_INO_ACL_LRU_SET, &nfsi->flags); |
9c7e7e233 NFS: Don't call i... |
2019 |
smp_mb__after_clear_bit(); |
979df72e6 NFS: Add an ACCES... |
2020 |
} |
59844a9bd NFS: Fix a lock i... |
2021 |
spin_unlock(&inode->i_lock); |
979df72e6 NFS: Add an ACCES... |
2022 2023 |
} spin_unlock(&nfs_access_lru_lock); |
1a81bb8a1 NFS: Clean up nfs... |
2024 |
nfs_access_free_list(&head); |
979df72e6 NFS: Add an ACCES... |
2025 2026 |
return (atomic_long_read(&nfs_access_nr_entries) / 100) * sysctl_vfs_cache_pressure; } |
1a81bb8a1 NFS: Clean up nfs... |
2027 |
static void __nfs_access_zap_cache(struct nfs_inode *nfsi, struct list_head *head) |
1da177e4c Linux-2.6.12-rc2 |
2028 |
{ |
1c3c07e9f NFS: Add a new AC... |
2029 |
struct rb_root *root_node = &nfsi->access_cache; |
1a81bb8a1 NFS: Clean up nfs... |
2030 |
struct rb_node *n; |
1c3c07e9f NFS: Add a new AC... |
2031 2032 2033 2034 2035 2036 |
struct nfs_access_entry *entry; /* Unhook entries from the cache */ while ((n = rb_first(root_node)) != NULL) { entry = rb_entry(n, struct nfs_access_entry, rb_node); rb_erase(n, root_node); |
1a81bb8a1 NFS: Clean up nfs... |
2037 |
list_move(&entry->lru, head); |
1c3c07e9f NFS: Add a new AC... |
2038 2039 |
} nfsi->cache_validity &= ~NFS_INO_INVALID_ACCESS; |
1da177e4c Linux-2.6.12-rc2 |
2040 |
} |
1c3c07e9f NFS: Add a new AC... |
2041 |
void nfs_access_zap_cache(struct inode *inode) |
1da177e4c Linux-2.6.12-rc2 |
2042 |
{ |
1a81bb8a1 NFS: Clean up nfs... |
2043 2044 2045 2046 |
LIST_HEAD(head); if (test_bit(NFS_INO_ACL_LRU_SET, &NFS_I(inode)->flags) == 0) return; |
cfcea3e8c NFS: Add a global... |
2047 |
/* Remove from global LRU init */ |
1a81bb8a1 NFS: Clean up nfs... |
2048 2049 |
spin_lock(&nfs_access_lru_lock); if (test_and_clear_bit(NFS_INO_ACL_LRU_SET, &NFS_I(inode)->flags)) |
cfcea3e8c NFS: Add a global... |
2050 |
list_del_init(&NFS_I(inode)->access_cache_inode_lru); |
cfcea3e8c NFS: Add a global... |
2051 |
|
1c3c07e9f NFS: Add a new AC... |
2052 |
spin_lock(&inode->i_lock); |
1a81bb8a1 NFS: Clean up nfs... |
2053 2054 2055 2056 |
__nfs_access_zap_cache(NFS_I(inode), &head); spin_unlock(&inode->i_lock); spin_unlock(&nfs_access_lru_lock); nfs_access_free_list(&head); |
1c3c07e9f NFS: Add a new AC... |
2057 |
} |
1da177e4c Linux-2.6.12-rc2 |
2058 |
|
1c3c07e9f NFS: Add a new AC... |
2059 2060 2061 2062 2063 2064 2065 2066 2067 2068 2069 2070 2071 2072 |
static struct nfs_access_entry *nfs_access_search_rbtree(struct inode *inode, struct rpc_cred *cred) { struct rb_node *n = NFS_I(inode)->access_cache.rb_node; struct nfs_access_entry *entry; while (n != NULL) { entry = rb_entry(n, struct nfs_access_entry, rb_node); if (cred < entry->cred) n = n->rb_left; else if (cred > entry->cred) n = n->rb_right; else return entry; |
1da177e4c Linux-2.6.12-rc2 |
2073 |
} |
1c3c07e9f NFS: Add a new AC... |
2074 2075 |
return NULL; } |
af22f94ae NFSv4: Simplify _... |
2076 |
static int nfs_access_get_cached(struct inode *inode, struct rpc_cred *cred, struct nfs_access_entry *res) |
1c3c07e9f NFS: Add a new AC... |
2077 2078 2079 2080 |
{ struct nfs_inode *nfsi = NFS_I(inode); struct nfs_access_entry *cache; int err = -ENOENT; |
dc59250c6 [PATCH] NFS: Intr... |
2081 |
spin_lock(&inode->i_lock); |
1c3c07e9f NFS: Add a new AC... |
2082 2083 2084 2085 2086 |
if (nfsi->cache_validity & NFS_INO_INVALID_ACCESS) goto out_zap; cache = nfs_access_search_rbtree(inode, cred); if (cache == NULL) goto out; |
b4d2314bb NFSv4: Don't igno... |
2087 |
if (!nfs_have_delegated_attributes(inode) && |
64672d55d optimize attribut... |
2088 |
!time_in_range_open(jiffies, cache->jiffies, cache->jiffies + nfsi->attrtimeo)) |
1c3c07e9f NFS: Add a new AC... |
2089 2090 2091 2092 |
goto out_stale; res->jiffies = cache->jiffies; res->cred = cache->cred; res->mask = cache->mask; |
cfcea3e8c NFS: Add a global... |
2093 |
list_move_tail(&cache->lru, &nfsi->access_cache_entry_lru); |
1c3c07e9f NFS: Add a new AC... |
2094 2095 2096 2097 2098 2099 |
err = 0; out: spin_unlock(&inode->i_lock); return err; out_stale: rb_erase(&cache->rb_node, &nfsi->access_cache); |
cfcea3e8c NFS: Add a global... |
2100 |
list_del(&cache->lru); |
1c3c07e9f NFS: Add a new AC... |
2101 2102 2103 2104 |
spin_unlock(&inode->i_lock); nfs_access_free_entry(cache); return -ENOENT; out_zap: |
1a81bb8a1 NFS: Clean up nfs... |
2105 2106 |
spin_unlock(&inode->i_lock); nfs_access_zap_cache(inode); |
1c3c07e9f NFS: Add a new AC... |
2107 2108 2109 2110 2111 |
return -ENOENT; } static void nfs_access_add_rbtree(struct inode *inode, struct nfs_access_entry *set) { |
cfcea3e8c NFS: Add a global... |
2112 2113 |
struct nfs_inode *nfsi = NFS_I(inode); struct rb_root *root_node = &nfsi->access_cache; |
1c3c07e9f NFS: Add a new AC... |
2114 2115 2116 2117 2118 2119 2120 2121 2122 2123 2124 2125 2126 2127 2128 2129 2130 2131 |
struct rb_node **p = &root_node->rb_node; struct rb_node *parent = NULL; struct nfs_access_entry *entry; spin_lock(&inode->i_lock); while (*p != NULL) { parent = *p; entry = rb_entry(parent, struct nfs_access_entry, rb_node); if (set->cred < entry->cred) p = &parent->rb_left; else if (set->cred > entry->cred) p = &parent->rb_right; else goto found; } rb_link_node(&set->rb_node, parent, p); rb_insert_color(&set->rb_node, root_node); |
cfcea3e8c NFS: Add a global... |
2132 |
list_add_tail(&set->lru, &nfsi->access_cache_entry_lru); |
dc59250c6 [PATCH] NFS: Intr... |
2133 |
spin_unlock(&inode->i_lock); |
1c3c07e9f NFS: Add a new AC... |
2134 2135 2136 |
return; found: rb_replace_node(parent, &set->rb_node, root_node); |
cfcea3e8c NFS: Add a global... |
2137 2138 |
list_add_tail(&set->lru, &nfsi->access_cache_entry_lru); list_del(&entry->lru); |
1c3c07e9f NFS: Add a new AC... |
2139 2140 2141 |
spin_unlock(&inode->i_lock); nfs_access_free_entry(entry); } |
af22f94ae NFSv4: Simplify _... |
2142 |
static void nfs_access_add_cache(struct inode *inode, struct nfs_access_entry *set) |
1c3c07e9f NFS: Add a new AC... |
2143 2144 2145 2146 2147 |
{ struct nfs_access_entry *cache = kmalloc(sizeof(*cache), GFP_KERNEL); if (cache == NULL) return; RB_CLEAR_NODE(&cache->rb_node); |
1da177e4c Linux-2.6.12-rc2 |
2148 |
cache->jiffies = set->jiffies; |
1c3c07e9f NFS: Add a new AC... |
2149 |
cache->cred = get_rpccred(set->cred); |
1da177e4c Linux-2.6.12-rc2 |
2150 |
cache->mask = set->mask; |
1c3c07e9f NFS: Add a new AC... |
2151 2152 |
nfs_access_add_rbtree(inode, cache); |
cfcea3e8c NFS: Add a global... |
2153 2154 2155 2156 2157 2158 2159 |
/* Update accounting */ smp_mb__before_atomic_inc(); atomic_long_inc(&nfs_access_nr_entries); smp_mb__after_atomic_inc(); /* Add inode to global LRU list */ |
1a81bb8a1 NFS: Clean up nfs... |
2160 |
if (!test_bit(NFS_INO_ACL_LRU_SET, &NFS_I(inode)->flags)) { |
cfcea3e8c NFS: Add a global... |
2161 |
spin_lock(&nfs_access_lru_lock); |
1a81bb8a1 NFS: Clean up nfs... |
2162 2163 2164 |
if (!test_and_set_bit(NFS_INO_ACL_LRU_SET, &NFS_I(inode)->flags)) list_add_tail(&NFS_I(inode)->access_cache_inode_lru, &nfs_access_lru_list); |
cfcea3e8c NFS: Add a global... |
2165 2166 |
spin_unlock(&nfs_access_lru_lock); } |
1da177e4c Linux-2.6.12-rc2 |
2167 2168 2169 2170 2171 2172 2173 2174 2175 2176 2177 2178 2179 2180 2181 2182 |
} static int nfs_do_access(struct inode *inode, struct rpc_cred *cred, int mask) { struct nfs_access_entry cache; int status; status = nfs_access_get_cached(inode, cred, &cache); if (status == 0) goto out; /* Be clever: ask server to check for all possible rights */ cache.mask = MAY_EXEC | MAY_WRITE | MAY_READ; cache.cred = cred; cache.jiffies = jiffies; status = NFS_PROTO(inode)->access(inode, &cache); |
a71ee337b NFS: Handle -ESTA... |
2183 2184 2185 2186 2187 2188 |
if (status != 0) { if (status == -ESTALE) { nfs_zap_caches(inode); if (!S_ISDIR(inode->i_mode)) set_bit(NFS_INO_STALE, &NFS_I(inode)->flags); } |
1da177e4c Linux-2.6.12-rc2 |
2189 |
return status; |
a71ee337b NFS: Handle -ESTA... |
2190 |
} |
1da177e4c Linux-2.6.12-rc2 |
2191 2192 |
nfs_access_add_cache(inode, &cache); out: |
e6305c43e [PATCH] sanitize ... |
2193 |
if ((mask & ~cache.mask & (MAY_READ | MAY_WRITE | MAY_EXEC)) == 0) |
1da177e4c Linux-2.6.12-rc2 |
2194 2195 2196 |
return 0; return -EACCES; } |
af22f94ae NFSv4: Simplify _... |
2197 2198 2199 |
static int nfs_open_permission_mask(int openflags) { int mask = 0; |
8a5e929dd don't translitera... |
2200 |
if ((openflags & O_ACCMODE) != O_WRONLY) |
af22f94ae NFSv4: Simplify _... |
2201 |
mask |= MAY_READ; |
8a5e929dd don't translitera... |
2202 |
if ((openflags & O_ACCMODE) != O_RDONLY) |
af22f94ae NFSv4: Simplify _... |
2203 |
mask |= MAY_WRITE; |
8a5e929dd don't translitera... |
2204 |
if (openflags & __FMODE_EXEC) |
af22f94ae NFSv4: Simplify _... |
2205 2206 2207 2208 2209 2210 2211 2212 |
mask |= MAY_EXEC; return mask; } int nfs_may_open(struct inode *inode, struct rpc_cred *cred, int openflags) { return nfs_do_access(inode, cred, nfs_open_permission_mask(openflags)); } |
10556cb21 ->permission() sa... |
2213 |
int nfs_permission(struct inode *inode, int mask) |
1da177e4c Linux-2.6.12-rc2 |
2214 2215 2216 |
{ struct rpc_cred *cred; int res = 0; |
10556cb21 ->permission() sa... |
2217 |
if (mask & MAY_NOT_BLOCK) |
b74c79e99 fs: provide rcu-w... |
2218 |
return -ECHILD; |
91d5b4702 NFS: add I/O perf... |
2219 |
nfs_inc_stats(inode, NFSIOS_VFSACCESS); |
e6305c43e [PATCH] sanitize ... |
2220 |
if ((mask & (MAY_READ | MAY_WRITE | MAY_EXEC)) == 0) |
1da177e4c Linux-2.6.12-rc2 |
2221 2222 |
goto out; /* Is this sys_access() ? */ |
9cfcac810 vfs: re-introduce... |
2223 |
if (mask & (MAY_ACCESS | MAY_CHDIR)) |
1da177e4c Linux-2.6.12-rc2 |
2224 2225 2226 2227 2228 2229 2230 2231 |
goto force_lookup; switch (inode->i_mode & S_IFMT) { case S_IFLNK: goto out; case S_IFREG: /* NFSv4 has atomic_open... */ if (nfs_server_capable(inode, NFS_CAP_ATOMIC_OPEN) |
7ee2cb7f3 nfs: Fix NFS v4 c... |
2232 2233 |
&& (mask & MAY_OPEN) && !(mask & MAY_EXEC)) |
1da177e4c Linux-2.6.12-rc2 |
2234 2235 2236 2237 2238 2239 2240 2241 2242 2243 2244 2245 |
goto out; break; case S_IFDIR: /* * Optimize away all write operations, since the server * will check permissions when we perform the op. */ if ((mask & MAY_WRITE) && !(mask & MAY_READ)) goto out; } force_lookup: |
1da177e4c Linux-2.6.12-rc2 |
2246 2247 |
if (!NFS_PROTO(inode)->access) goto out_notsup; |
98a8e3239 SUNRPC: Add a hel... |
2248 |
cred = rpc_lookup_cred(); |
1da177e4c Linux-2.6.12-rc2 |
2249 2250 2251 2252 2253 |
if (!IS_ERR(cred)) { res = nfs_do_access(inode, cred, mask); put_rpccred(cred); } else res = PTR_ERR(cred); |
1da177e4c Linux-2.6.12-rc2 |
2254 |
out: |
f696a3659 [PATCH] move exec... |
2255 2256 |
if (!res && (mask & MAY_EXEC) && !execute_ok(inode)) res = -EACCES; |
1e7cb3dc1 NFS: directory tr... |
2257 2258 2259 |
dfprintk(VFS, "NFS: permission(%s/%ld), mask=0x%x, res=%d ", inode->i_sb->s_id, inode->i_ino, mask, res); |
1da177e4c Linux-2.6.12-rc2 |
2260 2261 2262 2263 |
return res; out_notsup: res = nfs_revalidate_inode(NFS_SERVER(inode), inode); if (res == 0) |
2830ba7f3 ->permission() sa... |
2264 |
res = generic_permission(inode, mask); |
1e7cb3dc1 NFS: directory tr... |
2265 |
goto out; |
1da177e4c Linux-2.6.12-rc2 |
2266 2267 2268 2269 2270 2271 2272 2273 |
} /* * Local variables: * version-control: t * kept-new-versions: 5 * End: */ |