Blame view
fs/afs/dir.c
51.8 KB
2874c5fd2 treewide: Replace... |
1 |
// SPDX-License-Identifier: GPL-2.0-or-later |
1da177e4c Linux-2.6.12-rc2 |
2 3 |
/* dir.c: AFS filesystem directory handling * |
f3ddee8dc afs: Fix director... |
4 |
* Copyright (C) 2002, 2018 Red Hat, Inc. All Rights Reserved. |
1da177e4c Linux-2.6.12-rc2 |
5 |
* Written by David Howells (dhowells@redhat.com) |
1da177e4c Linux-2.6.12-rc2 |
6 7 8 |
*/ #include <linux/kernel.h> |
1da177e4c Linux-2.6.12-rc2 |
9 |
#include <linux/fs.h> |
34286d666 fs: rcu-walk awar... |
10 |
#include <linux/namei.h> |
1da177e4c Linux-2.6.12-rc2 |
11 |
#include <linux/pagemap.h> |
f3ddee8dc afs: Fix director... |
12 |
#include <linux/swap.h> |
00d3b7a45 [AFS]: Add securi... |
13 |
#include <linux/ctype.h> |
e8edc6e03 Detach sched.h fr... |
14 |
#include <linux/sched.h> |
f3ddee8dc afs: Fix director... |
15 |
#include <linux/task_io_accounting_ops.h> |
1da177e4c Linux-2.6.12-rc2 |
16 |
#include "internal.h" |
a58823ac4 afs: Fix applicat... |
17 |
#include "afs_fs.h" |
4ea219a83 afs: Split the di... |
18 |
#include "xdr_fs.h" |
1da177e4c Linux-2.6.12-rc2 |
19 |
|
260a98031 [AFS]: Add "direc... |
20 |
static struct dentry *afs_lookup(struct inode *dir, struct dentry *dentry, |
00cd8dd3b stop passing name... |
21 |
unsigned int flags); |
1da177e4c Linux-2.6.12-rc2 |
22 |
static int afs_dir_open(struct inode *inode, struct file *file); |
1bbae9f81 [readdir] convert... |
23 |
static int afs_readdir(struct file *file, struct dir_context *ctx); |
0b728e191 stop passing name... |
24 |
static int afs_d_revalidate(struct dentry *dentry, unsigned int flags); |
fe15ce446 fs: change d_dele... |
25 |
static int afs_d_delete(const struct dentry *dentry); |
79ddbfa50 afs: Implement si... |
26 |
static void afs_d_iput(struct dentry *dentry, struct inode *inode); |
5cf9dd55a afs: Prospectivel... |
27 |
static int afs_lookup_one_filldir(struct dir_context *ctx, const char *name, int nlen, |
afefdbb28 [PATCH] VFS: Make... |
28 |
loff_t fpos, u64 ino, unsigned dtype); |
5cf9dd55a afs: Prospectivel... |
29 30 |
static int afs_lookup_filldir(struct dir_context *ctx, const char *name, int nlen, loff_t fpos, u64 ino, unsigned dtype); |
4acdaf27e switch ->create()... |
31 |
static int afs_create(struct inode *dir, struct dentry *dentry, umode_t mode, |
ebfc3b49a don't pass nameid... |
32 |
bool excl); |
18bb1db3e switch vfs_mkdir(... |
33 |
static int afs_mkdir(struct inode *dir, struct dentry *dentry, umode_t mode); |
260a98031 [AFS]: Add "direc... |
34 35 36 37 38 39 40 |
static int afs_rmdir(struct inode *dir, struct dentry *dentry); static int afs_unlink(struct inode *dir, struct dentry *dentry); static int afs_link(struct dentry *from, struct inode *dir, struct dentry *dentry); static int afs_symlink(struct inode *dir, struct dentry *dentry, const char *content); static int afs_rename(struct inode *old_dir, struct dentry *old_dentry, |
1cd66c93b fs: make remainin... |
41 42 |
struct inode *new_dir, struct dentry *new_dentry, unsigned int flags); |
f3ddee8dc afs: Fix director... |
43 44 45 46 47 48 49 50 |
static int afs_dir_releasepage(struct page *page, gfp_t gfp_flags); static void afs_dir_invalidatepage(struct page *page, unsigned int offset, unsigned int length); static int afs_dir_set_page_dirty(struct page *page) { BUG(); /* This should never happen. */ } |
1da177e4c Linux-2.6.12-rc2 |
51 |
|
4b6f5d20b [PATCH] Make most... |
52 |
const struct file_operations afs_dir_file_operations = { |
1da177e4c Linux-2.6.12-rc2 |
53 |
.open = afs_dir_open, |
00d3b7a45 [AFS]: Add securi... |
54 |
.release = afs_release, |
29884eff1 afs: switch to ->... |
55 |
.iterate_shared = afs_readdir, |
e8d6c5541 AFS: implement fi... |
56 |
.lock = afs_lock, |
3222a3e55 [PATCH] fix ->lls... |
57 |
.llseek = generic_file_llseek, |
1da177e4c Linux-2.6.12-rc2 |
58 |
}; |
754661f14 [PATCH] mark stru... |
59 |
const struct inode_operations afs_dir_inode_operations = { |
260a98031 [AFS]: Add "direc... |
60 61 62 63 64 65 66 |
.create = afs_create, .lookup = afs_lookup, .link = afs_link, .unlink = afs_unlink, .symlink = afs_symlink, .mkdir = afs_mkdir, .rmdir = afs_rmdir, |
2773bf00a fs: rename "renam... |
67 |
.rename = afs_rename, |
00d3b7a45 [AFS]: Add securi... |
68 |
.permission = afs_permission, |
416351f28 AFS: AFS fixups |
69 |
.getattr = afs_getattr, |
31143d5d5 AFS: implement ba... |
70 |
.setattr = afs_setattr, |
d3e3b7eac afs: Add metadata... |
71 |
.listxattr = afs_listxattr, |
1da177e4c Linux-2.6.12-rc2 |
72 |
}; |
f3ddee8dc afs: Fix director... |
73 74 75 76 77 |
const struct address_space_operations afs_dir_aops = { .set_page_dirty = afs_dir_set_page_dirty, .releasepage = afs_dir_releasepage, .invalidatepage = afs_dir_invalidatepage, }; |
d61dcce29 switch afs |
78 |
const struct dentry_operations afs_fs_dentry_operations = { |
1da177e4c Linux-2.6.12-rc2 |
79 80 |
.d_revalidate = afs_d_revalidate, .d_delete = afs_d_delete, |
260a98031 [AFS]: Add "direc... |
81 |
.d_release = afs_d_release, |
d18610b0c AFS: Use d_automo... |
82 |
.d_automount = afs_d_automount, |
79ddbfa50 afs: Implement si... |
83 |
.d_iput = afs_d_iput, |
1da177e4c Linux-2.6.12-rc2 |
84 |
}; |
5cf9dd55a afs: Prospectivel... |
85 86 87 88 89 90 |
struct afs_lookup_one_cookie { struct dir_context ctx; struct qstr name; bool found; struct afs_fid fid; }; |
260a98031 [AFS]: Add "direc... |
91 |
struct afs_lookup_cookie { |
5cf9dd55a afs: Prospectivel... |
92 93 94 95 96 |
struct dir_context ctx; struct qstr name; bool found; bool one_only; unsigned short nr_fids; |
5cf9dd55a afs: Prospectivel... |
97 |
struct afs_fid fids[50]; |
1da177e4c Linux-2.6.12-rc2 |
98 |
}; |
1da177e4c Linux-2.6.12-rc2 |
99 100 101 |
/* * check that a directory page is valid */ |
f3ddee8dc afs: Fix director... |
102 103 |
static bool afs_dir_check_page(struct afs_vnode *dvnode, struct page *page, loff_t i_size) |
1da177e4c Linux-2.6.12-rc2 |
104 |
{ |
003176369 afs: Adjust the d... |
105 |
struct afs_xdr_dir_page *dbuf; |
f3ddee8dc afs: Fix director... |
106 |
loff_t latter, off; |
1da177e4c Linux-2.6.12-rc2 |
107 |
int tmp, qty; |
dab17c1ad afs: Fix director... |
108 109 110 111 |
/* Determine how many magic numbers there should be in this page, but * we must take care because the directory may change size under us. */ off = page_offset(page); |
dab17c1ad afs: Fix director... |
112 113 114 115 |
if (i_size <= off) goto checked; latter = i_size - off; |
1da177e4c Linux-2.6.12-rc2 |
116 117 118 119 |
if (latter >= PAGE_SIZE) qty = PAGE_SIZE; else qty = latter; |
003176369 afs: Adjust the d... |
120 |
qty /= sizeof(union afs_xdr_dir_block); |
1da177e4c Linux-2.6.12-rc2 |
121 122 |
/* check them */ |
63a4681ff afs: Locally edit... |
123 |
dbuf = kmap(page); |
1da177e4c Linux-2.6.12-rc2 |
124 |
for (tmp = 0; tmp < qty; tmp++) { |
003176369 afs: Adjust the d... |
125 |
if (dbuf->blocks[tmp].hdr.magic != AFS_DIR_MAGIC) { |
dab17c1ad afs: Fix director... |
126 127 |
printk("kAFS: %s(%lx): bad magic %d/%d is %04hx ", |
f3ddee8dc afs: Fix director... |
128 |
__func__, dvnode->vfs_inode.i_ino, tmp, qty, |
003176369 afs: Adjust the d... |
129 |
ntohs(dbuf->blocks[tmp].hdr.magic)); |
f3ddee8dc afs: Fix director... |
130 |
trace_afs_dir_check_failed(dvnode, off, i_size); |
63a4681ff afs: Locally edit... |
131 |
kunmap(page); |
f51375cd9 afs: Add a couple... |
132 |
trace_afs_file_error(dvnode, -EIO, afs_file_error_dir_bad_magic); |
1da177e4c Linux-2.6.12-rc2 |
133 134 |
goto error; } |
63a4681ff afs: Locally edit... |
135 136 137 138 139 140 |
/* Make sure each block is NUL terminated so we can reasonably * use string functions on it. The filenames in the page * *should* be NUL-terminated anyway. */ ((u8 *)&dbuf->blocks[tmp])[AFS_DIR_BLOCK_SIZE - 1] = 0; |
1da177e4c Linux-2.6.12-rc2 |
141 |
} |
63a4681ff afs: Locally edit... |
142 |
kunmap(page); |
dab17c1ad afs: Fix director... |
143 |
checked: |
f3ddee8dc afs: Fix director... |
144 |
afs_stat_v(dvnode, n_read_dir); |
be5b82dbf make ext2_get_pag... |
145 |
return true; |
1da177e4c Linux-2.6.12-rc2 |
146 |
|
ec26815ad [AFS]: Clean up t... |
147 |
error: |
be5b82dbf make ext2_get_pag... |
148 |
return false; |
ec26815ad [AFS]: Clean up t... |
149 |
} |
1da177e4c Linux-2.6.12-rc2 |
150 |
|
1da177e4c Linux-2.6.12-rc2 |
151 |
/* |
445b10289 afs: Improve dir ... |
152 153 154 155 156 157 158 159 160 161 162 163 164 165 166 167 168 169 170 171 172 173 174 175 176 177 178 179 180 181 182 183 184 185 186 |
* Check the contents of a directory that we've just read. */ static bool afs_dir_check_pages(struct afs_vnode *dvnode, struct afs_read *req) { struct afs_xdr_dir_page *dbuf; unsigned int i, j, qty = PAGE_SIZE / sizeof(union afs_xdr_dir_block); for (i = 0; i < req->nr_pages; i++) if (!afs_dir_check_page(dvnode, req->pages[i], req->actual_len)) goto bad; return true; bad: pr_warn("DIR %llx:%llx f=%llx l=%llx al=%llx r=%llx ", dvnode->fid.vid, dvnode->fid.vnode, req->file_size, req->len, req->actual_len, req->remain); pr_warn("DIR %llx %x %x %x ", req->pos, req->index, req->nr_pages, req->offset); for (i = 0; i < req->nr_pages; i++) { dbuf = kmap(req->pages[i]); for (j = 0; j < qty; j++) { union afs_xdr_dir_block *block = &dbuf->blocks[j]; pr_warn("[%02x] %32phN ", i * qty + j, block); } kunmap(req->pages[i]); } return false; } /* |
1da177e4c Linux-2.6.12-rc2 |
187 188 189 190 191 |
* open an AFS directory file */ static int afs_dir_open(struct inode *inode, struct file *file) { _enter("{%lu}", inode->i_ino); |
003176369 afs: Adjust the d... |
192 193 |
BUILD_BUG_ON(sizeof(union afs_xdr_dir_block) != 2048); BUILD_BUG_ON(sizeof(union afs_xdr_dirent) != 32); |
1da177e4c Linux-2.6.12-rc2 |
194 |
|
08e0e7c82 [AF_RXRPC]: Make ... |
195 |
if (test_bit(AFS_VNODE_DELETED, &AFS_FS_I(inode)->flags)) |
1da177e4c Linux-2.6.12-rc2 |
196 |
return -ENOENT; |
00d3b7a45 [AFS]: Add securi... |
197 |
return afs_open(inode, file); |
ec26815ad [AFS]: Clean up t... |
198 |
} |
1da177e4c Linux-2.6.12-rc2 |
199 |
|
1da177e4c Linux-2.6.12-rc2 |
200 |
/* |
f3ddee8dc afs: Fix director... |
201 202 203 204 205 |
* Read the directory into the pagecache in one go, scrubbing the previous * contents. The list of pages is returned, pinning them so that they don't * get reclaimed during the iteration. */ static struct afs_read *afs_read_dir(struct afs_vnode *dvnode, struct key *key) |
b61f7dcf4 afs: Fix director... |
206 |
__acquires(&dvnode->validate_lock) |
f3ddee8dc afs: Fix director... |
207 208 209 210 211 212 213 214 215 |
{ struct afs_read *req; loff_t i_size; int nr_pages, nr_inline, i, n; int ret = -ENOMEM; retry: i_size = i_size_read(&dvnode->vfs_inode); if (i_size < 2048) |
f51375cd9 afs: Add a couple... |
216 217 218 |
return ERR_PTR(afs_bad(dvnode, afs_file_error_dir_small)); if (i_size > 2048 * 1024) { trace_afs_file_error(dvnode, -EFBIG, afs_file_error_dir_big); |
f3ddee8dc afs: Fix director... |
219 |
return ERR_PTR(-EFBIG); |
f51375cd9 afs: Add a couple... |
220 |
} |
f3ddee8dc afs: Fix director... |
221 222 223 224 225 226 227 228 229 230 |
_enter("%llu", i_size); /* Get a request record to hold the page list. We want to hold it * inline if we can, but we don't want to make an order 1 allocation. */ nr_pages = (i_size + PAGE_SIZE - 1) / PAGE_SIZE; nr_inline = nr_pages; if (nr_inline > (PAGE_SIZE - sizeof(*req)) / sizeof(struct page *)) nr_inline = 0; |
ee102584e fs/afs: use struc... |
231 |
req = kzalloc(struct_size(req, array, nr_inline), GFP_KERNEL); |
f3ddee8dc afs: Fix director... |
232 233 234 235 236 237 238 239 240 241 242 243 244 245 246 247 248 249 250 251 252 253 254 255 256 257 258 259 260 261 262 263 264 265 266 267 268 269 270 271 272 273 274 |
if (!req) return ERR_PTR(-ENOMEM); refcount_set(&req->usage, 1); req->nr_pages = nr_pages; req->actual_len = i_size; /* May change */ req->len = nr_pages * PAGE_SIZE; /* We can ask for more than there is */ req->data_version = dvnode->status.data_version; /* May change */ if (nr_inline > 0) { req->pages = req->array; } else { req->pages = kcalloc(nr_pages, sizeof(struct page *), GFP_KERNEL); if (!req->pages) goto error; } /* Get a list of all the pages that hold or will hold the directory * content. We need to fill in any gaps that we might find where the * memory reclaimer has been at work. If there are any gaps, we will * need to reread the entire directory contents. */ i = 0; do { n = find_get_pages_contig(dvnode->vfs_inode.i_mapping, i, req->nr_pages - i, req->pages + i); _debug("find %u at %u/%u", n, i, req->nr_pages); if (n == 0) { gfp_t gfp = dvnode->vfs_inode.i_mapping->gfp_mask; if (test_and_clear_bit(AFS_VNODE_DIR_VALID, &dvnode->flags)) afs_stat_v(dvnode, n_inval); ret = -ENOMEM; req->pages[i] = __page_cache_alloc(gfp); if (!req->pages[i]) goto error; ret = add_to_page_cache_lru(req->pages[i], dvnode->vfs_inode.i_mapping, i, gfp); if (ret < 0) goto error; |
fa04a40b1 afs: Fix to take ... |
275 |
attach_page_private(req->pages[i], (void *)1); |
f3ddee8dc afs: Fix director... |
276 277 278 279 280 281 282 283 284 285 |
unlock_page(req->pages[i]); i++; } else { i += n; } } while (i < req->nr_pages); /* If we're going to reload, we need to lock all the pages to prevent * races. */ |
b61f7dcf4 afs: Fix director... |
286 287 288 |
ret = -ERESTARTSYS; if (down_read_killable(&dvnode->validate_lock) < 0) goto error; |
f3ddee8dc afs: Fix director... |
289 |
|
b61f7dcf4 afs: Fix director... |
290 291 |
if (test_bit(AFS_VNODE_DIR_VALID, &dvnode->flags)) goto success; |
f3ddee8dc afs: Fix director... |
292 |
|
b61f7dcf4 afs: Fix director... |
293 294 295 296 297 |
up_read(&dvnode->validate_lock); if (down_write_killable(&dvnode->validate_lock) < 0) goto error; if (!test_bit(AFS_VNODE_DIR_VALID, &dvnode->flags)) { |
99987c560 afs: Add director... |
298 |
trace_afs_reload_dir(dvnode); |
f3ddee8dc afs: Fix director... |
299 300 |
ret = afs_fetch_data(dvnode, key, req); if (ret < 0) |
b61f7dcf4 afs: Fix director... |
301 |
goto error_unlock; |
f3ddee8dc afs: Fix director... |
302 303 304 305 306 307 308 309 |
task_io_account_read(PAGE_SIZE * req->nr_pages); if (req->len < req->file_size) goto content_has_grown; /* Validate the data we just read. */ ret = -EIO; |
445b10289 afs: Improve dir ... |
310 311 |
if (!afs_dir_check_pages(dvnode, req)) goto error_unlock; |
f3ddee8dc afs: Fix director... |
312 313 314 315 316 |
// TODO: Trim excess pages set_bit(AFS_VNODE_DIR_VALID, &dvnode->flags); } |
b61f7dcf4 afs: Fix director... |
317 |
downgrade_write(&dvnode->validate_lock); |
f3ddee8dc afs: Fix director... |
318 |
success: |
f3ddee8dc afs: Fix director... |
319 |
return req; |
f3ddee8dc afs: Fix director... |
320 |
error_unlock: |
b61f7dcf4 afs: Fix director... |
321 |
up_write(&dvnode->validate_lock); |
f3ddee8dc afs: Fix director... |
322 323 324 325 326 327 |
error: afs_put_read(req); _leave(" = %d", ret); return ERR_PTR(ret); content_has_grown: |
b61f7dcf4 afs: Fix director... |
328 |
up_write(&dvnode->validate_lock); |
f3ddee8dc afs: Fix director... |
329 330 331 332 333 |
afs_put_read(req); goto retry; } /* |
1da177e4c Linux-2.6.12-rc2 |
334 335 |
* deal with one block in an AFS directory */ |
f51375cd9 afs: Add a couple... |
336 337 |
static int afs_dir_iterate_block(struct afs_vnode *dvnode, struct dir_context *ctx, |
003176369 afs: Adjust the d... |
338 |
union afs_xdr_dir_block *block, |
1bbae9f81 [readdir] convert... |
339 |
unsigned blkoff) |
1da177e4c Linux-2.6.12-rc2 |
340 |
{ |
003176369 afs: Adjust the d... |
341 |
union afs_xdr_dirent *dire; |
1da177e4c Linux-2.6.12-rc2 |
342 343 |
unsigned offset, next, curr; size_t nlen; |
1bbae9f81 [readdir] convert... |
344 |
int tmp; |
1da177e4c Linux-2.6.12-rc2 |
345 |
|
1bbae9f81 [readdir] convert... |
346 |
_enter("%u,%x,%p,,",(unsigned)ctx->pos,blkoff,block); |
1da177e4c Linux-2.6.12-rc2 |
347 |
|
003176369 afs: Adjust the d... |
348 |
curr = (ctx->pos - blkoff) / sizeof(union afs_xdr_dirent); |
1da177e4c Linux-2.6.12-rc2 |
349 350 |
/* walk through the block, an entry at a time */ |
4ea219a83 afs: Split the di... |
351 352 |
for (offset = (blkoff == 0 ? AFS_DIR_RESV_BLOCKS0 : AFS_DIR_RESV_BLOCKS); offset < AFS_DIR_SLOTS_PER_BLOCK; |
1da177e4c Linux-2.6.12-rc2 |
353 354 355 356 357 |
offset = next ) { next = offset + 1; /* skip entries marked unused in the bitmap */ |
003176369 afs: Adjust the d... |
358 |
if (!(block->hdr.bitmap[offset / 8] & |
1da177e4c Linux-2.6.12-rc2 |
359 |
(1 << (offset % 8)))) { |
5b5e0928f lib/vsprintf.c: r... |
360 |
_debug("ENT[%zu.%u]: unused", |
003176369 afs: Adjust the d... |
361 |
blkoff / sizeof(union afs_xdr_dir_block), offset); |
1da177e4c Linux-2.6.12-rc2 |
362 |
if (offset >= curr) |
1bbae9f81 [readdir] convert... |
363 |
ctx->pos = blkoff + |
003176369 afs: Adjust the d... |
364 |
next * sizeof(union afs_xdr_dirent); |
1da177e4c Linux-2.6.12-rc2 |
365 366 367 368 369 370 371 |
continue; } /* got a valid entry */ dire = &block->dirents[offset]; nlen = strnlen(dire->u.name, sizeof(*block) - |
003176369 afs: Adjust the d... |
372 |
offset * sizeof(union afs_xdr_dirent)); |
1da177e4c Linux-2.6.12-rc2 |
373 |
|
5b5e0928f lib/vsprintf.c: r... |
374 |
_debug("ENT[%zu.%u]: %s %zu \"%s\"", |
003176369 afs: Adjust the d... |
375 |
blkoff / sizeof(union afs_xdr_dir_block), offset, |
1da177e4c Linux-2.6.12-rc2 |
376 377 378 379 |
(offset < curr ? "skip" : "fill"), nlen, dire->u.name); /* work out where the next possible entry is */ |
003176369 afs: Adjust the d... |
380 |
for (tmp = nlen; tmp > 15; tmp -= sizeof(union afs_xdr_dirent)) { |
4ea219a83 afs: Split the di... |
381 |
if (next >= AFS_DIR_SLOTS_PER_BLOCK) { |
5b5e0928f lib/vsprintf.c: r... |
382 |
_debug("ENT[%zu.%u]:" |
1da177e4c Linux-2.6.12-rc2 |
383 |
" %u travelled beyond end dir block" |
5b5e0928f lib/vsprintf.c: r... |
384 |
" (len %u/%zu)", |
003176369 afs: Adjust the d... |
385 |
blkoff / sizeof(union afs_xdr_dir_block), |
1da177e4c Linux-2.6.12-rc2 |
386 |
offset, next, tmp, nlen); |
f51375cd9 afs: Add a couple... |
387 |
return afs_bad(dvnode, afs_file_error_dir_over_end); |
1da177e4c Linux-2.6.12-rc2 |
388 |
} |
003176369 afs: Adjust the d... |
389 |
if (!(block->hdr.bitmap[next / 8] & |
1da177e4c Linux-2.6.12-rc2 |
390 |
(1 << (next % 8)))) { |
5b5e0928f lib/vsprintf.c: r... |
391 392 |
_debug("ENT[%zu.%u]:" " %u unmarked extension (len %u/%zu)", |
003176369 afs: Adjust the d... |
393 |
blkoff / sizeof(union afs_xdr_dir_block), |
1da177e4c Linux-2.6.12-rc2 |
394 |
offset, next, tmp, nlen); |
f51375cd9 afs: Add a couple... |
395 |
return afs_bad(dvnode, afs_file_error_dir_unmarked_ext); |
1da177e4c Linux-2.6.12-rc2 |
396 |
} |
5b5e0928f lib/vsprintf.c: r... |
397 |
_debug("ENT[%zu.%u]: ext %u/%zu", |
003176369 afs: Adjust the d... |
398 |
blkoff / sizeof(union afs_xdr_dir_block), |
1da177e4c Linux-2.6.12-rc2 |
399 400 401 402 403 404 405 406 407 |
next, tmp, nlen); next++; } /* skip if starts before the current position */ if (offset < curr) continue; /* found the next entry */ |
1bbae9f81 [readdir] convert... |
408 |
if (!dir_emit(ctx, dire->u.name, nlen, |
1da177e4c Linux-2.6.12-rc2 |
409 |
ntohl(dire->u.vnode), |
5cf9dd55a afs: Prospectivel... |
410 411 |
(ctx->actor == afs_lookup_filldir || ctx->actor == afs_lookup_one_filldir)? |
1bbae9f81 [readdir] convert... |
412 |
ntohl(dire->u.unique) : DT_UNKNOWN)) { |
1da177e4c Linux-2.6.12-rc2 |
413 414 415 |
_leave(" = 0 [full]"); return 0; } |
003176369 afs: Adjust the d... |
416 |
ctx->pos = blkoff + next * sizeof(union afs_xdr_dirent); |
1da177e4c Linux-2.6.12-rc2 |
417 418 419 420 |
} _leave(" = 1 [more]"); return 1; |
ec26815ad [AFS]: Clean up t... |
421 |
} |
1da177e4c Linux-2.6.12-rc2 |
422 |
|
1da177e4c Linux-2.6.12-rc2 |
423 |
/* |
08e0e7c82 [AF_RXRPC]: Make ... |
424 |
* iterate through the data blob that lists the contents of an AFS directory |
1da177e4c Linux-2.6.12-rc2 |
425 |
*/ |
1bbae9f81 [readdir] convert... |
426 |
static int afs_dir_iterate(struct inode *dir, struct dir_context *ctx, |
9dd0b82ef afs: Fix missing ... |
427 |
struct key *key, afs_dataversion_t *_dir_version) |
1da177e4c Linux-2.6.12-rc2 |
428 |
{ |
f3ddee8dc afs: Fix director... |
429 |
struct afs_vnode *dvnode = AFS_FS_I(dir); |
003176369 afs: Adjust the d... |
430 431 |
struct afs_xdr_dir_page *dbuf; union afs_xdr_dir_block *dblock; |
f3ddee8dc afs: Fix director... |
432 |
struct afs_read *req; |
1da177e4c Linux-2.6.12-rc2 |
433 434 435 |
struct page *page; unsigned blkoff, limit; int ret; |
1bbae9f81 [readdir] convert... |
436 |
_enter("{%lu},%u,,", dir->i_ino, (unsigned)ctx->pos); |
1da177e4c Linux-2.6.12-rc2 |
437 |
|
08e0e7c82 [AF_RXRPC]: Make ... |
438 |
if (test_bit(AFS_VNODE_DELETED, &AFS_FS_I(dir)->flags)) { |
1da177e4c Linux-2.6.12-rc2 |
439 440 441 |
_leave(" = -ESTALE"); return -ESTALE; } |
f3ddee8dc afs: Fix director... |
442 443 444 |
req = afs_read_dir(dvnode, key); if (IS_ERR(req)) return PTR_ERR(req); |
9dd0b82ef afs: Fix missing ... |
445 |
*_dir_version = req->data_version; |
f3ddee8dc afs: Fix director... |
446 |
|
1da177e4c Linux-2.6.12-rc2 |
447 |
/* round the file position up to the next entry boundary */ |
003176369 afs: Adjust the d... |
448 449 |
ctx->pos += sizeof(union afs_xdr_dirent) - 1; ctx->pos &= ~(sizeof(union afs_xdr_dirent) - 1); |
1da177e4c Linux-2.6.12-rc2 |
450 451 452 |
/* walk through the blocks in sequence */ ret = 0; |
f3ddee8dc afs: Fix director... |
453 |
while (ctx->pos < req->actual_len) { |
003176369 afs: Adjust the d... |
454 |
blkoff = ctx->pos & ~(sizeof(union afs_xdr_dir_block) - 1); |
1da177e4c Linux-2.6.12-rc2 |
455 |
|
f3ddee8dc afs: Fix director... |
456 457 458 459 460 |
/* Fetch the appropriate page from the directory and re-add it * to the LRU. */ page = req->pages[blkoff / PAGE_SIZE]; if (!page) { |
f51375cd9 afs: Add a couple... |
461 |
ret = afs_bad(dvnode, afs_file_error_dir_missing_page); |
1da177e4c Linux-2.6.12-rc2 |
462 463 |
break; } |
f3ddee8dc afs: Fix director... |
464 |
mark_page_accessed(page); |
1da177e4c Linux-2.6.12-rc2 |
465 466 |
limit = blkoff & ~(PAGE_SIZE - 1); |
f3ddee8dc afs: Fix director... |
467 |
dbuf = kmap(page); |
1da177e4c Linux-2.6.12-rc2 |
468 469 470 471 |
/* deal with the individual blocks stashed on this page */ do { dblock = &dbuf->blocks[(blkoff % PAGE_SIZE) / |
003176369 afs: Adjust the d... |
472 |
sizeof(union afs_xdr_dir_block)]; |
f51375cd9 afs: Add a couple... |
473 |
ret = afs_dir_iterate_block(dvnode, ctx, dblock, blkoff); |
1da177e4c Linux-2.6.12-rc2 |
474 |
if (ret != 1) { |
f3ddee8dc afs: Fix director... |
475 |
kunmap(page); |
1da177e4c Linux-2.6.12-rc2 |
476 477 |
goto out; } |
003176369 afs: Adjust the d... |
478 |
blkoff += sizeof(union afs_xdr_dir_block); |
1da177e4c Linux-2.6.12-rc2 |
479 |
|
1bbae9f81 [readdir] convert... |
480 |
} while (ctx->pos < dir->i_size && blkoff < limit); |
1da177e4c Linux-2.6.12-rc2 |
481 |
|
f3ddee8dc afs: Fix director... |
482 |
kunmap(page); |
1da177e4c Linux-2.6.12-rc2 |
483 484 |
ret = 0; } |
ec26815ad [AFS]: Clean up t... |
485 |
out: |
b61f7dcf4 afs: Fix director... |
486 |
up_read(&dvnode->validate_lock); |
f3ddee8dc afs: Fix director... |
487 |
afs_put_read(req); |
1da177e4c Linux-2.6.12-rc2 |
488 489 |
_leave(" = %d", ret); return ret; |
ec26815ad [AFS]: Clean up t... |
490 |
} |
1da177e4c Linux-2.6.12-rc2 |
491 |
|
1da177e4c Linux-2.6.12-rc2 |
492 493 494 |
/* * read an AFS directory */ |
1bbae9f81 [readdir] convert... |
495 |
static int afs_readdir(struct file *file, struct dir_context *ctx) |
1da177e4c Linux-2.6.12-rc2 |
496 |
{ |
9dd0b82ef afs: Fix missing ... |
497 498 499 500 |
afs_dataversion_t dir_version; return afs_dir_iterate(file_inode(file), ctx, afs_file_key(file), &dir_version); |
ec26815ad [AFS]: Clean up t... |
501 |
} |
1da177e4c Linux-2.6.12-rc2 |
502 |
|
1da177e4c Linux-2.6.12-rc2 |
503 |
/* |
5cf9dd55a afs: Prospectivel... |
504 |
* Search the directory for a single name |
1da177e4c Linux-2.6.12-rc2 |
505 506 507 |
* - if afs_dir_iterate_block() spots this function, it'll pass the FID * uniquifier through dtype */ |
5cf9dd55a afs: Prospectivel... |
508 509 |
static int afs_lookup_one_filldir(struct dir_context *ctx, const char *name, int nlen, loff_t fpos, u64 ino, unsigned dtype) |
1da177e4c Linux-2.6.12-rc2 |
510 |
{ |
5cf9dd55a afs: Prospectivel... |
511 512 |
struct afs_lookup_one_cookie *cookie = container_of(ctx, struct afs_lookup_one_cookie, ctx); |
1da177e4c Linux-2.6.12-rc2 |
513 |
|
1bbae9f81 [readdir] convert... |
514 515 |
_enter("{%s,%u},%s,%u,,%llu,%u", cookie->name.name, cookie->name.len, name, nlen, |
ba3e0e1ac [AFS]: Fix u64 pr... |
516 |
(unsigned long long) ino, dtype); |
1da177e4c Linux-2.6.12-rc2 |
517 |
|
08e0e7c82 [AF_RXRPC]: Make ... |
518 |
/* insanity checks first */ |
003176369 afs: Adjust the d... |
519 520 |
BUILD_BUG_ON(sizeof(union afs_xdr_dir_block) != 2048); BUILD_BUG_ON(sizeof(union afs_xdr_dirent) != 32); |
08e0e7c82 [AF_RXRPC]: Make ... |
521 |
|
1bbae9f81 [readdir] convert... |
522 523 |
if (cookie->name.len != nlen || memcmp(cookie->name.name, name, nlen) != 0) { |
1da177e4c Linux-2.6.12-rc2 |
524 525 526 527 528 529 530 531 532 533 |
_leave(" = 0 [no]"); return 0; } cookie->fid.vnode = ino; cookie->fid.unique = dtype; cookie->found = 1; _leave(" = -1 [found]"); return -1; |
ec26815ad [AFS]: Clean up t... |
534 |
} |
1da177e4c Linux-2.6.12-rc2 |
535 |
|
1da177e4c Linux-2.6.12-rc2 |
536 |
/* |
5cf9dd55a afs: Prospectivel... |
537 |
* Do a lookup of a single name in a directory |
260a98031 [AFS]: Add "direc... |
538 |
* - just returns the FID the dentry name maps to if found |
1da177e4c Linux-2.6.12-rc2 |
539 |
*/ |
5cf9dd55a afs: Prospectivel... |
540 |
static int afs_do_lookup_one(struct inode *dir, struct dentry *dentry, |
9dd0b82ef afs: Fix missing ... |
541 542 |
struct afs_fid *fid, struct key *key, afs_dataversion_t *_dir_version) |
1da177e4c Linux-2.6.12-rc2 |
543 |
{ |
1bbae9f81 [readdir] convert... |
544 |
struct afs_super_info *as = dir->i_sb->s_fs_info; |
5cf9dd55a afs: Prospectivel... |
545 546 |
struct afs_lookup_one_cookie cookie = { .ctx.actor = afs_lookup_one_filldir, |
1bbae9f81 [readdir] convert... |
547 548 549 |
.name = dentry->d_name, .fid.vid = as->volume->vid }; |
1da177e4c Linux-2.6.12-rc2 |
550 |
int ret; |
a455589f1 assorted conversi... |
551 |
_enter("{%lu},%p{%pd},", dir->i_ino, dentry, dentry); |
1da177e4c Linux-2.6.12-rc2 |
552 |
|
1da177e4c Linux-2.6.12-rc2 |
553 |
/* search the directory */ |
9dd0b82ef afs: Fix missing ... |
554 |
ret = afs_dir_iterate(dir, &cookie.ctx, key, _dir_version); |
1da177e4c Linux-2.6.12-rc2 |
555 |
if (ret < 0) { |
08e0e7c82 [AF_RXRPC]: Make ... |
556 557 |
_leave(" = %d [iter]", ret); return ret; |
1da177e4c Linux-2.6.12-rc2 |
558 559 560 561 |
} ret = -ENOENT; if (!cookie.found) { |
08e0e7c82 [AF_RXRPC]: Make ... |
562 563 |
_leave(" = -ENOENT [not found]"); return -ENOENT; |
1da177e4c Linux-2.6.12-rc2 |
564 |
} |
08e0e7c82 [AF_RXRPC]: Make ... |
565 |
*fid = cookie.fid; |
3b6492df4 afs: Increase to ... |
566 |
_leave(" = 0 { vn=%llu u=%u }", fid->vnode, fid->unique); |
08e0e7c82 [AF_RXRPC]: Make ... |
567 568 569 570 |
return 0; } /* |
5cf9dd55a afs: Prospectivel... |
571 572 573 574 575 576 577 578 579 580 581 582 583 584 585 586 |
* search the directory for a name * - if afs_dir_iterate_block() spots this function, it'll pass the FID * uniquifier through dtype */ static int afs_lookup_filldir(struct dir_context *ctx, const char *name, int nlen, loff_t fpos, u64 ino, unsigned dtype) { struct afs_lookup_cookie *cookie = container_of(ctx, struct afs_lookup_cookie, ctx); int ret; _enter("{%s,%u},%s,%u,,%llu,%u", cookie->name.name, cookie->name.len, name, nlen, (unsigned long long) ino, dtype); /* insanity checks first */ |
003176369 afs: Adjust the d... |
587 588 |
BUILD_BUG_ON(sizeof(union afs_xdr_dir_block) != 2048); BUILD_BUG_ON(sizeof(union afs_xdr_dirent) != 32); |
5cf9dd55a afs: Prospectivel... |
589 590 591 592 593 594 595 596 597 |
if (cookie->found) { if (cookie->nr_fids < 50) { cookie->fids[cookie->nr_fids].vnode = ino; cookie->fids[cookie->nr_fids].unique = dtype; cookie->nr_fids++; } } else if (cookie->name.len == nlen && memcmp(cookie->name.name, name, nlen) == 0) { |
e49c7b2f6 afs: Build an abs... |
598 599 |
cookie->fids[1].vnode = ino; cookie->fids[1].unique = dtype; |
5cf9dd55a afs: Prospectivel... |
600 601 602 603 604 605 606 607 608 609 610 |
cookie->found = 1; if (cookie->one_only) return -1; } ret = cookie->nr_fids >= 50 ? -1 : 0; _leave(" = %d", ret); return ret; } /* |
e49c7b2f6 afs: Build an abs... |
611 612 613 614 615 616 617 618 619 620 621 622 623 624 625 626 627 628 629 |
* Deal with the result of a successful lookup operation. Turn all the files * into inodes and save the first one - which is the one we actually want. */ static void afs_do_lookup_success(struct afs_operation *op) { struct afs_vnode_param *vp; struct afs_vnode *vnode; struct inode *inode; u32 abort_code; int i; _enter(""); for (i = 0; i < op->nr_files; i++) { switch (i) { case 0: vp = &op->file[0]; abort_code = vp->scb.status.abort_code; if (abort_code != 0) { |
44767c353 afs: Remove afs_o... |
630 |
op->ac.abort_code = abort_code; |
e49c7b2f6 afs: Build an abs... |
631 632 633 634 635 636 637 638 639 640 641 642 643 644 645 646 647 648 649 650 651 652 653 654 655 656 657 658 659 660 661 662 663 664 665 666 667 668 669 670 671 672 673 674 675 676 |
op->error = afs_abort_to_error(abort_code); } break; case 1: vp = &op->file[1]; break; default: vp = &op->more_files[i - 2]; break; } if (!vp->scb.have_status && !vp->scb.have_error) continue; _debug("do [%u]", i); if (vp->vnode) { if (!test_bit(AFS_VNODE_UNSET, &vp->vnode->flags)) afs_vnode_commit_status(op, vp); } else if (vp->scb.status.abort_code == 0) { inode = afs_iget(op, vp); if (!IS_ERR(inode)) { vnode = AFS_FS_I(inode); afs_cache_permit(vnode, op->key, 0 /* Assume vnode->cb_break is 0 */ + op->cb_v_break, &vp->scb); vp->vnode = vnode; vp->put_vnode = true; } } else { _debug("- abort %d %llx:%llx.%x", vp->scb.status.abort_code, vp->fid.vid, vp->fid.vnode, vp->fid.unique); } } _leave(""); } static const struct afs_operation_ops afs_inline_bulk_status_operation = { .issue_afs_rpc = afs_fs_inline_bulk_status, .issue_yfs_rpc = yfs_fs_inline_bulk_status, .success = afs_do_lookup_success, }; |
b6489a49f afs: Fix silly re... |
677 |
static const struct afs_operation_ops afs_lookup_fetch_status_operation = { |
e49c7b2f6 afs: Build an abs... |
678 679 680 |
.issue_afs_rpc = afs_fs_fetch_status, .issue_yfs_rpc = yfs_fs_fetch_status, .success = afs_do_lookup_success, |
728279a5a afs: Fix use of a... |
681 |
.aborted = afs_check_for_remote_deletion, |
e49c7b2f6 afs: Build an abs... |
682 683 684 |
}; /* |
20325960f afs: Reorganise v... |
685 686 687 688 689 690 691 692 693 694 695 696 697 698 699 700 701 702 703 704 705 706 707 708 709 710 711 712 713 714 715 |
* See if we know that the server we expect to use doesn't support * FS.InlineBulkStatus. */ static bool afs_server_supports_ibulk(struct afs_vnode *dvnode) { struct afs_server_list *slist; struct afs_volume *volume = dvnode->volume; struct afs_server *server; bool ret = true; int i; if (!test_bit(AFS_VOLUME_MAYBE_NO_IBULK, &volume->flags)) return true; rcu_read_lock(); slist = rcu_dereference(volume->servers); for (i = 0; i < slist->nr_servers; i++) { server = slist->servers[i].server; if (server == dvnode->cb_server) { if (test_bit(AFS_SERVER_FL_NO_IBULK, &server->flags)) ret = false; break; } } rcu_read_unlock(); return ret; } /* |
5cf9dd55a afs: Prospectivel... |
716 717 718 719 720 721 722 723 |
* Do a lookup in a directory. We make use of bulk lookup to query a slew of * files in one go and create inodes for them. The inode of the file we were * asked for is returned. */ static struct inode *afs_do_lookup(struct inode *dir, struct dentry *dentry, struct key *key) { struct afs_lookup_cookie *cookie; |
e49c7b2f6 afs: Build an abs... |
724 725 |
struct afs_vnode_param *vp; struct afs_operation *op; |
39db9815d afs: Fix applicat... |
726 727 |
struct afs_vnode *dvnode = AFS_FS_I(dir), *vnode; struct inode *inode = NULL, *ti; |
9dd0b82ef afs: Fix missing ... |
728 |
afs_dataversion_t data_version = READ_ONCE(dvnode->status.data_version); |
e49c7b2f6 afs: Build an abs... |
729 730 |
long ret; int i; |
5cf9dd55a afs: Prospectivel... |
731 732 733 734 735 736 |
_enter("{%lu},%p{%pd},", dir->i_ino, dentry, dentry); cookie = kzalloc(sizeof(struct afs_lookup_cookie), GFP_KERNEL); if (!cookie) return ERR_PTR(-ENOMEM); |
e49c7b2f6 afs: Build an abs... |
737 738 |
for (i = 0; i < ARRAY_SIZE(cookie->fids); i++) cookie->fids[i].vid = dvnode->fid.vid; |
5cf9dd55a afs: Prospectivel... |
739 740 |
cookie->ctx.actor = afs_lookup_filldir; cookie->name = dentry->d_name; |
13fcc6356 afs: Always inclu... |
741 742 |
cookie->nr_fids = 2; /* slot 0 is saved for the fid we actually want * and slot 1 for the directory */ |
5cf9dd55a afs: Prospectivel... |
743 |
|
20325960f afs: Reorganise v... |
744 745 |
if (!afs_server_supports_ibulk(dvnode)) cookie->one_only = true; |
5cf9dd55a afs: Prospectivel... |
746 |
|
5cf9dd55a afs: Prospectivel... |
747 |
/* search the directory */ |
9dd0b82ef afs: Fix missing ... |
748 |
ret = afs_dir_iterate(dir, &cookie->ctx, key, &data_version); |
e49c7b2f6 afs: Build an abs... |
749 |
if (ret < 0) |
5cf9dd55a afs: Prospectivel... |
750 |
goto out; |
5cf9dd55a afs: Prospectivel... |
751 |
|
9dd0b82ef afs: Fix missing ... |
752 |
dentry->d_fsdata = (void *)(unsigned long)data_version; |
e49c7b2f6 afs: Build an abs... |
753 |
ret = -ENOENT; |
5cf9dd55a afs: Prospectivel... |
754 755 756 757 |
if (!cookie->found) goto out; /* Check to see if we already have an inode for the primary fid. */ |
e49c7b2f6 afs: Build an abs... |
758 759 |
inode = ilookup5(dir->i_sb, cookie->fids[1].vnode, afs_ilookup5_test_by_fid, &cookie->fids[1]); |
5cf9dd55a afs: Prospectivel... |
760 |
if (inode) |
e49c7b2f6 afs: Build an abs... |
761 |
goto out; /* We do */ |
5cf9dd55a afs: Prospectivel... |
762 |
|
e49c7b2f6 afs: Build an abs... |
763 764 765 766 767 768 769 |
/* Okay, we didn't find it. We need to query the server - and whilst * we're doing that, we're going to attempt to look up a bunch of other * vnodes also. */ op = afs_alloc_operation(NULL, dvnode->volume); if (IS_ERR(op)) { ret = PTR_ERR(op); |
5cf9dd55a afs: Prospectivel... |
770 |
goto out; |
e49c7b2f6 afs: Build an abs... |
771 |
} |
5cf9dd55a afs: Prospectivel... |
772 |
|
e49c7b2f6 afs: Build an abs... |
773 774 |
afs_op_set_vnode(op, 0, dvnode); afs_op_set_fid(op, 1, &cookie->fids[1]); |
13fcc6356 afs: Always inclu... |
775 |
|
e49c7b2f6 afs: Build an abs... |
776 777 |
op->nr_files = cookie->nr_fids; _debug("nr_files %u", op->nr_files); |
39db9815d afs: Fix applicat... |
778 |
|
e49c7b2f6 afs: Build an abs... |
779 780 781 782 783 784 785 786 787 788 789 790 791 792 793 794 795 796 797 798 799 800 801 802 |
/* Need space for examining all the selected files */ op->error = -ENOMEM; if (op->nr_files > 2) { op->more_files = kvcalloc(op->nr_files - 2, sizeof(struct afs_vnode_param), GFP_KERNEL); if (!op->more_files) goto out_op; for (i = 2; i < op->nr_files; i++) { vp = &op->more_files[i - 2]; vp->fid = cookie->fids[i]; /* Find any inodes that already exist and get their * callback counters. */ ti = ilookup5_nowait(dir->i_sb, vp->fid.vnode, afs_ilookup5_test_by_fid, &vp->fid); if (!IS_ERR_OR_NULL(ti)) { vnode = AFS_FS_I(ti); vp->dv_before = vnode->status.data_version; vp->cb_break_before = afs_calc_vnode_cb_break(vnode); vp->vnode = vnode; vp->put_vnode = true; |
a9e5c87ca afs: Fix speculat... |
803 |
vp->speculative = true; /* vnode not locked */ |
e49c7b2f6 afs: Build an abs... |
804 |
} |
39db9815d afs: Fix applicat... |
805 806 |
} } |
5cf9dd55a afs: Prospectivel... |
807 808 809 810 |
/* Try FS.InlineBulkStatus first. Abort codes for the individual * lookups contained therein are stored in the reply without aborting * the whole operation. */ |
e49c7b2f6 afs: Build an abs... |
811 812 813 814 815 |
op->error = -ENOTSUPP; if (!cookie->one_only) { op->ops = &afs_inline_bulk_status_operation; afs_begin_vnode_operation(op); afs_wait_for_operation(op); |
5cf9dd55a afs: Prospectivel... |
816 |
} |
e49c7b2f6 afs: Build an abs... |
817 818 819 820 821 822 |
if (op->error == -ENOTSUPP) { /* We could try FS.BulkStatus next, but this aborts the entire * op if any of the lookups fails - so, for the moment, revert * to FS.FetchStatus for op->file[1]. */ op->fetch_status.which = 1; |
f8ea5c7bc afs: Fix afs_do_l... |
823 |
op->ops = &afs_lookup_fetch_status_operation; |
e49c7b2f6 afs: Build an abs... |
824 825 |
afs_begin_vnode_operation(op); afs_wait_for_operation(op); |
5cf9dd55a afs: Prospectivel... |
826 |
} |
e49c7b2f6 afs: Build an abs... |
827 |
inode = ERR_PTR(op->error); |
5cf9dd55a afs: Prospectivel... |
828 |
|
e49c7b2f6 afs: Build an abs... |
829 830 831 832 |
out_op: if (op->error == 0) { inode = &op->file[1].vnode->vfs_inode; op->file[1].vnode = NULL; |
5cf9dd55a afs: Prospectivel... |
833 |
} |
e49c7b2f6 afs: Build an abs... |
834 835 836 837 838 |
if (op->file[0].scb.have_status) dentry->d_fsdata = (void *)(unsigned long)op->file[0].scb.status.data_version; else dentry->d_fsdata = (void *)(unsigned long)op->file[0].dv_before; ret = afs_put_operation(op); |
5cf9dd55a afs: Prospectivel... |
839 840 |
out: kfree(cookie); |
e49c7b2f6 afs: Build an abs... |
841 842 |
_leave(""); return inode ?: ERR_PTR(ret); |
5cf9dd55a afs: Prospectivel... |
843 844 845 |
} /* |
6f8880d8e afs: Implement @s... |
846 847 848 849 850 851 852 853 854 855 856 857 858 859 860 861 862 863 864 865 866 867 868 869 870 871 872 873 874 875 876 877 878 879 880 881 882 883 884 885 886 887 888 889 890 891 892 893 894 895 896 897 898 899 900 901 |
* Look up an entry in a directory with @sys substitution. */ static struct dentry *afs_lookup_atsys(struct inode *dir, struct dentry *dentry, struct key *key) { struct afs_sysnames *subs; struct afs_net *net = afs_i2net(dir); struct dentry *ret; char *buf, *p, *name; int len, i; _enter(""); ret = ERR_PTR(-ENOMEM); p = buf = kmalloc(AFSNAMEMAX, GFP_KERNEL); if (!buf) goto out_p; if (dentry->d_name.len > 4) { memcpy(p, dentry->d_name.name, dentry->d_name.len - 4); p += dentry->d_name.len - 4; } /* There is an ordered list of substitutes that we have to try. */ read_lock(&net->sysnames_lock); subs = net->sysnames; refcount_inc(&subs->usage); read_unlock(&net->sysnames_lock); for (i = 0; i < subs->nr; i++) { name = subs->subs[i]; len = dentry->d_name.len - 4 + strlen(name); if (len >= AFSNAMEMAX) { ret = ERR_PTR(-ENAMETOOLONG); goto out_s; } strcpy(p, name); ret = lookup_one_len(buf, dentry->d_parent, len); if (IS_ERR(ret) || d_is_positive(ret)) goto out_s; dput(ret); } /* We don't want to d_add() the @sys dentry here as we don't want to * the cached dentry to hide changes to the sysnames list. */ ret = NULL; out_s: afs_put_sysnames(subs); kfree(buf); out_p: key_put(key); return ret; } /* |
08e0e7c82 [AF_RXRPC]: Make ... |
902 903 |
* look up an entry in a directory */ |
260a98031 [AFS]: Add "direc... |
904 |
static struct dentry *afs_lookup(struct inode *dir, struct dentry *dentry, |
00cd8dd3b stop passing name... |
905 |
unsigned int flags) |
08e0e7c82 [AF_RXRPC]: Make ... |
906 |
{ |
5cf9dd55a afs: Prospectivel... |
907 |
struct afs_vnode *dvnode = AFS_FS_I(dir); |
40a708bd6 afs: Fix use-afte... |
908 |
struct afs_fid fid = {}; |
08e0e7c82 [AF_RXRPC]: Make ... |
909 |
struct inode *inode; |
34b2a88fb afs_lookup(): swi... |
910 |
struct dentry *d; |
00d3b7a45 [AFS]: Add securi... |
911 |
struct key *key; |
08e0e7c82 [AF_RXRPC]: Make ... |
912 |
int ret; |
3b6492df4 afs: Increase to ... |
913 |
_enter("{%llx:%llu},%p{%pd},", |
5cf9dd55a afs: Prospectivel... |
914 |
dvnode->fid.vid, dvnode->fid.vnode, dentry, dentry); |
260a98031 [AFS]: Add "direc... |
915 |
|
2b0143b5c VFS: normal files... |
916 |
ASSERTCMP(d_inode(dentry), ==, NULL); |
08e0e7c82 [AF_RXRPC]: Make ... |
917 |
|
45222b9e0 AFS: implement st... |
918 |
if (dentry->d_name.len >= AFSNAMEMAX) { |
08e0e7c82 [AF_RXRPC]: Make ... |
919 920 921 |
_leave(" = -ENAMETOOLONG"); return ERR_PTR(-ENAMETOOLONG); } |
5cf9dd55a afs: Prospectivel... |
922 |
if (test_bit(AFS_VNODE_DELETED, &dvnode->flags)) { |
08e0e7c82 [AF_RXRPC]: Make ... |
923 924 925 |
_leave(" = -ESTALE"); return ERR_PTR(-ESTALE); } |
5cf9dd55a afs: Prospectivel... |
926 |
key = afs_request_key(dvnode->volume->cell); |
00d3b7a45 [AFS]: Add securi... |
927 928 |
if (IS_ERR(key)) { _leave(" = %ld [key]", PTR_ERR(key)); |
e231c2ee6 Convert ERR_PTR(P... |
929 |
return ERR_CAST(key); |
00d3b7a45 [AFS]: Add securi... |
930 |
} |
5cf9dd55a afs: Prospectivel... |
931 |
ret = afs_validate(dvnode, key); |
260a98031 [AFS]: Add "direc... |
932 933 934 935 936 |
if (ret < 0) { key_put(key); _leave(" = %d [val]", ret); return ERR_PTR(ret); } |
6f8880d8e afs: Implement @s... |
937 938 939 940 941 942 |
if (dentry->d_name.len >= 4 && dentry->d_name.name[dentry->d_name.len - 4] == '@' && dentry->d_name.name[dentry->d_name.len - 3] == 's' && dentry->d_name.name[dentry->d_name.len - 2] == 'y' && dentry->d_name.name[dentry->d_name.len - 1] == 's') return afs_lookup_atsys(dir, dentry, key); |
d55b4da43 afs: Introduce a ... |
943 |
afs_stat_v(dvnode, n_lookup); |
5cf9dd55a afs: Prospectivel... |
944 |
inode = afs_do_lookup(dir, dentry, key); |
00d3b7a45 [AFS]: Add securi... |
945 |
key_put(key); |
f52b83b0b afs: Fix afs_look... |
946 |
if (inode == ERR_PTR(-ENOENT)) |
34b2a88fb afs_lookup(): swi... |
947 |
inode = afs_try_auto_mntpt(dentry, dir); |
40a708bd6 afs: Fix use-afte... |
948 949 950 |
if (!IS_ERR_OR_NULL(inode)) fid = AFS_FS_I(inode)->fid; |
fed79fd78 afs: Fix debuggin... |
951 |
_debug("splice %p", dentry->d_inode); |
34b2a88fb afs_lookup(): swi... |
952 |
d = d_splice_alias(inode, dentry); |
80548b039 afs: Add more tra... |
953 |
if (!IS_ERR_OR_NULL(d)) { |
34b2a88fb afs_lookup(): swi... |
954 |
d->d_fsdata = dentry->d_fsdata; |
40a708bd6 afs: Fix use-afte... |
955 |
trace_afs_lookup(dvnode, &d->d_name, &fid); |
80548b039 afs: Add more tra... |
956 |
} else { |
40a708bd6 afs: Fix use-afte... |
957 |
trace_afs_lookup(dvnode, &dentry->d_name, &fid); |
80548b039 afs: Add more tra... |
958 |
} |
e49c7b2f6 afs: Build an abs... |
959 |
_leave(""); |
34b2a88fb afs_lookup(): swi... |
960 |
return d; |
ec26815ad [AFS]: Clean up t... |
961 |
} |
1da177e4c Linux-2.6.12-rc2 |
962 |
|
1da177e4c Linux-2.6.12-rc2 |
963 |
/* |
a0753c290 afs: Support RCU ... |
964 965 966 967 968 969 970 971 972 973 974 975 976 977 978 979 980 981 982 983 984 985 986 987 988 989 990 991 992 993 994 995 996 997 998 999 1000 1001 1002 1003 1004 1005 1006 1007 1008 1009 1010 1011 1012 1013 1014 1015 |
* Check the validity of a dentry under RCU conditions. */ static int afs_d_revalidate_rcu(struct dentry *dentry) { struct afs_vnode *dvnode, *vnode; struct dentry *parent; struct inode *dir, *inode; long dir_version, de_version; _enter("%p", dentry); /* Check the parent directory is still valid first. */ parent = READ_ONCE(dentry->d_parent); dir = d_inode_rcu(parent); if (!dir) return -ECHILD; dvnode = AFS_FS_I(dir); if (test_bit(AFS_VNODE_DELETED, &dvnode->flags)) return -ECHILD; if (!afs_check_validity(dvnode)) return -ECHILD; /* We only need to invalidate a dentry if the server's copy changed * behind our back. If we made the change, it's no problem. Note that * on a 32-bit system, we only have 32 bits in the dentry to store the * version. */ dir_version = (long)READ_ONCE(dvnode->status.data_version); de_version = (long)READ_ONCE(dentry->d_fsdata); if (de_version != dir_version) { dir_version = (long)READ_ONCE(dvnode->invalid_before); if (de_version - dir_version < 0) return -ECHILD; } /* Check to see if the vnode referred to by the dentry still * has a callback. */ if (d_really_is_positive(dentry)) { inode = d_inode_rcu(dentry); if (inode) { vnode = AFS_FS_I(inode); if (!afs_check_validity(vnode)) return -ECHILD; } } return 1; /* Still valid */ } /* |
1da177e4c Linux-2.6.12-rc2 |
1016 1017 1018 |
* check that a dentry lookup hit has found a valid entry * - NOTE! the hit can be a negative hit too, so we can't assume we have an * inode |
1da177e4c Linux-2.6.12-rc2 |
1019 |
*/ |
0b728e191 stop passing name... |
1020 |
static int afs_d_revalidate(struct dentry *dentry, unsigned int flags) |
1da177e4c Linux-2.6.12-rc2 |
1021 |
{ |
260a98031 [AFS]: Add "direc... |
1022 |
struct afs_vnode *vnode, *dir; |
3f649ab72 treewide: Remove ... |
1023 |
struct afs_fid fid; |
1da177e4c Linux-2.6.12-rc2 |
1024 |
struct dentry *parent; |
c435ee345 afs: Overhaul the... |
1025 |
struct inode *inode; |
00d3b7a45 [AFS]: Add securi... |
1026 |
struct key *key; |
40fc81027 afs: Fix afs_d_va... |
1027 |
afs_dataversion_t dir_version, invalid_before; |
9dd0b82ef afs: Fix missing ... |
1028 |
long de_version; |
1da177e4c Linux-2.6.12-rc2 |
1029 |
int ret; |
0b728e191 stop passing name... |
1030 |
if (flags & LOOKUP_RCU) |
a0753c290 afs: Support RCU ... |
1031 |
return afs_d_revalidate_rcu(dentry); |
34286d666 fs: rcu-walk awar... |
1032 |
|
c435ee345 afs: Overhaul the... |
1033 1034 |
if (d_really_is_positive(dentry)) { vnode = AFS_FS_I(d_inode(dentry)); |
3b6492df4 afs: Increase to ... |
1035 |
_enter("{v={%llx:%llu} n=%pd fl=%lx},", |
a455589f1 assorted conversi... |
1036 |
vnode->fid.vid, vnode->fid.vnode, dentry, |
260a98031 [AFS]: Add "direc... |
1037 |
vnode->flags); |
c435ee345 afs: Overhaul the... |
1038 |
} else { |
a455589f1 assorted conversi... |
1039 |
_enter("{neg n=%pd}", dentry); |
c435ee345 afs: Overhaul the... |
1040 |
} |
1da177e4c Linux-2.6.12-rc2 |
1041 |
|
260a98031 [AFS]: Add "direc... |
1042 |
key = afs_request_key(AFS_FS_S(dentry->d_sb)->volume->cell); |
00d3b7a45 [AFS]: Add securi... |
1043 1044 |
if (IS_ERR(key)) key = NULL; |
c435ee345 afs: Overhaul the... |
1045 1046 1047 1048 1049 1050 1051 1052 1053 |
if (d_really_is_positive(dentry)) { inode = d_inode(dentry); if (inode) { vnode = AFS_FS_I(inode); afs_validate(vnode, key); if (test_bit(AFS_VNODE_DELETED, &vnode->flags)) goto out_bad; } } |
1da177e4c Linux-2.6.12-rc2 |
1054 |
/* lock down the parent dentry so we can peer at it */ |
08e0e7c82 [AF_RXRPC]: Make ... |
1055 |
parent = dget_parent(dentry); |
2b0143b5c VFS: normal files... |
1056 |
dir = AFS_FS_I(d_inode(parent)); |
1da177e4c Linux-2.6.12-rc2 |
1057 |
|
260a98031 [AFS]: Add "direc... |
1058 |
/* validate the parent directory */ |
c435ee345 afs: Overhaul the... |
1059 |
afs_validate(dir, key); |
260a98031 [AFS]: Add "direc... |
1060 1061 |
if (test_bit(AFS_VNODE_DELETED, &dir->flags)) { |
a455589f1 assorted conversi... |
1062 |
_debug("%pd: parent dir deleted", dentry); |
c435ee345 afs: Overhaul the... |
1063 |
goto out_bad_parent; |
1da177e4c Linux-2.6.12-rc2 |
1064 |
} |
a4ff7401f afs: Keep track o... |
1065 1066 1067 1068 1069 |
/* We only need to invalidate a dentry if the server's copy changed * behind our back. If we made the change, it's no problem. Note that * on a 32-bit system, we only have 32 bits in the dentry to store the * version. */ |
9dd0b82ef afs: Fix missing ... |
1070 |
dir_version = dir->status.data_version; |
a4ff7401f afs: Keep track o... |
1071 |
de_version = (long)dentry->d_fsdata; |
9dd0b82ef afs: Fix missing ... |
1072 |
if (de_version == (long)dir_version) |
5dc84855b afs: Only update ... |
1073 |
goto out_valid_noupdate; |
a4ff7401f afs: Keep track o... |
1074 |
|
40fc81027 afs: Fix afs_d_va... |
1075 1076 |
invalid_before = dir->invalid_before; if (de_version - (long)invalid_before >= 0) |
a4ff7401f afs: Keep track o... |
1077 |
goto out_valid; |
1da177e4c Linux-2.6.12-rc2 |
1078 |
|
260a98031 [AFS]: Add "direc... |
1079 |
_debug("dir modified"); |
d55b4da43 afs: Introduce a ... |
1080 |
afs_stat_v(dir, n_reval); |
260a98031 [AFS]: Add "direc... |
1081 1082 |
/* search the directory for this vnode */ |
9dd0b82ef afs: Fix missing ... |
1083 |
ret = afs_do_lookup_one(&dir->vfs_inode, dentry, &fid, key, &dir_version); |
260a98031 [AFS]: Add "direc... |
1084 1085 1086 |
switch (ret) { case 0: /* the filename maps to something */ |
2b0143b5c VFS: normal files... |
1087 |
if (d_really_is_negative(dentry)) |
c435ee345 afs: Overhaul the... |
1088 1089 1090 |
goto out_bad_parent; inode = d_inode(dentry); if (is_bad_inode(inode)) { |
a455589f1 assorted conversi... |
1091 1092 1093 |
printk("kAFS: afs_d_revalidate: %pd2 has bad inode ", dentry); |
c435ee345 afs: Overhaul the... |
1094 |
goto out_bad_parent; |
1da177e4c Linux-2.6.12-rc2 |
1095 |
} |
c435ee345 afs: Overhaul the... |
1096 |
vnode = AFS_FS_I(inode); |
1da177e4c Linux-2.6.12-rc2 |
1097 1098 |
/* if the vnode ID has changed, then the dirent points to a * different file */ |
08e0e7c82 [AF_RXRPC]: Make ... |
1099 |
if (fid.vnode != vnode->fid.vnode) { |
3b6492df4 afs: Increase to ... |
1100 |
_debug("%pd: dirent changed [%llu != %llu]", |
a455589f1 assorted conversi... |
1101 |
dentry, fid.vnode, |
08e0e7c82 [AF_RXRPC]: Make ... |
1102 |
vnode->fid.vnode); |
1da177e4c Linux-2.6.12-rc2 |
1103 1104 1105 1106 |
goto not_found; } /* if the vnode ID uniqifier has changed, then the file has |
260a98031 [AFS]: Add "direc... |
1107 1108 |
* been deleted and replaced, and the original vnode ID has * been reused */ |
08e0e7c82 [AF_RXRPC]: Make ... |
1109 |
if (fid.unique != vnode->fid.unique) { |
a455589f1 assorted conversi... |
1110 1111 |
_debug("%pd: file deleted (uq %u -> %u I:%u)", dentry, fid.unique, |
7a224228e vfs: Add 64 bit i... |
1112 |
vnode->fid.unique, |
c435ee345 afs: Overhaul the... |
1113 1114 |
vnode->vfs_inode.i_generation); write_seqlock(&vnode->cb_lock); |
08e0e7c82 [AF_RXRPC]: Make ... |
1115 |
set_bit(AFS_VNODE_DELETED, &vnode->flags); |
c435ee345 afs: Overhaul the... |
1116 |
write_sequnlock(&vnode->cb_lock); |
260a98031 [AFS]: Add "direc... |
1117 |
goto not_found; |
1da177e4c Linux-2.6.12-rc2 |
1118 |
} |
260a98031 [AFS]: Add "direc... |
1119 |
goto out_valid; |
08e0e7c82 [AF_RXRPC]: Make ... |
1120 |
|
260a98031 [AFS]: Add "direc... |
1121 1122 |
case -ENOENT: /* the filename is unknown */ |
a455589f1 assorted conversi... |
1123 |
_debug("%pd: dirent not found", dentry); |
2b0143b5c VFS: normal files... |
1124 |
if (d_really_is_positive(dentry)) |
260a98031 [AFS]: Add "direc... |
1125 1126 |
goto not_found; goto out_valid; |
1da177e4c Linux-2.6.12-rc2 |
1127 |
|
260a98031 [AFS]: Add "direc... |
1128 |
default: |
a455589f1 assorted conversi... |
1129 1130 |
_debug("failed to iterate dir %pd: %d", parent, ret); |
c435ee345 afs: Overhaul the... |
1131 |
goto out_bad_parent; |
08e0e7c82 [AF_RXRPC]: Make ... |
1132 |
} |
ec26815ad [AFS]: Clean up t... |
1133 |
out_valid: |
9dd0b82ef afs: Fix missing ... |
1134 |
dentry->d_fsdata = (void *)(unsigned long)dir_version; |
5dc84855b afs: Only update ... |
1135 |
out_valid_noupdate: |
1da177e4c Linux-2.6.12-rc2 |
1136 |
dput(parent); |
00d3b7a45 [AFS]: Add securi... |
1137 |
key_put(key); |
1da177e4c Linux-2.6.12-rc2 |
1138 1139 1140 1141 |
_leave(" = 1 [valid]"); return 1; /* the dirent, if it exists, now points to a different vnode */ |
ec26815ad [AFS]: Clean up t... |
1142 |
not_found: |
1da177e4c Linux-2.6.12-rc2 |
1143 1144 1145 |
spin_lock(&dentry->d_lock); dentry->d_flags |= DCACHE_NFSFS_RENAMED; spin_unlock(&dentry->d_lock); |
c435ee345 afs: Overhaul the... |
1146 |
out_bad_parent: |
a455589f1 assorted conversi... |
1147 |
_debug("dropping dentry %pd2", dentry); |
1da177e4c Linux-2.6.12-rc2 |
1148 |
dput(parent); |
c435ee345 afs: Overhaul the... |
1149 |
out_bad: |
00d3b7a45 [AFS]: Add securi... |
1150 |
key_put(key); |
1da177e4c Linux-2.6.12-rc2 |
1151 1152 1153 |
_leave(" = 0 [bad]"); return 0; |
ec26815ad [AFS]: Clean up t... |
1154 |
} |
1da177e4c Linux-2.6.12-rc2 |
1155 |
|
1da177e4c Linux-2.6.12-rc2 |
1156 1157 1158 1159 1160 1161 |
/* * allow the VFS to enquire as to whether a dentry should be unhashed (mustn't * sleep) * - called from dput() when d_count is going to 0. * - return 1 to request dentry be unhashed, 0 otherwise */ |
fe15ce446 fs: change d_dele... |
1162 |
static int afs_d_delete(const struct dentry *dentry) |
1da177e4c Linux-2.6.12-rc2 |
1163 |
{ |
a455589f1 assorted conversi... |
1164 |
_enter("%pd", dentry); |
1da177e4c Linux-2.6.12-rc2 |
1165 1166 1167 |
if (dentry->d_flags & DCACHE_NFSFS_RENAMED) goto zap; |
2b0143b5c VFS: normal files... |
1168 1169 1170 |
if (d_really_is_positive(dentry) && (test_bit(AFS_VNODE_DELETED, &AFS_FS_I(d_inode(dentry))->flags) || test_bit(AFS_VNODE_PSEUDODIR, &AFS_FS_I(d_inode(dentry))->flags))) |
bec5eb614 AFS: Implement an... |
1171 |
goto zap; |
1da177e4c Linux-2.6.12-rc2 |
1172 1173 1174 |
_leave(" = 0 [keep]"); return 0; |
ec26815ad [AFS]: Clean up t... |
1175 |
zap: |
1da177e4c Linux-2.6.12-rc2 |
1176 1177 |
_leave(" = 1 [zap]"); return 1; |
ec26815ad [AFS]: Clean up t... |
1178 |
} |
260a98031 [AFS]: Add "direc... |
1179 1180 |
/* |
79ddbfa50 afs: Implement si... |
1181 1182 1183 1184 1185 1186 1187 1188 1189 1190 |
* Clean up sillyrename files on dentry removal. */ static void afs_d_iput(struct dentry *dentry, struct inode *inode) { if (dentry->d_flags & DCACHE_NFSFS_RENAMED) afs_silly_iput(dentry, inode); iput(inode); } /* |
260a98031 [AFS]: Add "direc... |
1191 1192 |
* handle dentry release */ |
66c7e1d31 afs: Split the dy... |
1193 |
void afs_d_release(struct dentry *dentry) |
260a98031 [AFS]: Add "direc... |
1194 |
{ |
a455589f1 assorted conversi... |
1195 |
_enter("%pd", dentry); |
260a98031 [AFS]: Add "direc... |
1196 |
} |
728279a5a afs: Fix use of a... |
1197 1198 1199 1200 1201 1202 1203 1204 1205 1206 |
void afs_check_for_remote_deletion(struct afs_operation *op) { struct afs_vnode *vnode = op->file[0].vnode; switch (op->ac.abort_code) { case VNOVNODE: set_bit(AFS_VNODE_DELETED, &vnode->flags); afs_break_callback(vnode, afs_cb_break_for_deleted); } } |
260a98031 [AFS]: Add "direc... |
1207 |
/* |
d2ddc776a afs: Overhaul vol... |
1208 1209 |
* Create a new inode for create/mkdir/symlink */ |
e49c7b2f6 afs: Build an abs... |
1210 |
static void afs_vnode_new_inode(struct afs_operation *op) |
d2ddc776a afs: Overhaul vol... |
1211 |
{ |
e49c7b2f6 afs: Build an abs... |
1212 |
struct afs_vnode_param *vp = &op->file[1]; |
5a8132761 afs: Do better ac... |
1213 |
struct afs_vnode *vnode; |
d2ddc776a afs: Overhaul vol... |
1214 |
struct inode *inode; |
e49c7b2f6 afs: Build an abs... |
1215 1216 1217 |
_enter(""); ASSERTCMP(op->error, ==, 0); |
d2ddc776a afs: Overhaul vol... |
1218 |
|
e49c7b2f6 afs: Build an abs... |
1219 |
inode = afs_iget(op, vp); |
d2ddc776a afs: Overhaul vol... |
1220 1221 1222 1223 |
if (IS_ERR(inode)) { /* ENOMEM or EINTR at a really inconvenient time - just abandon * the new directory on the server. */ |
e49c7b2f6 afs: Build an abs... |
1224 |
op->error = PTR_ERR(inode); |
d2ddc776a afs: Overhaul vol... |
1225 1226 |
return; } |
5a8132761 afs: Do better ac... |
1227 1228 |
vnode = AFS_FS_I(inode); set_bit(AFS_VNODE_NEW_CONTENT, &vnode->flags); |
e49c7b2f6 afs: Build an abs... |
1229 1230 1231 |
if (!op->error) afs_cache_permit(vnode, op->key, vnode->cb_break, &vp->scb); d_instantiate(op->dentry, inode); |
d2ddc776a afs: Overhaul vol... |
1232 |
} |
e49c7b2f6 afs: Build an abs... |
1233 |
static void afs_create_success(struct afs_operation *op) |
b83591532 afs: Pass pre-fet... |
1234 |
{ |
e49c7b2f6 afs: Build an abs... |
1235 |
_enter("op=%08x", op->debug_id); |
da8d07551 afs: Concoct ctimes |
1236 |
op->ctime = op->file[0].scb.status.mtime_client; |
e49c7b2f6 afs: Build an abs... |
1237 1238 1239 |
afs_vnode_commit_status(op, &op->file[0]); afs_update_dentry_version(op, &op->file[0], op->dentry); afs_vnode_new_inode(op); |
b83591532 afs: Pass pre-fet... |
1240 |
} |
e49c7b2f6 afs: Build an abs... |
1241 |
static void afs_create_edit_dir(struct afs_operation *op) |
9dd0b82ef afs: Fix missing ... |
1242 |
{ |
e49c7b2f6 afs: Build an abs... |
1243 1244 1245 1246 1247 1248 1249 1250 1251 1252 1253 1254 |
struct afs_vnode_param *dvp = &op->file[0]; struct afs_vnode_param *vp = &op->file[1]; struct afs_vnode *dvnode = dvp->vnode; _enter("op=%08x", op->debug_id); down_write(&dvnode->validate_lock); if (test_bit(AFS_VNODE_DIR_VALID, &dvnode->flags) && dvnode->status.data_version == dvp->dv_before + dvp->dv_delta) afs_edit_dir_add(dvnode, &op->dentry->d_name, &vp->fid, op->create.reason); up_write(&dvnode->validate_lock); |
9dd0b82ef afs: Fix missing ... |
1255 |
} |
e49c7b2f6 afs: Build an abs... |
1256 1257 1258 1259 1260 1261 1262 1263 1264 1265 1266 1267 |
static void afs_create_put(struct afs_operation *op) { _enter("op=%08x", op->debug_id); if (op->error) d_drop(op->dentry); } static const struct afs_operation_ops afs_mkdir_operation = { .issue_afs_rpc = afs_fs_make_dir, .issue_yfs_rpc = yfs_fs_make_dir, .success = afs_create_success, |
728279a5a afs: Fix use of a... |
1268 |
.aborted = afs_check_for_remote_deletion, |
e49c7b2f6 afs: Build an abs... |
1269 1270 1271 |
.edit_dir = afs_create_edit_dir, .put = afs_create_put, }; |
9dd0b82ef afs: Fix missing ... |
1272 |
/* |
260a98031 [AFS]: Add "direc... |
1273 1274 |
* create a directory on an AFS filesystem */ |
18bb1db3e switch vfs_mkdir(... |
1275 |
static int afs_mkdir(struct inode *dir, struct dentry *dentry, umode_t mode) |
260a98031 [AFS]: Add "direc... |
1276 |
{ |
e49c7b2f6 afs: Build an abs... |
1277 |
struct afs_operation *op; |
d2ddc776a afs: Overhaul vol... |
1278 |
struct afs_vnode *dvnode = AFS_FS_I(dir); |
260a98031 [AFS]: Add "direc... |
1279 |
|
3b6492df4 afs: Increase to ... |
1280 |
_enter("{%llx:%llu},{%pd},%ho", |
a455589f1 assorted conversi... |
1281 |
dvnode->fid.vid, dvnode->fid.vnode, dentry, mode); |
260a98031 [AFS]: Add "direc... |
1282 |
|
e49c7b2f6 afs: Build an abs... |
1283 1284 1285 1286 |
op = afs_alloc_operation(NULL, dvnode->volume); if (IS_ERR(op)) { d_drop(dentry); return PTR_ERR(op); |
2105c2820 afs: Fix race bet... |
1287 |
} |
63a4681ff afs: Locally edit... |
1288 |
|
e49c7b2f6 afs: Build an abs... |
1289 1290 |
afs_op_set_vnode(op, 0, dvnode); op->file[0].dv_delta = 1; |
da8d07551 afs: Concoct ctimes |
1291 |
op->file[0].update_ctime = true; |
e49c7b2f6 afs: Build an abs... |
1292 1293 1294 1295 1296 |
op->dentry = dentry; op->create.mode = S_IFDIR | mode; op->create.reason = afs_edit_dir_for_mkdir; op->ops = &afs_mkdir_operation; return afs_do_sync_operation(op); |
260a98031 [AFS]: Add "direc... |
1297 1298 1299 |
} /* |
d2ddc776a afs: Overhaul vol... |
1300 1301 1302 1303 1304 1305 1306 1307 1308 1309 |
* Remove a subdir from a directory. */ static void afs_dir_remove_subdir(struct dentry *dentry) { if (d_really_is_positive(dentry)) { struct afs_vnode *vnode = AFS_FS_I(d_inode(dentry)); clear_nlink(&vnode->vfs_inode); set_bit(AFS_VNODE_DELETED, &vnode->flags); clear_bit(AFS_VNODE_CB_PROMISED, &vnode->flags); |
63a4681ff afs: Locally edit... |
1310 |
clear_bit(AFS_VNODE_DIR_VALID, &vnode->flags); |
d2ddc776a afs: Overhaul vol... |
1311 1312 |
} } |
e49c7b2f6 afs: Build an abs... |
1313 1314 1315 |
static void afs_rmdir_success(struct afs_operation *op) { _enter("op=%08x", op->debug_id); |
da8d07551 afs: Concoct ctimes |
1316 |
op->ctime = op->file[0].scb.status.mtime_client; |
e49c7b2f6 afs: Build an abs... |
1317 1318 1319 1320 1321 1322 1323 1324 1325 1326 1327 1328 1329 1330 1331 1332 1333 1334 1335 1336 1337 1338 1339 1340 1341 1342 1343 1344 1345 1346 1347 |
afs_vnode_commit_status(op, &op->file[0]); afs_update_dentry_version(op, &op->file[0], op->dentry); } static void afs_rmdir_edit_dir(struct afs_operation *op) { struct afs_vnode_param *dvp = &op->file[0]; struct afs_vnode *dvnode = dvp->vnode; _enter("op=%08x", op->debug_id); afs_dir_remove_subdir(op->dentry); down_write(&dvnode->validate_lock); if (test_bit(AFS_VNODE_DIR_VALID, &dvnode->flags) && dvnode->status.data_version == dvp->dv_before + dvp->dv_delta) afs_edit_dir_remove(dvnode, &op->dentry->d_name, afs_edit_dir_for_rmdir); up_write(&dvnode->validate_lock); } static void afs_rmdir_put(struct afs_operation *op) { _enter("op=%08x", op->debug_id); if (op->file[1].vnode) up_write(&op->file[1].vnode->rmdir_lock); } static const struct afs_operation_ops afs_rmdir_operation = { .issue_afs_rpc = afs_fs_remove_dir, .issue_yfs_rpc = yfs_fs_remove_dir, .success = afs_rmdir_success, |
728279a5a afs: Fix use of a... |
1348 |
.aborted = afs_check_for_remote_deletion, |
e49c7b2f6 afs: Build an abs... |
1349 1350 1351 |
.edit_dir = afs_rmdir_edit_dir, .put = afs_rmdir_put, }; |
d2ddc776a afs: Overhaul vol... |
1352 |
/* |
260a98031 [AFS]: Add "direc... |
1353 1354 1355 1356 |
* remove a directory from an AFS filesystem */ static int afs_rmdir(struct inode *dir, struct dentry *dentry) { |
e49c7b2f6 afs: Build an abs... |
1357 |
struct afs_operation *op; |
f58db83fd afs: Get the targ... |
1358 |
struct afs_vnode *dvnode = AFS_FS_I(dir), *vnode = NULL; |
260a98031 [AFS]: Add "direc... |
1359 |
int ret; |
3b6492df4 afs: Increase to ... |
1360 |
_enter("{%llx:%llu},{%pd}", |
a455589f1 assorted conversi... |
1361 |
dvnode->fid.vid, dvnode->fid.vnode, dentry); |
260a98031 [AFS]: Add "direc... |
1362 |
|
e49c7b2f6 afs: Build an abs... |
1363 1364 1365 |
op = afs_alloc_operation(NULL, dvnode->volume); if (IS_ERR(op)) return PTR_ERR(op); |
a58823ac4 afs: Fix applicat... |
1366 |
|
e49c7b2f6 afs: Build an abs... |
1367 1368 |
afs_op_set_vnode(op, 0, dvnode); op->file[0].dv_delta = 1; |
da8d07551 afs: Concoct ctimes |
1369 |
op->file[0].update_ctime = true; |
e49c7b2f6 afs: Build an abs... |
1370 1371 1372 |
op->dentry = dentry; op->ops = &afs_rmdir_operation; |
260a98031 [AFS]: Add "direc... |
1373 |
|
f58db83fd afs: Get the targ... |
1374 1375 1376 |
/* Try to make sure we have a callback promise on the victim. */ if (d_really_is_positive(dentry)) { vnode = AFS_FS_I(d_inode(dentry)); |
e49c7b2f6 afs: Build an abs... |
1377 |
ret = afs_validate(vnode, op->key); |
f58db83fd afs: Get the targ... |
1378 |
if (ret < 0) |
e49c7b2f6 afs: Build an abs... |
1379 |
goto error; |
f58db83fd afs: Get the targ... |
1380 |
} |
79ddbfa50 afs: Implement si... |
1381 1382 1383 |
if (vnode) { ret = down_write_killable(&vnode->rmdir_lock); if (ret < 0) |
e49c7b2f6 afs: Build an abs... |
1384 1385 |
goto error; op->file[1].vnode = vnode; |
79ddbfa50 afs: Implement si... |
1386 |
} |
e49c7b2f6 afs: Build an abs... |
1387 |
return afs_do_sync_operation(op); |
260a98031 [AFS]: Add "direc... |
1388 |
|
260a98031 [AFS]: Add "direc... |
1389 |
error: |
e49c7b2f6 afs: Build an abs... |
1390 |
return afs_put_operation(op); |
260a98031 [AFS]: Add "direc... |
1391 1392 1393 |
} /* |
d2ddc776a afs: Overhaul vol... |
1394 1395 1396 1397 1398 1399 1400 1401 1402 |
* Remove a link to a file or symlink from a directory. * * If the file was not deleted due to excess hard links, the fileserver will * break the callback promise on the file - if it had one - before it returns * to us, and if it was deleted, it won't * * However, if we didn't have a callback promise outstanding, or it was * outstanding on a different server, then it won't break it either... */ |
e49c7b2f6 afs: Build an abs... |
1403 |
static void afs_dir_remove_link(struct afs_operation *op) |
d2ddc776a afs: Overhaul vol... |
1404 |
{ |
e49c7b2f6 afs: Build an abs... |
1405 1406 1407 1408 |
struct afs_vnode *dvnode = op->file[0].vnode; struct afs_vnode *vnode = op->file[1].vnode; struct dentry *dentry = op->dentry; int ret; |
d2ddc776a afs: Overhaul vol... |
1409 |
|
e49c7b2f6 afs: Build an abs... |
1410 1411 1412 1413 1414 |
if (op->error != 0 || (op->file[1].scb.have_status && op->file[1].scb.have_error)) return; if (d_really_is_positive(dentry)) return; |
d2ddc776a afs: Overhaul vol... |
1415 |
|
e49c7b2f6 afs: Build an abs... |
1416 1417 1418 1419 1420 1421 1422 1423 1424 1425 1426 1427 |
if (test_bit(AFS_VNODE_DELETED, &vnode->flags)) { /* Already done */ } else if (test_bit(AFS_VNODE_DIR_VALID, &dvnode->flags)) { write_seqlock(&vnode->cb_lock); drop_nlink(&vnode->vfs_inode); if (vnode->vfs_inode.i_nlink == 0) { set_bit(AFS_VNODE_DELETED, &vnode->flags); __afs_break_callback(vnode, afs_cb_break_for_unlink); } write_sequnlock(&vnode->cb_lock); } else { afs_break_callback(vnode, afs_cb_break_for_unlink); |
440fbc3a8 afs: Fix unlink |
1428 |
|
e49c7b2f6 afs: Build an abs... |
1429 1430 |
if (test_bit(AFS_VNODE_DELETED, &vnode->flags)) _debug("AFS_VNODE_DELETED"); |
440fbc3a8 afs: Fix unlink |
1431 |
|
e49c7b2f6 afs: Build an abs... |
1432 1433 1434 |
ret = afs_validate(vnode, op->key); if (ret != -ESTALE) op->error = ret; |
d2ddc776a afs: Overhaul vol... |
1435 |
} |
e49c7b2f6 afs: Build an abs... |
1436 1437 1438 1439 1440 1441 |
_debug("nlink %d [val %d]", vnode->vfs_inode.i_nlink, op->error); } static void afs_unlink_success(struct afs_operation *op) { _enter("op=%08x", op->debug_id); |
da8d07551 afs: Concoct ctimes |
1442 |
op->ctime = op->file[0].scb.status.mtime_client; |
b6489a49f afs: Fix silly re... |
1443 |
afs_check_dir_conflict(op, &op->file[0]); |
e49c7b2f6 afs: Build an abs... |
1444 1445 1446 1447 1448 1449 1450 1451 1452 1453 1454 1455 1456 1457 1458 1459 1460 1461 |
afs_vnode_commit_status(op, &op->file[0]); afs_vnode_commit_status(op, &op->file[1]); afs_update_dentry_version(op, &op->file[0], op->dentry); afs_dir_remove_link(op); } static void afs_unlink_edit_dir(struct afs_operation *op) { struct afs_vnode_param *dvp = &op->file[0]; struct afs_vnode *dvnode = dvp->vnode; _enter("op=%08x", op->debug_id); down_write(&dvnode->validate_lock); if (test_bit(AFS_VNODE_DIR_VALID, &dvnode->flags) && dvnode->status.data_version == dvp->dv_before + dvp->dv_delta) afs_edit_dir_remove(dvnode, &op->dentry->d_name, afs_edit_dir_for_unlink); up_write(&dvnode->validate_lock); |
d2ddc776a afs: Overhaul vol... |
1462 |
} |
e49c7b2f6 afs: Build an abs... |
1463 1464 1465 1466 1467 1468 1469 1470 1471 1472 1473 |
static void afs_unlink_put(struct afs_operation *op) { _enter("op=%08x", op->debug_id); if (op->unlink.need_rehash && op->error < 0 && op->error != -ENOENT) d_rehash(op->dentry); } static const struct afs_operation_ops afs_unlink_operation = { .issue_afs_rpc = afs_fs_remove_file, .issue_yfs_rpc = yfs_fs_remove_file, .success = afs_unlink_success, |
728279a5a afs: Fix use of a... |
1474 |
.aborted = afs_check_for_remote_deletion, |
e49c7b2f6 afs: Build an abs... |
1475 1476 1477 |
.edit_dir = afs_unlink_edit_dir, .put = afs_unlink_put, }; |
d2ddc776a afs: Overhaul vol... |
1478 1479 |
/* * Remove a file or symlink from an AFS filesystem. |
260a98031 [AFS]: Add "direc... |
1480 1481 1482 |
*/ static int afs_unlink(struct inode *dir, struct dentry *dentry) { |
e49c7b2f6 afs: Build an abs... |
1483 |
struct afs_operation *op; |
fa59f52f5 afs: afs_unlink()... |
1484 1485 |
struct afs_vnode *dvnode = AFS_FS_I(dir); struct afs_vnode *vnode = AFS_FS_I(d_inode(dentry)); |
260a98031 [AFS]: Add "direc... |
1486 |
int ret; |
3b6492df4 afs: Increase to ... |
1487 |
_enter("{%llx:%llu},{%pd}", |
a455589f1 assorted conversi... |
1488 |
dvnode->fid.vid, dvnode->fid.vnode, dentry); |
260a98031 [AFS]: Add "direc... |
1489 |
|
45222b9e0 AFS: implement st... |
1490 |
if (dentry->d_name.len >= AFSNAMEMAX) |
d2ddc776a afs: Overhaul vol... |
1491 |
return -ENAMETOOLONG; |
260a98031 [AFS]: Add "direc... |
1492 |
|
e49c7b2f6 afs: Build an abs... |
1493 1494 1495 |
op = afs_alloc_operation(NULL, dvnode->volume); if (IS_ERR(op)) return PTR_ERR(op); |
a58823ac4 afs: Fix applicat... |
1496 |
|
e49c7b2f6 afs: Build an abs... |
1497 1498 |
afs_op_set_vnode(op, 0, dvnode); op->file[0].dv_delta = 1; |
da8d07551 afs: Concoct ctimes |
1499 |
op->file[0].update_ctime = true; |
260a98031 [AFS]: Add "direc... |
1500 |
|
d2ddc776a afs: Overhaul vol... |
1501 |
/* Try to make sure we have a callback promise on the victim. */ |
e49c7b2f6 afs: Build an abs... |
1502 1503 1504 1505 1506 |
ret = afs_validate(vnode, op->key); if (ret < 0) { op->error = ret; goto error; } |
260a98031 [AFS]: Add "direc... |
1507 |
|
79ddbfa50 afs: Implement si... |
1508 |
spin_lock(&dentry->d_lock); |
fa59f52f5 afs: afs_unlink()... |
1509 |
if (d_count(dentry) > 1) { |
79ddbfa50 afs: Implement si... |
1510 1511 1512 |
spin_unlock(&dentry->d_lock); /* Start asynchronous writeout of the inode */ write_inode_now(d_inode(dentry), 0); |
e49c7b2f6 afs: Build an abs... |
1513 1514 |
op->error = afs_sillyrename(dvnode, vnode, dentry, op->key); goto error; |
79ddbfa50 afs: Implement si... |
1515 1516 1517 1518 |
} if (!d_unhashed(dentry)) { /* Prevent a race with RCU lookup. */ __d_drop(dentry); |
e49c7b2f6 afs: Build an abs... |
1519 |
op->unlink.need_rehash = true; |
79ddbfa50 afs: Implement si... |
1520 1521 |
} spin_unlock(&dentry->d_lock); |
e49c7b2f6 afs: Build an abs... |
1522 |
op->file[1].vnode = vnode; |
da8d07551 afs: Concoct ctimes |
1523 |
op->file[1].update_ctime = true; |
b6489a49f afs: Fix silly re... |
1524 |
op->file[1].op_unlinked = true; |
e49c7b2f6 afs: Build an abs... |
1525 1526 |
op->dentry = dentry; op->ops = &afs_unlink_operation; |
b6489a49f afs: Fix silly re... |
1527 1528 1529 1530 1531 1532 1533 1534 1535 1536 1537 1538 1539 1540 1541 |
afs_begin_vnode_operation(op); afs_wait_for_operation(op); /* If there was a conflict with a third party, check the status of the * unlinked vnode. */ if (op->error == 0 && (op->flags & AFS_OPERATION_DIR_CONFLICT)) { op->file[1].update_ctime = false; op->fetch_status.which = 1; op->ops = &afs_fetch_status_operation; afs_begin_vnode_operation(op); afs_wait_for_operation(op); } return afs_put_operation(op); |
79ddbfa50 afs: Implement si... |
1542 |
|
260a98031 [AFS]: Add "direc... |
1543 |
error: |
e49c7b2f6 afs: Build an abs... |
1544 |
return afs_put_operation(op); |
260a98031 [AFS]: Add "direc... |
1545 |
} |
e49c7b2f6 afs: Build an abs... |
1546 1547 1548 1549 |
static const struct afs_operation_ops afs_create_operation = { .issue_afs_rpc = afs_fs_create_file, .issue_yfs_rpc = yfs_fs_create_file, .success = afs_create_success, |
728279a5a afs: Fix use of a... |
1550 |
.aborted = afs_check_for_remote_deletion, |
e49c7b2f6 afs: Build an abs... |
1551 1552 1553 |
.edit_dir = afs_create_edit_dir, .put = afs_create_put, }; |
260a98031 [AFS]: Add "direc... |
1554 1555 1556 |
/* * create a regular file on an AFS filesystem */ |
4acdaf27e switch ->create()... |
1557 |
static int afs_create(struct inode *dir, struct dentry *dentry, umode_t mode, |
ebfc3b49a don't pass nameid... |
1558 |
bool excl) |
260a98031 [AFS]: Add "direc... |
1559 |
{ |
e49c7b2f6 afs: Build an abs... |
1560 |
struct afs_operation *op; |
43dd388b2 afs: remove redun... |
1561 |
struct afs_vnode *dvnode = AFS_FS_I(dir); |
e49c7b2f6 afs: Build an abs... |
1562 |
int ret = -ENAMETOOLONG; |
260a98031 [AFS]: Add "direc... |
1563 |
|
e49c7b2f6 afs: Build an abs... |
1564 |
_enter("{%llx:%llu},{%pd},%ho", |
a455589f1 assorted conversi... |
1565 |
dvnode->fid.vid, dvnode->fid.vnode, dentry, mode); |
260a98031 [AFS]: Add "direc... |
1566 |
|
d2ddc776a afs: Overhaul vol... |
1567 1568 |
if (dentry->d_name.len >= AFSNAMEMAX) goto error; |
e49c7b2f6 afs: Build an abs... |
1569 1570 1571 |
op = afs_alloc_operation(NULL, dvnode->volume); if (IS_ERR(op)) { ret = PTR_ERR(op); |
260a98031 [AFS]: Add "direc... |
1572 1573 |
goto error; } |
e49c7b2f6 afs: Build an abs... |
1574 1575 |
afs_op_set_vnode(op, 0, dvnode); op->file[0].dv_delta = 1; |
da8d07551 afs: Concoct ctimes |
1576 |
op->file[0].update_ctime = true; |
63a4681ff afs: Locally edit... |
1577 |
|
e49c7b2f6 afs: Build an abs... |
1578 1579 1580 1581 1582 |
op->dentry = dentry; op->create.mode = S_IFREG | mode; op->create.reason = afs_edit_dir_for_create; op->ops = &afs_create_operation; return afs_do_sync_operation(op); |
260a98031 [AFS]: Add "direc... |
1583 |
|
260a98031 [AFS]: Add "direc... |
1584 1585 1586 1587 1588 |
error: d_drop(dentry); _leave(" = %d", ret); return ret; } |
e49c7b2f6 afs: Build an abs... |
1589 1590 1591 1592 1593 1594 |
static void afs_link_success(struct afs_operation *op) { struct afs_vnode_param *dvp = &op->file[0]; struct afs_vnode_param *vp = &op->file[1]; _enter("op=%08x", op->debug_id); |
da8d07551 afs: Concoct ctimes |
1595 |
op->ctime = dvp->scb.status.mtime_client; |
e49c7b2f6 afs: Build an abs... |
1596 1597 1598 1599 1600 1601 1602 1603 1604 1605 1606 1607 1608 1609 1610 1611 1612 1613 1614 1615 |
afs_vnode_commit_status(op, dvp); afs_vnode_commit_status(op, vp); afs_update_dentry_version(op, dvp, op->dentry); if (op->dentry_2->d_parent == op->dentry->d_parent) afs_update_dentry_version(op, dvp, op->dentry_2); ihold(&vp->vnode->vfs_inode); d_instantiate(op->dentry, &vp->vnode->vfs_inode); } static void afs_link_put(struct afs_operation *op) { _enter("op=%08x", op->debug_id); if (op->error) d_drop(op->dentry); } static const struct afs_operation_ops afs_link_operation = { .issue_afs_rpc = afs_fs_link, .issue_yfs_rpc = yfs_fs_link, .success = afs_link_success, |
728279a5a afs: Fix use of a... |
1616 |
.aborted = afs_check_for_remote_deletion, |
e49c7b2f6 afs: Build an abs... |
1617 1618 1619 |
.edit_dir = afs_create_edit_dir, .put = afs_link_put, }; |
260a98031 [AFS]: Add "direc... |
1620 1621 1622 1623 1624 1625 |
/* * create a hard link between files in an AFS filesystem */ static int afs_link(struct dentry *from, struct inode *dir, struct dentry *dentry) { |
e49c7b2f6 afs: Build an abs... |
1626 |
struct afs_operation *op; |
a58823ac4 afs: Fix applicat... |
1627 1628 |
struct afs_vnode *dvnode = AFS_FS_I(dir); struct afs_vnode *vnode = AFS_FS_I(d_inode(from)); |
e49c7b2f6 afs: Build an abs... |
1629 |
int ret = -ENAMETOOLONG; |
260a98031 [AFS]: Add "direc... |
1630 |
|
3b6492df4 afs: Increase to ... |
1631 |
_enter("{%llx:%llu},{%llx:%llu},{%pd}", |
260a98031 [AFS]: Add "direc... |
1632 1633 |
vnode->fid.vid, vnode->fid.vnode, dvnode->fid.vid, dvnode->fid.vnode, |
a455589f1 assorted conversi... |
1634 |
dentry); |
260a98031 [AFS]: Add "direc... |
1635 |
|
d2ddc776a afs: Overhaul vol... |
1636 1637 |
if (dentry->d_name.len >= AFSNAMEMAX) goto error; |
e49c7b2f6 afs: Build an abs... |
1638 1639 1640 |
op = afs_alloc_operation(NULL, dvnode->volume); if (IS_ERR(op)) { ret = PTR_ERR(op); |
a58823ac4 afs: Fix applicat... |
1641 |
goto error; |
260a98031 [AFS]: Add "direc... |
1642 |
} |
e49c7b2f6 afs: Build an abs... |
1643 1644 1645 |
afs_op_set_vnode(op, 0, dvnode); afs_op_set_vnode(op, 1, vnode); op->file[0].dv_delta = 1; |
da8d07551 afs: Concoct ctimes |
1646 1647 |
op->file[0].update_ctime = true; op->file[1].update_ctime = true; |
260a98031 [AFS]: Add "direc... |
1648 |
|
e49c7b2f6 afs: Build an abs... |
1649 1650 1651 1652 1653 |
op->dentry = dentry; op->dentry_2 = from; op->ops = &afs_link_operation; op->create.reason = afs_edit_dir_for_link; return afs_do_sync_operation(op); |
63a4681ff afs: Locally edit... |
1654 |
|
260a98031 [AFS]: Add "direc... |
1655 1656 1657 1658 1659 |
error: d_drop(dentry); _leave(" = %d", ret); return ret; } |
e49c7b2f6 afs: Build an abs... |
1660 1661 1662 1663 |
static const struct afs_operation_ops afs_symlink_operation = { .issue_afs_rpc = afs_fs_symlink, .issue_yfs_rpc = yfs_fs_symlink, .success = afs_create_success, |
728279a5a afs: Fix use of a... |
1664 |
.aborted = afs_check_for_remote_deletion, |
e49c7b2f6 afs: Build an abs... |
1665 1666 1667 |
.edit_dir = afs_create_edit_dir, .put = afs_create_put, }; |
260a98031 [AFS]: Add "direc... |
1668 1669 1670 1671 1672 1673 |
/* * create a symlink in an AFS filesystem */ static int afs_symlink(struct inode *dir, struct dentry *dentry, const char *content) { |
e49c7b2f6 afs: Build an abs... |
1674 |
struct afs_operation *op; |
d2ddc776a afs: Overhaul vol... |
1675 |
struct afs_vnode *dvnode = AFS_FS_I(dir); |
260a98031 [AFS]: Add "direc... |
1676 |
int ret; |
3b6492df4 afs: Increase to ... |
1677 |
_enter("{%llx:%llu},{%pd},%s", |
a455589f1 assorted conversi... |
1678 |
dvnode->fid.vid, dvnode->fid.vnode, dentry, |
260a98031 [AFS]: Add "direc... |
1679 |
content); |
d2ddc776a afs: Overhaul vol... |
1680 1681 1682 |
ret = -ENAMETOOLONG; if (dentry->d_name.len >= AFSNAMEMAX) goto error; |
260a98031 [AFS]: Add "direc... |
1683 |
ret = -EINVAL; |
45222b9e0 AFS: implement st... |
1684 |
if (strlen(content) >= AFSPATHMAX) |
260a98031 [AFS]: Add "direc... |
1685 |
goto error; |
e49c7b2f6 afs: Build an abs... |
1686 1687 1688 |
op = afs_alloc_operation(NULL, dvnode->volume); if (IS_ERR(op)) { ret = PTR_ERR(op); |
a58823ac4 afs: Fix applicat... |
1689 |
goto error; |
260a98031 [AFS]: Add "direc... |
1690 |
} |
e49c7b2f6 afs: Build an abs... |
1691 1692 |
afs_op_set_vnode(op, 0, dvnode); op->file[0].dv_delta = 1; |
260a98031 [AFS]: Add "direc... |
1693 |
|
e49c7b2f6 afs: Build an abs... |
1694 1695 1696 1697 1698 |
op->dentry = dentry; op->ops = &afs_symlink_operation; op->create.reason = afs_edit_dir_for_symlink; op->create.symlink = content; return afs_do_sync_operation(op); |
260a98031 [AFS]: Add "direc... |
1699 |
|
260a98031 [AFS]: Add "direc... |
1700 1701 1702 1703 1704 |
error: d_drop(dentry); _leave(" = %d", ret); return ret; } |
e49c7b2f6 afs: Build an abs... |
1705 1706 1707 |
static void afs_rename_success(struct afs_operation *op) { _enter("op=%08x", op->debug_id); |
da8d07551 afs: Concoct ctimes |
1708 |
op->ctime = op->file[0].scb.status.mtime_client; |
b6489a49f afs: Fix silly re... |
1709 |
afs_check_dir_conflict(op, &op->file[1]); |
e49c7b2f6 afs: Build an abs... |
1710 |
afs_vnode_commit_status(op, &op->file[0]); |
da8d07551 afs: Concoct ctimes |
1711 1712 |
if (op->file[1].vnode != op->file[0].vnode) { op->ctime = op->file[1].scb.status.mtime_client; |
e49c7b2f6 afs: Build an abs... |
1713 |
afs_vnode_commit_status(op, &op->file[1]); |
da8d07551 afs: Concoct ctimes |
1714 |
} |
e49c7b2f6 afs: Build an abs... |
1715 1716 1717 1718 1719 1720 1721 1722 1723 1724 1725 1726 1727 1728 1729 1730 1731 1732 1733 1734 1735 1736 1737 1738 1739 1740 1741 1742 1743 1744 1745 1746 1747 1748 1749 1750 1751 1752 1753 1754 1755 1756 1757 1758 1759 1760 1761 1762 1763 1764 1765 1766 1767 1768 1769 1770 1771 1772 1773 1774 1775 1776 1777 1778 1779 1780 1781 1782 1783 1784 1785 1786 1787 1788 1789 1790 1791 1792 1793 1794 |
} static void afs_rename_edit_dir(struct afs_operation *op) { struct afs_vnode_param *orig_dvp = &op->file[0]; struct afs_vnode_param *new_dvp = &op->file[1]; struct afs_vnode *orig_dvnode = orig_dvp->vnode; struct afs_vnode *new_dvnode = new_dvp->vnode; struct afs_vnode *vnode = AFS_FS_I(d_inode(op->dentry)); struct dentry *old_dentry = op->dentry; struct dentry *new_dentry = op->dentry_2; struct inode *new_inode; _enter("op=%08x", op->debug_id); if (op->rename.rehash) { d_rehash(op->rename.rehash); op->rename.rehash = NULL; } down_write(&orig_dvnode->validate_lock); if (test_bit(AFS_VNODE_DIR_VALID, &orig_dvnode->flags) && orig_dvnode->status.data_version == orig_dvp->dv_before + orig_dvp->dv_delta) afs_edit_dir_remove(orig_dvnode, &old_dentry->d_name, afs_edit_dir_for_rename_0); if (new_dvnode != orig_dvnode) { up_write(&orig_dvnode->validate_lock); down_write(&new_dvnode->validate_lock); } if (test_bit(AFS_VNODE_DIR_VALID, &new_dvnode->flags) && new_dvnode->status.data_version == new_dvp->dv_before + new_dvp->dv_delta) { if (!op->rename.new_negative) afs_edit_dir_remove(new_dvnode, &new_dentry->d_name, afs_edit_dir_for_rename_1); afs_edit_dir_add(new_dvnode, &new_dentry->d_name, &vnode->fid, afs_edit_dir_for_rename_2); } new_inode = d_inode(new_dentry); if (new_inode) { spin_lock(&new_inode->i_lock); if (new_inode->i_nlink > 0) drop_nlink(new_inode); spin_unlock(&new_inode->i_lock); } /* Now we can update d_fsdata on the dentries to reflect their * new parent's data_version. * * Note that if we ever implement RENAME_EXCHANGE, we'll have * to update both dentries with opposing dir versions. */ afs_update_dentry_version(op, new_dvp, op->dentry); afs_update_dentry_version(op, new_dvp, op->dentry_2); d_move(old_dentry, new_dentry); up_write(&new_dvnode->validate_lock); } static void afs_rename_put(struct afs_operation *op) { _enter("op=%08x", op->debug_id); if (op->rename.rehash) d_rehash(op->rename.rehash); dput(op->rename.tmp); if (op->error) d_rehash(op->dentry); } static const struct afs_operation_ops afs_rename_operation = { .issue_afs_rpc = afs_fs_rename, .issue_yfs_rpc = yfs_fs_rename, .success = afs_rename_success, .edit_dir = afs_rename_edit_dir, .put = afs_rename_put, }; |
260a98031 [AFS]: Add "direc... |
1795 1796 1797 1798 |
/* * rename a file in an AFS filesystem and/or move it between directories */ static int afs_rename(struct inode *old_dir, struct dentry *old_dentry, |
1cd66c93b fs: make remainin... |
1799 1800 |
struct inode *new_dir, struct dentry *new_dentry, unsigned int flags) |
260a98031 [AFS]: Add "direc... |
1801 |
{ |
e49c7b2f6 afs: Build an abs... |
1802 |
struct afs_operation *op; |
260a98031 [AFS]: Add "direc... |
1803 |
struct afs_vnode *orig_dvnode, *new_dvnode, *vnode; |
260a98031 [AFS]: Add "direc... |
1804 |
int ret; |
1cd66c93b fs: make remainin... |
1805 1806 |
if (flags) return -EINVAL; |
79ddbfa50 afs: Implement si... |
1807 1808 1809 |
/* Don't allow silly-rename files be moved around. */ if (old_dentry->d_flags & DCACHE_NFSFS_RENAMED) return -EINVAL; |
2b0143b5c VFS: normal files... |
1810 |
vnode = AFS_FS_I(d_inode(old_dentry)); |
260a98031 [AFS]: Add "direc... |
1811 1812 |
orig_dvnode = AFS_FS_I(old_dir); new_dvnode = AFS_FS_I(new_dir); |
3b6492df4 afs: Increase to ... |
1813 |
_enter("{%llx:%llu},{%llx:%llu},{%llx:%llu},{%pd}", |
260a98031 [AFS]: Add "direc... |
1814 1815 1816 |
orig_dvnode->fid.vid, orig_dvnode->fid.vnode, vnode->fid.vid, vnode->fid.vnode, new_dvnode->fid.vid, new_dvnode->fid.vnode, |
a455589f1 assorted conversi... |
1817 |
new_dentry); |
260a98031 [AFS]: Add "direc... |
1818 |
|
e49c7b2f6 afs: Build an abs... |
1819 1820 1821 |
op = afs_alloc_operation(NULL, orig_dvnode->volume); if (IS_ERR(op)) return PTR_ERR(op); |
a58823ac4 afs: Fix applicat... |
1822 |
|
e49c7b2f6 afs: Build an abs... |
1823 1824 1825 1826 |
afs_op_set_vnode(op, 0, orig_dvnode); afs_op_set_vnode(op, 1, new_dvnode); /* May be same as orig_dvnode */ op->file[0].dv_delta = 1; op->file[1].dv_delta = 1; |
da8d07551 afs: Concoct ctimes |
1827 1828 |
op->file[0].update_ctime = true; op->file[1].update_ctime = true; |
e49c7b2f6 afs: Build an abs... |
1829 1830 1831 1832 1833 |
op->dentry = old_dentry; op->dentry_2 = new_dentry; op->rename.new_negative = d_is_negative(new_dentry); op->ops = &afs_rename_operation; |
260a98031 [AFS]: Add "direc... |
1834 |
|
79ddbfa50 afs: Implement si... |
1835 1836 1837 1838 1839 1840 1841 1842 1843 1844 1845 |
/* 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. */ if (d_is_positive(new_dentry) && !d_is_dir(new_dentry)) { /* 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); |
e49c7b2f6 afs: Build an abs... |
1846 |
op->rename.rehash = new_dentry; |
79ddbfa50 afs: Implement si... |
1847 1848 1849 1850 1851 |
} if (d_count(new_dentry) > 2) { /* copy the target dentry's name */ ret = -ENOMEM; |
e49c7b2f6 afs: Build an abs... |
1852 1853 1854 1855 |
op->rename.tmp = d_alloc(new_dentry->d_parent, &new_dentry->d_name); if (!op->rename.tmp) goto error; |
79ddbfa50 afs: Implement si... |
1856 1857 1858 |
ret = afs_sillyrename(new_dvnode, AFS_FS_I(d_inode(new_dentry)), |
e49c7b2f6 afs: Build an abs... |
1859 |
new_dentry, op->key); |
79ddbfa50 afs: Implement si... |
1860 |
if (ret) |
e49c7b2f6 afs: Build an abs... |
1861 |
goto error; |
79ddbfa50 afs: Implement si... |
1862 |
|
e49c7b2f6 afs: Build an abs... |
1863 1864 1865 |
op->dentry_2 = op->rename.tmp; op->rename.rehash = NULL; op->rename.new_negative = true; |
79ddbfa50 afs: Implement si... |
1866 1867 |
} } |
9dd0b82ef afs: Fix missing ... |
1868 1869 1870 1871 1872 1873 1874 1875 1876 1877 |
/* This bit is potentially nasty as there's a potential race with * afs_d_revalidate{,_rcu}(). We have to change d_fsdata on the dentry * to reflect it's new parent's new data_version after the op, but * d_revalidate may see old_dentry between the op having taken place * and the version being updated. * * So drop the old_dentry for now to make other threads go through * lookup instead - which we hold a lock against. */ d_drop(old_dentry); |
e49c7b2f6 afs: Build an abs... |
1878 |
return afs_do_sync_operation(op); |
63a4681ff afs: Locally edit... |
1879 |
|
260a98031 [AFS]: Add "direc... |
1880 |
error: |
e49c7b2f6 afs: Build an abs... |
1881 |
return afs_put_operation(op); |
260a98031 [AFS]: Add "direc... |
1882 |
} |
f3ddee8dc afs: Fix director... |
1883 1884 1885 1886 1887 1888 1889 1890 |
/* * Release a directory page and clean up its private state if it's not busy * - return true if the page can now be released, false if not */ static int afs_dir_releasepage(struct page *page, gfp_t gfp_flags) { struct afs_vnode *dvnode = AFS_FS_I(page->mapping->host); |
3b6492df4 afs: Increase to ... |
1891 |
_enter("{{%llx:%llu}[%lu]}", dvnode->fid.vid, dvnode->fid.vnode, page->index); |
f3ddee8dc afs: Fix director... |
1892 |
|
fa04a40b1 afs: Fix to take ... |
1893 |
detach_page_private(page); |
f3ddee8dc afs: Fix director... |
1894 1895 1896 1897 1898 1899 1900 1901 1902 1903 1904 1905 1906 1907 1908 1909 1910 1911 1912 1913 1914 1915 1916 1917 1918 1919 |
/* The directory will need reloading. */ if (test_and_clear_bit(AFS_VNODE_DIR_VALID, &dvnode->flags)) afs_stat_v(dvnode, n_relpg); return 1; } /* * invalidate part or all of a page * - release a page and clean up its private data if offset is 0 (indicating * the entire page) */ static void afs_dir_invalidatepage(struct page *page, unsigned int offset, unsigned int length) { struct afs_vnode *dvnode = AFS_FS_I(page->mapping->host); _enter("{%lu},%u,%u", page->index, offset, length); BUG_ON(!PageLocked(page)); /* The directory will need reloading. */ if (test_and_clear_bit(AFS_VNODE_DIR_VALID, &dvnode->flags)) afs_stat_v(dvnode, n_inval); /* we clean up only if the entire page is being invalidated */ |
fa04a40b1 afs: Fix to take ... |
1920 1921 |
if (offset == 0 && length == PAGE_SIZE) detach_page_private(page); |
f3ddee8dc afs: Fix director... |
1922 |
} |