diff options
Diffstat (limited to 'fs')
112 files changed, 7579 insertions, 1837 deletions
diff --git a/fs/Kconfig b/fs/Kconfig index d78e950402c1..a97263be6a91 100644 --- a/fs/Kconfig +++ b/fs/Kconfig | |||
@@ -236,10 +236,12 @@ source "fs/nfsd/Kconfig" | |||
236 | 236 | ||
237 | config LOCKD | 237 | config LOCKD |
238 | tristate | 238 | tristate |
239 | depends on FILE_LOCKING | ||
239 | 240 | ||
240 | config LOCKD_V4 | 241 | config LOCKD_V4 |
241 | bool | 242 | bool |
242 | depends on NFSD_V3 || NFS_V3 | 243 | depends on NFSD_V3 || NFS_V3 |
244 | depends on FILE_LOCKING | ||
243 | default y | 245 | default y |
244 | 246 | ||
245 | config EXPORTFS | 247 | config EXPORTFS |
diff --git a/fs/anon_inodes.c b/fs/anon_inodes.c index 1dd96d4406c0..47d4a01c5393 100644 --- a/fs/anon_inodes.c +++ b/fs/anon_inodes.c | |||
@@ -52,6 +52,19 @@ static const struct dentry_operations anon_inodefs_dentry_operations = { | |||
52 | .d_delete = anon_inodefs_delete_dentry, | 52 | .d_delete = anon_inodefs_delete_dentry, |
53 | }; | 53 | }; |
54 | 54 | ||
55 | /* | ||
56 | * nop .set_page_dirty method so that people can use .page_mkwrite on | ||
57 | * anon inodes. | ||
58 | */ | ||
59 | static int anon_set_page_dirty(struct page *page) | ||
60 | { | ||
61 | return 0; | ||
62 | }; | ||
63 | |||
64 | static const struct address_space_operations anon_aops = { | ||
65 | .set_page_dirty = anon_set_page_dirty, | ||
66 | }; | ||
67 | |||
55 | /** | 68 | /** |
56 | * anon_inode_getfd - creates a new file instance by hooking it up to an | 69 | * anon_inode_getfd - creates a new file instance by hooking it up to an |
57 | * anonymous inode, and a dentry that describe the "class" | 70 | * anonymous inode, and a dentry that describe the "class" |
@@ -151,6 +164,8 @@ static struct inode *anon_inode_mkinode(void) | |||
151 | 164 | ||
152 | inode->i_fop = &anon_inode_fops; | 165 | inode->i_fop = &anon_inode_fops; |
153 | 166 | ||
167 | inode->i_mapping->a_ops = &anon_aops; | ||
168 | |||
154 | /* | 169 | /* |
155 | * Mark the inode dirty from the very beginning, | 170 | * Mark the inode dirty from the very beginning, |
156 | * that way it will never be moved to the dirty | 171 | * that way it will never be moved to the dirty |
diff --git a/fs/binfmt_elf.c b/fs/binfmt_elf.c index 40381df34869..9fa212b014a5 100644 --- a/fs/binfmt_elf.c +++ b/fs/binfmt_elf.c | |||
@@ -1340,8 +1340,10 @@ static void fill_prstatus(struct elf_prstatus *prstatus, | |||
1340 | prstatus->pr_info.si_signo = prstatus->pr_cursig = signr; | 1340 | prstatus->pr_info.si_signo = prstatus->pr_cursig = signr; |
1341 | prstatus->pr_sigpend = p->pending.signal.sig[0]; | 1341 | prstatus->pr_sigpend = p->pending.signal.sig[0]; |
1342 | prstatus->pr_sighold = p->blocked.sig[0]; | 1342 | prstatus->pr_sighold = p->blocked.sig[0]; |
1343 | rcu_read_lock(); | ||
1344 | prstatus->pr_ppid = task_pid_vnr(rcu_dereference(p->real_parent)); | ||
1345 | rcu_read_unlock(); | ||
1343 | prstatus->pr_pid = task_pid_vnr(p); | 1346 | prstatus->pr_pid = task_pid_vnr(p); |
1344 | prstatus->pr_ppid = task_pid_vnr(p->real_parent); | ||
1345 | prstatus->pr_pgrp = task_pgrp_vnr(p); | 1347 | prstatus->pr_pgrp = task_pgrp_vnr(p); |
1346 | prstatus->pr_sid = task_session_vnr(p); | 1348 | prstatus->pr_sid = task_session_vnr(p); |
1347 | if (thread_group_leader(p)) { | 1349 | if (thread_group_leader(p)) { |
@@ -1382,8 +1384,10 @@ static int fill_psinfo(struct elf_prpsinfo *psinfo, struct task_struct *p, | |||
1382 | psinfo->pr_psargs[i] = ' '; | 1384 | psinfo->pr_psargs[i] = ' '; |
1383 | psinfo->pr_psargs[len] = 0; | 1385 | psinfo->pr_psargs[len] = 0; |
1384 | 1386 | ||
1387 | rcu_read_lock(); | ||
1388 | psinfo->pr_ppid = task_pid_vnr(rcu_dereference(p->real_parent)); | ||
1389 | rcu_read_unlock(); | ||
1385 | psinfo->pr_pid = task_pid_vnr(p); | 1390 | psinfo->pr_pid = task_pid_vnr(p); |
1386 | psinfo->pr_ppid = task_pid_vnr(p->real_parent); | ||
1387 | psinfo->pr_pgrp = task_pgrp_vnr(p); | 1391 | psinfo->pr_pgrp = task_pgrp_vnr(p); |
1388 | psinfo->pr_sid = task_session_vnr(p); | 1392 | psinfo->pr_sid = task_session_vnr(p); |
1389 | 1393 | ||
diff --git a/fs/binfmt_elf_fdpic.c b/fs/binfmt_elf_fdpic.c index fdb66faa24f1..20fbeced472b 100644 --- a/fs/binfmt_elf_fdpic.c +++ b/fs/binfmt_elf_fdpic.c | |||
@@ -1387,8 +1387,10 @@ static void fill_prstatus(struct elf_prstatus *prstatus, | |||
1387 | prstatus->pr_info.si_signo = prstatus->pr_cursig = signr; | 1387 | prstatus->pr_info.si_signo = prstatus->pr_cursig = signr; |
1388 | prstatus->pr_sigpend = p->pending.signal.sig[0]; | 1388 | prstatus->pr_sigpend = p->pending.signal.sig[0]; |
1389 | prstatus->pr_sighold = p->blocked.sig[0]; | 1389 | prstatus->pr_sighold = p->blocked.sig[0]; |
1390 | rcu_read_lock(); | ||
1391 | prstatus->pr_ppid = task_pid_vnr(rcu_dereference(p->real_parent)); | ||
1392 | rcu_read_unlock(); | ||
1390 | prstatus->pr_pid = task_pid_vnr(p); | 1393 | prstatus->pr_pid = task_pid_vnr(p); |
1391 | prstatus->pr_ppid = task_pid_vnr(p->real_parent); | ||
1392 | prstatus->pr_pgrp = task_pgrp_vnr(p); | 1394 | prstatus->pr_pgrp = task_pgrp_vnr(p); |
1393 | prstatus->pr_sid = task_session_vnr(p); | 1395 | prstatus->pr_sid = task_session_vnr(p); |
1394 | if (thread_group_leader(p)) { | 1396 | if (thread_group_leader(p)) { |
@@ -1432,8 +1434,10 @@ static int fill_psinfo(struct elf_prpsinfo *psinfo, struct task_struct *p, | |||
1432 | psinfo->pr_psargs[i] = ' '; | 1434 | psinfo->pr_psargs[i] = ' '; |
1433 | psinfo->pr_psargs[len] = 0; | 1435 | psinfo->pr_psargs[len] = 0; |
1434 | 1436 | ||
1437 | rcu_read_lock(); | ||
1438 | psinfo->pr_ppid = task_pid_vnr(rcu_dereference(p->real_parent)); | ||
1439 | rcu_read_unlock(); | ||
1435 | psinfo->pr_pid = task_pid_vnr(p); | 1440 | psinfo->pr_pid = task_pid_vnr(p); |
1436 | psinfo->pr_ppid = task_pid_vnr(p->real_parent); | ||
1437 | psinfo->pr_pgrp = task_pgrp_vnr(p); | 1441 | psinfo->pr_pgrp = task_pgrp_vnr(p); |
1438 | psinfo->pr_sid = task_session_vnr(p); | 1442 | psinfo->pr_sid = task_session_vnr(p); |
1439 | 1443 | ||
diff --git a/fs/compat_ioctl.c b/fs/compat_ioctl.c index c5ded5ff72b5..c135202c38b3 100644 --- a/fs/compat_ioctl.c +++ b/fs/compat_ioctl.c | |||
@@ -94,7 +94,6 @@ | |||
94 | #include <linux/atm_tcp.h> | 94 | #include <linux/atm_tcp.h> |
95 | #include <linux/sonet.h> | 95 | #include <linux/sonet.h> |
96 | #include <linux/atm_suni.h> | 96 | #include <linux/atm_suni.h> |
97 | #include <linux/mtd/mtd.h> | ||
98 | 97 | ||
99 | #include <linux/usb.h> | 98 | #include <linux/usb.h> |
100 | #include <linux/usbdevice_fs.h> | 99 | #include <linux/usbdevice_fs.h> |
@@ -1405,46 +1404,6 @@ static int ioc_settimeout(unsigned int fd, unsigned int cmd, unsigned long arg) | |||
1405 | #define HIDPGETCONNLIST _IOR('H', 210, int) | 1404 | #define HIDPGETCONNLIST _IOR('H', 210, int) |
1406 | #define HIDPGETCONNINFO _IOR('H', 211, int) | 1405 | #define HIDPGETCONNINFO _IOR('H', 211, int) |
1407 | 1406 | ||
1408 | struct mtd_oob_buf32 { | ||
1409 | u_int32_t start; | ||
1410 | u_int32_t length; | ||
1411 | compat_caddr_t ptr; /* unsigned char* */ | ||
1412 | }; | ||
1413 | |||
1414 | #define MEMWRITEOOB32 _IOWR('M',3,struct mtd_oob_buf32) | ||
1415 | #define MEMREADOOB32 _IOWR('M',4,struct mtd_oob_buf32) | ||
1416 | |||
1417 | static int mtd_rw_oob(unsigned int fd, unsigned int cmd, unsigned long arg) | ||
1418 | { | ||
1419 | struct mtd_oob_buf __user *buf = compat_alloc_user_space(sizeof(*buf)); | ||
1420 | struct mtd_oob_buf32 __user *buf32 = compat_ptr(arg); | ||
1421 | u32 data; | ||
1422 | char __user *datap; | ||
1423 | unsigned int real_cmd; | ||
1424 | int err; | ||
1425 | |||
1426 | real_cmd = (cmd == MEMREADOOB32) ? | ||
1427 | MEMREADOOB : MEMWRITEOOB; | ||
1428 | |||
1429 | if (copy_in_user(&buf->start, &buf32->start, | ||
1430 | 2 * sizeof(u32)) || | ||
1431 | get_user(data, &buf32->ptr)) | ||
1432 | return -EFAULT; | ||
1433 | datap = compat_ptr(data); | ||
1434 | if (put_user(datap, &buf->ptr)) | ||
1435 | return -EFAULT; | ||
1436 | |||
1437 | err = sys_ioctl(fd, real_cmd, (unsigned long) buf); | ||
1438 | |||
1439 | if (!err) { | ||
1440 | if (copy_in_user(&buf32->start, &buf->start, | ||
1441 | 2 * sizeof(u32))) | ||
1442 | err = -EFAULT; | ||
1443 | } | ||
1444 | |||
1445 | return err; | ||
1446 | } | ||
1447 | |||
1448 | #ifdef CONFIG_BLOCK | 1407 | #ifdef CONFIG_BLOCK |
1449 | struct raw32_config_request | 1408 | struct raw32_config_request |
1450 | { | 1409 | { |
@@ -2426,15 +2385,6 @@ COMPATIBLE_IOCTL(USBDEVFS_SUBMITURB32) | |||
2426 | COMPATIBLE_IOCTL(USBDEVFS_REAPURB32) | 2385 | COMPATIBLE_IOCTL(USBDEVFS_REAPURB32) |
2427 | COMPATIBLE_IOCTL(USBDEVFS_REAPURBNDELAY32) | 2386 | COMPATIBLE_IOCTL(USBDEVFS_REAPURBNDELAY32) |
2428 | COMPATIBLE_IOCTL(USBDEVFS_CLEAR_HALT) | 2387 | COMPATIBLE_IOCTL(USBDEVFS_CLEAR_HALT) |
2429 | /* MTD */ | ||
2430 | COMPATIBLE_IOCTL(MEMGETINFO) | ||
2431 | COMPATIBLE_IOCTL(MEMERASE) | ||
2432 | COMPATIBLE_IOCTL(MEMLOCK) | ||
2433 | COMPATIBLE_IOCTL(MEMUNLOCK) | ||
2434 | COMPATIBLE_IOCTL(MEMGETREGIONCOUNT) | ||
2435 | COMPATIBLE_IOCTL(MEMGETREGIONINFO) | ||
2436 | COMPATIBLE_IOCTL(MEMGETBADBLOCK) | ||
2437 | COMPATIBLE_IOCTL(MEMSETBADBLOCK) | ||
2438 | /* NBD */ | 2388 | /* NBD */ |
2439 | ULONG_IOCTL(NBD_SET_SOCK) | 2389 | ULONG_IOCTL(NBD_SET_SOCK) |
2440 | ULONG_IOCTL(NBD_SET_BLKSIZE) | 2390 | ULONG_IOCTL(NBD_SET_BLKSIZE) |
@@ -2544,8 +2494,6 @@ COMPATIBLE_IOCTL(JSIOCGBUTTONS) | |||
2544 | COMPATIBLE_IOCTL(JSIOCGNAME(0)) | 2494 | COMPATIBLE_IOCTL(JSIOCGNAME(0)) |
2545 | 2495 | ||
2546 | /* now things that need handlers */ | 2496 | /* now things that need handlers */ |
2547 | HANDLE_IOCTL(MEMREADOOB32, mtd_rw_oob) | ||
2548 | HANDLE_IOCTL(MEMWRITEOOB32, mtd_rw_oob) | ||
2549 | #ifdef CONFIG_NET | 2497 | #ifdef CONFIG_NET |
2550 | HANDLE_IOCTL(SIOCGIFNAME, dev_ifname32) | 2498 | HANDLE_IOCTL(SIOCGIFNAME, dev_ifname32) |
2551 | HANDLE_IOCTL(SIOCGIFCONF, dev_ifconf) | 2499 | HANDLE_IOCTL(SIOCGIFCONF, dev_ifconf) |
diff --git a/fs/eventpoll.c b/fs/eventpoll.c index 5458e80fc558..085c5c063420 100644 --- a/fs/eventpoll.c +++ b/fs/eventpoll.c | |||
@@ -98,7 +98,7 @@ struct epoll_filefd { | |||
98 | struct nested_call_node { | 98 | struct nested_call_node { |
99 | struct list_head llink; | 99 | struct list_head llink; |
100 | void *cookie; | 100 | void *cookie; |
101 | int cpu; | 101 | void *ctx; |
102 | }; | 102 | }; |
103 | 103 | ||
104 | /* | 104 | /* |
@@ -317,17 +317,17 @@ static void ep_nested_calls_init(struct nested_calls *ncalls) | |||
317 | * @nproc: Nested call core function pointer. | 317 | * @nproc: Nested call core function pointer. |
318 | * @priv: Opaque data to be passed to the @nproc callback. | 318 | * @priv: Opaque data to be passed to the @nproc callback. |
319 | * @cookie: Cookie to be used to identify this nested call. | 319 | * @cookie: Cookie to be used to identify this nested call. |
320 | * @ctx: This instance context. | ||
320 | * | 321 | * |
321 | * Returns: Returns the code returned by the @nproc callback, or -1 if | 322 | * Returns: Returns the code returned by the @nproc callback, or -1 if |
322 | * the maximum recursion limit has been exceeded. | 323 | * the maximum recursion limit has been exceeded. |
323 | */ | 324 | */ |
324 | static int ep_call_nested(struct nested_calls *ncalls, int max_nests, | 325 | static int ep_call_nested(struct nested_calls *ncalls, int max_nests, |
325 | int (*nproc)(void *, void *, int), void *priv, | 326 | int (*nproc)(void *, void *, int), void *priv, |
326 | void *cookie) | 327 | void *cookie, void *ctx) |
327 | { | 328 | { |
328 | int error, call_nests = 0; | 329 | int error, call_nests = 0; |
329 | unsigned long flags; | 330 | unsigned long flags; |
330 | int this_cpu = get_cpu(); | ||
331 | struct list_head *lsthead = &ncalls->tasks_call_list; | 331 | struct list_head *lsthead = &ncalls->tasks_call_list; |
332 | struct nested_call_node *tncur; | 332 | struct nested_call_node *tncur; |
333 | struct nested_call_node tnode; | 333 | struct nested_call_node tnode; |
@@ -340,7 +340,7 @@ static int ep_call_nested(struct nested_calls *ncalls, int max_nests, | |||
340 | * very much limited. | 340 | * very much limited. |
341 | */ | 341 | */ |
342 | list_for_each_entry(tncur, lsthead, llink) { | 342 | list_for_each_entry(tncur, lsthead, llink) { |
343 | if (tncur->cpu == this_cpu && | 343 | if (tncur->ctx == ctx && |
344 | (tncur->cookie == cookie || ++call_nests > max_nests)) { | 344 | (tncur->cookie == cookie || ++call_nests > max_nests)) { |
345 | /* | 345 | /* |
346 | * Ops ... loop detected or maximum nest level reached. | 346 | * Ops ... loop detected or maximum nest level reached. |
@@ -352,7 +352,7 @@ static int ep_call_nested(struct nested_calls *ncalls, int max_nests, | |||
352 | } | 352 | } |
353 | 353 | ||
354 | /* Add the current task and cookie to the list */ | 354 | /* Add the current task and cookie to the list */ |
355 | tnode.cpu = this_cpu; | 355 | tnode.ctx = ctx; |
356 | tnode.cookie = cookie; | 356 | tnode.cookie = cookie; |
357 | list_add(&tnode.llink, lsthead); | 357 | list_add(&tnode.llink, lsthead); |
358 | 358 | ||
@@ -364,10 +364,9 @@ static int ep_call_nested(struct nested_calls *ncalls, int max_nests, | |||
364 | /* Remove the current task from the list */ | 364 | /* Remove the current task from the list */ |
365 | spin_lock_irqsave(&ncalls->lock, flags); | 365 | spin_lock_irqsave(&ncalls->lock, flags); |
366 | list_del(&tnode.llink); | 366 | list_del(&tnode.llink); |
367 | out_unlock: | 367 | out_unlock: |
368 | spin_unlock_irqrestore(&ncalls->lock, flags); | 368 | spin_unlock_irqrestore(&ncalls->lock, flags); |
369 | 369 | ||
370 | put_cpu(); | ||
371 | return error; | 370 | return error; |
372 | } | 371 | } |
373 | 372 | ||
@@ -408,8 +407,12 @@ static int ep_poll_wakeup_proc(void *priv, void *cookie, int call_nests) | |||
408 | */ | 407 | */ |
409 | static void ep_poll_safewake(wait_queue_head_t *wq) | 408 | static void ep_poll_safewake(wait_queue_head_t *wq) |
410 | { | 409 | { |
410 | int this_cpu = get_cpu(); | ||
411 | |||
411 | ep_call_nested(&poll_safewake_ncalls, EP_MAX_NESTS, | 412 | ep_call_nested(&poll_safewake_ncalls, EP_MAX_NESTS, |
412 | ep_poll_wakeup_proc, NULL, wq); | 413 | ep_poll_wakeup_proc, NULL, wq, (void *) (long) this_cpu); |
414 | |||
415 | put_cpu(); | ||
413 | } | 416 | } |
414 | 417 | ||
415 | /* | 418 | /* |
@@ -663,7 +666,7 @@ static unsigned int ep_eventpoll_poll(struct file *file, poll_table *wait) | |||
663 | * could re-enter here. | 666 | * could re-enter here. |
664 | */ | 667 | */ |
665 | pollflags = ep_call_nested(&poll_readywalk_ncalls, EP_MAX_NESTS, | 668 | pollflags = ep_call_nested(&poll_readywalk_ncalls, EP_MAX_NESTS, |
666 | ep_poll_readyevents_proc, ep, ep); | 669 | ep_poll_readyevents_proc, ep, ep, current); |
667 | 670 | ||
668 | return pollflags != -1 ? pollflags : 0; | 671 | return pollflags != -1 ? pollflags : 0; |
669 | } | 672 | } |
diff --git a/fs/ext2/dir.c b/fs/ext2/dir.c index 003500498c22..6cde970b0a1a 100644 --- a/fs/ext2/dir.c +++ b/fs/ext2/dir.c | |||
@@ -450,7 +450,7 @@ ino_t ext2_inode_by_name(struct inode *dir, struct qstr *child) | |||
450 | 450 | ||
451 | /* Releases the page */ | 451 | /* Releases the page */ |
452 | void ext2_set_link(struct inode *dir, struct ext2_dir_entry_2 *de, | 452 | void ext2_set_link(struct inode *dir, struct ext2_dir_entry_2 *de, |
453 | struct page *page, struct inode *inode) | 453 | struct page *page, struct inode *inode, int update_times) |
454 | { | 454 | { |
455 | loff_t pos = page_offset(page) + | 455 | loff_t pos = page_offset(page) + |
456 | (char *) de - (char *) page_address(page); | 456 | (char *) de - (char *) page_address(page); |
@@ -465,7 +465,8 @@ void ext2_set_link(struct inode *dir, struct ext2_dir_entry_2 *de, | |||
465 | ext2_set_de_type(de, inode); | 465 | ext2_set_de_type(de, inode); |
466 | err = ext2_commit_chunk(page, pos, len); | 466 | err = ext2_commit_chunk(page, pos, len); |
467 | ext2_put_page(page); | 467 | ext2_put_page(page); |
468 | dir->i_mtime = dir->i_ctime = CURRENT_TIME_SEC; | 468 | if (update_times) |
469 | dir->i_mtime = dir->i_ctime = CURRENT_TIME_SEC; | ||
469 | EXT2_I(dir)->i_flags &= ~EXT2_BTREE_FL; | 470 | EXT2_I(dir)->i_flags &= ~EXT2_BTREE_FL; |
470 | mark_inode_dirty(dir); | 471 | mark_inode_dirty(dir); |
471 | } | 472 | } |
diff --git a/fs/ext2/ext2.h b/fs/ext2/ext2.h index f2e5811936d0..d988a718aedb 100644 --- a/fs/ext2/ext2.h +++ b/fs/ext2/ext2.h | |||
@@ -111,7 +111,7 @@ extern struct ext2_dir_entry_2 * ext2_find_entry (struct inode *,struct qstr *, | |||
111 | extern int ext2_delete_entry (struct ext2_dir_entry_2 *, struct page *); | 111 | extern int ext2_delete_entry (struct ext2_dir_entry_2 *, struct page *); |
112 | extern int ext2_empty_dir (struct inode *); | 112 | extern int ext2_empty_dir (struct inode *); |
113 | extern struct ext2_dir_entry_2 * ext2_dotdot (struct inode *, struct page **); | 113 | extern struct ext2_dir_entry_2 * ext2_dotdot (struct inode *, struct page **); |
114 | extern void ext2_set_link(struct inode *, struct ext2_dir_entry_2 *, struct page *, struct inode *); | 114 | extern void ext2_set_link(struct inode *, struct ext2_dir_entry_2 *, struct page *, struct inode *, int); |
115 | 115 | ||
116 | /* ialloc.c */ | 116 | /* ialloc.c */ |
117 | extern struct inode * ext2_new_inode (struct inode *, int); | 117 | extern struct inode * ext2_new_inode (struct inode *, int); |
diff --git a/fs/ext2/namei.c b/fs/ext2/namei.c index 90ea17998a73..6524ecaebb7a 100644 --- a/fs/ext2/namei.c +++ b/fs/ext2/namei.c | |||
@@ -320,7 +320,7 @@ static int ext2_rename (struct inode * old_dir, struct dentry * old_dentry, | |||
320 | if (!new_de) | 320 | if (!new_de) |
321 | goto out_dir; | 321 | goto out_dir; |
322 | inode_inc_link_count(old_inode); | 322 | inode_inc_link_count(old_inode); |
323 | ext2_set_link(new_dir, new_de, new_page, old_inode); | 323 | ext2_set_link(new_dir, new_de, new_page, old_inode, 1); |
324 | new_inode->i_ctime = CURRENT_TIME_SEC; | 324 | new_inode->i_ctime = CURRENT_TIME_SEC; |
325 | if (dir_de) | 325 | if (dir_de) |
326 | drop_nlink(new_inode); | 326 | drop_nlink(new_inode); |
@@ -352,7 +352,8 @@ static int ext2_rename (struct inode * old_dir, struct dentry * old_dentry, | |||
352 | inode_dec_link_count(old_inode); | 352 | inode_dec_link_count(old_inode); |
353 | 353 | ||
354 | if (dir_de) { | 354 | if (dir_de) { |
355 | ext2_set_link(old_inode, dir_de, dir_page, new_dir); | 355 | if (old_dir != new_dir) |
356 | ext2_set_link(old_inode, dir_de, dir_page, new_dir, 0); | ||
356 | inode_dec_link_count(old_dir); | 357 | inode_dec_link_count(old_dir); |
357 | } | 358 | } |
358 | return 0; | 359 | return 0; |
diff --git a/fs/ext3/inode.c b/fs/ext3/inode.c index b0248c6d5d4c..05dea8132fc0 100644 --- a/fs/ext3/inode.c +++ b/fs/ext3/inode.c | |||
@@ -820,7 +820,7 @@ int ext3_get_blocks_handle(handle_t *handle, struct inode *inode, | |||
820 | while (count < maxblocks && count <= blocks_to_boundary) { | 820 | while (count < maxblocks && count <= blocks_to_boundary) { |
821 | ext3_fsblk_t blk; | 821 | ext3_fsblk_t blk; |
822 | 822 | ||
823 | if (!verify_chain(chain, partial)) { | 823 | if (!verify_chain(chain, chain + depth - 1)) { |
824 | /* | 824 | /* |
825 | * Indirect block might be removed by | 825 | * Indirect block might be removed by |
826 | * truncate while we were reading it. | 826 | * truncate while we were reading it. |
@@ -2374,7 +2374,7 @@ void ext3_truncate(struct inode *inode) | |||
2374 | struct page *page; | 2374 | struct page *page; |
2375 | 2375 | ||
2376 | if (!ext3_can_truncate(inode)) | 2376 | if (!ext3_can_truncate(inode)) |
2377 | return; | 2377 | goto out_notrans; |
2378 | 2378 | ||
2379 | if (inode->i_size == 0 && ext3_should_writeback_data(inode)) | 2379 | if (inode->i_size == 0 && ext3_should_writeback_data(inode)) |
2380 | ei->i_state |= EXT3_STATE_FLUSH_ON_CLOSE; | 2380 | ei->i_state |= EXT3_STATE_FLUSH_ON_CLOSE; |
@@ -2390,7 +2390,7 @@ void ext3_truncate(struct inode *inode) | |||
2390 | page = grab_cache_page(mapping, | 2390 | page = grab_cache_page(mapping, |
2391 | inode->i_size >> PAGE_CACHE_SHIFT); | 2391 | inode->i_size >> PAGE_CACHE_SHIFT); |
2392 | if (!page) | 2392 | if (!page) |
2393 | return; | 2393 | goto out_notrans; |
2394 | } | 2394 | } |
2395 | 2395 | ||
2396 | handle = start_transaction(inode); | 2396 | handle = start_transaction(inode); |
@@ -2401,7 +2401,7 @@ void ext3_truncate(struct inode *inode) | |||
2401 | unlock_page(page); | 2401 | unlock_page(page); |
2402 | page_cache_release(page); | 2402 | page_cache_release(page); |
2403 | } | 2403 | } |
2404 | return; /* AKPM: return what? */ | 2404 | goto out_notrans; |
2405 | } | 2405 | } |
2406 | 2406 | ||
2407 | last_block = (inode->i_size + blocksize-1) | 2407 | last_block = (inode->i_size + blocksize-1) |
@@ -2525,6 +2525,14 @@ out_stop: | |||
2525 | ext3_orphan_del(handle, inode); | 2525 | ext3_orphan_del(handle, inode); |
2526 | 2526 | ||
2527 | ext3_journal_stop(handle); | 2527 | ext3_journal_stop(handle); |
2528 | return; | ||
2529 | out_notrans: | ||
2530 | /* | ||
2531 | * Delete the inode from orphan list so that it doesn't stay there | ||
2532 | * forever and trigger assertion on umount. | ||
2533 | */ | ||
2534 | if (inode->i_nlink) | ||
2535 | ext3_orphan_del(NULL, inode); | ||
2528 | } | 2536 | } |
2529 | 2537 | ||
2530 | static ext3_fsblk_t ext3_get_inode_block(struct super_block *sb, | 2538 | static ext3_fsblk_t ext3_get_inode_block(struct super_block *sb, |
@@ -3122,12 +3130,6 @@ int ext3_setattr(struct dentry *dentry, struct iattr *attr) | |||
3122 | 3130 | ||
3123 | rc = inode_setattr(inode, attr); | 3131 | rc = inode_setattr(inode, attr); |
3124 | 3132 | ||
3125 | /* If inode_setattr's call to ext3_truncate failed to get a | ||
3126 | * transaction handle at all, we need to clean up the in-core | ||
3127 | * orphan list manually. */ | ||
3128 | if (inode->i_nlink) | ||
3129 | ext3_orphan_del(NULL, inode); | ||
3130 | |||
3131 | if (!rc && (ia_valid & ATTR_MODE)) | 3133 | if (!rc && (ia_valid & ATTR_MODE)) |
3132 | rc = ext3_acl_chmod(inode); | 3134 | rc = ext3_acl_chmod(inode); |
3133 | 3135 | ||
diff --git a/fs/ext3/resize.c b/fs/ext3/resize.c index 8a0b26340b54..8359e7b3dc89 100644 --- a/fs/ext3/resize.c +++ b/fs/ext3/resize.c | |||
@@ -990,7 +990,7 @@ int ext3_group_extend(struct super_block *sb, struct ext3_super_block *es, | |||
990 | sb->s_id, n_blocks_count); | 990 | sb->s_id, n_blocks_count); |
991 | if (sizeof(sector_t) < 8) | 991 | if (sizeof(sector_t) < 8) |
992 | ext3_warning(sb, __func__, | 992 | ext3_warning(sb, __func__, |
993 | "CONFIG_LBD not enabled\n"); | 993 | "CONFIG_LBDAF not enabled\n"); |
994 | return -EINVAL; | 994 | return -EINVAL; |
995 | } | 995 | } |
996 | 996 | ||
diff --git a/fs/ext3/super.c b/fs/ext3/super.c index 26aa64dee6aa..601e881e6105 100644 --- a/fs/ext3/super.c +++ b/fs/ext3/super.c | |||
@@ -1812,7 +1812,7 @@ static int ext3_fill_super (struct super_block *sb, void *data, int silent) | |||
1812 | printk(KERN_ERR "EXT3-fs: filesystem on %s:" | 1812 | printk(KERN_ERR "EXT3-fs: filesystem on %s:" |
1813 | " too large to mount safely\n", sb->s_id); | 1813 | " too large to mount safely\n", sb->s_id); |
1814 | if (sizeof(sector_t) < 8) | 1814 | if (sizeof(sector_t) < 8) |
1815 | printk(KERN_WARNING "EXT3-fs: CONFIG_LBD not " | 1815 | printk(KERN_WARNING "EXT3-fs: CONFIG_LBDAF not " |
1816 | "enabled\n"); | 1816 | "enabled\n"); |
1817 | goto failed_mount; | 1817 | goto failed_mount; |
1818 | } | 1818 | } |
diff --git a/fs/ext4/Makefile b/fs/ext4/Makefile index 8a34710ecf40..8867b2a1e5fe 100644 --- a/fs/ext4/Makefile +++ b/fs/ext4/Makefile | |||
@@ -6,7 +6,7 @@ obj-$(CONFIG_EXT4_FS) += ext4.o | |||
6 | 6 | ||
7 | ext4-y := balloc.o bitmap.o dir.o file.o fsync.o ialloc.o inode.o \ | 7 | ext4-y := balloc.o bitmap.o dir.o file.o fsync.o ialloc.o inode.o \ |
8 | ioctl.o namei.o super.o symlink.o hash.o resize.o extents.o \ | 8 | ioctl.o namei.o super.o symlink.o hash.o resize.o extents.o \ |
9 | ext4_jbd2.o migrate.o mballoc.o block_validity.o | 9 | ext4_jbd2.o migrate.o mballoc.o block_validity.o move_extent.o |
10 | 10 | ||
11 | ext4-$(CONFIG_EXT4_FS_XATTR) += xattr.o xattr_user.o xattr_trusted.o | 11 | ext4-$(CONFIG_EXT4_FS_XATTR) += xattr.o xattr_user.o xattr_trusted.o |
12 | ext4-$(CONFIG_EXT4_FS_POSIX_ACL) += acl.o | 12 | ext4-$(CONFIG_EXT4_FS_POSIX_ACL) += acl.o |
diff --git a/fs/ext4/ext4.h b/fs/ext4/ext4.h index cc7d5edc38c9..17b9998680e3 100644 --- a/fs/ext4/ext4.h +++ b/fs/ext4/ext4.h | |||
@@ -352,6 +352,7 @@ struct ext4_new_group_data { | |||
352 | /* note ioctl 10 reserved for an early version of the FIEMAP ioctl */ | 352 | /* note ioctl 10 reserved for an early version of the FIEMAP ioctl */ |
353 | /* note ioctl 11 reserved for filesystem-independent FIEMAP ioctl */ | 353 | /* note ioctl 11 reserved for filesystem-independent FIEMAP ioctl */ |
354 | #define EXT4_IOC_ALLOC_DA_BLKS _IO('f', 12) | 354 | #define EXT4_IOC_ALLOC_DA_BLKS _IO('f', 12) |
355 | #define EXT4_IOC_MOVE_EXT _IOWR('f', 15, struct move_extent) | ||
355 | 356 | ||
356 | /* | 357 | /* |
357 | * ioctl commands in 32 bit emulation | 358 | * ioctl commands in 32 bit emulation |
@@ -447,6 +448,15 @@ struct ext4_inode { | |||
447 | __le32 i_version_hi; /* high 32 bits for 64-bit version */ | 448 | __le32 i_version_hi; /* high 32 bits for 64-bit version */ |
448 | }; | 449 | }; |
449 | 450 | ||
451 | struct move_extent { | ||
452 | __u32 reserved; /* should be zero */ | ||
453 | __u32 donor_fd; /* donor file descriptor */ | ||
454 | __u64 orig_start; /* logical start offset in block for orig */ | ||
455 | __u64 donor_start; /* logical start offset in block for donor */ | ||
456 | __u64 len; /* block length to be moved */ | ||
457 | __u64 moved_len; /* moved block length */ | ||
458 | }; | ||
459 | #define MAX_DEFRAG_SIZE ((1UL<<31) - 1) | ||
450 | 460 | ||
451 | #define EXT4_EPOCH_BITS 2 | 461 | #define EXT4_EPOCH_BITS 2 |
452 | #define EXT4_EPOCH_MASK ((1 << EXT4_EPOCH_BITS) - 1) | 462 | #define EXT4_EPOCH_MASK ((1 << EXT4_EPOCH_BITS) - 1) |
@@ -674,7 +684,6 @@ struct ext4_inode_info { | |||
674 | #define EXT4_MOUNT_ERRORS_PANIC 0x00040 /* Panic on errors */ | 684 | #define EXT4_MOUNT_ERRORS_PANIC 0x00040 /* Panic on errors */ |
675 | #define EXT4_MOUNT_MINIX_DF 0x00080 /* Mimics the Minix statfs */ | 685 | #define EXT4_MOUNT_MINIX_DF 0x00080 /* Mimics the Minix statfs */ |
676 | #define EXT4_MOUNT_NOLOAD 0x00100 /* Don't use existing journal*/ | 686 | #define EXT4_MOUNT_NOLOAD 0x00100 /* Don't use existing journal*/ |
677 | #define EXT4_MOUNT_ABORT 0x00200 /* Fatal error detected */ | ||
678 | #define EXT4_MOUNT_DATA_FLAGS 0x00C00 /* Mode for data writes: */ | 687 | #define EXT4_MOUNT_DATA_FLAGS 0x00C00 /* Mode for data writes: */ |
679 | #define EXT4_MOUNT_JOURNAL_DATA 0x00400 /* Write data to journal */ | 688 | #define EXT4_MOUNT_JOURNAL_DATA 0x00400 /* Write data to journal */ |
680 | #define EXT4_MOUNT_ORDERED_DATA 0x00800 /* Flush data before commit */ | 689 | #define EXT4_MOUNT_ORDERED_DATA 0x00800 /* Flush data before commit */ |
@@ -696,17 +705,10 @@ struct ext4_inode_info { | |||
696 | #define EXT4_MOUNT_DATA_ERR_ABORT 0x10000000 /* Abort on file data write */ | 705 | #define EXT4_MOUNT_DATA_ERR_ABORT 0x10000000 /* Abort on file data write */ |
697 | #define EXT4_MOUNT_BLOCK_VALIDITY 0x20000000 /* Block validity checking */ | 706 | #define EXT4_MOUNT_BLOCK_VALIDITY 0x20000000 /* Block validity checking */ |
698 | 707 | ||
699 | /* Compatibility, for having both ext2_fs.h and ext4_fs.h included at once */ | ||
700 | #ifndef _LINUX_EXT2_FS_H | ||
701 | #define clear_opt(o, opt) o &= ~EXT4_MOUNT_##opt | 708 | #define clear_opt(o, opt) o &= ~EXT4_MOUNT_##opt |
702 | #define set_opt(o, opt) o |= EXT4_MOUNT_##opt | 709 | #define set_opt(o, opt) o |= EXT4_MOUNT_##opt |
703 | #define test_opt(sb, opt) (EXT4_SB(sb)->s_mount_opt & \ | 710 | #define test_opt(sb, opt) (EXT4_SB(sb)->s_mount_opt & \ |
704 | EXT4_MOUNT_##opt) | 711 | EXT4_MOUNT_##opt) |
705 | #else | ||
706 | #define EXT2_MOUNT_NOLOAD EXT4_MOUNT_NOLOAD | ||
707 | #define EXT2_MOUNT_ABORT EXT4_MOUNT_ABORT | ||
708 | #define EXT2_MOUNT_DATA_FLAGS EXT4_MOUNT_DATA_FLAGS | ||
709 | #endif | ||
710 | 712 | ||
711 | #define ext4_set_bit ext2_set_bit | 713 | #define ext4_set_bit ext2_set_bit |
712 | #define ext4_set_bit_atomic ext2_set_bit_atomic | 714 | #define ext4_set_bit_atomic ext2_set_bit_atomic |
@@ -824,6 +826,13 @@ struct ext4_super_block { | |||
824 | }; | 826 | }; |
825 | 827 | ||
826 | #ifdef __KERNEL__ | 828 | #ifdef __KERNEL__ |
829 | |||
830 | /* | ||
831 | * run-time mount flags | ||
832 | */ | ||
833 | #define EXT4_MF_MNTDIR_SAMPLED 0x0001 | ||
834 | #define EXT4_MF_FS_ABORTED 0x0002 /* Fatal error detected */ | ||
835 | |||
827 | /* | 836 | /* |
828 | * fourth extended-fs super-block data in memory | 837 | * fourth extended-fs super-block data in memory |
829 | */ | 838 | */ |
@@ -842,7 +851,8 @@ struct ext4_sb_info { | |||
842 | struct buffer_head * s_sbh; /* Buffer containing the super block */ | 851 | struct buffer_head * s_sbh; /* Buffer containing the super block */ |
843 | struct ext4_super_block *s_es; /* Pointer to the super block in the buffer */ | 852 | struct ext4_super_block *s_es; /* Pointer to the super block in the buffer */ |
844 | struct buffer_head **s_group_desc; | 853 | struct buffer_head **s_group_desc; |
845 | unsigned long s_mount_opt; | 854 | unsigned int s_mount_opt; |
855 | unsigned int s_mount_flags; | ||
846 | ext4_fsblk_t s_sb_block; | 856 | ext4_fsblk_t s_sb_block; |
847 | uid_t s_resuid; | 857 | uid_t s_resuid; |
848 | gid_t s_resgid; | 858 | gid_t s_resgid; |
@@ -853,6 +863,7 @@ struct ext4_sb_info { | |||
853 | int s_inode_size; | 863 | int s_inode_size; |
854 | int s_first_ino; | 864 | int s_first_ino; |
855 | unsigned int s_inode_readahead_blks; | 865 | unsigned int s_inode_readahead_blks; |
866 | unsigned int s_inode_goal; | ||
856 | spinlock_t s_next_gen_lock; | 867 | spinlock_t s_next_gen_lock; |
857 | u32 s_next_generation; | 868 | u32 s_next_generation; |
858 | u32 s_hash_seed[4]; | 869 | u32 s_hash_seed[4]; |
@@ -1305,7 +1316,8 @@ extern int ext4fs_dirhash(const char *name, int len, struct | |||
1305 | dx_hash_info *hinfo); | 1316 | dx_hash_info *hinfo); |
1306 | 1317 | ||
1307 | /* ialloc.c */ | 1318 | /* ialloc.c */ |
1308 | extern struct inode * ext4_new_inode(handle_t *, struct inode *, int); | 1319 | extern struct inode *ext4_new_inode(handle_t *, struct inode *, int, |
1320 | const struct qstr *qstr, __u32 goal); | ||
1309 | extern void ext4_free_inode(handle_t *, struct inode *); | 1321 | extern void ext4_free_inode(handle_t *, struct inode *); |
1310 | extern struct inode * ext4_orphan_get(struct super_block *, unsigned long); | 1322 | extern struct inode * ext4_orphan_get(struct super_block *, unsigned long); |
1311 | extern unsigned long ext4_count_free_inodes(struct super_block *); | 1323 | extern unsigned long ext4_count_free_inodes(struct super_block *); |
@@ -1329,7 +1341,7 @@ extern void ext4_discard_preallocations(struct inode *); | |||
1329 | extern int __init init_ext4_mballoc(void); | 1341 | extern int __init init_ext4_mballoc(void); |
1330 | extern void exit_ext4_mballoc(void); | 1342 | extern void exit_ext4_mballoc(void); |
1331 | extern void ext4_mb_free_blocks(handle_t *, struct inode *, | 1343 | extern void ext4_mb_free_blocks(handle_t *, struct inode *, |
1332 | unsigned long, unsigned long, int, unsigned long *); | 1344 | ext4_fsblk_t, unsigned long, int, unsigned long *); |
1333 | extern int ext4_mb_add_groupinfo(struct super_block *sb, | 1345 | extern int ext4_mb_add_groupinfo(struct super_block *sb, |
1334 | ext4_group_t i, struct ext4_group_desc *desc); | 1346 | ext4_group_t i, struct ext4_group_desc *desc); |
1335 | extern void ext4_mb_update_group_info(struct ext4_group_info *grp, | 1347 | extern void ext4_mb_update_group_info(struct ext4_group_info *grp, |
@@ -1647,6 +1659,11 @@ extern int ext4_get_blocks(handle_t *handle, struct inode *inode, | |||
1647 | struct buffer_head *bh, int flags); | 1659 | struct buffer_head *bh, int flags); |
1648 | extern int ext4_fiemap(struct inode *inode, struct fiemap_extent_info *fieinfo, | 1660 | extern int ext4_fiemap(struct inode *inode, struct fiemap_extent_info *fieinfo, |
1649 | __u64 start, __u64 len); | 1661 | __u64 start, __u64 len); |
1662 | /* move_extent.c */ | ||
1663 | extern int ext4_move_extents(struct file *o_filp, struct file *d_filp, | ||
1664 | __u64 start_orig, __u64 start_donor, | ||
1665 | __u64 len, __u64 *moved_len); | ||
1666 | |||
1650 | 1667 | ||
1651 | /* | 1668 | /* |
1652 | * Add new method to test wether block and inode bitmaps are properly | 1669 | * Add new method to test wether block and inode bitmaps are properly |
diff --git a/fs/ext4/ext4_extents.h b/fs/ext4/ext4_extents.h index f0c3ec85bd48..20a84105a10b 100644 --- a/fs/ext4/ext4_extents.h +++ b/fs/ext4/ext4_extents.h | |||
@@ -221,12 +221,16 @@ static inline int ext4_ext_get_actual_len(struct ext4_extent *ext) | |||
221 | } | 221 | } |
222 | 222 | ||
223 | extern int ext4_ext_calc_metadata_amount(struct inode *inode, int blocks); | 223 | extern int ext4_ext_calc_metadata_amount(struct inode *inode, int blocks); |
224 | extern ext4_fsblk_t ext_pblock(struct ext4_extent *ex); | ||
224 | extern ext4_fsblk_t idx_pblock(struct ext4_extent_idx *); | 225 | extern ext4_fsblk_t idx_pblock(struct ext4_extent_idx *); |
225 | extern void ext4_ext_store_pblock(struct ext4_extent *, ext4_fsblk_t); | 226 | extern void ext4_ext_store_pblock(struct ext4_extent *, ext4_fsblk_t); |
226 | extern int ext4_extent_tree_init(handle_t *, struct inode *); | 227 | extern int ext4_extent_tree_init(handle_t *, struct inode *); |
227 | extern int ext4_ext_calc_credits_for_single_extent(struct inode *inode, | 228 | extern int ext4_ext_calc_credits_for_single_extent(struct inode *inode, |
228 | int num, | 229 | int num, |
229 | struct ext4_ext_path *path); | 230 | struct ext4_ext_path *path); |
231 | extern int ext4_can_extents_be_merged(struct inode *inode, | ||
232 | struct ext4_extent *ex1, | ||
233 | struct ext4_extent *ex2); | ||
230 | extern int ext4_ext_try_to_merge(struct inode *inode, | 234 | extern int ext4_ext_try_to_merge(struct inode *inode, |
231 | struct ext4_ext_path *path, | 235 | struct ext4_ext_path *path, |
232 | struct ext4_extent *); | 236 | struct ext4_extent *); |
diff --git a/fs/ext4/extents.c b/fs/ext4/extents.c index 2593f748c3a4..50322a09bd01 100644 --- a/fs/ext4/extents.c +++ b/fs/ext4/extents.c | |||
@@ -49,7 +49,7 @@ | |||
49 | * ext_pblock: | 49 | * ext_pblock: |
50 | * combine low and high parts of physical block number into ext4_fsblk_t | 50 | * combine low and high parts of physical block number into ext4_fsblk_t |
51 | */ | 51 | */ |
52 | static ext4_fsblk_t ext_pblock(struct ext4_extent *ex) | 52 | ext4_fsblk_t ext_pblock(struct ext4_extent *ex) |
53 | { | 53 | { |
54 | ext4_fsblk_t block; | 54 | ext4_fsblk_t block; |
55 | 55 | ||
@@ -1417,7 +1417,7 @@ static int ext4_ext_correct_indexes(handle_t *handle, struct inode *inode, | |||
1417 | return err; | 1417 | return err; |
1418 | } | 1418 | } |
1419 | 1419 | ||
1420 | static int | 1420 | int |
1421 | ext4_can_extents_be_merged(struct inode *inode, struct ext4_extent *ex1, | 1421 | ext4_can_extents_be_merged(struct inode *inode, struct ext4_extent *ex1, |
1422 | struct ext4_extent *ex2) | 1422 | struct ext4_extent *ex2) |
1423 | { | 1423 | { |
diff --git a/fs/ext4/file.c b/fs/ext4/file.c index 588af8c77246..3f1873fef1c6 100644 --- a/fs/ext4/file.c +++ b/fs/ext4/file.c | |||
@@ -21,6 +21,8 @@ | |||
21 | #include <linux/time.h> | 21 | #include <linux/time.h> |
22 | #include <linux/fs.h> | 22 | #include <linux/fs.h> |
23 | #include <linux/jbd2.h> | 23 | #include <linux/jbd2.h> |
24 | #include <linux/mount.h> | ||
25 | #include <linux/path.h> | ||
24 | #include "ext4.h" | 26 | #include "ext4.h" |
25 | #include "ext4_jbd2.h" | 27 | #include "ext4_jbd2.h" |
26 | #include "xattr.h" | 28 | #include "xattr.h" |
@@ -145,6 +147,38 @@ static int ext4_file_mmap(struct file *file, struct vm_area_struct *vma) | |||
145 | return 0; | 147 | return 0; |
146 | } | 148 | } |
147 | 149 | ||
150 | static int ext4_file_open(struct inode * inode, struct file * filp) | ||
151 | { | ||
152 | struct super_block *sb = inode->i_sb; | ||
153 | struct ext4_sb_info *sbi = EXT4_SB(inode->i_sb); | ||
154 | struct vfsmount *mnt = filp->f_path.mnt; | ||
155 | struct path path; | ||
156 | char buf[64], *cp; | ||
157 | |||
158 | if (unlikely(!(sbi->s_mount_flags & EXT4_MF_MNTDIR_SAMPLED) && | ||
159 | !(sb->s_flags & MS_RDONLY))) { | ||
160 | sbi->s_mount_flags |= EXT4_MF_MNTDIR_SAMPLED; | ||
161 | /* | ||
162 | * Sample where the filesystem has been mounted and | ||
163 | * store it in the superblock for sysadmin convenience | ||
164 | * when trying to sort through large numbers of block | ||
165 | * devices or filesystem images. | ||
166 | */ | ||
167 | memset(buf, 0, sizeof(buf)); | ||
168 | path.mnt = mnt->mnt_parent; | ||
169 | path.dentry = mnt->mnt_mountpoint; | ||
170 | path_get(&path); | ||
171 | cp = d_path(&path, buf, sizeof(buf)); | ||
172 | path_put(&path); | ||
173 | if (!IS_ERR(cp)) { | ||
174 | memcpy(sbi->s_es->s_last_mounted, cp, | ||
175 | sizeof(sbi->s_es->s_last_mounted)); | ||
176 | sb->s_dirt = 1; | ||
177 | } | ||
178 | } | ||
179 | return generic_file_open(inode, filp); | ||
180 | } | ||
181 | |||
148 | const struct file_operations ext4_file_operations = { | 182 | const struct file_operations ext4_file_operations = { |
149 | .llseek = generic_file_llseek, | 183 | .llseek = generic_file_llseek, |
150 | .read = do_sync_read, | 184 | .read = do_sync_read, |
@@ -156,7 +190,7 @@ const struct file_operations ext4_file_operations = { | |||
156 | .compat_ioctl = ext4_compat_ioctl, | 190 | .compat_ioctl = ext4_compat_ioctl, |
157 | #endif | 191 | #endif |
158 | .mmap = ext4_file_mmap, | 192 | .mmap = ext4_file_mmap, |
159 | .open = generic_file_open, | 193 | .open = ext4_file_open, |
160 | .release = ext4_release_file, | 194 | .release = ext4_release_file, |
161 | .fsync = ext4_sync_file, | 195 | .fsync = ext4_sync_file, |
162 | .splice_read = generic_file_splice_read, | 196 | .splice_read = generic_file_splice_read, |
diff --git a/fs/ext4/fsync.c b/fs/ext4/fsync.c index 5afe4370840b..83cf6415f599 100644 --- a/fs/ext4/fsync.c +++ b/fs/ext4/fsync.c | |||
@@ -28,10 +28,12 @@ | |||
28 | #include <linux/writeback.h> | 28 | #include <linux/writeback.h> |
29 | #include <linux/jbd2.h> | 29 | #include <linux/jbd2.h> |
30 | #include <linux/blkdev.h> | 30 | #include <linux/blkdev.h> |
31 | #include <linux/marker.h> | 31 | |
32 | #include "ext4.h" | 32 | #include "ext4.h" |
33 | #include "ext4_jbd2.h" | 33 | #include "ext4_jbd2.h" |
34 | 34 | ||
35 | #include <trace/events/ext4.h> | ||
36 | |||
35 | /* | 37 | /* |
36 | * akpm: A new design for ext4_sync_file(). | 38 | * akpm: A new design for ext4_sync_file(). |
37 | * | 39 | * |
@@ -52,9 +54,7 @@ int ext4_sync_file(struct file *file, struct dentry *dentry, int datasync) | |||
52 | 54 | ||
53 | J_ASSERT(ext4_journal_current_handle() == NULL); | 55 | J_ASSERT(ext4_journal_current_handle() == NULL); |
54 | 56 | ||
55 | trace_mark(ext4_sync_file, "dev %s datasync %d ino %ld parent %ld", | 57 | trace_ext4_sync_file(file, dentry, datasync); |
56 | inode->i_sb->s_id, datasync, inode->i_ino, | ||
57 | dentry->d_parent->d_inode->i_ino); | ||
58 | 58 | ||
59 | /* | 59 | /* |
60 | * data=writeback: | 60 | * data=writeback: |
diff --git a/fs/ext4/ialloc.c b/fs/ext4/ialloc.c index 3743bd849bce..2f645732e3b7 100644 --- a/fs/ext4/ialloc.c +++ b/fs/ext4/ialloc.c | |||
@@ -23,11 +23,14 @@ | |||
23 | #include <linux/bitops.h> | 23 | #include <linux/bitops.h> |
24 | #include <linux/blkdev.h> | 24 | #include <linux/blkdev.h> |
25 | #include <asm/byteorder.h> | 25 | #include <asm/byteorder.h> |
26 | |||
26 | #include "ext4.h" | 27 | #include "ext4.h" |
27 | #include "ext4_jbd2.h" | 28 | #include "ext4_jbd2.h" |
28 | #include "xattr.h" | 29 | #include "xattr.h" |
29 | #include "acl.h" | 30 | #include "acl.h" |
30 | 31 | ||
32 | #include <trace/events/ext4.h> | ||
33 | |||
31 | /* | 34 | /* |
32 | * ialloc.c contains the inodes allocation and deallocation routines | 35 | * ialloc.c contains the inodes allocation and deallocation routines |
33 | */ | 36 | */ |
@@ -208,11 +211,7 @@ void ext4_free_inode(handle_t *handle, struct inode *inode) | |||
208 | 211 | ||
209 | ino = inode->i_ino; | 212 | ino = inode->i_ino; |
210 | ext4_debug("freeing inode %lu\n", ino); | 213 | ext4_debug("freeing inode %lu\n", ino); |
211 | trace_mark(ext4_free_inode, | 214 | trace_ext4_free_inode(inode); |
212 | "dev %s ino %lu mode %d uid %lu gid %lu bocks %llu", | ||
213 | sb->s_id, inode->i_ino, inode->i_mode, | ||
214 | (unsigned long) inode->i_uid, (unsigned long) inode->i_gid, | ||
215 | (unsigned long long) inode->i_blocks); | ||
216 | 215 | ||
217 | /* | 216 | /* |
218 | * Note: we must free any quota before locking the superblock, | 217 | * Note: we must free any quota before locking the superblock, |
@@ -471,7 +470,8 @@ void get_orlov_stats(struct super_block *sb, ext4_group_t g, | |||
471 | */ | 470 | */ |
472 | 471 | ||
473 | static int find_group_orlov(struct super_block *sb, struct inode *parent, | 472 | static int find_group_orlov(struct super_block *sb, struct inode *parent, |
474 | ext4_group_t *group, int mode) | 473 | ext4_group_t *group, int mode, |
474 | const struct qstr *qstr) | ||
475 | { | 475 | { |
476 | ext4_group_t parent_group = EXT4_I(parent)->i_block_group; | 476 | ext4_group_t parent_group = EXT4_I(parent)->i_block_group; |
477 | struct ext4_sb_info *sbi = EXT4_SB(sb); | 477 | struct ext4_sb_info *sbi = EXT4_SB(sb); |
@@ -486,6 +486,7 @@ static int find_group_orlov(struct super_block *sb, struct inode *parent, | |||
486 | struct ext4_group_desc *desc; | 486 | struct ext4_group_desc *desc; |
487 | struct orlov_stats stats; | 487 | struct orlov_stats stats; |
488 | int flex_size = ext4_flex_bg_size(sbi); | 488 | int flex_size = ext4_flex_bg_size(sbi); |
489 | struct dx_hash_info hinfo; | ||
489 | 490 | ||
490 | ngroups = real_ngroups; | 491 | ngroups = real_ngroups; |
491 | if (flex_size > 1) { | 492 | if (flex_size > 1) { |
@@ -507,7 +508,13 @@ static int find_group_orlov(struct super_block *sb, struct inode *parent, | |||
507 | int best_ndir = inodes_per_group; | 508 | int best_ndir = inodes_per_group; |
508 | int ret = -1; | 509 | int ret = -1; |
509 | 510 | ||
510 | get_random_bytes(&grp, sizeof(grp)); | 511 | if (qstr) { |
512 | hinfo.hash_version = DX_HASH_HALF_MD4; | ||
513 | hinfo.seed = sbi->s_hash_seed; | ||
514 | ext4fs_dirhash(qstr->name, qstr->len, &hinfo); | ||
515 | grp = hinfo.hash; | ||
516 | } else | ||
517 | get_random_bytes(&grp, sizeof(grp)); | ||
511 | parent_group = (unsigned)grp % ngroups; | 518 | parent_group = (unsigned)grp % ngroups; |
512 | for (i = 0; i < ngroups; i++) { | 519 | for (i = 0; i < ngroups; i++) { |
513 | g = (parent_group + i) % ngroups; | 520 | g = (parent_group + i) % ngroups; |
@@ -650,7 +657,7 @@ static int find_group_other(struct super_block *sb, struct inode *parent, | |||
650 | *group = parent_group + flex_size; | 657 | *group = parent_group + flex_size; |
651 | if (*group > ngroups) | 658 | if (*group > ngroups) |
652 | *group = 0; | 659 | *group = 0; |
653 | return find_group_orlov(sb, parent, group, mode); | 660 | return find_group_orlov(sb, parent, group, mode, 0); |
654 | } | 661 | } |
655 | 662 | ||
656 | /* | 663 | /* |
@@ -791,7 +798,8 @@ err_ret: | |||
791 | * For other inodes, search forward from the parent directory's block | 798 | * For other inodes, search forward from the parent directory's block |
792 | * group to find a free inode. | 799 | * group to find a free inode. |
793 | */ | 800 | */ |
794 | struct inode *ext4_new_inode(handle_t *handle, struct inode *dir, int mode) | 801 | struct inode *ext4_new_inode(handle_t *handle, struct inode *dir, int mode, |
802 | const struct qstr *qstr, __u32 goal) | ||
795 | { | 803 | { |
796 | struct super_block *sb; | 804 | struct super_block *sb; |
797 | struct buffer_head *inode_bitmap_bh = NULL; | 805 | struct buffer_head *inode_bitmap_bh = NULL; |
@@ -815,14 +823,23 @@ struct inode *ext4_new_inode(handle_t *handle, struct inode *dir, int mode) | |||
815 | 823 | ||
816 | sb = dir->i_sb; | 824 | sb = dir->i_sb; |
817 | ngroups = ext4_get_groups_count(sb); | 825 | ngroups = ext4_get_groups_count(sb); |
818 | trace_mark(ext4_request_inode, "dev %s dir %lu mode %d", sb->s_id, | 826 | trace_ext4_request_inode(dir, mode); |
819 | dir->i_ino, mode); | ||
820 | inode = new_inode(sb); | 827 | inode = new_inode(sb); |
821 | if (!inode) | 828 | if (!inode) |
822 | return ERR_PTR(-ENOMEM); | 829 | return ERR_PTR(-ENOMEM); |
823 | ei = EXT4_I(inode); | 830 | ei = EXT4_I(inode); |
824 | sbi = EXT4_SB(sb); | 831 | sbi = EXT4_SB(sb); |
825 | 832 | ||
833 | if (!goal) | ||
834 | goal = sbi->s_inode_goal; | ||
835 | |||
836 | if (goal && goal < le32_to_cpu(sbi->s_es->s_inodes_count)) { | ||
837 | group = (goal - 1) / EXT4_INODES_PER_GROUP(sb); | ||
838 | ino = (goal - 1) % EXT4_INODES_PER_GROUP(sb); | ||
839 | ret2 = 0; | ||
840 | goto got_group; | ||
841 | } | ||
842 | |||
826 | if (sbi->s_log_groups_per_flex && test_opt(sb, OLDALLOC)) { | 843 | if (sbi->s_log_groups_per_flex && test_opt(sb, OLDALLOC)) { |
827 | ret2 = find_group_flex(sb, dir, &group); | 844 | ret2 = find_group_flex(sb, dir, &group); |
828 | if (ret2 == -1) { | 845 | if (ret2 == -1) { |
@@ -841,7 +858,7 @@ struct inode *ext4_new_inode(handle_t *handle, struct inode *dir, int mode) | |||
841 | if (test_opt(sb, OLDALLOC)) | 858 | if (test_opt(sb, OLDALLOC)) |
842 | ret2 = find_group_dir(sb, dir, &group); | 859 | ret2 = find_group_dir(sb, dir, &group); |
843 | else | 860 | else |
844 | ret2 = find_group_orlov(sb, dir, &group, mode); | 861 | ret2 = find_group_orlov(sb, dir, &group, mode, qstr); |
845 | } else | 862 | } else |
846 | ret2 = find_group_other(sb, dir, &group, mode); | 863 | ret2 = find_group_other(sb, dir, &group, mode); |
847 | 864 | ||
@@ -851,7 +868,7 @@ got_group: | |||
851 | if (ret2 == -1) | 868 | if (ret2 == -1) |
852 | goto out; | 869 | goto out; |
853 | 870 | ||
854 | for (i = 0; i < ngroups; i++) { | 871 | for (i = 0; i < ngroups; i++, ino = 0) { |
855 | err = -EIO; | 872 | err = -EIO; |
856 | 873 | ||
857 | gdp = ext4_get_group_desc(sb, group, &group_desc_bh); | 874 | gdp = ext4_get_group_desc(sb, group, &group_desc_bh); |
@@ -863,8 +880,6 @@ got_group: | |||
863 | if (!inode_bitmap_bh) | 880 | if (!inode_bitmap_bh) |
864 | goto fail; | 881 | goto fail; |
865 | 882 | ||
866 | ino = 0; | ||
867 | |||
868 | repeat_in_this_group: | 883 | repeat_in_this_group: |
869 | ino = ext4_find_next_zero_bit((unsigned long *) | 884 | ino = ext4_find_next_zero_bit((unsigned long *) |
870 | inode_bitmap_bh->b_data, | 885 | inode_bitmap_bh->b_data, |
@@ -1047,8 +1062,7 @@ got: | |||
1047 | } | 1062 | } |
1048 | 1063 | ||
1049 | ext4_debug("allocating inode %lu\n", inode->i_ino); | 1064 | ext4_debug("allocating inode %lu\n", inode->i_ino); |
1050 | trace_mark(ext4_allocate_inode, "dev %s ino %lu dir %lu mode %d", | 1065 | trace_ext4_allocate_inode(inode, dir, mode); |
1051 | sb->s_id, inode->i_ino, dir->i_ino, mode); | ||
1052 | goto really_out; | 1066 | goto really_out; |
1053 | fail: | 1067 | fail: |
1054 | ext4_std_error(sb, err); | 1068 | ext4_std_error(sb, err); |
diff --git a/fs/ext4/inode.c b/fs/ext4/inode.c index 875db944b22f..7c17ae275af4 100644 --- a/fs/ext4/inode.c +++ b/fs/ext4/inode.c | |||
@@ -37,11 +37,14 @@ | |||
37 | #include <linux/namei.h> | 37 | #include <linux/namei.h> |
38 | #include <linux/uio.h> | 38 | #include <linux/uio.h> |
39 | #include <linux/bio.h> | 39 | #include <linux/bio.h> |
40 | |||
40 | #include "ext4_jbd2.h" | 41 | #include "ext4_jbd2.h" |
41 | #include "xattr.h" | 42 | #include "xattr.h" |
42 | #include "acl.h" | 43 | #include "acl.h" |
43 | #include "ext4_extents.h" | 44 | #include "ext4_extents.h" |
44 | 45 | ||
46 | #include <trace/events/ext4.h> | ||
47 | |||
45 | #define MPAGE_DA_EXTENT_TAIL 0x01 | 48 | #define MPAGE_DA_EXTENT_TAIL 0x01 |
46 | 49 | ||
47 | static inline int ext4_begin_ordered_truncate(struct inode *inode, | 50 | static inline int ext4_begin_ordered_truncate(struct inode *inode, |
@@ -78,7 +81,7 @@ static int ext4_inode_is_fast_symlink(struct inode *inode) | |||
78 | * If the handle isn't valid we're not journaling so there's nothing to do. | 81 | * If the handle isn't valid we're not journaling so there's nothing to do. |
79 | */ | 82 | */ |
80 | int ext4_forget(handle_t *handle, int is_metadata, struct inode *inode, | 83 | int ext4_forget(handle_t *handle, int is_metadata, struct inode *inode, |
81 | struct buffer_head *bh, ext4_fsblk_t blocknr) | 84 | struct buffer_head *bh, ext4_fsblk_t blocknr) |
82 | { | 85 | { |
83 | int err; | 86 | int err; |
84 | 87 | ||
@@ -90,7 +93,7 @@ int ext4_forget(handle_t *handle, int is_metadata, struct inode *inode, | |||
90 | BUFFER_TRACE(bh, "enter"); | 93 | BUFFER_TRACE(bh, "enter"); |
91 | 94 | ||
92 | jbd_debug(4, "forgetting bh %p: is_metadata = %d, mode %o, " | 95 | jbd_debug(4, "forgetting bh %p: is_metadata = %d, mode %o, " |
93 | "data mode %lx\n", | 96 | "data mode %x\n", |
94 | bh, is_metadata, inode->i_mode, | 97 | bh, is_metadata, inode->i_mode, |
95 | test_opt(inode->i_sb, DATA_FLAGS)); | 98 | test_opt(inode->i_sb, DATA_FLAGS)); |
96 | 99 | ||
@@ -329,8 +332,8 @@ static inline void add_chain(Indirect *p, struct buffer_head *bh, __le32 *v) | |||
329 | */ | 332 | */ |
330 | 333 | ||
331 | static int ext4_block_to_path(struct inode *inode, | 334 | static int ext4_block_to_path(struct inode *inode, |
332 | ext4_lblk_t i_block, | 335 | ext4_lblk_t i_block, |
333 | ext4_lblk_t offsets[4], int *boundary) | 336 | ext4_lblk_t offsets[4], int *boundary) |
334 | { | 337 | { |
335 | int ptrs = EXT4_ADDR_PER_BLOCK(inode->i_sb); | 338 | int ptrs = EXT4_ADDR_PER_BLOCK(inode->i_sb); |
336 | int ptrs_bits = EXT4_ADDR_PER_BLOCK_BITS(inode->i_sb); | 339 | int ptrs_bits = EXT4_ADDR_PER_BLOCK_BITS(inode->i_sb); |
@@ -362,9 +365,9 @@ static int ext4_block_to_path(struct inode *inode, | |||
362 | final = ptrs; | 365 | final = ptrs; |
363 | } else { | 366 | } else { |
364 | ext4_warning(inode->i_sb, "ext4_block_to_path", | 367 | ext4_warning(inode->i_sb, "ext4_block_to_path", |
365 | "block %lu > max in inode %lu", | 368 | "block %lu > max in inode %lu", |
366 | i_block + direct_blocks + | 369 | i_block + direct_blocks + |
367 | indirect_blocks + double_blocks, inode->i_ino); | 370 | indirect_blocks + double_blocks, inode->i_ino); |
368 | } | 371 | } |
369 | if (boundary) | 372 | if (boundary) |
370 | *boundary = final - 1 - (i_block & (ptrs - 1)); | 373 | *boundary = final - 1 - (i_block & (ptrs - 1)); |
@@ -379,25 +382,25 @@ static int __ext4_check_blockref(const char *function, struct inode *inode, | |||
379 | 382 | ||
380 | while (bref < p+max) { | 383 | while (bref < p+max) { |
381 | blk = le32_to_cpu(*bref++); | 384 | blk = le32_to_cpu(*bref++); |
382 | if (blk && | 385 | if (blk && |
383 | unlikely(!ext4_data_block_valid(EXT4_SB(inode->i_sb), | 386 | unlikely(!ext4_data_block_valid(EXT4_SB(inode->i_sb), |
384 | blk, 1))) { | 387 | blk, 1))) { |
385 | ext4_error(inode->i_sb, function, | 388 | ext4_error(inode->i_sb, function, |
386 | "invalid block reference %u " | 389 | "invalid block reference %u " |
387 | "in inode #%lu", blk, inode->i_ino); | 390 | "in inode #%lu", blk, inode->i_ino); |
388 | return -EIO; | 391 | return -EIO; |
389 | } | 392 | } |
390 | } | 393 | } |
391 | return 0; | 394 | return 0; |
392 | } | 395 | } |
393 | 396 | ||
394 | 397 | ||
395 | #define ext4_check_indirect_blockref(inode, bh) \ | 398 | #define ext4_check_indirect_blockref(inode, bh) \ |
396 | __ext4_check_blockref(__func__, inode, (__le32 *)(bh)->b_data, \ | 399 | __ext4_check_blockref(__func__, inode, (__le32 *)(bh)->b_data, \ |
397 | EXT4_ADDR_PER_BLOCK((inode)->i_sb)) | 400 | EXT4_ADDR_PER_BLOCK((inode)->i_sb)) |
398 | 401 | ||
399 | #define ext4_check_inode_blockref(inode) \ | 402 | #define ext4_check_inode_blockref(inode) \ |
400 | __ext4_check_blockref(__func__, inode, EXT4_I(inode)->i_data, \ | 403 | __ext4_check_blockref(__func__, inode, EXT4_I(inode)->i_data, \ |
401 | EXT4_NDIR_BLOCKS) | 404 | EXT4_NDIR_BLOCKS) |
402 | 405 | ||
403 | /** | 406 | /** |
@@ -447,7 +450,7 @@ static Indirect *ext4_get_branch(struct inode *inode, int depth, | |||
447 | bh = sb_getblk(sb, le32_to_cpu(p->key)); | 450 | bh = sb_getblk(sb, le32_to_cpu(p->key)); |
448 | if (unlikely(!bh)) | 451 | if (unlikely(!bh)) |
449 | goto failure; | 452 | goto failure; |
450 | 453 | ||
451 | if (!bh_uptodate_or_lock(bh)) { | 454 | if (!bh_uptodate_or_lock(bh)) { |
452 | if (bh_submit_read(bh) < 0) { | 455 | if (bh_submit_read(bh) < 0) { |
453 | put_bh(bh); | 456 | put_bh(bh); |
@@ -459,7 +462,7 @@ static Indirect *ext4_get_branch(struct inode *inode, int depth, | |||
459 | goto failure; | 462 | goto failure; |
460 | } | 463 | } |
461 | } | 464 | } |
462 | 465 | ||
463 | add_chain(++p, bh, (__le32 *)bh->b_data + *++offsets); | 466 | add_chain(++p, bh, (__le32 *)bh->b_data + *++offsets); |
464 | /* Reader: end */ | 467 | /* Reader: end */ |
465 | if (!p->key) | 468 | if (!p->key) |
@@ -552,7 +555,7 @@ static ext4_fsblk_t ext4_find_near(struct inode *inode, Indirect *ind) | |||
552 | * returns it. | 555 | * returns it. |
553 | */ | 556 | */ |
554 | static ext4_fsblk_t ext4_find_goal(struct inode *inode, ext4_lblk_t block, | 557 | static ext4_fsblk_t ext4_find_goal(struct inode *inode, ext4_lblk_t block, |
555 | Indirect *partial) | 558 | Indirect *partial) |
556 | { | 559 | { |
557 | /* | 560 | /* |
558 | * XXX need to get goal block from mballoc's data structures | 561 | * XXX need to get goal block from mballoc's data structures |
@@ -574,7 +577,7 @@ static ext4_fsblk_t ext4_find_goal(struct inode *inode, ext4_lblk_t block, | |||
574 | * direct and indirect blocks. | 577 | * direct and indirect blocks. |
575 | */ | 578 | */ |
576 | static int ext4_blks_to_allocate(Indirect *branch, int k, unsigned int blks, | 579 | static int ext4_blks_to_allocate(Indirect *branch, int k, unsigned int blks, |
577 | int blocks_to_boundary) | 580 | int blocks_to_boundary) |
578 | { | 581 | { |
579 | unsigned int count = 0; | 582 | unsigned int count = 0; |
580 | 583 | ||
@@ -610,9 +613,9 @@ static int ext4_blks_to_allocate(Indirect *branch, int k, unsigned int blks, | |||
610 | * direct blocks | 613 | * direct blocks |
611 | */ | 614 | */ |
612 | static int ext4_alloc_blocks(handle_t *handle, struct inode *inode, | 615 | static int ext4_alloc_blocks(handle_t *handle, struct inode *inode, |
613 | ext4_lblk_t iblock, ext4_fsblk_t goal, | 616 | ext4_lblk_t iblock, ext4_fsblk_t goal, |
614 | int indirect_blks, int blks, | 617 | int indirect_blks, int blks, |
615 | ext4_fsblk_t new_blocks[4], int *err) | 618 | ext4_fsblk_t new_blocks[4], int *err) |
616 | { | 619 | { |
617 | struct ext4_allocation_request ar; | 620 | struct ext4_allocation_request ar; |
618 | int target, i; | 621 | int target, i; |
@@ -683,10 +686,10 @@ static int ext4_alloc_blocks(handle_t *handle, struct inode *inode, | |||
683 | } | 686 | } |
684 | if (!*err) { | 687 | if (!*err) { |
685 | if (target == blks) { | 688 | if (target == blks) { |
686 | /* | 689 | /* |
687 | * save the new block number | 690 | * save the new block number |
688 | * for the first direct block | 691 | * for the first direct block |
689 | */ | 692 | */ |
690 | new_blocks[index] = current_block; | 693 | new_blocks[index] = current_block; |
691 | } | 694 | } |
692 | blk_allocated += ar.len; | 695 | blk_allocated += ar.len; |
@@ -728,9 +731,9 @@ failed_out: | |||
728 | * as described above and return 0. | 731 | * as described above and return 0. |
729 | */ | 732 | */ |
730 | static int ext4_alloc_branch(handle_t *handle, struct inode *inode, | 733 | static int ext4_alloc_branch(handle_t *handle, struct inode *inode, |
731 | ext4_lblk_t iblock, int indirect_blks, | 734 | ext4_lblk_t iblock, int indirect_blks, |
732 | int *blks, ext4_fsblk_t goal, | 735 | int *blks, ext4_fsblk_t goal, |
733 | ext4_lblk_t *offsets, Indirect *branch) | 736 | ext4_lblk_t *offsets, Indirect *branch) |
734 | { | 737 | { |
735 | int blocksize = inode->i_sb->s_blocksize; | 738 | int blocksize = inode->i_sb->s_blocksize; |
736 | int i, n = 0; | 739 | int i, n = 0; |
@@ -777,7 +780,7 @@ static int ext4_alloc_branch(handle_t *handle, struct inode *inode, | |||
777 | * the chain to point to the new allocated | 780 | * the chain to point to the new allocated |
778 | * data blocks numbers | 781 | * data blocks numbers |
779 | */ | 782 | */ |
780 | for (i=1; i < num; i++) | 783 | for (i = 1; i < num; i++) |
781 | *(branch[n].p + i) = cpu_to_le32(++current_block); | 784 | *(branch[n].p + i) = cpu_to_le32(++current_block); |
782 | } | 785 | } |
783 | BUFFER_TRACE(bh, "marking uptodate"); | 786 | BUFFER_TRACE(bh, "marking uptodate"); |
@@ -820,7 +823,8 @@ failed: | |||
820 | * chain to new block and return 0. | 823 | * chain to new block and return 0. |
821 | */ | 824 | */ |
822 | static int ext4_splice_branch(handle_t *handle, struct inode *inode, | 825 | static int ext4_splice_branch(handle_t *handle, struct inode *inode, |
823 | ext4_lblk_t block, Indirect *where, int num, int blks) | 826 | ext4_lblk_t block, Indirect *where, int num, |
827 | int blks) | ||
824 | { | 828 | { |
825 | int i; | 829 | int i; |
826 | int err = 0; | 830 | int err = 0; |
@@ -852,10 +856,6 @@ static int ext4_splice_branch(handle_t *handle, struct inode *inode, | |||
852 | } | 856 | } |
853 | 857 | ||
854 | /* We are done with atomic stuff, now do the rest of housekeeping */ | 858 | /* We are done with atomic stuff, now do the rest of housekeeping */ |
855 | |||
856 | inode->i_ctime = ext4_current_time(inode); | ||
857 | ext4_mark_inode_dirty(handle, inode); | ||
858 | |||
859 | /* had we spliced it onto indirect block? */ | 859 | /* had we spliced it onto indirect block? */ |
860 | if (where->bh) { | 860 | if (where->bh) { |
861 | /* | 861 | /* |
@@ -874,8 +874,8 @@ static int ext4_splice_branch(handle_t *handle, struct inode *inode, | |||
874 | } else { | 874 | } else { |
875 | /* | 875 | /* |
876 | * OK, we spliced it into the inode itself on a direct block. | 876 | * OK, we spliced it into the inode itself on a direct block. |
877 | * Inode was dirtied above. | ||
878 | */ | 877 | */ |
878 | ext4_mark_inode_dirty(handle, inode); | ||
879 | jbd_debug(5, "splicing direct\n"); | 879 | jbd_debug(5, "splicing direct\n"); |
880 | } | 880 | } |
881 | return err; | 881 | return err; |
@@ -921,9 +921,9 @@ err_out: | |||
921 | * blocks. | 921 | * blocks. |
922 | */ | 922 | */ |
923 | static int ext4_ind_get_blocks(handle_t *handle, struct inode *inode, | 923 | static int ext4_ind_get_blocks(handle_t *handle, struct inode *inode, |
924 | ext4_lblk_t iblock, unsigned int maxblocks, | 924 | ext4_lblk_t iblock, unsigned int maxblocks, |
925 | struct buffer_head *bh_result, | 925 | struct buffer_head *bh_result, |
926 | int flags) | 926 | int flags) |
927 | { | 927 | { |
928 | int err = -EIO; | 928 | int err = -EIO; |
929 | ext4_lblk_t offsets[4]; | 929 | ext4_lblk_t offsets[4]; |
@@ -939,7 +939,7 @@ static int ext4_ind_get_blocks(handle_t *handle, struct inode *inode, | |||
939 | J_ASSERT(!(EXT4_I(inode)->i_flags & EXT4_EXTENTS_FL)); | 939 | J_ASSERT(!(EXT4_I(inode)->i_flags & EXT4_EXTENTS_FL)); |
940 | J_ASSERT(handle != NULL || (flags & EXT4_GET_BLOCKS_CREATE) == 0); | 940 | J_ASSERT(handle != NULL || (flags & EXT4_GET_BLOCKS_CREATE) == 0); |
941 | depth = ext4_block_to_path(inode, iblock, offsets, | 941 | depth = ext4_block_to_path(inode, iblock, offsets, |
942 | &blocks_to_boundary); | 942 | &blocks_to_boundary); |
943 | 943 | ||
944 | if (depth == 0) | 944 | if (depth == 0) |
945 | goto out; | 945 | goto out; |
@@ -987,8 +987,8 @@ static int ext4_ind_get_blocks(handle_t *handle, struct inode *inode, | |||
987 | * Block out ext4_truncate while we alter the tree | 987 | * Block out ext4_truncate while we alter the tree |
988 | */ | 988 | */ |
989 | err = ext4_alloc_branch(handle, inode, iblock, indirect_blks, | 989 | err = ext4_alloc_branch(handle, inode, iblock, indirect_blks, |
990 | &count, goal, | 990 | &count, goal, |
991 | offsets + (partial - chain), partial); | 991 | offsets + (partial - chain), partial); |
992 | 992 | ||
993 | /* | 993 | /* |
994 | * The ext4_splice_branch call will free and forget any buffers | 994 | * The ext4_splice_branch call will free and forget any buffers |
@@ -999,8 +999,8 @@ static int ext4_ind_get_blocks(handle_t *handle, struct inode *inode, | |||
999 | */ | 999 | */ |
1000 | if (!err) | 1000 | if (!err) |
1001 | err = ext4_splice_branch(handle, inode, iblock, | 1001 | err = ext4_splice_branch(handle, inode, iblock, |
1002 | partial, indirect_blks, count); | 1002 | partial, indirect_blks, count); |
1003 | else | 1003 | else |
1004 | goto cleanup; | 1004 | goto cleanup; |
1005 | 1005 | ||
1006 | set_buffer_new(bh_result); | 1006 | set_buffer_new(bh_result); |
@@ -1172,7 +1172,7 @@ int ext4_get_blocks(handle_t *handle, struct inode *inode, sector_t block, | |||
1172 | up_read((&EXT4_I(inode)->i_data_sem)); | 1172 | up_read((&EXT4_I(inode)->i_data_sem)); |
1173 | 1173 | ||
1174 | if (retval > 0 && buffer_mapped(bh)) { | 1174 | if (retval > 0 && buffer_mapped(bh)) { |
1175 | int ret = check_block_validity(inode, block, | 1175 | int ret = check_block_validity(inode, block, |
1176 | bh->b_blocknr, retval); | 1176 | bh->b_blocknr, retval); |
1177 | if (ret != 0) | 1177 | if (ret != 0) |
1178 | return ret; | 1178 | return ret; |
@@ -1254,7 +1254,7 @@ int ext4_get_blocks(handle_t *handle, struct inode *inode, sector_t block, | |||
1254 | 1254 | ||
1255 | up_write((&EXT4_I(inode)->i_data_sem)); | 1255 | up_write((&EXT4_I(inode)->i_data_sem)); |
1256 | if (retval > 0 && buffer_mapped(bh)) { | 1256 | if (retval > 0 && buffer_mapped(bh)) { |
1257 | int ret = check_block_validity(inode, block, | 1257 | int ret = check_block_validity(inode, block, |
1258 | bh->b_blocknr, retval); | 1258 | bh->b_blocknr, retval); |
1259 | if (ret != 0) | 1259 | if (ret != 0) |
1260 | return ret; | 1260 | return ret; |
@@ -1405,8 +1405,7 @@ static int walk_page_buffers(handle_t *handle, | |||
1405 | 1405 | ||
1406 | for (bh = head, block_start = 0; | 1406 | for (bh = head, block_start = 0; |
1407 | ret == 0 && (bh != head || !block_start); | 1407 | ret == 0 && (bh != head || !block_start); |
1408 | block_start = block_end, bh = next) | 1408 | block_start = block_end, bh = next) { |
1409 | { | ||
1410 | next = bh->b_this_page; | 1409 | next = bh->b_this_page; |
1411 | block_end = block_start + blocksize; | 1410 | block_end = block_start + blocksize; |
1412 | if (block_end <= from || block_start >= to) { | 1411 | if (block_end <= from || block_start >= to) { |
@@ -1447,7 +1446,7 @@ static int walk_page_buffers(handle_t *handle, | |||
1447 | * write. | 1446 | * write. |
1448 | */ | 1447 | */ |
1449 | static int do_journal_get_write_access(handle_t *handle, | 1448 | static int do_journal_get_write_access(handle_t *handle, |
1450 | struct buffer_head *bh) | 1449 | struct buffer_head *bh) |
1451 | { | 1450 | { |
1452 | if (!buffer_mapped(bh) || buffer_freed(bh)) | 1451 | if (!buffer_mapped(bh) || buffer_freed(bh)) |
1453 | return 0; | 1452 | return 0; |
@@ -1455,27 +1454,24 @@ static int do_journal_get_write_access(handle_t *handle, | |||
1455 | } | 1454 | } |
1456 | 1455 | ||
1457 | static int ext4_write_begin(struct file *file, struct address_space *mapping, | 1456 | static int ext4_write_begin(struct file *file, struct address_space *mapping, |
1458 | loff_t pos, unsigned len, unsigned flags, | 1457 | loff_t pos, unsigned len, unsigned flags, |
1459 | struct page **pagep, void **fsdata) | 1458 | struct page **pagep, void **fsdata) |
1460 | { | 1459 | { |
1461 | struct inode *inode = mapping->host; | 1460 | struct inode *inode = mapping->host; |
1462 | int ret, needed_blocks; | 1461 | int ret, needed_blocks; |
1463 | handle_t *handle; | 1462 | handle_t *handle; |
1464 | int retries = 0; | 1463 | int retries = 0; |
1465 | struct page *page; | 1464 | struct page *page; |
1466 | pgoff_t index; | 1465 | pgoff_t index; |
1467 | unsigned from, to; | 1466 | unsigned from, to; |
1468 | 1467 | ||
1469 | trace_mark(ext4_write_begin, | 1468 | trace_ext4_write_begin(inode, pos, len, flags); |
1470 | "dev %s ino %lu pos %llu len %u flags %u", | ||
1471 | inode->i_sb->s_id, inode->i_ino, | ||
1472 | (unsigned long long) pos, len, flags); | ||
1473 | /* | 1469 | /* |
1474 | * Reserve one block more for addition to orphan list in case | 1470 | * Reserve one block more for addition to orphan list in case |
1475 | * we allocate blocks but write fails for some reason | 1471 | * we allocate blocks but write fails for some reason |
1476 | */ | 1472 | */ |
1477 | needed_blocks = ext4_writepage_trans_blocks(inode) + 1; | 1473 | needed_blocks = ext4_writepage_trans_blocks(inode) + 1; |
1478 | index = pos >> PAGE_CACHE_SHIFT; | 1474 | index = pos >> PAGE_CACHE_SHIFT; |
1479 | from = pos & (PAGE_CACHE_SIZE - 1); | 1475 | from = pos & (PAGE_CACHE_SIZE - 1); |
1480 | to = from + len; | 1476 | to = from + len; |
1481 | 1477 | ||
@@ -1523,7 +1519,7 @@ retry: | |||
1523 | ext4_journal_stop(handle); | 1519 | ext4_journal_stop(handle); |
1524 | if (pos + len > inode->i_size) { | 1520 | if (pos + len > inode->i_size) { |
1525 | vmtruncate(inode, inode->i_size); | 1521 | vmtruncate(inode, inode->i_size); |
1526 | /* | 1522 | /* |
1527 | * If vmtruncate failed early the inode might | 1523 | * If vmtruncate failed early the inode might |
1528 | * still be on the orphan list; we need to | 1524 | * still be on the orphan list; we need to |
1529 | * make sure the inode is removed from the | 1525 | * make sure the inode is removed from the |
@@ -1550,9 +1546,9 @@ static int write_end_fn(handle_t *handle, struct buffer_head *bh) | |||
1550 | } | 1546 | } |
1551 | 1547 | ||
1552 | static int ext4_generic_write_end(struct file *file, | 1548 | static int ext4_generic_write_end(struct file *file, |
1553 | struct address_space *mapping, | 1549 | struct address_space *mapping, |
1554 | loff_t pos, unsigned len, unsigned copied, | 1550 | loff_t pos, unsigned len, unsigned copied, |
1555 | struct page *page, void *fsdata) | 1551 | struct page *page, void *fsdata) |
1556 | { | 1552 | { |
1557 | int i_size_changed = 0; | 1553 | int i_size_changed = 0; |
1558 | struct inode *inode = mapping->host; | 1554 | struct inode *inode = mapping->host; |
@@ -1603,18 +1599,15 @@ static int ext4_generic_write_end(struct file *file, | |||
1603 | * buffers are managed internally. | 1599 | * buffers are managed internally. |
1604 | */ | 1600 | */ |
1605 | static int ext4_ordered_write_end(struct file *file, | 1601 | static int ext4_ordered_write_end(struct file *file, |
1606 | struct address_space *mapping, | 1602 | struct address_space *mapping, |
1607 | loff_t pos, unsigned len, unsigned copied, | 1603 | loff_t pos, unsigned len, unsigned copied, |
1608 | struct page *page, void *fsdata) | 1604 | struct page *page, void *fsdata) |
1609 | { | 1605 | { |
1610 | handle_t *handle = ext4_journal_current_handle(); | 1606 | handle_t *handle = ext4_journal_current_handle(); |
1611 | struct inode *inode = mapping->host; | 1607 | struct inode *inode = mapping->host; |
1612 | int ret = 0, ret2; | 1608 | int ret = 0, ret2; |
1613 | 1609 | ||
1614 | trace_mark(ext4_ordered_write_end, | 1610 | trace_ext4_ordered_write_end(inode, pos, len, copied); |
1615 | "dev %s ino %lu pos %llu len %u copied %u", | ||
1616 | inode->i_sb->s_id, inode->i_ino, | ||
1617 | (unsigned long long) pos, len, copied); | ||
1618 | ret = ext4_jbd2_file_inode(handle, inode); | 1611 | ret = ext4_jbd2_file_inode(handle, inode); |
1619 | 1612 | ||
1620 | if (ret == 0) { | 1613 | if (ret == 0) { |
@@ -1636,7 +1629,7 @@ static int ext4_ordered_write_end(struct file *file, | |||
1636 | 1629 | ||
1637 | if (pos + len > inode->i_size) { | 1630 | if (pos + len > inode->i_size) { |
1638 | vmtruncate(inode, inode->i_size); | 1631 | vmtruncate(inode, inode->i_size); |
1639 | /* | 1632 | /* |
1640 | * If vmtruncate failed early the inode might still be | 1633 | * If vmtruncate failed early the inode might still be |
1641 | * on the orphan list; we need to make sure the inode | 1634 | * on the orphan list; we need to make sure the inode |
1642 | * is removed from the orphan list in that case. | 1635 | * is removed from the orphan list in that case. |
@@ -1650,18 +1643,15 @@ static int ext4_ordered_write_end(struct file *file, | |||
1650 | } | 1643 | } |
1651 | 1644 | ||
1652 | static int ext4_writeback_write_end(struct file *file, | 1645 | static int ext4_writeback_write_end(struct file *file, |
1653 | struct address_space *mapping, | 1646 | struct address_space *mapping, |
1654 | loff_t pos, unsigned len, unsigned copied, | 1647 | loff_t pos, unsigned len, unsigned copied, |
1655 | struct page *page, void *fsdata) | 1648 | struct page *page, void *fsdata) |
1656 | { | 1649 | { |
1657 | handle_t *handle = ext4_journal_current_handle(); | 1650 | handle_t *handle = ext4_journal_current_handle(); |
1658 | struct inode *inode = mapping->host; | 1651 | struct inode *inode = mapping->host; |
1659 | int ret = 0, ret2; | 1652 | int ret = 0, ret2; |
1660 | 1653 | ||
1661 | trace_mark(ext4_writeback_write_end, | 1654 | trace_ext4_writeback_write_end(inode, pos, len, copied); |
1662 | "dev %s ino %lu pos %llu len %u copied %u", | ||
1663 | inode->i_sb->s_id, inode->i_ino, | ||
1664 | (unsigned long long) pos, len, copied); | ||
1665 | ret2 = ext4_generic_write_end(file, mapping, pos, len, copied, | 1655 | ret2 = ext4_generic_write_end(file, mapping, pos, len, copied, |
1666 | page, fsdata); | 1656 | page, fsdata); |
1667 | copied = ret2; | 1657 | copied = ret2; |
@@ -1681,7 +1671,7 @@ static int ext4_writeback_write_end(struct file *file, | |||
1681 | 1671 | ||
1682 | if (pos + len > inode->i_size) { | 1672 | if (pos + len > inode->i_size) { |
1683 | vmtruncate(inode, inode->i_size); | 1673 | vmtruncate(inode, inode->i_size); |
1684 | /* | 1674 | /* |
1685 | * If vmtruncate failed early the inode might still be | 1675 | * If vmtruncate failed early the inode might still be |
1686 | * on the orphan list; we need to make sure the inode | 1676 | * on the orphan list; we need to make sure the inode |
1687 | * is removed from the orphan list in that case. | 1677 | * is removed from the orphan list in that case. |
@@ -1694,9 +1684,9 @@ static int ext4_writeback_write_end(struct file *file, | |||
1694 | } | 1684 | } |
1695 | 1685 | ||
1696 | static int ext4_journalled_write_end(struct file *file, | 1686 | static int ext4_journalled_write_end(struct file *file, |
1697 | struct address_space *mapping, | 1687 | struct address_space *mapping, |
1698 | loff_t pos, unsigned len, unsigned copied, | 1688 | loff_t pos, unsigned len, unsigned copied, |
1699 | struct page *page, void *fsdata) | 1689 | struct page *page, void *fsdata) |
1700 | { | 1690 | { |
1701 | handle_t *handle = ext4_journal_current_handle(); | 1691 | handle_t *handle = ext4_journal_current_handle(); |
1702 | struct inode *inode = mapping->host; | 1692 | struct inode *inode = mapping->host; |
@@ -1705,10 +1695,7 @@ static int ext4_journalled_write_end(struct file *file, | |||
1705 | unsigned from, to; | 1695 | unsigned from, to; |
1706 | loff_t new_i_size; | 1696 | loff_t new_i_size; |
1707 | 1697 | ||
1708 | trace_mark(ext4_journalled_write_end, | 1698 | trace_ext4_journalled_write_end(inode, pos, len, copied); |
1709 | "dev %s ino %lu pos %llu len %u copied %u", | ||
1710 | inode->i_sb->s_id, inode->i_ino, | ||
1711 | (unsigned long long) pos, len, copied); | ||
1712 | from = pos & (PAGE_CACHE_SIZE - 1); | 1699 | from = pos & (PAGE_CACHE_SIZE - 1); |
1713 | to = from + len; | 1700 | to = from + len; |
1714 | 1701 | ||
@@ -1747,7 +1734,7 @@ static int ext4_journalled_write_end(struct file *file, | |||
1747 | ret = ret2; | 1734 | ret = ret2; |
1748 | if (pos + len > inode->i_size) { | 1735 | if (pos + len > inode->i_size) { |
1749 | vmtruncate(inode, inode->i_size); | 1736 | vmtruncate(inode, inode->i_size); |
1750 | /* | 1737 | /* |
1751 | * If vmtruncate failed early the inode might still be | 1738 | * If vmtruncate failed early the inode might still be |
1752 | * on the orphan list; we need to make sure the inode | 1739 | * on the orphan list; we need to make sure the inode |
1753 | * is removed from the orphan list in that case. | 1740 | * is removed from the orphan list in that case. |
@@ -1854,7 +1841,7 @@ static void ext4_da_release_space(struct inode *inode, int to_free) | |||
1854 | } | 1841 | } |
1855 | 1842 | ||
1856 | static void ext4_da_page_release_reservation(struct page *page, | 1843 | static void ext4_da_page_release_reservation(struct page *page, |
1857 | unsigned long offset) | 1844 | unsigned long offset) |
1858 | { | 1845 | { |
1859 | int to_release = 0; | 1846 | int to_release = 0; |
1860 | struct buffer_head *head, *bh; | 1847 | struct buffer_head *head, *bh; |
@@ -2554,9 +2541,7 @@ static int ext4_da_writepage(struct page *page, | |||
2554 | struct buffer_head *page_bufs; | 2541 | struct buffer_head *page_bufs; |
2555 | struct inode *inode = page->mapping->host; | 2542 | struct inode *inode = page->mapping->host; |
2556 | 2543 | ||
2557 | trace_mark(ext4_da_writepage, | 2544 | trace_ext4_da_writepage(inode, page); |
2558 | "dev %s ino %lu page_index %lu", | ||
2559 | inode->i_sb->s_id, inode->i_ino, page->index); | ||
2560 | size = i_size_read(inode); | 2545 | size = i_size_read(inode); |
2561 | if (page->index == size >> PAGE_CACHE_SHIFT) | 2546 | if (page->index == size >> PAGE_CACHE_SHIFT) |
2562 | len = size & ~PAGE_CACHE_MASK; | 2547 | len = size & ~PAGE_CACHE_MASK; |
@@ -2667,19 +2652,7 @@ static int ext4_da_writepages(struct address_space *mapping, | |||
2667 | int needed_blocks, ret = 0, nr_to_writebump = 0; | 2652 | int needed_blocks, ret = 0, nr_to_writebump = 0; |
2668 | struct ext4_sb_info *sbi = EXT4_SB(mapping->host->i_sb); | 2653 | struct ext4_sb_info *sbi = EXT4_SB(mapping->host->i_sb); |
2669 | 2654 | ||
2670 | trace_mark(ext4_da_writepages, | 2655 | trace_ext4_da_writepages(inode, wbc); |
2671 | "dev %s ino %lu nr_t_write %ld " | ||
2672 | "pages_skipped %ld range_start %llu " | ||
2673 | "range_end %llu nonblocking %d " | ||
2674 | "for_kupdate %d for_reclaim %d " | ||
2675 | "for_writepages %d range_cyclic %d", | ||
2676 | inode->i_sb->s_id, inode->i_ino, | ||
2677 | wbc->nr_to_write, wbc->pages_skipped, | ||
2678 | (unsigned long long) wbc->range_start, | ||
2679 | (unsigned long long) wbc->range_end, | ||
2680 | wbc->nonblocking, wbc->for_kupdate, | ||
2681 | wbc->for_reclaim, wbc->for_writepages, | ||
2682 | wbc->range_cyclic); | ||
2683 | 2656 | ||
2684 | /* | 2657 | /* |
2685 | * No pages to write? This is mainly a kludge to avoid starting | 2658 | * No pages to write? This is mainly a kludge to avoid starting |
@@ -2693,13 +2666,13 @@ static int ext4_da_writepages(struct address_space *mapping, | |||
2693 | * If the filesystem has aborted, it is read-only, so return | 2666 | * If the filesystem has aborted, it is read-only, so return |
2694 | * right away instead of dumping stack traces later on that | 2667 | * right away instead of dumping stack traces later on that |
2695 | * will obscure the real source of the problem. We test | 2668 | * will obscure the real source of the problem. We test |
2696 | * EXT4_MOUNT_ABORT instead of sb->s_flag's MS_RDONLY because | 2669 | * EXT4_MF_FS_ABORTED instead of sb->s_flag's MS_RDONLY because |
2697 | * the latter could be true if the filesystem is mounted | 2670 | * the latter could be true if the filesystem is mounted |
2698 | * read-only, and in that case, ext4_da_writepages should | 2671 | * read-only, and in that case, ext4_da_writepages should |
2699 | * *never* be called, so if that ever happens, we would want | 2672 | * *never* be called, so if that ever happens, we would want |
2700 | * the stack trace. | 2673 | * the stack trace. |
2701 | */ | 2674 | */ |
2702 | if (unlikely(sbi->s_mount_opt & EXT4_MOUNT_ABORT)) | 2675 | if (unlikely(sbi->s_mount_flags & EXT4_MF_FS_ABORTED)) |
2703 | return -EROFS; | 2676 | return -EROFS; |
2704 | 2677 | ||
2705 | /* | 2678 | /* |
@@ -2845,14 +2818,7 @@ out_writepages: | |||
2845 | if (!no_nrwrite_index_update) | 2818 | if (!no_nrwrite_index_update) |
2846 | wbc->no_nrwrite_index_update = 0; | 2819 | wbc->no_nrwrite_index_update = 0; |
2847 | wbc->nr_to_write -= nr_to_writebump; | 2820 | wbc->nr_to_write -= nr_to_writebump; |
2848 | trace_mark(ext4_da_writepage_result, | 2821 | trace_ext4_da_writepages_result(inode, wbc, ret, pages_written); |
2849 | "dev %s ino %lu ret %d pages_written %d " | ||
2850 | "pages_skipped %ld congestion %d " | ||
2851 | "more_io %d no_nrwrite_index_update %d", | ||
2852 | inode->i_sb->s_id, inode->i_ino, ret, | ||
2853 | pages_written, wbc->pages_skipped, | ||
2854 | wbc->encountered_congestion, wbc->more_io, | ||
2855 | wbc->no_nrwrite_index_update); | ||
2856 | return ret; | 2822 | return ret; |
2857 | } | 2823 | } |
2858 | 2824 | ||
@@ -2884,8 +2850,8 @@ static int ext4_nonda_switch(struct super_block *sb) | |||
2884 | } | 2850 | } |
2885 | 2851 | ||
2886 | static int ext4_da_write_begin(struct file *file, struct address_space *mapping, | 2852 | static int ext4_da_write_begin(struct file *file, struct address_space *mapping, |
2887 | loff_t pos, unsigned len, unsigned flags, | 2853 | loff_t pos, unsigned len, unsigned flags, |
2888 | struct page **pagep, void **fsdata) | 2854 | struct page **pagep, void **fsdata) |
2889 | { | 2855 | { |
2890 | int ret, retries = 0; | 2856 | int ret, retries = 0; |
2891 | struct page *page; | 2857 | struct page *page; |
@@ -2904,11 +2870,7 @@ static int ext4_da_write_begin(struct file *file, struct address_space *mapping, | |||
2904 | len, flags, pagep, fsdata); | 2870 | len, flags, pagep, fsdata); |
2905 | } | 2871 | } |
2906 | *fsdata = (void *)0; | 2872 | *fsdata = (void *)0; |
2907 | 2873 | trace_ext4_da_write_begin(inode, pos, len, flags); | |
2908 | trace_mark(ext4_da_write_begin, | ||
2909 | "dev %s ino %lu pos %llu len %u flags %u", | ||
2910 | inode->i_sb->s_id, inode->i_ino, | ||
2911 | (unsigned long long) pos, len, flags); | ||
2912 | retry: | 2874 | retry: |
2913 | /* | 2875 | /* |
2914 | * With delayed allocation, we don't log the i_disksize update | 2876 | * With delayed allocation, we don't log the i_disksize update |
@@ -2959,7 +2921,7 @@ out: | |||
2959 | * when write to the end of file but not require block allocation | 2921 | * when write to the end of file but not require block allocation |
2960 | */ | 2922 | */ |
2961 | static int ext4_da_should_update_i_disksize(struct page *page, | 2923 | static int ext4_da_should_update_i_disksize(struct page *page, |
2962 | unsigned long offset) | 2924 | unsigned long offset) |
2963 | { | 2925 | { |
2964 | struct buffer_head *bh; | 2926 | struct buffer_head *bh; |
2965 | struct inode *inode = page->mapping->host; | 2927 | struct inode *inode = page->mapping->host; |
@@ -2978,9 +2940,9 @@ static int ext4_da_should_update_i_disksize(struct page *page, | |||
2978 | } | 2940 | } |
2979 | 2941 | ||
2980 | static int ext4_da_write_end(struct file *file, | 2942 | static int ext4_da_write_end(struct file *file, |
2981 | struct address_space *mapping, | 2943 | struct address_space *mapping, |
2982 | loff_t pos, unsigned len, unsigned copied, | 2944 | loff_t pos, unsigned len, unsigned copied, |
2983 | struct page *page, void *fsdata) | 2945 | struct page *page, void *fsdata) |
2984 | { | 2946 | { |
2985 | struct inode *inode = mapping->host; | 2947 | struct inode *inode = mapping->host; |
2986 | int ret = 0, ret2; | 2948 | int ret = 0, ret2; |
@@ -3001,10 +2963,7 @@ static int ext4_da_write_end(struct file *file, | |||
3001 | } | 2963 | } |
3002 | } | 2964 | } |
3003 | 2965 | ||
3004 | trace_mark(ext4_da_write_end, | 2966 | trace_ext4_da_write_end(inode, pos, len, copied); |
3005 | "dev %s ino %lu pos %llu len %u copied %u", | ||
3006 | inode->i_sb->s_id, inode->i_ino, | ||
3007 | (unsigned long long) pos, len, copied); | ||
3008 | start = pos & (PAGE_CACHE_SIZE - 1); | 2967 | start = pos & (PAGE_CACHE_SIZE - 1); |
3009 | end = start + copied - 1; | 2968 | end = start + copied - 1; |
3010 | 2969 | ||
@@ -3081,7 +3040,7 @@ int ext4_alloc_da_blocks(struct inode *inode) | |||
3081 | * not strictly speaking necessary (and for users of | 3040 | * not strictly speaking necessary (and for users of |
3082 | * laptop_mode, not even desirable). However, to do otherwise | 3041 | * laptop_mode, not even desirable). However, to do otherwise |
3083 | * would require replicating code paths in: | 3042 | * would require replicating code paths in: |
3084 | * | 3043 | * |
3085 | * ext4_da_writepages() -> | 3044 | * ext4_da_writepages() -> |
3086 | * write_cache_pages() ---> (via passed in callback function) | 3045 | * write_cache_pages() ---> (via passed in callback function) |
3087 | * __mpage_da_writepage() --> | 3046 | * __mpage_da_writepage() --> |
@@ -3101,7 +3060,7 @@ int ext4_alloc_da_blocks(struct inode *inode) | |||
3101 | * write out the pages, but rather only collect contiguous | 3060 | * write out the pages, but rather only collect contiguous |
3102 | * logical block extents, call the multi-block allocator, and | 3061 | * logical block extents, call the multi-block allocator, and |
3103 | * then update the buffer heads with the block allocations. | 3062 | * then update the buffer heads with the block allocations. |
3104 | * | 3063 | * |
3105 | * For now, though, we'll cheat by calling filemap_flush(), | 3064 | * For now, though, we'll cheat by calling filemap_flush(), |
3106 | * which will map the blocks, and start the I/O, but not | 3065 | * which will map the blocks, and start the I/O, but not |
3107 | * actually wait for the I/O to complete. | 3066 | * actually wait for the I/O to complete. |
@@ -3237,7 +3196,7 @@ static int bput_one(handle_t *handle, struct buffer_head *bh) | |||
3237 | * | 3196 | * |
3238 | */ | 3197 | */ |
3239 | static int __ext4_normal_writepage(struct page *page, | 3198 | static int __ext4_normal_writepage(struct page *page, |
3240 | struct writeback_control *wbc) | 3199 | struct writeback_control *wbc) |
3241 | { | 3200 | { |
3242 | struct inode *inode = page->mapping->host; | 3201 | struct inode *inode = page->mapping->host; |
3243 | 3202 | ||
@@ -3249,15 +3208,13 @@ static int __ext4_normal_writepage(struct page *page, | |||
3249 | } | 3208 | } |
3250 | 3209 | ||
3251 | static int ext4_normal_writepage(struct page *page, | 3210 | static int ext4_normal_writepage(struct page *page, |
3252 | struct writeback_control *wbc) | 3211 | struct writeback_control *wbc) |
3253 | { | 3212 | { |
3254 | struct inode *inode = page->mapping->host; | 3213 | struct inode *inode = page->mapping->host; |
3255 | loff_t size = i_size_read(inode); | 3214 | loff_t size = i_size_read(inode); |
3256 | loff_t len; | 3215 | loff_t len; |
3257 | 3216 | ||
3258 | trace_mark(ext4_normal_writepage, | 3217 | trace_ext4_normal_writepage(inode, page); |
3259 | "dev %s ino %lu page_index %lu", | ||
3260 | inode->i_sb->s_id, inode->i_ino, page->index); | ||
3261 | J_ASSERT(PageLocked(page)); | 3218 | J_ASSERT(PageLocked(page)); |
3262 | if (page->index == size >> PAGE_CACHE_SHIFT) | 3219 | if (page->index == size >> PAGE_CACHE_SHIFT) |
3263 | len = size & ~PAGE_CACHE_MASK; | 3220 | len = size & ~PAGE_CACHE_MASK; |
@@ -3287,7 +3244,7 @@ static int ext4_normal_writepage(struct page *page, | |||
3287 | } | 3244 | } |
3288 | 3245 | ||
3289 | static int __ext4_journalled_writepage(struct page *page, | 3246 | static int __ext4_journalled_writepage(struct page *page, |
3290 | struct writeback_control *wbc) | 3247 | struct writeback_control *wbc) |
3291 | { | 3248 | { |
3292 | struct address_space *mapping = page->mapping; | 3249 | struct address_space *mapping = page->mapping; |
3293 | struct inode *inode = mapping->host; | 3250 | struct inode *inode = mapping->host; |
@@ -3337,15 +3294,13 @@ out: | |||
3337 | } | 3294 | } |
3338 | 3295 | ||
3339 | static int ext4_journalled_writepage(struct page *page, | 3296 | static int ext4_journalled_writepage(struct page *page, |
3340 | struct writeback_control *wbc) | 3297 | struct writeback_control *wbc) |
3341 | { | 3298 | { |
3342 | struct inode *inode = page->mapping->host; | 3299 | struct inode *inode = page->mapping->host; |
3343 | loff_t size = i_size_read(inode); | 3300 | loff_t size = i_size_read(inode); |
3344 | loff_t len; | 3301 | loff_t len; |
3345 | 3302 | ||
3346 | trace_mark(ext4_journalled_writepage, | 3303 | trace_ext4_journalled_writepage(inode, page); |
3347 | "dev %s ino %lu page_index %lu", | ||
3348 | inode->i_sb->s_id, inode->i_ino, page->index); | ||
3349 | J_ASSERT(PageLocked(page)); | 3304 | J_ASSERT(PageLocked(page)); |
3350 | if (page->index == size >> PAGE_CACHE_SHIFT) | 3305 | if (page->index == size >> PAGE_CACHE_SHIFT) |
3351 | len = size & ~PAGE_CACHE_MASK; | 3306 | len = size & ~PAGE_CACHE_MASK; |
@@ -3442,8 +3397,8 @@ static int ext4_releasepage(struct page *page, gfp_t wait) | |||
3442 | * VFS code falls back into buffered path in that case so we are safe. | 3397 | * VFS code falls back into buffered path in that case so we are safe. |
3443 | */ | 3398 | */ |
3444 | static ssize_t ext4_direct_IO(int rw, struct kiocb *iocb, | 3399 | static ssize_t ext4_direct_IO(int rw, struct kiocb *iocb, |
3445 | const struct iovec *iov, loff_t offset, | 3400 | const struct iovec *iov, loff_t offset, |
3446 | unsigned long nr_segs) | 3401 | unsigned long nr_segs) |
3447 | { | 3402 | { |
3448 | struct file *file = iocb->ki_filp; | 3403 | struct file *file = iocb->ki_filp; |
3449 | struct inode *inode = file->f_mapping->host; | 3404 | struct inode *inode = file->f_mapping->host; |
@@ -3763,7 +3718,8 @@ static inline int all_zeroes(__le32 *p, __le32 *q) | |||
3763 | * (no partially truncated stuff there). */ | 3718 | * (no partially truncated stuff there). */ |
3764 | 3719 | ||
3765 | static Indirect *ext4_find_shared(struct inode *inode, int depth, | 3720 | static Indirect *ext4_find_shared(struct inode *inode, int depth, |
3766 | ext4_lblk_t offsets[4], Indirect chain[4], __le32 *top) | 3721 | ext4_lblk_t offsets[4], Indirect chain[4], |
3722 | __le32 *top) | ||
3767 | { | 3723 | { |
3768 | Indirect *partial, *p; | 3724 | Indirect *partial, *p; |
3769 | int k, err; | 3725 | int k, err; |
@@ -3819,8 +3775,10 @@ no_top: | |||
3819 | * than `count' because there can be holes in there. | 3775 | * than `count' because there can be holes in there. |
3820 | */ | 3776 | */ |
3821 | static void ext4_clear_blocks(handle_t *handle, struct inode *inode, | 3777 | static void ext4_clear_blocks(handle_t *handle, struct inode *inode, |
3822 | struct buffer_head *bh, ext4_fsblk_t block_to_free, | 3778 | struct buffer_head *bh, |
3823 | unsigned long count, __le32 *first, __le32 *last) | 3779 | ext4_fsblk_t block_to_free, |
3780 | unsigned long count, __le32 *first, | ||
3781 | __le32 *last) | ||
3824 | { | 3782 | { |
3825 | __le32 *p; | 3783 | __le32 *p; |
3826 | if (try_to_extend_transaction(handle, inode)) { | 3784 | if (try_to_extend_transaction(handle, inode)) { |
@@ -3837,10 +3795,11 @@ static void ext4_clear_blocks(handle_t *handle, struct inode *inode, | |||
3837 | } | 3795 | } |
3838 | 3796 | ||
3839 | /* | 3797 | /* |
3840 | * Any buffers which are on the journal will be in memory. We find | 3798 | * Any buffers which are on the journal will be in memory. We |
3841 | * them on the hash table so jbd2_journal_revoke() will run jbd2_journal_forget() | 3799 | * find them on the hash table so jbd2_journal_revoke() will |
3842 | * on them. We've already detached each block from the file, so | 3800 | * run jbd2_journal_forget() on them. We've already detached |
3843 | * bforget() in jbd2_journal_forget() should be safe. | 3801 | * each block from the file, so bforget() in |
3802 | * jbd2_journal_forget() should be safe. | ||
3844 | * | 3803 | * |
3845 | * AKPM: turn on bforget in jbd2_journal_forget()!!! | 3804 | * AKPM: turn on bforget in jbd2_journal_forget()!!! |
3846 | */ | 3805 | */ |
@@ -4212,7 +4171,7 @@ void ext4_truncate(struct inode *inode) | |||
4212 | (__le32*)partial->bh->b_data+addr_per_block, | 4171 | (__le32*)partial->bh->b_data+addr_per_block, |
4213 | (chain+n-1) - partial); | 4172 | (chain+n-1) - partial); |
4214 | BUFFER_TRACE(partial->bh, "call brelse"); | 4173 | BUFFER_TRACE(partial->bh, "call brelse"); |
4215 | brelse (partial->bh); | 4174 | brelse(partial->bh); |
4216 | partial--; | 4175 | partial--; |
4217 | } | 4176 | } |
4218 | do_indirects: | 4177 | do_indirects: |
@@ -4453,8 +4412,9 @@ void ext4_get_inode_flags(struct ext4_inode_info *ei) | |||
4453 | if (flags & S_DIRSYNC) | 4412 | if (flags & S_DIRSYNC) |
4454 | ei->i_flags |= EXT4_DIRSYNC_FL; | 4413 | ei->i_flags |= EXT4_DIRSYNC_FL; |
4455 | } | 4414 | } |
4415 | |||
4456 | static blkcnt_t ext4_inode_blocks(struct ext4_inode *raw_inode, | 4416 | static blkcnt_t ext4_inode_blocks(struct ext4_inode *raw_inode, |
4457 | struct ext4_inode_info *ei) | 4417 | struct ext4_inode_info *ei) |
4458 | { | 4418 | { |
4459 | blkcnt_t i_blocks ; | 4419 | blkcnt_t i_blocks ; |
4460 | struct inode *inode = &(ei->vfs_inode); | 4420 | struct inode *inode = &(ei->vfs_inode); |
@@ -4569,7 +4529,7 @@ struct inode *ext4_iget(struct super_block *sb, unsigned long ino) | |||
4569 | EXT4_GOOD_OLD_INODE_SIZE + | 4529 | EXT4_GOOD_OLD_INODE_SIZE + |
4570 | ei->i_extra_isize; | 4530 | ei->i_extra_isize; |
4571 | if (*magic == cpu_to_le32(EXT4_XATTR_MAGIC)) | 4531 | if (*magic == cpu_to_le32(EXT4_XATTR_MAGIC)) |
4572 | ei->i_state |= EXT4_STATE_XATTR; | 4532 | ei->i_state |= EXT4_STATE_XATTR; |
4573 | } | 4533 | } |
4574 | } else | 4534 | } else |
4575 | ei->i_extra_isize = 0; | 4535 | ei->i_extra_isize = 0; |
@@ -4588,7 +4548,7 @@ struct inode *ext4_iget(struct super_block *sb, unsigned long ino) | |||
4588 | 4548 | ||
4589 | ret = 0; | 4549 | ret = 0; |
4590 | if (ei->i_file_acl && | 4550 | if (ei->i_file_acl && |
4591 | ((ei->i_file_acl < | 4551 | ((ei->i_file_acl < |
4592 | (le32_to_cpu(EXT4_SB(sb)->s_es->s_first_data_block) + | 4552 | (le32_to_cpu(EXT4_SB(sb)->s_es->s_first_data_block) + |
4593 | EXT4_SB(sb)->s_gdb_count)) || | 4553 | EXT4_SB(sb)->s_gdb_count)) || |
4594 | (ei->i_file_acl >= ext4_blocks_count(EXT4_SB(sb)->s_es)))) { | 4554 | (ei->i_file_acl >= ext4_blocks_count(EXT4_SB(sb)->s_es)))) { |
@@ -4603,15 +4563,15 @@ struct inode *ext4_iget(struct super_block *sb, unsigned long ino) | |||
4603 | !ext4_inode_is_fast_symlink(inode))) | 4563 | !ext4_inode_is_fast_symlink(inode))) |
4604 | /* Validate extent which is part of inode */ | 4564 | /* Validate extent which is part of inode */ |
4605 | ret = ext4_ext_check_inode(inode); | 4565 | ret = ext4_ext_check_inode(inode); |
4606 | } else if (S_ISREG(inode->i_mode) || S_ISDIR(inode->i_mode) || | 4566 | } else if (S_ISREG(inode->i_mode) || S_ISDIR(inode->i_mode) || |
4607 | (S_ISLNK(inode->i_mode) && | 4567 | (S_ISLNK(inode->i_mode) && |
4608 | !ext4_inode_is_fast_symlink(inode))) { | 4568 | !ext4_inode_is_fast_symlink(inode))) { |
4609 | /* Validate block references which are part of inode */ | 4569 | /* Validate block references which are part of inode */ |
4610 | ret = ext4_check_inode_blockref(inode); | 4570 | ret = ext4_check_inode_blockref(inode); |
4611 | } | 4571 | } |
4612 | if (ret) { | 4572 | if (ret) { |
4613 | brelse(bh); | 4573 | brelse(bh); |
4614 | goto bad_inode; | 4574 | goto bad_inode; |
4615 | } | 4575 | } |
4616 | 4576 | ||
4617 | if (S_ISREG(inode->i_mode)) { | 4577 | if (S_ISREG(inode->i_mode)) { |
@@ -4642,7 +4602,7 @@ struct inode *ext4_iget(struct super_block *sb, unsigned long ino) | |||
4642 | } else { | 4602 | } else { |
4643 | brelse(bh); | 4603 | brelse(bh); |
4644 | ret = -EIO; | 4604 | ret = -EIO; |
4645 | ext4_error(inode->i_sb, __func__, | 4605 | ext4_error(inode->i_sb, __func__, |
4646 | "bogus i_mode (%o) for inode=%lu", | 4606 | "bogus i_mode (%o) for inode=%lu", |
4647 | inode->i_mode, inode->i_ino); | 4607 | inode->i_mode, inode->i_ino); |
4648 | goto bad_inode; | 4608 | goto bad_inode; |
@@ -4795,8 +4755,9 @@ static int ext4_do_update_inode(handle_t *handle, | |||
4795 | cpu_to_le32(new_encode_dev(inode->i_rdev)); | 4755 | cpu_to_le32(new_encode_dev(inode->i_rdev)); |
4796 | raw_inode->i_block[2] = 0; | 4756 | raw_inode->i_block[2] = 0; |
4797 | } | 4757 | } |
4798 | } else for (block = 0; block < EXT4_N_BLOCKS; block++) | 4758 | } else |
4799 | raw_inode->i_block[block] = ei->i_data[block]; | 4759 | for (block = 0; block < EXT4_N_BLOCKS; block++) |
4760 | raw_inode->i_block[block] = ei->i_data[block]; | ||
4800 | 4761 | ||
4801 | raw_inode->i_disk_version = cpu_to_le32(inode->i_version); | 4762 | raw_inode->i_disk_version = cpu_to_le32(inode->i_version); |
4802 | if (ei->i_extra_isize) { | 4763 | if (ei->i_extra_isize) { |
@@ -5150,7 +5111,7 @@ int ext4_chunk_trans_blocks(struct inode *inode, int nrblocks) | |||
5150 | * Give this, we know that the caller already has write access to iloc->bh. | 5111 | * Give this, we know that the caller already has write access to iloc->bh. |
5151 | */ | 5112 | */ |
5152 | int ext4_mark_iloc_dirty(handle_t *handle, | 5113 | int ext4_mark_iloc_dirty(handle_t *handle, |
5153 | struct inode *inode, struct ext4_iloc *iloc) | 5114 | struct inode *inode, struct ext4_iloc *iloc) |
5154 | { | 5115 | { |
5155 | int err = 0; | 5116 | int err = 0; |
5156 | 5117 | ||
diff --git a/fs/ext4/ioctl.c b/fs/ext4/ioctl.c index 91e75f7a9e73..bb415408fdb6 100644 --- a/fs/ext4/ioctl.c +++ b/fs/ext4/ioctl.c | |||
@@ -14,6 +14,7 @@ | |||
14 | #include <linux/compat.h> | 14 | #include <linux/compat.h> |
15 | #include <linux/smp_lock.h> | 15 | #include <linux/smp_lock.h> |
16 | #include <linux/mount.h> | 16 | #include <linux/mount.h> |
17 | #include <linux/file.h> | ||
17 | #include <asm/uaccess.h> | 18 | #include <asm/uaccess.h> |
18 | #include "ext4_jbd2.h" | 19 | #include "ext4_jbd2.h" |
19 | #include "ext4.h" | 20 | #include "ext4.h" |
@@ -213,6 +214,41 @@ setversion_out: | |||
213 | 214 | ||
214 | return err; | 215 | return err; |
215 | } | 216 | } |
217 | |||
218 | case EXT4_IOC_MOVE_EXT: { | ||
219 | struct move_extent me; | ||
220 | struct file *donor_filp; | ||
221 | int err; | ||
222 | |||
223 | if (copy_from_user(&me, | ||
224 | (struct move_extent __user *)arg, sizeof(me))) | ||
225 | return -EFAULT; | ||
226 | |||
227 | donor_filp = fget(me.donor_fd); | ||
228 | if (!donor_filp) | ||
229 | return -EBADF; | ||
230 | |||
231 | if (!capable(CAP_DAC_OVERRIDE)) { | ||
232 | if ((current->real_cred->fsuid != inode->i_uid) || | ||
233 | !(inode->i_mode & S_IRUSR) || | ||
234 | !(donor_filp->f_dentry->d_inode->i_mode & | ||
235 | S_IRUSR)) { | ||
236 | fput(donor_filp); | ||
237 | return -EACCES; | ||
238 | } | ||
239 | } | ||
240 | |||
241 | err = ext4_move_extents(filp, donor_filp, me.orig_start, | ||
242 | me.donor_start, me.len, &me.moved_len); | ||
243 | fput(donor_filp); | ||
244 | |||
245 | if (!err) | ||
246 | if (copy_to_user((struct move_extent *)arg, | ||
247 | &me, sizeof(me))) | ||
248 | return -EFAULT; | ||
249 | return err; | ||
250 | } | ||
251 | |||
216 | case EXT4_IOC_GROUP_ADD: { | 252 | case EXT4_IOC_GROUP_ADD: { |
217 | struct ext4_new_group_data input; | 253 | struct ext4_new_group_data input; |
218 | struct super_block *sb = inode->i_sb; | 254 | struct super_block *sb = inode->i_sb; |
diff --git a/fs/ext4/mballoc.c b/fs/ext4/mballoc.c index ed8482e22c0e..519a0a686d94 100644 --- a/fs/ext4/mballoc.c +++ b/fs/ext4/mballoc.c | |||
@@ -22,6 +22,8 @@ | |||
22 | */ | 22 | */ |
23 | 23 | ||
24 | #include "mballoc.h" | 24 | #include "mballoc.h" |
25 | #include <trace/events/ext4.h> | ||
26 | |||
25 | /* | 27 | /* |
26 | * MUSTDO: | 28 | * MUSTDO: |
27 | * - test ext4_ext_search_left() and ext4_ext_search_right() | 29 | * - test ext4_ext_search_left() and ext4_ext_search_right() |
@@ -340,8 +342,6 @@ static void ext4_mb_generate_from_freelist(struct super_block *sb, void *bitmap, | |||
340 | ext4_group_t group); | 342 | ext4_group_t group); |
341 | static void release_blocks_on_commit(journal_t *journal, transaction_t *txn); | 343 | static void release_blocks_on_commit(journal_t *journal, transaction_t *txn); |
342 | 344 | ||
343 | |||
344 | |||
345 | static inline void *mb_correct_addr_and_bit(int *bit, void *addr) | 345 | static inline void *mb_correct_addr_and_bit(int *bit, void *addr) |
346 | { | 346 | { |
347 | #if BITS_PER_LONG == 64 | 347 | #if BITS_PER_LONG == 64 |
@@ -2859,9 +2859,8 @@ static void release_blocks_on_commit(journal_t *journal, transaction_t *txn) | |||
2859 | discard_block = (ext4_fsblk_t) entry->group * EXT4_BLOCKS_PER_GROUP(sb) | 2859 | discard_block = (ext4_fsblk_t) entry->group * EXT4_BLOCKS_PER_GROUP(sb) |
2860 | + entry->start_blk | 2860 | + entry->start_blk |
2861 | + le32_to_cpu(EXT4_SB(sb)->s_es->s_first_data_block); | 2861 | + le32_to_cpu(EXT4_SB(sb)->s_es->s_first_data_block); |
2862 | trace_mark(ext4_discard_blocks, "dev %s blk %llu count %u", | 2862 | trace_ext4_discard_blocks(sb, (unsigned long long)discard_block, |
2863 | sb->s_id, (unsigned long long) discard_block, | 2863 | entry->count); |
2864 | entry->count); | ||
2865 | sb_issue_discard(sb, discard_block, entry->count); | 2864 | sb_issue_discard(sb, discard_block, entry->count); |
2866 | 2865 | ||
2867 | kmem_cache_free(ext4_free_ext_cachep, entry); | 2866 | kmem_cache_free(ext4_free_ext_cachep, entry); |
@@ -3629,10 +3628,7 @@ ext4_mb_new_inode_pa(struct ext4_allocation_context *ac) | |||
3629 | 3628 | ||
3630 | mb_debug("new inode pa %p: %llu/%u for %u\n", pa, | 3629 | mb_debug("new inode pa %p: %llu/%u for %u\n", pa, |
3631 | pa->pa_pstart, pa->pa_len, pa->pa_lstart); | 3630 | pa->pa_pstart, pa->pa_len, pa->pa_lstart); |
3632 | trace_mark(ext4_mb_new_inode_pa, | 3631 | trace_ext4_mb_new_inode_pa(ac, pa); |
3633 | "dev %s ino %lu pstart %llu len %u lstart %u", | ||
3634 | sb->s_id, ac->ac_inode->i_ino, | ||
3635 | pa->pa_pstart, pa->pa_len, pa->pa_lstart); | ||
3636 | 3632 | ||
3637 | ext4_mb_use_inode_pa(ac, pa); | 3633 | ext4_mb_use_inode_pa(ac, pa); |
3638 | atomic_add(pa->pa_free, &EXT4_SB(sb)->s_mb_preallocated); | 3634 | atomic_add(pa->pa_free, &EXT4_SB(sb)->s_mb_preallocated); |
@@ -3691,9 +3687,8 @@ ext4_mb_new_group_pa(struct ext4_allocation_context *ac) | |||
3691 | pa->pa_type = MB_GROUP_PA; | 3687 | pa->pa_type = MB_GROUP_PA; |
3692 | 3688 | ||
3693 | mb_debug("new group pa %p: %llu/%u for %u\n", pa, | 3689 | mb_debug("new group pa %p: %llu/%u for %u\n", pa, |
3694 | pa->pa_pstart, pa->pa_len, pa->pa_lstart); | 3690 | pa->pa_pstart, pa->pa_len, pa->pa_lstart); |
3695 | trace_mark(ext4_mb_new_group_pa, "dev %s pstart %llu len %u lstart %u", | 3691 | trace_ext4_mb_new_group_pa(ac, pa); |
3696 | sb->s_id, pa->pa_pstart, pa->pa_len, pa->pa_lstart); | ||
3697 | 3692 | ||
3698 | ext4_mb_use_group_pa(ac, pa); | 3693 | ext4_mb_use_group_pa(ac, pa); |
3699 | atomic_add(pa->pa_free, &EXT4_SB(sb)->s_mb_preallocated); | 3694 | atomic_add(pa->pa_free, &EXT4_SB(sb)->s_mb_preallocated); |
@@ -3783,10 +3778,8 @@ ext4_mb_release_inode_pa(struct ext4_buddy *e4b, struct buffer_head *bitmap_bh, | |||
3783 | ext4_mb_store_history(ac); | 3778 | ext4_mb_store_history(ac); |
3784 | } | 3779 | } |
3785 | 3780 | ||
3786 | trace_mark(ext4_mb_release_inode_pa, | 3781 | trace_ext4_mb_release_inode_pa(ac, pa, grp_blk_start + bit, |
3787 | "dev %s ino %lu block %llu count %u", | 3782 | next - bit); |
3788 | sb->s_id, pa->pa_inode->i_ino, grp_blk_start + bit, | ||
3789 | next - bit); | ||
3790 | mb_free_blocks(pa->pa_inode, e4b, bit, next - bit); | 3783 | mb_free_blocks(pa->pa_inode, e4b, bit, next - bit); |
3791 | bit = next + 1; | 3784 | bit = next + 1; |
3792 | } | 3785 | } |
@@ -3820,8 +3813,7 @@ ext4_mb_release_group_pa(struct ext4_buddy *e4b, | |||
3820 | if (ac) | 3813 | if (ac) |
3821 | ac->ac_op = EXT4_MB_HISTORY_DISCARD; | 3814 | ac->ac_op = EXT4_MB_HISTORY_DISCARD; |
3822 | 3815 | ||
3823 | trace_mark(ext4_mb_release_group_pa, "dev %s pstart %llu len %d", | 3816 | trace_ext4_mb_release_group_pa(ac, pa); |
3824 | sb->s_id, pa->pa_pstart, pa->pa_len); | ||
3825 | BUG_ON(pa->pa_deleted == 0); | 3817 | BUG_ON(pa->pa_deleted == 0); |
3826 | ext4_get_group_no_and_offset(sb, pa->pa_pstart, &group, &bit); | 3818 | ext4_get_group_no_and_offset(sb, pa->pa_pstart, &group, &bit); |
3827 | BUG_ON(group != e4b->bd_group && pa->pa_len != 0); | 3819 | BUG_ON(group != e4b->bd_group && pa->pa_len != 0); |
@@ -3889,6 +3881,8 @@ ext4_mb_discard_group_preallocations(struct super_block *sb, | |||
3889 | 3881 | ||
3890 | INIT_LIST_HEAD(&list); | 3882 | INIT_LIST_HEAD(&list); |
3891 | ac = kmem_cache_alloc(ext4_ac_cachep, GFP_NOFS); | 3883 | ac = kmem_cache_alloc(ext4_ac_cachep, GFP_NOFS); |
3884 | if (ac) | ||
3885 | ac->ac_sb = sb; | ||
3892 | repeat: | 3886 | repeat: |
3893 | ext4_lock_group(sb, group); | 3887 | ext4_lock_group(sb, group); |
3894 | list_for_each_entry_safe(pa, tmp, | 3888 | list_for_each_entry_safe(pa, tmp, |
@@ -3987,12 +3981,15 @@ void ext4_discard_preallocations(struct inode *inode) | |||
3987 | } | 3981 | } |
3988 | 3982 | ||
3989 | mb_debug("discard preallocation for inode %lu\n", inode->i_ino); | 3983 | mb_debug("discard preallocation for inode %lu\n", inode->i_ino); |
3990 | trace_mark(ext4_discard_preallocations, "dev %s ino %lu", sb->s_id, | 3984 | trace_ext4_discard_preallocations(inode); |
3991 | inode->i_ino); | ||
3992 | 3985 | ||
3993 | INIT_LIST_HEAD(&list); | 3986 | INIT_LIST_HEAD(&list); |
3994 | 3987 | ||
3995 | ac = kmem_cache_alloc(ext4_ac_cachep, GFP_NOFS); | 3988 | ac = kmem_cache_alloc(ext4_ac_cachep, GFP_NOFS); |
3989 | if (ac) { | ||
3990 | ac->ac_sb = sb; | ||
3991 | ac->ac_inode = inode; | ||
3992 | } | ||
3996 | repeat: | 3993 | repeat: |
3997 | /* first, collect all pa's in the inode */ | 3994 | /* first, collect all pa's in the inode */ |
3998 | spin_lock(&ei->i_prealloc_lock); | 3995 | spin_lock(&ei->i_prealloc_lock); |
@@ -4276,6 +4273,8 @@ ext4_mb_discard_lg_preallocations(struct super_block *sb, | |||
4276 | 4273 | ||
4277 | INIT_LIST_HEAD(&discard_list); | 4274 | INIT_LIST_HEAD(&discard_list); |
4278 | ac = kmem_cache_alloc(ext4_ac_cachep, GFP_NOFS); | 4275 | ac = kmem_cache_alloc(ext4_ac_cachep, GFP_NOFS); |
4276 | if (ac) | ||
4277 | ac->ac_sb = sb; | ||
4279 | 4278 | ||
4280 | spin_lock(&lg->lg_prealloc_lock); | 4279 | spin_lock(&lg->lg_prealloc_lock); |
4281 | list_for_each_entry_rcu(pa, &lg->lg_prealloc_list[order], | 4280 | list_for_each_entry_rcu(pa, &lg->lg_prealloc_list[order], |
@@ -4445,8 +4444,7 @@ static int ext4_mb_discard_preallocations(struct super_block *sb, int needed) | |||
4445 | int ret; | 4444 | int ret; |
4446 | int freed = 0; | 4445 | int freed = 0; |
4447 | 4446 | ||
4448 | trace_mark(ext4_mb_discard_preallocations, "dev %s needed %d", | 4447 | trace_ext4_mb_discard_preallocations(sb, needed); |
4449 | sb->s_id, needed); | ||
4450 | for (i = 0; i < ngroups && needed > 0; i++) { | 4448 | for (i = 0; i < ngroups && needed > 0; i++) { |
4451 | ret = ext4_mb_discard_group_preallocations(sb, i, needed); | 4449 | ret = ext4_mb_discard_group_preallocations(sb, i, needed); |
4452 | freed += ret; | 4450 | freed += ret; |
@@ -4475,17 +4473,7 @@ ext4_fsblk_t ext4_mb_new_blocks(handle_t *handle, | |||
4475 | sb = ar->inode->i_sb; | 4473 | sb = ar->inode->i_sb; |
4476 | sbi = EXT4_SB(sb); | 4474 | sbi = EXT4_SB(sb); |
4477 | 4475 | ||
4478 | trace_mark(ext4_request_blocks, "dev %s flags %u len %u ino %lu " | 4476 | trace_ext4_request_blocks(ar); |
4479 | "lblk %llu goal %llu lleft %llu lright %llu " | ||
4480 | "pleft %llu pright %llu ", | ||
4481 | sb->s_id, ar->flags, ar->len, | ||
4482 | ar->inode ? ar->inode->i_ino : 0, | ||
4483 | (unsigned long long) ar->logical, | ||
4484 | (unsigned long long) ar->goal, | ||
4485 | (unsigned long long) ar->lleft, | ||
4486 | (unsigned long long) ar->lright, | ||
4487 | (unsigned long long) ar->pleft, | ||
4488 | (unsigned long long) ar->pright); | ||
4489 | 4477 | ||
4490 | /* | 4478 | /* |
4491 | * For delayed allocation, we could skip the ENOSPC and | 4479 | * For delayed allocation, we could skip the ENOSPC and |
@@ -4521,7 +4509,10 @@ ext4_fsblk_t ext4_mb_new_blocks(handle_t *handle, | |||
4521 | } | 4509 | } |
4522 | 4510 | ||
4523 | ac = kmem_cache_alloc(ext4_ac_cachep, GFP_NOFS); | 4511 | ac = kmem_cache_alloc(ext4_ac_cachep, GFP_NOFS); |
4524 | if (!ac) { | 4512 | if (ac) { |
4513 | ac->ac_sb = sb; | ||
4514 | ac->ac_inode = ar->inode; | ||
4515 | } else { | ||
4525 | ar->len = 0; | 4516 | ar->len = 0; |
4526 | *errp = -ENOMEM; | 4517 | *errp = -ENOMEM; |
4527 | goto out1; | 4518 | goto out1; |
@@ -4594,18 +4585,7 @@ out3: | |||
4594 | reserv_blks); | 4585 | reserv_blks); |
4595 | } | 4586 | } |
4596 | 4587 | ||
4597 | trace_mark(ext4_allocate_blocks, | 4588 | trace_ext4_allocate_blocks(ar, (unsigned long long)block); |
4598 | "dev %s block %llu flags %u len %u ino %lu " | ||
4599 | "logical %llu goal %llu lleft %llu lright %llu " | ||
4600 | "pleft %llu pright %llu ", | ||
4601 | sb->s_id, (unsigned long long) block, | ||
4602 | ar->flags, ar->len, ar->inode ? ar->inode->i_ino : 0, | ||
4603 | (unsigned long long) ar->logical, | ||
4604 | (unsigned long long) ar->goal, | ||
4605 | (unsigned long long) ar->lleft, | ||
4606 | (unsigned long long) ar->lright, | ||
4607 | (unsigned long long) ar->pleft, | ||
4608 | (unsigned long long) ar->pright); | ||
4609 | 4589 | ||
4610 | return block; | 4590 | return block; |
4611 | } | 4591 | } |
@@ -4709,7 +4689,7 @@ ext4_mb_free_metadata(handle_t *handle, struct ext4_buddy *e4b, | |||
4709 | * Main entry point into mballoc to free blocks | 4689 | * Main entry point into mballoc to free blocks |
4710 | */ | 4690 | */ |
4711 | void ext4_mb_free_blocks(handle_t *handle, struct inode *inode, | 4691 | void ext4_mb_free_blocks(handle_t *handle, struct inode *inode, |
4712 | unsigned long block, unsigned long count, | 4692 | ext4_fsblk_t block, unsigned long count, |
4713 | int metadata, unsigned long *freed) | 4693 | int metadata, unsigned long *freed) |
4714 | { | 4694 | { |
4715 | struct buffer_head *bitmap_bh = NULL; | 4695 | struct buffer_head *bitmap_bh = NULL; |
@@ -4735,15 +4715,12 @@ void ext4_mb_free_blocks(handle_t *handle, struct inode *inode, | |||
4735 | block + count > ext4_blocks_count(es)) { | 4715 | block + count > ext4_blocks_count(es)) { |
4736 | ext4_error(sb, __func__, | 4716 | ext4_error(sb, __func__, |
4737 | "Freeing blocks not in datazone - " | 4717 | "Freeing blocks not in datazone - " |
4738 | "block = %lu, count = %lu", block, count); | 4718 | "block = %llu, count = %lu", block, count); |
4739 | goto error_return; | 4719 | goto error_return; |
4740 | } | 4720 | } |
4741 | 4721 | ||
4742 | ext4_debug("freeing block %lu\n", block); | 4722 | ext4_debug("freeing block %llu\n", block); |
4743 | trace_mark(ext4_free_blocks, | 4723 | trace_ext4_free_blocks(inode, block, count, metadata); |
4744 | "dev %s block %llu count %lu metadata %d ino %lu", | ||
4745 | sb->s_id, (unsigned long long) block, count, metadata, | ||
4746 | inode ? inode->i_ino : 0); | ||
4747 | 4724 | ||
4748 | ac = kmem_cache_alloc(ext4_ac_cachep, GFP_NOFS); | 4725 | ac = kmem_cache_alloc(ext4_ac_cachep, GFP_NOFS); |
4749 | if (ac) { | 4726 | if (ac) { |
@@ -4784,7 +4761,7 @@ do_more: | |||
4784 | 4761 | ||
4785 | ext4_error(sb, __func__, | 4762 | ext4_error(sb, __func__, |
4786 | "Freeing blocks in system zone - " | 4763 | "Freeing blocks in system zone - " |
4787 | "Block = %lu, count = %lu", block, count); | 4764 | "Block = %llu, count = %lu", block, count); |
4788 | /* err = 0. ext4_std_error should be a no op */ | 4765 | /* err = 0. ext4_std_error should be a no op */ |
4789 | goto error_return; | 4766 | goto error_return; |
4790 | } | 4767 | } |
diff --git a/fs/ext4/mballoc.h b/fs/ext4/mballoc.h index 75e34f69215b..c96bb19f58f9 100644 --- a/fs/ext4/mballoc.h +++ b/fs/ext4/mballoc.h | |||
@@ -19,7 +19,6 @@ | |||
19 | #include <linux/seq_file.h> | 19 | #include <linux/seq_file.h> |
20 | #include <linux/version.h> | 20 | #include <linux/version.h> |
21 | #include <linux/blkdev.h> | 21 | #include <linux/blkdev.h> |
22 | #include <linux/marker.h> | ||
23 | #include <linux/mutex.h> | 22 | #include <linux/mutex.h> |
24 | #include "ext4_jbd2.h" | 23 | #include "ext4_jbd2.h" |
25 | #include "ext4.h" | 24 | #include "ext4.h" |
diff --git a/fs/ext4/migrate.c b/fs/ext4/migrate.c index fe64d9f79852..313a50b39741 100644 --- a/fs/ext4/migrate.c +++ b/fs/ext4/migrate.c | |||
@@ -458,6 +458,7 @@ int ext4_ext_migrate(struct inode *inode) | |||
458 | struct inode *tmp_inode = NULL; | 458 | struct inode *tmp_inode = NULL; |
459 | struct list_blocks_struct lb; | 459 | struct list_blocks_struct lb; |
460 | unsigned long max_entries; | 460 | unsigned long max_entries; |
461 | __u32 goal; | ||
461 | 462 | ||
462 | /* | 463 | /* |
463 | * If the filesystem does not support extents, or the inode | 464 | * If the filesystem does not support extents, or the inode |
@@ -483,9 +484,10 @@ int ext4_ext_migrate(struct inode *inode) | |||
483 | retval = PTR_ERR(handle); | 484 | retval = PTR_ERR(handle); |
484 | return retval; | 485 | return retval; |
485 | } | 486 | } |
486 | tmp_inode = ext4_new_inode(handle, | 487 | goal = (((inode->i_ino - 1) / EXT4_INODES_PER_GROUP(inode->i_sb)) * |
487 | inode->i_sb->s_root->d_inode, | 488 | EXT4_INODES_PER_GROUP(inode->i_sb)) + 1; |
488 | S_IFREG); | 489 | tmp_inode = ext4_new_inode(handle, inode->i_sb->s_root->d_inode, |
490 | S_IFREG, 0, goal); | ||
489 | if (IS_ERR(tmp_inode)) { | 491 | if (IS_ERR(tmp_inode)) { |
490 | retval = -ENOMEM; | 492 | retval = -ENOMEM; |
491 | ext4_journal_stop(handle); | 493 | ext4_journal_stop(handle); |
diff --git a/fs/ext4/move_extent.c b/fs/ext4/move_extent.c new file mode 100644 index 000000000000..bbf2dd9404dc --- /dev/null +++ b/fs/ext4/move_extent.c | |||
@@ -0,0 +1,1320 @@ | |||
1 | /* | ||
2 | * Copyright (c) 2008,2009 NEC Software Tohoku, Ltd. | ||
3 | * Written by Takashi Sato <t-sato@yk.jp.nec.com> | ||
4 | * Akira Fujita <a-fujita@rs.jp.nec.com> | ||
5 | * | ||
6 | * This program is free software; you can redistribute it and/or modify it | ||
7 | * under the terms of version 2.1 of the GNU Lesser General Public License | ||
8 | * as published by the Free Software Foundation. | ||
9 | * | ||
10 | * This program is distributed in the hope that it will be useful, | ||
11 | * but WITHOUT ANY WARRANTY; without even the implied warranty of | ||
12 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the | ||
13 | * GNU General Public License for more details. | ||
14 | */ | ||
15 | |||
16 | #include <linux/fs.h> | ||
17 | #include <linux/quotaops.h> | ||
18 | #include "ext4_jbd2.h" | ||
19 | #include "ext4_extents.h" | ||
20 | #include "ext4.h" | ||
21 | |||
22 | #define get_ext_path(path, inode, block, ret) \ | ||
23 | do { \ | ||
24 | path = ext4_ext_find_extent(inode, block, path); \ | ||
25 | if (IS_ERR(path)) { \ | ||
26 | ret = PTR_ERR(path); \ | ||
27 | path = NULL; \ | ||
28 | } \ | ||
29 | } while (0) | ||
30 | |||
31 | /** | ||
32 | * copy_extent_status - Copy the extent's initialization status | ||
33 | * | ||
34 | * @src: an extent for getting initialize status | ||
35 | * @dest: an extent to be set the status | ||
36 | */ | ||
37 | static void | ||
38 | copy_extent_status(struct ext4_extent *src, struct ext4_extent *dest) | ||
39 | { | ||
40 | if (ext4_ext_is_uninitialized(src)) | ||
41 | ext4_ext_mark_uninitialized(dest); | ||
42 | else | ||
43 | dest->ee_len = cpu_to_le16(ext4_ext_get_actual_len(dest)); | ||
44 | } | ||
45 | |||
46 | /** | ||
47 | * mext_next_extent - Search for the next extent and set it to "extent" | ||
48 | * | ||
49 | * @inode: inode which is searched | ||
50 | * @path: this will obtain data for the next extent | ||
51 | * @extent: pointer to the next extent we have just gotten | ||
52 | * | ||
53 | * Search the next extent in the array of ext4_ext_path structure (@path) | ||
54 | * and set it to ext4_extent structure (@extent). In addition, the member of | ||
55 | * @path (->p_ext) also points the next extent. Return 0 on success, 1 if | ||
56 | * ext4_ext_path structure refers to the last extent, or a negative error | ||
57 | * value on failure. | ||
58 | */ | ||
59 | static int | ||
60 | mext_next_extent(struct inode *inode, struct ext4_ext_path *path, | ||
61 | struct ext4_extent **extent) | ||
62 | { | ||
63 | int ppos, leaf_ppos = path->p_depth; | ||
64 | |||
65 | ppos = leaf_ppos; | ||
66 | if (EXT_LAST_EXTENT(path[ppos].p_hdr) > path[ppos].p_ext) { | ||
67 | /* leaf block */ | ||
68 | *extent = ++path[ppos].p_ext; | ||
69 | return 0; | ||
70 | } | ||
71 | |||
72 | while (--ppos >= 0) { | ||
73 | if (EXT_LAST_INDEX(path[ppos].p_hdr) > | ||
74 | path[ppos].p_idx) { | ||
75 | int cur_ppos = ppos; | ||
76 | |||
77 | /* index block */ | ||
78 | path[ppos].p_idx++; | ||
79 | path[ppos].p_block = idx_pblock(path[ppos].p_idx); | ||
80 | if (path[ppos+1].p_bh) | ||
81 | brelse(path[ppos+1].p_bh); | ||
82 | path[ppos+1].p_bh = | ||
83 | sb_bread(inode->i_sb, path[ppos].p_block); | ||
84 | if (!path[ppos+1].p_bh) | ||
85 | return -EIO; | ||
86 | path[ppos+1].p_hdr = | ||
87 | ext_block_hdr(path[ppos+1].p_bh); | ||
88 | |||
89 | /* Halfway index block */ | ||
90 | while (++cur_ppos < leaf_ppos) { | ||
91 | path[cur_ppos].p_idx = | ||
92 | EXT_FIRST_INDEX(path[cur_ppos].p_hdr); | ||
93 | path[cur_ppos].p_block = | ||
94 | idx_pblock(path[cur_ppos].p_idx); | ||
95 | if (path[cur_ppos+1].p_bh) | ||
96 | brelse(path[cur_ppos+1].p_bh); | ||
97 | path[cur_ppos+1].p_bh = sb_bread(inode->i_sb, | ||
98 | path[cur_ppos].p_block); | ||
99 | if (!path[cur_ppos+1].p_bh) | ||
100 | return -EIO; | ||
101 | path[cur_ppos+1].p_hdr = | ||
102 | ext_block_hdr(path[cur_ppos+1].p_bh); | ||
103 | } | ||
104 | |||
105 | /* leaf block */ | ||
106 | path[leaf_ppos].p_ext = *extent = | ||
107 | EXT_FIRST_EXTENT(path[leaf_ppos].p_hdr); | ||
108 | return 0; | ||
109 | } | ||
110 | } | ||
111 | /* We found the last extent */ | ||
112 | return 1; | ||
113 | } | ||
114 | |||
115 | /** | ||
116 | * mext_double_down_read - Acquire two inodes' read semaphore | ||
117 | * | ||
118 | * @orig_inode: original inode structure | ||
119 | * @donor_inode: donor inode structure | ||
120 | * Acquire read semaphore of the two inodes (orig and donor) by i_ino order. | ||
121 | */ | ||
122 | static void | ||
123 | mext_double_down_read(struct inode *orig_inode, struct inode *donor_inode) | ||
124 | { | ||
125 | struct inode *first = orig_inode, *second = donor_inode; | ||
126 | |||
127 | BUG_ON(orig_inode == NULL || donor_inode == NULL); | ||
128 | |||
129 | /* | ||
130 | * Use the inode number to provide the stable locking order instead | ||
131 | * of its address, because the C language doesn't guarantee you can | ||
132 | * compare pointers that don't come from the same array. | ||
133 | */ | ||
134 | if (donor_inode->i_ino < orig_inode->i_ino) { | ||
135 | first = donor_inode; | ||
136 | second = orig_inode; | ||
137 | } | ||
138 | |||
139 | down_read(&EXT4_I(first)->i_data_sem); | ||
140 | down_read(&EXT4_I(second)->i_data_sem); | ||
141 | } | ||
142 | |||
143 | /** | ||
144 | * mext_double_down_write - Acquire two inodes' write semaphore | ||
145 | * | ||
146 | * @orig_inode: original inode structure | ||
147 | * @donor_inode: donor inode structure | ||
148 | * Acquire write semaphore of the two inodes (orig and donor) by i_ino order. | ||
149 | */ | ||
150 | static void | ||
151 | mext_double_down_write(struct inode *orig_inode, struct inode *donor_inode) | ||
152 | { | ||
153 | struct inode *first = orig_inode, *second = donor_inode; | ||
154 | |||
155 | BUG_ON(orig_inode == NULL || donor_inode == NULL); | ||
156 | |||
157 | /* | ||
158 | * Use the inode number to provide the stable locking order instead | ||
159 | * of its address, because the C language doesn't guarantee you can | ||
160 | * compare pointers that don't come from the same array. | ||
161 | */ | ||
162 | if (donor_inode->i_ino < orig_inode->i_ino) { | ||
163 | first = donor_inode; | ||
164 | second = orig_inode; | ||
165 | } | ||
166 | |||
167 | down_write(&EXT4_I(first)->i_data_sem); | ||
168 | down_write(&EXT4_I(second)->i_data_sem); | ||
169 | } | ||
170 | |||
171 | /** | ||
172 | * mext_double_up_read - Release two inodes' read semaphore | ||
173 | * | ||
174 | * @orig_inode: original inode structure to be released its lock first | ||
175 | * @donor_inode: donor inode structure to be released its lock second | ||
176 | * Release read semaphore of two inodes (orig and donor). | ||
177 | */ | ||
178 | static void | ||
179 | mext_double_up_read(struct inode *orig_inode, struct inode *donor_inode) | ||
180 | { | ||
181 | BUG_ON(orig_inode == NULL || donor_inode == NULL); | ||
182 | |||
183 | up_read(&EXT4_I(orig_inode)->i_data_sem); | ||
184 | up_read(&EXT4_I(donor_inode)->i_data_sem); | ||
185 | } | ||
186 | |||
187 | /** | ||
188 | * mext_double_up_write - Release two inodes' write semaphore | ||
189 | * | ||
190 | * @orig_inode: original inode structure to be released its lock first | ||
191 | * @donor_inode: donor inode structure to be released its lock second | ||
192 | * Release write semaphore of two inodes (orig and donor). | ||
193 | */ | ||
194 | static void | ||
195 | mext_double_up_write(struct inode *orig_inode, struct inode *donor_inode) | ||
196 | { | ||
197 | BUG_ON(orig_inode == NULL || donor_inode == NULL); | ||
198 | |||
199 | up_write(&EXT4_I(orig_inode)->i_data_sem); | ||
200 | up_write(&EXT4_I(donor_inode)->i_data_sem); | ||
201 | } | ||
202 | |||
203 | /** | ||
204 | * mext_insert_across_blocks - Insert extents across leaf block | ||
205 | * | ||
206 | * @handle: journal handle | ||
207 | * @orig_inode: original inode | ||
208 | * @o_start: first original extent to be changed | ||
209 | * @o_end: last original extent to be changed | ||
210 | * @start_ext: first new extent to be inserted | ||
211 | * @new_ext: middle of new extent to be inserted | ||
212 | * @end_ext: last new extent to be inserted | ||
213 | * | ||
214 | * Allocate a new leaf block and insert extents into it. Return 0 on success, | ||
215 | * or a negative error value on failure. | ||
216 | */ | ||
217 | static int | ||
218 | mext_insert_across_blocks(handle_t *handle, struct inode *orig_inode, | ||
219 | struct ext4_extent *o_start, struct ext4_extent *o_end, | ||
220 | struct ext4_extent *start_ext, struct ext4_extent *new_ext, | ||
221 | struct ext4_extent *end_ext) | ||
222 | { | ||
223 | struct ext4_ext_path *orig_path = NULL; | ||
224 | ext4_lblk_t eblock = 0; | ||
225 | int new_flag = 0; | ||
226 | int end_flag = 0; | ||
227 | int err = 0; | ||
228 | |||
229 | if (start_ext->ee_len && new_ext->ee_len && end_ext->ee_len) { | ||
230 | if (o_start == o_end) { | ||
231 | |||
232 | /* start_ext new_ext end_ext | ||
233 | * donor |---------|-----------|--------| | ||
234 | * orig |------------------------------| | ||
235 | */ | ||
236 | end_flag = 1; | ||
237 | } else { | ||
238 | |||
239 | /* start_ext new_ext end_ext | ||
240 | * donor |---------|----------|---------| | ||
241 | * orig |---------------|--------------| | ||
242 | */ | ||
243 | o_end->ee_block = end_ext->ee_block; | ||
244 | o_end->ee_len = end_ext->ee_len; | ||
245 | ext4_ext_store_pblock(o_end, ext_pblock(end_ext)); | ||
246 | } | ||
247 | |||
248 | o_start->ee_len = start_ext->ee_len; | ||
249 | new_flag = 1; | ||
250 | |||
251 | } else if (start_ext->ee_len && new_ext->ee_len && | ||
252 | !end_ext->ee_len && o_start == o_end) { | ||
253 | |||
254 | /* start_ext new_ext | ||
255 | * donor |--------------|---------------| | ||
256 | * orig |------------------------------| | ||
257 | */ | ||
258 | o_start->ee_len = start_ext->ee_len; | ||
259 | new_flag = 1; | ||
260 | |||
261 | } else if (!start_ext->ee_len && new_ext->ee_len && | ||
262 | end_ext->ee_len && o_start == o_end) { | ||
263 | |||
264 | /* new_ext end_ext | ||
265 | * donor |--------------|---------------| | ||
266 | * orig |------------------------------| | ||
267 | */ | ||
268 | o_end->ee_block = end_ext->ee_block; | ||
269 | o_end->ee_len = end_ext->ee_len; | ||
270 | ext4_ext_store_pblock(o_end, ext_pblock(end_ext)); | ||
271 | |||
272 | /* | ||
273 | * Set 0 to the extent block if new_ext was | ||
274 | * the first block. | ||
275 | */ | ||
276 | if (new_ext->ee_block) | ||
277 | eblock = le32_to_cpu(new_ext->ee_block); | ||
278 | |||
279 | new_flag = 1; | ||
280 | } else { | ||
281 | ext4_debug("ext4 move extent: Unexpected insert case\n"); | ||
282 | return -EIO; | ||
283 | } | ||
284 | |||
285 | if (new_flag) { | ||
286 | get_ext_path(orig_path, orig_inode, eblock, err); | ||
287 | if (orig_path == NULL) | ||
288 | goto out; | ||
289 | |||
290 | if (ext4_ext_insert_extent(handle, orig_inode, | ||
291 | orig_path, new_ext)) | ||
292 | goto out; | ||
293 | } | ||
294 | |||
295 | if (end_flag) { | ||
296 | get_ext_path(orig_path, orig_inode, | ||
297 | le32_to_cpu(end_ext->ee_block) - 1, err); | ||
298 | if (orig_path == NULL) | ||
299 | goto out; | ||
300 | |||
301 | if (ext4_ext_insert_extent(handle, orig_inode, | ||
302 | orig_path, end_ext)) | ||
303 | goto out; | ||
304 | } | ||
305 | out: | ||
306 | if (orig_path) { | ||
307 | ext4_ext_drop_refs(orig_path); | ||
308 | kfree(orig_path); | ||
309 | } | ||
310 | |||
311 | return err; | ||
312 | |||
313 | } | ||
314 | |||
315 | /** | ||
316 | * mext_insert_inside_block - Insert new extent to the extent block | ||
317 | * | ||
318 | * @o_start: first original extent to be moved | ||
319 | * @o_end: last original extent to be moved | ||
320 | * @start_ext: first new extent to be inserted | ||
321 | * @new_ext: middle of new extent to be inserted | ||
322 | * @end_ext: last new extent to be inserted | ||
323 | * @eh: extent header of target leaf block | ||
324 | * @range_to_move: used to decide how to insert extent | ||
325 | * | ||
326 | * Insert extents into the leaf block. The extent (@o_start) is overwritten | ||
327 | * by inserted extents. | ||
328 | */ | ||
329 | static void | ||
330 | mext_insert_inside_block(struct ext4_extent *o_start, | ||
331 | struct ext4_extent *o_end, | ||
332 | struct ext4_extent *start_ext, | ||
333 | struct ext4_extent *new_ext, | ||
334 | struct ext4_extent *end_ext, | ||
335 | struct ext4_extent_header *eh, | ||
336 | int range_to_move) | ||
337 | { | ||
338 | int i = 0; | ||
339 | unsigned long len; | ||
340 | |||
341 | /* Move the existing extents */ | ||
342 | if (range_to_move && o_end < EXT_LAST_EXTENT(eh)) { | ||
343 | len = (unsigned long)(EXT_LAST_EXTENT(eh) + 1) - | ||
344 | (unsigned long)(o_end + 1); | ||
345 | memmove(o_end + 1 + range_to_move, o_end + 1, len); | ||
346 | } | ||
347 | |||
348 | /* Insert start entry */ | ||
349 | if (start_ext->ee_len) | ||
350 | o_start[i++].ee_len = start_ext->ee_len; | ||
351 | |||
352 | /* Insert new entry */ | ||
353 | if (new_ext->ee_len) { | ||
354 | o_start[i] = *new_ext; | ||
355 | ext4_ext_store_pblock(&o_start[i++], ext_pblock(new_ext)); | ||
356 | } | ||
357 | |||
358 | /* Insert end entry */ | ||
359 | if (end_ext->ee_len) | ||
360 | o_start[i] = *end_ext; | ||
361 | |||
362 | /* Increment the total entries counter on the extent block */ | ||
363 | le16_add_cpu(&eh->eh_entries, range_to_move); | ||
364 | } | ||
365 | |||
366 | /** | ||
367 | * mext_insert_extents - Insert new extent | ||
368 | * | ||
369 | * @handle: journal handle | ||
370 | * @orig_inode: original inode | ||
371 | * @orig_path: path indicates first extent to be changed | ||
372 | * @o_start: first original extent to be changed | ||
373 | * @o_end: last original extent to be changed | ||
374 | * @start_ext: first new extent to be inserted | ||
375 | * @new_ext: middle of new extent to be inserted | ||
376 | * @end_ext: last new extent to be inserted | ||
377 | * | ||
378 | * Call the function to insert extents. If we cannot add more extents into | ||
379 | * the leaf block, we call mext_insert_across_blocks() to create a | ||
380 | * new leaf block. Otherwise call mext_insert_inside_block(). Return 0 | ||
381 | * on success, or a negative error value on failure. | ||
382 | */ | ||
383 | static int | ||
384 | mext_insert_extents(handle_t *handle, struct inode *orig_inode, | ||
385 | struct ext4_ext_path *orig_path, | ||
386 | struct ext4_extent *o_start, | ||
387 | struct ext4_extent *o_end, | ||
388 | struct ext4_extent *start_ext, | ||
389 | struct ext4_extent *new_ext, | ||
390 | struct ext4_extent *end_ext) | ||
391 | { | ||
392 | struct ext4_extent_header *eh; | ||
393 | unsigned long need_slots, slots_range; | ||
394 | int range_to_move, depth, ret; | ||
395 | |||
396 | /* | ||
397 | * The extents need to be inserted | ||
398 | * start_extent + new_extent + end_extent. | ||
399 | */ | ||
400 | need_slots = (start_ext->ee_len ? 1 : 0) + (end_ext->ee_len ? 1 : 0) + | ||
401 | (new_ext->ee_len ? 1 : 0); | ||
402 | |||
403 | /* The number of slots between start and end */ | ||
404 | slots_range = ((unsigned long)(o_end + 1) - (unsigned long)o_start + 1) | ||
405 | / sizeof(struct ext4_extent); | ||
406 | |||
407 | /* Range to move the end of extent */ | ||
408 | range_to_move = need_slots - slots_range; | ||
409 | depth = orig_path->p_depth; | ||
410 | orig_path += depth; | ||
411 | eh = orig_path->p_hdr; | ||
412 | |||
413 | if (depth) { | ||
414 | /* Register to journal */ | ||
415 | ret = ext4_journal_get_write_access(handle, orig_path->p_bh); | ||
416 | if (ret) | ||
417 | return ret; | ||
418 | } | ||
419 | |||
420 | /* Expansion */ | ||
421 | if (range_to_move > 0 && | ||
422 | (range_to_move > le16_to_cpu(eh->eh_max) | ||
423 | - le16_to_cpu(eh->eh_entries))) { | ||
424 | |||
425 | ret = mext_insert_across_blocks(handle, orig_inode, o_start, | ||
426 | o_end, start_ext, new_ext, end_ext); | ||
427 | if (ret < 0) | ||
428 | return ret; | ||
429 | } else | ||
430 | mext_insert_inside_block(o_start, o_end, start_ext, new_ext, | ||
431 | end_ext, eh, range_to_move); | ||
432 | |||
433 | if (depth) { | ||
434 | ret = ext4_handle_dirty_metadata(handle, orig_inode, | ||
435 | orig_path->p_bh); | ||
436 | if (ret) | ||
437 | return ret; | ||
438 | } else { | ||
439 | ret = ext4_mark_inode_dirty(handle, orig_inode); | ||
440 | if (ret < 0) | ||
441 | return ret; | ||
442 | } | ||
443 | |||
444 | return 0; | ||
445 | } | ||
446 | |||
447 | /** | ||
448 | * mext_leaf_block - Move one leaf extent block into the inode. | ||
449 | * | ||
450 | * @handle: journal handle | ||
451 | * @orig_inode: original inode | ||
452 | * @orig_path: path indicates first extent to be changed | ||
453 | * @dext: donor extent | ||
454 | * @from: start offset on the target file | ||
455 | * | ||
456 | * In order to insert extents into the leaf block, we must divide the extent | ||
457 | * in the leaf block into three extents. The one is located to be inserted | ||
458 | * extents, and the others are located around it. | ||
459 | * | ||
460 | * Therefore, this function creates structures to save extents of the leaf | ||
461 | * block, and inserts extents by calling mext_insert_extents() with | ||
462 | * created extents. Return 0 on success, or a negative error value on failure. | ||
463 | */ | ||
464 | static int | ||
465 | mext_leaf_block(handle_t *handle, struct inode *orig_inode, | ||
466 | struct ext4_ext_path *orig_path, struct ext4_extent *dext, | ||
467 | ext4_lblk_t *from) | ||
468 | { | ||
469 | struct ext4_extent *oext, *o_start, *o_end, *prev_ext; | ||
470 | struct ext4_extent new_ext, start_ext, end_ext; | ||
471 | ext4_lblk_t new_ext_end; | ||
472 | ext4_fsblk_t new_phys_end; | ||
473 | int oext_alen, new_ext_alen, end_ext_alen; | ||
474 | int depth = ext_depth(orig_inode); | ||
475 | int ret; | ||
476 | |||
477 | o_start = o_end = oext = orig_path[depth].p_ext; | ||
478 | oext_alen = ext4_ext_get_actual_len(oext); | ||
479 | start_ext.ee_len = end_ext.ee_len = 0; | ||
480 | |||
481 | new_ext.ee_block = cpu_to_le32(*from); | ||
482 | ext4_ext_store_pblock(&new_ext, ext_pblock(dext)); | ||
483 | new_ext.ee_len = dext->ee_len; | ||
484 | new_ext_alen = ext4_ext_get_actual_len(&new_ext); | ||
485 | new_ext_end = le32_to_cpu(new_ext.ee_block) + new_ext_alen - 1; | ||
486 | new_phys_end = ext_pblock(&new_ext) + new_ext_alen - 1; | ||
487 | |||
488 | /* | ||
489 | * Case: original extent is first | ||
490 | * oext |--------| | ||
491 | * new_ext |--| | ||
492 | * start_ext |--| | ||
493 | */ | ||
494 | if (le32_to_cpu(oext->ee_block) < le32_to_cpu(new_ext.ee_block) && | ||
495 | le32_to_cpu(new_ext.ee_block) < | ||
496 | le32_to_cpu(oext->ee_block) + oext_alen) { | ||
497 | start_ext.ee_len = cpu_to_le16(le32_to_cpu(new_ext.ee_block) - | ||
498 | le32_to_cpu(oext->ee_block)); | ||
499 | copy_extent_status(oext, &start_ext); | ||
500 | } else if (oext > EXT_FIRST_EXTENT(orig_path[depth].p_hdr)) { | ||
501 | prev_ext = oext - 1; | ||
502 | /* | ||
503 | * We can merge new_ext into previous extent, | ||
504 | * if these are contiguous and same extent type. | ||
505 | */ | ||
506 | if (ext4_can_extents_be_merged(orig_inode, prev_ext, | ||
507 | &new_ext)) { | ||
508 | o_start = prev_ext; | ||
509 | start_ext.ee_len = cpu_to_le16( | ||
510 | ext4_ext_get_actual_len(prev_ext) + | ||
511 | new_ext_alen); | ||
512 | copy_extent_status(prev_ext, &start_ext); | ||
513 | new_ext.ee_len = 0; | ||
514 | } | ||
515 | } | ||
516 | |||
517 | /* | ||
518 | * Case: new_ext_end must be less than oext | ||
519 | * oext |-----------| | ||
520 | * new_ext |-------| | ||
521 | */ | ||
522 | BUG_ON(le32_to_cpu(oext->ee_block) + oext_alen - 1 < new_ext_end); | ||
523 | |||
524 | /* | ||
525 | * Case: new_ext is smaller than original extent | ||
526 | * oext |---------------| | ||
527 | * new_ext |-----------| | ||
528 | * end_ext |---| | ||
529 | */ | ||
530 | if (le32_to_cpu(oext->ee_block) <= new_ext_end && | ||
531 | new_ext_end < le32_to_cpu(oext->ee_block) + oext_alen - 1) { | ||
532 | end_ext.ee_len = | ||
533 | cpu_to_le16(le32_to_cpu(oext->ee_block) + | ||
534 | oext_alen - 1 - new_ext_end); | ||
535 | copy_extent_status(oext, &end_ext); | ||
536 | end_ext_alen = ext4_ext_get_actual_len(&end_ext); | ||
537 | ext4_ext_store_pblock(&end_ext, | ||
538 | (ext_pblock(o_end) + oext_alen - end_ext_alen)); | ||
539 | end_ext.ee_block = | ||
540 | cpu_to_le32(le32_to_cpu(o_end->ee_block) + | ||
541 | oext_alen - end_ext_alen); | ||
542 | } | ||
543 | |||
544 | ret = mext_insert_extents(handle, orig_inode, orig_path, o_start, | ||
545 | o_end, &start_ext, &new_ext, &end_ext); | ||
546 | return ret; | ||
547 | } | ||
548 | |||
549 | /** | ||
550 | * mext_calc_swap_extents - Calculate extents for extent swapping. | ||
551 | * | ||
552 | * @tmp_dext: the extent that will belong to the original inode | ||
553 | * @tmp_oext: the extent that will belong to the donor inode | ||
554 | * @orig_off: block offset of original inode | ||
555 | * @donor_off: block offset of donor inode | ||
556 | * @max_count: the maximun length of extents | ||
557 | */ | ||
558 | static void | ||
559 | mext_calc_swap_extents(struct ext4_extent *tmp_dext, | ||
560 | struct ext4_extent *tmp_oext, | ||
561 | ext4_lblk_t orig_off, ext4_lblk_t donor_off, | ||
562 | ext4_lblk_t max_count) | ||
563 | { | ||
564 | ext4_lblk_t diff, orig_diff; | ||
565 | struct ext4_extent dext_old, oext_old; | ||
566 | |||
567 | dext_old = *tmp_dext; | ||
568 | oext_old = *tmp_oext; | ||
569 | |||
570 | /* When tmp_dext is too large, pick up the target range. */ | ||
571 | diff = donor_off - le32_to_cpu(tmp_dext->ee_block); | ||
572 | |||
573 | ext4_ext_store_pblock(tmp_dext, ext_pblock(tmp_dext) + diff); | ||
574 | tmp_dext->ee_block = | ||
575 | cpu_to_le32(le32_to_cpu(tmp_dext->ee_block) + diff); | ||
576 | tmp_dext->ee_len = cpu_to_le16(le16_to_cpu(tmp_dext->ee_len) - diff); | ||
577 | |||
578 | if (max_count < ext4_ext_get_actual_len(tmp_dext)) | ||
579 | tmp_dext->ee_len = cpu_to_le16(max_count); | ||
580 | |||
581 | orig_diff = orig_off - le32_to_cpu(tmp_oext->ee_block); | ||
582 | ext4_ext_store_pblock(tmp_oext, ext_pblock(tmp_oext) + orig_diff); | ||
583 | |||
584 | /* Adjust extent length if donor extent is larger than orig */ | ||
585 | if (ext4_ext_get_actual_len(tmp_dext) > | ||
586 | ext4_ext_get_actual_len(tmp_oext) - orig_diff) | ||
587 | tmp_dext->ee_len = cpu_to_le16(le16_to_cpu(tmp_oext->ee_len) - | ||
588 | orig_diff); | ||
589 | |||
590 | tmp_oext->ee_len = cpu_to_le16(ext4_ext_get_actual_len(tmp_dext)); | ||
591 | |||
592 | copy_extent_status(&oext_old, tmp_dext); | ||
593 | copy_extent_status(&dext_old, tmp_oext); | ||
594 | } | ||
595 | |||
596 | /** | ||
597 | * mext_replace_branches - Replace original extents with new extents | ||
598 | * | ||
599 | * @handle: journal handle | ||
600 | * @orig_inode: original inode | ||
601 | * @donor_inode: donor inode | ||
602 | * @from: block offset of orig_inode | ||
603 | * @count: block count to be replaced | ||
604 | * | ||
605 | * Replace original inode extents and donor inode extents page by page. | ||
606 | * We implement this replacement in the following three steps: | ||
607 | * 1. Save the block information of original and donor inodes into | ||
608 | * dummy extents. | ||
609 | * 2. Change the block information of original inode to point at the | ||
610 | * donor inode blocks. | ||
611 | * 3. Change the block information of donor inode to point at the saved | ||
612 | * original inode blocks in the dummy extents. | ||
613 | * | ||
614 | * Return 0 on success, or a negative error value on failure. | ||
615 | */ | ||
616 | static int | ||
617 | mext_replace_branches(handle_t *handle, struct inode *orig_inode, | ||
618 | struct inode *donor_inode, ext4_lblk_t from, | ||
619 | ext4_lblk_t count) | ||
620 | { | ||
621 | struct ext4_ext_path *orig_path = NULL; | ||
622 | struct ext4_ext_path *donor_path = NULL; | ||
623 | struct ext4_extent *oext, *dext; | ||
624 | struct ext4_extent tmp_dext, tmp_oext; | ||
625 | ext4_lblk_t orig_off = from, donor_off = from; | ||
626 | int err = 0; | ||
627 | int depth; | ||
628 | int replaced_count = 0; | ||
629 | int dext_alen; | ||
630 | |||
631 | mext_double_down_write(orig_inode, donor_inode); | ||
632 | |||
633 | /* Get the original extent for the block "orig_off" */ | ||
634 | get_ext_path(orig_path, orig_inode, orig_off, err); | ||
635 | if (orig_path == NULL) | ||
636 | goto out; | ||
637 | |||
638 | /* Get the donor extent for the head */ | ||
639 | get_ext_path(donor_path, donor_inode, donor_off, err); | ||
640 | if (donor_path == NULL) | ||
641 | goto out; | ||
642 | depth = ext_depth(orig_inode); | ||
643 | oext = orig_path[depth].p_ext; | ||
644 | tmp_oext = *oext; | ||
645 | |||
646 | depth = ext_depth(donor_inode); | ||
647 | dext = donor_path[depth].p_ext; | ||
648 | tmp_dext = *dext; | ||
649 | |||
650 | mext_calc_swap_extents(&tmp_dext, &tmp_oext, orig_off, | ||
651 | donor_off, count); | ||
652 | |||
653 | /* Loop for the donor extents */ | ||
654 | while (1) { | ||
655 | /* The extent for donor must be found. */ | ||
656 | BUG_ON(!dext || donor_off != le32_to_cpu(tmp_dext.ee_block)); | ||
657 | |||
658 | /* Set donor extent to orig extent */ | ||
659 | err = mext_leaf_block(handle, orig_inode, | ||
660 | orig_path, &tmp_dext, &orig_off); | ||
661 | if (err < 0) | ||
662 | goto out; | ||
663 | |||
664 | /* Set orig extent to donor extent */ | ||
665 | err = mext_leaf_block(handle, donor_inode, | ||
666 | donor_path, &tmp_oext, &donor_off); | ||
667 | if (err < 0) | ||
668 | goto out; | ||
669 | |||
670 | dext_alen = ext4_ext_get_actual_len(&tmp_dext); | ||
671 | replaced_count += dext_alen; | ||
672 | donor_off += dext_alen; | ||
673 | orig_off += dext_alen; | ||
674 | |||
675 | /* Already moved the expected blocks */ | ||
676 | if (replaced_count >= count) | ||
677 | break; | ||
678 | |||
679 | if (orig_path) | ||
680 | ext4_ext_drop_refs(orig_path); | ||
681 | get_ext_path(orig_path, orig_inode, orig_off, err); | ||
682 | if (orig_path == NULL) | ||
683 | goto out; | ||
684 | depth = ext_depth(orig_inode); | ||
685 | oext = orig_path[depth].p_ext; | ||
686 | if (le32_to_cpu(oext->ee_block) + | ||
687 | ext4_ext_get_actual_len(oext) <= orig_off) { | ||
688 | err = 0; | ||
689 | goto out; | ||
690 | } | ||
691 | tmp_oext = *oext; | ||
692 | |||
693 | if (donor_path) | ||
694 | ext4_ext_drop_refs(donor_path); | ||
695 | get_ext_path(donor_path, donor_inode, | ||
696 | donor_off, err); | ||
697 | if (donor_path == NULL) | ||
698 | goto out; | ||
699 | depth = ext_depth(donor_inode); | ||
700 | dext = donor_path[depth].p_ext; | ||
701 | if (le32_to_cpu(dext->ee_block) + | ||
702 | ext4_ext_get_actual_len(dext) <= donor_off) { | ||
703 | err = 0; | ||
704 | goto out; | ||
705 | } | ||
706 | tmp_dext = *dext; | ||
707 | |||
708 | mext_calc_swap_extents(&tmp_dext, &tmp_oext, orig_off, | ||
709 | donor_off, | ||
710 | count - replaced_count); | ||
711 | } | ||
712 | |||
713 | out: | ||
714 | if (orig_path) { | ||
715 | ext4_ext_drop_refs(orig_path); | ||
716 | kfree(orig_path); | ||
717 | } | ||
718 | if (donor_path) { | ||
719 | ext4_ext_drop_refs(donor_path); | ||
720 | kfree(donor_path); | ||
721 | } | ||
722 | |||
723 | mext_double_up_write(orig_inode, donor_inode); | ||
724 | return err; | ||
725 | } | ||
726 | |||
727 | /** | ||
728 | * move_extent_per_page - Move extent data per page | ||
729 | * | ||
730 | * @o_filp: file structure of original file | ||
731 | * @donor_inode: donor inode | ||
732 | * @orig_page_offset: page index on original file | ||
733 | * @data_offset_in_page: block index where data swapping starts | ||
734 | * @block_len_in_page: the number of blocks to be swapped | ||
735 | * @uninit: orig extent is uninitialized or not | ||
736 | * | ||
737 | * Save the data in original inode blocks and replace original inode extents | ||
738 | * with donor inode extents by calling mext_replace_branches(). | ||
739 | * Finally, write out the saved data in new original inode blocks. Return 0 | ||
740 | * on success, or a negative error value on failure. | ||
741 | */ | ||
742 | static int | ||
743 | move_extent_par_page(struct file *o_filp, struct inode *donor_inode, | ||
744 | pgoff_t orig_page_offset, int data_offset_in_page, | ||
745 | int block_len_in_page, int uninit) | ||
746 | { | ||
747 | struct inode *orig_inode = o_filp->f_dentry->d_inode; | ||
748 | struct address_space *mapping = orig_inode->i_mapping; | ||
749 | struct buffer_head *bh; | ||
750 | struct page *page = NULL; | ||
751 | const struct address_space_operations *a_ops = mapping->a_ops; | ||
752 | handle_t *handle; | ||
753 | ext4_lblk_t orig_blk_offset; | ||
754 | long long offs = orig_page_offset << PAGE_CACHE_SHIFT; | ||
755 | unsigned long blocksize = orig_inode->i_sb->s_blocksize; | ||
756 | unsigned int w_flags = 0; | ||
757 | unsigned int tmp_data_len, data_len; | ||
758 | void *fsdata; | ||
759 | int ret, i, jblocks; | ||
760 | int blocks_per_page = PAGE_CACHE_SIZE >> orig_inode->i_blkbits; | ||
761 | |||
762 | /* | ||
763 | * It needs twice the amount of ordinary journal buffers because | ||
764 | * inode and donor_inode may change each different metadata blocks. | ||
765 | */ | ||
766 | jblocks = ext4_writepage_trans_blocks(orig_inode) * 2; | ||
767 | handle = ext4_journal_start(orig_inode, jblocks); | ||
768 | if (IS_ERR(handle)) { | ||
769 | ret = PTR_ERR(handle); | ||
770 | return ret; | ||
771 | } | ||
772 | |||
773 | if (segment_eq(get_fs(), KERNEL_DS)) | ||
774 | w_flags |= AOP_FLAG_UNINTERRUPTIBLE; | ||
775 | |||
776 | orig_blk_offset = orig_page_offset * blocks_per_page + | ||
777 | data_offset_in_page; | ||
778 | |||
779 | /* | ||
780 | * If orig extent is uninitialized one, | ||
781 | * it's not necessary force the page into memory | ||
782 | * and then force it to be written out again. | ||
783 | * Just swap data blocks between orig and donor. | ||
784 | */ | ||
785 | if (uninit) { | ||
786 | ret = mext_replace_branches(handle, orig_inode, | ||
787 | donor_inode, orig_blk_offset, | ||
788 | block_len_in_page); | ||
789 | |||
790 | /* Clear the inode cache not to refer to the old data */ | ||
791 | ext4_ext_invalidate_cache(orig_inode); | ||
792 | ext4_ext_invalidate_cache(donor_inode); | ||
793 | goto out2; | ||
794 | } | ||
795 | |||
796 | offs = (long long)orig_blk_offset << orig_inode->i_blkbits; | ||
797 | |||
798 | /* Calculate data_len */ | ||
799 | if ((orig_blk_offset + block_len_in_page - 1) == | ||
800 | ((orig_inode->i_size - 1) >> orig_inode->i_blkbits)) { | ||
801 | /* Replace the last block */ | ||
802 | tmp_data_len = orig_inode->i_size & (blocksize - 1); | ||
803 | /* | ||
804 | * If data_len equal zero, it shows data_len is multiples of | ||
805 | * blocksize. So we set appropriate value. | ||
806 | */ | ||
807 | if (tmp_data_len == 0) | ||
808 | tmp_data_len = blocksize; | ||
809 | |||
810 | data_len = tmp_data_len + | ||
811 | ((block_len_in_page - 1) << orig_inode->i_blkbits); | ||
812 | } else { | ||
813 | data_len = block_len_in_page << orig_inode->i_blkbits; | ||
814 | } | ||
815 | |||
816 | ret = a_ops->write_begin(o_filp, mapping, offs, data_len, w_flags, | ||
817 | &page, &fsdata); | ||
818 | if (unlikely(ret < 0)) | ||
819 | goto out; | ||
820 | |||
821 | if (!PageUptodate(page)) { | ||
822 | mapping->a_ops->readpage(o_filp, page); | ||
823 | lock_page(page); | ||
824 | } | ||
825 | |||
826 | /* | ||
827 | * try_to_release_page() doesn't call releasepage in writeback mode. | ||
828 | * We should care about the order of writing to the same file | ||
829 | * by multiple move extent processes. | ||
830 | * It needs to call wait_on_page_writeback() to wait for the | ||
831 | * writeback of the page. | ||
832 | */ | ||
833 | if (PageWriteback(page)) | ||
834 | wait_on_page_writeback(page); | ||
835 | |||
836 | /* Release old bh and drop refs */ | ||
837 | try_to_release_page(page, 0); | ||
838 | |||
839 | ret = mext_replace_branches(handle, orig_inode, donor_inode, | ||
840 | orig_blk_offset, block_len_in_page); | ||
841 | if (ret < 0) | ||
842 | goto out; | ||
843 | |||
844 | /* Clear the inode cache not to refer to the old data */ | ||
845 | ext4_ext_invalidate_cache(orig_inode); | ||
846 | ext4_ext_invalidate_cache(donor_inode); | ||
847 | |||
848 | if (!page_has_buffers(page)) | ||
849 | create_empty_buffers(page, 1 << orig_inode->i_blkbits, 0); | ||
850 | |||
851 | bh = page_buffers(page); | ||
852 | for (i = 0; i < data_offset_in_page; i++) | ||
853 | bh = bh->b_this_page; | ||
854 | |||
855 | for (i = 0; i < block_len_in_page; i++) { | ||
856 | ret = ext4_get_block(orig_inode, | ||
857 | (sector_t)(orig_blk_offset + i), bh, 0); | ||
858 | if (ret < 0) | ||
859 | goto out; | ||
860 | |||
861 | if (bh->b_this_page != NULL) | ||
862 | bh = bh->b_this_page; | ||
863 | } | ||
864 | |||
865 | ret = a_ops->write_end(o_filp, mapping, offs, data_len, data_len, | ||
866 | page, fsdata); | ||
867 | page = NULL; | ||
868 | |||
869 | out: | ||
870 | if (unlikely(page)) { | ||
871 | if (PageLocked(page)) | ||
872 | unlock_page(page); | ||
873 | page_cache_release(page); | ||
874 | } | ||
875 | out2: | ||
876 | ext4_journal_stop(handle); | ||
877 | |||
878 | return ret < 0 ? ret : 0; | ||
879 | } | ||
880 | |||
881 | /** | ||
882 | * mext_check_argumants - Check whether move extent can be done | ||
883 | * | ||
884 | * @orig_inode: original inode | ||
885 | * @donor_inode: donor inode | ||
886 | * @orig_start: logical start offset in block for orig | ||
887 | * @donor_start: logical start offset in block for donor | ||
888 | * @len: the number of blocks to be moved | ||
889 | * @moved_len: moved block length | ||
890 | * | ||
891 | * Check the arguments of ext4_move_extents() whether the files can be | ||
892 | * exchanged with each other. | ||
893 | * Return 0 on success, or a negative error value on failure. | ||
894 | */ | ||
895 | static int | ||
896 | mext_check_arguments(struct inode *orig_inode, | ||
897 | struct inode *donor_inode, __u64 orig_start, | ||
898 | __u64 donor_start, __u64 *len, __u64 moved_len) | ||
899 | { | ||
900 | /* Regular file check */ | ||
901 | if (!S_ISREG(orig_inode->i_mode) || !S_ISREG(donor_inode->i_mode)) { | ||
902 | ext4_debug("ext4 move extent: The argument files should be " | ||
903 | "regular file [ino:orig %lu, donor %lu]\n", | ||
904 | orig_inode->i_ino, donor_inode->i_ino); | ||
905 | return -EINVAL; | ||
906 | } | ||
907 | |||
908 | /* Ext4 move extent does not support swapfile */ | ||
909 | if (IS_SWAPFILE(orig_inode) || IS_SWAPFILE(donor_inode)) { | ||
910 | ext4_debug("ext4 move extent: The argument files should " | ||
911 | "not be swapfile [ino:orig %lu, donor %lu]\n", | ||
912 | orig_inode->i_ino, donor_inode->i_ino); | ||
913 | return -EINVAL; | ||
914 | } | ||
915 | |||
916 | /* Files should be in the same ext4 FS */ | ||
917 | if (orig_inode->i_sb != donor_inode->i_sb) { | ||
918 | ext4_debug("ext4 move extent: The argument files " | ||
919 | "should be in same FS [ino:orig %lu, donor %lu]\n", | ||
920 | orig_inode->i_ino, donor_inode->i_ino); | ||
921 | return -EINVAL; | ||
922 | } | ||
923 | |||
924 | /* orig and donor should be different file */ | ||
925 | if (orig_inode->i_ino == donor_inode->i_ino) { | ||
926 | ext4_debug("ext4 move extent: The argument files should not " | ||
927 | "be same file [ino:orig %lu, donor %lu]\n", | ||
928 | orig_inode->i_ino, donor_inode->i_ino); | ||
929 | return -EINVAL; | ||
930 | } | ||
931 | |||
932 | /* Ext4 move extent supports only extent based file */ | ||
933 | if (!(EXT4_I(orig_inode)->i_flags & EXT4_EXTENTS_FL)) { | ||
934 | ext4_debug("ext4 move extent: orig file is not extents " | ||
935 | "based file [ino:orig %lu]\n", orig_inode->i_ino); | ||
936 | return -EOPNOTSUPP; | ||
937 | } else if (!(EXT4_I(donor_inode)->i_flags & EXT4_EXTENTS_FL)) { | ||
938 | ext4_debug("ext4 move extent: donor file is not extents " | ||
939 | "based file [ino:donor %lu]\n", donor_inode->i_ino); | ||
940 | return -EOPNOTSUPP; | ||
941 | } | ||
942 | |||
943 | if ((!orig_inode->i_size) || (!donor_inode->i_size)) { | ||
944 | ext4_debug("ext4 move extent: File size is 0 byte\n"); | ||
945 | return -EINVAL; | ||
946 | } | ||
947 | |||
948 | /* Start offset should be same */ | ||
949 | if (orig_start != donor_start) { | ||
950 | ext4_debug("ext4 move extent: orig and donor's start " | ||
951 | "offset are not same [ino:orig %lu, donor %lu]\n", | ||
952 | orig_inode->i_ino, donor_inode->i_ino); | ||
953 | return -EINVAL; | ||
954 | } | ||
955 | |||
956 | if (moved_len) { | ||
957 | ext4_debug("ext4 move extent: moved_len should be 0 " | ||
958 | "[ino:orig %lu, donor %lu]\n", orig_inode->i_ino, | ||
959 | donor_inode->i_ino); | ||
960 | return -EINVAL; | ||
961 | } | ||
962 | |||
963 | if ((orig_start > MAX_DEFRAG_SIZE) || | ||
964 | (donor_start > MAX_DEFRAG_SIZE) || | ||
965 | (*len > MAX_DEFRAG_SIZE) || | ||
966 | (orig_start + *len > MAX_DEFRAG_SIZE)) { | ||
967 | ext4_debug("ext4 move extent: Can't handle over [%lu] blocks " | ||
968 | "[ino:orig %lu, donor %lu]\n", MAX_DEFRAG_SIZE, | ||
969 | orig_inode->i_ino, donor_inode->i_ino); | ||
970 | return -EINVAL; | ||
971 | } | ||
972 | |||
973 | if (orig_inode->i_size > donor_inode->i_size) { | ||
974 | if (orig_start >= donor_inode->i_size) { | ||
975 | ext4_debug("ext4 move extent: orig start offset " | ||
976 | "[%llu] should be less than donor file size " | ||
977 | "[%lld] [ino:orig %lu, donor_inode %lu]\n", | ||
978 | orig_start, donor_inode->i_size, | ||
979 | orig_inode->i_ino, donor_inode->i_ino); | ||
980 | return -EINVAL; | ||
981 | } | ||
982 | |||
983 | if (orig_start + *len > donor_inode->i_size) { | ||
984 | ext4_debug("ext4 move extent: End offset [%llu] should " | ||
985 | "be less than donor file size [%lld]." | ||
986 | "So adjust length from %llu to %lld " | ||
987 | "[ino:orig %lu, donor %lu]\n", | ||
988 | orig_start + *len, donor_inode->i_size, | ||
989 | *len, donor_inode->i_size - orig_start, | ||
990 | orig_inode->i_ino, donor_inode->i_ino); | ||
991 | *len = donor_inode->i_size - orig_start; | ||
992 | } | ||
993 | } else { | ||
994 | if (orig_start >= orig_inode->i_size) { | ||
995 | ext4_debug("ext4 move extent: start offset [%llu] " | ||
996 | "should be less than original file size " | ||
997 | "[%lld] [inode:orig %lu, donor %lu]\n", | ||
998 | orig_start, orig_inode->i_size, | ||
999 | orig_inode->i_ino, donor_inode->i_ino); | ||
1000 | return -EINVAL; | ||
1001 | } | ||
1002 | |||
1003 | if (orig_start + *len > orig_inode->i_size) { | ||
1004 | ext4_debug("ext4 move extent: Adjust length " | ||
1005 | "from %llu to %lld. Because it should be " | ||
1006 | "less than original file size " | ||
1007 | "[ino:orig %lu, donor %lu]\n", | ||
1008 | *len, orig_inode->i_size - orig_start, | ||
1009 | orig_inode->i_ino, donor_inode->i_ino); | ||
1010 | *len = orig_inode->i_size - orig_start; | ||
1011 | } | ||
1012 | } | ||
1013 | |||
1014 | if (!*len) { | ||
1015 | ext4_debug("ext4 move extent: len shoudld not be 0 " | ||
1016 | "[ino:orig %lu, donor %lu]\n", orig_inode->i_ino, | ||
1017 | donor_inode->i_ino); | ||
1018 | return -EINVAL; | ||
1019 | } | ||
1020 | |||
1021 | return 0; | ||
1022 | } | ||
1023 | |||
1024 | /** | ||
1025 | * mext_inode_double_lock - Lock i_mutex on both @inode1 and @inode2 | ||
1026 | * | ||
1027 | * @inode1: the inode structure | ||
1028 | * @inode2: the inode structure | ||
1029 | * | ||
1030 | * Lock two inodes' i_mutex by i_ino order. This function is moved from | ||
1031 | * fs/inode.c. | ||
1032 | */ | ||
1033 | static void | ||
1034 | mext_inode_double_lock(struct inode *inode1, struct inode *inode2) | ||
1035 | { | ||
1036 | if (inode1 == NULL || inode2 == NULL || inode1 == inode2) { | ||
1037 | if (inode1) | ||
1038 | mutex_lock(&inode1->i_mutex); | ||
1039 | else if (inode2) | ||
1040 | mutex_lock(&inode2->i_mutex); | ||
1041 | return; | ||
1042 | } | ||
1043 | |||
1044 | if (inode1->i_ino < inode2->i_ino) { | ||
1045 | mutex_lock_nested(&inode1->i_mutex, I_MUTEX_PARENT); | ||
1046 | mutex_lock_nested(&inode2->i_mutex, I_MUTEX_CHILD); | ||
1047 | } else { | ||
1048 | mutex_lock_nested(&inode2->i_mutex, I_MUTEX_PARENT); | ||
1049 | mutex_lock_nested(&inode1->i_mutex, I_MUTEX_CHILD); | ||
1050 | } | ||
1051 | } | ||
1052 | |||
1053 | /** | ||
1054 | * mext_inode_double_unlock - Release i_mutex on both @inode1 and @inode2 | ||
1055 | * | ||
1056 | * @inode1: the inode that is released first | ||
1057 | * @inode2: the inode that is released second | ||
1058 | * | ||
1059 | * This function is moved from fs/inode.c. | ||
1060 | */ | ||
1061 | |||
1062 | static void | ||
1063 | mext_inode_double_unlock(struct inode *inode1, struct inode *inode2) | ||
1064 | { | ||
1065 | if (inode1) | ||
1066 | mutex_unlock(&inode1->i_mutex); | ||
1067 | |||
1068 | if (inode2 && inode2 != inode1) | ||
1069 | mutex_unlock(&inode2->i_mutex); | ||
1070 | } | ||
1071 | |||
1072 | /** | ||
1073 | * ext4_move_extents - Exchange the specified range of a file | ||
1074 | * | ||
1075 | * @o_filp: file structure of the original file | ||
1076 | * @d_filp: file structure of the donor file | ||
1077 | * @orig_start: start offset in block for orig | ||
1078 | * @donor_start: start offset in block for donor | ||
1079 | * @len: the number of blocks to be moved | ||
1080 | * @moved_len: moved block length | ||
1081 | * | ||
1082 | * This function returns 0 and moved block length is set in moved_len | ||
1083 | * if succeed, otherwise returns error value. | ||
1084 | * | ||
1085 | * Note: ext4_move_extents() proceeds the following order. | ||
1086 | * 1:ext4_move_extents() calculates the last block number of moving extent | ||
1087 | * function by the start block number (orig_start) and the number of blocks | ||
1088 | * to be moved (len) specified as arguments. | ||
1089 | * If the {orig, donor}_start points a hole, the extent's start offset | ||
1090 | * pointed by ext_cur (current extent), holecheck_path, orig_path are set | ||
1091 | * after hole behind. | ||
1092 | * 2:Continue step 3 to step 5, until the holecheck_path points to last_extent | ||
1093 | * or the ext_cur exceeds the block_end which is last logical block number. | ||
1094 | * 3:To get the length of continues area, call mext_next_extent() | ||
1095 | * specified with the ext_cur (initial value is holecheck_path) re-cursive, | ||
1096 | * until find un-continuous extent, the start logical block number exceeds | ||
1097 | * the block_end or the extent points to the last extent. | ||
1098 | * 4:Exchange the original inode data with donor inode data | ||
1099 | * from orig_page_offset to seq_end_page. | ||
1100 | * The start indexes of data are specified as arguments. | ||
1101 | * That of the original inode is orig_page_offset, | ||
1102 | * and the donor inode is also orig_page_offset | ||
1103 | * (To easily handle blocksize != pagesize case, the offset for the | ||
1104 | * donor inode is block unit). | ||
1105 | * 5:Update holecheck_path and orig_path to points a next proceeding extent, | ||
1106 | * then returns to step 2. | ||
1107 | * 6:Release holecheck_path, orig_path and set the len to moved_len | ||
1108 | * which shows the number of moved blocks. | ||
1109 | * The moved_len is useful for the command to calculate the file offset | ||
1110 | * for starting next move extent ioctl. | ||
1111 | * 7:Return 0 on success, or a negative error value on failure. | ||
1112 | */ | ||
1113 | int | ||
1114 | ext4_move_extents(struct file *o_filp, struct file *d_filp, | ||
1115 | __u64 orig_start, __u64 donor_start, __u64 len, | ||
1116 | __u64 *moved_len) | ||
1117 | { | ||
1118 | struct inode *orig_inode = o_filp->f_dentry->d_inode; | ||
1119 | struct inode *donor_inode = d_filp->f_dentry->d_inode; | ||
1120 | struct ext4_ext_path *orig_path = NULL, *holecheck_path = NULL; | ||
1121 | struct ext4_extent *ext_prev, *ext_cur, *ext_dummy; | ||
1122 | ext4_lblk_t block_start = orig_start; | ||
1123 | ext4_lblk_t block_end, seq_start, add_blocks, file_end, seq_blocks = 0; | ||
1124 | ext4_lblk_t rest_blocks; | ||
1125 | pgoff_t orig_page_offset = 0, seq_end_page; | ||
1126 | int ret, depth, last_extent = 0; | ||
1127 | int blocks_per_page = PAGE_CACHE_SIZE >> orig_inode->i_blkbits; | ||
1128 | int data_offset_in_page; | ||
1129 | int block_len_in_page; | ||
1130 | int uninit; | ||
1131 | |||
1132 | /* protect orig and donor against a truncate */ | ||
1133 | mext_inode_double_lock(orig_inode, donor_inode); | ||
1134 | |||
1135 | mext_double_down_read(orig_inode, donor_inode); | ||
1136 | /* Check the filesystem environment whether move_extent can be done */ | ||
1137 | ret = mext_check_arguments(orig_inode, donor_inode, orig_start, | ||
1138 | donor_start, &len, *moved_len); | ||
1139 | mext_double_up_read(orig_inode, donor_inode); | ||
1140 | if (ret) | ||
1141 | goto out2; | ||
1142 | |||
1143 | file_end = (i_size_read(orig_inode) - 1) >> orig_inode->i_blkbits; | ||
1144 | block_end = block_start + len - 1; | ||
1145 | if (file_end < block_end) | ||
1146 | len -= block_end - file_end; | ||
1147 | |||
1148 | get_ext_path(orig_path, orig_inode, block_start, ret); | ||
1149 | if (orig_path == NULL) | ||
1150 | goto out2; | ||
1151 | |||
1152 | /* Get path structure to check the hole */ | ||
1153 | get_ext_path(holecheck_path, orig_inode, block_start, ret); | ||
1154 | if (holecheck_path == NULL) | ||
1155 | goto out; | ||
1156 | |||
1157 | depth = ext_depth(orig_inode); | ||
1158 | ext_cur = holecheck_path[depth].p_ext; | ||
1159 | if (ext_cur == NULL) { | ||
1160 | ret = -EINVAL; | ||
1161 | goto out; | ||
1162 | } | ||
1163 | |||
1164 | /* | ||
1165 | * Get proper extent whose ee_block is beyond block_start | ||
1166 | * if block_start was within the hole. | ||
1167 | */ | ||
1168 | if (le32_to_cpu(ext_cur->ee_block) + | ||
1169 | ext4_ext_get_actual_len(ext_cur) - 1 < block_start) { | ||
1170 | last_extent = mext_next_extent(orig_inode, | ||
1171 | holecheck_path, &ext_cur); | ||
1172 | if (last_extent < 0) { | ||
1173 | ret = last_extent; | ||
1174 | goto out; | ||
1175 | } | ||
1176 | last_extent = mext_next_extent(orig_inode, orig_path, | ||
1177 | &ext_dummy); | ||
1178 | if (last_extent < 0) { | ||
1179 | ret = last_extent; | ||
1180 | goto out; | ||
1181 | } | ||
1182 | } | ||
1183 | seq_start = block_start; | ||
1184 | |||
1185 | /* No blocks within the specified range. */ | ||
1186 | if (le32_to_cpu(ext_cur->ee_block) > block_end) { | ||
1187 | ext4_debug("ext4 move extent: The specified range of file " | ||
1188 | "may be the hole\n"); | ||
1189 | ret = -EINVAL; | ||
1190 | goto out; | ||
1191 | } | ||
1192 | |||
1193 | /* Adjust start blocks */ | ||
1194 | add_blocks = min(le32_to_cpu(ext_cur->ee_block) + | ||
1195 | ext4_ext_get_actual_len(ext_cur), block_end + 1) - | ||
1196 | max(le32_to_cpu(ext_cur->ee_block), block_start); | ||
1197 | |||
1198 | while (!last_extent && le32_to_cpu(ext_cur->ee_block) <= block_end) { | ||
1199 | seq_blocks += add_blocks; | ||
1200 | |||
1201 | /* Adjust tail blocks */ | ||
1202 | if (seq_start + seq_blocks - 1 > block_end) | ||
1203 | seq_blocks = block_end - seq_start + 1; | ||
1204 | |||
1205 | ext_prev = ext_cur; | ||
1206 | last_extent = mext_next_extent(orig_inode, holecheck_path, | ||
1207 | &ext_cur); | ||
1208 | if (last_extent < 0) { | ||
1209 | ret = last_extent; | ||
1210 | break; | ||
1211 | } | ||
1212 | add_blocks = ext4_ext_get_actual_len(ext_cur); | ||
1213 | |||
1214 | /* | ||
1215 | * Extend the length of contiguous block (seq_blocks) | ||
1216 | * if extents are contiguous. | ||
1217 | */ | ||
1218 | if (ext4_can_extents_be_merged(orig_inode, | ||
1219 | ext_prev, ext_cur) && | ||
1220 | block_end >= le32_to_cpu(ext_cur->ee_block) && | ||
1221 | !last_extent) | ||
1222 | continue; | ||
1223 | |||
1224 | /* Is original extent is uninitialized */ | ||
1225 | uninit = ext4_ext_is_uninitialized(ext_prev); | ||
1226 | |||
1227 | data_offset_in_page = seq_start % blocks_per_page; | ||
1228 | |||
1229 | /* | ||
1230 | * Calculate data blocks count that should be swapped | ||
1231 | * at the first page. | ||
1232 | */ | ||
1233 | if (data_offset_in_page + seq_blocks > blocks_per_page) { | ||
1234 | /* Swapped blocks are across pages */ | ||
1235 | block_len_in_page = | ||
1236 | blocks_per_page - data_offset_in_page; | ||
1237 | } else { | ||
1238 | /* Swapped blocks are in a page */ | ||
1239 | block_len_in_page = seq_blocks; | ||
1240 | } | ||
1241 | |||
1242 | orig_page_offset = seq_start >> | ||
1243 | (PAGE_CACHE_SHIFT - orig_inode->i_blkbits); | ||
1244 | seq_end_page = (seq_start + seq_blocks - 1) >> | ||
1245 | (PAGE_CACHE_SHIFT - orig_inode->i_blkbits); | ||
1246 | seq_start = le32_to_cpu(ext_cur->ee_block); | ||
1247 | rest_blocks = seq_blocks; | ||
1248 | |||
1249 | /* Discard preallocations of two inodes */ | ||
1250 | down_write(&EXT4_I(orig_inode)->i_data_sem); | ||
1251 | ext4_discard_preallocations(orig_inode); | ||
1252 | up_write(&EXT4_I(orig_inode)->i_data_sem); | ||
1253 | |||
1254 | down_write(&EXT4_I(donor_inode)->i_data_sem); | ||
1255 | ext4_discard_preallocations(donor_inode); | ||
1256 | up_write(&EXT4_I(donor_inode)->i_data_sem); | ||
1257 | |||
1258 | while (orig_page_offset <= seq_end_page) { | ||
1259 | |||
1260 | /* Swap original branches with new branches */ | ||
1261 | ret = move_extent_par_page(o_filp, donor_inode, | ||
1262 | orig_page_offset, | ||
1263 | data_offset_in_page, | ||
1264 | block_len_in_page, uninit); | ||
1265 | if (ret < 0) | ||
1266 | goto out; | ||
1267 | orig_page_offset++; | ||
1268 | /* Count how many blocks we have exchanged */ | ||
1269 | *moved_len += block_len_in_page; | ||
1270 | BUG_ON(*moved_len > len); | ||
1271 | |||
1272 | data_offset_in_page = 0; | ||
1273 | rest_blocks -= block_len_in_page; | ||
1274 | if (rest_blocks > blocks_per_page) | ||
1275 | block_len_in_page = blocks_per_page; | ||
1276 | else | ||
1277 | block_len_in_page = rest_blocks; | ||
1278 | } | ||
1279 | |||
1280 | /* Decrease buffer counter */ | ||
1281 | if (holecheck_path) | ||
1282 | ext4_ext_drop_refs(holecheck_path); | ||
1283 | get_ext_path(holecheck_path, orig_inode, | ||
1284 | seq_start, ret); | ||
1285 | if (holecheck_path == NULL) | ||
1286 | break; | ||
1287 | depth = holecheck_path->p_depth; | ||
1288 | |||
1289 | /* Decrease buffer counter */ | ||
1290 | if (orig_path) | ||
1291 | ext4_ext_drop_refs(orig_path); | ||
1292 | get_ext_path(orig_path, orig_inode, seq_start, ret); | ||
1293 | if (orig_path == NULL) | ||
1294 | break; | ||
1295 | |||
1296 | ext_cur = holecheck_path[depth].p_ext; | ||
1297 | add_blocks = ext4_ext_get_actual_len(ext_cur); | ||
1298 | seq_blocks = 0; | ||
1299 | |||
1300 | } | ||
1301 | out: | ||
1302 | if (orig_path) { | ||
1303 | ext4_ext_drop_refs(orig_path); | ||
1304 | kfree(orig_path); | ||
1305 | } | ||
1306 | if (holecheck_path) { | ||
1307 | ext4_ext_drop_refs(holecheck_path); | ||
1308 | kfree(holecheck_path); | ||
1309 | } | ||
1310 | out2: | ||
1311 | mext_inode_double_unlock(orig_inode, donor_inode); | ||
1312 | |||
1313 | if (ret) | ||
1314 | return ret; | ||
1315 | |||
1316 | /* All of the specified blocks must be exchanged in succeed */ | ||
1317 | BUG_ON(*moved_len != len); | ||
1318 | |||
1319 | return 0; | ||
1320 | } | ||
diff --git a/fs/ext4/namei.c b/fs/ext4/namei.c index 07eb6649e4fa..de04013d16ff 100644 --- a/fs/ext4/namei.c +++ b/fs/ext4/namei.c | |||
@@ -1782,7 +1782,7 @@ retry: | |||
1782 | if (IS_DIRSYNC(dir)) | 1782 | if (IS_DIRSYNC(dir)) |
1783 | ext4_handle_sync(handle); | 1783 | ext4_handle_sync(handle); |
1784 | 1784 | ||
1785 | inode = ext4_new_inode (handle, dir, mode); | 1785 | inode = ext4_new_inode(handle, dir, mode, &dentry->d_name, 0); |
1786 | err = PTR_ERR(inode); | 1786 | err = PTR_ERR(inode); |
1787 | if (!IS_ERR(inode)) { | 1787 | if (!IS_ERR(inode)) { |
1788 | inode->i_op = &ext4_file_inode_operations; | 1788 | inode->i_op = &ext4_file_inode_operations; |
@@ -1816,7 +1816,7 @@ retry: | |||
1816 | if (IS_DIRSYNC(dir)) | 1816 | if (IS_DIRSYNC(dir)) |
1817 | ext4_handle_sync(handle); | 1817 | ext4_handle_sync(handle); |
1818 | 1818 | ||
1819 | inode = ext4_new_inode(handle, dir, mode); | 1819 | inode = ext4_new_inode(handle, dir, mode, &dentry->d_name, 0); |
1820 | err = PTR_ERR(inode); | 1820 | err = PTR_ERR(inode); |
1821 | if (!IS_ERR(inode)) { | 1821 | if (!IS_ERR(inode)) { |
1822 | init_special_inode(inode, inode->i_mode, rdev); | 1822 | init_special_inode(inode, inode->i_mode, rdev); |
@@ -1853,7 +1853,8 @@ retry: | |||
1853 | if (IS_DIRSYNC(dir)) | 1853 | if (IS_DIRSYNC(dir)) |
1854 | ext4_handle_sync(handle); | 1854 | ext4_handle_sync(handle); |
1855 | 1855 | ||
1856 | inode = ext4_new_inode(handle, dir, S_IFDIR | mode); | 1856 | inode = ext4_new_inode(handle, dir, S_IFDIR | mode, |
1857 | &dentry->d_name, 0); | ||
1857 | err = PTR_ERR(inode); | 1858 | err = PTR_ERR(inode); |
1858 | if (IS_ERR(inode)) | 1859 | if (IS_ERR(inode)) |
1859 | goto out_stop; | 1860 | goto out_stop; |
@@ -2264,7 +2265,8 @@ retry: | |||
2264 | if (IS_DIRSYNC(dir)) | 2265 | if (IS_DIRSYNC(dir)) |
2265 | ext4_handle_sync(handle); | 2266 | ext4_handle_sync(handle); |
2266 | 2267 | ||
2267 | inode = ext4_new_inode(handle, dir, S_IFLNK|S_IRWXUGO); | 2268 | inode = ext4_new_inode(handle, dir, S_IFLNK|S_IRWXUGO, |
2269 | &dentry->d_name, 0); | ||
2268 | err = PTR_ERR(inode); | 2270 | err = PTR_ERR(inode); |
2269 | if (IS_ERR(inode)) | 2271 | if (IS_ERR(inode)) |
2270 | goto out_stop; | 2272 | goto out_stop; |
diff --git a/fs/ext4/resize.c b/fs/ext4/resize.c index 27eb289eea37..68b0351fc647 100644 --- a/fs/ext4/resize.c +++ b/fs/ext4/resize.c | |||
@@ -1002,7 +1002,7 @@ int ext4_group_extend(struct super_block *sb, struct ext4_super_block *es, | |||
1002 | " too large to resize to %llu blocks safely\n", | 1002 | " too large to resize to %llu blocks safely\n", |
1003 | sb->s_id, n_blocks_count); | 1003 | sb->s_id, n_blocks_count); |
1004 | if (sizeof(sector_t) < 8) | 1004 | if (sizeof(sector_t) < 8) |
1005 | ext4_warning(sb, __func__, "CONFIG_LBD not enabled"); | 1005 | ext4_warning(sb, __func__, "CONFIG_LBDAF not enabled"); |
1006 | return -EINVAL; | 1006 | return -EINVAL; |
1007 | } | 1007 | } |
1008 | 1008 | ||
diff --git a/fs/ext4/super.c b/fs/ext4/super.c index 012c4251397e..8bb9e2d3e4b8 100644 --- a/fs/ext4/super.c +++ b/fs/ext4/super.c | |||
@@ -37,7 +37,6 @@ | |||
37 | #include <linux/seq_file.h> | 37 | #include <linux/seq_file.h> |
38 | #include <linux/proc_fs.h> | 38 | #include <linux/proc_fs.h> |
39 | #include <linux/ctype.h> | 39 | #include <linux/ctype.h> |
40 | #include <linux/marker.h> | ||
41 | #include <linux/log2.h> | 40 | #include <linux/log2.h> |
42 | #include <linux/crc16.h> | 41 | #include <linux/crc16.h> |
43 | #include <asm/uaccess.h> | 42 | #include <asm/uaccess.h> |
@@ -47,6 +46,9 @@ | |||
47 | #include "xattr.h" | 46 | #include "xattr.h" |
48 | #include "acl.h" | 47 | #include "acl.h" |
49 | 48 | ||
49 | #define CREATE_TRACE_POINTS | ||
50 | #include <trace/events/ext4.h> | ||
51 | |||
50 | static int default_mb_history_length = 1000; | 52 | static int default_mb_history_length = 1000; |
51 | 53 | ||
52 | module_param_named(default_mb_history_length, default_mb_history_length, | 54 | module_param_named(default_mb_history_length, default_mb_history_length, |
@@ -301,7 +303,7 @@ static void ext4_handle_error(struct super_block *sb) | |||
301 | if (!test_opt(sb, ERRORS_CONT)) { | 303 | if (!test_opt(sb, ERRORS_CONT)) { |
302 | journal_t *journal = EXT4_SB(sb)->s_journal; | 304 | journal_t *journal = EXT4_SB(sb)->s_journal; |
303 | 305 | ||
304 | EXT4_SB(sb)->s_mount_opt |= EXT4_MOUNT_ABORT; | 306 | EXT4_SB(sb)->s_mount_flags |= EXT4_MF_FS_ABORTED; |
305 | if (journal) | 307 | if (journal) |
306 | jbd2_journal_abort(journal, -EIO); | 308 | jbd2_journal_abort(journal, -EIO); |
307 | } | 309 | } |
@@ -414,7 +416,7 @@ void ext4_abort(struct super_block *sb, const char *function, | |||
414 | ext4_msg(sb, KERN_CRIT, "Remounting filesystem read-only"); | 416 | ext4_msg(sb, KERN_CRIT, "Remounting filesystem read-only"); |
415 | EXT4_SB(sb)->s_mount_state |= EXT4_ERROR_FS; | 417 | EXT4_SB(sb)->s_mount_state |= EXT4_ERROR_FS; |
416 | sb->s_flags |= MS_RDONLY; | 418 | sb->s_flags |= MS_RDONLY; |
417 | EXT4_SB(sb)->s_mount_opt |= EXT4_MOUNT_ABORT; | 419 | EXT4_SB(sb)->s_mount_flags |= EXT4_MF_FS_ABORTED; |
418 | if (EXT4_SB(sb)->s_journal) | 420 | if (EXT4_SB(sb)->s_journal) |
419 | jbd2_journal_abort(EXT4_SB(sb)->s_journal, -EIO); | 421 | jbd2_journal_abort(EXT4_SB(sb)->s_journal, -EIO); |
420 | } | 422 | } |
@@ -1474,7 +1476,7 @@ set_qf_format: | |||
1474 | break; | 1476 | break; |
1475 | #endif | 1477 | #endif |
1476 | case Opt_abort: | 1478 | case Opt_abort: |
1477 | set_opt(sbi->s_mount_opt, ABORT); | 1479 | sbi->s_mount_flags |= EXT4_MF_FS_ABORTED; |
1478 | break; | 1480 | break; |
1479 | case Opt_nobarrier: | 1481 | case Opt_nobarrier: |
1480 | clear_opt(sbi->s_mount_opt, BARRIER); | 1482 | clear_opt(sbi->s_mount_opt, BARRIER); |
@@ -1653,7 +1655,7 @@ static int ext4_setup_super(struct super_block *sb, struct ext4_super_block *es, | |||
1653 | ext4_commit_super(sb, 1); | 1655 | ext4_commit_super(sb, 1); |
1654 | if (test_opt(sb, DEBUG)) | 1656 | if (test_opt(sb, DEBUG)) |
1655 | printk(KERN_INFO "[EXT4 FS bs=%lu, gc=%u, " | 1657 | printk(KERN_INFO "[EXT4 FS bs=%lu, gc=%u, " |
1656 | "bpg=%lu, ipg=%lu, mo=%04lx]\n", | 1658 | "bpg=%lu, ipg=%lu, mo=%04x]\n", |
1657 | sb->s_blocksize, | 1659 | sb->s_blocksize, |
1658 | sbi->s_groups_count, | 1660 | sbi->s_groups_count, |
1659 | EXT4_BLOCKS_PER_GROUP(sb), | 1661 | EXT4_BLOCKS_PER_GROUP(sb), |
@@ -1957,7 +1959,7 @@ static loff_t ext4_max_size(int blkbits, int has_huge_files) | |||
1957 | /* small i_blocks in vfs inode? */ | 1959 | /* small i_blocks in vfs inode? */ |
1958 | if (!has_huge_files || sizeof(blkcnt_t) < sizeof(u64)) { | 1960 | if (!has_huge_files || sizeof(blkcnt_t) < sizeof(u64)) { |
1959 | /* | 1961 | /* |
1960 | * CONFIG_LBD is not enabled implies the inode | 1962 | * CONFIG_LBDAF is not enabled implies the inode |
1961 | * i_block represent total blocks in 512 bytes | 1963 | * i_block represent total blocks in 512 bytes |
1962 | * 32 == size of vfs inode i_blocks * 8 | 1964 | * 32 == size of vfs inode i_blocks * 8 |
1963 | */ | 1965 | */ |
@@ -2000,7 +2002,7 @@ static loff_t ext4_max_bitmap_size(int bits, int has_huge_files) | |||
2000 | 2002 | ||
2001 | if (!has_huge_files || sizeof(blkcnt_t) < sizeof(u64)) { | 2003 | if (!has_huge_files || sizeof(blkcnt_t) < sizeof(u64)) { |
2002 | /* | 2004 | /* |
2003 | * !has_huge_files or CONFIG_LBD not enabled implies that | 2005 | * !has_huge_files or CONFIG_LBDAF not enabled implies that |
2004 | * the inode i_block field represents total file blocks in | 2006 | * the inode i_block field represents total file blocks in |
2005 | * 2^32 512-byte sectors == size of vfs inode i_blocks * 8 | 2007 | * 2^32 512-byte sectors == size of vfs inode i_blocks * 8 |
2006 | */ | 2008 | */ |
@@ -2204,6 +2206,7 @@ EXT4_RO_ATTR(session_write_kbytes); | |||
2204 | EXT4_RO_ATTR(lifetime_write_kbytes); | 2206 | EXT4_RO_ATTR(lifetime_write_kbytes); |
2205 | EXT4_ATTR_OFFSET(inode_readahead_blks, 0644, sbi_ui_show, | 2207 | EXT4_ATTR_OFFSET(inode_readahead_blks, 0644, sbi_ui_show, |
2206 | inode_readahead_blks_store, s_inode_readahead_blks); | 2208 | inode_readahead_blks_store, s_inode_readahead_blks); |
2209 | EXT4_RW_ATTR_SBI_UI(inode_goal, s_inode_goal); | ||
2207 | EXT4_RW_ATTR_SBI_UI(mb_stats, s_mb_stats); | 2210 | EXT4_RW_ATTR_SBI_UI(mb_stats, s_mb_stats); |
2208 | EXT4_RW_ATTR_SBI_UI(mb_max_to_scan, s_mb_max_to_scan); | 2211 | EXT4_RW_ATTR_SBI_UI(mb_max_to_scan, s_mb_max_to_scan); |
2209 | EXT4_RW_ATTR_SBI_UI(mb_min_to_scan, s_mb_min_to_scan); | 2212 | EXT4_RW_ATTR_SBI_UI(mb_min_to_scan, s_mb_min_to_scan); |
@@ -2216,6 +2219,7 @@ static struct attribute *ext4_attrs[] = { | |||
2216 | ATTR_LIST(session_write_kbytes), | 2219 | ATTR_LIST(session_write_kbytes), |
2217 | ATTR_LIST(lifetime_write_kbytes), | 2220 | ATTR_LIST(lifetime_write_kbytes), |
2218 | ATTR_LIST(inode_readahead_blks), | 2221 | ATTR_LIST(inode_readahead_blks), |
2222 | ATTR_LIST(inode_goal), | ||
2219 | ATTR_LIST(mb_stats), | 2223 | ATTR_LIST(mb_stats), |
2220 | ATTR_LIST(mb_max_to_scan), | 2224 | ATTR_LIST(mb_max_to_scan), |
2221 | ATTR_LIST(mb_min_to_scan), | 2225 | ATTR_LIST(mb_min_to_scan), |
@@ -2436,13 +2440,13 @@ static int ext4_fill_super(struct super_block *sb, void *data, int silent) | |||
2436 | if (has_huge_files) { | 2440 | if (has_huge_files) { |
2437 | /* | 2441 | /* |
2438 | * Large file size enabled file system can only be | 2442 | * Large file size enabled file system can only be |
2439 | * mount if kernel is build with CONFIG_LBD | 2443 | * mount if kernel is build with CONFIG_LBDAF |
2440 | */ | 2444 | */ |
2441 | if (sizeof(root->i_blocks) < sizeof(u64) && | 2445 | if (sizeof(root->i_blocks) < sizeof(u64) && |
2442 | !(sb->s_flags & MS_RDONLY)) { | 2446 | !(sb->s_flags & MS_RDONLY)) { |
2443 | ext4_msg(sb, KERN_ERR, "Filesystem with huge " | 2447 | ext4_msg(sb, KERN_ERR, "Filesystem with huge " |
2444 | "files cannot be mounted read-write " | 2448 | "files cannot be mounted read-write " |
2445 | "without CONFIG_LBD"); | 2449 | "without CONFIG_LBDAF"); |
2446 | goto failed_mount; | 2450 | goto failed_mount; |
2447 | } | 2451 | } |
2448 | } | 2452 | } |
@@ -2566,7 +2570,7 @@ static int ext4_fill_super(struct super_block *sb, void *data, int silent) | |||
2566 | ext4_msg(sb, KERN_ERR, "filesystem" | 2570 | ext4_msg(sb, KERN_ERR, "filesystem" |
2567 | " too large to mount safely"); | 2571 | " too large to mount safely"); |
2568 | if (sizeof(sector_t) < 8) | 2572 | if (sizeof(sector_t) < 8) |
2569 | ext4_msg(sb, KERN_WARNING, "CONFIG_LBD not enabled"); | 2573 | ext4_msg(sb, KERN_WARNING, "CONFIG_LBDAF not enabled"); |
2570 | goto failed_mount; | 2574 | goto failed_mount; |
2571 | } | 2575 | } |
2572 | 2576 | ||
@@ -3346,7 +3350,7 @@ static int ext4_sync_fs(struct super_block *sb, int wait) | |||
3346 | int ret = 0; | 3350 | int ret = 0; |
3347 | tid_t target; | 3351 | tid_t target; |
3348 | 3352 | ||
3349 | trace_mark(ext4_sync_fs, "dev %s wait %d", sb->s_id, wait); | 3353 | trace_ext4_sync_fs(sb, wait); |
3350 | if (jbd2_journal_start_commit(EXT4_SB(sb)->s_journal, &target)) { | 3354 | if (jbd2_journal_start_commit(EXT4_SB(sb)->s_journal, &target)) { |
3351 | if (wait) | 3355 | if (wait) |
3352 | jbd2_log_wait_commit(EXT4_SB(sb)->s_journal, target); | 3356 | jbd2_log_wait_commit(EXT4_SB(sb)->s_journal, target); |
@@ -3450,7 +3454,7 @@ static int ext4_remount(struct super_block *sb, int *flags, char *data) | |||
3450 | goto restore_opts; | 3454 | goto restore_opts; |
3451 | } | 3455 | } |
3452 | 3456 | ||
3453 | if (sbi->s_mount_opt & EXT4_MOUNT_ABORT) | 3457 | if (sbi->s_mount_flags & EXT4_MF_FS_ABORTED) |
3454 | ext4_abort(sb, __func__, "Abort forced by user"); | 3458 | ext4_abort(sb, __func__, "Abort forced by user"); |
3455 | 3459 | ||
3456 | sb->s_flags = (sb->s_flags & ~MS_POSIXACL) | | 3460 | sb->s_flags = (sb->s_flags & ~MS_POSIXACL) | |
@@ -3465,7 +3469,7 @@ static int ext4_remount(struct super_block *sb, int *flags, char *data) | |||
3465 | 3469 | ||
3466 | if ((*flags & MS_RDONLY) != (sb->s_flags & MS_RDONLY) || | 3470 | if ((*flags & MS_RDONLY) != (sb->s_flags & MS_RDONLY) || |
3467 | n_blocks_count > ext4_blocks_count(es)) { | 3471 | n_blocks_count > ext4_blocks_count(es)) { |
3468 | if (sbi->s_mount_opt & EXT4_MOUNT_ABORT) { | 3472 | if (sbi->s_mount_flags & EXT4_MF_FS_ABORTED) { |
3469 | err = -EROFS; | 3473 | err = -EROFS; |
3470 | goto restore_opts; | 3474 | goto restore_opts; |
3471 | } | 3475 | } |
diff --git a/fs/fat/inode.c b/fs/fat/inode.c index 304b411cb8bc..8970d8c49bb0 100644 --- a/fs/fat/inode.c +++ b/fs/fat/inode.c | |||
@@ -966,7 +966,7 @@ static int parse_options(char *options, int is_vfat, int silent, int *debug, | |||
966 | 966 | ||
967 | opts->fs_uid = current_uid(); | 967 | opts->fs_uid = current_uid(); |
968 | opts->fs_gid = current_gid(); | 968 | opts->fs_gid = current_gid(); |
969 | opts->fs_fmask = current_umask(); | 969 | opts->fs_fmask = opts->fs_dmask = current_umask(); |
970 | opts->allow_utime = -1; | 970 | opts->allow_utime = -1; |
971 | opts->codepage = fat_default_codepage; | 971 | opts->codepage = fat_default_codepage; |
972 | opts->iocharset = fat_default_iocharset; | 972 | opts->iocharset = fat_default_iocharset; |
diff --git a/fs/gfs2/Kconfig b/fs/gfs2/Kconfig index cad957cdb1e5..5971359d2090 100644 --- a/fs/gfs2/Kconfig +++ b/fs/gfs2/Kconfig | |||
@@ -1,6 +1,6 @@ | |||
1 | config GFS2_FS | 1 | config GFS2_FS |
2 | tristate "GFS2 file system support" | 2 | tristate "GFS2 file system support" |
3 | depends on EXPERIMENTAL && (64BIT || LBD) | 3 | depends on EXPERIMENTAL && (64BIT || LBDAF) |
4 | select DLM if GFS2_FS_LOCKING_DLM | 4 | select DLM if GFS2_FS_LOCKING_DLM |
5 | select CONFIGFS_FS if GFS2_FS_LOCKING_DLM | 5 | select CONFIGFS_FS if GFS2_FS_LOCKING_DLM |
6 | select SYSFS if GFS2_FS_LOCKING_DLM | 6 | select SYSFS if GFS2_FS_LOCKING_DLM |
diff --git a/fs/inode.c b/fs/inode.c index f643be565df8..04c785bb63c3 100644 --- a/fs/inode.c +++ b/fs/inode.c | |||
@@ -665,12 +665,17 @@ void unlock_new_inode(struct inode *inode) | |||
665 | if (inode->i_mode & S_IFDIR) { | 665 | if (inode->i_mode & S_IFDIR) { |
666 | struct file_system_type *type = inode->i_sb->s_type; | 666 | struct file_system_type *type = inode->i_sb->s_type; |
667 | 667 | ||
668 | /* | 668 | /* Set new key only if filesystem hasn't already changed it */ |
669 | * ensure nobody is actually holding i_mutex | 669 | if (!lockdep_match_class(&inode->i_mutex, |
670 | */ | 670 | &type->i_mutex_key)) { |
671 | mutex_destroy(&inode->i_mutex); | 671 | /* |
672 | mutex_init(&inode->i_mutex); | 672 | * ensure nobody is actually holding i_mutex |
673 | lockdep_set_class(&inode->i_mutex, &type->i_mutex_dir_key); | 673 | */ |
674 | mutex_destroy(&inode->i_mutex); | ||
675 | mutex_init(&inode->i_mutex); | ||
676 | lockdep_set_class(&inode->i_mutex, | ||
677 | &type->i_mutex_dir_key); | ||
678 | } | ||
674 | } | 679 | } |
675 | #endif | 680 | #endif |
676 | /* | 681 | /* |
diff --git a/fs/isofs/dir.c b/fs/isofs/dir.c index 2f0dc5a14633..8ba5441063be 100644 --- a/fs/isofs/dir.c +++ b/fs/isofs/dir.c | |||
@@ -195,9 +195,8 @@ static int do_isofs_readdir(struct inode *inode, struct file *filp, | |||
195 | * Do not report hidden files if so instructed, or associated | 195 | * Do not report hidden files if so instructed, or associated |
196 | * files unless instructed to do so | 196 | * files unless instructed to do so |
197 | */ | 197 | */ |
198 | if ((sbi->s_hide == 'y' && | 198 | if ((sbi->s_hide && (de->flags[-sbi->s_high_sierra] & 1)) || |
199 | (de->flags[-sbi->s_high_sierra] & 1)) || | 199 | (!sbi->s_showassoc && |
200 | (sbi->s_showassoc =='n' && | ||
201 | (de->flags[-sbi->s_high_sierra] & 4))) { | 200 | (de->flags[-sbi->s_high_sierra] & 4))) { |
202 | filp->f_pos += de_len; | 201 | filp->f_pos += de_len; |
203 | continue; | 202 | continue; |
diff --git a/fs/isofs/inode.c b/fs/isofs/inode.c index 068b34b5a107..58a7963e168a 100644 --- a/fs/isofs/inode.c +++ b/fs/isofs/inode.c | |||
@@ -141,13 +141,17 @@ static const struct dentry_operations isofs_dentry_ops[] = { | |||
141 | }; | 141 | }; |
142 | 142 | ||
143 | struct iso9660_options{ | 143 | struct iso9660_options{ |
144 | char map; | 144 | unsigned int rock:1; |
145 | char rock; | 145 | unsigned int cruft:1; |
146 | unsigned int hide:1; | ||
147 | unsigned int showassoc:1; | ||
148 | unsigned int nocompress:1; | ||
149 | unsigned int overriderockperm:1; | ||
150 | unsigned int uid_set:1; | ||
151 | unsigned int gid_set:1; | ||
152 | unsigned int utf8:1; | ||
153 | unsigned char map; | ||
146 | char joliet; | 154 | char joliet; |
147 | char cruft; | ||
148 | char hide; | ||
149 | char showassoc; | ||
150 | char nocompress; | ||
151 | unsigned char check; | 155 | unsigned char check; |
152 | unsigned int blocksize; | 156 | unsigned int blocksize; |
153 | mode_t fmode; | 157 | mode_t fmode; |
@@ -155,7 +159,6 @@ struct iso9660_options{ | |||
155 | gid_t gid; | 159 | gid_t gid; |
156 | uid_t uid; | 160 | uid_t uid; |
157 | char *iocharset; | 161 | char *iocharset; |
158 | unsigned char utf8; | ||
159 | /* LVE */ | 162 | /* LVE */ |
160 | s32 session; | 163 | s32 session; |
161 | s32 sbsector; | 164 | s32 sbsector; |
@@ -312,7 +315,7 @@ enum { | |||
312 | Opt_block, Opt_check_r, Opt_check_s, Opt_cruft, Opt_gid, Opt_ignore, | 315 | Opt_block, Opt_check_r, Opt_check_s, Opt_cruft, Opt_gid, Opt_ignore, |
313 | Opt_iocharset, Opt_map_a, Opt_map_n, Opt_map_o, Opt_mode, Opt_nojoliet, | 316 | Opt_iocharset, Opt_map_a, Opt_map_n, Opt_map_o, Opt_mode, Opt_nojoliet, |
314 | Opt_norock, Opt_sb, Opt_session, Opt_uid, Opt_unhide, Opt_utf8, Opt_err, | 317 | Opt_norock, Opt_sb, Opt_session, Opt_uid, Opt_unhide, Opt_utf8, Opt_err, |
315 | Opt_nocompress, Opt_hide, Opt_showassoc, Opt_dmode, | 318 | Opt_nocompress, Opt_hide, Opt_showassoc, Opt_dmode, Opt_overriderockperm, |
316 | }; | 319 | }; |
317 | 320 | ||
318 | static const match_table_t tokens = { | 321 | static const match_table_t tokens = { |
@@ -340,6 +343,7 @@ static const match_table_t tokens = { | |||
340 | {Opt_gid, "gid=%u"}, | 343 | {Opt_gid, "gid=%u"}, |
341 | {Opt_mode, "mode=%u"}, | 344 | {Opt_mode, "mode=%u"}, |
342 | {Opt_dmode, "dmode=%u"}, | 345 | {Opt_dmode, "dmode=%u"}, |
346 | {Opt_overriderockperm, "overriderockperm"}, | ||
343 | {Opt_block, "block=%u"}, | 347 | {Opt_block, "block=%u"}, |
344 | {Opt_ignore, "conv=binary"}, | 348 | {Opt_ignore, "conv=binary"}, |
345 | {Opt_ignore, "conv=b"}, | 349 | {Opt_ignore, "conv=b"}, |
@@ -359,24 +363,22 @@ static int parse_options(char *options, struct iso9660_options *popt) | |||
359 | int option; | 363 | int option; |
360 | 364 | ||
361 | popt->map = 'n'; | 365 | popt->map = 'n'; |
362 | popt->rock = 'y'; | 366 | popt->rock = 1; |
363 | popt->joliet = 'y'; | 367 | popt->joliet = 1; |
364 | popt->cruft = 'n'; | 368 | popt->cruft = 0; |
365 | popt->hide = 'n'; | 369 | popt->hide = 0; |
366 | popt->showassoc = 'n'; | 370 | popt->showassoc = 0; |
367 | popt->check = 'u'; /* unset */ | 371 | popt->check = 'u'; /* unset */ |
368 | popt->nocompress = 0; | 372 | popt->nocompress = 0; |
369 | popt->blocksize = 1024; | 373 | popt->blocksize = 1024; |
370 | popt->fmode = popt->dmode = S_IRUGO | S_IXUGO; /* | 374 | popt->fmode = popt->dmode = ISOFS_INVALID_MODE; |
371 | * r-x for all. The disc could | 375 | popt->uid_set = 0; |
372 | * be shared with DOS machines so | 376 | popt->gid_set = 0; |
373 | * virtually anything could be | ||
374 | * a valid executable. | ||
375 | */ | ||
376 | popt->gid = 0; | 377 | popt->gid = 0; |
377 | popt->uid = 0; | 378 | popt->uid = 0; |
378 | popt->iocharset = NULL; | 379 | popt->iocharset = NULL; |
379 | popt->utf8 = 0; | 380 | popt->utf8 = 0; |
381 | popt->overriderockperm = 0; | ||
380 | popt->session=-1; | 382 | popt->session=-1; |
381 | popt->sbsector=-1; | 383 | popt->sbsector=-1; |
382 | if (!options) | 384 | if (!options) |
@@ -393,20 +395,20 @@ static int parse_options(char *options, struct iso9660_options *popt) | |||
393 | token = match_token(p, tokens, args); | 395 | token = match_token(p, tokens, args); |
394 | switch (token) { | 396 | switch (token) { |
395 | case Opt_norock: | 397 | case Opt_norock: |
396 | popt->rock = 'n'; | 398 | popt->rock = 0; |
397 | break; | 399 | break; |
398 | case Opt_nojoliet: | 400 | case Opt_nojoliet: |
399 | popt->joliet = 'n'; | 401 | popt->joliet = 0; |
400 | break; | 402 | break; |
401 | case Opt_hide: | 403 | case Opt_hide: |
402 | popt->hide = 'y'; | 404 | popt->hide = 1; |
403 | break; | 405 | break; |
404 | case Opt_unhide: | 406 | case Opt_unhide: |
405 | case Opt_showassoc: | 407 | case Opt_showassoc: |
406 | popt->showassoc = 'y'; | 408 | popt->showassoc = 1; |
407 | break; | 409 | break; |
408 | case Opt_cruft: | 410 | case Opt_cruft: |
409 | popt->cruft = 'y'; | 411 | popt->cruft = 1; |
410 | break; | 412 | break; |
411 | case Opt_utf8: | 413 | case Opt_utf8: |
412 | popt->utf8 = 1; | 414 | popt->utf8 = 1; |
@@ -450,11 +452,13 @@ static int parse_options(char *options, struct iso9660_options *popt) | |||
450 | if (match_int(&args[0], &option)) | 452 | if (match_int(&args[0], &option)) |
451 | return 0; | 453 | return 0; |
452 | popt->uid = option; | 454 | popt->uid = option; |
455 | popt->uid_set = 1; | ||
453 | break; | 456 | break; |
454 | case Opt_gid: | 457 | case Opt_gid: |
455 | if (match_int(&args[0], &option)) | 458 | if (match_int(&args[0], &option)) |
456 | return 0; | 459 | return 0; |
457 | popt->gid = option; | 460 | popt->gid = option; |
461 | popt->gid_set = 1; | ||
458 | break; | 462 | break; |
459 | case Opt_mode: | 463 | case Opt_mode: |
460 | if (match_int(&args[0], &option)) | 464 | if (match_int(&args[0], &option)) |
@@ -466,6 +470,9 @@ static int parse_options(char *options, struct iso9660_options *popt) | |||
466 | return 0; | 470 | return 0; |
467 | popt->dmode = option; | 471 | popt->dmode = option; |
468 | break; | 472 | break; |
473 | case Opt_overriderockperm: | ||
474 | popt->overriderockperm = 1; | ||
475 | break; | ||
469 | case Opt_block: | 476 | case Opt_block: |
470 | if (match_int(&args[0], &option)) | 477 | if (match_int(&args[0], &option)) |
471 | return 0; | 478 | return 0; |
@@ -650,7 +657,7 @@ static int isofs_fill_super(struct super_block *s, void *data, int silent) | |||
650 | goto out_freebh; | 657 | goto out_freebh; |
651 | 658 | ||
652 | sbi->s_high_sierra = 1; | 659 | sbi->s_high_sierra = 1; |
653 | opt.rock = 'n'; | 660 | opt.rock = 0; |
654 | h_pri = (struct hs_primary_descriptor *)vdp; | 661 | h_pri = (struct hs_primary_descriptor *)vdp; |
655 | goto root_found; | 662 | goto root_found; |
656 | } | 663 | } |
@@ -673,7 +680,7 @@ static int isofs_fill_super(struct super_block *s, void *data, int silent) | |||
673 | 680 | ||
674 | root_found: | 681 | root_found: |
675 | 682 | ||
676 | if (joliet_level && (pri == NULL || opt.rock == 'n')) { | 683 | if (joliet_level && (pri == NULL || !opt.rock)) { |
677 | /* This is the case of Joliet with the norock mount flag. | 684 | /* This is the case of Joliet with the norock mount flag. |
678 | * A disc with both Joliet and Rock Ridge is handled later | 685 | * A disc with both Joliet and Rock Ridge is handled later |
679 | */ | 686 | */ |
@@ -802,22 +809,31 @@ root_found: | |||
802 | s->s_op = &isofs_sops; | 809 | s->s_op = &isofs_sops; |
803 | s->s_export_op = &isofs_export_ops; | 810 | s->s_export_op = &isofs_export_ops; |
804 | sbi->s_mapping = opt.map; | 811 | sbi->s_mapping = opt.map; |
805 | sbi->s_rock = (opt.rock == 'y' ? 2 : 0); | 812 | sbi->s_rock = (opt.rock ? 2 : 0); |
806 | sbi->s_rock_offset = -1; /* initial offset, will guess until SP is found*/ | 813 | sbi->s_rock_offset = -1; /* initial offset, will guess until SP is found*/ |
807 | sbi->s_cruft = opt.cruft; | 814 | sbi->s_cruft = opt.cruft; |
808 | sbi->s_hide = opt.hide; | 815 | sbi->s_hide = opt.hide; |
809 | sbi->s_showassoc = opt.showassoc; | 816 | sbi->s_showassoc = opt.showassoc; |
810 | sbi->s_uid = opt.uid; | 817 | sbi->s_uid = opt.uid; |
811 | sbi->s_gid = opt.gid; | 818 | sbi->s_gid = opt.gid; |
819 | sbi->s_uid_set = opt.uid_set; | ||
820 | sbi->s_gid_set = opt.gid_set; | ||
812 | sbi->s_utf8 = opt.utf8; | 821 | sbi->s_utf8 = opt.utf8; |
813 | sbi->s_nocompress = opt.nocompress; | 822 | sbi->s_nocompress = opt.nocompress; |
823 | sbi->s_overriderockperm = opt.overriderockperm; | ||
814 | /* | 824 | /* |
815 | * It would be incredibly stupid to allow people to mark every file | 825 | * It would be incredibly stupid to allow people to mark every file |
816 | * on the disk as suid, so we merely allow them to set the default | 826 | * on the disk as suid, so we merely allow them to set the default |
817 | * permissions. | 827 | * permissions. |
818 | */ | 828 | */ |
819 | sbi->s_fmode = opt.fmode & 0777; | 829 | if (opt.fmode != ISOFS_INVALID_MODE) |
820 | sbi->s_dmode = opt.dmode & 0777; | 830 | sbi->s_fmode = opt.fmode & 0777; |
831 | else | ||
832 | sbi->s_fmode = ISOFS_INVALID_MODE; | ||
833 | if (opt.dmode != ISOFS_INVALID_MODE) | ||
834 | sbi->s_dmode = opt.dmode & 0777; | ||
835 | else | ||
836 | sbi->s_dmode = ISOFS_INVALID_MODE; | ||
821 | 837 | ||
822 | /* | 838 | /* |
823 | * Read the root inode, which _may_ result in changing | 839 | * Read the root inode, which _may_ result in changing |
@@ -1095,18 +1111,6 @@ static const struct address_space_operations isofs_aops = { | |||
1095 | .bmap = _isofs_bmap | 1111 | .bmap = _isofs_bmap |
1096 | }; | 1112 | }; |
1097 | 1113 | ||
1098 | static inline void test_and_set_uid(uid_t *p, uid_t value) | ||
1099 | { | ||
1100 | if (value) | ||
1101 | *p = value; | ||
1102 | } | ||
1103 | |||
1104 | static inline void test_and_set_gid(gid_t *p, gid_t value) | ||
1105 | { | ||
1106 | if (value) | ||
1107 | *p = value; | ||
1108 | } | ||
1109 | |||
1110 | static int isofs_read_level3_size(struct inode *inode) | 1114 | static int isofs_read_level3_size(struct inode *inode) |
1111 | { | 1115 | { |
1112 | unsigned long bufsize = ISOFS_BUFFER_SIZE(inode); | 1116 | unsigned long bufsize = ISOFS_BUFFER_SIZE(inode); |
@@ -1261,7 +1265,10 @@ static int isofs_read_inode(struct inode *inode) | |||
1261 | ei->i_file_format = isofs_file_normal; | 1265 | ei->i_file_format = isofs_file_normal; |
1262 | 1266 | ||
1263 | if (de->flags[-high_sierra] & 2) { | 1267 | if (de->flags[-high_sierra] & 2) { |
1264 | inode->i_mode = sbi->s_dmode | S_IFDIR; | 1268 | if (sbi->s_dmode != ISOFS_INVALID_MODE) |
1269 | inode->i_mode = S_IFDIR | sbi->s_dmode; | ||
1270 | else | ||
1271 | inode->i_mode = S_IFDIR | S_IRUGO | S_IXUGO; | ||
1265 | inode->i_nlink = 1; /* | 1272 | inode->i_nlink = 1; /* |
1266 | * Set to 1. We know there are 2, but | 1273 | * Set to 1. We know there are 2, but |
1267 | * the find utility tries to optimize | 1274 | * the find utility tries to optimize |
@@ -1270,8 +1277,16 @@ static int isofs_read_inode(struct inode *inode) | |||
1270 | * do it the hard way. | 1277 | * do it the hard way. |
1271 | */ | 1278 | */ |
1272 | } else { | 1279 | } else { |
1273 | /* Everybody gets to read the file. */ | 1280 | if (sbi->s_fmode != ISOFS_INVALID_MODE) { |
1274 | inode->i_mode = sbi->s_fmode | S_IFREG; | 1281 | inode->i_mode = S_IFREG | sbi->s_fmode; |
1282 | } else { | ||
1283 | /* | ||
1284 | * Set default permissions: r-x for all. The disc | ||
1285 | * could be shared with DOS machines so virtually | ||
1286 | * anything could be a valid executable. | ||
1287 | */ | ||
1288 | inode->i_mode = S_IFREG | S_IRUGO | S_IXUGO; | ||
1289 | } | ||
1275 | inode->i_nlink = 1; | 1290 | inode->i_nlink = 1; |
1276 | } | 1291 | } |
1277 | inode->i_uid = sbi->s_uid; | 1292 | inode->i_uid = sbi->s_uid; |
@@ -1300,7 +1315,7 @@ static int isofs_read_inode(struct inode *inode) | |||
1300 | * this CDROM was mounted with the cruft option. | 1315 | * this CDROM was mounted with the cruft option. |
1301 | */ | 1316 | */ |
1302 | 1317 | ||
1303 | if (sbi->s_cruft == 'y') | 1318 | if (sbi->s_cruft) |
1304 | inode->i_size &= 0x00ffffff; | 1319 | inode->i_size &= 0x00ffffff; |
1305 | 1320 | ||
1306 | if (de->interleave[0]) { | 1321 | if (de->interleave[0]) { |
@@ -1346,9 +1361,18 @@ static int isofs_read_inode(struct inode *inode) | |||
1346 | if (!high_sierra) { | 1361 | if (!high_sierra) { |
1347 | parse_rock_ridge_inode(de, inode); | 1362 | parse_rock_ridge_inode(de, inode); |
1348 | /* if we want uid/gid set, override the rock ridge setting */ | 1363 | /* if we want uid/gid set, override the rock ridge setting */ |
1349 | test_and_set_uid(&inode->i_uid, sbi->s_uid); | 1364 | if (sbi->s_uid_set) |
1350 | test_and_set_gid(&inode->i_gid, sbi->s_gid); | 1365 | inode->i_uid = sbi->s_uid; |
1366 | if (sbi->s_gid_set) | ||
1367 | inode->i_gid = sbi->s_gid; | ||
1351 | } | 1368 | } |
1369 | /* Now set final access rights if overriding rock ridge setting */ | ||
1370 | if (S_ISDIR(inode->i_mode) && sbi->s_overriderockperm && | ||
1371 | sbi->s_dmode != ISOFS_INVALID_MODE) | ||
1372 | inode->i_mode = S_IFDIR | sbi->s_dmode; | ||
1373 | if (S_ISREG(inode->i_mode) && sbi->s_overriderockperm && | ||
1374 | sbi->s_fmode != ISOFS_INVALID_MODE) | ||
1375 | inode->i_mode = S_IFREG | sbi->s_fmode; | ||
1352 | 1376 | ||
1353 | /* Install the inode operations vector */ | 1377 | /* Install the inode operations vector */ |
1354 | if (S_ISREG(inode->i_mode)) { | 1378 | if (S_ISREG(inode->i_mode)) { |
diff --git a/fs/isofs/isofs.h b/fs/isofs/isofs.h index ccbf72faf27a..7d33de84f52a 100644 --- a/fs/isofs/isofs.h +++ b/fs/isofs/isofs.h | |||
@@ -35,21 +35,20 @@ struct isofs_sb_info { | |||
35 | unsigned long s_log_zone_size; | 35 | unsigned long s_log_zone_size; |
36 | unsigned long s_max_size; | 36 | unsigned long s_max_size; |
37 | 37 | ||
38 | unsigned char s_high_sierra; /* A simple flag */ | ||
39 | unsigned char s_mapping; | ||
40 | int s_rock_offset; /* offset of SUSP fields within SU area */ | 38 | int s_rock_offset; /* offset of SUSP fields within SU area */ |
41 | unsigned char s_rock; | ||
42 | unsigned char s_joliet_level; | 39 | unsigned char s_joliet_level; |
43 | unsigned char s_utf8; | 40 | unsigned char s_mapping; |
44 | unsigned char s_cruft; /* Broken disks with high | 41 | unsigned int s_high_sierra:1; |
45 | byte of length containing | 42 | unsigned int s_rock:2; |
46 | junk */ | 43 | unsigned int s_utf8:1; |
47 | unsigned char s_unhide; | 44 | unsigned int s_cruft:1; /* Broken disks with high byte of length |
48 | unsigned char s_nosuid; | 45 | * containing junk */ |
49 | unsigned char s_nodev; | 46 | unsigned int s_nocompress:1; |
50 | unsigned char s_nocompress; | 47 | unsigned int s_hide:1; |
51 | unsigned char s_hide; | 48 | unsigned int s_showassoc:1; |
52 | unsigned char s_showassoc; | 49 | unsigned int s_overriderockperm:1; |
50 | unsigned int s_uid_set:1; | ||
51 | unsigned int s_gid_set:1; | ||
53 | 52 | ||
54 | mode_t s_fmode; | 53 | mode_t s_fmode; |
55 | mode_t s_dmode; | 54 | mode_t s_dmode; |
@@ -58,6 +57,8 @@ struct isofs_sb_info { | |||
58 | struct nls_table *s_nls_iocharset; /* Native language support table */ | 57 | struct nls_table *s_nls_iocharset; /* Native language support table */ |
59 | }; | 58 | }; |
60 | 59 | ||
60 | #define ISOFS_INVALID_MODE ((mode_t) -1) | ||
61 | |||
61 | static inline struct isofs_sb_info *ISOFS_SB(struct super_block *sb) | 62 | static inline struct isofs_sb_info *ISOFS_SB(struct super_block *sb) |
62 | { | 63 | { |
63 | return sb->s_fs_info; | 64 | return sb->s_fs_info; |
diff --git a/fs/isofs/namei.c b/fs/isofs/namei.c index 8299889a835e..eaa831311c9c 100644 --- a/fs/isofs/namei.c +++ b/fs/isofs/namei.c | |||
@@ -142,9 +142,9 @@ isofs_find_entry(struct inode *dir, struct dentry *dentry, | |||
142 | */ | 142 | */ |
143 | match = 0; | 143 | match = 0; |
144 | if (dlen > 0 && | 144 | if (dlen > 0 && |
145 | (sbi->s_hide =='n' || | 145 | (!sbi->s_hide || |
146 | (!(de->flags[-sbi->s_high_sierra] & 1))) && | 146 | (!(de->flags[-sbi->s_high_sierra] & 1))) && |
147 | (sbi->s_showassoc =='y' || | 147 | (sbi->s_showassoc || |
148 | (!(de->flags[-sbi->s_high_sierra] & 4)))) { | 148 | (!(de->flags[-sbi->s_high_sierra] & 4)))) { |
149 | match = (isofs_cmp(dentry, dpnt, dlen) == 0); | 149 | match = (isofs_cmp(dentry, dpnt, dlen) == 0); |
150 | } | 150 | } |
diff --git a/fs/jbd/transaction.c b/fs/jbd/transaction.c index ed886e6db399..73242ba7c7b1 100644 --- a/fs/jbd/transaction.c +++ b/fs/jbd/transaction.c | |||
@@ -1686,35 +1686,6 @@ out: | |||
1686 | return; | 1686 | return; |
1687 | } | 1687 | } |
1688 | 1688 | ||
1689 | /* | ||
1690 | * journal_try_to_free_buffers() could race with journal_commit_transaction() | ||
1691 | * The latter might still hold the a count on buffers when inspecting | ||
1692 | * them on t_syncdata_list or t_locked_list. | ||
1693 | * | ||
1694 | * journal_try_to_free_buffers() will call this function to | ||
1695 | * wait for the current transaction to finish syncing data buffers, before | ||
1696 | * tryinf to free that buffer. | ||
1697 | * | ||
1698 | * Called with journal->j_state_lock held. | ||
1699 | */ | ||
1700 | static void journal_wait_for_transaction_sync_data(journal_t *journal) | ||
1701 | { | ||
1702 | transaction_t *transaction = NULL; | ||
1703 | tid_t tid; | ||
1704 | |||
1705 | spin_lock(&journal->j_state_lock); | ||
1706 | transaction = journal->j_committing_transaction; | ||
1707 | |||
1708 | if (!transaction) { | ||
1709 | spin_unlock(&journal->j_state_lock); | ||
1710 | return; | ||
1711 | } | ||
1712 | |||
1713 | tid = transaction->t_tid; | ||
1714 | spin_unlock(&journal->j_state_lock); | ||
1715 | log_wait_commit(journal, tid); | ||
1716 | } | ||
1717 | |||
1718 | /** | 1689 | /** |
1719 | * int journal_try_to_free_buffers() - try to free page buffers. | 1690 | * int journal_try_to_free_buffers() - try to free page buffers. |
1720 | * @journal: journal for operation | 1691 | * @journal: journal for operation |
@@ -1786,25 +1757,6 @@ int journal_try_to_free_buffers(journal_t *journal, | |||
1786 | 1757 | ||
1787 | ret = try_to_free_buffers(page); | 1758 | ret = try_to_free_buffers(page); |
1788 | 1759 | ||
1789 | /* | ||
1790 | * There are a number of places where journal_try_to_free_buffers() | ||
1791 | * could race with journal_commit_transaction(), the later still | ||
1792 | * holds the reference to the buffers to free while processing them. | ||
1793 | * try_to_free_buffers() failed to free those buffers. Some of the | ||
1794 | * caller of releasepage() request page buffers to be dropped, otherwise | ||
1795 | * treat the fail-to-free as errors (such as generic_file_direct_IO()) | ||
1796 | * | ||
1797 | * So, if the caller of try_to_release_page() wants the synchronous | ||
1798 | * behaviour(i.e make sure buffers are dropped upon return), | ||
1799 | * let's wait for the current transaction to finish flush of | ||
1800 | * dirty data buffers, then try to free those buffers again, | ||
1801 | * with the journal locked. | ||
1802 | */ | ||
1803 | if (ret == 0 && (gfp_mask & __GFP_WAIT) && (gfp_mask & __GFP_FS)) { | ||
1804 | journal_wait_for_transaction_sync_data(journal); | ||
1805 | ret = try_to_free_buffers(page); | ||
1806 | } | ||
1807 | |||
1808 | busy: | 1760 | busy: |
1809 | return ret; | 1761 | return ret; |
1810 | } | 1762 | } |
diff --git a/fs/jbd2/checkpoint.c b/fs/jbd2/checkpoint.c index 17159cacbd9e..5d70b3e6d49b 100644 --- a/fs/jbd2/checkpoint.c +++ b/fs/jbd2/checkpoint.c | |||
@@ -20,9 +20,9 @@ | |||
20 | #include <linux/time.h> | 20 | #include <linux/time.h> |
21 | #include <linux/fs.h> | 21 | #include <linux/fs.h> |
22 | #include <linux/jbd2.h> | 22 | #include <linux/jbd2.h> |
23 | #include <linux/marker.h> | ||
24 | #include <linux/errno.h> | 23 | #include <linux/errno.h> |
25 | #include <linux/slab.h> | 24 | #include <linux/slab.h> |
25 | #include <trace/events/jbd2.h> | ||
26 | 26 | ||
27 | /* | 27 | /* |
28 | * Unlink a buffer from a transaction checkpoint list. | 28 | * Unlink a buffer from a transaction checkpoint list. |
@@ -358,8 +358,7 @@ int jbd2_log_do_checkpoint(journal_t *journal) | |||
358 | * journal straight away. | 358 | * journal straight away. |
359 | */ | 359 | */ |
360 | result = jbd2_cleanup_journal_tail(journal); | 360 | result = jbd2_cleanup_journal_tail(journal); |
361 | trace_mark(jbd2_checkpoint, "dev %s need_checkpoint %d", | 361 | trace_jbd2_checkpoint(journal, result); |
362 | journal->j_devname, result); | ||
363 | jbd_debug(1, "cleanup_journal_tail returned %d\n", result); | 362 | jbd_debug(1, "cleanup_journal_tail returned %d\n", result); |
364 | if (result <= 0) | 363 | if (result <= 0) |
365 | return result; | 364 | return result; |
diff --git a/fs/jbd2/commit.c b/fs/jbd2/commit.c index 0b7d3b8226fd..7b4088b2364d 100644 --- a/fs/jbd2/commit.c +++ b/fs/jbd2/commit.c | |||
@@ -16,7 +16,6 @@ | |||
16 | #include <linux/time.h> | 16 | #include <linux/time.h> |
17 | #include <linux/fs.h> | 17 | #include <linux/fs.h> |
18 | #include <linux/jbd2.h> | 18 | #include <linux/jbd2.h> |
19 | #include <linux/marker.h> | ||
20 | #include <linux/errno.h> | 19 | #include <linux/errno.h> |
21 | #include <linux/slab.h> | 20 | #include <linux/slab.h> |
22 | #include <linux/mm.h> | 21 | #include <linux/mm.h> |
@@ -26,6 +25,7 @@ | |||
26 | #include <linux/writeback.h> | 25 | #include <linux/writeback.h> |
27 | #include <linux/backing-dev.h> | 26 | #include <linux/backing-dev.h> |
28 | #include <linux/bio.h> | 27 | #include <linux/bio.h> |
28 | #include <trace/events/jbd2.h> | ||
29 | 29 | ||
30 | /* | 30 | /* |
31 | * Default IO end handler for temporary BJ_IO buffer_heads. | 31 | * Default IO end handler for temporary BJ_IO buffer_heads. |
@@ -253,6 +253,7 @@ static int journal_submit_data_buffers(journal_t *journal, | |||
253 | * block allocation with delalloc. We need to write | 253 | * block allocation with delalloc. We need to write |
254 | * only allocated blocks here. | 254 | * only allocated blocks here. |
255 | */ | 255 | */ |
256 | trace_jbd2_submit_inode_data(jinode->i_vfs_inode); | ||
256 | err = journal_submit_inode_data_buffers(mapping); | 257 | err = journal_submit_inode_data_buffers(mapping); |
257 | if (!ret) | 258 | if (!ret) |
258 | ret = err; | 259 | ret = err; |
@@ -394,8 +395,7 @@ void jbd2_journal_commit_transaction(journal_t *journal) | |||
394 | commit_transaction = journal->j_running_transaction; | 395 | commit_transaction = journal->j_running_transaction; |
395 | J_ASSERT(commit_transaction->t_state == T_RUNNING); | 396 | J_ASSERT(commit_transaction->t_state == T_RUNNING); |
396 | 397 | ||
397 | trace_mark(jbd2_start_commit, "dev %s transaction %d", | 398 | trace_jbd2_start_commit(journal, commit_transaction); |
398 | journal->j_devname, commit_transaction->t_tid); | ||
399 | jbd_debug(1, "JBD: starting commit of transaction %d\n", | 399 | jbd_debug(1, "JBD: starting commit of transaction %d\n", |
400 | commit_transaction->t_tid); | 400 | commit_transaction->t_tid); |
401 | 401 | ||
@@ -409,6 +409,7 @@ void jbd2_journal_commit_transaction(journal_t *journal) | |||
409 | */ | 409 | */ |
410 | if (commit_transaction->t_synchronous_commit) | 410 | if (commit_transaction->t_synchronous_commit) |
411 | write_op = WRITE_SYNC_PLUG; | 411 | write_op = WRITE_SYNC_PLUG; |
412 | trace_jbd2_commit_locking(journal, commit_transaction); | ||
412 | stats.u.run.rs_wait = commit_transaction->t_max_wait; | 413 | stats.u.run.rs_wait = commit_transaction->t_max_wait; |
413 | stats.u.run.rs_locked = jiffies; | 414 | stats.u.run.rs_locked = jiffies; |
414 | stats.u.run.rs_running = jbd2_time_diff(commit_transaction->t_start, | 415 | stats.u.run.rs_running = jbd2_time_diff(commit_transaction->t_start, |
@@ -484,6 +485,7 @@ void jbd2_journal_commit_transaction(journal_t *journal) | |||
484 | */ | 485 | */ |
485 | jbd2_journal_switch_revoke_table(journal); | 486 | jbd2_journal_switch_revoke_table(journal); |
486 | 487 | ||
488 | trace_jbd2_commit_flushing(journal, commit_transaction); | ||
487 | stats.u.run.rs_flushing = jiffies; | 489 | stats.u.run.rs_flushing = jiffies; |
488 | stats.u.run.rs_locked = jbd2_time_diff(stats.u.run.rs_locked, | 490 | stats.u.run.rs_locked = jbd2_time_diff(stats.u.run.rs_locked, |
489 | stats.u.run.rs_flushing); | 491 | stats.u.run.rs_flushing); |
@@ -520,6 +522,7 @@ void jbd2_journal_commit_transaction(journal_t *journal) | |||
520 | commit_transaction->t_state = T_COMMIT; | 522 | commit_transaction->t_state = T_COMMIT; |
521 | spin_unlock(&journal->j_state_lock); | 523 | spin_unlock(&journal->j_state_lock); |
522 | 524 | ||
525 | trace_jbd2_commit_logging(journal, commit_transaction); | ||
523 | stats.u.run.rs_logging = jiffies; | 526 | stats.u.run.rs_logging = jiffies; |
524 | stats.u.run.rs_flushing = jbd2_time_diff(stats.u.run.rs_flushing, | 527 | stats.u.run.rs_flushing = jbd2_time_diff(stats.u.run.rs_flushing, |
525 | stats.u.run.rs_logging); | 528 | stats.u.run.rs_logging); |
@@ -1054,9 +1057,7 @@ restart_loop: | |||
1054 | if (journal->j_commit_callback) | 1057 | if (journal->j_commit_callback) |
1055 | journal->j_commit_callback(journal, commit_transaction); | 1058 | journal->j_commit_callback(journal, commit_transaction); |
1056 | 1059 | ||
1057 | trace_mark(jbd2_end_commit, "dev %s transaction %d head %d", | 1060 | trace_jbd2_end_commit(journal, commit_transaction); |
1058 | journal->j_devname, commit_transaction->t_tid, | ||
1059 | journal->j_tail_sequence); | ||
1060 | jbd_debug(1, "JBD: commit %d complete, head %d\n", | 1061 | jbd_debug(1, "JBD: commit %d complete, head %d\n", |
1061 | journal->j_commit_sequence, journal->j_tail_sequence); | 1062 | journal->j_commit_sequence, journal->j_tail_sequence); |
1062 | if (to_free) | 1063 | if (to_free) |
diff --git a/fs/jbd2/journal.c b/fs/jbd2/journal.c index 62be7d294ec2..18bfd5dab642 100644 --- a/fs/jbd2/journal.c +++ b/fs/jbd2/journal.c | |||
@@ -38,6 +38,10 @@ | |||
38 | #include <linux/debugfs.h> | 38 | #include <linux/debugfs.h> |
39 | #include <linux/seq_file.h> | 39 | #include <linux/seq_file.h> |
40 | #include <linux/math64.h> | 40 | #include <linux/math64.h> |
41 | #include <linux/hash.h> | ||
42 | |||
43 | #define CREATE_TRACE_POINTS | ||
44 | #include <trace/events/jbd2.h> | ||
41 | 45 | ||
42 | #include <asm/uaccess.h> | 46 | #include <asm/uaccess.h> |
43 | #include <asm/page.h> | 47 | #include <asm/page.h> |
@@ -2377,6 +2381,71 @@ static void __exit journal_exit(void) | |||
2377 | jbd2_journal_destroy_caches(); | 2381 | jbd2_journal_destroy_caches(); |
2378 | } | 2382 | } |
2379 | 2383 | ||
2384 | /* | ||
2385 | * jbd2_dev_to_name is a utility function used by the jbd2 and ext4 | ||
2386 | * tracing infrastructure to map a dev_t to a device name. | ||
2387 | * | ||
2388 | * The caller should use rcu_read_lock() in order to make sure the | ||
2389 | * device name stays valid until its done with it. We use | ||
2390 | * rcu_read_lock() as well to make sure we're safe in case the caller | ||
2391 | * gets sloppy, and because rcu_read_lock() is cheap and can be safely | ||
2392 | * nested. | ||
2393 | */ | ||
2394 | struct devname_cache { | ||
2395 | struct rcu_head rcu; | ||
2396 | dev_t device; | ||
2397 | char devname[BDEVNAME_SIZE]; | ||
2398 | }; | ||
2399 | #define CACHE_SIZE_BITS 6 | ||
2400 | static struct devname_cache *devcache[1 << CACHE_SIZE_BITS]; | ||
2401 | static DEFINE_SPINLOCK(devname_cache_lock); | ||
2402 | |||
2403 | static void free_devcache(struct rcu_head *rcu) | ||
2404 | { | ||
2405 | kfree(rcu); | ||
2406 | } | ||
2407 | |||
2408 | const char *jbd2_dev_to_name(dev_t device) | ||
2409 | { | ||
2410 | int i = hash_32(device, CACHE_SIZE_BITS); | ||
2411 | char *ret; | ||
2412 | struct block_device *bd; | ||
2413 | |||
2414 | rcu_read_lock(); | ||
2415 | if (devcache[i] && devcache[i]->device == device) { | ||
2416 | ret = devcache[i]->devname; | ||
2417 | rcu_read_unlock(); | ||
2418 | return ret; | ||
2419 | } | ||
2420 | rcu_read_unlock(); | ||
2421 | |||
2422 | spin_lock(&devname_cache_lock); | ||
2423 | if (devcache[i]) { | ||
2424 | if (devcache[i]->device == device) { | ||
2425 | ret = devcache[i]->devname; | ||
2426 | spin_unlock(&devname_cache_lock); | ||
2427 | return ret; | ||
2428 | } | ||
2429 | call_rcu(&devcache[i]->rcu, free_devcache); | ||
2430 | } | ||
2431 | devcache[i] = kmalloc(sizeof(struct devname_cache), GFP_KERNEL); | ||
2432 | if (!devcache[i]) { | ||
2433 | spin_unlock(&devname_cache_lock); | ||
2434 | return "NODEV-ALLOCFAILURE"; /* Something non-NULL */ | ||
2435 | } | ||
2436 | devcache[i]->device = device; | ||
2437 | bd = bdget(device); | ||
2438 | if (bd) { | ||
2439 | bdevname(bd, devcache[i]->devname); | ||
2440 | bdput(bd); | ||
2441 | } else | ||
2442 | __bdevname(device, devcache[i]->devname); | ||
2443 | ret = devcache[i]->devname; | ||
2444 | spin_unlock(&devname_cache_lock); | ||
2445 | return ret; | ||
2446 | } | ||
2447 | EXPORT_SYMBOL(jbd2_dev_to_name); | ||
2448 | |||
2380 | MODULE_LICENSE("GPL"); | 2449 | MODULE_LICENSE("GPL"); |
2381 | module_init(journal_init); | 2450 | module_init(journal_init); |
2382 | module_exit(journal_exit); | 2451 | module_exit(journal_exit); |
diff --git a/fs/jbd2/transaction.c b/fs/jbd2/transaction.c index 996ffda06bf3..494501edba6b 100644 --- a/fs/jbd2/transaction.c +++ b/fs/jbd2/transaction.c | |||
@@ -1547,36 +1547,6 @@ out: | |||
1547 | return; | 1547 | return; |
1548 | } | 1548 | } |
1549 | 1549 | ||
1550 | /* | ||
1551 | * jbd2_journal_try_to_free_buffers() could race with | ||
1552 | * jbd2_journal_commit_transaction(). The later might still hold the | ||
1553 | * reference count to the buffers when inspecting them on | ||
1554 | * t_syncdata_list or t_locked_list. | ||
1555 | * | ||
1556 | * jbd2_journal_try_to_free_buffers() will call this function to | ||
1557 | * wait for the current transaction to finish syncing data buffers, before | ||
1558 | * try to free that buffer. | ||
1559 | * | ||
1560 | * Called with journal->j_state_lock hold. | ||
1561 | */ | ||
1562 | static void jbd2_journal_wait_for_transaction_sync_data(journal_t *journal) | ||
1563 | { | ||
1564 | transaction_t *transaction; | ||
1565 | tid_t tid; | ||
1566 | |||
1567 | spin_lock(&journal->j_state_lock); | ||
1568 | transaction = journal->j_committing_transaction; | ||
1569 | |||
1570 | if (!transaction) { | ||
1571 | spin_unlock(&journal->j_state_lock); | ||
1572 | return; | ||
1573 | } | ||
1574 | |||
1575 | tid = transaction->t_tid; | ||
1576 | spin_unlock(&journal->j_state_lock); | ||
1577 | jbd2_log_wait_commit(journal, tid); | ||
1578 | } | ||
1579 | |||
1580 | /** | 1550 | /** |
1581 | * int jbd2_journal_try_to_free_buffers() - try to free page buffers. | 1551 | * int jbd2_journal_try_to_free_buffers() - try to free page buffers. |
1582 | * @journal: journal for operation | 1552 | * @journal: journal for operation |
@@ -1649,25 +1619,6 @@ int jbd2_journal_try_to_free_buffers(journal_t *journal, | |||
1649 | 1619 | ||
1650 | ret = try_to_free_buffers(page); | 1620 | ret = try_to_free_buffers(page); |
1651 | 1621 | ||
1652 | /* | ||
1653 | * There are a number of places where jbd2_journal_try_to_free_buffers() | ||
1654 | * could race with jbd2_journal_commit_transaction(), the later still | ||
1655 | * holds the reference to the buffers to free while processing them. | ||
1656 | * try_to_free_buffers() failed to free those buffers. Some of the | ||
1657 | * caller of releasepage() request page buffers to be dropped, otherwise | ||
1658 | * treat the fail-to-free as errors (such as generic_file_direct_IO()) | ||
1659 | * | ||
1660 | * So, if the caller of try_to_release_page() wants the synchronous | ||
1661 | * behaviour(i.e make sure buffers are dropped upon return), | ||
1662 | * let's wait for the current transaction to finish flush of | ||
1663 | * dirty data buffers, then try to free those buffers again, | ||
1664 | * with the journal locked. | ||
1665 | */ | ||
1666 | if (ret == 0 && (gfp_mask & __GFP_WAIT) && (gfp_mask & __GFP_FS)) { | ||
1667 | jbd2_journal_wait_for_transaction_sync_data(journal); | ||
1668 | ret = try_to_free_buffers(page); | ||
1669 | } | ||
1670 | |||
1671 | busy: | 1622 | busy: |
1672 | return ret; | 1623 | return ret; |
1673 | } | 1624 | } |
diff --git a/fs/jffs2/scan.c b/fs/jffs2/scan.c index 1d437de1e9a8..7515e73e2bfb 100644 --- a/fs/jffs2/scan.c +++ b/fs/jffs2/scan.c | |||
@@ -196,7 +196,7 @@ int jffs2_scan_medium(struct jffs2_sb_info *c) | |||
196 | if (c->nextblock) { | 196 | if (c->nextblock) { |
197 | ret = file_dirty(c, c->nextblock); | 197 | ret = file_dirty(c, c->nextblock); |
198 | if (ret) | 198 | if (ret) |
199 | return ret; | 199 | goto out; |
200 | /* deleting summary information of the old nextblock */ | 200 | /* deleting summary information of the old nextblock */ |
201 | jffs2_sum_reset_collected(c->summary); | 201 | jffs2_sum_reset_collected(c->summary); |
202 | } | 202 | } |
@@ -207,7 +207,7 @@ int jffs2_scan_medium(struct jffs2_sb_info *c) | |||
207 | } else { | 207 | } else { |
208 | ret = file_dirty(c, jeb); | 208 | ret = file_dirty(c, jeb); |
209 | if (ret) | 209 | if (ret) |
210 | return ret; | 210 | goto out; |
211 | } | 211 | } |
212 | break; | 212 | break; |
213 | 213 | ||
diff --git a/fs/lockd/clntproc.c b/fs/lockd/clntproc.c index dd7957064a8c..f2fdcbce143e 100644 --- a/fs/lockd/clntproc.c +++ b/fs/lockd/clntproc.c | |||
@@ -126,7 +126,6 @@ static void nlmclnt_setlockargs(struct nlm_rqst *req, struct file_lock *fl) | |||
126 | struct nlm_lock *lock = &argp->lock; | 126 | struct nlm_lock *lock = &argp->lock; |
127 | 127 | ||
128 | nlmclnt_next_cookie(&argp->cookie); | 128 | nlmclnt_next_cookie(&argp->cookie); |
129 | argp->state = nsm_local_state; | ||
130 | memcpy(&lock->fh, NFS_FH(fl->fl_file->f_path.dentry->d_inode), sizeof(struct nfs_fh)); | 129 | memcpy(&lock->fh, NFS_FH(fl->fl_file->f_path.dentry->d_inode), sizeof(struct nfs_fh)); |
131 | lock->caller = utsname()->nodename; | 130 | lock->caller = utsname()->nodename; |
132 | lock->oh.data = req->a_owner; | 131 | lock->oh.data = req->a_owner; |
@@ -165,6 +164,7 @@ int nlmclnt_proc(struct nlm_host *host, int cmd, struct file_lock *fl) | |||
165 | /* Set up the argument struct */ | 164 | /* Set up the argument struct */ |
166 | nlmclnt_setlockargs(call, fl); | 165 | nlmclnt_setlockargs(call, fl); |
167 | 166 | ||
167 | lock_kernel(); | ||
168 | if (IS_SETLK(cmd) || IS_SETLKW(cmd)) { | 168 | if (IS_SETLK(cmd) || IS_SETLKW(cmd)) { |
169 | if (fl->fl_type != F_UNLCK) { | 169 | if (fl->fl_type != F_UNLCK) { |
170 | call->a_args.block = IS_SETLKW(cmd) ? 1 : 0; | 170 | call->a_args.block = IS_SETLKW(cmd) ? 1 : 0; |
@@ -178,6 +178,7 @@ int nlmclnt_proc(struct nlm_host *host, int cmd, struct file_lock *fl) | |||
178 | 178 | ||
179 | fl->fl_ops->fl_release_private(fl); | 179 | fl->fl_ops->fl_release_private(fl); |
180 | fl->fl_ops = NULL; | 180 | fl->fl_ops = NULL; |
181 | unlock_kernel(); | ||
181 | 182 | ||
182 | dprintk("lockd: clnt proc returns %d\n", status); | 183 | dprintk("lockd: clnt proc returns %d\n", status); |
183 | return status; | 184 | return status; |
@@ -519,6 +520,7 @@ nlmclnt_lock(struct nlm_rqst *req, struct file_lock *fl) | |||
519 | 520 | ||
520 | if (nsm_monitor(host) < 0) | 521 | if (nsm_monitor(host) < 0) |
521 | goto out; | 522 | goto out; |
523 | req->a_args.state = nsm_local_state; | ||
522 | 524 | ||
523 | fl->fl_flags |= FL_ACCESS; | 525 | fl->fl_flags |= FL_ACCESS; |
524 | status = do_vfs_lock(fl); | 526 | status = do_vfs_lock(fl); |
diff --git a/fs/lockd/mon.c b/fs/lockd/mon.c index 6d5d4a4169e5..7fce1b525849 100644 --- a/fs/lockd/mon.c +++ b/fs/lockd/mon.c | |||
@@ -53,7 +53,7 @@ static DEFINE_SPINLOCK(nsm_lock); | |||
53 | /* | 53 | /* |
54 | * Local NSM state | 54 | * Local NSM state |
55 | */ | 55 | */ |
56 | int __read_mostly nsm_local_state; | 56 | u32 __read_mostly nsm_local_state; |
57 | int __read_mostly nsm_use_hostnames; | 57 | int __read_mostly nsm_use_hostnames; |
58 | 58 | ||
59 | static inline struct sockaddr *nsm_addr(const struct nsm_handle *nsm) | 59 | static inline struct sockaddr *nsm_addr(const struct nsm_handle *nsm) |
@@ -112,6 +112,7 @@ static struct rpc_clnt *nsm_create(void) | |||
112 | .program = &nsm_program, | 112 | .program = &nsm_program, |
113 | .version = NSM_VERSION, | 113 | .version = NSM_VERSION, |
114 | .authflavor = RPC_AUTH_NULL, | 114 | .authflavor = RPC_AUTH_NULL, |
115 | .flags = RPC_CLNT_CREATE_NOPING, | ||
115 | }; | 116 | }; |
116 | 117 | ||
117 | return rpc_create(&args); | 118 | return rpc_create(&args); |
@@ -184,13 +185,19 @@ int nsm_monitor(const struct nlm_host *host) | |||
184 | nsm->sm_mon_name = nsm_use_hostnames ? nsm->sm_name : nsm->sm_addrbuf; | 185 | nsm->sm_mon_name = nsm_use_hostnames ? nsm->sm_name : nsm->sm_addrbuf; |
185 | 186 | ||
186 | status = nsm_mon_unmon(nsm, NSMPROC_MON, &res); | 187 | status = nsm_mon_unmon(nsm, NSMPROC_MON, &res); |
187 | if (res.status != 0) | 188 | if (unlikely(res.status != 0)) |
188 | status = -EIO; | 189 | status = -EIO; |
189 | if (status < 0) | 190 | if (unlikely(status < 0)) { |
190 | printk(KERN_NOTICE "lockd: cannot monitor %s\n", nsm->sm_name); | 191 | printk(KERN_NOTICE "lockd: cannot monitor %s\n", nsm->sm_name); |
191 | else | 192 | return status; |
192 | nsm->sm_monitored = 1; | 193 | } |
193 | return status; | 194 | |
195 | nsm->sm_monitored = 1; | ||
196 | if (unlikely(nsm_local_state != res.state)) { | ||
197 | nsm_local_state = res.state; | ||
198 | dprintk("lockd: NSM state changed to %d\n", nsm_local_state); | ||
199 | } | ||
200 | return 0; | ||
194 | } | 201 | } |
195 | 202 | ||
196 | /** | 203 | /** |
diff --git a/fs/lockd/svclock.c b/fs/lockd/svclock.c index 83ee34203bd7..e577a78d7bac 100644 --- a/fs/lockd/svclock.c +++ b/fs/lockd/svclock.c | |||
@@ -326,6 +326,8 @@ static void nlmsvc_freegrantargs(struct nlm_rqst *call) | |||
326 | { | 326 | { |
327 | if (call->a_args.lock.oh.data != call->a_owner) | 327 | if (call->a_args.lock.oh.data != call->a_owner) |
328 | kfree(call->a_args.lock.oh.data); | 328 | kfree(call->a_args.lock.oh.data); |
329 | |||
330 | locks_release_private(&call->a_args.lock.fl); | ||
329 | } | 331 | } |
330 | 332 | ||
331 | /* | 333 | /* |
diff --git a/fs/locks.c b/fs/locks.c index ec3deea29e37..b6440f52178f 100644 --- a/fs/locks.c +++ b/fs/locks.c | |||
@@ -151,7 +151,7 @@ static struct file_lock *locks_alloc_lock(void) | |||
151 | return kmem_cache_alloc(filelock_cache, GFP_KERNEL); | 151 | return kmem_cache_alloc(filelock_cache, GFP_KERNEL); |
152 | } | 152 | } |
153 | 153 | ||
154 | static void locks_release_private(struct file_lock *fl) | 154 | void locks_release_private(struct file_lock *fl) |
155 | { | 155 | { |
156 | if (fl->fl_ops) { | 156 | if (fl->fl_ops) { |
157 | if (fl->fl_ops->fl_release_private) | 157 | if (fl->fl_ops->fl_release_private) |
@@ -165,6 +165,7 @@ static void locks_release_private(struct file_lock *fl) | |||
165 | } | 165 | } |
166 | 166 | ||
167 | } | 167 | } |
168 | EXPORT_SYMBOL_GPL(locks_release_private); | ||
168 | 169 | ||
169 | /* Free a lock which is not in use. */ | 170 | /* Free a lock which is not in use. */ |
170 | static void locks_free_lock(struct file_lock *fl) | 171 | static void locks_free_lock(struct file_lock *fl) |
diff --git a/fs/minix/minix.h b/fs/minix/minix.h index cb7fdd11f9a5..9dcf95b42116 100644 --- a/fs/minix/minix.h +++ b/fs/minix/minix.h | |||
@@ -1,3 +1,6 @@ | |||
1 | #ifndef FS_MINIX_H | ||
2 | #define FS_MINIX_H | ||
3 | |||
1 | #include <linux/fs.h> | 4 | #include <linux/fs.h> |
2 | #include <linux/pagemap.h> | 5 | #include <linux/pagemap.h> |
3 | #include <linux/minix_fs.h> | 6 | #include <linux/minix_fs.h> |
@@ -86,3 +89,5 @@ static inline struct minix_inode_info *minix_i(struct inode *inode) | |||
86 | { | 89 | { |
87 | return list_entry(inode, struct minix_inode_info, vfs_inode); | 90 | return list_entry(inode, struct minix_inode_info, vfs_inode); |
88 | } | 91 | } |
92 | |||
93 | #endif /* FS_MINIX_H */ | ||
diff --git a/fs/namespace.c b/fs/namespace.c index 2dd333b0fe7f..a7bea8c8bd46 100644 --- a/fs/namespace.c +++ b/fs/namespace.c | |||
@@ -1937,6 +1937,21 @@ dput_out: | |||
1937 | return retval; | 1937 | return retval; |
1938 | } | 1938 | } |
1939 | 1939 | ||
1940 | static struct mnt_namespace *alloc_mnt_ns(void) | ||
1941 | { | ||
1942 | struct mnt_namespace *new_ns; | ||
1943 | |||
1944 | new_ns = kmalloc(sizeof(struct mnt_namespace), GFP_KERNEL); | ||
1945 | if (!new_ns) | ||
1946 | return ERR_PTR(-ENOMEM); | ||
1947 | atomic_set(&new_ns->count, 1); | ||
1948 | new_ns->root = NULL; | ||
1949 | INIT_LIST_HEAD(&new_ns->list); | ||
1950 | init_waitqueue_head(&new_ns->poll); | ||
1951 | new_ns->event = 0; | ||
1952 | return new_ns; | ||
1953 | } | ||
1954 | |||
1940 | /* | 1955 | /* |
1941 | * Allocate a new namespace structure and populate it with contents | 1956 | * Allocate a new namespace structure and populate it with contents |
1942 | * copied from the namespace of the passed in task structure. | 1957 | * copied from the namespace of the passed in task structure. |
@@ -1948,14 +1963,9 @@ static struct mnt_namespace *dup_mnt_ns(struct mnt_namespace *mnt_ns, | |||
1948 | struct vfsmount *rootmnt = NULL, *pwdmnt = NULL; | 1963 | struct vfsmount *rootmnt = NULL, *pwdmnt = NULL; |
1949 | struct vfsmount *p, *q; | 1964 | struct vfsmount *p, *q; |
1950 | 1965 | ||
1951 | new_ns = kmalloc(sizeof(struct mnt_namespace), GFP_KERNEL); | 1966 | new_ns = alloc_mnt_ns(); |
1952 | if (!new_ns) | 1967 | if (IS_ERR(new_ns)) |
1953 | return ERR_PTR(-ENOMEM); | 1968 | return new_ns; |
1954 | |||
1955 | atomic_set(&new_ns->count, 1); | ||
1956 | INIT_LIST_HEAD(&new_ns->list); | ||
1957 | init_waitqueue_head(&new_ns->poll); | ||
1958 | new_ns->event = 0; | ||
1959 | 1969 | ||
1960 | down_write(&namespace_sem); | 1970 | down_write(&namespace_sem); |
1961 | /* First pass: copy the tree topology */ | 1971 | /* First pass: copy the tree topology */ |
@@ -2019,6 +2029,24 @@ struct mnt_namespace *copy_mnt_ns(unsigned long flags, struct mnt_namespace *ns, | |||
2019 | return new_ns; | 2029 | return new_ns; |
2020 | } | 2030 | } |
2021 | 2031 | ||
2032 | /** | ||
2033 | * create_mnt_ns - creates a private namespace and adds a root filesystem | ||
2034 | * @mnt: pointer to the new root filesystem mountpoint | ||
2035 | */ | ||
2036 | struct mnt_namespace *create_mnt_ns(struct vfsmount *mnt) | ||
2037 | { | ||
2038 | struct mnt_namespace *new_ns; | ||
2039 | |||
2040 | new_ns = alloc_mnt_ns(); | ||
2041 | if (!IS_ERR(new_ns)) { | ||
2042 | mnt->mnt_ns = new_ns; | ||
2043 | new_ns->root = mnt; | ||
2044 | list_add(&new_ns->list, &new_ns->root->mnt_list); | ||
2045 | } | ||
2046 | return new_ns; | ||
2047 | } | ||
2048 | EXPORT_SYMBOL(create_mnt_ns); | ||
2049 | |||
2022 | SYSCALL_DEFINE5(mount, char __user *, dev_name, char __user *, dir_name, | 2050 | SYSCALL_DEFINE5(mount, char __user *, dev_name, char __user *, dir_name, |
2023 | char __user *, type, unsigned long, flags, void __user *, data) | 2051 | char __user *, type, unsigned long, flags, void __user *, data) |
2024 | { | 2052 | { |
@@ -2246,10 +2274,14 @@ void __init mnt_init(void) | |||
2246 | init_mount_tree(); | 2274 | init_mount_tree(); |
2247 | } | 2275 | } |
2248 | 2276 | ||
2249 | void __put_mnt_ns(struct mnt_namespace *ns) | 2277 | void put_mnt_ns(struct mnt_namespace *ns) |
2250 | { | 2278 | { |
2251 | struct vfsmount *root = ns->root; | 2279 | struct vfsmount *root; |
2252 | LIST_HEAD(umount_list); | 2280 | LIST_HEAD(umount_list); |
2281 | |||
2282 | if (!atomic_dec_and_lock(&ns->count, &vfsmount_lock)) | ||
2283 | return; | ||
2284 | root = ns->root; | ||
2253 | ns->root = NULL; | 2285 | ns->root = NULL; |
2254 | spin_unlock(&vfsmount_lock); | 2286 | spin_unlock(&vfsmount_lock); |
2255 | down_write(&namespace_sem); | 2287 | down_write(&namespace_sem); |
@@ -2260,3 +2292,4 @@ void __put_mnt_ns(struct mnt_namespace *ns) | |||
2260 | release_mounts(&umount_list); | 2292 | release_mounts(&umount_list); |
2261 | kfree(ns); | 2293 | kfree(ns); |
2262 | } | 2294 | } |
2295 | EXPORT_SYMBOL(put_mnt_ns); | ||
diff --git a/fs/nfs/Kconfig b/fs/nfs/Kconfig index e67f3ec07736..2a77bc25d5af 100644 --- a/fs/nfs/Kconfig +++ b/fs/nfs/Kconfig | |||
@@ -1,6 +1,6 @@ | |||
1 | config NFS_FS | 1 | config NFS_FS |
2 | tristate "NFS client support" | 2 | tristate "NFS client support" |
3 | depends on INET | 3 | depends on INET && FILE_LOCKING |
4 | select LOCKD | 4 | select LOCKD |
5 | select SUNRPC | 5 | select SUNRPC |
6 | select NFS_ACL_SUPPORT if NFS_V3_ACL | 6 | select NFS_ACL_SUPPORT if NFS_V3_ACL |
@@ -74,6 +74,15 @@ config NFS_V4 | |||
74 | 74 | ||
75 | If unsure, say N. | 75 | If unsure, say N. |
76 | 76 | ||
77 | config NFS_V4_1 | ||
78 | bool "NFS client support for NFSv4.1 (DEVELOPER ONLY)" | ||
79 | depends on NFS_V4 && EXPERIMENTAL | ||
80 | help | ||
81 | This option enables support for minor version 1 of the NFSv4 protocol | ||
82 | (draft-ietf-nfsv4-minorversion1) in the kernel's NFS client. | ||
83 | |||
84 | Unless you're an NFS developer, say N. | ||
85 | |||
77 | config ROOT_NFS | 86 | config ROOT_NFS |
78 | bool "Root file system on NFS" | 87 | bool "Root file system on NFS" |
79 | depends on NFS_FS=y && IP_PNP | 88 | depends on NFS_FS=y && IP_PNP |
diff --git a/fs/nfs/callback.c b/fs/nfs/callback.c index a886e692ddd0..7f604c7941fb 100644 --- a/fs/nfs/callback.c +++ b/fs/nfs/callback.c | |||
@@ -17,6 +17,9 @@ | |||
17 | #include <linux/freezer.h> | 17 | #include <linux/freezer.h> |
18 | #include <linux/kthread.h> | 18 | #include <linux/kthread.h> |
19 | #include <linux/sunrpc/svcauth_gss.h> | 19 | #include <linux/sunrpc/svcauth_gss.h> |
20 | #if defined(CONFIG_NFS_V4_1) | ||
21 | #include <linux/sunrpc/bc_xprt.h> | ||
22 | #endif | ||
20 | 23 | ||
21 | #include <net/inet_sock.h> | 24 | #include <net/inet_sock.h> |
22 | 25 | ||
@@ -28,11 +31,12 @@ | |||
28 | 31 | ||
29 | struct nfs_callback_data { | 32 | struct nfs_callback_data { |
30 | unsigned int users; | 33 | unsigned int users; |
34 | struct svc_serv *serv; | ||
31 | struct svc_rqst *rqst; | 35 | struct svc_rqst *rqst; |
32 | struct task_struct *task; | 36 | struct task_struct *task; |
33 | }; | 37 | }; |
34 | 38 | ||
35 | static struct nfs_callback_data nfs_callback_info; | 39 | static struct nfs_callback_data nfs_callback_info[NFS4_MAX_MINOR_VERSION + 1]; |
36 | static DEFINE_MUTEX(nfs_callback_mutex); | 40 | static DEFINE_MUTEX(nfs_callback_mutex); |
37 | static struct svc_program nfs4_callback_program; | 41 | static struct svc_program nfs4_callback_program; |
38 | 42 | ||
@@ -56,10 +60,10 @@ module_param_call(callback_tcpport, param_set_port, param_get_int, | |||
56 | &nfs_callback_set_tcpport, 0644); | 60 | &nfs_callback_set_tcpport, 0644); |
57 | 61 | ||
58 | /* | 62 | /* |
59 | * This is the callback kernel thread. | 63 | * This is the NFSv4 callback kernel thread. |
60 | */ | 64 | */ |
61 | static int | 65 | static int |
62 | nfs_callback_svc(void *vrqstp) | 66 | nfs4_callback_svc(void *vrqstp) |
63 | { | 67 | { |
64 | int err, preverr = 0; | 68 | int err, preverr = 0; |
65 | struct svc_rqst *rqstp = vrqstp; | 69 | struct svc_rqst *rqstp = vrqstp; |
@@ -97,20 +101,12 @@ nfs_callback_svc(void *vrqstp) | |||
97 | } | 101 | } |
98 | 102 | ||
99 | /* | 103 | /* |
100 | * Bring up the callback thread if it is not already up. | 104 | * Prepare to bring up the NFSv4 callback service |
101 | */ | 105 | */ |
102 | int nfs_callback_up(void) | 106 | struct svc_rqst * |
107 | nfs4_callback_up(struct svc_serv *serv) | ||
103 | { | 108 | { |
104 | struct svc_serv *serv = NULL; | 109 | int ret; |
105 | int ret = 0; | ||
106 | |||
107 | mutex_lock(&nfs_callback_mutex); | ||
108 | if (nfs_callback_info.users++ || nfs_callback_info.task != NULL) | ||
109 | goto out; | ||
110 | serv = svc_create(&nfs4_callback_program, NFS4_CALLBACK_BUFSIZE, NULL); | ||
111 | ret = -ENOMEM; | ||
112 | if (!serv) | ||
113 | goto out_err; | ||
114 | 110 | ||
115 | ret = svc_create_xprt(serv, "tcp", PF_INET, | 111 | ret = svc_create_xprt(serv, "tcp", PF_INET, |
116 | nfs_callback_set_tcpport, SVC_SOCK_ANONYMOUS); | 112 | nfs_callback_set_tcpport, SVC_SOCK_ANONYMOUS); |
@@ -127,27 +123,174 @@ int nfs_callback_up(void) | |||
127 | nfs_callback_tcpport6 = ret; | 123 | nfs_callback_tcpport6 = ret; |
128 | dprintk("NFS: Callback listener port = %u (af %u)\n", | 124 | dprintk("NFS: Callback listener port = %u (af %u)\n", |
129 | nfs_callback_tcpport6, PF_INET6); | 125 | nfs_callback_tcpport6, PF_INET6); |
130 | } else if (ret != -EAFNOSUPPORT) | 126 | } else if (ret == -EAFNOSUPPORT) |
127 | ret = 0; | ||
128 | else | ||
131 | goto out_err; | 129 | goto out_err; |
132 | #endif /* defined(CONFIG_IPV6) || defined(CONFIG_IPV6_MODULE) */ | 130 | #endif /* defined(CONFIG_IPV6) || defined(CONFIG_IPV6_MODULE) */ |
133 | 131 | ||
134 | nfs_callback_info.rqst = svc_prepare_thread(serv, &serv->sv_pools[0]); | 132 | return svc_prepare_thread(serv, &serv->sv_pools[0]); |
135 | if (IS_ERR(nfs_callback_info.rqst)) { | 133 | |
136 | ret = PTR_ERR(nfs_callback_info.rqst); | 134 | out_err: |
137 | nfs_callback_info.rqst = NULL; | 135 | if (ret == 0) |
136 | ret = -ENOMEM; | ||
137 | return ERR_PTR(ret); | ||
138 | } | ||
139 | |||
140 | #if defined(CONFIG_NFS_V4_1) | ||
141 | /* | ||
142 | * The callback service for NFSv4.1 callbacks | ||
143 | */ | ||
144 | static int | ||
145 | nfs41_callback_svc(void *vrqstp) | ||
146 | { | ||
147 | struct svc_rqst *rqstp = vrqstp; | ||
148 | struct svc_serv *serv = rqstp->rq_server; | ||
149 | struct rpc_rqst *req; | ||
150 | int error; | ||
151 | DEFINE_WAIT(wq); | ||
152 | |||
153 | set_freezable(); | ||
154 | |||
155 | /* | ||
156 | * FIXME: do we really need to run this under the BKL? If so, please | ||
157 | * add a comment about what it's intended to protect. | ||
158 | */ | ||
159 | lock_kernel(); | ||
160 | while (!kthread_should_stop()) { | ||
161 | prepare_to_wait(&serv->sv_cb_waitq, &wq, TASK_INTERRUPTIBLE); | ||
162 | spin_lock_bh(&serv->sv_cb_lock); | ||
163 | if (!list_empty(&serv->sv_cb_list)) { | ||
164 | req = list_first_entry(&serv->sv_cb_list, | ||
165 | struct rpc_rqst, rq_bc_list); | ||
166 | list_del(&req->rq_bc_list); | ||
167 | spin_unlock_bh(&serv->sv_cb_lock); | ||
168 | dprintk("Invoking bc_svc_process()\n"); | ||
169 | error = bc_svc_process(serv, req, rqstp); | ||
170 | dprintk("bc_svc_process() returned w/ error code= %d\n", | ||
171 | error); | ||
172 | } else { | ||
173 | spin_unlock_bh(&serv->sv_cb_lock); | ||
174 | schedule(); | ||
175 | } | ||
176 | finish_wait(&serv->sv_cb_waitq, &wq); | ||
177 | } | ||
178 | unlock_kernel(); | ||
179 | return 0; | ||
180 | } | ||
181 | |||
182 | /* | ||
183 | * Bring up the NFSv4.1 callback service | ||
184 | */ | ||
185 | struct svc_rqst * | ||
186 | nfs41_callback_up(struct svc_serv *serv, struct rpc_xprt *xprt) | ||
187 | { | ||
188 | struct svc_xprt *bc_xprt; | ||
189 | struct svc_rqst *rqstp = ERR_PTR(-ENOMEM); | ||
190 | |||
191 | dprintk("--> %s\n", __func__); | ||
192 | /* Create a svc_sock for the service */ | ||
193 | bc_xprt = svc_sock_create(serv, xprt->prot); | ||
194 | if (!bc_xprt) | ||
195 | goto out; | ||
196 | |||
197 | /* | ||
198 | * Save the svc_serv in the transport so that it can | ||
199 | * be referenced when the session backchannel is initialized | ||
200 | */ | ||
201 | serv->bc_xprt = bc_xprt; | ||
202 | xprt->bc_serv = serv; | ||
203 | |||
204 | INIT_LIST_HEAD(&serv->sv_cb_list); | ||
205 | spin_lock_init(&serv->sv_cb_lock); | ||
206 | init_waitqueue_head(&serv->sv_cb_waitq); | ||
207 | rqstp = svc_prepare_thread(serv, &serv->sv_pools[0]); | ||
208 | if (IS_ERR(rqstp)) | ||
209 | svc_sock_destroy(bc_xprt); | ||
210 | out: | ||
211 | dprintk("--> %s return %p\n", __func__, rqstp); | ||
212 | return rqstp; | ||
213 | } | ||
214 | |||
215 | static inline int nfs_minorversion_callback_svc_setup(u32 minorversion, | ||
216 | struct svc_serv *serv, struct rpc_xprt *xprt, | ||
217 | struct svc_rqst **rqstpp, int (**callback_svc)(void *vrqstp)) | ||
218 | { | ||
219 | if (minorversion) { | ||
220 | *rqstpp = nfs41_callback_up(serv, xprt); | ||
221 | *callback_svc = nfs41_callback_svc; | ||
222 | } | ||
223 | return minorversion; | ||
224 | } | ||
225 | |||
226 | static inline void nfs_callback_bc_serv(u32 minorversion, struct rpc_xprt *xprt, | ||
227 | struct nfs_callback_data *cb_info) | ||
228 | { | ||
229 | if (minorversion) | ||
230 | xprt->bc_serv = cb_info->serv; | ||
231 | } | ||
232 | #else | ||
233 | static inline int nfs_minorversion_callback_svc_setup(u32 minorversion, | ||
234 | struct svc_serv *serv, struct rpc_xprt *xprt, | ||
235 | struct svc_rqst **rqstpp, int (**callback_svc)(void *vrqstp)) | ||
236 | { | ||
237 | return 0; | ||
238 | } | ||
239 | |||
240 | static inline void nfs_callback_bc_serv(u32 minorversion, struct rpc_xprt *xprt, | ||
241 | struct nfs_callback_data *cb_info) | ||
242 | { | ||
243 | } | ||
244 | #endif /* CONFIG_NFS_V4_1 */ | ||
245 | |||
246 | /* | ||
247 | * Bring up the callback thread if it is not already up. | ||
248 | */ | ||
249 | int nfs_callback_up(u32 minorversion, struct rpc_xprt *xprt) | ||
250 | { | ||
251 | struct svc_serv *serv = NULL; | ||
252 | struct svc_rqst *rqstp; | ||
253 | int (*callback_svc)(void *vrqstp); | ||
254 | struct nfs_callback_data *cb_info = &nfs_callback_info[minorversion]; | ||
255 | char svc_name[12]; | ||
256 | int ret = 0; | ||
257 | int minorversion_setup; | ||
258 | |||
259 | mutex_lock(&nfs_callback_mutex); | ||
260 | if (cb_info->users++ || cb_info->task != NULL) { | ||
261 | nfs_callback_bc_serv(minorversion, xprt, cb_info); | ||
262 | goto out; | ||
263 | } | ||
264 | serv = svc_create(&nfs4_callback_program, NFS4_CALLBACK_BUFSIZE, NULL); | ||
265 | if (!serv) { | ||
266 | ret = -ENOMEM; | ||
267 | goto out_err; | ||
268 | } | ||
269 | |||
270 | minorversion_setup = nfs_minorversion_callback_svc_setup(minorversion, | ||
271 | serv, xprt, &rqstp, &callback_svc); | ||
272 | if (!minorversion_setup) { | ||
273 | /* v4.0 callback setup */ | ||
274 | rqstp = nfs4_callback_up(serv); | ||
275 | callback_svc = nfs4_callback_svc; | ||
276 | } | ||
277 | |||
278 | if (IS_ERR(rqstp)) { | ||
279 | ret = PTR_ERR(rqstp); | ||
138 | goto out_err; | 280 | goto out_err; |
139 | } | 281 | } |
140 | 282 | ||
141 | svc_sock_update_bufs(serv); | 283 | svc_sock_update_bufs(serv); |
142 | 284 | ||
143 | nfs_callback_info.task = kthread_run(nfs_callback_svc, | 285 | sprintf(svc_name, "nfsv4.%u-svc", minorversion); |
144 | nfs_callback_info.rqst, | 286 | cb_info->serv = serv; |
145 | "nfsv4-svc"); | 287 | cb_info->rqst = rqstp; |
146 | if (IS_ERR(nfs_callback_info.task)) { | 288 | cb_info->task = kthread_run(callback_svc, cb_info->rqst, svc_name); |
147 | ret = PTR_ERR(nfs_callback_info.task); | 289 | if (IS_ERR(cb_info->task)) { |
148 | svc_exit_thread(nfs_callback_info.rqst); | 290 | ret = PTR_ERR(cb_info->task); |
149 | nfs_callback_info.rqst = NULL; | 291 | svc_exit_thread(cb_info->rqst); |
150 | nfs_callback_info.task = NULL; | 292 | cb_info->rqst = NULL; |
293 | cb_info->task = NULL; | ||
151 | goto out_err; | 294 | goto out_err; |
152 | } | 295 | } |
153 | out: | 296 | out: |
@@ -164,22 +307,25 @@ out: | |||
164 | out_err: | 307 | out_err: |
165 | dprintk("NFS: Couldn't create callback socket or server thread; " | 308 | dprintk("NFS: Couldn't create callback socket or server thread; " |
166 | "err = %d\n", ret); | 309 | "err = %d\n", ret); |
167 | nfs_callback_info.users--; | 310 | cb_info->users--; |
168 | goto out; | 311 | goto out; |
169 | } | 312 | } |
170 | 313 | ||
171 | /* | 314 | /* |
172 | * Kill the callback thread if it's no longer being used. | 315 | * Kill the callback thread if it's no longer being used. |
173 | */ | 316 | */ |
174 | void nfs_callback_down(void) | 317 | void nfs_callback_down(int minorversion) |
175 | { | 318 | { |
319 | struct nfs_callback_data *cb_info = &nfs_callback_info[minorversion]; | ||
320 | |||
176 | mutex_lock(&nfs_callback_mutex); | 321 | mutex_lock(&nfs_callback_mutex); |
177 | nfs_callback_info.users--; | 322 | cb_info->users--; |
178 | if (nfs_callback_info.users == 0 && nfs_callback_info.task != NULL) { | 323 | if (cb_info->users == 0 && cb_info->task != NULL) { |
179 | kthread_stop(nfs_callback_info.task); | 324 | kthread_stop(cb_info->task); |
180 | svc_exit_thread(nfs_callback_info.rqst); | 325 | svc_exit_thread(cb_info->rqst); |
181 | nfs_callback_info.rqst = NULL; | 326 | cb_info->serv = NULL; |
182 | nfs_callback_info.task = NULL; | 327 | cb_info->rqst = NULL; |
328 | cb_info->task = NULL; | ||
183 | } | 329 | } |
184 | mutex_unlock(&nfs_callback_mutex); | 330 | mutex_unlock(&nfs_callback_mutex); |
185 | } | 331 | } |
diff --git a/fs/nfs/callback.h b/fs/nfs/callback.h index e110e286a262..07baa8254ca1 100644 --- a/fs/nfs/callback.h +++ b/fs/nfs/callback.h | |||
@@ -20,13 +20,24 @@ enum nfs4_callback_procnum { | |||
20 | enum nfs4_callback_opnum { | 20 | enum nfs4_callback_opnum { |
21 | OP_CB_GETATTR = 3, | 21 | OP_CB_GETATTR = 3, |
22 | OP_CB_RECALL = 4, | 22 | OP_CB_RECALL = 4, |
23 | /* Callback operations new to NFSv4.1 */ | ||
24 | OP_CB_LAYOUTRECALL = 5, | ||
25 | OP_CB_NOTIFY = 6, | ||
26 | OP_CB_PUSH_DELEG = 7, | ||
27 | OP_CB_RECALL_ANY = 8, | ||
28 | OP_CB_RECALLABLE_OBJ_AVAIL = 9, | ||
29 | OP_CB_RECALL_SLOT = 10, | ||
30 | OP_CB_SEQUENCE = 11, | ||
31 | OP_CB_WANTS_CANCELLED = 12, | ||
32 | OP_CB_NOTIFY_LOCK = 13, | ||
33 | OP_CB_NOTIFY_DEVICEID = 14, | ||
23 | OP_CB_ILLEGAL = 10044, | 34 | OP_CB_ILLEGAL = 10044, |
24 | }; | 35 | }; |
25 | 36 | ||
26 | struct cb_compound_hdr_arg { | 37 | struct cb_compound_hdr_arg { |
27 | unsigned int taglen; | 38 | unsigned int taglen; |
28 | const char *tag; | 39 | const char *tag; |
29 | unsigned int callback_ident; | 40 | unsigned int minorversion; |
30 | unsigned nops; | 41 | unsigned nops; |
31 | }; | 42 | }; |
32 | 43 | ||
@@ -59,16 +70,59 @@ struct cb_recallargs { | |||
59 | uint32_t truncate; | 70 | uint32_t truncate; |
60 | }; | 71 | }; |
61 | 72 | ||
73 | #if defined(CONFIG_NFS_V4_1) | ||
74 | |||
75 | struct referring_call { | ||
76 | uint32_t rc_sequenceid; | ||
77 | uint32_t rc_slotid; | ||
78 | }; | ||
79 | |||
80 | struct referring_call_list { | ||
81 | struct nfs4_sessionid rcl_sessionid; | ||
82 | uint32_t rcl_nrefcalls; | ||
83 | struct referring_call *rcl_refcalls; | ||
84 | }; | ||
85 | |||
86 | struct cb_sequenceargs { | ||
87 | struct sockaddr *csa_addr; | ||
88 | struct nfs4_sessionid csa_sessionid; | ||
89 | uint32_t csa_sequenceid; | ||
90 | uint32_t csa_slotid; | ||
91 | uint32_t csa_highestslotid; | ||
92 | uint32_t csa_cachethis; | ||
93 | uint32_t csa_nrclists; | ||
94 | struct referring_call_list *csa_rclists; | ||
95 | }; | ||
96 | |||
97 | struct cb_sequenceres { | ||
98 | __be32 csr_status; | ||
99 | struct nfs4_sessionid csr_sessionid; | ||
100 | uint32_t csr_sequenceid; | ||
101 | uint32_t csr_slotid; | ||
102 | uint32_t csr_highestslotid; | ||
103 | uint32_t csr_target_highestslotid; | ||
104 | }; | ||
105 | |||
106 | extern unsigned nfs4_callback_sequence(struct cb_sequenceargs *args, | ||
107 | struct cb_sequenceres *res); | ||
108 | |||
109 | #endif /* CONFIG_NFS_V4_1 */ | ||
110 | |||
62 | extern __be32 nfs4_callback_getattr(struct cb_getattrargs *args, struct cb_getattrres *res); | 111 | extern __be32 nfs4_callback_getattr(struct cb_getattrargs *args, struct cb_getattrres *res); |
63 | extern __be32 nfs4_callback_recall(struct cb_recallargs *args, void *dummy); | 112 | extern __be32 nfs4_callback_recall(struct cb_recallargs *args, void *dummy); |
64 | 113 | ||
65 | #ifdef CONFIG_NFS_V4 | 114 | #ifdef CONFIG_NFS_V4 |
66 | extern int nfs_callback_up(void); | 115 | extern int nfs_callback_up(u32 minorversion, struct rpc_xprt *xprt); |
67 | extern void nfs_callback_down(void); | 116 | extern void nfs_callback_down(int minorversion); |
68 | #else | 117 | #endif /* CONFIG_NFS_V4 */ |
69 | #define nfs_callback_up() (0) | 118 | |
70 | #define nfs_callback_down() do {} while(0) | 119 | /* |
71 | #endif | 120 | * nfs41: Callbacks are expected to not cause substantial latency, |
121 | * so we limit their concurrency to 1 by setting up the maximum number | ||
122 | * of slots for the backchannel. | ||
123 | */ | ||
124 | #define NFS41_BC_MIN_CALLBACKS 1 | ||
125 | #define NFS41_BC_MAX_CALLBACKS 1 | ||
72 | 126 | ||
73 | extern unsigned int nfs_callback_set_tcpport; | 127 | extern unsigned int nfs_callback_set_tcpport; |
74 | extern unsigned short nfs_callback_tcpport; | 128 | extern unsigned short nfs_callback_tcpport; |
diff --git a/fs/nfs/callback_proc.c b/fs/nfs/callback_proc.c index f7e83e23cf9f..b7da1f54da68 100644 --- a/fs/nfs/callback_proc.c +++ b/fs/nfs/callback_proc.c | |||
@@ -101,3 +101,130 @@ out: | |||
101 | dprintk("%s: exit with status = %d\n", __func__, ntohl(res)); | 101 | dprintk("%s: exit with status = %d\n", __func__, ntohl(res)); |
102 | return res; | 102 | return res; |
103 | } | 103 | } |
104 | |||
105 | #if defined(CONFIG_NFS_V4_1) | ||
106 | |||
107 | /* | ||
108 | * Validate the sequenceID sent by the server. | ||
109 | * Return success if the sequenceID is one more than what we last saw on | ||
110 | * this slot, accounting for wraparound. Increments the slot's sequence. | ||
111 | * | ||
112 | * We don't yet implement a duplicate request cache, so at this time | ||
113 | * we will log replays, and process them as if we had not seen them before, | ||
114 | * but we don't bump the sequence in the slot. Not too worried about it, | ||
115 | * since we only currently implement idempotent callbacks anyway. | ||
116 | * | ||
117 | * We have a single slot backchannel at this time, so we don't bother | ||
118 | * checking the used_slots bit array on the table. The lower layer guarantees | ||
119 | * a single outstanding callback request at a time. | ||
120 | */ | ||
121 | static int | ||
122 | validate_seqid(struct nfs4_slot_table *tbl, u32 slotid, u32 seqid) | ||
123 | { | ||
124 | struct nfs4_slot *slot; | ||
125 | |||
126 | dprintk("%s enter. slotid %d seqid %d\n", | ||
127 | __func__, slotid, seqid); | ||
128 | |||
129 | if (slotid > NFS41_BC_MAX_CALLBACKS) | ||
130 | return htonl(NFS4ERR_BADSLOT); | ||
131 | |||
132 | slot = tbl->slots + slotid; | ||
133 | dprintk("%s slot table seqid: %d\n", __func__, slot->seq_nr); | ||
134 | |||
135 | /* Normal */ | ||
136 | if (likely(seqid == slot->seq_nr + 1)) { | ||
137 | slot->seq_nr++; | ||
138 | return htonl(NFS4_OK); | ||
139 | } | ||
140 | |||
141 | /* Replay */ | ||
142 | if (seqid == slot->seq_nr) { | ||
143 | dprintk("%s seqid %d is a replay - no DRC available\n", | ||
144 | __func__, seqid); | ||
145 | return htonl(NFS4_OK); | ||
146 | } | ||
147 | |||
148 | /* Wraparound */ | ||
149 | if (seqid == 1 && (slot->seq_nr + 1) == 0) { | ||
150 | slot->seq_nr = 1; | ||
151 | return htonl(NFS4_OK); | ||
152 | } | ||
153 | |||
154 | /* Misordered request */ | ||
155 | return htonl(NFS4ERR_SEQ_MISORDERED); | ||
156 | } | ||
157 | |||
158 | /* | ||
159 | * Returns a pointer to a held 'struct nfs_client' that matches the server's | ||
160 | * address, major version number, and session ID. It is the caller's | ||
161 | * responsibility to release the returned reference. | ||
162 | * | ||
163 | * Returns NULL if there are no connections with sessions, or if no session | ||
164 | * matches the one of interest. | ||
165 | */ | ||
166 | static struct nfs_client *find_client_with_session( | ||
167 | const struct sockaddr *addr, u32 nfsversion, | ||
168 | struct nfs4_sessionid *sessionid) | ||
169 | { | ||
170 | struct nfs_client *clp; | ||
171 | |||
172 | clp = nfs_find_client(addr, 4); | ||
173 | if (clp == NULL) | ||
174 | return NULL; | ||
175 | |||
176 | do { | ||
177 | struct nfs_client *prev = clp; | ||
178 | |||
179 | if (clp->cl_session != NULL) { | ||
180 | if (memcmp(clp->cl_session->sess_id.data, | ||
181 | sessionid->data, | ||
182 | NFS4_MAX_SESSIONID_LEN) == 0) { | ||
183 | /* Returns a held reference to clp */ | ||
184 | return clp; | ||
185 | } | ||
186 | } | ||
187 | clp = nfs_find_client_next(prev); | ||
188 | nfs_put_client(prev); | ||
189 | } while (clp != NULL); | ||
190 | |||
191 | return NULL; | ||
192 | } | ||
193 | |||
194 | /* FIXME: referring calls should be processed */ | ||
195 | unsigned nfs4_callback_sequence(struct cb_sequenceargs *args, | ||
196 | struct cb_sequenceres *res) | ||
197 | { | ||
198 | struct nfs_client *clp; | ||
199 | int i, status; | ||
200 | |||
201 | for (i = 0; i < args->csa_nrclists; i++) | ||
202 | kfree(args->csa_rclists[i].rcl_refcalls); | ||
203 | kfree(args->csa_rclists); | ||
204 | |||
205 | status = htonl(NFS4ERR_BADSESSION); | ||
206 | clp = find_client_with_session(args->csa_addr, 4, &args->csa_sessionid); | ||
207 | if (clp == NULL) | ||
208 | goto out; | ||
209 | |||
210 | status = validate_seqid(&clp->cl_session->bc_slot_table, | ||
211 | args->csa_slotid, args->csa_sequenceid); | ||
212 | if (status) | ||
213 | goto out_putclient; | ||
214 | |||
215 | memcpy(&res->csr_sessionid, &args->csa_sessionid, | ||
216 | sizeof(res->csr_sessionid)); | ||
217 | res->csr_sequenceid = args->csa_sequenceid; | ||
218 | res->csr_slotid = args->csa_slotid; | ||
219 | res->csr_highestslotid = NFS41_BC_MAX_CALLBACKS - 1; | ||
220 | res->csr_target_highestslotid = NFS41_BC_MAX_CALLBACKS - 1; | ||
221 | |||
222 | out_putclient: | ||
223 | nfs_put_client(clp); | ||
224 | out: | ||
225 | dprintk("%s: exit with status = %d\n", __func__, ntohl(status)); | ||
226 | res->csr_status = status; | ||
227 | return res->csr_status; | ||
228 | } | ||
229 | |||
230 | #endif /* CONFIG_NFS_V4_1 */ | ||
diff --git a/fs/nfs/callback_xdr.c b/fs/nfs/callback_xdr.c index dd0ef34b5845..e5a2dac5f715 100644 --- a/fs/nfs/callback_xdr.c +++ b/fs/nfs/callback_xdr.c | |||
@@ -20,6 +20,11 @@ | |||
20 | 2 + 2 + 3 + 3) | 20 | 2 + 2 + 3 + 3) |
21 | #define CB_OP_RECALL_RES_MAXSZ (CB_OP_HDR_RES_MAXSZ) | 21 | #define CB_OP_RECALL_RES_MAXSZ (CB_OP_HDR_RES_MAXSZ) |
22 | 22 | ||
23 | #if defined(CONFIG_NFS_V4_1) | ||
24 | #define CB_OP_SEQUENCE_RES_MAXSZ (CB_OP_HDR_RES_MAXSZ + \ | ||
25 | 4 + 1 + 3) | ||
26 | #endif /* CONFIG_NFS_V4_1 */ | ||
27 | |||
23 | #define NFSDBG_FACILITY NFSDBG_CALLBACK | 28 | #define NFSDBG_FACILITY NFSDBG_CALLBACK |
24 | 29 | ||
25 | typedef __be32 (*callback_process_op_t)(void *, void *); | 30 | typedef __be32 (*callback_process_op_t)(void *, void *); |
@@ -132,7 +137,6 @@ static __be32 decode_stateid(struct xdr_stream *xdr, nfs4_stateid *stateid) | |||
132 | static __be32 decode_compound_hdr_arg(struct xdr_stream *xdr, struct cb_compound_hdr_arg *hdr) | 137 | static __be32 decode_compound_hdr_arg(struct xdr_stream *xdr, struct cb_compound_hdr_arg *hdr) |
133 | { | 138 | { |
134 | __be32 *p; | 139 | __be32 *p; |
135 | unsigned int minor_version; | ||
136 | __be32 status; | 140 | __be32 status; |
137 | 141 | ||
138 | status = decode_string(xdr, &hdr->taglen, &hdr->tag); | 142 | status = decode_string(xdr, &hdr->taglen, &hdr->tag); |
@@ -147,15 +151,19 @@ static __be32 decode_compound_hdr_arg(struct xdr_stream *xdr, struct cb_compound | |||
147 | p = read_buf(xdr, 12); | 151 | p = read_buf(xdr, 12); |
148 | if (unlikely(p == NULL)) | 152 | if (unlikely(p == NULL)) |
149 | return htonl(NFS4ERR_RESOURCE); | 153 | return htonl(NFS4ERR_RESOURCE); |
150 | minor_version = ntohl(*p++); | 154 | hdr->minorversion = ntohl(*p++); |
151 | /* Check minor version is zero. */ | 155 | /* Check minor version is zero or one. */ |
152 | if (minor_version != 0) { | 156 | if (hdr->minorversion <= 1) { |
153 | printk(KERN_WARNING "%s: NFSv4 server callback with illegal minor version %u!\n", | 157 | p++; /* skip callback_ident */ |
154 | __func__, minor_version); | 158 | } else { |
159 | printk(KERN_WARNING "%s: NFSv4 server callback with " | ||
160 | "illegal minor version %u!\n", | ||
161 | __func__, hdr->minorversion); | ||
155 | return htonl(NFS4ERR_MINOR_VERS_MISMATCH); | 162 | return htonl(NFS4ERR_MINOR_VERS_MISMATCH); |
156 | } | 163 | } |
157 | hdr->callback_ident = ntohl(*p++); | ||
158 | hdr->nops = ntohl(*p); | 164 | hdr->nops = ntohl(*p); |
165 | dprintk("%s: minorversion %d nops %d\n", __func__, | ||
166 | hdr->minorversion, hdr->nops); | ||
159 | return 0; | 167 | return 0; |
160 | } | 168 | } |
161 | 169 | ||
@@ -204,6 +212,122 @@ out: | |||
204 | return status; | 212 | return status; |
205 | } | 213 | } |
206 | 214 | ||
215 | #if defined(CONFIG_NFS_V4_1) | ||
216 | |||
217 | static unsigned decode_sessionid(struct xdr_stream *xdr, | ||
218 | struct nfs4_sessionid *sid) | ||
219 | { | ||
220 | uint32_t *p; | ||
221 | int len = NFS4_MAX_SESSIONID_LEN; | ||
222 | |||
223 | p = read_buf(xdr, len); | ||
224 | if (unlikely(p == NULL)) | ||
225 | return htonl(NFS4ERR_RESOURCE);; | ||
226 | |||
227 | memcpy(sid->data, p, len); | ||
228 | return 0; | ||
229 | } | ||
230 | |||
231 | static unsigned decode_rc_list(struct xdr_stream *xdr, | ||
232 | struct referring_call_list *rc_list) | ||
233 | { | ||
234 | uint32_t *p; | ||
235 | int i; | ||
236 | unsigned status; | ||
237 | |||
238 | status = decode_sessionid(xdr, &rc_list->rcl_sessionid); | ||
239 | if (status) | ||
240 | goto out; | ||
241 | |||
242 | status = htonl(NFS4ERR_RESOURCE); | ||
243 | p = read_buf(xdr, sizeof(uint32_t)); | ||
244 | if (unlikely(p == NULL)) | ||
245 | goto out; | ||
246 | |||
247 | rc_list->rcl_nrefcalls = ntohl(*p++); | ||
248 | if (rc_list->rcl_nrefcalls) { | ||
249 | p = read_buf(xdr, | ||
250 | rc_list->rcl_nrefcalls * 2 * sizeof(uint32_t)); | ||
251 | if (unlikely(p == NULL)) | ||
252 | goto out; | ||
253 | rc_list->rcl_refcalls = kmalloc(rc_list->rcl_nrefcalls * | ||
254 | sizeof(*rc_list->rcl_refcalls), | ||
255 | GFP_KERNEL); | ||
256 | if (unlikely(rc_list->rcl_refcalls == NULL)) | ||
257 | goto out; | ||
258 | for (i = 0; i < rc_list->rcl_nrefcalls; i++) { | ||
259 | rc_list->rcl_refcalls[i].rc_sequenceid = ntohl(*p++); | ||
260 | rc_list->rcl_refcalls[i].rc_slotid = ntohl(*p++); | ||
261 | } | ||
262 | } | ||
263 | status = 0; | ||
264 | |||
265 | out: | ||
266 | return status; | ||
267 | } | ||
268 | |||
269 | static unsigned decode_cb_sequence_args(struct svc_rqst *rqstp, | ||
270 | struct xdr_stream *xdr, | ||
271 | struct cb_sequenceargs *args) | ||
272 | { | ||
273 | uint32_t *p; | ||
274 | int i; | ||
275 | unsigned status; | ||
276 | |||
277 | status = decode_sessionid(xdr, &args->csa_sessionid); | ||
278 | if (status) | ||
279 | goto out; | ||
280 | |||
281 | status = htonl(NFS4ERR_RESOURCE); | ||
282 | p = read_buf(xdr, 5 * sizeof(uint32_t)); | ||
283 | if (unlikely(p == NULL)) | ||
284 | goto out; | ||
285 | |||
286 | args->csa_addr = svc_addr(rqstp); | ||
287 | args->csa_sequenceid = ntohl(*p++); | ||
288 | args->csa_slotid = ntohl(*p++); | ||
289 | args->csa_highestslotid = ntohl(*p++); | ||
290 | args->csa_cachethis = ntohl(*p++); | ||
291 | args->csa_nrclists = ntohl(*p++); | ||
292 | args->csa_rclists = NULL; | ||
293 | if (args->csa_nrclists) { | ||
294 | args->csa_rclists = kmalloc(args->csa_nrclists * | ||
295 | sizeof(*args->csa_rclists), | ||
296 | GFP_KERNEL); | ||
297 | if (unlikely(args->csa_rclists == NULL)) | ||
298 | goto out; | ||
299 | |||
300 | for (i = 0; i < args->csa_nrclists; i++) { | ||
301 | status = decode_rc_list(xdr, &args->csa_rclists[i]); | ||
302 | if (status) | ||
303 | goto out_free; | ||
304 | } | ||
305 | } | ||
306 | status = 0; | ||
307 | |||
308 | dprintk("%s: sessionid %x:%x:%x:%x sequenceid %u slotid %u " | ||
309 | "highestslotid %u cachethis %d nrclists %u\n", | ||
310 | __func__, | ||
311 | ((u32 *)&args->csa_sessionid)[0], | ||
312 | ((u32 *)&args->csa_sessionid)[1], | ||
313 | ((u32 *)&args->csa_sessionid)[2], | ||
314 | ((u32 *)&args->csa_sessionid)[3], | ||
315 | args->csa_sequenceid, args->csa_slotid, | ||
316 | args->csa_highestslotid, args->csa_cachethis, | ||
317 | args->csa_nrclists); | ||
318 | out: | ||
319 | dprintk("%s: exit with status = %d\n", __func__, ntohl(status)); | ||
320 | return status; | ||
321 | |||
322 | out_free: | ||
323 | for (i = 0; i < args->csa_nrclists; i++) | ||
324 | kfree(args->csa_rclists[i].rcl_refcalls); | ||
325 | kfree(args->csa_rclists); | ||
326 | goto out; | ||
327 | } | ||
328 | |||
329 | #endif /* CONFIG_NFS_V4_1 */ | ||
330 | |||
207 | static __be32 encode_string(struct xdr_stream *xdr, unsigned int len, const char *str) | 331 | static __be32 encode_string(struct xdr_stream *xdr, unsigned int len, const char *str) |
208 | { | 332 | { |
209 | __be32 *p; | 333 | __be32 *p; |
@@ -353,31 +477,134 @@ out: | |||
353 | return status; | 477 | return status; |
354 | } | 478 | } |
355 | 479 | ||
356 | static __be32 process_op(struct svc_rqst *rqstp, | 480 | #if defined(CONFIG_NFS_V4_1) |
481 | |||
482 | static unsigned encode_sessionid(struct xdr_stream *xdr, | ||
483 | const struct nfs4_sessionid *sid) | ||
484 | { | ||
485 | uint32_t *p; | ||
486 | int len = NFS4_MAX_SESSIONID_LEN; | ||
487 | |||
488 | p = xdr_reserve_space(xdr, len); | ||
489 | if (unlikely(p == NULL)) | ||
490 | return htonl(NFS4ERR_RESOURCE); | ||
491 | |||
492 | memcpy(p, sid, len); | ||
493 | return 0; | ||
494 | } | ||
495 | |||
496 | static unsigned encode_cb_sequence_res(struct svc_rqst *rqstp, | ||
497 | struct xdr_stream *xdr, | ||
498 | const struct cb_sequenceres *res) | ||
499 | { | ||
500 | uint32_t *p; | ||
501 | unsigned status = res->csr_status; | ||
502 | |||
503 | if (unlikely(status != 0)) | ||
504 | goto out; | ||
505 | |||
506 | encode_sessionid(xdr, &res->csr_sessionid); | ||
507 | |||
508 | p = xdr_reserve_space(xdr, 4 * sizeof(uint32_t)); | ||
509 | if (unlikely(p == NULL)) | ||
510 | return htonl(NFS4ERR_RESOURCE); | ||
511 | |||
512 | *p++ = htonl(res->csr_sequenceid); | ||
513 | *p++ = htonl(res->csr_slotid); | ||
514 | *p++ = htonl(res->csr_highestslotid); | ||
515 | *p++ = htonl(res->csr_target_highestslotid); | ||
516 | out: | ||
517 | dprintk("%s: exit with status = %d\n", __func__, ntohl(status)); | ||
518 | return status; | ||
519 | } | ||
520 | |||
521 | static __be32 | ||
522 | preprocess_nfs41_op(int nop, unsigned int op_nr, struct callback_op **op) | ||
523 | { | ||
524 | if (op_nr == OP_CB_SEQUENCE) { | ||
525 | if (nop != 0) | ||
526 | return htonl(NFS4ERR_SEQUENCE_POS); | ||
527 | } else { | ||
528 | if (nop == 0) | ||
529 | return htonl(NFS4ERR_OP_NOT_IN_SESSION); | ||
530 | } | ||
531 | |||
532 | switch (op_nr) { | ||
533 | case OP_CB_GETATTR: | ||
534 | case OP_CB_RECALL: | ||
535 | case OP_CB_SEQUENCE: | ||
536 | *op = &callback_ops[op_nr]; | ||
537 | break; | ||
538 | |||
539 | case OP_CB_LAYOUTRECALL: | ||
540 | case OP_CB_NOTIFY_DEVICEID: | ||
541 | case OP_CB_NOTIFY: | ||
542 | case OP_CB_PUSH_DELEG: | ||
543 | case OP_CB_RECALL_ANY: | ||
544 | case OP_CB_RECALLABLE_OBJ_AVAIL: | ||
545 | case OP_CB_RECALL_SLOT: | ||
546 | case OP_CB_WANTS_CANCELLED: | ||
547 | case OP_CB_NOTIFY_LOCK: | ||
548 | return htonl(NFS4ERR_NOTSUPP); | ||
549 | |||
550 | default: | ||
551 | return htonl(NFS4ERR_OP_ILLEGAL); | ||
552 | } | ||
553 | |||
554 | return htonl(NFS_OK); | ||
555 | } | ||
556 | |||
557 | #else /* CONFIG_NFS_V4_1 */ | ||
558 | |||
559 | static __be32 | ||
560 | preprocess_nfs41_op(int nop, unsigned int op_nr, struct callback_op **op) | ||
561 | { | ||
562 | return htonl(NFS4ERR_MINOR_VERS_MISMATCH); | ||
563 | } | ||
564 | |||
565 | #endif /* CONFIG_NFS_V4_1 */ | ||
566 | |||
567 | static __be32 | ||
568 | preprocess_nfs4_op(unsigned int op_nr, struct callback_op **op) | ||
569 | { | ||
570 | switch (op_nr) { | ||
571 | case OP_CB_GETATTR: | ||
572 | case OP_CB_RECALL: | ||
573 | *op = &callback_ops[op_nr]; | ||
574 | break; | ||
575 | default: | ||
576 | return htonl(NFS4ERR_OP_ILLEGAL); | ||
577 | } | ||
578 | |||
579 | return htonl(NFS_OK); | ||
580 | } | ||
581 | |||
582 | static __be32 process_op(uint32_t minorversion, int nop, | ||
583 | struct svc_rqst *rqstp, | ||
357 | struct xdr_stream *xdr_in, void *argp, | 584 | struct xdr_stream *xdr_in, void *argp, |
358 | struct xdr_stream *xdr_out, void *resp) | 585 | struct xdr_stream *xdr_out, void *resp) |
359 | { | 586 | { |
360 | struct callback_op *op = &callback_ops[0]; | 587 | struct callback_op *op = &callback_ops[0]; |
361 | unsigned int op_nr = OP_CB_ILLEGAL; | 588 | unsigned int op_nr = OP_CB_ILLEGAL; |
362 | __be32 status = 0; | 589 | __be32 status; |
363 | long maxlen; | 590 | long maxlen; |
364 | __be32 res; | 591 | __be32 res; |
365 | 592 | ||
366 | dprintk("%s: start\n", __func__); | 593 | dprintk("%s: start\n", __func__); |
367 | status = decode_op_hdr(xdr_in, &op_nr); | 594 | status = decode_op_hdr(xdr_in, &op_nr); |
368 | if (likely(status == 0)) { | 595 | if (unlikely(status)) { |
369 | switch (op_nr) { | 596 | status = htonl(NFS4ERR_OP_ILLEGAL); |
370 | case OP_CB_GETATTR: | 597 | goto out; |
371 | case OP_CB_RECALL: | ||
372 | op = &callback_ops[op_nr]; | ||
373 | break; | ||
374 | default: | ||
375 | op_nr = OP_CB_ILLEGAL; | ||
376 | op = &callback_ops[0]; | ||
377 | status = htonl(NFS4ERR_OP_ILLEGAL); | ||
378 | } | ||
379 | } | 598 | } |
380 | 599 | ||
600 | dprintk("%s: minorversion=%d nop=%d op_nr=%u\n", | ||
601 | __func__, minorversion, nop, op_nr); | ||
602 | |||
603 | status = minorversion ? preprocess_nfs41_op(nop, op_nr, &op) : | ||
604 | preprocess_nfs4_op(op_nr, &op); | ||
605 | if (status == htonl(NFS4ERR_OP_ILLEGAL)) | ||
606 | op_nr = OP_CB_ILLEGAL; | ||
607 | out: | ||
381 | maxlen = xdr_out->end - xdr_out->p; | 608 | maxlen = xdr_out->end - xdr_out->p; |
382 | if (maxlen > 0 && maxlen < PAGE_SIZE) { | 609 | if (maxlen > 0 && maxlen < PAGE_SIZE) { |
383 | if (likely(status == 0 && op->decode_args != NULL)) | 610 | if (likely(status == 0 && op->decode_args != NULL)) |
@@ -425,7 +652,8 @@ static __be32 nfs4_callback_compound(struct svc_rqst *rqstp, void *argp, void *r | |||
425 | return rpc_system_err; | 652 | return rpc_system_err; |
426 | 653 | ||
427 | while (status == 0 && nops != hdr_arg.nops) { | 654 | while (status == 0 && nops != hdr_arg.nops) { |
428 | status = process_op(rqstp, &xdr_in, argp, &xdr_out, resp); | 655 | status = process_op(hdr_arg.minorversion, nops, |
656 | rqstp, &xdr_in, argp, &xdr_out, resp); | ||
429 | nops++; | 657 | nops++; |
430 | } | 658 | } |
431 | 659 | ||
@@ -452,7 +680,15 @@ static struct callback_op callback_ops[] = { | |||
452 | .process_op = (callback_process_op_t)nfs4_callback_recall, | 680 | .process_op = (callback_process_op_t)nfs4_callback_recall, |
453 | .decode_args = (callback_decode_arg_t)decode_recall_args, | 681 | .decode_args = (callback_decode_arg_t)decode_recall_args, |
454 | .res_maxsize = CB_OP_RECALL_RES_MAXSZ, | 682 | .res_maxsize = CB_OP_RECALL_RES_MAXSZ, |
455 | } | 683 | }, |
684 | #if defined(CONFIG_NFS_V4_1) | ||
685 | [OP_CB_SEQUENCE] = { | ||
686 | .process_op = (callback_process_op_t)nfs4_callback_sequence, | ||
687 | .decode_args = (callback_decode_arg_t)decode_cb_sequence_args, | ||
688 | .encode_res = (callback_encode_res_t)encode_cb_sequence_res, | ||
689 | .res_maxsize = CB_OP_SEQUENCE_RES_MAXSZ, | ||
690 | }, | ||
691 | #endif /* CONFIG_NFS_V4_1 */ | ||
456 | }; | 692 | }; |
457 | 693 | ||
458 | /* | 694 | /* |
diff --git a/fs/nfs/client.c b/fs/nfs/client.c index 75c9cd2aa119..c2d061675d80 100644 --- a/fs/nfs/client.c +++ b/fs/nfs/client.c | |||
@@ -37,6 +37,7 @@ | |||
37 | #include <linux/in6.h> | 37 | #include <linux/in6.h> |
38 | #include <net/ipv6.h> | 38 | #include <net/ipv6.h> |
39 | #include <linux/nfs_xdr.h> | 39 | #include <linux/nfs_xdr.h> |
40 | #include <linux/sunrpc/bc_xprt.h> | ||
40 | 41 | ||
41 | #include <asm/system.h> | 42 | #include <asm/system.h> |
42 | 43 | ||
@@ -102,6 +103,7 @@ struct nfs_client_initdata { | |||
102 | size_t addrlen; | 103 | size_t addrlen; |
103 | const struct nfs_rpc_ops *rpc_ops; | 104 | const struct nfs_rpc_ops *rpc_ops; |
104 | int proto; | 105 | int proto; |
106 | u32 minorversion; | ||
105 | }; | 107 | }; |
106 | 108 | ||
107 | /* | 109 | /* |
@@ -114,18 +116,13 @@ static struct nfs_client *nfs_alloc_client(const struct nfs_client_initdata *cl_ | |||
114 | { | 116 | { |
115 | struct nfs_client *clp; | 117 | struct nfs_client *clp; |
116 | struct rpc_cred *cred; | 118 | struct rpc_cred *cred; |
119 | int err = -ENOMEM; | ||
117 | 120 | ||
118 | if ((clp = kzalloc(sizeof(*clp), GFP_KERNEL)) == NULL) | 121 | if ((clp = kzalloc(sizeof(*clp), GFP_KERNEL)) == NULL) |
119 | goto error_0; | 122 | goto error_0; |
120 | 123 | ||
121 | clp->rpc_ops = cl_init->rpc_ops; | 124 | clp->rpc_ops = cl_init->rpc_ops; |
122 | 125 | ||
123 | if (cl_init->rpc_ops->version == 4) { | ||
124 | if (nfs_callback_up() < 0) | ||
125 | goto error_2; | ||
126 | __set_bit(NFS_CS_CALLBACK, &clp->cl_res_state); | ||
127 | } | ||
128 | |||
129 | atomic_set(&clp->cl_count, 1); | 126 | atomic_set(&clp->cl_count, 1); |
130 | clp->cl_cons_state = NFS_CS_INITING; | 127 | clp->cl_cons_state = NFS_CS_INITING; |
131 | 128 | ||
@@ -133,9 +130,10 @@ static struct nfs_client *nfs_alloc_client(const struct nfs_client_initdata *cl_ | |||
133 | clp->cl_addrlen = cl_init->addrlen; | 130 | clp->cl_addrlen = cl_init->addrlen; |
134 | 131 | ||
135 | if (cl_init->hostname) { | 132 | if (cl_init->hostname) { |
133 | err = -ENOMEM; | ||
136 | clp->cl_hostname = kstrdup(cl_init->hostname, GFP_KERNEL); | 134 | clp->cl_hostname = kstrdup(cl_init->hostname, GFP_KERNEL); |
137 | if (!clp->cl_hostname) | 135 | if (!clp->cl_hostname) |
138 | goto error_3; | 136 | goto error_cleanup; |
139 | } | 137 | } |
140 | 138 | ||
141 | INIT_LIST_HEAD(&clp->cl_superblocks); | 139 | INIT_LIST_HEAD(&clp->cl_superblocks); |
@@ -150,6 +148,7 @@ static struct nfs_client *nfs_alloc_client(const struct nfs_client_initdata *cl_ | |||
150 | rpc_init_wait_queue(&clp->cl_rpcwaitq, "NFS client"); | 148 | rpc_init_wait_queue(&clp->cl_rpcwaitq, "NFS client"); |
151 | clp->cl_boot_time = CURRENT_TIME; | 149 | clp->cl_boot_time = CURRENT_TIME; |
152 | clp->cl_state = 1 << NFS4CLNT_LEASE_EXPIRED; | 150 | clp->cl_state = 1 << NFS4CLNT_LEASE_EXPIRED; |
151 | clp->cl_minorversion = cl_init->minorversion; | ||
153 | #endif | 152 | #endif |
154 | cred = rpc_lookup_machine_cred(); | 153 | cred = rpc_lookup_machine_cred(); |
155 | if (!IS_ERR(cred)) | 154 | if (!IS_ERR(cred)) |
@@ -159,13 +158,10 @@ static struct nfs_client *nfs_alloc_client(const struct nfs_client_initdata *cl_ | |||
159 | 158 | ||
160 | return clp; | 159 | return clp; |
161 | 160 | ||
162 | error_3: | 161 | error_cleanup: |
163 | if (__test_and_clear_bit(NFS_CS_CALLBACK, &clp->cl_res_state)) | ||
164 | nfs_callback_down(); | ||
165 | error_2: | ||
166 | kfree(clp); | 162 | kfree(clp); |
167 | error_0: | 163 | error_0: |
168 | return NULL; | 164 | return ERR_PTR(err); |
169 | } | 165 | } |
170 | 166 | ||
171 | static void nfs4_shutdown_client(struct nfs_client *clp) | 167 | static void nfs4_shutdown_client(struct nfs_client *clp) |
@@ -182,12 +178,42 @@ static void nfs4_shutdown_client(struct nfs_client *clp) | |||
182 | } | 178 | } |
183 | 179 | ||
184 | /* | 180 | /* |
181 | * Destroy the NFS4 callback service | ||
182 | */ | ||
183 | static void nfs4_destroy_callback(struct nfs_client *clp) | ||
184 | { | ||
185 | #ifdef CONFIG_NFS_V4 | ||
186 | if (__test_and_clear_bit(NFS_CS_CALLBACK, &clp->cl_res_state)) | ||
187 | nfs_callback_down(clp->cl_minorversion); | ||
188 | #endif /* CONFIG_NFS_V4 */ | ||
189 | } | ||
190 | |||
191 | /* | ||
192 | * Clears/puts all minor version specific parts from an nfs_client struct | ||
193 | * reverting it to minorversion 0. | ||
194 | */ | ||
195 | static void nfs4_clear_client_minor_version(struct nfs_client *clp) | ||
196 | { | ||
197 | #ifdef CONFIG_NFS_V4_1 | ||
198 | if (nfs4_has_session(clp)) { | ||
199 | nfs4_destroy_session(clp->cl_session); | ||
200 | clp->cl_session = NULL; | ||
201 | } | ||
202 | |||
203 | clp->cl_call_sync = _nfs4_call_sync; | ||
204 | #endif /* CONFIG_NFS_V4_1 */ | ||
205 | |||
206 | nfs4_destroy_callback(clp); | ||
207 | } | ||
208 | |||
209 | /* | ||
185 | * Destroy a shared client record | 210 | * Destroy a shared client record |
186 | */ | 211 | */ |
187 | static void nfs_free_client(struct nfs_client *clp) | 212 | static void nfs_free_client(struct nfs_client *clp) |
188 | { | 213 | { |
189 | dprintk("--> nfs_free_client(%u)\n", clp->rpc_ops->version); | 214 | dprintk("--> nfs_free_client(%u)\n", clp->rpc_ops->version); |
190 | 215 | ||
216 | nfs4_clear_client_minor_version(clp); | ||
191 | nfs4_shutdown_client(clp); | 217 | nfs4_shutdown_client(clp); |
192 | 218 | ||
193 | nfs_fscache_release_client_cookie(clp); | 219 | nfs_fscache_release_client_cookie(clp); |
@@ -196,9 +222,6 @@ static void nfs_free_client(struct nfs_client *clp) | |||
196 | if (!IS_ERR(clp->cl_rpcclient)) | 222 | if (!IS_ERR(clp->cl_rpcclient)) |
197 | rpc_shutdown_client(clp->cl_rpcclient); | 223 | rpc_shutdown_client(clp->cl_rpcclient); |
198 | 224 | ||
199 | if (__test_and_clear_bit(NFS_CS_CALLBACK, &clp->cl_res_state)) | ||
200 | nfs_callback_down(); | ||
201 | |||
202 | if (clp->cl_machine_cred != NULL) | 225 | if (clp->cl_machine_cred != NULL) |
203 | put_rpccred(clp->cl_machine_cred); | 226 | put_rpccred(clp->cl_machine_cred); |
204 | 227 | ||
@@ -347,7 +370,8 @@ struct nfs_client *nfs_find_client(const struct sockaddr *addr, u32 nfsversion) | |||
347 | struct sockaddr *clap = (struct sockaddr *)&clp->cl_addr; | 370 | struct sockaddr *clap = (struct sockaddr *)&clp->cl_addr; |
348 | 371 | ||
349 | /* Don't match clients that failed to initialise properly */ | 372 | /* Don't match clients that failed to initialise properly */ |
350 | if (clp->cl_cons_state != NFS_CS_READY) | 373 | if (!(clp->cl_cons_state == NFS_CS_READY || |
374 | clp->cl_cons_state == NFS_CS_SESSION_INITING)) | ||
351 | continue; | 375 | continue; |
352 | 376 | ||
353 | /* Different NFS versions cannot share the same nfs_client */ | 377 | /* Different NFS versions cannot share the same nfs_client */ |
@@ -420,7 +444,9 @@ static struct nfs_client *nfs_match_client(const struct nfs_client_initdata *dat | |||
420 | 444 | ||
421 | if (clp->cl_proto != data->proto) | 445 | if (clp->cl_proto != data->proto) |
422 | continue; | 446 | continue; |
423 | 447 | /* Match nfsv4 minorversion */ | |
448 | if (clp->cl_minorversion != data->minorversion) | ||
449 | continue; | ||
424 | /* Match the full socket address */ | 450 | /* Match the full socket address */ |
425 | if (!nfs_sockaddr_cmp(sap, clap)) | 451 | if (!nfs_sockaddr_cmp(sap, clap)) |
426 | continue; | 452 | continue; |
@@ -456,9 +482,10 @@ static struct nfs_client *nfs_get_client(const struct nfs_client_initdata *cl_in | |||
456 | spin_unlock(&nfs_client_lock); | 482 | spin_unlock(&nfs_client_lock); |
457 | 483 | ||
458 | new = nfs_alloc_client(cl_init); | 484 | new = nfs_alloc_client(cl_init); |
459 | } while (new); | 485 | } while (!IS_ERR(new)); |
460 | 486 | ||
461 | return ERR_PTR(-ENOMEM); | 487 | dprintk("--> nfs_get_client() = %ld [failed]\n", PTR_ERR(new)); |
488 | return new; | ||
462 | 489 | ||
463 | /* install a new client and return with it unready */ | 490 | /* install a new client and return with it unready */ |
464 | install_client: | 491 | install_client: |
@@ -478,7 +505,7 @@ found_client: | |||
478 | nfs_free_client(new); | 505 | nfs_free_client(new); |
479 | 506 | ||
480 | error = wait_event_killable(nfs_client_active_wq, | 507 | error = wait_event_killable(nfs_client_active_wq, |
481 | clp->cl_cons_state != NFS_CS_INITING); | 508 | clp->cl_cons_state < NFS_CS_INITING); |
482 | if (error < 0) { | 509 | if (error < 0) { |
483 | nfs_put_client(clp); | 510 | nfs_put_client(clp); |
484 | return ERR_PTR(-ERESTARTSYS); | 511 | return ERR_PTR(-ERESTARTSYS); |
@@ -499,13 +526,29 @@ found_client: | |||
499 | /* | 526 | /* |
500 | * Mark a server as ready or failed | 527 | * Mark a server as ready or failed |
501 | */ | 528 | */ |
502 | static void nfs_mark_client_ready(struct nfs_client *clp, int state) | 529 | void nfs_mark_client_ready(struct nfs_client *clp, int state) |
503 | { | 530 | { |
504 | clp->cl_cons_state = state; | 531 | clp->cl_cons_state = state; |
505 | wake_up_all(&nfs_client_active_wq); | 532 | wake_up_all(&nfs_client_active_wq); |
506 | } | 533 | } |
507 | 534 | ||
508 | /* | 535 | /* |
536 | * With sessions, the client is not marked ready until after a | ||
537 | * successful EXCHANGE_ID and CREATE_SESSION. | ||
538 | * | ||
539 | * Map errors cl_cons_state errors to EPROTONOSUPPORT to indicate | ||
540 | * other versions of NFS can be tried. | ||
541 | */ | ||
542 | int nfs4_check_client_ready(struct nfs_client *clp) | ||
543 | { | ||
544 | if (!nfs4_has_session(clp)) | ||
545 | return 0; | ||
546 | if (clp->cl_cons_state < NFS_CS_READY) | ||
547 | return -EPROTONOSUPPORT; | ||
548 | return 0; | ||
549 | } | ||
550 | |||
551 | /* | ||
509 | * Initialise the timeout values for a connection | 552 | * Initialise the timeout values for a connection |
510 | */ | 553 | */ |
511 | static void nfs_init_timeout_values(struct rpc_timeout *to, int proto, | 554 | static void nfs_init_timeout_values(struct rpc_timeout *to, int proto, |
@@ -1050,6 +1093,61 @@ error: | |||
1050 | 1093 | ||
1051 | #ifdef CONFIG_NFS_V4 | 1094 | #ifdef CONFIG_NFS_V4 |
1052 | /* | 1095 | /* |
1096 | * Initialize the NFS4 callback service | ||
1097 | */ | ||
1098 | static int nfs4_init_callback(struct nfs_client *clp) | ||
1099 | { | ||
1100 | int error; | ||
1101 | |||
1102 | if (clp->rpc_ops->version == 4) { | ||
1103 | if (nfs4_has_session(clp)) { | ||
1104 | error = xprt_setup_backchannel( | ||
1105 | clp->cl_rpcclient->cl_xprt, | ||
1106 | NFS41_BC_MIN_CALLBACKS); | ||
1107 | if (error < 0) | ||
1108 | return error; | ||
1109 | } | ||
1110 | |||
1111 | error = nfs_callback_up(clp->cl_minorversion, | ||
1112 | clp->cl_rpcclient->cl_xprt); | ||
1113 | if (error < 0) { | ||
1114 | dprintk("%s: failed to start callback. Error = %d\n", | ||
1115 | __func__, error); | ||
1116 | return error; | ||
1117 | } | ||
1118 | __set_bit(NFS_CS_CALLBACK, &clp->cl_res_state); | ||
1119 | } | ||
1120 | return 0; | ||
1121 | } | ||
1122 | |||
1123 | /* | ||
1124 | * Initialize the minor version specific parts of an NFS4 client record | ||
1125 | */ | ||
1126 | static int nfs4_init_client_minor_version(struct nfs_client *clp) | ||
1127 | { | ||
1128 | clp->cl_call_sync = _nfs4_call_sync; | ||
1129 | |||
1130 | #if defined(CONFIG_NFS_V4_1) | ||
1131 | if (clp->cl_minorversion) { | ||
1132 | struct nfs4_session *session = NULL; | ||
1133 | /* | ||
1134 | * Create the session and mark it expired. | ||
1135 | * When a SEQUENCE operation encounters the expired session | ||
1136 | * it will do session recovery to initialize it. | ||
1137 | */ | ||
1138 | session = nfs4_alloc_session(clp); | ||
1139 | if (!session) | ||
1140 | return -ENOMEM; | ||
1141 | |||
1142 | clp->cl_session = session; | ||
1143 | clp->cl_call_sync = _nfs4_call_sync_session; | ||
1144 | } | ||
1145 | #endif /* CONFIG_NFS_V4_1 */ | ||
1146 | |||
1147 | return nfs4_init_callback(clp); | ||
1148 | } | ||
1149 | |||
1150 | /* | ||
1053 | * Initialise an NFS4 client record | 1151 | * Initialise an NFS4 client record |
1054 | */ | 1152 | */ |
1055 | static int nfs4_init_client(struct nfs_client *clp, | 1153 | static int nfs4_init_client(struct nfs_client *clp, |
@@ -1083,7 +1181,12 @@ static int nfs4_init_client(struct nfs_client *clp, | |||
1083 | } | 1181 | } |
1084 | __set_bit(NFS_CS_IDMAP, &clp->cl_res_state); | 1182 | __set_bit(NFS_CS_IDMAP, &clp->cl_res_state); |
1085 | 1183 | ||
1086 | nfs_mark_client_ready(clp, NFS_CS_READY); | 1184 | error = nfs4_init_client_minor_version(clp); |
1185 | if (error < 0) | ||
1186 | goto error; | ||
1187 | |||
1188 | if (!nfs4_has_session(clp)) | ||
1189 | nfs_mark_client_ready(clp, NFS_CS_READY); | ||
1087 | return 0; | 1190 | return 0; |
1088 | 1191 | ||
1089 | error: | 1192 | error: |
@@ -1101,7 +1204,8 @@ static int nfs4_set_client(struct nfs_server *server, | |||
1101 | const size_t addrlen, | 1204 | const size_t addrlen, |
1102 | const char *ip_addr, | 1205 | const char *ip_addr, |
1103 | rpc_authflavor_t authflavour, | 1206 | rpc_authflavor_t authflavour, |
1104 | int proto, const struct rpc_timeout *timeparms) | 1207 | int proto, const struct rpc_timeout *timeparms, |
1208 | u32 minorversion) | ||
1105 | { | 1209 | { |
1106 | struct nfs_client_initdata cl_init = { | 1210 | struct nfs_client_initdata cl_init = { |
1107 | .hostname = hostname, | 1211 | .hostname = hostname, |
@@ -1109,6 +1213,7 @@ static int nfs4_set_client(struct nfs_server *server, | |||
1109 | .addrlen = addrlen, | 1213 | .addrlen = addrlen, |
1110 | .rpc_ops = &nfs_v4_clientops, | 1214 | .rpc_ops = &nfs_v4_clientops, |
1111 | .proto = proto, | 1215 | .proto = proto, |
1216 | .minorversion = minorversion, | ||
1112 | }; | 1217 | }; |
1113 | struct nfs_client *clp; | 1218 | struct nfs_client *clp; |
1114 | int error; | 1219 | int error; |
@@ -1138,6 +1243,36 @@ error: | |||
1138 | } | 1243 | } |
1139 | 1244 | ||
1140 | /* | 1245 | /* |
1246 | * Initialize a session. | ||
1247 | * Note: save the mount rsize and wsize for create_server negotiation. | ||
1248 | */ | ||
1249 | static void nfs4_init_session(struct nfs_client *clp, | ||
1250 | unsigned int wsize, unsigned int rsize) | ||
1251 | { | ||
1252 | #if defined(CONFIG_NFS_V4_1) | ||
1253 | if (nfs4_has_session(clp)) { | ||
1254 | clp->cl_session->fc_attrs.max_rqst_sz = wsize; | ||
1255 | clp->cl_session->fc_attrs.max_resp_sz = rsize; | ||
1256 | } | ||
1257 | #endif /* CONFIG_NFS_V4_1 */ | ||
1258 | } | ||
1259 | |||
1260 | /* | ||
1261 | * Session has been established, and the client marked ready. | ||
1262 | * Set the mount rsize and wsize with negotiated fore channel | ||
1263 | * attributes which will be bound checked in nfs_server_set_fsinfo. | ||
1264 | */ | ||
1265 | static void nfs4_session_set_rwsize(struct nfs_server *server) | ||
1266 | { | ||
1267 | #ifdef CONFIG_NFS_V4_1 | ||
1268 | if (!nfs4_has_session(server->nfs_client)) | ||
1269 | return; | ||
1270 | server->rsize = server->nfs_client->cl_session->fc_attrs.max_resp_sz; | ||
1271 | server->wsize = server->nfs_client->cl_session->fc_attrs.max_rqst_sz; | ||
1272 | #endif /* CONFIG_NFS_V4_1 */ | ||
1273 | } | ||
1274 | |||
1275 | /* | ||
1141 | * Create a version 4 volume record | 1276 | * Create a version 4 volume record |
1142 | */ | 1277 | */ |
1143 | static int nfs4_init_server(struct nfs_server *server, | 1278 | static int nfs4_init_server(struct nfs_server *server, |
@@ -1164,7 +1299,8 @@ static int nfs4_init_server(struct nfs_server *server, | |||
1164 | data->client_address, | 1299 | data->client_address, |
1165 | data->auth_flavors[0], | 1300 | data->auth_flavors[0], |
1166 | data->nfs_server.protocol, | 1301 | data->nfs_server.protocol, |
1167 | &timeparms); | 1302 | &timeparms, |
1303 | data->minorversion); | ||
1168 | if (error < 0) | 1304 | if (error < 0) |
1169 | goto error; | 1305 | goto error; |
1170 | 1306 | ||
@@ -1214,6 +1350,8 @@ struct nfs_server *nfs4_create_server(const struct nfs_parsed_mount_data *data, | |||
1214 | BUG_ON(!server->nfs_client->rpc_ops); | 1350 | BUG_ON(!server->nfs_client->rpc_ops); |
1215 | BUG_ON(!server->nfs_client->rpc_ops->file_inode_ops); | 1351 | BUG_ON(!server->nfs_client->rpc_ops->file_inode_ops); |
1216 | 1352 | ||
1353 | nfs4_init_session(server->nfs_client, server->wsize, server->rsize); | ||
1354 | |||
1217 | /* Probe the root fh to retrieve its FSID */ | 1355 | /* Probe the root fh to retrieve its FSID */ |
1218 | error = nfs4_path_walk(server, mntfh, data->nfs_server.export_path); | 1356 | error = nfs4_path_walk(server, mntfh, data->nfs_server.export_path); |
1219 | if (error < 0) | 1357 | if (error < 0) |
@@ -1224,6 +1362,8 @@ struct nfs_server *nfs4_create_server(const struct nfs_parsed_mount_data *data, | |||
1224 | (unsigned long long) server->fsid.minor); | 1362 | (unsigned long long) server->fsid.minor); |
1225 | dprintk("Mount FH: %d\n", mntfh->size); | 1363 | dprintk("Mount FH: %d\n", mntfh->size); |
1226 | 1364 | ||
1365 | nfs4_session_set_rwsize(server); | ||
1366 | |||
1227 | error = nfs_probe_fsinfo(server, mntfh, &fattr); | 1367 | error = nfs_probe_fsinfo(server, mntfh, &fattr); |
1228 | if (error < 0) | 1368 | if (error < 0) |
1229 | goto error; | 1369 | goto error; |
@@ -1282,7 +1422,8 @@ struct nfs_server *nfs4_create_referral_server(struct nfs_clone_mount *data, | |||
1282 | parent_client->cl_ipaddr, | 1422 | parent_client->cl_ipaddr, |
1283 | data->authflavor, | 1423 | data->authflavor, |
1284 | parent_server->client->cl_xprt->prot, | 1424 | parent_server->client->cl_xprt->prot, |
1285 | parent_server->client->cl_timeout); | 1425 | parent_server->client->cl_timeout, |
1426 | parent_client->cl_minorversion); | ||
1286 | if (error < 0) | 1427 | if (error < 0) |
1287 | goto error; | 1428 | goto error; |
1288 | 1429 | ||
diff --git a/fs/nfs/delegation.c b/fs/nfs/delegation.c index 968225a88015..af05b918cb5b 100644 --- a/fs/nfs/delegation.c +++ b/fs/nfs/delegation.c | |||
@@ -68,29 +68,26 @@ static int nfs_delegation_claim_locks(struct nfs_open_context *ctx, struct nfs4_ | |||
68 | { | 68 | { |
69 | struct inode *inode = state->inode; | 69 | struct inode *inode = state->inode; |
70 | struct file_lock *fl; | 70 | struct file_lock *fl; |
71 | int status; | 71 | int status = 0; |
72 | |||
73 | if (inode->i_flock == NULL) | ||
74 | goto out; | ||
72 | 75 | ||
76 | /* Protect inode->i_flock using the BKL */ | ||
77 | lock_kernel(); | ||
73 | for (fl = inode->i_flock; fl != NULL; fl = fl->fl_next) { | 78 | for (fl = inode->i_flock; fl != NULL; fl = fl->fl_next) { |
74 | if (!(fl->fl_flags & (FL_POSIX|FL_FLOCK))) | 79 | if (!(fl->fl_flags & (FL_POSIX|FL_FLOCK))) |
75 | continue; | 80 | continue; |
76 | if (nfs_file_open_context(fl->fl_file) != ctx) | 81 | if (nfs_file_open_context(fl->fl_file) != ctx) |
77 | continue; | 82 | continue; |
83 | unlock_kernel(); | ||
78 | status = nfs4_lock_delegation_recall(state, fl); | 84 | status = nfs4_lock_delegation_recall(state, fl); |
79 | if (status >= 0) | 85 | if (status < 0) |
80 | continue; | 86 | goto out; |
81 | switch (status) { | 87 | lock_kernel(); |
82 | default: | ||
83 | printk(KERN_ERR "%s: unhandled error %d.\n", | ||
84 | __func__, status); | ||
85 | case -NFS4ERR_EXPIRED: | ||
86 | /* kill_proc(fl->fl_pid, SIGLOST, 1); */ | ||
87 | case -NFS4ERR_STALE_CLIENTID: | ||
88 | nfs4_schedule_state_recovery(NFS_SERVER(inode)->nfs_client); | ||
89 | goto out_err; | ||
90 | } | ||
91 | } | 88 | } |
92 | return 0; | 89 | unlock_kernel(); |
93 | out_err: | 90 | out: |
94 | return status; | 91 | return status; |
95 | } | 92 | } |
96 | 93 | ||
@@ -268,7 +265,10 @@ static int __nfs_inode_return_delegation(struct inode *inode, struct nfs_delegat | |||
268 | struct nfs_inode *nfsi = NFS_I(inode); | 265 | struct nfs_inode *nfsi = NFS_I(inode); |
269 | 266 | ||
270 | nfs_msync_inode(inode); | 267 | nfs_msync_inode(inode); |
271 | /* Guard against new delegated open calls */ | 268 | /* |
269 | * Guard against new delegated open/lock/unlock calls and against | ||
270 | * state recovery | ||
271 | */ | ||
272 | down_write(&nfsi->rwsem); | 272 | down_write(&nfsi->rwsem); |
273 | nfs_delegation_claim_opens(inode, &delegation->stateid); | 273 | nfs_delegation_claim_opens(inode, &delegation->stateid); |
274 | up_write(&nfsi->rwsem); | 274 | up_write(&nfsi->rwsem); |
diff --git a/fs/nfs/direct.c b/fs/nfs/direct.c index 08f6b040d289..489fc01a3204 100644 --- a/fs/nfs/direct.c +++ b/fs/nfs/direct.c | |||
@@ -259,6 +259,9 @@ static void nfs_direct_read_release(void *calldata) | |||
259 | } | 259 | } |
260 | 260 | ||
261 | static const struct rpc_call_ops nfs_read_direct_ops = { | 261 | static const struct rpc_call_ops nfs_read_direct_ops = { |
262 | #if defined(CONFIG_NFS_V4_1) | ||
263 | .rpc_call_prepare = nfs_read_prepare, | ||
264 | #endif /* CONFIG_NFS_V4_1 */ | ||
262 | .rpc_call_done = nfs_direct_read_result, | 265 | .rpc_call_done = nfs_direct_read_result, |
263 | .rpc_release = nfs_direct_read_release, | 266 | .rpc_release = nfs_direct_read_release, |
264 | }; | 267 | }; |
@@ -535,6 +538,9 @@ static void nfs_direct_commit_release(void *calldata) | |||
535 | } | 538 | } |
536 | 539 | ||
537 | static const struct rpc_call_ops nfs_commit_direct_ops = { | 540 | static const struct rpc_call_ops nfs_commit_direct_ops = { |
541 | #if defined(CONFIG_NFS_V4_1) | ||
542 | .rpc_call_prepare = nfs_write_prepare, | ||
543 | #endif /* CONFIG_NFS_V4_1 */ | ||
538 | .rpc_call_done = nfs_direct_commit_result, | 544 | .rpc_call_done = nfs_direct_commit_result, |
539 | .rpc_release = nfs_direct_commit_release, | 545 | .rpc_release = nfs_direct_commit_release, |
540 | }; | 546 | }; |
@@ -673,6 +679,9 @@ out_unlock: | |||
673 | } | 679 | } |
674 | 680 | ||
675 | static const struct rpc_call_ops nfs_write_direct_ops = { | 681 | static const struct rpc_call_ops nfs_write_direct_ops = { |
682 | #if defined(CONFIG_NFS_V4_1) | ||
683 | .rpc_call_prepare = nfs_write_prepare, | ||
684 | #endif /* CONFIG_NFS_V4_1 */ | ||
676 | .rpc_call_done = nfs_direct_write_result, | 685 | .rpc_call_done = nfs_direct_write_result, |
677 | .rpc_release = nfs_direct_write_release, | 686 | .rpc_release = nfs_direct_write_release, |
678 | }; | 687 | }; |
diff --git a/fs/nfs/file.c b/fs/nfs/file.c index ec7e27d00bc6..0055b813ec2c 100644 --- a/fs/nfs/file.c +++ b/fs/nfs/file.c | |||
@@ -48,6 +48,9 @@ static ssize_t nfs_file_splice_read(struct file *filp, loff_t *ppos, | |||
48 | size_t count, unsigned int flags); | 48 | size_t count, unsigned int flags); |
49 | static ssize_t nfs_file_read(struct kiocb *, const struct iovec *iov, | 49 | static ssize_t nfs_file_read(struct kiocb *, const struct iovec *iov, |
50 | unsigned long nr_segs, loff_t pos); | 50 | unsigned long nr_segs, loff_t pos); |
51 | static ssize_t nfs_file_splice_write(struct pipe_inode_info *pipe, | ||
52 | struct file *filp, loff_t *ppos, | ||
53 | size_t count, unsigned int flags); | ||
51 | static ssize_t nfs_file_write(struct kiocb *, const struct iovec *iov, | 54 | static ssize_t nfs_file_write(struct kiocb *, const struct iovec *iov, |
52 | unsigned long nr_segs, loff_t pos); | 55 | unsigned long nr_segs, loff_t pos); |
53 | static int nfs_file_flush(struct file *, fl_owner_t id); | 56 | static int nfs_file_flush(struct file *, fl_owner_t id); |
@@ -73,6 +76,7 @@ const struct file_operations nfs_file_operations = { | |||
73 | .lock = nfs_lock, | 76 | .lock = nfs_lock, |
74 | .flock = nfs_flock, | 77 | .flock = nfs_flock, |
75 | .splice_read = nfs_file_splice_read, | 78 | .splice_read = nfs_file_splice_read, |
79 | .splice_write = nfs_file_splice_write, | ||
76 | .check_flags = nfs_check_flags, | 80 | .check_flags = nfs_check_flags, |
77 | .setlease = nfs_setlease, | 81 | .setlease = nfs_setlease, |
78 | }; | 82 | }; |
@@ -587,12 +591,38 @@ out_swapfile: | |||
587 | goto out; | 591 | goto out; |
588 | } | 592 | } |
589 | 593 | ||
594 | static ssize_t nfs_file_splice_write(struct pipe_inode_info *pipe, | ||
595 | struct file *filp, loff_t *ppos, | ||
596 | size_t count, unsigned int flags) | ||
597 | { | ||
598 | struct dentry *dentry = filp->f_path.dentry; | ||
599 | struct inode *inode = dentry->d_inode; | ||
600 | ssize_t ret; | ||
601 | |||
602 | dprintk("NFS splice_write(%s/%s, %lu@%llu)\n", | ||
603 | dentry->d_parent->d_name.name, dentry->d_name.name, | ||
604 | (unsigned long) count, (unsigned long long) *ppos); | ||
605 | |||
606 | /* | ||
607 | * The combination of splice and an O_APPEND destination is disallowed. | ||
608 | */ | ||
609 | |||
610 | nfs_add_stats(inode, NFSIOS_NORMALWRITTENBYTES, count); | ||
611 | |||
612 | ret = generic_file_splice_write(pipe, filp, ppos, count, flags); | ||
613 | if (ret >= 0 && nfs_need_sync_write(filp, inode)) { | ||
614 | int err = nfs_do_fsync(nfs_file_open_context(filp), inode); | ||
615 | if (err < 0) | ||
616 | ret = err; | ||
617 | } | ||
618 | return ret; | ||
619 | } | ||
620 | |||
590 | static int do_getlk(struct file *filp, int cmd, struct file_lock *fl) | 621 | static int do_getlk(struct file *filp, int cmd, struct file_lock *fl) |
591 | { | 622 | { |
592 | struct inode *inode = filp->f_mapping->host; | 623 | struct inode *inode = filp->f_mapping->host; |
593 | int status = 0; | 624 | int status = 0; |
594 | 625 | ||
595 | lock_kernel(); | ||
596 | /* Try local locking first */ | 626 | /* Try local locking first */ |
597 | posix_test_lock(filp, fl); | 627 | posix_test_lock(filp, fl); |
598 | if (fl->fl_type != F_UNLCK) { | 628 | if (fl->fl_type != F_UNLCK) { |
@@ -608,7 +638,6 @@ static int do_getlk(struct file *filp, int cmd, struct file_lock *fl) | |||
608 | 638 | ||
609 | status = NFS_PROTO(inode)->lock(filp, cmd, fl); | 639 | status = NFS_PROTO(inode)->lock(filp, cmd, fl); |
610 | out: | 640 | out: |
611 | unlock_kernel(); | ||
612 | return status; | 641 | return status; |
613 | out_noconflict: | 642 | out_noconflict: |
614 | fl->fl_type = F_UNLCK; | 643 | fl->fl_type = F_UNLCK; |
@@ -650,13 +679,11 @@ static int do_unlk(struct file *filp, int cmd, struct file_lock *fl) | |||
650 | * If we're signalled while cleaning up locks on process exit, we | 679 | * If we're signalled while cleaning up locks on process exit, we |
651 | * still need to complete the unlock. | 680 | * still need to complete the unlock. |
652 | */ | 681 | */ |
653 | lock_kernel(); | ||
654 | /* Use local locking if mounted with "-onolock" */ | 682 | /* Use local locking if mounted with "-onolock" */ |
655 | if (!(NFS_SERVER(inode)->flags & NFS_MOUNT_NONLM)) | 683 | if (!(NFS_SERVER(inode)->flags & NFS_MOUNT_NONLM)) |
656 | status = NFS_PROTO(inode)->lock(filp, cmd, fl); | 684 | status = NFS_PROTO(inode)->lock(filp, cmd, fl); |
657 | else | 685 | else |
658 | status = do_vfs_lock(filp, fl); | 686 | status = do_vfs_lock(filp, fl); |
659 | unlock_kernel(); | ||
660 | return status; | 687 | return status; |
661 | } | 688 | } |
662 | 689 | ||
@@ -673,13 +700,11 @@ static int do_setlk(struct file *filp, int cmd, struct file_lock *fl) | |||
673 | if (status != 0) | 700 | if (status != 0) |
674 | goto out; | 701 | goto out; |
675 | 702 | ||
676 | lock_kernel(); | ||
677 | /* Use local locking if mounted with "-onolock" */ | 703 | /* Use local locking if mounted with "-onolock" */ |
678 | if (!(NFS_SERVER(inode)->flags & NFS_MOUNT_NONLM)) | 704 | if (!(NFS_SERVER(inode)->flags & NFS_MOUNT_NONLM)) |
679 | status = NFS_PROTO(inode)->lock(filp, cmd, fl); | 705 | status = NFS_PROTO(inode)->lock(filp, cmd, fl); |
680 | else | 706 | else |
681 | status = do_vfs_lock(filp, fl); | 707 | status = do_vfs_lock(filp, fl); |
682 | unlock_kernel(); | ||
683 | if (status < 0) | 708 | if (status < 0) |
684 | goto out; | 709 | goto out; |
685 | /* | 710 | /* |
diff --git a/fs/nfs/internal.h b/fs/nfs/internal.h index e4d6a8348adf..7dd90a6769d0 100644 --- a/fs/nfs/internal.h +++ b/fs/nfs/internal.h | |||
@@ -2,6 +2,7 @@ | |||
2 | * NFS internal definitions | 2 | * NFS internal definitions |
3 | */ | 3 | */ |
4 | 4 | ||
5 | #include "nfs4_fs.h" | ||
5 | #include <linux/mount.h> | 6 | #include <linux/mount.h> |
6 | #include <linux/security.h> | 7 | #include <linux/security.h> |
7 | 8 | ||
@@ -17,6 +18,18 @@ struct nfs_string; | |||
17 | */ | 18 | */ |
18 | #define NFS_MAX_READAHEAD (RPC_DEF_SLOT_TABLE - 1) | 19 | #define NFS_MAX_READAHEAD (RPC_DEF_SLOT_TABLE - 1) |
19 | 20 | ||
21 | /* | ||
22 | * Determine if sessions are in use. | ||
23 | */ | ||
24 | static inline int nfs4_has_session(const struct nfs_client *clp) | ||
25 | { | ||
26 | #ifdef CONFIG_NFS_V4_1 | ||
27 | if (clp->cl_session) | ||
28 | return 1; | ||
29 | #endif /* CONFIG_NFS_V4_1 */ | ||
30 | return 0; | ||
31 | } | ||
32 | |||
20 | struct nfs_clone_mount { | 33 | struct nfs_clone_mount { |
21 | const struct super_block *sb; | 34 | const struct super_block *sb; |
22 | const struct dentry *dentry; | 35 | const struct dentry *dentry; |
@@ -30,6 +43,12 @@ struct nfs_clone_mount { | |||
30 | }; | 43 | }; |
31 | 44 | ||
32 | /* | 45 | /* |
46 | * Note: RFC 1813 doesn't limit the number of auth flavors that | ||
47 | * a server can return, so make something up. | ||
48 | */ | ||
49 | #define NFS_MAX_SECFLAVORS (12) | ||
50 | |||
51 | /* | ||
33 | * In-kernel mount arguments | 52 | * In-kernel mount arguments |
34 | */ | 53 | */ |
35 | struct nfs_parsed_mount_data { | 54 | struct nfs_parsed_mount_data { |
@@ -44,6 +63,7 @@ struct nfs_parsed_mount_data { | |||
44 | unsigned int auth_flavor_len; | 63 | unsigned int auth_flavor_len; |
45 | rpc_authflavor_t auth_flavors[1]; | 64 | rpc_authflavor_t auth_flavors[1]; |
46 | char *client_address; | 65 | char *client_address; |
66 | unsigned int minorversion; | ||
47 | char *fscache_uniq; | 67 | char *fscache_uniq; |
48 | 68 | ||
49 | struct { | 69 | struct { |
@@ -77,6 +97,8 @@ struct nfs_mount_request { | |||
77 | unsigned short protocol; | 97 | unsigned short protocol; |
78 | struct nfs_fh *fh; | 98 | struct nfs_fh *fh; |
79 | int noresvport; | 99 | int noresvport; |
100 | unsigned int *auth_flav_len; | ||
101 | rpc_authflavor_t *auth_flavs; | ||
80 | }; | 102 | }; |
81 | 103 | ||
82 | extern int nfs_mount(struct nfs_mount_request *info); | 104 | extern int nfs_mount(struct nfs_mount_request *info); |
@@ -99,6 +121,8 @@ extern void nfs_free_server(struct nfs_server *server); | |||
99 | extern struct nfs_server *nfs_clone_server(struct nfs_server *, | 121 | extern struct nfs_server *nfs_clone_server(struct nfs_server *, |
100 | struct nfs_fh *, | 122 | struct nfs_fh *, |
101 | struct nfs_fattr *); | 123 | struct nfs_fattr *); |
124 | extern void nfs_mark_client_ready(struct nfs_client *clp, int state); | ||
125 | extern int nfs4_check_client_ready(struct nfs_client *clp); | ||
102 | #ifdef CONFIG_PROC_FS | 126 | #ifdef CONFIG_PROC_FS |
103 | extern int __init nfs_fs_proc_init(void); | 127 | extern int __init nfs_fs_proc_init(void); |
104 | extern void nfs_fs_proc_exit(void); | 128 | extern void nfs_fs_proc_exit(void); |
@@ -146,6 +170,20 @@ extern __be32 * nfs_decode_dirent(__be32 *, struct nfs_entry *, int); | |||
146 | extern struct rpc_procinfo nfs3_procedures[]; | 170 | extern struct rpc_procinfo nfs3_procedures[]; |
147 | extern __be32 *nfs3_decode_dirent(__be32 *, struct nfs_entry *, int); | 171 | extern __be32 *nfs3_decode_dirent(__be32 *, struct nfs_entry *, int); |
148 | 172 | ||
173 | /* nfs4proc.c */ | ||
174 | static inline void nfs4_restart_rpc(struct rpc_task *task, | ||
175 | const struct nfs_client *clp) | ||
176 | { | ||
177 | #ifdef CONFIG_NFS_V4_1 | ||
178 | if (nfs4_has_session(clp) && | ||
179 | test_bit(NFS4CLNT_SESSION_SETUP, &clp->cl_state)) { | ||
180 | rpc_restart_call_prepare(task); | ||
181 | return; | ||
182 | } | ||
183 | #endif /* CONFIG_NFS_V4_1 */ | ||
184 | rpc_restart_call(task); | ||
185 | } | ||
186 | |||
149 | /* nfs4xdr.c */ | 187 | /* nfs4xdr.c */ |
150 | #ifdef CONFIG_NFS_V4 | 188 | #ifdef CONFIG_NFS_V4 |
151 | extern __be32 *nfs4_decode_dirent(__be32 *p, struct nfs_entry *entry, int plus); | 189 | extern __be32 *nfs4_decode_dirent(__be32 *p, struct nfs_entry *entry, int plus); |
@@ -205,6 +243,38 @@ extern int nfs4_path_walk(struct nfs_server *server, | |||
205 | const char *path); | 243 | const char *path); |
206 | #endif | 244 | #endif |
207 | 245 | ||
246 | /* read.c */ | ||
247 | extern void nfs_read_prepare(struct rpc_task *task, void *calldata); | ||
248 | |||
249 | /* write.c */ | ||
250 | extern void nfs_write_prepare(struct rpc_task *task, void *calldata); | ||
251 | |||
252 | /* nfs4proc.c */ | ||
253 | extern int _nfs4_call_sync(struct nfs_server *server, | ||
254 | struct rpc_message *msg, | ||
255 | struct nfs4_sequence_args *args, | ||
256 | struct nfs4_sequence_res *res, | ||
257 | int cache_reply); | ||
258 | extern int _nfs4_call_sync_session(struct nfs_server *server, | ||
259 | struct rpc_message *msg, | ||
260 | struct nfs4_sequence_args *args, | ||
261 | struct nfs4_sequence_res *res, | ||
262 | int cache_reply); | ||
263 | |||
264 | #ifdef CONFIG_NFS_V4_1 | ||
265 | extern void nfs41_sequence_free_slot(const struct nfs_client *, | ||
266 | struct nfs4_sequence_res *res); | ||
267 | #endif /* CONFIG_NFS_V4_1 */ | ||
268 | |||
269 | static inline void nfs4_sequence_free_slot(const struct nfs_client *clp, | ||
270 | struct nfs4_sequence_res *res) | ||
271 | { | ||
272 | #ifdef CONFIG_NFS_V4_1 | ||
273 | if (nfs4_has_session(clp)) | ||
274 | nfs41_sequence_free_slot(clp, res); | ||
275 | #endif /* CONFIG_NFS_V4_1 */ | ||
276 | } | ||
277 | |||
208 | /* | 278 | /* |
209 | * Determine the device name as a string | 279 | * Determine the device name as a string |
210 | */ | 280 | */ |
diff --git a/fs/nfs/mount_clnt.c b/fs/nfs/mount_clnt.c index ca905a5bb1ba..38ef9eaec407 100644 --- a/fs/nfs/mount_clnt.c +++ b/fs/nfs/mount_clnt.c | |||
@@ -20,8 +20,116 @@ | |||
20 | # define NFSDBG_FACILITY NFSDBG_MOUNT | 20 | # define NFSDBG_FACILITY NFSDBG_MOUNT |
21 | #endif | 21 | #endif |
22 | 22 | ||
23 | /* | ||
24 | * Defined by RFC 1094, section A.3; and RFC 1813, section 5.1.4 | ||
25 | */ | ||
26 | #define MNTPATHLEN (1024) | ||
27 | |||
28 | /* | ||
29 | * XDR data type sizes | ||
30 | */ | ||
31 | #define encode_dirpath_sz (1 + XDR_QUADLEN(MNTPATHLEN)) | ||
32 | #define MNT_status_sz (1) | ||
33 | #define MNT_fhs_status_sz (1) | ||
34 | #define MNT_fhandle_sz XDR_QUADLEN(NFS2_FHSIZE) | ||
35 | #define MNT_fhandle3_sz (1 + XDR_QUADLEN(NFS3_FHSIZE)) | ||
36 | #define MNT_authflav3_sz (1 + NFS_MAX_SECFLAVORS) | ||
37 | |||
38 | /* | ||
39 | * XDR argument and result sizes | ||
40 | */ | ||
41 | #define MNT_enc_dirpath_sz encode_dirpath_sz | ||
42 | #define MNT_dec_mountres_sz (MNT_status_sz + MNT_fhandle_sz) | ||
43 | #define MNT_dec_mountres3_sz (MNT_status_sz + MNT_fhandle_sz + \ | ||
44 | MNT_authflav3_sz) | ||
45 | |||
46 | /* | ||
47 | * Defined by RFC 1094, section A.5 | ||
48 | */ | ||
49 | enum { | ||
50 | MOUNTPROC_NULL = 0, | ||
51 | MOUNTPROC_MNT = 1, | ||
52 | MOUNTPROC_DUMP = 2, | ||
53 | MOUNTPROC_UMNT = 3, | ||
54 | MOUNTPROC_UMNTALL = 4, | ||
55 | MOUNTPROC_EXPORT = 5, | ||
56 | }; | ||
57 | |||
58 | /* | ||
59 | * Defined by RFC 1813, section 5.2 | ||
60 | */ | ||
61 | enum { | ||
62 | MOUNTPROC3_NULL = 0, | ||
63 | MOUNTPROC3_MNT = 1, | ||
64 | MOUNTPROC3_DUMP = 2, | ||
65 | MOUNTPROC3_UMNT = 3, | ||
66 | MOUNTPROC3_UMNTALL = 4, | ||
67 | MOUNTPROC3_EXPORT = 5, | ||
68 | }; | ||
69 | |||
23 | static struct rpc_program mnt_program; | 70 | static struct rpc_program mnt_program; |
24 | 71 | ||
72 | /* | ||
73 | * Defined by OpenGroup XNFS Version 3W, chapter 8 | ||
74 | */ | ||
75 | enum mountstat { | ||
76 | MNT_OK = 0, | ||
77 | MNT_EPERM = 1, | ||
78 | MNT_ENOENT = 2, | ||
79 | MNT_EACCES = 13, | ||
80 | MNT_EINVAL = 22, | ||
81 | }; | ||
82 | |||
83 | static struct { | ||
84 | u32 status; | ||
85 | int errno; | ||
86 | } mnt_errtbl[] = { | ||
87 | { .status = MNT_OK, .errno = 0, }, | ||
88 | { .status = MNT_EPERM, .errno = -EPERM, }, | ||
89 | { .status = MNT_ENOENT, .errno = -ENOENT, }, | ||
90 | { .status = MNT_EACCES, .errno = -EACCES, }, | ||
91 | { .status = MNT_EINVAL, .errno = -EINVAL, }, | ||
92 | }; | ||
93 | |||
94 | /* | ||
95 | * Defined by RFC 1813, section 5.1.5 | ||
96 | */ | ||
97 | enum mountstat3 { | ||
98 | MNT3_OK = 0, /* no error */ | ||
99 | MNT3ERR_PERM = 1, /* Not owner */ | ||
100 | MNT3ERR_NOENT = 2, /* No such file or directory */ | ||
101 | MNT3ERR_IO = 5, /* I/O error */ | ||
102 | MNT3ERR_ACCES = 13, /* Permission denied */ | ||
103 | MNT3ERR_NOTDIR = 20, /* Not a directory */ | ||
104 | MNT3ERR_INVAL = 22, /* Invalid argument */ | ||
105 | MNT3ERR_NAMETOOLONG = 63, /* Filename too long */ | ||
106 | MNT3ERR_NOTSUPP = 10004, /* Operation not supported */ | ||
107 | MNT3ERR_SERVERFAULT = 10006, /* A failure on the server */ | ||
108 | }; | ||
109 | |||
110 | static struct { | ||
111 | u32 status; | ||
112 | int errno; | ||
113 | } mnt3_errtbl[] = { | ||
114 | { .status = MNT3_OK, .errno = 0, }, | ||
115 | { .status = MNT3ERR_PERM, .errno = -EPERM, }, | ||
116 | { .status = MNT3ERR_NOENT, .errno = -ENOENT, }, | ||
117 | { .status = MNT3ERR_IO, .errno = -EIO, }, | ||
118 | { .status = MNT3ERR_ACCES, .errno = -EACCES, }, | ||
119 | { .status = MNT3ERR_NOTDIR, .errno = -ENOTDIR, }, | ||
120 | { .status = MNT3ERR_INVAL, .errno = -EINVAL, }, | ||
121 | { .status = MNT3ERR_NAMETOOLONG, .errno = -ENAMETOOLONG, }, | ||
122 | { .status = MNT3ERR_NOTSUPP, .errno = -ENOTSUPP, }, | ||
123 | { .status = MNT3ERR_SERVERFAULT, .errno = -ESERVERFAULT, }, | ||
124 | }; | ||
125 | |||
126 | struct mountres { | ||
127 | int errno; | ||
128 | struct nfs_fh *fh; | ||
129 | unsigned int *auth_count; | ||
130 | rpc_authflavor_t *auth_flavors; | ||
131 | }; | ||
132 | |||
25 | struct mnt_fhstatus { | 133 | struct mnt_fhstatus { |
26 | u32 status; | 134 | u32 status; |
27 | struct nfs_fh *fh; | 135 | struct nfs_fh *fh; |
@@ -35,8 +143,10 @@ struct mnt_fhstatus { | |||
35 | */ | 143 | */ |
36 | int nfs_mount(struct nfs_mount_request *info) | 144 | int nfs_mount(struct nfs_mount_request *info) |
37 | { | 145 | { |
38 | struct mnt_fhstatus result = { | 146 | struct mountres result = { |
39 | .fh = info->fh | 147 | .fh = info->fh, |
148 | .auth_count = info->auth_flav_len, | ||
149 | .auth_flavors = info->auth_flavs, | ||
40 | }; | 150 | }; |
41 | struct rpc_message msg = { | 151 | struct rpc_message msg = { |
42 | .rpc_argp = info->dirpath, | 152 | .rpc_argp = info->dirpath, |
@@ -68,14 +178,14 @@ int nfs_mount(struct nfs_mount_request *info) | |||
68 | if (info->version == NFS_MNT3_VERSION) | 178 | if (info->version == NFS_MNT3_VERSION) |
69 | msg.rpc_proc = &mnt_clnt->cl_procinfo[MOUNTPROC3_MNT]; | 179 | msg.rpc_proc = &mnt_clnt->cl_procinfo[MOUNTPROC3_MNT]; |
70 | else | 180 | else |
71 | msg.rpc_proc = &mnt_clnt->cl_procinfo[MNTPROC_MNT]; | 181 | msg.rpc_proc = &mnt_clnt->cl_procinfo[MOUNTPROC_MNT]; |
72 | 182 | ||
73 | status = rpc_call_sync(mnt_clnt, &msg, 0); | 183 | status = rpc_call_sync(mnt_clnt, &msg, 0); |
74 | rpc_shutdown_client(mnt_clnt); | 184 | rpc_shutdown_client(mnt_clnt); |
75 | 185 | ||
76 | if (status < 0) | 186 | if (status < 0) |
77 | goto out_call_err; | 187 | goto out_call_err; |
78 | if (result.status != 0) | 188 | if (result.errno != 0) |
79 | goto out_mnt_err; | 189 | goto out_mnt_err; |
80 | 190 | ||
81 | dprintk("NFS: MNT request succeeded\n"); | 191 | dprintk("NFS: MNT request succeeded\n"); |
@@ -86,72 +196,215 @@ out: | |||
86 | 196 | ||
87 | out_clnt_err: | 197 | out_clnt_err: |
88 | status = PTR_ERR(mnt_clnt); | 198 | status = PTR_ERR(mnt_clnt); |
89 | dprintk("NFS: failed to create RPC client, status=%d\n", status); | 199 | dprintk("NFS: failed to create MNT RPC client, status=%d\n", status); |
90 | goto out; | 200 | goto out; |
91 | 201 | ||
92 | out_call_err: | 202 | out_call_err: |
93 | dprintk("NFS: failed to start MNT request, status=%d\n", status); | 203 | dprintk("NFS: MNT request failed, status=%d\n", status); |
94 | goto out; | 204 | goto out; |
95 | 205 | ||
96 | out_mnt_err: | 206 | out_mnt_err: |
97 | dprintk("NFS: MNT server returned result %d\n", result.status); | 207 | dprintk("NFS: MNT server returned result %d\n", result.errno); |
98 | status = nfs_stat_to_errno(result.status); | 208 | status = result.errno; |
99 | goto out; | 209 | goto out; |
100 | } | 210 | } |
101 | 211 | ||
102 | /* | 212 | /* |
103 | * XDR encode/decode functions for MOUNT | 213 | * XDR encode/decode functions for MOUNT |
104 | */ | 214 | */ |
105 | static int xdr_encode_dirpath(struct rpc_rqst *req, __be32 *p, | 215 | |
106 | const char *path) | 216 | static int encode_mntdirpath(struct xdr_stream *xdr, const char *pathname) |
217 | { | ||
218 | const u32 pathname_len = strlen(pathname); | ||
219 | __be32 *p; | ||
220 | |||
221 | if (unlikely(pathname_len > MNTPATHLEN)) | ||
222 | return -EIO; | ||
223 | |||
224 | p = xdr_reserve_space(xdr, sizeof(u32) + pathname_len); | ||
225 | if (unlikely(p == NULL)) | ||
226 | return -EIO; | ||
227 | xdr_encode_opaque(p, pathname, pathname_len); | ||
228 | |||
229 | return 0; | ||
230 | } | ||
231 | |||
232 | static int mnt_enc_dirpath(struct rpc_rqst *req, __be32 *p, | ||
233 | const char *dirpath) | ||
234 | { | ||
235 | struct xdr_stream xdr; | ||
236 | |||
237 | xdr_init_encode(&xdr, &req->rq_snd_buf, p); | ||
238 | return encode_mntdirpath(&xdr, dirpath); | ||
239 | } | ||
240 | |||
241 | /* | ||
242 | * RFC 1094: "A non-zero status indicates some sort of error. In this | ||
243 | * case, the status is a UNIX error number." This can be problematic | ||
244 | * if the server and client use different errno values for the same | ||
245 | * error. | ||
246 | * | ||
247 | * However, the OpenGroup XNFS spec provides a simple mapping that is | ||
248 | * independent of local errno values on the server and the client. | ||
249 | */ | ||
250 | static int decode_status(struct xdr_stream *xdr, struct mountres *res) | ||
107 | { | 251 | { |
108 | p = xdr_encode_string(p, path); | 252 | unsigned int i; |
253 | u32 status; | ||
254 | __be32 *p; | ||
255 | |||
256 | p = xdr_inline_decode(xdr, sizeof(status)); | ||
257 | if (unlikely(p == NULL)) | ||
258 | return -EIO; | ||
259 | status = ntohl(*p); | ||
109 | 260 | ||
110 | req->rq_slen = xdr_adjust_iovec(req->rq_svec, p); | 261 | for (i = 0; i <= ARRAY_SIZE(mnt_errtbl); i++) { |
262 | if (mnt_errtbl[i].status == status) { | ||
263 | res->errno = mnt_errtbl[i].errno; | ||
264 | return 0; | ||
265 | } | ||
266 | } | ||
267 | |||
268 | dprintk("NFS: unrecognized MNT status code: %u\n", status); | ||
269 | res->errno = -EACCES; | ||
111 | return 0; | 270 | return 0; |
112 | } | 271 | } |
113 | 272 | ||
114 | static int xdr_decode_fhstatus(struct rpc_rqst *req, __be32 *p, | 273 | static int decode_fhandle(struct xdr_stream *xdr, struct mountres *res) |
115 | struct mnt_fhstatus *res) | ||
116 | { | 274 | { |
117 | struct nfs_fh *fh = res->fh; | 275 | struct nfs_fh *fh = res->fh; |
276 | __be32 *p; | ||
277 | |||
278 | p = xdr_inline_decode(xdr, NFS2_FHSIZE); | ||
279 | if (unlikely(p == NULL)) | ||
280 | return -EIO; | ||
281 | |||
282 | fh->size = NFS2_FHSIZE; | ||
283 | memcpy(fh->data, p, NFS2_FHSIZE); | ||
284 | return 0; | ||
285 | } | ||
286 | |||
287 | static int mnt_dec_mountres(struct rpc_rqst *req, __be32 *p, | ||
288 | struct mountres *res) | ||
289 | { | ||
290 | struct xdr_stream xdr; | ||
291 | int status; | ||
292 | |||
293 | xdr_init_decode(&xdr, &req->rq_rcv_buf, p); | ||
294 | |||
295 | status = decode_status(&xdr, res); | ||
296 | if (unlikely(status != 0 || res->errno != 0)) | ||
297 | return status; | ||
298 | return decode_fhandle(&xdr, res); | ||
299 | } | ||
300 | |||
301 | static int decode_fhs_status(struct xdr_stream *xdr, struct mountres *res) | ||
302 | { | ||
303 | unsigned int i; | ||
304 | u32 status; | ||
305 | __be32 *p; | ||
118 | 306 | ||
119 | if ((res->status = ntohl(*p++)) == 0) { | 307 | p = xdr_inline_decode(xdr, sizeof(status)); |
120 | fh->size = NFS2_FHSIZE; | 308 | if (unlikely(p == NULL)) |
121 | memcpy(fh->data, p, NFS2_FHSIZE); | 309 | return -EIO; |
310 | status = ntohl(*p); | ||
311 | |||
312 | for (i = 0; i <= ARRAY_SIZE(mnt3_errtbl); i++) { | ||
313 | if (mnt3_errtbl[i].status == status) { | ||
314 | res->errno = mnt3_errtbl[i].errno; | ||
315 | return 0; | ||
316 | } | ||
122 | } | 317 | } |
318 | |||
319 | dprintk("NFS: unrecognized MNT3 status code: %u\n", status); | ||
320 | res->errno = -EACCES; | ||
123 | return 0; | 321 | return 0; |
124 | } | 322 | } |
125 | 323 | ||
126 | static int xdr_decode_fhstatus3(struct rpc_rqst *req, __be32 *p, | 324 | static int decode_fhandle3(struct xdr_stream *xdr, struct mountres *res) |
127 | struct mnt_fhstatus *res) | ||
128 | { | 325 | { |
129 | struct nfs_fh *fh = res->fh; | 326 | struct nfs_fh *fh = res->fh; |
130 | unsigned size; | 327 | u32 size; |
131 | 328 | __be32 *p; | |
132 | if ((res->status = ntohl(*p++)) == 0) { | 329 | |
133 | size = ntohl(*p++); | 330 | p = xdr_inline_decode(xdr, sizeof(size)); |
134 | if (size <= NFS3_FHSIZE && size != 0) { | 331 | if (unlikely(p == NULL)) |
135 | fh->size = size; | 332 | return -EIO; |
136 | memcpy(fh->data, p, size); | 333 | |
137 | } else | 334 | size = ntohl(*p++); |
138 | res->status = -EBADHANDLE; | 335 | if (size > NFS3_FHSIZE || size == 0) |
336 | return -EIO; | ||
337 | |||
338 | p = xdr_inline_decode(xdr, size); | ||
339 | if (unlikely(p == NULL)) | ||
340 | return -EIO; | ||
341 | |||
342 | fh->size = size; | ||
343 | memcpy(fh->data, p, size); | ||
344 | return 0; | ||
345 | } | ||
346 | |||
347 | static int decode_auth_flavors(struct xdr_stream *xdr, struct mountres *res) | ||
348 | { | ||
349 | rpc_authflavor_t *flavors = res->auth_flavors; | ||
350 | unsigned int *count = res->auth_count; | ||
351 | u32 entries, i; | ||
352 | __be32 *p; | ||
353 | |||
354 | if (*count == 0) | ||
355 | return 0; | ||
356 | |||
357 | p = xdr_inline_decode(xdr, sizeof(entries)); | ||
358 | if (unlikely(p == NULL)) | ||
359 | return -EIO; | ||
360 | entries = ntohl(*p); | ||
361 | dprintk("NFS: received %u auth flavors\n", entries); | ||
362 | if (entries > NFS_MAX_SECFLAVORS) | ||
363 | entries = NFS_MAX_SECFLAVORS; | ||
364 | |||
365 | p = xdr_inline_decode(xdr, sizeof(u32) * entries); | ||
366 | if (unlikely(p == NULL)) | ||
367 | return -EIO; | ||
368 | |||
369 | if (entries > *count) | ||
370 | entries = *count; | ||
371 | |||
372 | for (i = 0; i < entries; i++) { | ||
373 | flavors[i] = ntohl(*p++); | ||
374 | dprintk("NFS:\tflavor %u: %d\n", i, flavors[i]); | ||
139 | } | 375 | } |
376 | *count = i; | ||
377 | |||
140 | return 0; | 378 | return 0; |
141 | } | 379 | } |
142 | 380 | ||
143 | #define MNT_dirpath_sz (1 + 256) | 381 | static int mnt_dec_mountres3(struct rpc_rqst *req, __be32 *p, |
144 | #define MNT_fhstatus_sz (1 + 8) | 382 | struct mountres *res) |
145 | #define MNT_fhstatus3_sz (1 + 16) | 383 | { |
384 | struct xdr_stream xdr; | ||
385 | int status; | ||
386 | |||
387 | xdr_init_decode(&xdr, &req->rq_rcv_buf, p); | ||
388 | |||
389 | status = decode_fhs_status(&xdr, res); | ||
390 | if (unlikely(status != 0 || res->errno != 0)) | ||
391 | return status; | ||
392 | status = decode_fhandle3(&xdr, res); | ||
393 | if (unlikely(status != 0)) { | ||
394 | res->errno = -EBADHANDLE; | ||
395 | return 0; | ||
396 | } | ||
397 | return decode_auth_flavors(&xdr, res); | ||
398 | } | ||
146 | 399 | ||
147 | static struct rpc_procinfo mnt_procedures[] = { | 400 | static struct rpc_procinfo mnt_procedures[] = { |
148 | [MNTPROC_MNT] = { | 401 | [MOUNTPROC_MNT] = { |
149 | .p_proc = MNTPROC_MNT, | 402 | .p_proc = MOUNTPROC_MNT, |
150 | .p_encode = (kxdrproc_t) xdr_encode_dirpath, | 403 | .p_encode = (kxdrproc_t)mnt_enc_dirpath, |
151 | .p_decode = (kxdrproc_t) xdr_decode_fhstatus, | 404 | .p_decode = (kxdrproc_t)mnt_dec_mountres, |
152 | .p_arglen = MNT_dirpath_sz, | 405 | .p_arglen = MNT_enc_dirpath_sz, |
153 | .p_replen = MNT_fhstatus_sz, | 406 | .p_replen = MNT_dec_mountres_sz, |
154 | .p_statidx = MNTPROC_MNT, | 407 | .p_statidx = MOUNTPROC_MNT, |
155 | .p_name = "MOUNT", | 408 | .p_name = "MOUNT", |
156 | }, | 409 | }, |
157 | }; | 410 | }; |
@@ -159,10 +412,10 @@ static struct rpc_procinfo mnt_procedures[] = { | |||
159 | static struct rpc_procinfo mnt3_procedures[] = { | 412 | static struct rpc_procinfo mnt3_procedures[] = { |
160 | [MOUNTPROC3_MNT] = { | 413 | [MOUNTPROC3_MNT] = { |
161 | .p_proc = MOUNTPROC3_MNT, | 414 | .p_proc = MOUNTPROC3_MNT, |
162 | .p_encode = (kxdrproc_t) xdr_encode_dirpath, | 415 | .p_encode = (kxdrproc_t)mnt_enc_dirpath, |
163 | .p_decode = (kxdrproc_t) xdr_decode_fhstatus3, | 416 | .p_decode = (kxdrproc_t)mnt_dec_mountres3, |
164 | .p_arglen = MNT_dirpath_sz, | 417 | .p_arglen = MNT_enc_dirpath_sz, |
165 | .p_replen = MNT_fhstatus3_sz, | 418 | .p_replen = MNT_dec_mountres3_sz, |
166 | .p_statidx = MOUNTPROC3_MNT, | 419 | .p_statidx = MOUNTPROC3_MNT, |
167 | .p_name = "MOUNT", | 420 | .p_name = "MOUNT", |
168 | }, | 421 | }, |
diff --git a/fs/nfs/namespace.c b/fs/nfs/namespace.c index f01caec84463..40c766782891 100644 --- a/fs/nfs/namespace.c +++ b/fs/nfs/namespace.c | |||
@@ -65,6 +65,11 @@ char *nfs_path(const char *base, | |||
65 | dentry = dentry->d_parent; | 65 | dentry = dentry->d_parent; |
66 | } | 66 | } |
67 | spin_unlock(&dcache_lock); | 67 | spin_unlock(&dcache_lock); |
68 | if (*end != '/') { | ||
69 | if (--buflen < 0) | ||
70 | goto Elong; | ||
71 | *--end = '/'; | ||
72 | } | ||
68 | namelen = strlen(base); | 73 | namelen = strlen(base); |
69 | /* Strip off excess slashes in base string */ | 74 | /* Strip off excess slashes in base string */ |
70 | while (namelen > 0 && base[namelen - 1] == '/') | 75 | while (namelen > 0 && base[namelen - 1] == '/') |
diff --git a/fs/nfs/nfs3acl.c b/fs/nfs/nfs3acl.c index 6bbf0e6daad2..bac60515a4b3 100644 --- a/fs/nfs/nfs3acl.c +++ b/fs/nfs/nfs3acl.c | |||
@@ -207,8 +207,6 @@ struct posix_acl *nfs3_proc_getacl(struct inode *inode, int type) | |||
207 | status = nfs_revalidate_inode(server, inode); | 207 | status = nfs_revalidate_inode(server, inode); |
208 | if (status < 0) | 208 | if (status < 0) |
209 | return ERR_PTR(status); | 209 | return ERR_PTR(status); |
210 | if (NFS_I(inode)->cache_validity & NFS_INO_INVALID_ACL) | ||
211 | nfs_zap_acl_cache(inode); | ||
212 | acl = nfs3_get_cached_acl(inode, type); | 210 | acl = nfs3_get_cached_acl(inode, type); |
213 | if (acl != ERR_PTR(-EAGAIN)) | 211 | if (acl != ERR_PTR(-EAGAIN)) |
214 | return acl; | 212 | return acl; |
diff --git a/fs/nfs/nfs4_fs.h b/fs/nfs/nfs4_fs.h index 84345deab26f..61bc3a32e1e2 100644 --- a/fs/nfs/nfs4_fs.h +++ b/fs/nfs/nfs4_fs.h | |||
@@ -44,6 +44,7 @@ enum nfs4_client_state { | |||
44 | NFS4CLNT_RECLAIM_REBOOT, | 44 | NFS4CLNT_RECLAIM_REBOOT, |
45 | NFS4CLNT_RECLAIM_NOGRACE, | 45 | NFS4CLNT_RECLAIM_NOGRACE, |
46 | NFS4CLNT_DELEGRETURN, | 46 | NFS4CLNT_DELEGRETURN, |
47 | NFS4CLNT_SESSION_SETUP, | ||
47 | }; | 48 | }; |
48 | 49 | ||
49 | /* | 50 | /* |
@@ -177,6 +178,14 @@ struct nfs4_state_recovery_ops { | |||
177 | int state_flag_bit; | 178 | int state_flag_bit; |
178 | int (*recover_open)(struct nfs4_state_owner *, struct nfs4_state *); | 179 | int (*recover_open)(struct nfs4_state_owner *, struct nfs4_state *); |
179 | int (*recover_lock)(struct nfs4_state *, struct file_lock *); | 180 | int (*recover_lock)(struct nfs4_state *, struct file_lock *); |
181 | int (*establish_clid)(struct nfs_client *, struct rpc_cred *); | ||
182 | struct rpc_cred * (*get_clid_cred)(struct nfs_client *); | ||
183 | }; | ||
184 | |||
185 | struct nfs4_state_maintenance_ops { | ||
186 | int (*sched_state_renewal)(struct nfs_client *, struct rpc_cred *); | ||
187 | struct rpc_cred * (*get_state_renewal_cred_locked)(struct nfs_client *); | ||
188 | int (*renew_lease)(struct nfs_client *, struct rpc_cred *); | ||
180 | }; | 189 | }; |
181 | 190 | ||
182 | extern const struct dentry_operations nfs4_dentry_operations; | 191 | extern const struct dentry_operations nfs4_dentry_operations; |
@@ -193,6 +202,7 @@ extern int nfs4_proc_setclientid(struct nfs_client *, u32, unsigned short, struc | |||
193 | extern int nfs4_proc_setclientid_confirm(struct nfs_client *, struct rpc_cred *); | 202 | extern int nfs4_proc_setclientid_confirm(struct nfs_client *, struct rpc_cred *); |
194 | extern int nfs4_proc_async_renew(struct nfs_client *, struct rpc_cred *); | 203 | extern int nfs4_proc_async_renew(struct nfs_client *, struct rpc_cred *); |
195 | extern int nfs4_proc_renew(struct nfs_client *, struct rpc_cred *); | 204 | extern int nfs4_proc_renew(struct nfs_client *, struct rpc_cred *); |
205 | extern int nfs4_init_clientid(struct nfs_client *, struct rpc_cred *); | ||
196 | extern int nfs4_do_close(struct path *path, struct nfs4_state *state, int wait); | 206 | extern int nfs4_do_close(struct path *path, struct nfs4_state *state, int wait); |
197 | extern struct dentry *nfs4_atomic_open(struct inode *, struct dentry *, struct nameidata *); | 207 | extern struct dentry *nfs4_atomic_open(struct inode *, struct dentry *, struct nameidata *); |
198 | extern int nfs4_open_revalidate(struct inode *, struct dentry *, int, struct nameidata *); | 208 | extern int nfs4_open_revalidate(struct inode *, struct dentry *, int, struct nameidata *); |
@@ -200,8 +210,26 @@ extern int nfs4_server_capabilities(struct nfs_server *server, struct nfs_fh *fh | |||
200 | extern int nfs4_proc_fs_locations(struct inode *dir, const struct qstr *name, | 210 | extern int nfs4_proc_fs_locations(struct inode *dir, const struct qstr *name, |
201 | struct nfs4_fs_locations *fs_locations, struct page *page); | 211 | struct nfs4_fs_locations *fs_locations, struct page *page); |
202 | 212 | ||
203 | extern struct nfs4_state_recovery_ops nfs4_reboot_recovery_ops; | 213 | extern struct nfs4_state_recovery_ops *nfs4_reboot_recovery_ops[]; |
204 | extern struct nfs4_state_recovery_ops nfs4_nograce_recovery_ops; | 214 | extern struct nfs4_state_recovery_ops *nfs4_nograce_recovery_ops[]; |
215 | #if defined(CONFIG_NFS_V4_1) | ||
216 | extern int nfs4_setup_sequence(struct nfs_client *clp, | ||
217 | struct nfs4_sequence_args *args, struct nfs4_sequence_res *res, | ||
218 | int cache_reply, struct rpc_task *task); | ||
219 | extern void nfs4_destroy_session(struct nfs4_session *session); | ||
220 | extern struct nfs4_session *nfs4_alloc_session(struct nfs_client *clp); | ||
221 | extern int nfs4_proc_create_session(struct nfs_client *, int reset); | ||
222 | extern int nfs4_proc_destroy_session(struct nfs4_session *); | ||
223 | #else /* CONFIG_NFS_v4_1 */ | ||
224 | static inline int nfs4_setup_sequence(struct nfs_client *clp, | ||
225 | struct nfs4_sequence_args *args, struct nfs4_sequence_res *res, | ||
226 | int cache_reply, struct rpc_task *task) | ||
227 | { | ||
228 | return 0; | ||
229 | } | ||
230 | #endif /* CONFIG_NFS_V4_1 */ | ||
231 | |||
232 | extern struct nfs4_state_maintenance_ops *nfs4_state_renewal_ops[]; | ||
205 | 233 | ||
206 | extern const u32 nfs4_fattr_bitmap[2]; | 234 | extern const u32 nfs4_fattr_bitmap[2]; |
207 | extern const u32 nfs4_statfs_bitmap[2]; | 235 | extern const u32 nfs4_statfs_bitmap[2]; |
@@ -216,7 +244,12 @@ extern void nfs4_kill_renewd(struct nfs_client *); | |||
216 | extern void nfs4_renew_state(struct work_struct *); | 244 | extern void nfs4_renew_state(struct work_struct *); |
217 | 245 | ||
218 | /* nfs4state.c */ | 246 | /* nfs4state.c */ |
247 | struct rpc_cred *nfs4_get_setclientid_cred(struct nfs_client *clp); | ||
219 | struct rpc_cred *nfs4_get_renew_cred_locked(struct nfs_client *clp); | 248 | struct rpc_cred *nfs4_get_renew_cred_locked(struct nfs_client *clp); |
249 | #if defined(CONFIG_NFS_V4_1) | ||
250 | struct rpc_cred *nfs4_get_machine_cred_locked(struct nfs_client *clp); | ||
251 | struct rpc_cred *nfs4_get_exchange_id_cred(struct nfs_client *clp); | ||
252 | #endif /* CONFIG_NFS_V4_1 */ | ||
220 | 253 | ||
221 | extern struct nfs4_state_owner * nfs4_get_state_owner(struct nfs_server *, struct rpc_cred *); | 254 | extern struct nfs4_state_owner * nfs4_get_state_owner(struct nfs_server *, struct rpc_cred *); |
222 | extern void nfs4_put_state_owner(struct nfs4_state_owner *); | 255 | extern void nfs4_put_state_owner(struct nfs4_state_owner *); |
diff --git a/fs/nfs/nfs4proc.c b/fs/nfs/nfs4proc.c index 4674f8092da8..92ce43517814 100644 --- a/fs/nfs/nfs4proc.c +++ b/fs/nfs/nfs4proc.c | |||
@@ -48,11 +48,14 @@ | |||
48 | #include <linux/smp_lock.h> | 48 | #include <linux/smp_lock.h> |
49 | #include <linux/namei.h> | 49 | #include <linux/namei.h> |
50 | #include <linux/mount.h> | 50 | #include <linux/mount.h> |
51 | #include <linux/module.h> | ||
52 | #include <linux/sunrpc/bc_xprt.h> | ||
51 | 53 | ||
52 | #include "nfs4_fs.h" | 54 | #include "nfs4_fs.h" |
53 | #include "delegation.h" | 55 | #include "delegation.h" |
54 | #include "internal.h" | 56 | #include "internal.h" |
55 | #include "iostat.h" | 57 | #include "iostat.h" |
58 | #include "callback.h" | ||
56 | 59 | ||
57 | #define NFSDBG_FACILITY NFSDBG_PROC | 60 | #define NFSDBG_FACILITY NFSDBG_PROC |
58 | 61 | ||
@@ -247,7 +250,25 @@ static int nfs4_handle_exception(const struct nfs_server *server, int errorcode, | |||
247 | ret = nfs4_wait_clnt_recover(clp); | 250 | ret = nfs4_wait_clnt_recover(clp); |
248 | if (ret == 0) | 251 | if (ret == 0) |
249 | exception->retry = 1; | 252 | exception->retry = 1; |
253 | #if !defined(CONFIG_NFS_V4_1) | ||
250 | break; | 254 | break; |
255 | #else /* !defined(CONFIG_NFS_V4_1) */ | ||
256 | if (!nfs4_has_session(server->nfs_client)) | ||
257 | break; | ||
258 | /* FALLTHROUGH */ | ||
259 | case -NFS4ERR_BADSESSION: | ||
260 | case -NFS4ERR_BADSLOT: | ||
261 | case -NFS4ERR_BAD_HIGH_SLOT: | ||
262 | case -NFS4ERR_CONN_NOT_BOUND_TO_SESSION: | ||
263 | case -NFS4ERR_DEADSESSION: | ||
264 | case -NFS4ERR_SEQ_FALSE_RETRY: | ||
265 | case -NFS4ERR_SEQ_MISORDERED: | ||
266 | dprintk("%s ERROR: %d Reset session\n", __func__, | ||
267 | errorcode); | ||
268 | set_bit(NFS4CLNT_SESSION_SETUP, &clp->cl_state); | ||
269 | exception->retry = 1; | ||
270 | /* FALLTHROUGH */ | ||
271 | #endif /* !defined(CONFIG_NFS_V4_1) */ | ||
251 | case -NFS4ERR_FILE_OPEN: | 272 | case -NFS4ERR_FILE_OPEN: |
252 | case -NFS4ERR_GRACE: | 273 | case -NFS4ERR_GRACE: |
253 | case -NFS4ERR_DELAY: | 274 | case -NFS4ERR_DELAY: |
@@ -271,6 +292,353 @@ static void renew_lease(const struct nfs_server *server, unsigned long timestamp | |||
271 | spin_unlock(&clp->cl_lock); | 292 | spin_unlock(&clp->cl_lock); |
272 | } | 293 | } |
273 | 294 | ||
295 | #if defined(CONFIG_NFS_V4_1) | ||
296 | |||
297 | /* | ||
298 | * nfs4_free_slot - free a slot and efficiently update slot table. | ||
299 | * | ||
300 | * freeing a slot is trivially done by clearing its respective bit | ||
301 | * in the bitmap. | ||
302 | * If the freed slotid equals highest_used_slotid we want to update it | ||
303 | * so that the server would be able to size down the slot table if needed, | ||
304 | * otherwise we know that the highest_used_slotid is still in use. | ||
305 | * When updating highest_used_slotid there may be "holes" in the bitmap | ||
306 | * so we need to scan down from highest_used_slotid to 0 looking for the now | ||
307 | * highest slotid in use. | ||
308 | * If none found, highest_used_slotid is set to -1. | ||
309 | */ | ||
310 | static void | ||
311 | nfs4_free_slot(struct nfs4_slot_table *tbl, u8 free_slotid) | ||
312 | { | ||
313 | int slotid = free_slotid; | ||
314 | |||
315 | spin_lock(&tbl->slot_tbl_lock); | ||
316 | /* clear used bit in bitmap */ | ||
317 | __clear_bit(slotid, tbl->used_slots); | ||
318 | |||
319 | /* update highest_used_slotid when it is freed */ | ||
320 | if (slotid == tbl->highest_used_slotid) { | ||
321 | slotid = find_last_bit(tbl->used_slots, tbl->max_slots); | ||
322 | if (slotid >= 0 && slotid < tbl->max_slots) | ||
323 | tbl->highest_used_slotid = slotid; | ||
324 | else | ||
325 | tbl->highest_used_slotid = -1; | ||
326 | } | ||
327 | rpc_wake_up_next(&tbl->slot_tbl_waitq); | ||
328 | spin_unlock(&tbl->slot_tbl_lock); | ||
329 | dprintk("%s: free_slotid %u highest_used_slotid %d\n", __func__, | ||
330 | free_slotid, tbl->highest_used_slotid); | ||
331 | } | ||
332 | |||
333 | void nfs41_sequence_free_slot(const struct nfs_client *clp, | ||
334 | struct nfs4_sequence_res *res) | ||
335 | { | ||
336 | struct nfs4_slot_table *tbl; | ||
337 | |||
338 | if (!nfs4_has_session(clp)) { | ||
339 | dprintk("%s: No session\n", __func__); | ||
340 | return; | ||
341 | } | ||
342 | tbl = &clp->cl_session->fc_slot_table; | ||
343 | if (res->sr_slotid == NFS4_MAX_SLOT_TABLE) { | ||
344 | dprintk("%s: No slot\n", __func__); | ||
345 | /* just wake up the next guy waiting since | ||
346 | * we may have not consumed a slot after all */ | ||
347 | rpc_wake_up_next(&tbl->slot_tbl_waitq); | ||
348 | return; | ||
349 | } | ||
350 | nfs4_free_slot(tbl, res->sr_slotid); | ||
351 | res->sr_slotid = NFS4_MAX_SLOT_TABLE; | ||
352 | } | ||
353 | |||
354 | static void nfs41_sequence_done(struct nfs_client *clp, | ||
355 | struct nfs4_sequence_res *res, | ||
356 | int rpc_status) | ||
357 | { | ||
358 | unsigned long timestamp; | ||
359 | struct nfs4_slot_table *tbl; | ||
360 | struct nfs4_slot *slot; | ||
361 | |||
362 | /* | ||
363 | * sr_status remains 1 if an RPC level error occurred. The server | ||
364 | * may or may not have processed the sequence operation.. | ||
365 | * Proceed as if the server received and processed the sequence | ||
366 | * operation. | ||
367 | */ | ||
368 | if (res->sr_status == 1) | ||
369 | res->sr_status = NFS_OK; | ||
370 | |||
371 | /* -ERESTARTSYS can result in skipping nfs41_sequence_setup */ | ||
372 | if (res->sr_slotid == NFS4_MAX_SLOT_TABLE) | ||
373 | goto out; | ||
374 | |||
375 | tbl = &clp->cl_session->fc_slot_table; | ||
376 | slot = tbl->slots + res->sr_slotid; | ||
377 | |||
378 | if (res->sr_status == 0) { | ||
379 | /* Update the slot's sequence and clientid lease timer */ | ||
380 | ++slot->seq_nr; | ||
381 | timestamp = res->sr_renewal_time; | ||
382 | spin_lock(&clp->cl_lock); | ||
383 | if (time_before(clp->cl_last_renewal, timestamp)) | ||
384 | clp->cl_last_renewal = timestamp; | ||
385 | spin_unlock(&clp->cl_lock); | ||
386 | return; | ||
387 | } | ||
388 | out: | ||
389 | /* The session may be reset by one of the error handlers. */ | ||
390 | dprintk("%s: Error %d free the slot \n", __func__, res->sr_status); | ||
391 | nfs41_sequence_free_slot(clp, res); | ||
392 | } | ||
393 | |||
394 | /* | ||
395 | * nfs4_find_slot - efficiently look for a free slot | ||
396 | * | ||
397 | * nfs4_find_slot looks for an unset bit in the used_slots bitmap. | ||
398 | * If found, we mark the slot as used, update the highest_used_slotid, | ||
399 | * and respectively set up the sequence operation args. | ||
400 | * The slot number is returned if found, or NFS4_MAX_SLOT_TABLE otherwise. | ||
401 | * | ||
402 | * Note: must be called with under the slot_tbl_lock. | ||
403 | */ | ||
404 | static u8 | ||
405 | nfs4_find_slot(struct nfs4_slot_table *tbl, struct rpc_task *task) | ||
406 | { | ||
407 | int slotid; | ||
408 | u8 ret_id = NFS4_MAX_SLOT_TABLE; | ||
409 | BUILD_BUG_ON((u8)NFS4_MAX_SLOT_TABLE != (int)NFS4_MAX_SLOT_TABLE); | ||
410 | |||
411 | dprintk("--> %s used_slots=%04lx highest_used=%d max_slots=%d\n", | ||
412 | __func__, tbl->used_slots[0], tbl->highest_used_slotid, | ||
413 | tbl->max_slots); | ||
414 | slotid = find_first_zero_bit(tbl->used_slots, tbl->max_slots); | ||
415 | if (slotid >= tbl->max_slots) | ||
416 | goto out; | ||
417 | __set_bit(slotid, tbl->used_slots); | ||
418 | if (slotid > tbl->highest_used_slotid) | ||
419 | tbl->highest_used_slotid = slotid; | ||
420 | ret_id = slotid; | ||
421 | out: | ||
422 | dprintk("<-- %s used_slots=%04lx highest_used=%d slotid=%d \n", | ||
423 | __func__, tbl->used_slots[0], tbl->highest_used_slotid, ret_id); | ||
424 | return ret_id; | ||
425 | } | ||
426 | |||
427 | static int nfs4_recover_session(struct nfs4_session *session) | ||
428 | { | ||
429 | struct nfs_client *clp = session->clp; | ||
430 | int ret; | ||
431 | |||
432 | for (;;) { | ||
433 | ret = nfs4_wait_clnt_recover(clp); | ||
434 | if (ret != 0) | ||
435 | return ret; | ||
436 | if (!test_bit(NFS4CLNT_SESSION_SETUP, &clp->cl_state)) | ||
437 | break; | ||
438 | nfs4_schedule_state_manager(clp); | ||
439 | } | ||
440 | return 0; | ||
441 | } | ||
442 | |||
443 | static int nfs41_setup_sequence(struct nfs4_session *session, | ||
444 | struct nfs4_sequence_args *args, | ||
445 | struct nfs4_sequence_res *res, | ||
446 | int cache_reply, | ||
447 | struct rpc_task *task) | ||
448 | { | ||
449 | struct nfs4_slot *slot; | ||
450 | struct nfs4_slot_table *tbl; | ||
451 | int status = 0; | ||
452 | u8 slotid; | ||
453 | |||
454 | dprintk("--> %s\n", __func__); | ||
455 | /* slot already allocated? */ | ||
456 | if (res->sr_slotid != NFS4_MAX_SLOT_TABLE) | ||
457 | return 0; | ||
458 | |||
459 | memset(res, 0, sizeof(*res)); | ||
460 | res->sr_slotid = NFS4_MAX_SLOT_TABLE; | ||
461 | tbl = &session->fc_slot_table; | ||
462 | |||
463 | spin_lock(&tbl->slot_tbl_lock); | ||
464 | if (test_bit(NFS4CLNT_SESSION_SETUP, &session->clp->cl_state)) { | ||
465 | if (tbl->highest_used_slotid != -1) { | ||
466 | rpc_sleep_on(&tbl->slot_tbl_waitq, task, NULL); | ||
467 | spin_unlock(&tbl->slot_tbl_lock); | ||
468 | dprintk("<-- %s: Session reset: draining\n", __func__); | ||
469 | return -EAGAIN; | ||
470 | } | ||
471 | |||
472 | /* The slot table is empty; start the reset thread */ | ||
473 | dprintk("%s Session Reset\n", __func__); | ||
474 | spin_unlock(&tbl->slot_tbl_lock); | ||
475 | status = nfs4_recover_session(session); | ||
476 | if (status) | ||
477 | return status; | ||
478 | spin_lock(&tbl->slot_tbl_lock); | ||
479 | } | ||
480 | |||
481 | slotid = nfs4_find_slot(tbl, task); | ||
482 | if (slotid == NFS4_MAX_SLOT_TABLE) { | ||
483 | rpc_sleep_on(&tbl->slot_tbl_waitq, task, NULL); | ||
484 | spin_unlock(&tbl->slot_tbl_lock); | ||
485 | dprintk("<-- %s: no free slots\n", __func__); | ||
486 | return -EAGAIN; | ||
487 | } | ||
488 | spin_unlock(&tbl->slot_tbl_lock); | ||
489 | |||
490 | slot = tbl->slots + slotid; | ||
491 | args->sa_session = session; | ||
492 | args->sa_slotid = slotid; | ||
493 | args->sa_cache_this = cache_reply; | ||
494 | |||
495 | dprintk("<-- %s slotid=%d seqid=%d\n", __func__, slotid, slot->seq_nr); | ||
496 | |||
497 | res->sr_session = session; | ||
498 | res->sr_slotid = slotid; | ||
499 | res->sr_renewal_time = jiffies; | ||
500 | /* | ||
501 | * sr_status is only set in decode_sequence, and so will remain | ||
502 | * set to 1 if an rpc level failure occurs. | ||
503 | */ | ||
504 | res->sr_status = 1; | ||
505 | return 0; | ||
506 | } | ||
507 | |||
508 | int nfs4_setup_sequence(struct nfs_client *clp, | ||
509 | struct nfs4_sequence_args *args, | ||
510 | struct nfs4_sequence_res *res, | ||
511 | int cache_reply, | ||
512 | struct rpc_task *task) | ||
513 | { | ||
514 | int ret = 0; | ||
515 | |||
516 | dprintk("--> %s clp %p session %p sr_slotid %d\n", | ||
517 | __func__, clp, clp->cl_session, res->sr_slotid); | ||
518 | |||
519 | if (!nfs4_has_session(clp)) | ||
520 | goto out; | ||
521 | ret = nfs41_setup_sequence(clp->cl_session, args, res, cache_reply, | ||
522 | task); | ||
523 | if (ret != -EAGAIN) { | ||
524 | /* terminate rpc task */ | ||
525 | task->tk_status = ret; | ||
526 | task->tk_action = NULL; | ||
527 | } | ||
528 | out: | ||
529 | dprintk("<-- %s status=%d\n", __func__, ret); | ||
530 | return ret; | ||
531 | } | ||
532 | |||
533 | struct nfs41_call_sync_data { | ||
534 | struct nfs_client *clp; | ||
535 | struct nfs4_sequence_args *seq_args; | ||
536 | struct nfs4_sequence_res *seq_res; | ||
537 | int cache_reply; | ||
538 | }; | ||
539 | |||
540 | static void nfs41_call_sync_prepare(struct rpc_task *task, void *calldata) | ||
541 | { | ||
542 | struct nfs41_call_sync_data *data = calldata; | ||
543 | |||
544 | dprintk("--> %s data->clp->cl_session %p\n", __func__, | ||
545 | data->clp->cl_session); | ||
546 | if (nfs4_setup_sequence(data->clp, data->seq_args, | ||
547 | data->seq_res, data->cache_reply, task)) | ||
548 | return; | ||
549 | rpc_call_start(task); | ||
550 | } | ||
551 | |||
552 | static void nfs41_call_sync_done(struct rpc_task *task, void *calldata) | ||
553 | { | ||
554 | struct nfs41_call_sync_data *data = calldata; | ||
555 | |||
556 | nfs41_sequence_done(data->clp, data->seq_res, task->tk_status); | ||
557 | nfs41_sequence_free_slot(data->clp, data->seq_res); | ||
558 | } | ||
559 | |||
560 | struct rpc_call_ops nfs41_call_sync_ops = { | ||
561 | .rpc_call_prepare = nfs41_call_sync_prepare, | ||
562 | .rpc_call_done = nfs41_call_sync_done, | ||
563 | }; | ||
564 | |||
565 | static int nfs4_call_sync_sequence(struct nfs_client *clp, | ||
566 | struct rpc_clnt *clnt, | ||
567 | struct rpc_message *msg, | ||
568 | struct nfs4_sequence_args *args, | ||
569 | struct nfs4_sequence_res *res, | ||
570 | int cache_reply) | ||
571 | { | ||
572 | int ret; | ||
573 | struct rpc_task *task; | ||
574 | struct nfs41_call_sync_data data = { | ||
575 | .clp = clp, | ||
576 | .seq_args = args, | ||
577 | .seq_res = res, | ||
578 | .cache_reply = cache_reply, | ||
579 | }; | ||
580 | struct rpc_task_setup task_setup = { | ||
581 | .rpc_client = clnt, | ||
582 | .rpc_message = msg, | ||
583 | .callback_ops = &nfs41_call_sync_ops, | ||
584 | .callback_data = &data | ||
585 | }; | ||
586 | |||
587 | res->sr_slotid = NFS4_MAX_SLOT_TABLE; | ||
588 | task = rpc_run_task(&task_setup); | ||
589 | if (IS_ERR(task)) | ||
590 | ret = PTR_ERR(task); | ||
591 | else { | ||
592 | ret = task->tk_status; | ||
593 | rpc_put_task(task); | ||
594 | } | ||
595 | return ret; | ||
596 | } | ||
597 | |||
598 | int _nfs4_call_sync_session(struct nfs_server *server, | ||
599 | struct rpc_message *msg, | ||
600 | struct nfs4_sequence_args *args, | ||
601 | struct nfs4_sequence_res *res, | ||
602 | int cache_reply) | ||
603 | { | ||
604 | return nfs4_call_sync_sequence(server->nfs_client, server->client, | ||
605 | msg, args, res, cache_reply); | ||
606 | } | ||
607 | |||
608 | #endif /* CONFIG_NFS_V4_1 */ | ||
609 | |||
610 | int _nfs4_call_sync(struct nfs_server *server, | ||
611 | struct rpc_message *msg, | ||
612 | struct nfs4_sequence_args *args, | ||
613 | struct nfs4_sequence_res *res, | ||
614 | int cache_reply) | ||
615 | { | ||
616 | args->sa_session = res->sr_session = NULL; | ||
617 | return rpc_call_sync(server->client, msg, 0); | ||
618 | } | ||
619 | |||
620 | #define nfs4_call_sync(server, msg, args, res, cache_reply) \ | ||
621 | (server)->nfs_client->cl_call_sync((server), (msg), &(args)->seq_args, \ | ||
622 | &(res)->seq_res, (cache_reply)) | ||
623 | |||
624 | static void nfs4_sequence_done(const struct nfs_server *server, | ||
625 | struct nfs4_sequence_res *res, int rpc_status) | ||
626 | { | ||
627 | #ifdef CONFIG_NFS_V4_1 | ||
628 | if (nfs4_has_session(server->nfs_client)) | ||
629 | nfs41_sequence_done(server->nfs_client, res, rpc_status); | ||
630 | #endif /* CONFIG_NFS_V4_1 */ | ||
631 | } | ||
632 | |||
633 | /* no restart, therefore free slot here */ | ||
634 | static void nfs4_sequence_done_free_slot(const struct nfs_server *server, | ||
635 | struct nfs4_sequence_res *res, | ||
636 | int rpc_status) | ||
637 | { | ||
638 | nfs4_sequence_done(server, res, rpc_status); | ||
639 | nfs4_sequence_free_slot(server->nfs_client, res); | ||
640 | } | ||
641 | |||
274 | static void update_changeattr(struct inode *dir, struct nfs4_change_info *cinfo) | 642 | static void update_changeattr(struct inode *dir, struct nfs4_change_info *cinfo) |
275 | { | 643 | { |
276 | struct nfs_inode *nfsi = NFS_I(dir); | 644 | struct nfs_inode *nfsi = NFS_I(dir); |
@@ -312,6 +680,7 @@ static void nfs4_init_opendata_res(struct nfs4_opendata *p) | |||
312 | p->o_res.server = p->o_arg.server; | 680 | p->o_res.server = p->o_arg.server; |
313 | nfs_fattr_init(&p->f_attr); | 681 | nfs_fattr_init(&p->f_attr); |
314 | nfs_fattr_init(&p->dir_attr); | 682 | nfs_fattr_init(&p->dir_attr); |
683 | p->o_res.seq_res.sr_slotid = NFS4_MAX_SLOT_TABLE; | ||
315 | } | 684 | } |
316 | 685 | ||
317 | static struct nfs4_opendata *nfs4_opendata_alloc(struct path *path, | 686 | static struct nfs4_opendata *nfs4_opendata_alloc(struct path *path, |
@@ -804,16 +1173,30 @@ int nfs4_open_delegation_recall(struct nfs_open_context *ctx, struct nfs4_state | |||
804 | err = _nfs4_open_delegation_recall(ctx, state, stateid); | 1173 | err = _nfs4_open_delegation_recall(ctx, state, stateid); |
805 | switch (err) { | 1174 | switch (err) { |
806 | case 0: | 1175 | case 0: |
807 | return err; | 1176 | case -ENOENT: |
1177 | case -ESTALE: | ||
1178 | goto out; | ||
808 | case -NFS4ERR_STALE_CLIENTID: | 1179 | case -NFS4ERR_STALE_CLIENTID: |
809 | case -NFS4ERR_STALE_STATEID: | 1180 | case -NFS4ERR_STALE_STATEID: |
810 | case -NFS4ERR_EXPIRED: | 1181 | case -NFS4ERR_EXPIRED: |
811 | /* Don't recall a delegation if it was lost */ | 1182 | /* Don't recall a delegation if it was lost */ |
812 | nfs4_schedule_state_recovery(server->nfs_client); | 1183 | nfs4_schedule_state_recovery(server->nfs_client); |
813 | return err; | 1184 | goto out; |
1185 | case -ERESTARTSYS: | ||
1186 | /* | ||
1187 | * The show must go on: exit, but mark the | ||
1188 | * stateid as needing recovery. | ||
1189 | */ | ||
1190 | case -NFS4ERR_ADMIN_REVOKED: | ||
1191 | case -NFS4ERR_BAD_STATEID: | ||
1192 | nfs4_state_mark_reclaim_nograce(server->nfs_client, state); | ||
1193 | case -ENOMEM: | ||
1194 | err = 0; | ||
1195 | goto out; | ||
814 | } | 1196 | } |
815 | err = nfs4_handle_exception(server, err, &exception); | 1197 | err = nfs4_handle_exception(server, err, &exception); |
816 | } while (exception.retry); | 1198 | } while (exception.retry); |
1199 | out: | ||
817 | return err; | 1200 | return err; |
818 | } | 1201 | } |
819 | 1202 | ||
@@ -929,6 +1312,10 @@ static void nfs4_open_prepare(struct rpc_task *task, void *calldata) | |||
929 | nfs_copy_fh(&data->o_res.fh, data->o_arg.fh); | 1312 | nfs_copy_fh(&data->o_res.fh, data->o_arg.fh); |
930 | } | 1313 | } |
931 | data->timestamp = jiffies; | 1314 | data->timestamp = jiffies; |
1315 | if (nfs4_setup_sequence(data->o_arg.server->nfs_client, | ||
1316 | &data->o_arg.seq_args, | ||
1317 | &data->o_res.seq_res, 1, task)) | ||
1318 | return; | ||
932 | rpc_call_start(task); | 1319 | rpc_call_start(task); |
933 | return; | 1320 | return; |
934 | out_no_action: | 1321 | out_no_action: |
@@ -941,6 +1328,10 @@ static void nfs4_open_done(struct rpc_task *task, void *calldata) | |||
941 | struct nfs4_opendata *data = calldata; | 1328 | struct nfs4_opendata *data = calldata; |
942 | 1329 | ||
943 | data->rpc_status = task->tk_status; | 1330 | data->rpc_status = task->tk_status; |
1331 | |||
1332 | nfs4_sequence_done_free_slot(data->o_arg.server, &data->o_res.seq_res, | ||
1333 | task->tk_status); | ||
1334 | |||
944 | if (RPC_ASSASSINATED(task)) | 1335 | if (RPC_ASSASSINATED(task)) |
945 | return; | 1336 | return; |
946 | if (task->tk_status == 0) { | 1337 | if (task->tk_status == 0) { |
@@ -1269,7 +1660,7 @@ static int _nfs4_do_setattr(struct inode *inode, struct rpc_cred *cred, | |||
1269 | } else | 1660 | } else |
1270 | memcpy(&arg.stateid, &zero_stateid, sizeof(arg.stateid)); | 1661 | memcpy(&arg.stateid, &zero_stateid, sizeof(arg.stateid)); |
1271 | 1662 | ||
1272 | status = rpc_call_sync(server->client, &msg, 0); | 1663 | status = nfs4_call_sync(server, &msg, &arg, &res, 1); |
1273 | if (status == 0 && state != NULL) | 1664 | if (status == 0 && state != NULL) |
1274 | renew_lease(server, timestamp); | 1665 | renew_lease(server, timestamp); |
1275 | return status; | 1666 | return status; |
@@ -1318,6 +1709,7 @@ static void nfs4_close_done(struct rpc_task *task, void *data) | |||
1318 | struct nfs4_state *state = calldata->state; | 1709 | struct nfs4_state *state = calldata->state; |
1319 | struct nfs_server *server = NFS_SERVER(calldata->inode); | 1710 | struct nfs_server *server = NFS_SERVER(calldata->inode); |
1320 | 1711 | ||
1712 | nfs4_sequence_done(server, &calldata->res.seq_res, task->tk_status); | ||
1321 | if (RPC_ASSASSINATED(task)) | 1713 | if (RPC_ASSASSINATED(task)) |
1322 | return; | 1714 | return; |
1323 | /* hmm. we are done with the inode, and in the process of freeing | 1715 | /* hmm. we are done with the inode, and in the process of freeing |
@@ -1336,10 +1728,11 @@ static void nfs4_close_done(struct rpc_task *task, void *data) | |||
1336 | break; | 1728 | break; |
1337 | default: | 1729 | default: |
1338 | if (nfs4_async_handle_error(task, server, state) == -EAGAIN) { | 1730 | if (nfs4_async_handle_error(task, server, state) == -EAGAIN) { |
1339 | rpc_restart_call(task); | 1731 | nfs4_restart_rpc(task, server->nfs_client); |
1340 | return; | 1732 | return; |
1341 | } | 1733 | } |
1342 | } | 1734 | } |
1735 | nfs4_sequence_free_slot(server->nfs_client, &calldata->res.seq_res); | ||
1343 | nfs_refresh_inode(calldata->inode, calldata->res.fattr); | 1736 | nfs_refresh_inode(calldata->inode, calldata->res.fattr); |
1344 | } | 1737 | } |
1345 | 1738 | ||
@@ -1380,6 +1773,10 @@ static void nfs4_close_prepare(struct rpc_task *task, void *data) | |||
1380 | calldata->arg.fmode = FMODE_WRITE; | 1773 | calldata->arg.fmode = FMODE_WRITE; |
1381 | } | 1774 | } |
1382 | calldata->timestamp = jiffies; | 1775 | calldata->timestamp = jiffies; |
1776 | if (nfs4_setup_sequence((NFS_SERVER(calldata->inode))->nfs_client, | ||
1777 | &calldata->arg.seq_args, &calldata->res.seq_res, | ||
1778 | 1, task)) | ||
1779 | return; | ||
1383 | rpc_call_start(task); | 1780 | rpc_call_start(task); |
1384 | } | 1781 | } |
1385 | 1782 | ||
@@ -1419,13 +1816,15 @@ int nfs4_do_close(struct path *path, struct nfs4_state *state, int wait) | |||
1419 | }; | 1816 | }; |
1420 | int status = -ENOMEM; | 1817 | int status = -ENOMEM; |
1421 | 1818 | ||
1422 | calldata = kmalloc(sizeof(*calldata), GFP_KERNEL); | 1819 | calldata = kzalloc(sizeof(*calldata), GFP_KERNEL); |
1423 | if (calldata == NULL) | 1820 | if (calldata == NULL) |
1424 | goto out; | 1821 | goto out; |
1425 | calldata->inode = state->inode; | 1822 | calldata->inode = state->inode; |
1426 | calldata->state = state; | 1823 | calldata->state = state; |
1427 | calldata->arg.fh = NFS_FH(state->inode); | 1824 | calldata->arg.fh = NFS_FH(state->inode); |
1428 | calldata->arg.stateid = &state->open_stateid; | 1825 | calldata->arg.stateid = &state->open_stateid; |
1826 | if (nfs4_has_session(server->nfs_client)) | ||
1827 | memset(calldata->arg.stateid->data, 0, 4); /* clear seqid */ | ||
1429 | /* Serialization for the sequence id */ | 1828 | /* Serialization for the sequence id */ |
1430 | calldata->arg.seqid = nfs_alloc_seqid(&state->owner->so_seqid); | 1829 | calldata->arg.seqid = nfs_alloc_seqid(&state->owner->so_seqid); |
1431 | if (calldata->arg.seqid == NULL) | 1830 | if (calldata->arg.seqid == NULL) |
@@ -1435,6 +1834,7 @@ int nfs4_do_close(struct path *path, struct nfs4_state *state, int wait) | |||
1435 | calldata->res.fattr = &calldata->fattr; | 1834 | calldata->res.fattr = &calldata->fattr; |
1436 | calldata->res.seqid = calldata->arg.seqid; | 1835 | calldata->res.seqid = calldata->arg.seqid; |
1437 | calldata->res.server = server; | 1836 | calldata->res.server = server; |
1837 | calldata->res.seq_res.sr_slotid = NFS4_MAX_SLOT_TABLE; | ||
1438 | calldata->path.mnt = mntget(path->mnt); | 1838 | calldata->path.mnt = mntget(path->mnt); |
1439 | calldata->path.dentry = dget(path->dentry); | 1839 | calldata->path.dentry = dget(path->dentry); |
1440 | 1840 | ||
@@ -1584,15 +1984,18 @@ void nfs4_close_context(struct nfs_open_context *ctx, int is_sync) | |||
1584 | 1984 | ||
1585 | static int _nfs4_server_capabilities(struct nfs_server *server, struct nfs_fh *fhandle) | 1985 | static int _nfs4_server_capabilities(struct nfs_server *server, struct nfs_fh *fhandle) |
1586 | { | 1986 | { |
1987 | struct nfs4_server_caps_arg args = { | ||
1988 | .fhandle = fhandle, | ||
1989 | }; | ||
1587 | struct nfs4_server_caps_res res = {}; | 1990 | struct nfs4_server_caps_res res = {}; |
1588 | struct rpc_message msg = { | 1991 | struct rpc_message msg = { |
1589 | .rpc_proc = &nfs4_procedures[NFSPROC4_CLNT_SERVER_CAPS], | 1992 | .rpc_proc = &nfs4_procedures[NFSPROC4_CLNT_SERVER_CAPS], |
1590 | .rpc_argp = fhandle, | 1993 | .rpc_argp = &args, |
1591 | .rpc_resp = &res, | 1994 | .rpc_resp = &res, |
1592 | }; | 1995 | }; |
1593 | int status; | 1996 | int status; |
1594 | 1997 | ||
1595 | status = rpc_call_sync(server->client, &msg, 0); | 1998 | status = nfs4_call_sync(server, &msg, &args, &res, 0); |
1596 | if (status == 0) { | 1999 | if (status == 0) { |
1597 | memcpy(server->attr_bitmask, res.attr_bitmask, sizeof(server->attr_bitmask)); | 2000 | memcpy(server->attr_bitmask, res.attr_bitmask, sizeof(server->attr_bitmask)); |
1598 | if (res.attr_bitmask[0] & FATTR4_WORD0_ACL) | 2001 | if (res.attr_bitmask[0] & FATTR4_WORD0_ACL) |
@@ -1606,6 +2009,7 @@ static int _nfs4_server_capabilities(struct nfs_server *server, struct nfs_fh *f | |||
1606 | server->cache_consistency_bitmask[1] &= FATTR4_WORD1_TIME_METADATA|FATTR4_WORD1_TIME_MODIFY; | 2009 | server->cache_consistency_bitmask[1] &= FATTR4_WORD1_TIME_METADATA|FATTR4_WORD1_TIME_MODIFY; |
1607 | server->acl_bitmask = res.acl_bitmask; | 2010 | server->acl_bitmask = res.acl_bitmask; |
1608 | } | 2011 | } |
2012 | |||
1609 | return status; | 2013 | return status; |
1610 | } | 2014 | } |
1611 | 2015 | ||
@@ -1637,8 +2041,15 @@ static int _nfs4_lookup_root(struct nfs_server *server, struct nfs_fh *fhandle, | |||
1637 | .rpc_argp = &args, | 2041 | .rpc_argp = &args, |
1638 | .rpc_resp = &res, | 2042 | .rpc_resp = &res, |
1639 | }; | 2043 | }; |
2044 | int status; | ||
2045 | |||
1640 | nfs_fattr_init(info->fattr); | 2046 | nfs_fattr_init(info->fattr); |
1641 | return rpc_call_sync(server->client, &msg, 0); | 2047 | status = nfs4_recover_expired_lease(server); |
2048 | if (!status) | ||
2049 | status = nfs4_check_client_ready(server->nfs_client); | ||
2050 | if (!status) | ||
2051 | status = nfs4_call_sync(server, &msg, &args, &res, 0); | ||
2052 | return status; | ||
1642 | } | 2053 | } |
1643 | 2054 | ||
1644 | static int nfs4_lookup_root(struct nfs_server *server, struct nfs_fh *fhandle, | 2055 | static int nfs4_lookup_root(struct nfs_server *server, struct nfs_fh *fhandle, |
@@ -1728,7 +2139,7 @@ static int _nfs4_proc_getattr(struct nfs_server *server, struct nfs_fh *fhandle, | |||
1728 | }; | 2139 | }; |
1729 | 2140 | ||
1730 | nfs_fattr_init(fattr); | 2141 | nfs_fattr_init(fattr); |
1731 | return rpc_call_sync(server->client, &msg, 0); | 2142 | return nfs4_call_sync(server, &msg, &args, &res, 0); |
1732 | } | 2143 | } |
1733 | 2144 | ||
1734 | static int nfs4_proc_getattr(struct nfs_server *server, struct nfs_fh *fhandle, struct nfs_fattr *fattr) | 2145 | static int nfs4_proc_getattr(struct nfs_server *server, struct nfs_fh *fhandle, struct nfs_fattr *fattr) |
@@ -1812,7 +2223,7 @@ static int _nfs4_proc_lookupfh(struct nfs_server *server, const struct nfs_fh *d | |||
1812 | nfs_fattr_init(fattr); | 2223 | nfs_fattr_init(fattr); |
1813 | 2224 | ||
1814 | dprintk("NFS call lookupfh %s\n", name->name); | 2225 | dprintk("NFS call lookupfh %s\n", name->name); |
1815 | status = rpc_call_sync(server->client, &msg, 0); | 2226 | status = nfs4_call_sync(server, &msg, &args, &res, 0); |
1816 | dprintk("NFS reply lookupfh: %d\n", status); | 2227 | dprintk("NFS reply lookupfh: %d\n", status); |
1817 | return status; | 2228 | return status; |
1818 | } | 2229 | } |
@@ -1898,7 +2309,7 @@ static int _nfs4_proc_access(struct inode *inode, struct nfs_access_entry *entry | |||
1898 | args.access |= NFS4_ACCESS_EXECUTE; | 2309 | args.access |= NFS4_ACCESS_EXECUTE; |
1899 | } | 2310 | } |
1900 | nfs_fattr_init(&fattr); | 2311 | nfs_fattr_init(&fattr); |
1901 | status = rpc_call_sync(NFS_CLIENT(inode), &msg, 0); | 2312 | status = nfs4_call_sync(server, &msg, &args, &res, 0); |
1902 | if (!status) { | 2313 | if (!status) { |
1903 | entry->mask = 0; | 2314 | entry->mask = 0; |
1904 | if (res.access & NFS4_ACCESS_READ) | 2315 | if (res.access & NFS4_ACCESS_READ) |
@@ -1957,13 +2368,14 @@ static int _nfs4_proc_readlink(struct inode *inode, struct page *page, | |||
1957 | .pglen = pglen, | 2368 | .pglen = pglen, |
1958 | .pages = &page, | 2369 | .pages = &page, |
1959 | }; | 2370 | }; |
2371 | struct nfs4_readlink_res res; | ||
1960 | struct rpc_message msg = { | 2372 | struct rpc_message msg = { |
1961 | .rpc_proc = &nfs4_procedures[NFSPROC4_CLNT_READLINK], | 2373 | .rpc_proc = &nfs4_procedures[NFSPROC4_CLNT_READLINK], |
1962 | .rpc_argp = &args, | 2374 | .rpc_argp = &args, |
1963 | .rpc_resp = NULL, | 2375 | .rpc_resp = &res, |
1964 | }; | 2376 | }; |
1965 | 2377 | ||
1966 | return rpc_call_sync(NFS_CLIENT(inode), &msg, 0); | 2378 | return nfs4_call_sync(NFS_SERVER(inode), &msg, &args, &res, 0); |
1967 | } | 2379 | } |
1968 | 2380 | ||
1969 | static int nfs4_proc_readlink(struct inode *inode, struct page *page, | 2381 | static int nfs4_proc_readlink(struct inode *inode, struct page *page, |
@@ -2057,7 +2469,7 @@ static int _nfs4_proc_remove(struct inode *dir, struct qstr *name) | |||
2057 | int status; | 2469 | int status; |
2058 | 2470 | ||
2059 | nfs_fattr_init(&res.dir_attr); | 2471 | nfs_fattr_init(&res.dir_attr); |
2060 | status = rpc_call_sync(server->client, &msg, 0); | 2472 | status = nfs4_call_sync(server, &msg, &args, &res, 1); |
2061 | if (status == 0) { | 2473 | if (status == 0) { |
2062 | update_changeattr(dir, &res.cinfo); | 2474 | update_changeattr(dir, &res.cinfo); |
2063 | nfs_post_op_update_inode(dir, &res.dir_attr); | 2475 | nfs_post_op_update_inode(dir, &res.dir_attr); |
@@ -2092,8 +2504,10 @@ static int nfs4_proc_unlink_done(struct rpc_task *task, struct inode *dir) | |||
2092 | { | 2504 | { |
2093 | struct nfs_removeres *res = task->tk_msg.rpc_resp; | 2505 | struct nfs_removeres *res = task->tk_msg.rpc_resp; |
2094 | 2506 | ||
2507 | nfs4_sequence_done(res->server, &res->seq_res, task->tk_status); | ||
2095 | if (nfs4_async_handle_error(task, res->server, NULL) == -EAGAIN) | 2508 | if (nfs4_async_handle_error(task, res->server, NULL) == -EAGAIN) |
2096 | return 0; | 2509 | return 0; |
2510 | nfs4_sequence_free_slot(res->server->nfs_client, &res->seq_res); | ||
2097 | update_changeattr(dir, &res->cinfo); | 2511 | update_changeattr(dir, &res->cinfo); |
2098 | nfs_post_op_update_inode(dir, &res->dir_attr); | 2512 | nfs_post_op_update_inode(dir, &res->dir_attr); |
2099 | return 1; | 2513 | return 1; |
@@ -2125,7 +2539,7 @@ static int _nfs4_proc_rename(struct inode *old_dir, struct qstr *old_name, | |||
2125 | 2539 | ||
2126 | nfs_fattr_init(res.old_fattr); | 2540 | nfs_fattr_init(res.old_fattr); |
2127 | nfs_fattr_init(res.new_fattr); | 2541 | nfs_fattr_init(res.new_fattr); |
2128 | status = rpc_call_sync(server->client, &msg, 0); | 2542 | status = nfs4_call_sync(server, &msg, &arg, &res, 1); |
2129 | 2543 | ||
2130 | if (!status) { | 2544 | if (!status) { |
2131 | update_changeattr(old_dir, &res.old_cinfo); | 2545 | update_changeattr(old_dir, &res.old_cinfo); |
@@ -2174,7 +2588,7 @@ static int _nfs4_proc_link(struct inode *inode, struct inode *dir, struct qstr * | |||
2174 | 2588 | ||
2175 | nfs_fattr_init(res.fattr); | 2589 | nfs_fattr_init(res.fattr); |
2176 | nfs_fattr_init(res.dir_attr); | 2590 | nfs_fattr_init(res.dir_attr); |
2177 | status = rpc_call_sync(server->client, &msg, 0); | 2591 | status = nfs4_call_sync(server, &msg, &arg, &res, 1); |
2178 | if (!status) { | 2592 | if (!status) { |
2179 | update_changeattr(dir, &res.cinfo); | 2593 | update_changeattr(dir, &res.cinfo); |
2180 | nfs_post_op_update_inode(dir, res.dir_attr); | 2594 | nfs_post_op_update_inode(dir, res.dir_attr); |
@@ -2235,7 +2649,8 @@ static struct nfs4_createdata *nfs4_alloc_createdata(struct inode *dir, | |||
2235 | 2649 | ||
2236 | static int nfs4_do_create(struct inode *dir, struct dentry *dentry, struct nfs4_createdata *data) | 2650 | static int nfs4_do_create(struct inode *dir, struct dentry *dentry, struct nfs4_createdata *data) |
2237 | { | 2651 | { |
2238 | int status = rpc_call_sync(NFS_CLIENT(dir), &data->msg, 0); | 2652 | int status = nfs4_call_sync(NFS_SERVER(dir), &data->msg, |
2653 | &data->arg, &data->res, 1); | ||
2239 | if (status == 0) { | 2654 | if (status == 0) { |
2240 | update_changeattr(dir, &data->res.dir_cinfo); | 2655 | update_changeattr(dir, &data->res.dir_cinfo); |
2241 | nfs_post_op_update_inode(dir, data->res.dir_fattr); | 2656 | nfs_post_op_update_inode(dir, data->res.dir_fattr); |
@@ -2344,7 +2759,7 @@ static int _nfs4_proc_readdir(struct dentry *dentry, struct rpc_cred *cred, | |||
2344 | (unsigned long long)cookie); | 2759 | (unsigned long long)cookie); |
2345 | nfs4_setup_readdir(cookie, NFS_COOKIEVERF(dir), dentry, &args); | 2760 | nfs4_setup_readdir(cookie, NFS_COOKIEVERF(dir), dentry, &args); |
2346 | res.pgbase = args.pgbase; | 2761 | res.pgbase = args.pgbase; |
2347 | status = rpc_call_sync(NFS_CLIENT(dir), &msg, 0); | 2762 | status = nfs4_call_sync(NFS_SERVER(dir), &msg, &args, &res, 0); |
2348 | if (status == 0) | 2763 | if (status == 0) |
2349 | memcpy(NFS_COOKIEVERF(dir), res.verifier.data, NFS4_VERIFIER_SIZE); | 2764 | memcpy(NFS_COOKIEVERF(dir), res.verifier.data, NFS4_VERIFIER_SIZE); |
2350 | 2765 | ||
@@ -2422,14 +2837,17 @@ static int _nfs4_proc_statfs(struct nfs_server *server, struct nfs_fh *fhandle, | |||
2422 | .fh = fhandle, | 2837 | .fh = fhandle, |
2423 | .bitmask = server->attr_bitmask, | 2838 | .bitmask = server->attr_bitmask, |
2424 | }; | 2839 | }; |
2840 | struct nfs4_statfs_res res = { | ||
2841 | .fsstat = fsstat, | ||
2842 | }; | ||
2425 | struct rpc_message msg = { | 2843 | struct rpc_message msg = { |
2426 | .rpc_proc = &nfs4_procedures[NFSPROC4_CLNT_STATFS], | 2844 | .rpc_proc = &nfs4_procedures[NFSPROC4_CLNT_STATFS], |
2427 | .rpc_argp = &args, | 2845 | .rpc_argp = &args, |
2428 | .rpc_resp = fsstat, | 2846 | .rpc_resp = &res, |
2429 | }; | 2847 | }; |
2430 | 2848 | ||
2431 | nfs_fattr_init(fsstat->fattr); | 2849 | nfs_fattr_init(fsstat->fattr); |
2432 | return rpc_call_sync(server->client, &msg, 0); | 2850 | return nfs4_call_sync(server, &msg, &args, &res, 0); |
2433 | } | 2851 | } |
2434 | 2852 | ||
2435 | static int nfs4_proc_statfs(struct nfs_server *server, struct nfs_fh *fhandle, struct nfs_fsstat *fsstat) | 2853 | static int nfs4_proc_statfs(struct nfs_server *server, struct nfs_fh *fhandle, struct nfs_fsstat *fsstat) |
@@ -2451,13 +2869,16 @@ static int _nfs4_do_fsinfo(struct nfs_server *server, struct nfs_fh *fhandle, | |||
2451 | .fh = fhandle, | 2869 | .fh = fhandle, |
2452 | .bitmask = server->attr_bitmask, | 2870 | .bitmask = server->attr_bitmask, |
2453 | }; | 2871 | }; |
2872 | struct nfs4_fsinfo_res res = { | ||
2873 | .fsinfo = fsinfo, | ||
2874 | }; | ||
2454 | struct rpc_message msg = { | 2875 | struct rpc_message msg = { |
2455 | .rpc_proc = &nfs4_procedures[NFSPROC4_CLNT_FSINFO], | 2876 | .rpc_proc = &nfs4_procedures[NFSPROC4_CLNT_FSINFO], |
2456 | .rpc_argp = &args, | 2877 | .rpc_argp = &args, |
2457 | .rpc_resp = fsinfo, | 2878 | .rpc_resp = &res, |
2458 | }; | 2879 | }; |
2459 | 2880 | ||
2460 | return rpc_call_sync(server->client, &msg, 0); | 2881 | return nfs4_call_sync(server, &msg, &args, &res, 0); |
2461 | } | 2882 | } |
2462 | 2883 | ||
2463 | static int nfs4_do_fsinfo(struct nfs_server *server, struct nfs_fh *fhandle, struct nfs_fsinfo *fsinfo) | 2884 | static int nfs4_do_fsinfo(struct nfs_server *server, struct nfs_fh *fhandle, struct nfs_fsinfo *fsinfo) |
@@ -2486,10 +2907,13 @@ static int _nfs4_proc_pathconf(struct nfs_server *server, struct nfs_fh *fhandle | |||
2486 | .fh = fhandle, | 2907 | .fh = fhandle, |
2487 | .bitmask = server->attr_bitmask, | 2908 | .bitmask = server->attr_bitmask, |
2488 | }; | 2909 | }; |
2910 | struct nfs4_pathconf_res res = { | ||
2911 | .pathconf = pathconf, | ||
2912 | }; | ||
2489 | struct rpc_message msg = { | 2913 | struct rpc_message msg = { |
2490 | .rpc_proc = &nfs4_procedures[NFSPROC4_CLNT_PATHCONF], | 2914 | .rpc_proc = &nfs4_procedures[NFSPROC4_CLNT_PATHCONF], |
2491 | .rpc_argp = &args, | 2915 | .rpc_argp = &args, |
2492 | .rpc_resp = pathconf, | 2916 | .rpc_resp = &res, |
2493 | }; | 2917 | }; |
2494 | 2918 | ||
2495 | /* None of the pathconf attributes are mandatory to implement */ | 2919 | /* None of the pathconf attributes are mandatory to implement */ |
@@ -2499,7 +2923,7 @@ static int _nfs4_proc_pathconf(struct nfs_server *server, struct nfs_fh *fhandle | |||
2499 | } | 2923 | } |
2500 | 2924 | ||
2501 | nfs_fattr_init(pathconf->fattr); | 2925 | nfs_fattr_init(pathconf->fattr); |
2502 | return rpc_call_sync(server->client, &msg, 0); | 2926 | return nfs4_call_sync(server, &msg, &args, &res, 0); |
2503 | } | 2927 | } |
2504 | 2928 | ||
2505 | static int nfs4_proc_pathconf(struct nfs_server *server, struct nfs_fh *fhandle, | 2929 | static int nfs4_proc_pathconf(struct nfs_server *server, struct nfs_fh *fhandle, |
@@ -2520,8 +2944,13 @@ static int nfs4_read_done(struct rpc_task *task, struct nfs_read_data *data) | |||
2520 | { | 2944 | { |
2521 | struct nfs_server *server = NFS_SERVER(data->inode); | 2945 | struct nfs_server *server = NFS_SERVER(data->inode); |
2522 | 2946 | ||
2947 | dprintk("--> %s\n", __func__); | ||
2948 | |||
2949 | /* nfs4_sequence_free_slot called in the read rpc_call_done */ | ||
2950 | nfs4_sequence_done(server, &data->res.seq_res, task->tk_status); | ||
2951 | |||
2523 | if (nfs4_async_handle_error(task, server, data->args.context->state) == -EAGAIN) { | 2952 | if (nfs4_async_handle_error(task, server, data->args.context->state) == -EAGAIN) { |
2524 | rpc_restart_call(task); | 2953 | nfs4_restart_rpc(task, server->nfs_client); |
2525 | return -EAGAIN; | 2954 | return -EAGAIN; |
2526 | } | 2955 | } |
2527 | 2956 | ||
@@ -2541,8 +2970,12 @@ static int nfs4_write_done(struct rpc_task *task, struct nfs_write_data *data) | |||
2541 | { | 2970 | { |
2542 | struct inode *inode = data->inode; | 2971 | struct inode *inode = data->inode; |
2543 | 2972 | ||
2973 | /* slot is freed in nfs_writeback_done */ | ||
2974 | nfs4_sequence_done(NFS_SERVER(inode), &data->res.seq_res, | ||
2975 | task->tk_status); | ||
2976 | |||
2544 | if (nfs4_async_handle_error(task, NFS_SERVER(inode), data->args.context->state) == -EAGAIN) { | 2977 | if (nfs4_async_handle_error(task, NFS_SERVER(inode), data->args.context->state) == -EAGAIN) { |
2545 | rpc_restart_call(task); | 2978 | nfs4_restart_rpc(task, NFS_SERVER(inode)->nfs_client); |
2546 | return -EAGAIN; | 2979 | return -EAGAIN; |
2547 | } | 2980 | } |
2548 | if (task->tk_status >= 0) { | 2981 | if (task->tk_status >= 0) { |
@@ -2567,10 +3000,14 @@ static int nfs4_commit_done(struct rpc_task *task, struct nfs_write_data *data) | |||
2567 | { | 3000 | { |
2568 | struct inode *inode = data->inode; | 3001 | struct inode *inode = data->inode; |
2569 | 3002 | ||
3003 | nfs4_sequence_done(NFS_SERVER(inode), &data->res.seq_res, | ||
3004 | task->tk_status); | ||
2570 | if (nfs4_async_handle_error(task, NFS_SERVER(inode), NULL) == -EAGAIN) { | 3005 | if (nfs4_async_handle_error(task, NFS_SERVER(inode), NULL) == -EAGAIN) { |
2571 | rpc_restart_call(task); | 3006 | nfs4_restart_rpc(task, NFS_SERVER(inode)->nfs_client); |
2572 | return -EAGAIN; | 3007 | return -EAGAIN; |
2573 | } | 3008 | } |
3009 | nfs4_sequence_free_slot(NFS_SERVER(inode)->nfs_client, | ||
3010 | &data->res.seq_res); | ||
2574 | nfs_refresh_inode(inode, data->res.fattr); | 3011 | nfs_refresh_inode(inode, data->res.fattr); |
2575 | return 0; | 3012 | return 0; |
2576 | } | 3013 | } |
@@ -2603,6 +3040,9 @@ static void nfs4_renew_done(struct rpc_task *task, void *data) | |||
2603 | if (time_before(clp->cl_last_renewal,timestamp)) | 3040 | if (time_before(clp->cl_last_renewal,timestamp)) |
2604 | clp->cl_last_renewal = timestamp; | 3041 | clp->cl_last_renewal = timestamp; |
2605 | spin_unlock(&clp->cl_lock); | 3042 | spin_unlock(&clp->cl_lock); |
3043 | dprintk("%s calling put_rpccred on rpc_cred %p\n", __func__, | ||
3044 | task->tk_msg.rpc_cred); | ||
3045 | put_rpccred(task->tk_msg.rpc_cred); | ||
2606 | } | 3046 | } |
2607 | 3047 | ||
2608 | static const struct rpc_call_ops nfs4_renew_ops = { | 3048 | static const struct rpc_call_ops nfs4_renew_ops = { |
@@ -2742,12 +3182,14 @@ static ssize_t __nfs4_get_acl_uncached(struct inode *inode, void *buf, size_t bu | |||
2742 | .acl_pages = pages, | 3182 | .acl_pages = pages, |
2743 | .acl_len = buflen, | 3183 | .acl_len = buflen, |
2744 | }; | 3184 | }; |
2745 | size_t resp_len = buflen; | 3185 | struct nfs_getaclres res = { |
3186 | .acl_len = buflen, | ||
3187 | }; | ||
2746 | void *resp_buf; | 3188 | void *resp_buf; |
2747 | struct rpc_message msg = { | 3189 | struct rpc_message msg = { |
2748 | .rpc_proc = &nfs4_procedures[NFSPROC4_CLNT_GETACL], | 3190 | .rpc_proc = &nfs4_procedures[NFSPROC4_CLNT_GETACL], |
2749 | .rpc_argp = &args, | 3191 | .rpc_argp = &args, |
2750 | .rpc_resp = &resp_len, | 3192 | .rpc_resp = &res, |
2751 | }; | 3193 | }; |
2752 | struct page *localpage = NULL; | 3194 | struct page *localpage = NULL; |
2753 | int ret; | 3195 | int ret; |
@@ -2761,26 +3203,26 @@ static ssize_t __nfs4_get_acl_uncached(struct inode *inode, void *buf, size_t bu | |||
2761 | return -ENOMEM; | 3203 | return -ENOMEM; |
2762 | args.acl_pages[0] = localpage; | 3204 | args.acl_pages[0] = localpage; |
2763 | args.acl_pgbase = 0; | 3205 | args.acl_pgbase = 0; |
2764 | resp_len = args.acl_len = PAGE_SIZE; | 3206 | args.acl_len = PAGE_SIZE; |
2765 | } else { | 3207 | } else { |
2766 | resp_buf = buf; | 3208 | resp_buf = buf; |
2767 | buf_to_pages(buf, buflen, args.acl_pages, &args.acl_pgbase); | 3209 | buf_to_pages(buf, buflen, args.acl_pages, &args.acl_pgbase); |
2768 | } | 3210 | } |
2769 | ret = rpc_call_sync(NFS_CLIENT(inode), &msg, 0); | 3211 | ret = nfs4_call_sync(NFS_SERVER(inode), &msg, &args, &res, 0); |
2770 | if (ret) | 3212 | if (ret) |
2771 | goto out_free; | 3213 | goto out_free; |
2772 | if (resp_len > args.acl_len) | 3214 | if (res.acl_len > args.acl_len) |
2773 | nfs4_write_cached_acl(inode, NULL, resp_len); | 3215 | nfs4_write_cached_acl(inode, NULL, res.acl_len); |
2774 | else | 3216 | else |
2775 | nfs4_write_cached_acl(inode, resp_buf, resp_len); | 3217 | nfs4_write_cached_acl(inode, resp_buf, res.acl_len); |
2776 | if (buf) { | 3218 | if (buf) { |
2777 | ret = -ERANGE; | 3219 | ret = -ERANGE; |
2778 | if (resp_len > buflen) | 3220 | if (res.acl_len > buflen) |
2779 | goto out_free; | 3221 | goto out_free; |
2780 | if (localpage) | 3222 | if (localpage) |
2781 | memcpy(buf, resp_buf, resp_len); | 3223 | memcpy(buf, resp_buf, res.acl_len); |
2782 | } | 3224 | } |
2783 | ret = resp_len; | 3225 | ret = res.acl_len; |
2784 | out_free: | 3226 | out_free: |
2785 | if (localpage) | 3227 | if (localpage) |
2786 | __free_page(localpage); | 3228 | __free_page(localpage); |
@@ -2810,8 +3252,6 @@ static ssize_t nfs4_proc_get_acl(struct inode *inode, void *buf, size_t buflen) | |||
2810 | ret = nfs_revalidate_inode(server, inode); | 3252 | ret = nfs_revalidate_inode(server, inode); |
2811 | if (ret < 0) | 3253 | if (ret < 0) |
2812 | return ret; | 3254 | return ret; |
2813 | if (NFS_I(inode)->cache_validity & NFS_INO_INVALID_ACL) | ||
2814 | nfs_zap_acl_cache(inode); | ||
2815 | ret = nfs4_read_cached_acl(inode, buf, buflen); | 3255 | ret = nfs4_read_cached_acl(inode, buf, buflen); |
2816 | if (ret != -ENOENT) | 3256 | if (ret != -ENOENT) |
2817 | return ret; | 3257 | return ret; |
@@ -2827,10 +3267,11 @@ static int __nfs4_proc_set_acl(struct inode *inode, const void *buf, size_t bufl | |||
2827 | .acl_pages = pages, | 3267 | .acl_pages = pages, |
2828 | .acl_len = buflen, | 3268 | .acl_len = buflen, |
2829 | }; | 3269 | }; |
3270 | struct nfs_setaclres res; | ||
2830 | struct rpc_message msg = { | 3271 | struct rpc_message msg = { |
2831 | .rpc_proc = &nfs4_procedures[NFSPROC4_CLNT_SETACL], | 3272 | .rpc_proc = &nfs4_procedures[NFSPROC4_CLNT_SETACL], |
2832 | .rpc_argp = &arg, | 3273 | .rpc_argp = &arg, |
2833 | .rpc_resp = NULL, | 3274 | .rpc_resp = &res, |
2834 | }; | 3275 | }; |
2835 | int ret; | 3276 | int ret; |
2836 | 3277 | ||
@@ -2838,7 +3279,7 @@ static int __nfs4_proc_set_acl(struct inode *inode, const void *buf, size_t bufl | |||
2838 | return -EOPNOTSUPP; | 3279 | return -EOPNOTSUPP; |
2839 | nfs_inode_return_delegation(inode); | 3280 | nfs_inode_return_delegation(inode); |
2840 | buf_to_pages(buf, buflen, arg.acl_pages, &arg.acl_pgbase); | 3281 | buf_to_pages(buf, buflen, arg.acl_pages, &arg.acl_pgbase); |
2841 | ret = rpc_call_sync(NFS_CLIENT(inode), &msg, 0); | 3282 | ret = nfs4_call_sync(server, &msg, &arg, &res, 1); |
2842 | nfs_access_zap_cache(inode); | 3283 | nfs_access_zap_cache(inode); |
2843 | nfs_zap_acl_cache(inode); | 3284 | nfs_zap_acl_cache(inode); |
2844 | return ret; | 3285 | return ret; |
@@ -2857,10 +3298,8 @@ static int nfs4_proc_set_acl(struct inode *inode, const void *buf, size_t buflen | |||
2857 | } | 3298 | } |
2858 | 3299 | ||
2859 | static int | 3300 | static int |
2860 | nfs4_async_handle_error(struct rpc_task *task, const struct nfs_server *server, struct nfs4_state *state) | 3301 | _nfs4_async_handle_error(struct rpc_task *task, const struct nfs_server *server, struct nfs_client *clp, struct nfs4_state *state) |
2861 | { | 3302 | { |
2862 | struct nfs_client *clp = server->nfs_client; | ||
2863 | |||
2864 | if (!clp || task->tk_status >= 0) | 3303 | if (!clp || task->tk_status >= 0) |
2865 | return 0; | 3304 | return 0; |
2866 | switch(task->tk_status) { | 3305 | switch(task->tk_status) { |
@@ -2879,8 +3318,23 @@ nfs4_async_handle_error(struct rpc_task *task, const struct nfs_server *server, | |||
2879 | rpc_wake_up_queued_task(&clp->cl_rpcwaitq, task); | 3318 | rpc_wake_up_queued_task(&clp->cl_rpcwaitq, task); |
2880 | task->tk_status = 0; | 3319 | task->tk_status = 0; |
2881 | return -EAGAIN; | 3320 | return -EAGAIN; |
3321 | #if defined(CONFIG_NFS_V4_1) | ||
3322 | case -NFS4ERR_BADSESSION: | ||
3323 | case -NFS4ERR_BADSLOT: | ||
3324 | case -NFS4ERR_BAD_HIGH_SLOT: | ||
3325 | case -NFS4ERR_DEADSESSION: | ||
3326 | case -NFS4ERR_CONN_NOT_BOUND_TO_SESSION: | ||
3327 | case -NFS4ERR_SEQ_FALSE_RETRY: | ||
3328 | case -NFS4ERR_SEQ_MISORDERED: | ||
3329 | dprintk("%s ERROR %d, Reset session\n", __func__, | ||
3330 | task->tk_status); | ||
3331 | set_bit(NFS4CLNT_SESSION_SETUP, &clp->cl_state); | ||
3332 | task->tk_status = 0; | ||
3333 | return -EAGAIN; | ||
3334 | #endif /* CONFIG_NFS_V4_1 */ | ||
2882 | case -NFS4ERR_DELAY: | 3335 | case -NFS4ERR_DELAY: |
2883 | nfs_inc_server_stats(server, NFSIOS_DELAY); | 3336 | if (server) |
3337 | nfs_inc_server_stats(server, NFSIOS_DELAY); | ||
2884 | case -NFS4ERR_GRACE: | 3338 | case -NFS4ERR_GRACE: |
2885 | rpc_delay(task, NFS4_POLL_RETRY_MAX); | 3339 | rpc_delay(task, NFS4_POLL_RETRY_MAX); |
2886 | task->tk_status = 0; | 3340 | task->tk_status = 0; |
@@ -2893,6 +3347,12 @@ nfs4_async_handle_error(struct rpc_task *task, const struct nfs_server *server, | |||
2893 | return 0; | 3347 | return 0; |
2894 | } | 3348 | } |
2895 | 3349 | ||
3350 | static int | ||
3351 | nfs4_async_handle_error(struct rpc_task *task, const struct nfs_server *server, struct nfs4_state *state) | ||
3352 | { | ||
3353 | return _nfs4_async_handle_error(task, server, server->nfs_client, state); | ||
3354 | } | ||
3355 | |||
2896 | int nfs4_proc_setclientid(struct nfs_client *clp, u32 program, unsigned short port, struct rpc_cred *cred) | 3356 | int nfs4_proc_setclientid(struct nfs_client *clp, u32 program, unsigned short port, struct rpc_cred *cred) |
2897 | { | 3357 | { |
2898 | nfs4_verifier sc_verifier; | 3358 | nfs4_verifier sc_verifier; |
@@ -3000,6 +3460,10 @@ struct nfs4_delegreturndata { | |||
3000 | static void nfs4_delegreturn_done(struct rpc_task *task, void *calldata) | 3460 | static void nfs4_delegreturn_done(struct rpc_task *task, void *calldata) |
3001 | { | 3461 | { |
3002 | struct nfs4_delegreturndata *data = calldata; | 3462 | struct nfs4_delegreturndata *data = calldata; |
3463 | |||
3464 | nfs4_sequence_done_free_slot(data->res.server, &data->res.seq_res, | ||
3465 | task->tk_status); | ||
3466 | |||
3003 | data->rpc_status = task->tk_status; | 3467 | data->rpc_status = task->tk_status; |
3004 | if (data->rpc_status == 0) | 3468 | if (data->rpc_status == 0) |
3005 | renew_lease(data->res.server, data->timestamp); | 3469 | renew_lease(data->res.server, data->timestamp); |
@@ -3010,7 +3474,25 @@ static void nfs4_delegreturn_release(void *calldata) | |||
3010 | kfree(calldata); | 3474 | kfree(calldata); |
3011 | } | 3475 | } |
3012 | 3476 | ||
3477 | #if defined(CONFIG_NFS_V4_1) | ||
3478 | static void nfs4_delegreturn_prepare(struct rpc_task *task, void *data) | ||
3479 | { | ||
3480 | struct nfs4_delegreturndata *d_data; | ||
3481 | |||
3482 | d_data = (struct nfs4_delegreturndata *)data; | ||
3483 | |||
3484 | if (nfs4_setup_sequence(d_data->res.server->nfs_client, | ||
3485 | &d_data->args.seq_args, | ||
3486 | &d_data->res.seq_res, 1, task)) | ||
3487 | return; | ||
3488 | rpc_call_start(task); | ||
3489 | } | ||
3490 | #endif /* CONFIG_NFS_V4_1 */ | ||
3491 | |||
3013 | static const struct rpc_call_ops nfs4_delegreturn_ops = { | 3492 | static const struct rpc_call_ops nfs4_delegreturn_ops = { |
3493 | #if defined(CONFIG_NFS_V4_1) | ||
3494 | .rpc_call_prepare = nfs4_delegreturn_prepare, | ||
3495 | #endif /* CONFIG_NFS_V4_1 */ | ||
3014 | .rpc_call_done = nfs4_delegreturn_done, | 3496 | .rpc_call_done = nfs4_delegreturn_done, |
3015 | .rpc_release = nfs4_delegreturn_release, | 3497 | .rpc_release = nfs4_delegreturn_release, |
3016 | }; | 3498 | }; |
@@ -3032,7 +3514,7 @@ static int _nfs4_proc_delegreturn(struct inode *inode, struct rpc_cred *cred, co | |||
3032 | }; | 3514 | }; |
3033 | int status = 0; | 3515 | int status = 0; |
3034 | 3516 | ||
3035 | data = kmalloc(sizeof(*data), GFP_KERNEL); | 3517 | data = kzalloc(sizeof(*data), GFP_KERNEL); |
3036 | if (data == NULL) | 3518 | if (data == NULL) |
3037 | return -ENOMEM; | 3519 | return -ENOMEM; |
3038 | data->args.fhandle = &data->fh; | 3520 | data->args.fhandle = &data->fh; |
@@ -3042,6 +3524,7 @@ static int _nfs4_proc_delegreturn(struct inode *inode, struct rpc_cred *cred, co | |||
3042 | memcpy(&data->stateid, stateid, sizeof(data->stateid)); | 3524 | memcpy(&data->stateid, stateid, sizeof(data->stateid)); |
3043 | data->res.fattr = &data->fattr; | 3525 | data->res.fattr = &data->fattr; |
3044 | data->res.server = server; | 3526 | data->res.server = server; |
3527 | data->res.seq_res.sr_slotid = NFS4_MAX_SLOT_TABLE; | ||
3045 | nfs_fattr_init(data->res.fattr); | 3528 | nfs_fattr_init(data->res.fattr); |
3046 | data->timestamp = jiffies; | 3529 | data->timestamp = jiffies; |
3047 | data->rpc_status = 0; | 3530 | data->rpc_status = 0; |
@@ -3127,7 +3610,7 @@ static int _nfs4_proc_getlk(struct nfs4_state *state, int cmd, struct file_lock | |||
3127 | goto out; | 3610 | goto out; |
3128 | lsp = request->fl_u.nfs4_fl.owner; | 3611 | lsp = request->fl_u.nfs4_fl.owner; |
3129 | arg.lock_owner.id = lsp->ls_id.id; | 3612 | arg.lock_owner.id = lsp->ls_id.id; |
3130 | status = rpc_call_sync(server->client, &msg, 0); | 3613 | status = nfs4_call_sync(server, &msg, &arg, &res, 1); |
3131 | switch (status) { | 3614 | switch (status) { |
3132 | case 0: | 3615 | case 0: |
3133 | request->fl_type = F_UNLCK; | 3616 | request->fl_type = F_UNLCK; |
@@ -3187,13 +3670,14 @@ static struct nfs4_unlockdata *nfs4_alloc_unlockdata(struct file_lock *fl, | |||
3187 | struct nfs4_unlockdata *p; | 3670 | struct nfs4_unlockdata *p; |
3188 | struct inode *inode = lsp->ls_state->inode; | 3671 | struct inode *inode = lsp->ls_state->inode; |
3189 | 3672 | ||
3190 | p = kmalloc(sizeof(*p), GFP_KERNEL); | 3673 | p = kzalloc(sizeof(*p), GFP_KERNEL); |
3191 | if (p == NULL) | 3674 | if (p == NULL) |
3192 | return NULL; | 3675 | return NULL; |
3193 | p->arg.fh = NFS_FH(inode); | 3676 | p->arg.fh = NFS_FH(inode); |
3194 | p->arg.fl = &p->fl; | 3677 | p->arg.fl = &p->fl; |
3195 | p->arg.seqid = seqid; | 3678 | p->arg.seqid = seqid; |
3196 | p->res.seqid = seqid; | 3679 | p->res.seqid = seqid; |
3680 | p->res.seq_res.sr_slotid = NFS4_MAX_SLOT_TABLE; | ||
3197 | p->arg.stateid = &lsp->ls_stateid; | 3681 | p->arg.stateid = &lsp->ls_stateid; |
3198 | p->lsp = lsp; | 3682 | p->lsp = lsp; |
3199 | atomic_inc(&lsp->ls_count); | 3683 | atomic_inc(&lsp->ls_count); |
@@ -3217,6 +3701,8 @@ static void nfs4_locku_done(struct rpc_task *task, void *data) | |||
3217 | { | 3701 | { |
3218 | struct nfs4_unlockdata *calldata = data; | 3702 | struct nfs4_unlockdata *calldata = data; |
3219 | 3703 | ||
3704 | nfs4_sequence_done(calldata->server, &calldata->res.seq_res, | ||
3705 | task->tk_status); | ||
3220 | if (RPC_ASSASSINATED(task)) | 3706 | if (RPC_ASSASSINATED(task)) |
3221 | return; | 3707 | return; |
3222 | switch (task->tk_status) { | 3708 | switch (task->tk_status) { |
@@ -3233,8 +3719,11 @@ static void nfs4_locku_done(struct rpc_task *task, void *data) | |||
3233 | break; | 3719 | break; |
3234 | default: | 3720 | default: |
3235 | if (nfs4_async_handle_error(task, calldata->server, NULL) == -EAGAIN) | 3721 | if (nfs4_async_handle_error(task, calldata->server, NULL) == -EAGAIN) |
3236 | rpc_restart_call(task); | 3722 | nfs4_restart_rpc(task, |
3723 | calldata->server->nfs_client); | ||
3237 | } | 3724 | } |
3725 | nfs4_sequence_free_slot(calldata->server->nfs_client, | ||
3726 | &calldata->res.seq_res); | ||
3238 | } | 3727 | } |
3239 | 3728 | ||
3240 | static void nfs4_locku_prepare(struct rpc_task *task, void *data) | 3729 | static void nfs4_locku_prepare(struct rpc_task *task, void *data) |
@@ -3249,6 +3738,10 @@ static void nfs4_locku_prepare(struct rpc_task *task, void *data) | |||
3249 | return; | 3738 | return; |
3250 | } | 3739 | } |
3251 | calldata->timestamp = jiffies; | 3740 | calldata->timestamp = jiffies; |
3741 | if (nfs4_setup_sequence(calldata->server->nfs_client, | ||
3742 | &calldata->arg.seq_args, | ||
3743 | &calldata->res.seq_res, 1, task)) | ||
3744 | return; | ||
3252 | rpc_call_start(task); | 3745 | rpc_call_start(task); |
3253 | } | 3746 | } |
3254 | 3747 | ||
@@ -3341,6 +3834,7 @@ struct nfs4_lockdata { | |||
3341 | unsigned long timestamp; | 3834 | unsigned long timestamp; |
3342 | int rpc_status; | 3835 | int rpc_status; |
3343 | int cancelled; | 3836 | int cancelled; |
3837 | struct nfs_server *server; | ||
3344 | }; | 3838 | }; |
3345 | 3839 | ||
3346 | static struct nfs4_lockdata *nfs4_alloc_lockdata(struct file_lock *fl, | 3840 | static struct nfs4_lockdata *nfs4_alloc_lockdata(struct file_lock *fl, |
@@ -3366,7 +3860,9 @@ static struct nfs4_lockdata *nfs4_alloc_lockdata(struct file_lock *fl, | |||
3366 | p->arg.lock_owner.clientid = server->nfs_client->cl_clientid; | 3860 | p->arg.lock_owner.clientid = server->nfs_client->cl_clientid; |
3367 | p->arg.lock_owner.id = lsp->ls_id.id; | 3861 | p->arg.lock_owner.id = lsp->ls_id.id; |
3368 | p->res.lock_seqid = p->arg.lock_seqid; | 3862 | p->res.lock_seqid = p->arg.lock_seqid; |
3863 | p->res.seq_res.sr_slotid = NFS4_MAX_SLOT_TABLE; | ||
3369 | p->lsp = lsp; | 3864 | p->lsp = lsp; |
3865 | p->server = server; | ||
3370 | atomic_inc(&lsp->ls_count); | 3866 | atomic_inc(&lsp->ls_count); |
3371 | p->ctx = get_nfs_open_context(ctx); | 3867 | p->ctx = get_nfs_open_context(ctx); |
3372 | memcpy(&p->fl, fl, sizeof(p->fl)); | 3868 | memcpy(&p->fl, fl, sizeof(p->fl)); |
@@ -3396,6 +3892,9 @@ static void nfs4_lock_prepare(struct rpc_task *task, void *calldata) | |||
3396 | } else | 3892 | } else |
3397 | data->arg.new_lock_owner = 0; | 3893 | data->arg.new_lock_owner = 0; |
3398 | data->timestamp = jiffies; | 3894 | data->timestamp = jiffies; |
3895 | if (nfs4_setup_sequence(data->server->nfs_client, &data->arg.seq_args, | ||
3896 | &data->res.seq_res, 1, task)) | ||
3897 | return; | ||
3399 | rpc_call_start(task); | 3898 | rpc_call_start(task); |
3400 | dprintk("%s: done!, ret = %d\n", __func__, data->rpc_status); | 3899 | dprintk("%s: done!, ret = %d\n", __func__, data->rpc_status); |
3401 | } | 3900 | } |
@@ -3406,6 +3905,9 @@ static void nfs4_lock_done(struct rpc_task *task, void *calldata) | |||
3406 | 3905 | ||
3407 | dprintk("%s: begin!\n", __func__); | 3906 | dprintk("%s: begin!\n", __func__); |
3408 | 3907 | ||
3908 | nfs4_sequence_done_free_slot(data->server, &data->res.seq_res, | ||
3909 | task->tk_status); | ||
3910 | |||
3409 | data->rpc_status = task->tk_status; | 3911 | data->rpc_status = task->tk_status; |
3410 | if (RPC_ASSASSINATED(task)) | 3912 | if (RPC_ASSASSINATED(task)) |
3411 | goto out; | 3913 | goto out; |
@@ -3487,8 +3989,6 @@ static int _nfs4_do_setlk(struct nfs4_state *state, int cmd, struct file_lock *f | |||
3487 | ret = nfs4_wait_for_completion_rpc_task(task); | 3989 | ret = nfs4_wait_for_completion_rpc_task(task); |
3488 | if (ret == 0) { | 3990 | if (ret == 0) { |
3489 | ret = data->rpc_status; | 3991 | ret = data->rpc_status; |
3490 | if (ret == -NFS4ERR_DENIED) | ||
3491 | ret = -EAGAIN; | ||
3492 | } else | 3992 | } else |
3493 | data->cancelled = 1; | 3993 | data->cancelled = 1; |
3494 | rpc_put_task(task); | 3994 | rpc_put_task(task); |
@@ -3576,9 +4076,11 @@ static int nfs4_proc_setlk(struct nfs4_state *state, int cmd, struct file_lock * | |||
3576 | int err; | 4076 | int err; |
3577 | 4077 | ||
3578 | do { | 4078 | do { |
4079 | err = _nfs4_proc_setlk(state, cmd, request); | ||
4080 | if (err == -NFS4ERR_DENIED) | ||
4081 | err = -EAGAIN; | ||
3579 | err = nfs4_handle_exception(NFS_SERVER(state->inode), | 4082 | err = nfs4_handle_exception(NFS_SERVER(state->inode), |
3580 | _nfs4_proc_setlk(state, cmd, request), | 4083 | err, &exception); |
3581 | &exception); | ||
3582 | } while (exception.retry); | 4084 | } while (exception.retry); |
3583 | return err; | 4085 | return err; |
3584 | } | 4086 | } |
@@ -3630,8 +4132,37 @@ int nfs4_lock_delegation_recall(struct nfs4_state *state, struct file_lock *fl) | |||
3630 | goto out; | 4132 | goto out; |
3631 | do { | 4133 | do { |
3632 | err = _nfs4_do_setlk(state, F_SETLK, fl, 0); | 4134 | err = _nfs4_do_setlk(state, F_SETLK, fl, 0); |
3633 | if (err != -NFS4ERR_DELAY) | 4135 | switch (err) { |
3634 | break; | 4136 | default: |
4137 | printk(KERN_ERR "%s: unhandled error %d.\n", | ||
4138 | __func__, err); | ||
4139 | case 0: | ||
4140 | case -ESTALE: | ||
4141 | goto out; | ||
4142 | case -NFS4ERR_EXPIRED: | ||
4143 | case -NFS4ERR_STALE_CLIENTID: | ||
4144 | case -NFS4ERR_STALE_STATEID: | ||
4145 | nfs4_schedule_state_recovery(server->nfs_client); | ||
4146 | goto out; | ||
4147 | case -ERESTARTSYS: | ||
4148 | /* | ||
4149 | * The show must go on: exit, but mark the | ||
4150 | * stateid as needing recovery. | ||
4151 | */ | ||
4152 | case -NFS4ERR_ADMIN_REVOKED: | ||
4153 | case -NFS4ERR_BAD_STATEID: | ||
4154 | case -NFS4ERR_OPENMODE: | ||
4155 | nfs4_state_mark_reclaim_nograce(server->nfs_client, state); | ||
4156 | err = 0; | ||
4157 | goto out; | ||
4158 | case -ENOMEM: | ||
4159 | case -NFS4ERR_DENIED: | ||
4160 | /* kill_proc(fl->fl_pid, SIGLOST, 1); */ | ||
4161 | err = 0; | ||
4162 | goto out; | ||
4163 | case -NFS4ERR_DELAY: | ||
4164 | break; | ||
4165 | } | ||
3635 | err = nfs4_handle_exception(server, err, &exception); | 4166 | err = nfs4_handle_exception(server, err, &exception); |
3636 | } while (exception.retry); | 4167 | } while (exception.retry); |
3637 | out: | 4168 | out: |
@@ -3706,10 +4237,13 @@ int nfs4_proc_fs_locations(struct inode *dir, const struct qstr *name, | |||
3706 | .page = page, | 4237 | .page = page, |
3707 | .bitmask = bitmask, | 4238 | .bitmask = bitmask, |
3708 | }; | 4239 | }; |
4240 | struct nfs4_fs_locations_res res = { | ||
4241 | .fs_locations = fs_locations, | ||
4242 | }; | ||
3709 | struct rpc_message msg = { | 4243 | struct rpc_message msg = { |
3710 | .rpc_proc = &nfs4_procedures[NFSPROC4_CLNT_FS_LOCATIONS], | 4244 | .rpc_proc = &nfs4_procedures[NFSPROC4_CLNT_FS_LOCATIONS], |
3711 | .rpc_argp = &args, | 4245 | .rpc_argp = &args, |
3712 | .rpc_resp = fs_locations, | 4246 | .rpc_resp = &res, |
3713 | }; | 4247 | }; |
3714 | int status; | 4248 | int status; |
3715 | 4249 | ||
@@ -3717,24 +4251,720 @@ int nfs4_proc_fs_locations(struct inode *dir, const struct qstr *name, | |||
3717 | nfs_fattr_init(&fs_locations->fattr); | 4251 | nfs_fattr_init(&fs_locations->fattr); |
3718 | fs_locations->server = server; | 4252 | fs_locations->server = server; |
3719 | fs_locations->nlocations = 0; | 4253 | fs_locations->nlocations = 0; |
3720 | status = rpc_call_sync(server->client, &msg, 0); | 4254 | status = nfs4_call_sync(server, &msg, &args, &res, 0); |
3721 | nfs_fixup_referral_attributes(&fs_locations->fattr); | 4255 | nfs_fixup_referral_attributes(&fs_locations->fattr); |
3722 | dprintk("%s: returned status = %d\n", __func__, status); | 4256 | dprintk("%s: returned status = %d\n", __func__, status); |
3723 | return status; | 4257 | return status; |
3724 | } | 4258 | } |
3725 | 4259 | ||
3726 | struct nfs4_state_recovery_ops nfs4_reboot_recovery_ops = { | 4260 | #ifdef CONFIG_NFS_V4_1 |
4261 | /* | ||
4262 | * nfs4_proc_exchange_id() | ||
4263 | * | ||
4264 | * Since the clientid has expired, all compounds using sessions | ||
4265 | * associated with the stale clientid will be returning | ||
4266 | * NFS4ERR_BADSESSION in the sequence operation, and will therefore | ||
4267 | * be in some phase of session reset. | ||
4268 | */ | ||
4269 | static int nfs4_proc_exchange_id(struct nfs_client *clp, struct rpc_cred *cred) | ||
4270 | { | ||
4271 | nfs4_verifier verifier; | ||
4272 | struct nfs41_exchange_id_args args = { | ||
4273 | .client = clp, | ||
4274 | .flags = clp->cl_exchange_flags, | ||
4275 | }; | ||
4276 | struct nfs41_exchange_id_res res = { | ||
4277 | .client = clp, | ||
4278 | }; | ||
4279 | int status; | ||
4280 | struct rpc_message msg = { | ||
4281 | .rpc_proc = &nfs4_procedures[NFSPROC4_CLNT_EXCHANGE_ID], | ||
4282 | .rpc_argp = &args, | ||
4283 | .rpc_resp = &res, | ||
4284 | .rpc_cred = cred, | ||
4285 | }; | ||
4286 | __be32 *p; | ||
4287 | |||
4288 | dprintk("--> %s\n", __func__); | ||
4289 | BUG_ON(clp == NULL); | ||
4290 | |||
4291 | p = (u32 *)verifier.data; | ||
4292 | *p++ = htonl((u32)clp->cl_boot_time.tv_sec); | ||
4293 | *p = htonl((u32)clp->cl_boot_time.tv_nsec); | ||
4294 | args.verifier = &verifier; | ||
4295 | |||
4296 | while (1) { | ||
4297 | args.id_len = scnprintf(args.id, sizeof(args.id), | ||
4298 | "%s/%s %u", | ||
4299 | clp->cl_ipaddr, | ||
4300 | rpc_peeraddr2str(clp->cl_rpcclient, | ||
4301 | RPC_DISPLAY_ADDR), | ||
4302 | clp->cl_id_uniquifier); | ||
4303 | |||
4304 | status = rpc_call_sync(clp->cl_rpcclient, &msg, 0); | ||
4305 | |||
4306 | if (status != NFS4ERR_CLID_INUSE) | ||
4307 | break; | ||
4308 | |||
4309 | if (signalled()) | ||
4310 | break; | ||
4311 | |||
4312 | if (++clp->cl_id_uniquifier == 0) | ||
4313 | break; | ||
4314 | } | ||
4315 | |||
4316 | dprintk("<-- %s status= %d\n", __func__, status); | ||
4317 | return status; | ||
4318 | } | ||
4319 | |||
4320 | struct nfs4_get_lease_time_data { | ||
4321 | struct nfs4_get_lease_time_args *args; | ||
4322 | struct nfs4_get_lease_time_res *res; | ||
4323 | struct nfs_client *clp; | ||
4324 | }; | ||
4325 | |||
4326 | static void nfs4_get_lease_time_prepare(struct rpc_task *task, | ||
4327 | void *calldata) | ||
4328 | { | ||
4329 | int ret; | ||
4330 | struct nfs4_get_lease_time_data *data = | ||
4331 | (struct nfs4_get_lease_time_data *)calldata; | ||
4332 | |||
4333 | dprintk("--> %s\n", __func__); | ||
4334 | /* just setup sequence, do not trigger session recovery | ||
4335 | since we're invoked within one */ | ||
4336 | ret = nfs41_setup_sequence(data->clp->cl_session, | ||
4337 | &data->args->la_seq_args, | ||
4338 | &data->res->lr_seq_res, 0, task); | ||
4339 | |||
4340 | BUG_ON(ret == -EAGAIN); | ||
4341 | rpc_call_start(task); | ||
4342 | dprintk("<-- %s\n", __func__); | ||
4343 | } | ||
4344 | |||
4345 | /* | ||
4346 | * Called from nfs4_state_manager thread for session setup, so don't recover | ||
4347 | * from sequence operation or clientid errors. | ||
4348 | */ | ||
4349 | static void nfs4_get_lease_time_done(struct rpc_task *task, void *calldata) | ||
4350 | { | ||
4351 | struct nfs4_get_lease_time_data *data = | ||
4352 | (struct nfs4_get_lease_time_data *)calldata; | ||
4353 | |||
4354 | dprintk("--> %s\n", __func__); | ||
4355 | nfs41_sequence_done(data->clp, &data->res->lr_seq_res, task->tk_status); | ||
4356 | switch (task->tk_status) { | ||
4357 | case -NFS4ERR_DELAY: | ||
4358 | case -NFS4ERR_GRACE: | ||
4359 | dprintk("%s Retry: tk_status %d\n", __func__, task->tk_status); | ||
4360 | rpc_delay(task, NFS4_POLL_RETRY_MIN); | ||
4361 | task->tk_status = 0; | ||
4362 | nfs4_restart_rpc(task, data->clp); | ||
4363 | return; | ||
4364 | } | ||
4365 | nfs41_sequence_free_slot(data->clp, &data->res->lr_seq_res); | ||
4366 | dprintk("<-- %s\n", __func__); | ||
4367 | } | ||
4368 | |||
4369 | struct rpc_call_ops nfs4_get_lease_time_ops = { | ||
4370 | .rpc_call_prepare = nfs4_get_lease_time_prepare, | ||
4371 | .rpc_call_done = nfs4_get_lease_time_done, | ||
4372 | }; | ||
4373 | |||
4374 | int nfs4_proc_get_lease_time(struct nfs_client *clp, struct nfs_fsinfo *fsinfo) | ||
4375 | { | ||
4376 | struct rpc_task *task; | ||
4377 | struct nfs4_get_lease_time_args args; | ||
4378 | struct nfs4_get_lease_time_res res = { | ||
4379 | .lr_fsinfo = fsinfo, | ||
4380 | }; | ||
4381 | struct nfs4_get_lease_time_data data = { | ||
4382 | .args = &args, | ||
4383 | .res = &res, | ||
4384 | .clp = clp, | ||
4385 | }; | ||
4386 | struct rpc_message msg = { | ||
4387 | .rpc_proc = &nfs4_procedures[NFSPROC4_CLNT_GET_LEASE_TIME], | ||
4388 | .rpc_argp = &args, | ||
4389 | .rpc_resp = &res, | ||
4390 | }; | ||
4391 | struct rpc_task_setup task_setup = { | ||
4392 | .rpc_client = clp->cl_rpcclient, | ||
4393 | .rpc_message = &msg, | ||
4394 | .callback_ops = &nfs4_get_lease_time_ops, | ||
4395 | .callback_data = &data | ||
4396 | }; | ||
4397 | int status; | ||
4398 | |||
4399 | res.lr_seq_res.sr_slotid = NFS4_MAX_SLOT_TABLE; | ||
4400 | dprintk("--> %s\n", __func__); | ||
4401 | task = rpc_run_task(&task_setup); | ||
4402 | |||
4403 | if (IS_ERR(task)) | ||
4404 | status = PTR_ERR(task); | ||
4405 | else { | ||
4406 | status = task->tk_status; | ||
4407 | rpc_put_task(task); | ||
4408 | } | ||
4409 | dprintk("<-- %s return %d\n", __func__, status); | ||
4410 | |||
4411 | return status; | ||
4412 | } | ||
4413 | |||
4414 | /* | ||
4415 | * Reset a slot table | ||
4416 | */ | ||
4417 | static int nfs4_reset_slot_table(struct nfs4_slot_table *tbl, int max_slots, | ||
4418 | int old_max_slots, int ivalue) | ||
4419 | { | ||
4420 | int i; | ||
4421 | int ret = 0; | ||
4422 | |||
4423 | dprintk("--> %s: max_reqs=%u, tbl %p\n", __func__, max_slots, tbl); | ||
4424 | |||
4425 | /* | ||
4426 | * Until we have dynamic slot table adjustment, insist | ||
4427 | * upon the same slot table size | ||
4428 | */ | ||
4429 | if (max_slots != old_max_slots) { | ||
4430 | dprintk("%s reset slot table does't match old\n", | ||
4431 | __func__); | ||
4432 | ret = -EINVAL; /*XXX NFS4ERR_REQ_TOO_BIG ? */ | ||
4433 | goto out; | ||
4434 | } | ||
4435 | spin_lock(&tbl->slot_tbl_lock); | ||
4436 | for (i = 0; i < max_slots; ++i) | ||
4437 | tbl->slots[i].seq_nr = ivalue; | ||
4438 | tbl->highest_used_slotid = -1; | ||
4439 | spin_unlock(&tbl->slot_tbl_lock); | ||
4440 | dprintk("%s: tbl=%p slots=%p max_slots=%d\n", __func__, | ||
4441 | tbl, tbl->slots, tbl->max_slots); | ||
4442 | out: | ||
4443 | dprintk("<-- %s: return %d\n", __func__, ret); | ||
4444 | return ret; | ||
4445 | } | ||
4446 | |||
4447 | /* | ||
4448 | * Reset the forechannel and backchannel slot tables | ||
4449 | */ | ||
4450 | static int nfs4_reset_slot_tables(struct nfs4_session *session) | ||
4451 | { | ||
4452 | int status; | ||
4453 | |||
4454 | status = nfs4_reset_slot_table(&session->fc_slot_table, | ||
4455 | session->fc_attrs.max_reqs, | ||
4456 | session->fc_slot_table.max_slots, | ||
4457 | 1); | ||
4458 | if (status) | ||
4459 | return status; | ||
4460 | |||
4461 | status = nfs4_reset_slot_table(&session->bc_slot_table, | ||
4462 | session->bc_attrs.max_reqs, | ||
4463 | session->bc_slot_table.max_slots, | ||
4464 | 0); | ||
4465 | return status; | ||
4466 | } | ||
4467 | |||
4468 | /* Destroy the slot table */ | ||
4469 | static void nfs4_destroy_slot_tables(struct nfs4_session *session) | ||
4470 | { | ||
4471 | if (session->fc_slot_table.slots != NULL) { | ||
4472 | kfree(session->fc_slot_table.slots); | ||
4473 | session->fc_slot_table.slots = NULL; | ||
4474 | } | ||
4475 | if (session->bc_slot_table.slots != NULL) { | ||
4476 | kfree(session->bc_slot_table.slots); | ||
4477 | session->bc_slot_table.slots = NULL; | ||
4478 | } | ||
4479 | return; | ||
4480 | } | ||
4481 | |||
4482 | /* | ||
4483 | * Initialize slot table | ||
4484 | */ | ||
4485 | static int nfs4_init_slot_table(struct nfs4_slot_table *tbl, | ||
4486 | int max_slots, int ivalue) | ||
4487 | { | ||
4488 | int i; | ||
4489 | struct nfs4_slot *slot; | ||
4490 | int ret = -ENOMEM; | ||
4491 | |||
4492 | BUG_ON(max_slots > NFS4_MAX_SLOT_TABLE); | ||
4493 | |||
4494 | dprintk("--> %s: max_reqs=%u\n", __func__, max_slots); | ||
4495 | |||
4496 | slot = kcalloc(max_slots, sizeof(struct nfs4_slot), GFP_KERNEL); | ||
4497 | if (!slot) | ||
4498 | goto out; | ||
4499 | for (i = 0; i < max_slots; ++i) | ||
4500 | slot[i].seq_nr = ivalue; | ||
4501 | ret = 0; | ||
4502 | |||
4503 | spin_lock(&tbl->slot_tbl_lock); | ||
4504 | if (tbl->slots != NULL) { | ||
4505 | spin_unlock(&tbl->slot_tbl_lock); | ||
4506 | dprintk("%s: slot table already initialized. tbl=%p slots=%p\n", | ||
4507 | __func__, tbl, tbl->slots); | ||
4508 | WARN_ON(1); | ||
4509 | goto out_free; | ||
4510 | } | ||
4511 | tbl->max_slots = max_slots; | ||
4512 | tbl->slots = slot; | ||
4513 | tbl->highest_used_slotid = -1; /* no slot is currently used */ | ||
4514 | spin_unlock(&tbl->slot_tbl_lock); | ||
4515 | dprintk("%s: tbl=%p slots=%p max_slots=%d\n", __func__, | ||
4516 | tbl, tbl->slots, tbl->max_slots); | ||
4517 | out: | ||
4518 | dprintk("<-- %s: return %d\n", __func__, ret); | ||
4519 | return ret; | ||
4520 | |||
4521 | out_free: | ||
4522 | kfree(slot); | ||
4523 | goto out; | ||
4524 | } | ||
4525 | |||
4526 | /* | ||
4527 | * Initialize the forechannel and backchannel tables | ||
4528 | */ | ||
4529 | static int nfs4_init_slot_tables(struct nfs4_session *session) | ||
4530 | { | ||
4531 | int status; | ||
4532 | |||
4533 | status = nfs4_init_slot_table(&session->fc_slot_table, | ||
4534 | session->fc_attrs.max_reqs, 1); | ||
4535 | if (status) | ||
4536 | return status; | ||
4537 | |||
4538 | status = nfs4_init_slot_table(&session->bc_slot_table, | ||
4539 | session->bc_attrs.max_reqs, 0); | ||
4540 | if (status) | ||
4541 | nfs4_destroy_slot_tables(session); | ||
4542 | |||
4543 | return status; | ||
4544 | } | ||
4545 | |||
4546 | struct nfs4_session *nfs4_alloc_session(struct nfs_client *clp) | ||
4547 | { | ||
4548 | struct nfs4_session *session; | ||
4549 | struct nfs4_slot_table *tbl; | ||
4550 | |||
4551 | session = kzalloc(sizeof(struct nfs4_session), GFP_KERNEL); | ||
4552 | if (!session) | ||
4553 | return NULL; | ||
4554 | |||
4555 | set_bit(NFS4CLNT_SESSION_SETUP, &clp->cl_state); | ||
4556 | /* | ||
4557 | * The create session reply races with the server back | ||
4558 | * channel probe. Mark the client NFS_CS_SESSION_INITING | ||
4559 | * so that the client back channel can find the | ||
4560 | * nfs_client struct | ||
4561 | */ | ||
4562 | clp->cl_cons_state = NFS_CS_SESSION_INITING; | ||
4563 | |||
4564 | tbl = &session->fc_slot_table; | ||
4565 | spin_lock_init(&tbl->slot_tbl_lock); | ||
4566 | rpc_init_wait_queue(&tbl->slot_tbl_waitq, "ForeChannel Slot table"); | ||
4567 | |||
4568 | tbl = &session->bc_slot_table; | ||
4569 | spin_lock_init(&tbl->slot_tbl_lock); | ||
4570 | rpc_init_wait_queue(&tbl->slot_tbl_waitq, "BackChannel Slot table"); | ||
4571 | |||
4572 | session->clp = clp; | ||
4573 | return session; | ||
4574 | } | ||
4575 | |||
4576 | void nfs4_destroy_session(struct nfs4_session *session) | ||
4577 | { | ||
4578 | nfs4_proc_destroy_session(session); | ||
4579 | dprintk("%s Destroy backchannel for xprt %p\n", | ||
4580 | __func__, session->clp->cl_rpcclient->cl_xprt); | ||
4581 | xprt_destroy_backchannel(session->clp->cl_rpcclient->cl_xprt, | ||
4582 | NFS41_BC_MIN_CALLBACKS); | ||
4583 | nfs4_destroy_slot_tables(session); | ||
4584 | kfree(session); | ||
4585 | } | ||
4586 | |||
4587 | /* | ||
4588 | * Initialize the values to be used by the client in CREATE_SESSION | ||
4589 | * If nfs4_init_session set the fore channel request and response sizes, | ||
4590 | * use them. | ||
4591 | * | ||
4592 | * Set the back channel max_resp_sz_cached to zero to force the client to | ||
4593 | * always set csa_cachethis to FALSE because the current implementation | ||
4594 | * of the back channel DRC only supports caching the CB_SEQUENCE operation. | ||
4595 | */ | ||
4596 | static void nfs4_init_channel_attrs(struct nfs41_create_session_args *args) | ||
4597 | { | ||
4598 | struct nfs4_session *session = args->client->cl_session; | ||
4599 | unsigned int mxrqst_sz = session->fc_attrs.max_rqst_sz, | ||
4600 | mxresp_sz = session->fc_attrs.max_resp_sz; | ||
4601 | |||
4602 | if (mxrqst_sz == 0) | ||
4603 | mxrqst_sz = NFS_MAX_FILE_IO_SIZE; | ||
4604 | if (mxresp_sz == 0) | ||
4605 | mxresp_sz = NFS_MAX_FILE_IO_SIZE; | ||
4606 | /* Fore channel attributes */ | ||
4607 | args->fc_attrs.headerpadsz = 0; | ||
4608 | args->fc_attrs.max_rqst_sz = mxrqst_sz; | ||
4609 | args->fc_attrs.max_resp_sz = mxresp_sz; | ||
4610 | args->fc_attrs.max_resp_sz_cached = mxresp_sz; | ||
4611 | args->fc_attrs.max_ops = NFS4_MAX_OPS; | ||
4612 | args->fc_attrs.max_reqs = session->clp->cl_rpcclient->cl_xprt->max_reqs; | ||
4613 | |||
4614 | dprintk("%s: Fore Channel : max_rqst_sz=%u max_resp_sz=%u " | ||
4615 | "max_resp_sz_cached=%u max_ops=%u max_reqs=%u\n", | ||
4616 | __func__, | ||
4617 | args->fc_attrs.max_rqst_sz, args->fc_attrs.max_resp_sz, | ||
4618 | args->fc_attrs.max_resp_sz_cached, args->fc_attrs.max_ops, | ||
4619 | args->fc_attrs.max_reqs); | ||
4620 | |||
4621 | /* Back channel attributes */ | ||
4622 | args->bc_attrs.headerpadsz = 0; | ||
4623 | args->bc_attrs.max_rqst_sz = PAGE_SIZE; | ||
4624 | args->bc_attrs.max_resp_sz = PAGE_SIZE; | ||
4625 | args->bc_attrs.max_resp_sz_cached = 0; | ||
4626 | args->bc_attrs.max_ops = NFS4_MAX_BACK_CHANNEL_OPS; | ||
4627 | args->bc_attrs.max_reqs = 1; | ||
4628 | |||
4629 | dprintk("%s: Back Channel : max_rqst_sz=%u max_resp_sz=%u " | ||
4630 | "max_resp_sz_cached=%u max_ops=%u max_reqs=%u\n", | ||
4631 | __func__, | ||
4632 | args->bc_attrs.max_rqst_sz, args->bc_attrs.max_resp_sz, | ||
4633 | args->bc_attrs.max_resp_sz_cached, args->bc_attrs.max_ops, | ||
4634 | args->bc_attrs.max_reqs); | ||
4635 | } | ||
4636 | |||
4637 | static int _verify_channel_attr(char *chan, char *attr_name, u32 sent, u32 rcvd) | ||
4638 | { | ||
4639 | if (rcvd <= sent) | ||
4640 | return 0; | ||
4641 | printk(KERN_WARNING "%s: Session INVALID: %s channel %s increased. " | ||
4642 | "sent=%u rcvd=%u\n", __func__, chan, attr_name, sent, rcvd); | ||
4643 | return -EINVAL; | ||
4644 | } | ||
4645 | |||
4646 | #define _verify_fore_channel_attr(_name_) \ | ||
4647 | _verify_channel_attr("fore", #_name_, \ | ||
4648 | args->fc_attrs._name_, \ | ||
4649 | session->fc_attrs._name_) | ||
4650 | |||
4651 | #define _verify_back_channel_attr(_name_) \ | ||
4652 | _verify_channel_attr("back", #_name_, \ | ||
4653 | args->bc_attrs._name_, \ | ||
4654 | session->bc_attrs._name_) | ||
4655 | |||
4656 | /* | ||
4657 | * The server is not allowed to increase the fore channel header pad size, | ||
4658 | * maximum response size, or maximum number of operations. | ||
4659 | * | ||
4660 | * The back channel attributes are only negotiatied down: We send what the | ||
4661 | * (back channel) server insists upon. | ||
4662 | */ | ||
4663 | static int nfs4_verify_channel_attrs(struct nfs41_create_session_args *args, | ||
4664 | struct nfs4_session *session) | ||
4665 | { | ||
4666 | int ret = 0; | ||
4667 | |||
4668 | ret |= _verify_fore_channel_attr(headerpadsz); | ||
4669 | ret |= _verify_fore_channel_attr(max_resp_sz); | ||
4670 | ret |= _verify_fore_channel_attr(max_ops); | ||
4671 | |||
4672 | ret |= _verify_back_channel_attr(headerpadsz); | ||
4673 | ret |= _verify_back_channel_attr(max_rqst_sz); | ||
4674 | ret |= _verify_back_channel_attr(max_resp_sz); | ||
4675 | ret |= _verify_back_channel_attr(max_resp_sz_cached); | ||
4676 | ret |= _verify_back_channel_attr(max_ops); | ||
4677 | ret |= _verify_back_channel_attr(max_reqs); | ||
4678 | |||
4679 | return ret; | ||
4680 | } | ||
4681 | |||
4682 | static int _nfs4_proc_create_session(struct nfs_client *clp) | ||
4683 | { | ||
4684 | struct nfs4_session *session = clp->cl_session; | ||
4685 | struct nfs41_create_session_args args = { | ||
4686 | .client = clp, | ||
4687 | .cb_program = NFS4_CALLBACK, | ||
4688 | }; | ||
4689 | struct nfs41_create_session_res res = { | ||
4690 | .client = clp, | ||
4691 | }; | ||
4692 | struct rpc_message msg = { | ||
4693 | .rpc_proc = &nfs4_procedures[NFSPROC4_CLNT_CREATE_SESSION], | ||
4694 | .rpc_argp = &args, | ||
4695 | .rpc_resp = &res, | ||
4696 | }; | ||
4697 | int status; | ||
4698 | |||
4699 | nfs4_init_channel_attrs(&args); | ||
4700 | args.flags = (SESSION4_PERSIST | SESSION4_BACK_CHAN); | ||
4701 | |||
4702 | status = rpc_call_sync(session->clp->cl_rpcclient, &msg, 0); | ||
4703 | |||
4704 | if (!status) | ||
4705 | /* Verify the session's negotiated channel_attrs values */ | ||
4706 | status = nfs4_verify_channel_attrs(&args, session); | ||
4707 | if (!status) { | ||
4708 | /* Increment the clientid slot sequence id */ | ||
4709 | clp->cl_seqid++; | ||
4710 | } | ||
4711 | |||
4712 | return status; | ||
4713 | } | ||
4714 | |||
4715 | /* | ||
4716 | * Issues a CREATE_SESSION operation to the server. | ||
4717 | * It is the responsibility of the caller to verify the session is | ||
4718 | * expired before calling this routine. | ||
4719 | */ | ||
4720 | int nfs4_proc_create_session(struct nfs_client *clp, int reset) | ||
4721 | { | ||
4722 | int status; | ||
4723 | unsigned *ptr; | ||
4724 | struct nfs_fsinfo fsinfo; | ||
4725 | struct nfs4_session *session = clp->cl_session; | ||
4726 | |||
4727 | dprintk("--> %s clp=%p session=%p\n", __func__, clp, session); | ||
4728 | |||
4729 | status = _nfs4_proc_create_session(clp); | ||
4730 | if (status) | ||
4731 | goto out; | ||
4732 | |||
4733 | /* Init or reset the fore channel */ | ||
4734 | if (reset) | ||
4735 | status = nfs4_reset_slot_tables(session); | ||
4736 | else | ||
4737 | status = nfs4_init_slot_tables(session); | ||
4738 | dprintk("fore channel slot table initialization returned %d\n", status); | ||
4739 | if (status) | ||
4740 | goto out; | ||
4741 | |||
4742 | ptr = (unsigned *)&session->sess_id.data[0]; | ||
4743 | dprintk("%s client>seqid %d sessionid %u:%u:%u:%u\n", __func__, | ||
4744 | clp->cl_seqid, ptr[0], ptr[1], ptr[2], ptr[3]); | ||
4745 | |||
4746 | if (reset) | ||
4747 | /* Lease time is aleady set */ | ||
4748 | goto out; | ||
4749 | |||
4750 | /* Get the lease time */ | ||
4751 | status = nfs4_proc_get_lease_time(clp, &fsinfo); | ||
4752 | if (status == 0) { | ||
4753 | /* Update lease time and schedule renewal */ | ||
4754 | spin_lock(&clp->cl_lock); | ||
4755 | clp->cl_lease_time = fsinfo.lease_time * HZ; | ||
4756 | clp->cl_last_renewal = jiffies; | ||
4757 | clear_bit(NFS4CLNT_LEASE_EXPIRED, &clp->cl_state); | ||
4758 | spin_unlock(&clp->cl_lock); | ||
4759 | |||
4760 | nfs4_schedule_state_renewal(clp); | ||
4761 | } | ||
4762 | out: | ||
4763 | dprintk("<-- %s\n", __func__); | ||
4764 | return status; | ||
4765 | } | ||
4766 | |||
4767 | /* | ||
4768 | * Issue the over-the-wire RPC DESTROY_SESSION. | ||
4769 | * The caller must serialize access to this routine. | ||
4770 | */ | ||
4771 | int nfs4_proc_destroy_session(struct nfs4_session *session) | ||
4772 | { | ||
4773 | int status = 0; | ||
4774 | struct rpc_message msg; | ||
4775 | |||
4776 | dprintk("--> nfs4_proc_destroy_session\n"); | ||
4777 | |||
4778 | /* session is still being setup */ | ||
4779 | if (session->clp->cl_cons_state != NFS_CS_READY) | ||
4780 | return status; | ||
4781 | |||
4782 | msg.rpc_proc = &nfs4_procedures[NFSPROC4_CLNT_DESTROY_SESSION]; | ||
4783 | msg.rpc_argp = session; | ||
4784 | msg.rpc_resp = NULL; | ||
4785 | msg.rpc_cred = NULL; | ||
4786 | status = rpc_call_sync(session->clp->cl_rpcclient, &msg, 0); | ||
4787 | |||
4788 | if (status) | ||
4789 | printk(KERN_WARNING | ||
4790 | "Got error %d from the server on DESTROY_SESSION. " | ||
4791 | "Session has been destroyed regardless...\n", status); | ||
4792 | |||
4793 | dprintk("<-- nfs4_proc_destroy_session\n"); | ||
4794 | return status; | ||
4795 | } | ||
4796 | |||
4797 | /* | ||
4798 | * Renew the cl_session lease. | ||
4799 | */ | ||
4800 | static int nfs4_proc_sequence(struct nfs_client *clp, struct rpc_cred *cred) | ||
4801 | { | ||
4802 | struct nfs4_sequence_args args; | ||
4803 | struct nfs4_sequence_res res; | ||
4804 | |||
4805 | struct rpc_message msg = { | ||
4806 | .rpc_proc = &nfs4_procedures[NFSPROC4_CLNT_SEQUENCE], | ||
4807 | .rpc_argp = &args, | ||
4808 | .rpc_resp = &res, | ||
4809 | .rpc_cred = cred, | ||
4810 | }; | ||
4811 | |||
4812 | args.sa_cache_this = 0; | ||
4813 | |||
4814 | return nfs4_call_sync_sequence(clp, clp->cl_rpcclient, &msg, &args, | ||
4815 | &res, 0); | ||
4816 | } | ||
4817 | |||
4818 | void nfs41_sequence_call_done(struct rpc_task *task, void *data) | ||
4819 | { | ||
4820 | struct nfs_client *clp = (struct nfs_client *)data; | ||
4821 | |||
4822 | nfs41_sequence_done(clp, task->tk_msg.rpc_resp, task->tk_status); | ||
4823 | |||
4824 | if (task->tk_status < 0) { | ||
4825 | dprintk("%s ERROR %d\n", __func__, task->tk_status); | ||
4826 | |||
4827 | if (_nfs4_async_handle_error(task, NULL, clp, NULL) | ||
4828 | == -EAGAIN) { | ||
4829 | nfs4_restart_rpc(task, clp); | ||
4830 | return; | ||
4831 | } | ||
4832 | } | ||
4833 | nfs41_sequence_free_slot(clp, task->tk_msg.rpc_resp); | ||
4834 | dprintk("%s rpc_cred %p\n", __func__, task->tk_msg.rpc_cred); | ||
4835 | |||
4836 | put_rpccred(task->tk_msg.rpc_cred); | ||
4837 | kfree(task->tk_msg.rpc_argp); | ||
4838 | kfree(task->tk_msg.rpc_resp); | ||
4839 | |||
4840 | dprintk("<-- %s\n", __func__); | ||
4841 | } | ||
4842 | |||
4843 | static void nfs41_sequence_prepare(struct rpc_task *task, void *data) | ||
4844 | { | ||
4845 | struct nfs_client *clp; | ||
4846 | struct nfs4_sequence_args *args; | ||
4847 | struct nfs4_sequence_res *res; | ||
4848 | |||
4849 | clp = (struct nfs_client *)data; | ||
4850 | args = task->tk_msg.rpc_argp; | ||
4851 | res = task->tk_msg.rpc_resp; | ||
4852 | |||
4853 | if (nfs4_setup_sequence(clp, args, res, 0, task)) | ||
4854 | return; | ||
4855 | rpc_call_start(task); | ||
4856 | } | ||
4857 | |||
4858 | static const struct rpc_call_ops nfs41_sequence_ops = { | ||
4859 | .rpc_call_done = nfs41_sequence_call_done, | ||
4860 | .rpc_call_prepare = nfs41_sequence_prepare, | ||
4861 | }; | ||
4862 | |||
4863 | static int nfs41_proc_async_sequence(struct nfs_client *clp, | ||
4864 | struct rpc_cred *cred) | ||
4865 | { | ||
4866 | struct nfs4_sequence_args *args; | ||
4867 | struct nfs4_sequence_res *res; | ||
4868 | struct rpc_message msg = { | ||
4869 | .rpc_proc = &nfs4_procedures[NFSPROC4_CLNT_SEQUENCE], | ||
4870 | .rpc_cred = cred, | ||
4871 | }; | ||
4872 | |||
4873 | args = kzalloc(sizeof(*args), GFP_KERNEL); | ||
4874 | if (!args) | ||
4875 | return -ENOMEM; | ||
4876 | res = kzalloc(sizeof(*res), GFP_KERNEL); | ||
4877 | if (!res) { | ||
4878 | kfree(args); | ||
4879 | return -ENOMEM; | ||
4880 | } | ||
4881 | res->sr_slotid = NFS4_MAX_SLOT_TABLE; | ||
4882 | msg.rpc_argp = args; | ||
4883 | msg.rpc_resp = res; | ||
4884 | |||
4885 | return rpc_call_async(clp->cl_rpcclient, &msg, RPC_TASK_SOFT, | ||
4886 | &nfs41_sequence_ops, (void *)clp); | ||
4887 | } | ||
4888 | |||
4889 | #endif /* CONFIG_NFS_V4_1 */ | ||
4890 | |||
4891 | struct nfs4_state_recovery_ops nfs40_reboot_recovery_ops = { | ||
3727 | .owner_flag_bit = NFS_OWNER_RECLAIM_REBOOT, | 4892 | .owner_flag_bit = NFS_OWNER_RECLAIM_REBOOT, |
3728 | .state_flag_bit = NFS_STATE_RECLAIM_REBOOT, | 4893 | .state_flag_bit = NFS_STATE_RECLAIM_REBOOT, |
3729 | .recover_open = nfs4_open_reclaim, | 4894 | .recover_open = nfs4_open_reclaim, |
3730 | .recover_lock = nfs4_lock_reclaim, | 4895 | .recover_lock = nfs4_lock_reclaim, |
4896 | .establish_clid = nfs4_init_clientid, | ||
4897 | .get_clid_cred = nfs4_get_setclientid_cred, | ||
4898 | }; | ||
4899 | |||
4900 | #if defined(CONFIG_NFS_V4_1) | ||
4901 | struct nfs4_state_recovery_ops nfs41_reboot_recovery_ops = { | ||
4902 | .owner_flag_bit = NFS_OWNER_RECLAIM_REBOOT, | ||
4903 | .state_flag_bit = NFS_STATE_RECLAIM_REBOOT, | ||
4904 | .recover_open = nfs4_open_reclaim, | ||
4905 | .recover_lock = nfs4_lock_reclaim, | ||
4906 | .establish_clid = nfs4_proc_exchange_id, | ||
4907 | .get_clid_cred = nfs4_get_exchange_id_cred, | ||
4908 | }; | ||
4909 | #endif /* CONFIG_NFS_V4_1 */ | ||
4910 | |||
4911 | struct nfs4_state_recovery_ops nfs40_nograce_recovery_ops = { | ||
4912 | .owner_flag_bit = NFS_OWNER_RECLAIM_NOGRACE, | ||
4913 | .state_flag_bit = NFS_STATE_RECLAIM_NOGRACE, | ||
4914 | .recover_open = nfs4_open_expired, | ||
4915 | .recover_lock = nfs4_lock_expired, | ||
4916 | .establish_clid = nfs4_init_clientid, | ||
4917 | .get_clid_cred = nfs4_get_setclientid_cred, | ||
3731 | }; | 4918 | }; |
3732 | 4919 | ||
3733 | struct nfs4_state_recovery_ops nfs4_nograce_recovery_ops = { | 4920 | #if defined(CONFIG_NFS_V4_1) |
4921 | struct nfs4_state_recovery_ops nfs41_nograce_recovery_ops = { | ||
3734 | .owner_flag_bit = NFS_OWNER_RECLAIM_NOGRACE, | 4922 | .owner_flag_bit = NFS_OWNER_RECLAIM_NOGRACE, |
3735 | .state_flag_bit = NFS_STATE_RECLAIM_NOGRACE, | 4923 | .state_flag_bit = NFS_STATE_RECLAIM_NOGRACE, |
3736 | .recover_open = nfs4_open_expired, | 4924 | .recover_open = nfs4_open_expired, |
3737 | .recover_lock = nfs4_lock_expired, | 4925 | .recover_lock = nfs4_lock_expired, |
4926 | .establish_clid = nfs4_proc_exchange_id, | ||
4927 | .get_clid_cred = nfs4_get_exchange_id_cred, | ||
4928 | }; | ||
4929 | #endif /* CONFIG_NFS_V4_1 */ | ||
4930 | |||
4931 | struct nfs4_state_maintenance_ops nfs40_state_renewal_ops = { | ||
4932 | .sched_state_renewal = nfs4_proc_async_renew, | ||
4933 | .get_state_renewal_cred_locked = nfs4_get_renew_cred_locked, | ||
4934 | .renew_lease = nfs4_proc_renew, | ||
4935 | }; | ||
4936 | |||
4937 | #if defined(CONFIG_NFS_V4_1) | ||
4938 | struct nfs4_state_maintenance_ops nfs41_state_renewal_ops = { | ||
4939 | .sched_state_renewal = nfs41_proc_async_sequence, | ||
4940 | .get_state_renewal_cred_locked = nfs4_get_machine_cred_locked, | ||
4941 | .renew_lease = nfs4_proc_sequence, | ||
4942 | }; | ||
4943 | #endif | ||
4944 | |||
4945 | /* | ||
4946 | * Per minor version reboot and network partition recovery ops | ||
4947 | */ | ||
4948 | |||
4949 | struct nfs4_state_recovery_ops *nfs4_reboot_recovery_ops[] = { | ||
4950 | &nfs40_reboot_recovery_ops, | ||
4951 | #if defined(CONFIG_NFS_V4_1) | ||
4952 | &nfs41_reboot_recovery_ops, | ||
4953 | #endif | ||
4954 | }; | ||
4955 | |||
4956 | struct nfs4_state_recovery_ops *nfs4_nograce_recovery_ops[] = { | ||
4957 | &nfs40_nograce_recovery_ops, | ||
4958 | #if defined(CONFIG_NFS_V4_1) | ||
4959 | &nfs41_nograce_recovery_ops, | ||
4960 | #endif | ||
4961 | }; | ||
4962 | |||
4963 | struct nfs4_state_maintenance_ops *nfs4_state_renewal_ops[] = { | ||
4964 | &nfs40_state_renewal_ops, | ||
4965 | #if defined(CONFIG_NFS_V4_1) | ||
4966 | &nfs41_state_renewal_ops, | ||
4967 | #endif | ||
3738 | }; | 4968 | }; |
3739 | 4969 | ||
3740 | static const struct inode_operations nfs4_file_inode_operations = { | 4970 | static const struct inode_operations nfs4_file_inode_operations = { |
diff --git a/fs/nfs/nfs4renewd.c b/fs/nfs/nfs4renewd.c index f524e932ff7b..e27c6cef18f2 100644 --- a/fs/nfs/nfs4renewd.c +++ b/fs/nfs/nfs4renewd.c | |||
@@ -59,12 +59,14 @@ | |||
59 | void | 59 | void |
60 | nfs4_renew_state(struct work_struct *work) | 60 | nfs4_renew_state(struct work_struct *work) |
61 | { | 61 | { |
62 | struct nfs4_state_maintenance_ops *ops; | ||
62 | struct nfs_client *clp = | 63 | struct nfs_client *clp = |
63 | container_of(work, struct nfs_client, cl_renewd.work); | 64 | container_of(work, struct nfs_client, cl_renewd.work); |
64 | struct rpc_cred *cred; | 65 | struct rpc_cred *cred; |
65 | long lease, timeout; | 66 | long lease, timeout; |
66 | unsigned long last, now; | 67 | unsigned long last, now; |
67 | 68 | ||
69 | ops = nfs4_state_renewal_ops[clp->cl_minorversion]; | ||
68 | dprintk("%s: start\n", __func__); | 70 | dprintk("%s: start\n", __func__); |
69 | /* Are there any active superblocks? */ | 71 | /* Are there any active superblocks? */ |
70 | if (list_empty(&clp->cl_superblocks)) | 72 | if (list_empty(&clp->cl_superblocks)) |
@@ -76,7 +78,7 @@ nfs4_renew_state(struct work_struct *work) | |||
76 | timeout = (2 * lease) / 3 + (long)last - (long)now; | 78 | timeout = (2 * lease) / 3 + (long)last - (long)now; |
77 | /* Are we close to a lease timeout? */ | 79 | /* Are we close to a lease timeout? */ |
78 | if (time_after(now, last + lease/3)) { | 80 | if (time_after(now, last + lease/3)) { |
79 | cred = nfs4_get_renew_cred_locked(clp); | 81 | cred = ops->get_state_renewal_cred_locked(clp); |
80 | spin_unlock(&clp->cl_lock); | 82 | spin_unlock(&clp->cl_lock); |
81 | if (cred == NULL) { | 83 | if (cred == NULL) { |
82 | if (list_empty(&clp->cl_delegations)) { | 84 | if (list_empty(&clp->cl_delegations)) { |
@@ -86,7 +88,7 @@ nfs4_renew_state(struct work_struct *work) | |||
86 | nfs_expire_all_delegations(clp); | 88 | nfs_expire_all_delegations(clp); |
87 | } else { | 89 | } else { |
88 | /* Queue an asynchronous RENEW. */ | 90 | /* Queue an asynchronous RENEW. */ |
89 | nfs4_proc_async_renew(clp, cred); | 91 | ops->sched_state_renewal(clp, cred); |
90 | put_rpccred(cred); | 92 | put_rpccred(cred); |
91 | } | 93 | } |
92 | timeout = (2 * lease) / 3; | 94 | timeout = (2 * lease) / 3; |
diff --git a/fs/nfs/nfs4state.c b/fs/nfs/nfs4state.c index 0298e909559f..b73c5a728655 100644 --- a/fs/nfs/nfs4state.c +++ b/fs/nfs/nfs4state.c | |||
@@ -60,7 +60,7 @@ const nfs4_stateid zero_stateid; | |||
60 | 60 | ||
61 | static LIST_HEAD(nfs4_clientid_list); | 61 | static LIST_HEAD(nfs4_clientid_list); |
62 | 62 | ||
63 | static int nfs4_init_client(struct nfs_client *clp, struct rpc_cred *cred) | 63 | int nfs4_init_clientid(struct nfs_client *clp, struct rpc_cred *cred) |
64 | { | 64 | { |
65 | unsigned short port; | 65 | unsigned short port; |
66 | int status; | 66 | int status; |
@@ -77,7 +77,7 @@ static int nfs4_init_client(struct nfs_client *clp, struct rpc_cred *cred) | |||
77 | return status; | 77 | return status; |
78 | } | 78 | } |
79 | 79 | ||
80 | static struct rpc_cred *nfs4_get_machine_cred_locked(struct nfs_client *clp) | 80 | struct rpc_cred *nfs4_get_machine_cred_locked(struct nfs_client *clp) |
81 | { | 81 | { |
82 | struct rpc_cred *cred = NULL; | 82 | struct rpc_cred *cred = NULL; |
83 | 83 | ||
@@ -114,17 +114,21 @@ struct rpc_cred *nfs4_get_renew_cred_locked(struct nfs_client *clp) | |||
114 | return cred; | 114 | return cred; |
115 | } | 115 | } |
116 | 116 | ||
117 | static struct rpc_cred *nfs4_get_renew_cred(struct nfs_client *clp) | 117 | #if defined(CONFIG_NFS_V4_1) |
118 | |||
119 | struct rpc_cred *nfs4_get_exchange_id_cred(struct nfs_client *clp) | ||
118 | { | 120 | { |
119 | struct rpc_cred *cred; | 121 | struct rpc_cred *cred; |
120 | 122 | ||
121 | spin_lock(&clp->cl_lock); | 123 | spin_lock(&clp->cl_lock); |
122 | cred = nfs4_get_renew_cred_locked(clp); | 124 | cred = nfs4_get_machine_cred_locked(clp); |
123 | spin_unlock(&clp->cl_lock); | 125 | spin_unlock(&clp->cl_lock); |
124 | return cred; | 126 | return cred; |
125 | } | 127 | } |
126 | 128 | ||
127 | static struct rpc_cred *nfs4_get_setclientid_cred(struct nfs_client *clp) | 129 | #endif /* CONFIG_NFS_V4_1 */ |
130 | |||
131 | struct rpc_cred *nfs4_get_setclientid_cred(struct nfs_client *clp) | ||
128 | { | 132 | { |
129 | struct nfs4_state_owner *sp; | 133 | struct nfs4_state_owner *sp; |
130 | struct rb_node *pos; | 134 | struct rb_node *pos; |
@@ -738,12 +742,14 @@ static void nfs_increment_seqid(int status, struct nfs_seqid *seqid) | |||
738 | 742 | ||
739 | void nfs_increment_open_seqid(int status, struct nfs_seqid *seqid) | 743 | void nfs_increment_open_seqid(int status, struct nfs_seqid *seqid) |
740 | { | 744 | { |
741 | if (status == -NFS4ERR_BAD_SEQID) { | 745 | struct nfs4_state_owner *sp = container_of(seqid->sequence, |
742 | struct nfs4_state_owner *sp = container_of(seqid->sequence, | 746 | struct nfs4_state_owner, so_seqid); |
743 | struct nfs4_state_owner, so_seqid); | 747 | struct nfs_server *server = sp->so_server; |
748 | |||
749 | if (status == -NFS4ERR_BAD_SEQID) | ||
744 | nfs4_drop_state_owner(sp); | 750 | nfs4_drop_state_owner(sp); |
745 | } | 751 | if (!nfs4_has_session(server->nfs_client)) |
746 | nfs_increment_seqid(status, seqid); | 752 | nfs_increment_seqid(status, seqid); |
747 | } | 753 | } |
748 | 754 | ||
749 | /* | 755 | /* |
@@ -847,32 +853,45 @@ static int nfs4_reclaim_locks(struct nfs4_state *state, const struct nfs4_state_ | |||
847 | struct file_lock *fl; | 853 | struct file_lock *fl; |
848 | int status = 0; | 854 | int status = 0; |
849 | 855 | ||
856 | if (inode->i_flock == NULL) | ||
857 | return 0; | ||
858 | |||
859 | /* Guard against delegation returns and new lock/unlock calls */ | ||
850 | down_write(&nfsi->rwsem); | 860 | down_write(&nfsi->rwsem); |
861 | /* Protect inode->i_flock using the BKL */ | ||
862 | lock_kernel(); | ||
851 | for (fl = inode->i_flock; fl != NULL; fl = fl->fl_next) { | 863 | for (fl = inode->i_flock; fl != NULL; fl = fl->fl_next) { |
852 | if (!(fl->fl_flags & (FL_POSIX|FL_FLOCK))) | 864 | if (!(fl->fl_flags & (FL_POSIX|FL_FLOCK))) |
853 | continue; | 865 | continue; |
854 | if (nfs_file_open_context(fl->fl_file)->state != state) | 866 | if (nfs_file_open_context(fl->fl_file)->state != state) |
855 | continue; | 867 | continue; |
868 | unlock_kernel(); | ||
856 | status = ops->recover_lock(state, fl); | 869 | status = ops->recover_lock(state, fl); |
857 | if (status >= 0) | ||
858 | continue; | ||
859 | switch (status) { | 870 | switch (status) { |
871 | case 0: | ||
872 | break; | ||
873 | case -ESTALE: | ||
874 | case -NFS4ERR_ADMIN_REVOKED: | ||
875 | case -NFS4ERR_STALE_STATEID: | ||
876 | case -NFS4ERR_BAD_STATEID: | ||
877 | case -NFS4ERR_EXPIRED: | ||
878 | case -NFS4ERR_NO_GRACE: | ||
879 | case -NFS4ERR_STALE_CLIENTID: | ||
880 | goto out; | ||
860 | default: | 881 | default: |
861 | printk(KERN_ERR "%s: unhandled error %d. Zeroing state\n", | 882 | printk(KERN_ERR "%s: unhandled error %d. Zeroing state\n", |
862 | __func__, status); | 883 | __func__, status); |
863 | case -NFS4ERR_EXPIRED: | 884 | case -ENOMEM: |
864 | case -NFS4ERR_NO_GRACE: | 885 | case -NFS4ERR_DENIED: |
865 | case -NFS4ERR_RECLAIM_BAD: | 886 | case -NFS4ERR_RECLAIM_BAD: |
866 | case -NFS4ERR_RECLAIM_CONFLICT: | 887 | case -NFS4ERR_RECLAIM_CONFLICT: |
867 | /* kill_proc(fl->fl_pid, SIGLOST, 1); */ | 888 | /* kill_proc(fl->fl_pid, SIGLOST, 1); */ |
868 | break; | 889 | status = 0; |
869 | case -NFS4ERR_STALE_CLIENTID: | ||
870 | goto out_err; | ||
871 | } | 890 | } |
891 | lock_kernel(); | ||
872 | } | 892 | } |
873 | up_write(&nfsi->rwsem); | 893 | unlock_kernel(); |
874 | return 0; | 894 | out: |
875 | out_err: | ||
876 | up_write(&nfsi->rwsem); | 895 | up_write(&nfsi->rwsem); |
877 | return status; | 896 | return status; |
878 | } | 897 | } |
@@ -918,6 +937,7 @@ restart: | |||
918 | printk(KERN_ERR "%s: unhandled error %d. Zeroing state\n", | 937 | printk(KERN_ERR "%s: unhandled error %d. Zeroing state\n", |
919 | __func__, status); | 938 | __func__, status); |
920 | case -ENOENT: | 939 | case -ENOENT: |
940 | case -ENOMEM: | ||
921 | case -ESTALE: | 941 | case -ESTALE: |
922 | /* | 942 | /* |
923 | * Open state on this file cannot be recovered | 943 | * Open state on this file cannot be recovered |
@@ -928,6 +948,9 @@ restart: | |||
928 | /* Mark the file as being 'closed' */ | 948 | /* Mark the file as being 'closed' */ |
929 | state->state = 0; | 949 | state->state = 0; |
930 | break; | 950 | break; |
951 | case -NFS4ERR_ADMIN_REVOKED: | ||
952 | case -NFS4ERR_STALE_STATEID: | ||
953 | case -NFS4ERR_BAD_STATEID: | ||
931 | case -NFS4ERR_RECLAIM_BAD: | 954 | case -NFS4ERR_RECLAIM_BAD: |
932 | case -NFS4ERR_RECLAIM_CONFLICT: | 955 | case -NFS4ERR_RECLAIM_CONFLICT: |
933 | nfs4_state_mark_reclaim_nograce(sp->so_client, state); | 956 | nfs4_state_mark_reclaim_nograce(sp->so_client, state); |
@@ -1042,6 +1065,14 @@ static void nfs4_recovery_handle_error(struct nfs_client *clp, int error) | |||
1042 | case -NFS4ERR_EXPIRED: | 1065 | case -NFS4ERR_EXPIRED: |
1043 | set_bit(NFS4CLNT_LEASE_EXPIRED, &clp->cl_state); | 1066 | set_bit(NFS4CLNT_LEASE_EXPIRED, &clp->cl_state); |
1044 | nfs4_state_start_reclaim_nograce(clp); | 1067 | nfs4_state_start_reclaim_nograce(clp); |
1068 | case -NFS4ERR_BADSESSION: | ||
1069 | case -NFS4ERR_BADSLOT: | ||
1070 | case -NFS4ERR_BAD_HIGH_SLOT: | ||
1071 | case -NFS4ERR_DEADSESSION: | ||
1072 | case -NFS4ERR_CONN_NOT_BOUND_TO_SESSION: | ||
1073 | case -NFS4ERR_SEQ_FALSE_RETRY: | ||
1074 | case -NFS4ERR_SEQ_MISORDERED: | ||
1075 | set_bit(NFS4CLNT_SESSION_SETUP, &clp->cl_state); | ||
1045 | } | 1076 | } |
1046 | } | 1077 | } |
1047 | 1078 | ||
@@ -1075,18 +1106,22 @@ restart: | |||
1075 | static int nfs4_check_lease(struct nfs_client *clp) | 1106 | static int nfs4_check_lease(struct nfs_client *clp) |
1076 | { | 1107 | { |
1077 | struct rpc_cred *cred; | 1108 | struct rpc_cred *cred; |
1109 | struct nfs4_state_maintenance_ops *ops = | ||
1110 | nfs4_state_renewal_ops[clp->cl_minorversion]; | ||
1078 | int status = -NFS4ERR_EXPIRED; | 1111 | int status = -NFS4ERR_EXPIRED; |
1079 | 1112 | ||
1080 | /* Is the client already known to have an expired lease? */ | 1113 | /* Is the client already known to have an expired lease? */ |
1081 | if (test_bit(NFS4CLNT_LEASE_EXPIRED, &clp->cl_state)) | 1114 | if (test_bit(NFS4CLNT_LEASE_EXPIRED, &clp->cl_state)) |
1082 | return 0; | 1115 | return 0; |
1083 | cred = nfs4_get_renew_cred(clp); | 1116 | spin_lock(&clp->cl_lock); |
1117 | cred = ops->get_state_renewal_cred_locked(clp); | ||
1118 | spin_unlock(&clp->cl_lock); | ||
1084 | if (cred == NULL) { | 1119 | if (cred == NULL) { |
1085 | cred = nfs4_get_setclientid_cred(clp); | 1120 | cred = nfs4_get_setclientid_cred(clp); |
1086 | if (cred == NULL) | 1121 | if (cred == NULL) |
1087 | goto out; | 1122 | goto out; |
1088 | } | 1123 | } |
1089 | status = nfs4_proc_renew(clp, cred); | 1124 | status = ops->renew_lease(clp, cred); |
1090 | put_rpccred(cred); | 1125 | put_rpccred(cred); |
1091 | out: | 1126 | out: |
1092 | nfs4_recovery_handle_error(clp, status); | 1127 | nfs4_recovery_handle_error(clp, status); |
@@ -1096,21 +1131,98 @@ out: | |||
1096 | static int nfs4_reclaim_lease(struct nfs_client *clp) | 1131 | static int nfs4_reclaim_lease(struct nfs_client *clp) |
1097 | { | 1132 | { |
1098 | struct rpc_cred *cred; | 1133 | struct rpc_cred *cred; |
1134 | struct nfs4_state_recovery_ops *ops = | ||
1135 | nfs4_reboot_recovery_ops[clp->cl_minorversion]; | ||
1099 | int status = -ENOENT; | 1136 | int status = -ENOENT; |
1100 | 1137 | ||
1101 | cred = nfs4_get_setclientid_cred(clp); | 1138 | cred = ops->get_clid_cred(clp); |
1102 | if (cred != NULL) { | 1139 | if (cred != NULL) { |
1103 | status = nfs4_init_client(clp, cred); | 1140 | status = ops->establish_clid(clp, cred); |
1104 | put_rpccred(cred); | 1141 | put_rpccred(cred); |
1105 | /* Handle case where the user hasn't set up machine creds */ | 1142 | /* Handle case where the user hasn't set up machine creds */ |
1106 | if (status == -EACCES && cred == clp->cl_machine_cred) { | 1143 | if (status == -EACCES && cred == clp->cl_machine_cred) { |
1107 | nfs4_clear_machine_cred(clp); | 1144 | nfs4_clear_machine_cred(clp); |
1108 | status = -EAGAIN; | 1145 | status = -EAGAIN; |
1109 | } | 1146 | } |
1147 | if (status == -NFS4ERR_MINOR_VERS_MISMATCH) | ||
1148 | status = -EPROTONOSUPPORT; | ||
1149 | } | ||
1150 | return status; | ||
1151 | } | ||
1152 | |||
1153 | #ifdef CONFIG_NFS_V4_1 | ||
1154 | static void nfs4_session_recovery_handle_error(struct nfs_client *clp, int err) | ||
1155 | { | ||
1156 | switch (err) { | ||
1157 | case -NFS4ERR_STALE_CLIENTID: | ||
1158 | set_bit(NFS4CLNT_LEASE_EXPIRED, &clp->cl_state); | ||
1159 | set_bit(NFS4CLNT_SESSION_SETUP, &clp->cl_state); | ||
1160 | } | ||
1161 | } | ||
1162 | |||
1163 | static int nfs4_reset_session(struct nfs_client *clp) | ||
1164 | { | ||
1165 | int status; | ||
1166 | |||
1167 | status = nfs4_proc_destroy_session(clp->cl_session); | ||
1168 | if (status && status != -NFS4ERR_BADSESSION && | ||
1169 | status != -NFS4ERR_DEADSESSION) { | ||
1170 | nfs4_session_recovery_handle_error(clp, status); | ||
1171 | goto out; | ||
1110 | } | 1172 | } |
1173 | |||
1174 | memset(clp->cl_session->sess_id.data, 0, NFS4_MAX_SESSIONID_LEN); | ||
1175 | status = nfs4_proc_create_session(clp, 1); | ||
1176 | if (status) | ||
1177 | nfs4_session_recovery_handle_error(clp, status); | ||
1178 | /* fall through*/ | ||
1179 | out: | ||
1180 | /* Wake up the next rpc task even on error */ | ||
1181 | rpc_wake_up_next(&clp->cl_session->fc_slot_table.slot_tbl_waitq); | ||
1111 | return status; | 1182 | return status; |
1112 | } | 1183 | } |
1113 | 1184 | ||
1185 | static int nfs4_initialize_session(struct nfs_client *clp) | ||
1186 | { | ||
1187 | int status; | ||
1188 | |||
1189 | status = nfs4_proc_create_session(clp, 0); | ||
1190 | if (!status) { | ||
1191 | nfs_mark_client_ready(clp, NFS_CS_READY); | ||
1192 | } else if (status == -NFS4ERR_STALE_CLIENTID) { | ||
1193 | set_bit(NFS4CLNT_LEASE_EXPIRED, &clp->cl_state); | ||
1194 | set_bit(NFS4CLNT_SESSION_SETUP, &clp->cl_state); | ||
1195 | } else { | ||
1196 | nfs_mark_client_ready(clp, status); | ||
1197 | } | ||
1198 | return status; | ||
1199 | } | ||
1200 | #else /* CONFIG_NFS_V4_1 */ | ||
1201 | static int nfs4_reset_session(struct nfs_client *clp) { return 0; } | ||
1202 | static int nfs4_initialize_session(struct nfs_client *clp) { return 0; } | ||
1203 | #endif /* CONFIG_NFS_V4_1 */ | ||
1204 | |||
1205 | /* Set NFS4CLNT_LEASE_EXPIRED for all v4.0 errors and for recoverable errors | ||
1206 | * on EXCHANGE_ID for v4.1 | ||
1207 | */ | ||
1208 | static void nfs4_set_lease_expired(struct nfs_client *clp, int status) | ||
1209 | { | ||
1210 | if (nfs4_has_session(clp)) { | ||
1211 | switch (status) { | ||
1212 | case -NFS4ERR_DELAY: | ||
1213 | case -NFS4ERR_CLID_INUSE: | ||
1214 | case -EAGAIN: | ||
1215 | break; | ||
1216 | |||
1217 | case -NFS4ERR_NOT_SAME: /* FixMe: implement recovery | ||
1218 | * in nfs4_exchange_id */ | ||
1219 | default: | ||
1220 | return; | ||
1221 | } | ||
1222 | } | ||
1223 | set_bit(NFS4CLNT_LEASE_EXPIRED, &clp->cl_state); | ||
1224 | } | ||
1225 | |||
1114 | static void nfs4_state_manager(struct nfs_client *clp) | 1226 | static void nfs4_state_manager(struct nfs_client *clp) |
1115 | { | 1227 | { |
1116 | int status = 0; | 1228 | int status = 0; |
@@ -1121,9 +1233,12 @@ static void nfs4_state_manager(struct nfs_client *clp) | |||
1121 | /* We're going to have to re-establish a clientid */ | 1233 | /* We're going to have to re-establish a clientid */ |
1122 | status = nfs4_reclaim_lease(clp); | 1234 | status = nfs4_reclaim_lease(clp); |
1123 | if (status) { | 1235 | if (status) { |
1124 | set_bit(NFS4CLNT_LEASE_EXPIRED, &clp->cl_state); | 1236 | nfs4_set_lease_expired(clp, status); |
1125 | if (status == -EAGAIN) | 1237 | if (status == -EAGAIN) |
1126 | continue; | 1238 | continue; |
1239 | if (clp->cl_cons_state == | ||
1240 | NFS_CS_SESSION_INITING) | ||
1241 | nfs_mark_client_ready(clp, status); | ||
1127 | goto out_error; | 1242 | goto out_error; |
1128 | } | 1243 | } |
1129 | clear_bit(NFS4CLNT_CHECK_LEASE, &clp->cl_state); | 1244 | clear_bit(NFS4CLNT_CHECK_LEASE, &clp->cl_state); |
@@ -1134,25 +1249,44 @@ static void nfs4_state_manager(struct nfs_client *clp) | |||
1134 | if (status != 0) | 1249 | if (status != 0) |
1135 | continue; | 1250 | continue; |
1136 | } | 1251 | } |
1137 | 1252 | /* Initialize or reset the session */ | |
1253 | if (nfs4_has_session(clp) && | ||
1254 | test_and_clear_bit(NFS4CLNT_SESSION_SETUP, &clp->cl_state)) { | ||
1255 | if (clp->cl_cons_state == NFS_CS_SESSION_INITING) | ||
1256 | status = nfs4_initialize_session(clp); | ||
1257 | else | ||
1258 | status = nfs4_reset_session(clp); | ||
1259 | if (status) { | ||
1260 | if (status == -NFS4ERR_STALE_CLIENTID) | ||
1261 | continue; | ||
1262 | goto out_error; | ||
1263 | } | ||
1264 | } | ||
1138 | /* First recover reboot state... */ | 1265 | /* First recover reboot state... */ |
1139 | if (test_and_clear_bit(NFS4CLNT_RECLAIM_REBOOT, &clp->cl_state)) { | 1266 | if (test_and_clear_bit(NFS4CLNT_RECLAIM_REBOOT, &clp->cl_state)) { |
1140 | status = nfs4_do_reclaim(clp, &nfs4_reboot_recovery_ops); | 1267 | status = nfs4_do_reclaim(clp, |
1268 | nfs4_reboot_recovery_ops[clp->cl_minorversion]); | ||
1141 | if (status == -NFS4ERR_STALE_CLIENTID) | 1269 | if (status == -NFS4ERR_STALE_CLIENTID) |
1142 | continue; | 1270 | continue; |
1271 | if (test_bit(NFS4CLNT_SESSION_SETUP, &clp->cl_state)) | ||
1272 | continue; | ||
1143 | nfs4_state_end_reclaim_reboot(clp); | 1273 | nfs4_state_end_reclaim_reboot(clp); |
1144 | continue; | 1274 | continue; |
1145 | } | 1275 | } |
1146 | 1276 | ||
1147 | /* Now recover expired state... */ | 1277 | /* Now recover expired state... */ |
1148 | if (test_and_clear_bit(NFS4CLNT_RECLAIM_NOGRACE, &clp->cl_state)) { | 1278 | if (test_and_clear_bit(NFS4CLNT_RECLAIM_NOGRACE, &clp->cl_state)) { |
1149 | status = nfs4_do_reclaim(clp, &nfs4_nograce_recovery_ops); | 1279 | status = nfs4_do_reclaim(clp, |
1280 | nfs4_nograce_recovery_ops[clp->cl_minorversion]); | ||
1150 | if (status < 0) { | 1281 | if (status < 0) { |
1151 | set_bit(NFS4CLNT_RECLAIM_NOGRACE, &clp->cl_state); | 1282 | set_bit(NFS4CLNT_RECLAIM_NOGRACE, &clp->cl_state); |
1152 | if (status == -NFS4ERR_STALE_CLIENTID) | 1283 | if (status == -NFS4ERR_STALE_CLIENTID) |
1153 | continue; | 1284 | continue; |
1154 | if (status == -NFS4ERR_EXPIRED) | 1285 | if (status == -NFS4ERR_EXPIRED) |
1155 | continue; | 1286 | continue; |
1287 | if (test_bit(NFS4CLNT_SESSION_SETUP, | ||
1288 | &clp->cl_state)) | ||
1289 | continue; | ||
1156 | goto out_error; | 1290 | goto out_error; |
1157 | } else | 1291 | } else |
1158 | nfs4_state_end_reclaim_nograce(clp); | 1292 | nfs4_state_end_reclaim_nograce(clp); |
diff --git a/fs/nfs/nfs4xdr.c b/fs/nfs/nfs4xdr.c index 1690f0e44b91..617273e7d47f 100644 --- a/fs/nfs/nfs4xdr.c +++ b/fs/nfs/nfs4xdr.c | |||
@@ -192,12 +192,16 @@ static int nfs4_stat_to_errno(int); | |||
192 | decode_verifier_maxsz) | 192 | decode_verifier_maxsz) |
193 | #define encode_remove_maxsz (op_encode_hdr_maxsz + \ | 193 | #define encode_remove_maxsz (op_encode_hdr_maxsz + \ |
194 | nfs4_name_maxsz) | 194 | nfs4_name_maxsz) |
195 | #define decode_remove_maxsz (op_decode_hdr_maxsz + \ | ||
196 | decode_change_info_maxsz) | ||
195 | #define encode_rename_maxsz (op_encode_hdr_maxsz + \ | 197 | #define encode_rename_maxsz (op_encode_hdr_maxsz + \ |
196 | 2 * nfs4_name_maxsz) | 198 | 2 * nfs4_name_maxsz) |
197 | #define decode_rename_maxsz (op_decode_hdr_maxsz + 5 + 5) | 199 | #define decode_rename_maxsz (op_decode_hdr_maxsz + \ |
200 | decode_change_info_maxsz + \ | ||
201 | decode_change_info_maxsz) | ||
198 | #define encode_link_maxsz (op_encode_hdr_maxsz + \ | 202 | #define encode_link_maxsz (op_encode_hdr_maxsz + \ |
199 | nfs4_name_maxsz) | 203 | nfs4_name_maxsz) |
200 | #define decode_link_maxsz (op_decode_hdr_maxsz + 5) | 204 | #define decode_link_maxsz (op_decode_hdr_maxsz + decode_change_info_maxsz) |
201 | #define encode_lock_maxsz (op_encode_hdr_maxsz + \ | 205 | #define encode_lock_maxsz (op_encode_hdr_maxsz + \ |
202 | 7 + \ | 206 | 7 + \ |
203 | 1 + encode_stateid_maxsz + 8) | 207 | 1 + encode_stateid_maxsz + 8) |
@@ -240,43 +244,115 @@ static int nfs4_stat_to_errno(int); | |||
240 | (encode_getattr_maxsz) | 244 | (encode_getattr_maxsz) |
241 | #define decode_fs_locations_maxsz \ | 245 | #define decode_fs_locations_maxsz \ |
242 | (0) | 246 | (0) |
247 | |||
248 | #if defined(CONFIG_NFS_V4_1) | ||
249 | #define NFS4_MAX_MACHINE_NAME_LEN (64) | ||
250 | |||
251 | #define encode_exchange_id_maxsz (op_encode_hdr_maxsz + \ | ||
252 | encode_verifier_maxsz + \ | ||
253 | 1 /* co_ownerid.len */ + \ | ||
254 | XDR_QUADLEN(NFS4_EXCHANGE_ID_LEN) + \ | ||
255 | 1 /* flags */ + \ | ||
256 | 1 /* spa_how */ + \ | ||
257 | 0 /* SP4_NONE (for now) */ + \ | ||
258 | 1 /* zero implemetation id array */) | ||
259 | #define decode_exchange_id_maxsz (op_decode_hdr_maxsz + \ | ||
260 | 2 /* eir_clientid */ + \ | ||
261 | 1 /* eir_sequenceid */ + \ | ||
262 | 1 /* eir_flags */ + \ | ||
263 | 1 /* spr_how */ + \ | ||
264 | 0 /* SP4_NONE (for now) */ + \ | ||
265 | 2 /* eir_server_owner.so_minor_id */ + \ | ||
266 | /* eir_server_owner.so_major_id<> */ \ | ||
267 | XDR_QUADLEN(NFS4_OPAQUE_LIMIT) + 1 + \ | ||
268 | /* eir_server_scope<> */ \ | ||
269 | XDR_QUADLEN(NFS4_OPAQUE_LIMIT) + 1 + \ | ||
270 | 1 /* eir_server_impl_id array length */ + \ | ||
271 | 0 /* ignored eir_server_impl_id contents */) | ||
272 | #define encode_channel_attrs_maxsz (6 + 1 /* ca_rdma_ird.len (0) */) | ||
273 | #define decode_channel_attrs_maxsz (6 + \ | ||
274 | 1 /* ca_rdma_ird.len */ + \ | ||
275 | 1 /* ca_rdma_ird */) | ||
276 | #define encode_create_session_maxsz (op_encode_hdr_maxsz + \ | ||
277 | 2 /* csa_clientid */ + \ | ||
278 | 1 /* csa_sequence */ + \ | ||
279 | 1 /* csa_flags */ + \ | ||
280 | encode_channel_attrs_maxsz + \ | ||
281 | encode_channel_attrs_maxsz + \ | ||
282 | 1 /* csa_cb_program */ + \ | ||
283 | 1 /* csa_sec_parms.len (1) */ + \ | ||
284 | 1 /* cb_secflavor (AUTH_SYS) */ + \ | ||
285 | 1 /* stamp */ + \ | ||
286 | 1 /* machinename.len */ + \ | ||
287 | XDR_QUADLEN(NFS4_MAX_MACHINE_NAME_LEN) + \ | ||
288 | 1 /* uid */ + \ | ||
289 | 1 /* gid */ + \ | ||
290 | 1 /* gids.len (0) */) | ||
291 | #define decode_create_session_maxsz (op_decode_hdr_maxsz + \ | ||
292 | XDR_QUADLEN(NFS4_MAX_SESSIONID_LEN) + \ | ||
293 | 1 /* csr_sequence */ + \ | ||
294 | 1 /* csr_flags */ + \ | ||
295 | decode_channel_attrs_maxsz + \ | ||
296 | decode_channel_attrs_maxsz) | ||
297 | #define encode_destroy_session_maxsz (op_encode_hdr_maxsz + 4) | ||
298 | #define decode_destroy_session_maxsz (op_decode_hdr_maxsz) | ||
299 | #define encode_sequence_maxsz (op_encode_hdr_maxsz + \ | ||
300 | XDR_QUADLEN(NFS4_MAX_SESSIONID_LEN) + 4) | ||
301 | #define decode_sequence_maxsz (op_decode_hdr_maxsz + \ | ||
302 | XDR_QUADLEN(NFS4_MAX_SESSIONID_LEN) + 5) | ||
303 | #else /* CONFIG_NFS_V4_1 */ | ||
304 | #define encode_sequence_maxsz 0 | ||
305 | #define decode_sequence_maxsz 0 | ||
306 | #endif /* CONFIG_NFS_V4_1 */ | ||
307 | |||
243 | #define NFS4_enc_compound_sz (1024) /* XXX: large enough? */ | 308 | #define NFS4_enc_compound_sz (1024) /* XXX: large enough? */ |
244 | #define NFS4_dec_compound_sz (1024) /* XXX: large enough? */ | 309 | #define NFS4_dec_compound_sz (1024) /* XXX: large enough? */ |
245 | #define NFS4_enc_read_sz (compound_encode_hdr_maxsz + \ | 310 | #define NFS4_enc_read_sz (compound_encode_hdr_maxsz + \ |
311 | encode_sequence_maxsz + \ | ||
246 | encode_putfh_maxsz + \ | 312 | encode_putfh_maxsz + \ |
247 | encode_read_maxsz) | 313 | encode_read_maxsz) |
248 | #define NFS4_dec_read_sz (compound_decode_hdr_maxsz + \ | 314 | #define NFS4_dec_read_sz (compound_decode_hdr_maxsz + \ |
315 | decode_sequence_maxsz + \ | ||
249 | decode_putfh_maxsz + \ | 316 | decode_putfh_maxsz + \ |
250 | decode_read_maxsz) | 317 | decode_read_maxsz) |
251 | #define NFS4_enc_readlink_sz (compound_encode_hdr_maxsz + \ | 318 | #define NFS4_enc_readlink_sz (compound_encode_hdr_maxsz + \ |
319 | encode_sequence_maxsz + \ | ||
252 | encode_putfh_maxsz + \ | 320 | encode_putfh_maxsz + \ |
253 | encode_readlink_maxsz) | 321 | encode_readlink_maxsz) |
254 | #define NFS4_dec_readlink_sz (compound_decode_hdr_maxsz + \ | 322 | #define NFS4_dec_readlink_sz (compound_decode_hdr_maxsz + \ |
323 | decode_sequence_maxsz + \ | ||
255 | decode_putfh_maxsz + \ | 324 | decode_putfh_maxsz + \ |
256 | decode_readlink_maxsz) | 325 | decode_readlink_maxsz) |
257 | #define NFS4_enc_readdir_sz (compound_encode_hdr_maxsz + \ | 326 | #define NFS4_enc_readdir_sz (compound_encode_hdr_maxsz + \ |
327 | encode_sequence_maxsz + \ | ||
258 | encode_putfh_maxsz + \ | 328 | encode_putfh_maxsz + \ |
259 | encode_readdir_maxsz) | 329 | encode_readdir_maxsz) |
260 | #define NFS4_dec_readdir_sz (compound_decode_hdr_maxsz + \ | 330 | #define NFS4_dec_readdir_sz (compound_decode_hdr_maxsz + \ |
331 | decode_sequence_maxsz + \ | ||
261 | decode_putfh_maxsz + \ | 332 | decode_putfh_maxsz + \ |
262 | decode_readdir_maxsz) | 333 | decode_readdir_maxsz) |
263 | #define NFS4_enc_write_sz (compound_encode_hdr_maxsz + \ | 334 | #define NFS4_enc_write_sz (compound_encode_hdr_maxsz + \ |
335 | encode_sequence_maxsz + \ | ||
264 | encode_putfh_maxsz + \ | 336 | encode_putfh_maxsz + \ |
265 | encode_write_maxsz + \ | 337 | encode_write_maxsz + \ |
266 | encode_getattr_maxsz) | 338 | encode_getattr_maxsz) |
267 | #define NFS4_dec_write_sz (compound_decode_hdr_maxsz + \ | 339 | #define NFS4_dec_write_sz (compound_decode_hdr_maxsz + \ |
340 | decode_sequence_maxsz + \ | ||
268 | decode_putfh_maxsz + \ | 341 | decode_putfh_maxsz + \ |
269 | decode_write_maxsz + \ | 342 | decode_write_maxsz + \ |
270 | decode_getattr_maxsz) | 343 | decode_getattr_maxsz) |
271 | #define NFS4_enc_commit_sz (compound_encode_hdr_maxsz + \ | 344 | #define NFS4_enc_commit_sz (compound_encode_hdr_maxsz + \ |
345 | encode_sequence_maxsz + \ | ||
272 | encode_putfh_maxsz + \ | 346 | encode_putfh_maxsz + \ |
273 | encode_commit_maxsz + \ | 347 | encode_commit_maxsz + \ |
274 | encode_getattr_maxsz) | 348 | encode_getattr_maxsz) |
275 | #define NFS4_dec_commit_sz (compound_decode_hdr_maxsz + \ | 349 | #define NFS4_dec_commit_sz (compound_decode_hdr_maxsz + \ |
350 | decode_sequence_maxsz + \ | ||
276 | decode_putfh_maxsz + \ | 351 | decode_putfh_maxsz + \ |
277 | decode_commit_maxsz + \ | 352 | decode_commit_maxsz + \ |
278 | decode_getattr_maxsz) | 353 | decode_getattr_maxsz) |
279 | #define NFS4_enc_open_sz (compound_encode_hdr_maxsz + \ | 354 | #define NFS4_enc_open_sz (compound_encode_hdr_maxsz + \ |
355 | encode_sequence_maxsz + \ | ||
280 | encode_putfh_maxsz + \ | 356 | encode_putfh_maxsz + \ |
281 | encode_savefh_maxsz + \ | 357 | encode_savefh_maxsz + \ |
282 | encode_open_maxsz + \ | 358 | encode_open_maxsz + \ |
@@ -285,6 +361,7 @@ static int nfs4_stat_to_errno(int); | |||
285 | encode_restorefh_maxsz + \ | 361 | encode_restorefh_maxsz + \ |
286 | encode_getattr_maxsz) | 362 | encode_getattr_maxsz) |
287 | #define NFS4_dec_open_sz (compound_decode_hdr_maxsz + \ | 363 | #define NFS4_dec_open_sz (compound_decode_hdr_maxsz + \ |
364 | decode_sequence_maxsz + \ | ||
288 | decode_putfh_maxsz + \ | 365 | decode_putfh_maxsz + \ |
289 | decode_savefh_maxsz + \ | 366 | decode_savefh_maxsz + \ |
290 | decode_open_maxsz + \ | 367 | decode_open_maxsz + \ |
@@ -301,43 +378,53 @@ static int nfs4_stat_to_errno(int); | |||
301 | decode_putfh_maxsz + \ | 378 | decode_putfh_maxsz + \ |
302 | decode_open_confirm_maxsz) | 379 | decode_open_confirm_maxsz) |
303 | #define NFS4_enc_open_noattr_sz (compound_encode_hdr_maxsz + \ | 380 | #define NFS4_enc_open_noattr_sz (compound_encode_hdr_maxsz + \ |
381 | encode_sequence_maxsz + \ | ||
304 | encode_putfh_maxsz + \ | 382 | encode_putfh_maxsz + \ |
305 | encode_open_maxsz + \ | 383 | encode_open_maxsz + \ |
306 | encode_getattr_maxsz) | 384 | encode_getattr_maxsz) |
307 | #define NFS4_dec_open_noattr_sz (compound_decode_hdr_maxsz + \ | 385 | #define NFS4_dec_open_noattr_sz (compound_decode_hdr_maxsz + \ |
386 | decode_sequence_maxsz + \ | ||
308 | decode_putfh_maxsz + \ | 387 | decode_putfh_maxsz + \ |
309 | decode_open_maxsz + \ | 388 | decode_open_maxsz + \ |
310 | decode_getattr_maxsz) | 389 | decode_getattr_maxsz) |
311 | #define NFS4_enc_open_downgrade_sz \ | 390 | #define NFS4_enc_open_downgrade_sz \ |
312 | (compound_encode_hdr_maxsz + \ | 391 | (compound_encode_hdr_maxsz + \ |
392 | encode_sequence_maxsz + \ | ||
313 | encode_putfh_maxsz + \ | 393 | encode_putfh_maxsz + \ |
314 | encode_open_downgrade_maxsz + \ | 394 | encode_open_downgrade_maxsz + \ |
315 | encode_getattr_maxsz) | 395 | encode_getattr_maxsz) |
316 | #define NFS4_dec_open_downgrade_sz \ | 396 | #define NFS4_dec_open_downgrade_sz \ |
317 | (compound_decode_hdr_maxsz + \ | 397 | (compound_decode_hdr_maxsz + \ |
398 | decode_sequence_maxsz + \ | ||
318 | decode_putfh_maxsz + \ | 399 | decode_putfh_maxsz + \ |
319 | decode_open_downgrade_maxsz + \ | 400 | decode_open_downgrade_maxsz + \ |
320 | decode_getattr_maxsz) | 401 | decode_getattr_maxsz) |
321 | #define NFS4_enc_close_sz (compound_encode_hdr_maxsz + \ | 402 | #define NFS4_enc_close_sz (compound_encode_hdr_maxsz + \ |
403 | encode_sequence_maxsz + \ | ||
322 | encode_putfh_maxsz + \ | 404 | encode_putfh_maxsz + \ |
323 | encode_close_maxsz + \ | 405 | encode_close_maxsz + \ |
324 | encode_getattr_maxsz) | 406 | encode_getattr_maxsz) |
325 | #define NFS4_dec_close_sz (compound_decode_hdr_maxsz + \ | 407 | #define NFS4_dec_close_sz (compound_decode_hdr_maxsz + \ |
408 | decode_sequence_maxsz + \ | ||
326 | decode_putfh_maxsz + \ | 409 | decode_putfh_maxsz + \ |
327 | decode_close_maxsz + \ | 410 | decode_close_maxsz + \ |
328 | decode_getattr_maxsz) | 411 | decode_getattr_maxsz) |
329 | #define NFS4_enc_setattr_sz (compound_encode_hdr_maxsz + \ | 412 | #define NFS4_enc_setattr_sz (compound_encode_hdr_maxsz + \ |
413 | encode_sequence_maxsz + \ | ||
330 | encode_putfh_maxsz + \ | 414 | encode_putfh_maxsz + \ |
331 | encode_setattr_maxsz + \ | 415 | encode_setattr_maxsz + \ |
332 | encode_getattr_maxsz) | 416 | encode_getattr_maxsz) |
333 | #define NFS4_dec_setattr_sz (compound_decode_hdr_maxsz + \ | 417 | #define NFS4_dec_setattr_sz (compound_decode_hdr_maxsz + \ |
418 | decode_sequence_maxsz + \ | ||
334 | decode_putfh_maxsz + \ | 419 | decode_putfh_maxsz + \ |
335 | decode_setattr_maxsz + \ | 420 | decode_setattr_maxsz + \ |
336 | decode_getattr_maxsz) | 421 | decode_getattr_maxsz) |
337 | #define NFS4_enc_fsinfo_sz (compound_encode_hdr_maxsz + \ | 422 | #define NFS4_enc_fsinfo_sz (compound_encode_hdr_maxsz + \ |
423 | encode_sequence_maxsz + \ | ||
338 | encode_putfh_maxsz + \ | 424 | encode_putfh_maxsz + \ |
339 | encode_fsinfo_maxsz) | 425 | encode_fsinfo_maxsz) |
340 | #define NFS4_dec_fsinfo_sz (compound_decode_hdr_maxsz + \ | 426 | #define NFS4_dec_fsinfo_sz (compound_decode_hdr_maxsz + \ |
427 | decode_sequence_maxsz + \ | ||
341 | decode_putfh_maxsz + \ | 428 | decode_putfh_maxsz + \ |
342 | decode_fsinfo_maxsz) | 429 | decode_fsinfo_maxsz) |
343 | #define NFS4_enc_renew_sz (compound_encode_hdr_maxsz + \ | 430 | #define NFS4_enc_renew_sz (compound_encode_hdr_maxsz + \ |
@@ -359,64 +446,81 @@ static int nfs4_stat_to_errno(int); | |||
359 | decode_putrootfh_maxsz + \ | 446 | decode_putrootfh_maxsz + \ |
360 | decode_fsinfo_maxsz) | 447 | decode_fsinfo_maxsz) |
361 | #define NFS4_enc_lock_sz (compound_encode_hdr_maxsz + \ | 448 | #define NFS4_enc_lock_sz (compound_encode_hdr_maxsz + \ |
449 | encode_sequence_maxsz + \ | ||
362 | encode_putfh_maxsz + \ | 450 | encode_putfh_maxsz + \ |
363 | encode_lock_maxsz) | 451 | encode_lock_maxsz) |
364 | #define NFS4_dec_lock_sz (compound_decode_hdr_maxsz + \ | 452 | #define NFS4_dec_lock_sz (compound_decode_hdr_maxsz + \ |
453 | decode_sequence_maxsz + \ | ||
365 | decode_putfh_maxsz + \ | 454 | decode_putfh_maxsz + \ |
366 | decode_lock_maxsz) | 455 | decode_lock_maxsz) |
367 | #define NFS4_enc_lockt_sz (compound_encode_hdr_maxsz + \ | 456 | #define NFS4_enc_lockt_sz (compound_encode_hdr_maxsz + \ |
457 | encode_sequence_maxsz + \ | ||
368 | encode_putfh_maxsz + \ | 458 | encode_putfh_maxsz + \ |
369 | encode_lockt_maxsz) | 459 | encode_lockt_maxsz) |
370 | #define NFS4_dec_lockt_sz (compound_decode_hdr_maxsz + \ | 460 | #define NFS4_dec_lockt_sz (compound_decode_hdr_maxsz + \ |
461 | decode_sequence_maxsz + \ | ||
371 | decode_putfh_maxsz + \ | 462 | decode_putfh_maxsz + \ |
372 | decode_lockt_maxsz) | 463 | decode_lockt_maxsz) |
373 | #define NFS4_enc_locku_sz (compound_encode_hdr_maxsz + \ | 464 | #define NFS4_enc_locku_sz (compound_encode_hdr_maxsz + \ |
465 | encode_sequence_maxsz + \ | ||
374 | encode_putfh_maxsz + \ | 466 | encode_putfh_maxsz + \ |
375 | encode_locku_maxsz) | 467 | encode_locku_maxsz) |
376 | #define NFS4_dec_locku_sz (compound_decode_hdr_maxsz + \ | 468 | #define NFS4_dec_locku_sz (compound_decode_hdr_maxsz + \ |
469 | decode_sequence_maxsz + \ | ||
377 | decode_putfh_maxsz + \ | 470 | decode_putfh_maxsz + \ |
378 | decode_locku_maxsz) | 471 | decode_locku_maxsz) |
379 | #define NFS4_enc_access_sz (compound_encode_hdr_maxsz + \ | 472 | #define NFS4_enc_access_sz (compound_encode_hdr_maxsz + \ |
473 | encode_sequence_maxsz + \ | ||
380 | encode_putfh_maxsz + \ | 474 | encode_putfh_maxsz + \ |
381 | encode_access_maxsz + \ | 475 | encode_access_maxsz + \ |
382 | encode_getattr_maxsz) | 476 | encode_getattr_maxsz) |
383 | #define NFS4_dec_access_sz (compound_decode_hdr_maxsz + \ | 477 | #define NFS4_dec_access_sz (compound_decode_hdr_maxsz + \ |
478 | decode_sequence_maxsz + \ | ||
384 | decode_putfh_maxsz + \ | 479 | decode_putfh_maxsz + \ |
385 | decode_access_maxsz + \ | 480 | decode_access_maxsz + \ |
386 | decode_getattr_maxsz) | 481 | decode_getattr_maxsz) |
387 | #define NFS4_enc_getattr_sz (compound_encode_hdr_maxsz + \ | 482 | #define NFS4_enc_getattr_sz (compound_encode_hdr_maxsz + \ |
483 | encode_sequence_maxsz + \ | ||
388 | encode_putfh_maxsz + \ | 484 | encode_putfh_maxsz + \ |
389 | encode_getattr_maxsz) | 485 | encode_getattr_maxsz) |
390 | #define NFS4_dec_getattr_sz (compound_decode_hdr_maxsz + \ | 486 | #define NFS4_dec_getattr_sz (compound_decode_hdr_maxsz + \ |
487 | decode_sequence_maxsz + \ | ||
391 | decode_putfh_maxsz + \ | 488 | decode_putfh_maxsz + \ |
392 | decode_getattr_maxsz) | 489 | decode_getattr_maxsz) |
393 | #define NFS4_enc_lookup_sz (compound_encode_hdr_maxsz + \ | 490 | #define NFS4_enc_lookup_sz (compound_encode_hdr_maxsz + \ |
491 | encode_sequence_maxsz + \ | ||
394 | encode_putfh_maxsz + \ | 492 | encode_putfh_maxsz + \ |
395 | encode_lookup_maxsz + \ | 493 | encode_lookup_maxsz + \ |
396 | encode_getattr_maxsz + \ | 494 | encode_getattr_maxsz + \ |
397 | encode_getfh_maxsz) | 495 | encode_getfh_maxsz) |
398 | #define NFS4_dec_lookup_sz (compound_decode_hdr_maxsz + \ | 496 | #define NFS4_dec_lookup_sz (compound_decode_hdr_maxsz + \ |
497 | decode_sequence_maxsz + \ | ||
399 | decode_putfh_maxsz + \ | 498 | decode_putfh_maxsz + \ |
400 | decode_lookup_maxsz + \ | 499 | decode_lookup_maxsz + \ |
401 | decode_getattr_maxsz + \ | 500 | decode_getattr_maxsz + \ |
402 | decode_getfh_maxsz) | 501 | decode_getfh_maxsz) |
403 | #define NFS4_enc_lookup_root_sz (compound_encode_hdr_maxsz + \ | 502 | #define NFS4_enc_lookup_root_sz (compound_encode_hdr_maxsz + \ |
503 | encode_sequence_maxsz + \ | ||
404 | encode_putrootfh_maxsz + \ | 504 | encode_putrootfh_maxsz + \ |
405 | encode_getattr_maxsz + \ | 505 | encode_getattr_maxsz + \ |
406 | encode_getfh_maxsz) | 506 | encode_getfh_maxsz) |
407 | #define NFS4_dec_lookup_root_sz (compound_decode_hdr_maxsz + \ | 507 | #define NFS4_dec_lookup_root_sz (compound_decode_hdr_maxsz + \ |
508 | decode_sequence_maxsz + \ | ||
408 | decode_putrootfh_maxsz + \ | 509 | decode_putrootfh_maxsz + \ |
409 | decode_getattr_maxsz + \ | 510 | decode_getattr_maxsz + \ |
410 | decode_getfh_maxsz) | 511 | decode_getfh_maxsz) |
411 | #define NFS4_enc_remove_sz (compound_encode_hdr_maxsz + \ | 512 | #define NFS4_enc_remove_sz (compound_encode_hdr_maxsz + \ |
513 | encode_sequence_maxsz + \ | ||
412 | encode_putfh_maxsz + \ | 514 | encode_putfh_maxsz + \ |
413 | encode_remove_maxsz + \ | 515 | encode_remove_maxsz + \ |
414 | encode_getattr_maxsz) | 516 | encode_getattr_maxsz) |
415 | #define NFS4_dec_remove_sz (compound_decode_hdr_maxsz + \ | 517 | #define NFS4_dec_remove_sz (compound_decode_hdr_maxsz + \ |
518 | decode_sequence_maxsz + \ | ||
416 | decode_putfh_maxsz + \ | 519 | decode_putfh_maxsz + \ |
417 | op_decode_hdr_maxsz + 5 + \ | 520 | decode_remove_maxsz + \ |
418 | decode_getattr_maxsz) | 521 | decode_getattr_maxsz) |
419 | #define NFS4_enc_rename_sz (compound_encode_hdr_maxsz + \ | 522 | #define NFS4_enc_rename_sz (compound_encode_hdr_maxsz + \ |
523 | encode_sequence_maxsz + \ | ||
420 | encode_putfh_maxsz + \ | 524 | encode_putfh_maxsz + \ |
421 | encode_savefh_maxsz + \ | 525 | encode_savefh_maxsz + \ |
422 | encode_putfh_maxsz + \ | 526 | encode_putfh_maxsz + \ |
@@ -425,6 +529,7 @@ static int nfs4_stat_to_errno(int); | |||
425 | encode_restorefh_maxsz + \ | 529 | encode_restorefh_maxsz + \ |
426 | encode_getattr_maxsz) | 530 | encode_getattr_maxsz) |
427 | #define NFS4_dec_rename_sz (compound_decode_hdr_maxsz + \ | 531 | #define NFS4_dec_rename_sz (compound_decode_hdr_maxsz + \ |
532 | decode_sequence_maxsz + \ | ||
428 | decode_putfh_maxsz + \ | 533 | decode_putfh_maxsz + \ |
429 | decode_savefh_maxsz + \ | 534 | decode_savefh_maxsz + \ |
430 | decode_putfh_maxsz + \ | 535 | decode_putfh_maxsz + \ |
@@ -433,6 +538,7 @@ static int nfs4_stat_to_errno(int); | |||
433 | decode_restorefh_maxsz + \ | 538 | decode_restorefh_maxsz + \ |
434 | decode_getattr_maxsz) | 539 | decode_getattr_maxsz) |
435 | #define NFS4_enc_link_sz (compound_encode_hdr_maxsz + \ | 540 | #define NFS4_enc_link_sz (compound_encode_hdr_maxsz + \ |
541 | encode_sequence_maxsz + \ | ||
436 | encode_putfh_maxsz + \ | 542 | encode_putfh_maxsz + \ |
437 | encode_savefh_maxsz + \ | 543 | encode_savefh_maxsz + \ |
438 | encode_putfh_maxsz + \ | 544 | encode_putfh_maxsz + \ |
@@ -441,6 +547,7 @@ static int nfs4_stat_to_errno(int); | |||
441 | encode_restorefh_maxsz + \ | 547 | encode_restorefh_maxsz + \ |
442 | decode_getattr_maxsz) | 548 | decode_getattr_maxsz) |
443 | #define NFS4_dec_link_sz (compound_decode_hdr_maxsz + \ | 549 | #define NFS4_dec_link_sz (compound_decode_hdr_maxsz + \ |
550 | decode_sequence_maxsz + \ | ||
444 | decode_putfh_maxsz + \ | 551 | decode_putfh_maxsz + \ |
445 | decode_savefh_maxsz + \ | 552 | decode_savefh_maxsz + \ |
446 | decode_putfh_maxsz + \ | 553 | decode_putfh_maxsz + \ |
@@ -449,16 +556,19 @@ static int nfs4_stat_to_errno(int); | |||
449 | decode_restorefh_maxsz + \ | 556 | decode_restorefh_maxsz + \ |
450 | decode_getattr_maxsz) | 557 | decode_getattr_maxsz) |
451 | #define NFS4_enc_symlink_sz (compound_encode_hdr_maxsz + \ | 558 | #define NFS4_enc_symlink_sz (compound_encode_hdr_maxsz + \ |
559 | encode_sequence_maxsz + \ | ||
452 | encode_putfh_maxsz + \ | 560 | encode_putfh_maxsz + \ |
453 | encode_symlink_maxsz + \ | 561 | encode_symlink_maxsz + \ |
454 | encode_getattr_maxsz + \ | 562 | encode_getattr_maxsz + \ |
455 | encode_getfh_maxsz) | 563 | encode_getfh_maxsz) |
456 | #define NFS4_dec_symlink_sz (compound_decode_hdr_maxsz + \ | 564 | #define NFS4_dec_symlink_sz (compound_decode_hdr_maxsz + \ |
565 | decode_sequence_maxsz + \ | ||
457 | decode_putfh_maxsz + \ | 566 | decode_putfh_maxsz + \ |
458 | decode_symlink_maxsz + \ | 567 | decode_symlink_maxsz + \ |
459 | decode_getattr_maxsz + \ | 568 | decode_getattr_maxsz + \ |
460 | decode_getfh_maxsz) | 569 | decode_getfh_maxsz) |
461 | #define NFS4_enc_create_sz (compound_encode_hdr_maxsz + \ | 570 | #define NFS4_enc_create_sz (compound_encode_hdr_maxsz + \ |
571 | encode_sequence_maxsz + \ | ||
462 | encode_putfh_maxsz + \ | 572 | encode_putfh_maxsz + \ |
463 | encode_savefh_maxsz + \ | 573 | encode_savefh_maxsz + \ |
464 | encode_create_maxsz + \ | 574 | encode_create_maxsz + \ |
@@ -467,6 +577,7 @@ static int nfs4_stat_to_errno(int); | |||
467 | encode_restorefh_maxsz + \ | 577 | encode_restorefh_maxsz + \ |
468 | encode_getattr_maxsz) | 578 | encode_getattr_maxsz) |
469 | #define NFS4_dec_create_sz (compound_decode_hdr_maxsz + \ | 579 | #define NFS4_dec_create_sz (compound_decode_hdr_maxsz + \ |
580 | decode_sequence_maxsz + \ | ||
470 | decode_putfh_maxsz + \ | 581 | decode_putfh_maxsz + \ |
471 | decode_savefh_maxsz + \ | 582 | decode_savefh_maxsz + \ |
472 | decode_create_maxsz + \ | 583 | decode_create_maxsz + \ |
@@ -475,52 +586,98 @@ static int nfs4_stat_to_errno(int); | |||
475 | decode_restorefh_maxsz + \ | 586 | decode_restorefh_maxsz + \ |
476 | decode_getattr_maxsz) | 587 | decode_getattr_maxsz) |
477 | #define NFS4_enc_pathconf_sz (compound_encode_hdr_maxsz + \ | 588 | #define NFS4_enc_pathconf_sz (compound_encode_hdr_maxsz + \ |
589 | encode_sequence_maxsz + \ | ||
478 | encode_putfh_maxsz + \ | 590 | encode_putfh_maxsz + \ |
479 | encode_getattr_maxsz) | 591 | encode_getattr_maxsz) |
480 | #define NFS4_dec_pathconf_sz (compound_decode_hdr_maxsz + \ | 592 | #define NFS4_dec_pathconf_sz (compound_decode_hdr_maxsz + \ |
593 | decode_sequence_maxsz + \ | ||
481 | decode_putfh_maxsz + \ | 594 | decode_putfh_maxsz + \ |
482 | decode_getattr_maxsz) | 595 | decode_getattr_maxsz) |
483 | #define NFS4_enc_statfs_sz (compound_encode_hdr_maxsz + \ | 596 | #define NFS4_enc_statfs_sz (compound_encode_hdr_maxsz + \ |
597 | encode_sequence_maxsz + \ | ||
484 | encode_putfh_maxsz + \ | 598 | encode_putfh_maxsz + \ |
485 | encode_statfs_maxsz) | 599 | encode_statfs_maxsz) |
486 | #define NFS4_dec_statfs_sz (compound_decode_hdr_maxsz + \ | 600 | #define NFS4_dec_statfs_sz (compound_decode_hdr_maxsz + \ |
601 | decode_sequence_maxsz + \ | ||
487 | decode_putfh_maxsz + \ | 602 | decode_putfh_maxsz + \ |
488 | decode_statfs_maxsz) | 603 | decode_statfs_maxsz) |
489 | #define NFS4_enc_server_caps_sz (compound_encode_hdr_maxsz + \ | 604 | #define NFS4_enc_server_caps_sz (compound_encode_hdr_maxsz + \ |
605 | encode_sequence_maxsz + \ | ||
490 | encode_putfh_maxsz + \ | 606 | encode_putfh_maxsz + \ |
491 | encode_getattr_maxsz) | 607 | encode_getattr_maxsz) |
492 | #define NFS4_dec_server_caps_sz (compound_decode_hdr_maxsz + \ | 608 | #define NFS4_dec_server_caps_sz (compound_decode_hdr_maxsz + \ |
609 | decode_sequence_maxsz + \ | ||
493 | decode_putfh_maxsz + \ | 610 | decode_putfh_maxsz + \ |
494 | decode_getattr_maxsz) | 611 | decode_getattr_maxsz) |
495 | #define NFS4_enc_delegreturn_sz (compound_encode_hdr_maxsz + \ | 612 | #define NFS4_enc_delegreturn_sz (compound_encode_hdr_maxsz + \ |
613 | encode_sequence_maxsz + \ | ||
496 | encode_putfh_maxsz + \ | 614 | encode_putfh_maxsz + \ |
497 | encode_delegreturn_maxsz + \ | 615 | encode_delegreturn_maxsz + \ |
498 | encode_getattr_maxsz) | 616 | encode_getattr_maxsz) |
499 | #define NFS4_dec_delegreturn_sz (compound_decode_hdr_maxsz + \ | 617 | #define NFS4_dec_delegreturn_sz (compound_decode_hdr_maxsz + \ |
618 | decode_sequence_maxsz + \ | ||
500 | decode_delegreturn_maxsz + \ | 619 | decode_delegreturn_maxsz + \ |
501 | decode_getattr_maxsz) | 620 | decode_getattr_maxsz) |
502 | #define NFS4_enc_getacl_sz (compound_encode_hdr_maxsz + \ | 621 | #define NFS4_enc_getacl_sz (compound_encode_hdr_maxsz + \ |
622 | encode_sequence_maxsz + \ | ||
503 | encode_putfh_maxsz + \ | 623 | encode_putfh_maxsz + \ |
504 | encode_getacl_maxsz) | 624 | encode_getacl_maxsz) |
505 | #define NFS4_dec_getacl_sz (compound_decode_hdr_maxsz + \ | 625 | #define NFS4_dec_getacl_sz (compound_decode_hdr_maxsz + \ |
626 | decode_sequence_maxsz + \ | ||
506 | decode_putfh_maxsz + \ | 627 | decode_putfh_maxsz + \ |
507 | decode_getacl_maxsz) | 628 | decode_getacl_maxsz) |
508 | #define NFS4_enc_setacl_sz (compound_encode_hdr_maxsz + \ | 629 | #define NFS4_enc_setacl_sz (compound_encode_hdr_maxsz + \ |
630 | encode_sequence_maxsz + \ | ||
509 | encode_putfh_maxsz + \ | 631 | encode_putfh_maxsz + \ |
510 | encode_setacl_maxsz) | 632 | encode_setacl_maxsz) |
511 | #define NFS4_dec_setacl_sz (compound_decode_hdr_maxsz + \ | 633 | #define NFS4_dec_setacl_sz (compound_decode_hdr_maxsz + \ |
634 | decode_sequence_maxsz + \ | ||
512 | decode_putfh_maxsz + \ | 635 | decode_putfh_maxsz + \ |
513 | decode_setacl_maxsz) | 636 | decode_setacl_maxsz) |
514 | #define NFS4_enc_fs_locations_sz \ | 637 | #define NFS4_enc_fs_locations_sz \ |
515 | (compound_encode_hdr_maxsz + \ | 638 | (compound_encode_hdr_maxsz + \ |
639 | encode_sequence_maxsz + \ | ||
516 | encode_putfh_maxsz + \ | 640 | encode_putfh_maxsz + \ |
517 | encode_lookup_maxsz + \ | 641 | encode_lookup_maxsz + \ |
518 | encode_fs_locations_maxsz) | 642 | encode_fs_locations_maxsz) |
519 | #define NFS4_dec_fs_locations_sz \ | 643 | #define NFS4_dec_fs_locations_sz \ |
520 | (compound_decode_hdr_maxsz + \ | 644 | (compound_decode_hdr_maxsz + \ |
645 | decode_sequence_maxsz + \ | ||
521 | decode_putfh_maxsz + \ | 646 | decode_putfh_maxsz + \ |
522 | decode_lookup_maxsz + \ | 647 | decode_lookup_maxsz + \ |
523 | decode_fs_locations_maxsz) | 648 | decode_fs_locations_maxsz) |
649 | #if defined(CONFIG_NFS_V4_1) | ||
650 | #define NFS4_enc_exchange_id_sz \ | ||
651 | (compound_encode_hdr_maxsz + \ | ||
652 | encode_exchange_id_maxsz) | ||
653 | #define NFS4_dec_exchange_id_sz \ | ||
654 | (compound_decode_hdr_maxsz + \ | ||
655 | decode_exchange_id_maxsz) | ||
656 | #define NFS4_enc_create_session_sz \ | ||
657 | (compound_encode_hdr_maxsz + \ | ||
658 | encode_create_session_maxsz) | ||
659 | #define NFS4_dec_create_session_sz \ | ||
660 | (compound_decode_hdr_maxsz + \ | ||
661 | decode_create_session_maxsz) | ||
662 | #define NFS4_enc_destroy_session_sz (compound_encode_hdr_maxsz + \ | ||
663 | encode_destroy_session_maxsz) | ||
664 | #define NFS4_dec_destroy_session_sz (compound_decode_hdr_maxsz + \ | ||
665 | decode_destroy_session_maxsz) | ||
666 | #define NFS4_enc_sequence_sz \ | ||
667 | (compound_decode_hdr_maxsz + \ | ||
668 | encode_sequence_maxsz) | ||
669 | #define NFS4_dec_sequence_sz \ | ||
670 | (compound_decode_hdr_maxsz + \ | ||
671 | decode_sequence_maxsz) | ||
672 | #define NFS4_enc_get_lease_time_sz (compound_encode_hdr_maxsz + \ | ||
673 | encode_sequence_maxsz + \ | ||
674 | encode_putrootfh_maxsz + \ | ||
675 | encode_fsinfo_maxsz) | ||
676 | #define NFS4_dec_get_lease_time_sz (compound_decode_hdr_maxsz + \ | ||
677 | decode_sequence_maxsz + \ | ||
678 | decode_putrootfh_maxsz + \ | ||
679 | decode_fsinfo_maxsz) | ||
680 | #endif /* CONFIG_NFS_V4_1 */ | ||
524 | 681 | ||
525 | static const umode_t nfs_type2fmt[] = { | 682 | static const umode_t nfs_type2fmt[] = { |
526 | [NF4BAD] = 0, | 683 | [NF4BAD] = 0, |
@@ -541,6 +698,8 @@ struct compound_hdr { | |||
541 | __be32 * nops_p; | 698 | __be32 * nops_p; |
542 | uint32_t taglen; | 699 | uint32_t taglen; |
543 | char * tag; | 700 | char * tag; |
701 | uint32_t replen; /* expected reply words */ | ||
702 | u32 minorversion; | ||
544 | }; | 703 | }; |
545 | 704 | ||
546 | /* | 705 | /* |
@@ -576,22 +735,31 @@ static void encode_string(struct xdr_stream *xdr, unsigned int len, const char * | |||
576 | xdr_encode_opaque(p, str, len); | 735 | xdr_encode_opaque(p, str, len); |
577 | } | 736 | } |
578 | 737 | ||
579 | static void encode_compound_hdr(struct xdr_stream *xdr, struct compound_hdr *hdr) | 738 | static void encode_compound_hdr(struct xdr_stream *xdr, |
739 | struct rpc_rqst *req, | ||
740 | struct compound_hdr *hdr) | ||
580 | { | 741 | { |
581 | __be32 *p; | 742 | __be32 *p; |
743 | struct rpc_auth *auth = req->rq_task->tk_msg.rpc_cred->cr_auth; | ||
744 | |||
745 | /* initialize running count of expected bytes in reply. | ||
746 | * NOTE: the replied tag SHOULD be the same is the one sent, | ||
747 | * but this is not required as a MUST for the server to do so. */ | ||
748 | hdr->replen = RPC_REPHDRSIZE + auth->au_rslack + 3 + hdr->taglen; | ||
582 | 749 | ||
583 | dprintk("encode_compound: tag=%.*s\n", (int)hdr->taglen, hdr->tag); | 750 | dprintk("encode_compound: tag=%.*s\n", (int)hdr->taglen, hdr->tag); |
584 | BUG_ON(hdr->taglen > NFS4_MAXTAGLEN); | 751 | BUG_ON(hdr->taglen > NFS4_MAXTAGLEN); |
585 | RESERVE_SPACE(12+(XDR_QUADLEN(hdr->taglen)<<2)); | 752 | RESERVE_SPACE(12+(XDR_QUADLEN(hdr->taglen)<<2)); |
586 | WRITE32(hdr->taglen); | 753 | WRITE32(hdr->taglen); |
587 | WRITEMEM(hdr->tag, hdr->taglen); | 754 | WRITEMEM(hdr->tag, hdr->taglen); |
588 | WRITE32(NFS4_MINOR_VERSION); | 755 | WRITE32(hdr->minorversion); |
589 | hdr->nops_p = p; | 756 | hdr->nops_p = p; |
590 | WRITE32(hdr->nops); | 757 | WRITE32(hdr->nops); |
591 | } | 758 | } |
592 | 759 | ||
593 | static void encode_nops(struct compound_hdr *hdr) | 760 | static void encode_nops(struct compound_hdr *hdr) |
594 | { | 761 | { |
762 | BUG_ON(hdr->nops > NFS4_MAX_OPS); | ||
595 | *hdr->nops_p = htonl(hdr->nops); | 763 | *hdr->nops_p = htonl(hdr->nops); |
596 | } | 764 | } |
597 | 765 | ||
@@ -736,6 +904,7 @@ static void encode_access(struct xdr_stream *xdr, u32 access, struct compound_hd | |||
736 | WRITE32(OP_ACCESS); | 904 | WRITE32(OP_ACCESS); |
737 | WRITE32(access); | 905 | WRITE32(access); |
738 | hdr->nops++; | 906 | hdr->nops++; |
907 | hdr->replen += decode_access_maxsz; | ||
739 | } | 908 | } |
740 | 909 | ||
741 | static void encode_close(struct xdr_stream *xdr, const struct nfs_closeargs *arg, struct compound_hdr *hdr) | 910 | static void encode_close(struct xdr_stream *xdr, const struct nfs_closeargs *arg, struct compound_hdr *hdr) |
@@ -747,6 +916,7 @@ static void encode_close(struct xdr_stream *xdr, const struct nfs_closeargs *arg | |||
747 | WRITE32(arg->seqid->sequence->counter); | 916 | WRITE32(arg->seqid->sequence->counter); |
748 | WRITEMEM(arg->stateid->data, NFS4_STATEID_SIZE); | 917 | WRITEMEM(arg->stateid->data, NFS4_STATEID_SIZE); |
749 | hdr->nops++; | 918 | hdr->nops++; |
919 | hdr->replen += decode_close_maxsz; | ||
750 | } | 920 | } |
751 | 921 | ||
752 | static void encode_commit(struct xdr_stream *xdr, const struct nfs_writeargs *args, struct compound_hdr *hdr) | 922 | static void encode_commit(struct xdr_stream *xdr, const struct nfs_writeargs *args, struct compound_hdr *hdr) |
@@ -758,6 +928,7 @@ static void encode_commit(struct xdr_stream *xdr, const struct nfs_writeargs *ar | |||
758 | WRITE64(args->offset); | 928 | WRITE64(args->offset); |
759 | WRITE32(args->count); | 929 | WRITE32(args->count); |
760 | hdr->nops++; | 930 | hdr->nops++; |
931 | hdr->replen += decode_commit_maxsz; | ||
761 | } | 932 | } |
762 | 933 | ||
763 | static void encode_create(struct xdr_stream *xdr, const struct nfs4_create_arg *create, struct compound_hdr *hdr) | 934 | static void encode_create(struct xdr_stream *xdr, const struct nfs4_create_arg *create, struct compound_hdr *hdr) |
@@ -789,6 +960,7 @@ static void encode_create(struct xdr_stream *xdr, const struct nfs4_create_arg * | |||
789 | WRITE32(create->name->len); | 960 | WRITE32(create->name->len); |
790 | WRITEMEM(create->name->name, create->name->len); | 961 | WRITEMEM(create->name->name, create->name->len); |
791 | hdr->nops++; | 962 | hdr->nops++; |
963 | hdr->replen += decode_create_maxsz; | ||
792 | 964 | ||
793 | encode_attrs(xdr, create->attrs, create->server); | 965 | encode_attrs(xdr, create->attrs, create->server); |
794 | } | 966 | } |
@@ -802,6 +974,7 @@ static void encode_getattr_one(struct xdr_stream *xdr, uint32_t bitmap, struct c | |||
802 | WRITE32(1); | 974 | WRITE32(1); |
803 | WRITE32(bitmap); | 975 | WRITE32(bitmap); |
804 | hdr->nops++; | 976 | hdr->nops++; |
977 | hdr->replen += decode_getattr_maxsz; | ||
805 | } | 978 | } |
806 | 979 | ||
807 | static void encode_getattr_two(struct xdr_stream *xdr, uint32_t bm0, uint32_t bm1, struct compound_hdr *hdr) | 980 | static void encode_getattr_two(struct xdr_stream *xdr, uint32_t bm0, uint32_t bm1, struct compound_hdr *hdr) |
@@ -814,6 +987,7 @@ static void encode_getattr_two(struct xdr_stream *xdr, uint32_t bm0, uint32_t bm | |||
814 | WRITE32(bm0); | 987 | WRITE32(bm0); |
815 | WRITE32(bm1); | 988 | WRITE32(bm1); |
816 | hdr->nops++; | 989 | hdr->nops++; |
990 | hdr->replen += decode_getattr_maxsz; | ||
817 | } | 991 | } |
818 | 992 | ||
819 | static void encode_getfattr(struct xdr_stream *xdr, const u32* bitmask, struct compound_hdr *hdr) | 993 | static void encode_getfattr(struct xdr_stream *xdr, const u32* bitmask, struct compound_hdr *hdr) |
@@ -841,6 +1015,7 @@ static void encode_getfh(struct xdr_stream *xdr, struct compound_hdr *hdr) | |||
841 | RESERVE_SPACE(4); | 1015 | RESERVE_SPACE(4); |
842 | WRITE32(OP_GETFH); | 1016 | WRITE32(OP_GETFH); |
843 | hdr->nops++; | 1017 | hdr->nops++; |
1018 | hdr->replen += decode_getfh_maxsz; | ||
844 | } | 1019 | } |
845 | 1020 | ||
846 | static void encode_link(struct xdr_stream *xdr, const struct qstr *name, struct compound_hdr *hdr) | 1021 | static void encode_link(struct xdr_stream *xdr, const struct qstr *name, struct compound_hdr *hdr) |
@@ -852,6 +1027,7 @@ static void encode_link(struct xdr_stream *xdr, const struct qstr *name, struct | |||
852 | WRITE32(name->len); | 1027 | WRITE32(name->len); |
853 | WRITEMEM(name->name, name->len); | 1028 | WRITEMEM(name->name, name->len); |
854 | hdr->nops++; | 1029 | hdr->nops++; |
1030 | hdr->replen += decode_link_maxsz; | ||
855 | } | 1031 | } |
856 | 1032 | ||
857 | static inline int nfs4_lock_type(struct file_lock *fl, int block) | 1033 | static inline int nfs4_lock_type(struct file_lock *fl, int block) |
@@ -899,6 +1075,7 @@ static void encode_lock(struct xdr_stream *xdr, const struct nfs_lock_args *args | |||
899 | WRITE32(args->lock_seqid->sequence->counter); | 1075 | WRITE32(args->lock_seqid->sequence->counter); |
900 | } | 1076 | } |
901 | hdr->nops++; | 1077 | hdr->nops++; |
1078 | hdr->replen += decode_lock_maxsz; | ||
902 | } | 1079 | } |
903 | 1080 | ||
904 | static void encode_lockt(struct xdr_stream *xdr, const struct nfs_lockt_args *args, struct compound_hdr *hdr) | 1081 | static void encode_lockt(struct xdr_stream *xdr, const struct nfs_lockt_args *args, struct compound_hdr *hdr) |
@@ -915,6 +1092,7 @@ static void encode_lockt(struct xdr_stream *xdr, const struct nfs_lockt_args *ar | |||
915 | WRITEMEM("lock id:", 8); | 1092 | WRITEMEM("lock id:", 8); |
916 | WRITE64(args->lock_owner.id); | 1093 | WRITE64(args->lock_owner.id); |
917 | hdr->nops++; | 1094 | hdr->nops++; |
1095 | hdr->replen += decode_lockt_maxsz; | ||
918 | } | 1096 | } |
919 | 1097 | ||
920 | static void encode_locku(struct xdr_stream *xdr, const struct nfs_locku_args *args, struct compound_hdr *hdr) | 1098 | static void encode_locku(struct xdr_stream *xdr, const struct nfs_locku_args *args, struct compound_hdr *hdr) |
@@ -929,6 +1107,7 @@ static void encode_locku(struct xdr_stream *xdr, const struct nfs_locku_args *ar | |||
929 | WRITE64(args->fl->fl_start); | 1107 | WRITE64(args->fl->fl_start); |
930 | WRITE64(nfs4_lock_length(args->fl)); | 1108 | WRITE64(nfs4_lock_length(args->fl)); |
931 | hdr->nops++; | 1109 | hdr->nops++; |
1110 | hdr->replen += decode_locku_maxsz; | ||
932 | } | 1111 | } |
933 | 1112 | ||
934 | static void encode_lookup(struct xdr_stream *xdr, const struct qstr *name, struct compound_hdr *hdr) | 1113 | static void encode_lookup(struct xdr_stream *xdr, const struct qstr *name, struct compound_hdr *hdr) |
@@ -941,6 +1120,7 @@ static void encode_lookup(struct xdr_stream *xdr, const struct qstr *name, struc | |||
941 | WRITE32(len); | 1120 | WRITE32(len); |
942 | WRITEMEM(name->name, len); | 1121 | WRITEMEM(name->name, len); |
943 | hdr->nops++; | 1122 | hdr->nops++; |
1123 | hdr->replen += decode_lookup_maxsz; | ||
944 | } | 1124 | } |
945 | 1125 | ||
946 | static void encode_share_access(struct xdr_stream *xdr, fmode_t fmode) | 1126 | static void encode_share_access(struct xdr_stream *xdr, fmode_t fmode) |
@@ -1080,6 +1260,7 @@ static void encode_open(struct xdr_stream *xdr, const struct nfs_openargs *arg, | |||
1080 | BUG(); | 1260 | BUG(); |
1081 | } | 1261 | } |
1082 | hdr->nops++; | 1262 | hdr->nops++; |
1263 | hdr->replen += decode_open_maxsz; | ||
1083 | } | 1264 | } |
1084 | 1265 | ||
1085 | static void encode_open_confirm(struct xdr_stream *xdr, const struct nfs_open_confirmargs *arg, struct compound_hdr *hdr) | 1266 | static void encode_open_confirm(struct xdr_stream *xdr, const struct nfs_open_confirmargs *arg, struct compound_hdr *hdr) |
@@ -1091,6 +1272,7 @@ static void encode_open_confirm(struct xdr_stream *xdr, const struct nfs_open_co | |||
1091 | WRITEMEM(arg->stateid->data, NFS4_STATEID_SIZE); | 1272 | WRITEMEM(arg->stateid->data, NFS4_STATEID_SIZE); |
1092 | WRITE32(arg->seqid->sequence->counter); | 1273 | WRITE32(arg->seqid->sequence->counter); |
1093 | hdr->nops++; | 1274 | hdr->nops++; |
1275 | hdr->replen += decode_open_confirm_maxsz; | ||
1094 | } | 1276 | } |
1095 | 1277 | ||
1096 | static void encode_open_downgrade(struct xdr_stream *xdr, const struct nfs_closeargs *arg, struct compound_hdr *hdr) | 1278 | static void encode_open_downgrade(struct xdr_stream *xdr, const struct nfs_closeargs *arg, struct compound_hdr *hdr) |
@@ -1103,6 +1285,7 @@ static void encode_open_downgrade(struct xdr_stream *xdr, const struct nfs_close | |||
1103 | WRITE32(arg->seqid->sequence->counter); | 1285 | WRITE32(arg->seqid->sequence->counter); |
1104 | encode_share_access(xdr, arg->fmode); | 1286 | encode_share_access(xdr, arg->fmode); |
1105 | hdr->nops++; | 1287 | hdr->nops++; |
1288 | hdr->replen += decode_open_downgrade_maxsz; | ||
1106 | } | 1289 | } |
1107 | 1290 | ||
1108 | static void | 1291 | static void |
@@ -1116,6 +1299,7 @@ encode_putfh(struct xdr_stream *xdr, const struct nfs_fh *fh, struct compound_hd | |||
1116 | WRITE32(len); | 1299 | WRITE32(len); |
1117 | WRITEMEM(fh->data, len); | 1300 | WRITEMEM(fh->data, len); |
1118 | hdr->nops++; | 1301 | hdr->nops++; |
1302 | hdr->replen += decode_putfh_maxsz; | ||
1119 | } | 1303 | } |
1120 | 1304 | ||
1121 | static void encode_putrootfh(struct xdr_stream *xdr, struct compound_hdr *hdr) | 1305 | static void encode_putrootfh(struct xdr_stream *xdr, struct compound_hdr *hdr) |
@@ -1125,6 +1309,7 @@ static void encode_putrootfh(struct xdr_stream *xdr, struct compound_hdr *hdr) | |||
1125 | RESERVE_SPACE(4); | 1309 | RESERVE_SPACE(4); |
1126 | WRITE32(OP_PUTROOTFH); | 1310 | WRITE32(OP_PUTROOTFH); |
1127 | hdr->nops++; | 1311 | hdr->nops++; |
1312 | hdr->replen += decode_putrootfh_maxsz; | ||
1128 | } | 1313 | } |
1129 | 1314 | ||
1130 | static void encode_stateid(struct xdr_stream *xdr, const struct nfs_open_context *ctx) | 1315 | static void encode_stateid(struct xdr_stream *xdr, const struct nfs_open_context *ctx) |
@@ -1153,6 +1338,7 @@ static void encode_read(struct xdr_stream *xdr, const struct nfs_readargs *args, | |||
1153 | WRITE64(args->offset); | 1338 | WRITE64(args->offset); |
1154 | WRITE32(args->count); | 1339 | WRITE32(args->count); |
1155 | hdr->nops++; | 1340 | hdr->nops++; |
1341 | hdr->replen += decode_read_maxsz; | ||
1156 | } | 1342 | } |
1157 | 1343 | ||
1158 | static void encode_readdir(struct xdr_stream *xdr, const struct nfs4_readdir_arg *readdir, struct rpc_rqst *req, struct compound_hdr *hdr) | 1344 | static void encode_readdir(struct xdr_stream *xdr, const struct nfs4_readdir_arg *readdir, struct rpc_rqst *req, struct compound_hdr *hdr) |
@@ -1178,6 +1364,7 @@ static void encode_readdir(struct xdr_stream *xdr, const struct nfs4_readdir_arg | |||
1178 | WRITE32(attrs[0] & readdir->bitmask[0]); | 1364 | WRITE32(attrs[0] & readdir->bitmask[0]); |
1179 | WRITE32(attrs[1] & readdir->bitmask[1]); | 1365 | WRITE32(attrs[1] & readdir->bitmask[1]); |
1180 | hdr->nops++; | 1366 | hdr->nops++; |
1367 | hdr->replen += decode_readdir_maxsz; | ||
1181 | dprintk("%s: cookie = %Lu, verifier = %08x:%08x, bitmap = %08x:%08x\n", | 1368 | dprintk("%s: cookie = %Lu, verifier = %08x:%08x, bitmap = %08x:%08x\n", |
1182 | __func__, | 1369 | __func__, |
1183 | (unsigned long long)readdir->cookie, | 1370 | (unsigned long long)readdir->cookie, |
@@ -1194,6 +1381,7 @@ static void encode_readlink(struct xdr_stream *xdr, const struct nfs4_readlink * | |||
1194 | RESERVE_SPACE(4); | 1381 | RESERVE_SPACE(4); |
1195 | WRITE32(OP_READLINK); | 1382 | WRITE32(OP_READLINK); |
1196 | hdr->nops++; | 1383 | hdr->nops++; |
1384 | hdr->replen += decode_readlink_maxsz; | ||
1197 | } | 1385 | } |
1198 | 1386 | ||
1199 | static void encode_remove(struct xdr_stream *xdr, const struct qstr *name, struct compound_hdr *hdr) | 1387 | static void encode_remove(struct xdr_stream *xdr, const struct qstr *name, struct compound_hdr *hdr) |
@@ -1205,6 +1393,7 @@ static void encode_remove(struct xdr_stream *xdr, const struct qstr *name, struc | |||
1205 | WRITE32(name->len); | 1393 | WRITE32(name->len); |
1206 | WRITEMEM(name->name, name->len); | 1394 | WRITEMEM(name->name, name->len); |
1207 | hdr->nops++; | 1395 | hdr->nops++; |
1396 | hdr->replen += decode_remove_maxsz; | ||
1208 | } | 1397 | } |
1209 | 1398 | ||
1210 | static void encode_rename(struct xdr_stream *xdr, const struct qstr *oldname, const struct qstr *newname, struct compound_hdr *hdr) | 1399 | static void encode_rename(struct xdr_stream *xdr, const struct qstr *oldname, const struct qstr *newname, struct compound_hdr *hdr) |
@@ -1220,6 +1409,7 @@ static void encode_rename(struct xdr_stream *xdr, const struct qstr *oldname, co | |||
1220 | WRITE32(newname->len); | 1409 | WRITE32(newname->len); |
1221 | WRITEMEM(newname->name, newname->len); | 1410 | WRITEMEM(newname->name, newname->len); |
1222 | hdr->nops++; | 1411 | hdr->nops++; |
1412 | hdr->replen += decode_rename_maxsz; | ||
1223 | } | 1413 | } |
1224 | 1414 | ||
1225 | static void encode_renew(struct xdr_stream *xdr, const struct nfs_client *client_stateid, struct compound_hdr *hdr) | 1415 | static void encode_renew(struct xdr_stream *xdr, const struct nfs_client *client_stateid, struct compound_hdr *hdr) |
@@ -1230,6 +1420,7 @@ static void encode_renew(struct xdr_stream *xdr, const struct nfs_client *client | |||
1230 | WRITE32(OP_RENEW); | 1420 | WRITE32(OP_RENEW); |
1231 | WRITE64(client_stateid->cl_clientid); | 1421 | WRITE64(client_stateid->cl_clientid); |
1232 | hdr->nops++; | 1422 | hdr->nops++; |
1423 | hdr->replen += decode_renew_maxsz; | ||
1233 | } | 1424 | } |
1234 | 1425 | ||
1235 | static void | 1426 | static void |
@@ -1240,6 +1431,7 @@ encode_restorefh(struct xdr_stream *xdr, struct compound_hdr *hdr) | |||
1240 | RESERVE_SPACE(4); | 1431 | RESERVE_SPACE(4); |
1241 | WRITE32(OP_RESTOREFH); | 1432 | WRITE32(OP_RESTOREFH); |
1242 | hdr->nops++; | 1433 | hdr->nops++; |
1434 | hdr->replen += decode_restorefh_maxsz; | ||
1243 | } | 1435 | } |
1244 | 1436 | ||
1245 | static int | 1437 | static int |
@@ -1259,6 +1451,7 @@ encode_setacl(struct xdr_stream *xdr, struct nfs_setaclargs *arg, struct compoun | |||
1259 | WRITE32(arg->acl_len); | 1451 | WRITE32(arg->acl_len); |
1260 | xdr_write_pages(xdr, arg->acl_pages, arg->acl_pgbase, arg->acl_len); | 1452 | xdr_write_pages(xdr, arg->acl_pages, arg->acl_pgbase, arg->acl_len); |
1261 | hdr->nops++; | 1453 | hdr->nops++; |
1454 | hdr->replen += decode_setacl_maxsz; | ||
1262 | return 0; | 1455 | return 0; |
1263 | } | 1456 | } |
1264 | 1457 | ||
@@ -1270,6 +1463,7 @@ encode_savefh(struct xdr_stream *xdr, struct compound_hdr *hdr) | |||
1270 | RESERVE_SPACE(4); | 1463 | RESERVE_SPACE(4); |
1271 | WRITE32(OP_SAVEFH); | 1464 | WRITE32(OP_SAVEFH); |
1272 | hdr->nops++; | 1465 | hdr->nops++; |
1466 | hdr->replen += decode_savefh_maxsz; | ||
1273 | } | 1467 | } |
1274 | 1468 | ||
1275 | static void encode_setattr(struct xdr_stream *xdr, const struct nfs_setattrargs *arg, const struct nfs_server *server, struct compound_hdr *hdr) | 1469 | static void encode_setattr(struct xdr_stream *xdr, const struct nfs_setattrargs *arg, const struct nfs_server *server, struct compound_hdr *hdr) |
@@ -1280,6 +1474,7 @@ static void encode_setattr(struct xdr_stream *xdr, const struct nfs_setattrargs | |||
1280 | WRITE32(OP_SETATTR); | 1474 | WRITE32(OP_SETATTR); |
1281 | WRITEMEM(arg->stateid.data, NFS4_STATEID_SIZE); | 1475 | WRITEMEM(arg->stateid.data, NFS4_STATEID_SIZE); |
1282 | hdr->nops++; | 1476 | hdr->nops++; |
1477 | hdr->replen += decode_setattr_maxsz; | ||
1283 | encode_attrs(xdr, arg->iap, server); | 1478 | encode_attrs(xdr, arg->iap, server); |
1284 | } | 1479 | } |
1285 | 1480 | ||
@@ -1299,6 +1494,7 @@ static void encode_setclientid(struct xdr_stream *xdr, const struct nfs4_setclie | |||
1299 | RESERVE_SPACE(4); | 1494 | RESERVE_SPACE(4); |
1300 | WRITE32(setclientid->sc_cb_ident); | 1495 | WRITE32(setclientid->sc_cb_ident); |
1301 | hdr->nops++; | 1496 | hdr->nops++; |
1497 | hdr->replen += decode_setclientid_maxsz; | ||
1302 | } | 1498 | } |
1303 | 1499 | ||
1304 | static void encode_setclientid_confirm(struct xdr_stream *xdr, const struct nfs_client *client_state, struct compound_hdr *hdr) | 1500 | static void encode_setclientid_confirm(struct xdr_stream *xdr, const struct nfs_client *client_state, struct compound_hdr *hdr) |
@@ -1310,6 +1506,7 @@ static void encode_setclientid_confirm(struct xdr_stream *xdr, const struct nfs_ | |||
1310 | WRITE64(client_state->cl_clientid); | 1506 | WRITE64(client_state->cl_clientid); |
1311 | WRITEMEM(client_state->cl_confirm.data, NFS4_VERIFIER_SIZE); | 1507 | WRITEMEM(client_state->cl_confirm.data, NFS4_VERIFIER_SIZE); |
1312 | hdr->nops++; | 1508 | hdr->nops++; |
1509 | hdr->replen += decode_setclientid_confirm_maxsz; | ||
1313 | } | 1510 | } |
1314 | 1511 | ||
1315 | static void encode_write(struct xdr_stream *xdr, const struct nfs_writeargs *args, struct compound_hdr *hdr) | 1512 | static void encode_write(struct xdr_stream *xdr, const struct nfs_writeargs *args, struct compound_hdr *hdr) |
@@ -1328,6 +1525,7 @@ static void encode_write(struct xdr_stream *xdr, const struct nfs_writeargs *arg | |||
1328 | 1525 | ||
1329 | xdr_write_pages(xdr, args->pages, args->pgbase, args->count); | 1526 | xdr_write_pages(xdr, args->pages, args->pgbase, args->count); |
1330 | hdr->nops++; | 1527 | hdr->nops++; |
1528 | hdr->replen += decode_write_maxsz; | ||
1331 | } | 1529 | } |
1332 | 1530 | ||
1333 | static void encode_delegreturn(struct xdr_stream *xdr, const nfs4_stateid *stateid, struct compound_hdr *hdr) | 1531 | static void encode_delegreturn(struct xdr_stream *xdr, const nfs4_stateid *stateid, struct compound_hdr *hdr) |
@@ -1339,11 +1537,163 @@ static void encode_delegreturn(struct xdr_stream *xdr, const nfs4_stateid *state | |||
1339 | WRITE32(OP_DELEGRETURN); | 1537 | WRITE32(OP_DELEGRETURN); |
1340 | WRITEMEM(stateid->data, NFS4_STATEID_SIZE); | 1538 | WRITEMEM(stateid->data, NFS4_STATEID_SIZE); |
1341 | hdr->nops++; | 1539 | hdr->nops++; |
1540 | hdr->replen += decode_delegreturn_maxsz; | ||
1541 | } | ||
1542 | |||
1543 | #if defined(CONFIG_NFS_V4_1) | ||
1544 | /* NFSv4.1 operations */ | ||
1545 | static void encode_exchange_id(struct xdr_stream *xdr, | ||
1546 | struct nfs41_exchange_id_args *args, | ||
1547 | struct compound_hdr *hdr) | ||
1548 | { | ||
1549 | __be32 *p; | ||
1550 | |||
1551 | RESERVE_SPACE(4 + sizeof(args->verifier->data)); | ||
1552 | WRITE32(OP_EXCHANGE_ID); | ||
1553 | WRITEMEM(args->verifier->data, sizeof(args->verifier->data)); | ||
1554 | |||
1555 | encode_string(xdr, args->id_len, args->id); | ||
1556 | |||
1557 | RESERVE_SPACE(12); | ||
1558 | WRITE32(args->flags); | ||
1559 | WRITE32(0); /* zero length state_protect4_a */ | ||
1560 | WRITE32(0); /* zero length implementation id array */ | ||
1561 | hdr->nops++; | ||
1562 | hdr->replen += decode_exchange_id_maxsz; | ||
1563 | } | ||
1564 | |||
1565 | static void encode_create_session(struct xdr_stream *xdr, | ||
1566 | struct nfs41_create_session_args *args, | ||
1567 | struct compound_hdr *hdr) | ||
1568 | { | ||
1569 | __be32 *p; | ||
1570 | char machine_name[NFS4_MAX_MACHINE_NAME_LEN]; | ||
1571 | uint32_t len; | ||
1572 | struct nfs_client *clp = args->client; | ||
1573 | |||
1574 | RESERVE_SPACE(4); | ||
1575 | WRITE32(OP_CREATE_SESSION); | ||
1576 | |||
1577 | RESERVE_SPACE(8); | ||
1578 | WRITE64(clp->cl_ex_clid); | ||
1579 | |||
1580 | RESERVE_SPACE(8); | ||
1581 | WRITE32(clp->cl_seqid); /*Sequence id */ | ||
1582 | WRITE32(args->flags); /*flags */ | ||
1583 | |||
1584 | RESERVE_SPACE(2*28); /* 2 channel_attrs */ | ||
1585 | /* Fore Channel */ | ||
1586 | WRITE32(args->fc_attrs.headerpadsz); /* header padding size */ | ||
1587 | WRITE32(args->fc_attrs.max_rqst_sz); /* max req size */ | ||
1588 | WRITE32(args->fc_attrs.max_resp_sz); /* max resp size */ | ||
1589 | WRITE32(args->fc_attrs.max_resp_sz_cached); /* Max resp sz cached */ | ||
1590 | WRITE32(args->fc_attrs.max_ops); /* max operations */ | ||
1591 | WRITE32(args->fc_attrs.max_reqs); /* max requests */ | ||
1592 | WRITE32(0); /* rdmachannel_attrs */ | ||
1593 | |||
1594 | /* Back Channel */ | ||
1595 | WRITE32(args->fc_attrs.headerpadsz); /* header padding size */ | ||
1596 | WRITE32(args->bc_attrs.max_rqst_sz); /* max req size */ | ||
1597 | WRITE32(args->bc_attrs.max_resp_sz); /* max resp size */ | ||
1598 | WRITE32(args->bc_attrs.max_resp_sz_cached); /* Max resp sz cached */ | ||
1599 | WRITE32(args->bc_attrs.max_ops); /* max operations */ | ||
1600 | WRITE32(args->bc_attrs.max_reqs); /* max requests */ | ||
1601 | WRITE32(0); /* rdmachannel_attrs */ | ||
1602 | |||
1603 | RESERVE_SPACE(4); | ||
1604 | WRITE32(args->cb_program); /* cb_program */ | ||
1605 | |||
1606 | RESERVE_SPACE(4); /* # of security flavors */ | ||
1607 | WRITE32(1); | ||
1608 | |||
1609 | RESERVE_SPACE(4); | ||
1610 | WRITE32(RPC_AUTH_UNIX); /* auth_sys */ | ||
1611 | |||
1612 | /* authsys_parms rfc1831 */ | ||
1613 | RESERVE_SPACE(4); | ||
1614 | WRITE32((u32)clp->cl_boot_time.tv_nsec); /* stamp */ | ||
1615 | len = scnprintf(machine_name, sizeof(machine_name), "%s", | ||
1616 | clp->cl_ipaddr); | ||
1617 | RESERVE_SPACE(16 + len); | ||
1618 | WRITE32(len); | ||
1619 | WRITEMEM(machine_name, len); | ||
1620 | WRITE32(0); /* UID */ | ||
1621 | WRITE32(0); /* GID */ | ||
1622 | WRITE32(0); /* No more gids */ | ||
1623 | hdr->nops++; | ||
1624 | hdr->replen += decode_create_session_maxsz; | ||
1625 | } | ||
1626 | |||
1627 | static void encode_destroy_session(struct xdr_stream *xdr, | ||
1628 | struct nfs4_session *session, | ||
1629 | struct compound_hdr *hdr) | ||
1630 | { | ||
1631 | __be32 *p; | ||
1632 | RESERVE_SPACE(4 + NFS4_MAX_SESSIONID_LEN); | ||
1633 | WRITE32(OP_DESTROY_SESSION); | ||
1634 | WRITEMEM(session->sess_id.data, NFS4_MAX_SESSIONID_LEN); | ||
1635 | hdr->nops++; | ||
1636 | hdr->replen += decode_destroy_session_maxsz; | ||
1342 | } | 1637 | } |
1638 | #endif /* CONFIG_NFS_V4_1 */ | ||
1639 | |||
1640 | static void encode_sequence(struct xdr_stream *xdr, | ||
1641 | const struct nfs4_sequence_args *args, | ||
1642 | struct compound_hdr *hdr) | ||
1643 | { | ||
1644 | #if defined(CONFIG_NFS_V4_1) | ||
1645 | struct nfs4_session *session = args->sa_session; | ||
1646 | struct nfs4_slot_table *tp; | ||
1647 | struct nfs4_slot *slot; | ||
1648 | __be32 *p; | ||
1649 | |||
1650 | if (!session) | ||
1651 | return; | ||
1652 | |||
1653 | tp = &session->fc_slot_table; | ||
1654 | |||
1655 | WARN_ON(args->sa_slotid == NFS4_MAX_SLOT_TABLE); | ||
1656 | slot = tp->slots + args->sa_slotid; | ||
1657 | |||
1658 | RESERVE_SPACE(4); | ||
1659 | WRITE32(OP_SEQUENCE); | ||
1660 | |||
1661 | /* | ||
1662 | * Sessionid + seqid + slotid + max slotid + cache_this | ||
1663 | */ | ||
1664 | dprintk("%s: sessionid=%u:%u:%u:%u seqid=%d slotid=%d " | ||
1665 | "max_slotid=%d cache_this=%d\n", | ||
1666 | __func__, | ||
1667 | ((u32 *)session->sess_id.data)[0], | ||
1668 | ((u32 *)session->sess_id.data)[1], | ||
1669 | ((u32 *)session->sess_id.data)[2], | ||
1670 | ((u32 *)session->sess_id.data)[3], | ||
1671 | slot->seq_nr, args->sa_slotid, | ||
1672 | tp->highest_used_slotid, args->sa_cache_this); | ||
1673 | RESERVE_SPACE(NFS4_MAX_SESSIONID_LEN + 16); | ||
1674 | WRITEMEM(session->sess_id.data, NFS4_MAX_SESSIONID_LEN); | ||
1675 | WRITE32(slot->seq_nr); | ||
1676 | WRITE32(args->sa_slotid); | ||
1677 | WRITE32(tp->highest_used_slotid); | ||
1678 | WRITE32(args->sa_cache_this); | ||
1679 | hdr->nops++; | ||
1680 | hdr->replen += decode_sequence_maxsz; | ||
1681 | #endif /* CONFIG_NFS_V4_1 */ | ||
1682 | } | ||
1683 | |||
1343 | /* | 1684 | /* |
1344 | * END OF "GENERIC" ENCODE ROUTINES. | 1685 | * END OF "GENERIC" ENCODE ROUTINES. |
1345 | */ | 1686 | */ |
1346 | 1687 | ||
1688 | static u32 nfs4_xdr_minorversion(const struct nfs4_sequence_args *args) | ||
1689 | { | ||
1690 | #if defined(CONFIG_NFS_V4_1) | ||
1691 | if (args->sa_session) | ||
1692 | return args->sa_session->clp->cl_minorversion; | ||
1693 | #endif /* CONFIG_NFS_V4_1 */ | ||
1694 | return 0; | ||
1695 | } | ||
1696 | |||
1347 | /* | 1697 | /* |
1348 | * Encode an ACCESS request | 1698 | * Encode an ACCESS request |
1349 | */ | 1699 | */ |
@@ -1351,11 +1701,12 @@ static int nfs4_xdr_enc_access(struct rpc_rqst *req, __be32 *p, const struct nfs | |||
1351 | { | 1701 | { |
1352 | struct xdr_stream xdr; | 1702 | struct xdr_stream xdr; |
1353 | struct compound_hdr hdr = { | 1703 | struct compound_hdr hdr = { |
1354 | .nops = 0, | 1704 | .minorversion = nfs4_xdr_minorversion(&args->seq_args), |
1355 | }; | 1705 | }; |
1356 | 1706 | ||
1357 | xdr_init_encode(&xdr, &req->rq_snd_buf, p); | 1707 | xdr_init_encode(&xdr, &req->rq_snd_buf, p); |
1358 | encode_compound_hdr(&xdr, &hdr); | 1708 | encode_compound_hdr(&xdr, req, &hdr); |
1709 | encode_sequence(&xdr, &args->seq_args, &hdr); | ||
1359 | encode_putfh(&xdr, args->fh, &hdr); | 1710 | encode_putfh(&xdr, args->fh, &hdr); |
1360 | encode_access(&xdr, args->access, &hdr); | 1711 | encode_access(&xdr, args->access, &hdr); |
1361 | encode_getfattr(&xdr, args->bitmask, &hdr); | 1712 | encode_getfattr(&xdr, args->bitmask, &hdr); |
@@ -1370,11 +1721,12 @@ static int nfs4_xdr_enc_lookup(struct rpc_rqst *req, __be32 *p, const struct nfs | |||
1370 | { | 1721 | { |
1371 | struct xdr_stream xdr; | 1722 | struct xdr_stream xdr; |
1372 | struct compound_hdr hdr = { | 1723 | struct compound_hdr hdr = { |
1373 | .nops = 0, | 1724 | .minorversion = nfs4_xdr_minorversion(&args->seq_args), |
1374 | }; | 1725 | }; |
1375 | 1726 | ||
1376 | xdr_init_encode(&xdr, &req->rq_snd_buf, p); | 1727 | xdr_init_encode(&xdr, &req->rq_snd_buf, p); |
1377 | encode_compound_hdr(&xdr, &hdr); | 1728 | encode_compound_hdr(&xdr, req, &hdr); |
1729 | encode_sequence(&xdr, &args->seq_args, &hdr); | ||
1378 | encode_putfh(&xdr, args->dir_fh, &hdr); | 1730 | encode_putfh(&xdr, args->dir_fh, &hdr); |
1379 | encode_lookup(&xdr, args->name, &hdr); | 1731 | encode_lookup(&xdr, args->name, &hdr); |
1380 | encode_getfh(&xdr, &hdr); | 1732 | encode_getfh(&xdr, &hdr); |
@@ -1390,11 +1742,12 @@ static int nfs4_xdr_enc_lookup_root(struct rpc_rqst *req, __be32 *p, const struc | |||
1390 | { | 1742 | { |
1391 | struct xdr_stream xdr; | 1743 | struct xdr_stream xdr; |
1392 | struct compound_hdr hdr = { | 1744 | struct compound_hdr hdr = { |
1393 | .nops = 0, | 1745 | .minorversion = nfs4_xdr_minorversion(&args->seq_args), |
1394 | }; | 1746 | }; |
1395 | 1747 | ||
1396 | xdr_init_encode(&xdr, &req->rq_snd_buf, p); | 1748 | xdr_init_encode(&xdr, &req->rq_snd_buf, p); |
1397 | encode_compound_hdr(&xdr, &hdr); | 1749 | encode_compound_hdr(&xdr, req, &hdr); |
1750 | encode_sequence(&xdr, &args->seq_args, &hdr); | ||
1398 | encode_putrootfh(&xdr, &hdr); | 1751 | encode_putrootfh(&xdr, &hdr); |
1399 | encode_getfh(&xdr, &hdr); | 1752 | encode_getfh(&xdr, &hdr); |
1400 | encode_getfattr(&xdr, args->bitmask, &hdr); | 1753 | encode_getfattr(&xdr, args->bitmask, &hdr); |
@@ -1409,11 +1762,12 @@ static int nfs4_xdr_enc_remove(struct rpc_rqst *req, __be32 *p, const struct nfs | |||
1409 | { | 1762 | { |
1410 | struct xdr_stream xdr; | 1763 | struct xdr_stream xdr; |
1411 | struct compound_hdr hdr = { | 1764 | struct compound_hdr hdr = { |
1412 | .nops = 0, | 1765 | .minorversion = nfs4_xdr_minorversion(&args->seq_args), |
1413 | }; | 1766 | }; |
1414 | 1767 | ||
1415 | xdr_init_encode(&xdr, &req->rq_snd_buf, p); | 1768 | xdr_init_encode(&xdr, &req->rq_snd_buf, p); |
1416 | encode_compound_hdr(&xdr, &hdr); | 1769 | encode_compound_hdr(&xdr, req, &hdr); |
1770 | encode_sequence(&xdr, &args->seq_args, &hdr); | ||
1417 | encode_putfh(&xdr, args->fh, &hdr); | 1771 | encode_putfh(&xdr, args->fh, &hdr); |
1418 | encode_remove(&xdr, &args->name, &hdr); | 1772 | encode_remove(&xdr, &args->name, &hdr); |
1419 | encode_getfattr(&xdr, args->bitmask, &hdr); | 1773 | encode_getfattr(&xdr, args->bitmask, &hdr); |
@@ -1428,11 +1782,12 @@ static int nfs4_xdr_enc_rename(struct rpc_rqst *req, __be32 *p, const struct nfs | |||
1428 | { | 1782 | { |
1429 | struct xdr_stream xdr; | 1783 | struct xdr_stream xdr; |
1430 | struct compound_hdr hdr = { | 1784 | struct compound_hdr hdr = { |
1431 | .nops = 0, | 1785 | .minorversion = nfs4_xdr_minorversion(&args->seq_args), |
1432 | }; | 1786 | }; |
1433 | 1787 | ||
1434 | xdr_init_encode(&xdr, &req->rq_snd_buf, p); | 1788 | xdr_init_encode(&xdr, &req->rq_snd_buf, p); |
1435 | encode_compound_hdr(&xdr, &hdr); | 1789 | encode_compound_hdr(&xdr, req, &hdr); |
1790 | encode_sequence(&xdr, &args->seq_args, &hdr); | ||
1436 | encode_putfh(&xdr, args->old_dir, &hdr); | 1791 | encode_putfh(&xdr, args->old_dir, &hdr); |
1437 | encode_savefh(&xdr, &hdr); | 1792 | encode_savefh(&xdr, &hdr); |
1438 | encode_putfh(&xdr, args->new_dir, &hdr); | 1793 | encode_putfh(&xdr, args->new_dir, &hdr); |
@@ -1451,11 +1806,12 @@ static int nfs4_xdr_enc_link(struct rpc_rqst *req, __be32 *p, const struct nfs4_ | |||
1451 | { | 1806 | { |
1452 | struct xdr_stream xdr; | 1807 | struct xdr_stream xdr; |
1453 | struct compound_hdr hdr = { | 1808 | struct compound_hdr hdr = { |
1454 | .nops = 0, | 1809 | .minorversion = nfs4_xdr_minorversion(&args->seq_args), |
1455 | }; | 1810 | }; |
1456 | 1811 | ||
1457 | xdr_init_encode(&xdr, &req->rq_snd_buf, p); | 1812 | xdr_init_encode(&xdr, &req->rq_snd_buf, p); |
1458 | encode_compound_hdr(&xdr, &hdr); | 1813 | encode_compound_hdr(&xdr, req, &hdr); |
1814 | encode_sequence(&xdr, &args->seq_args, &hdr); | ||
1459 | encode_putfh(&xdr, args->fh, &hdr); | 1815 | encode_putfh(&xdr, args->fh, &hdr); |
1460 | encode_savefh(&xdr, &hdr); | 1816 | encode_savefh(&xdr, &hdr); |
1461 | encode_putfh(&xdr, args->dir_fh, &hdr); | 1817 | encode_putfh(&xdr, args->dir_fh, &hdr); |
@@ -1474,11 +1830,12 @@ static int nfs4_xdr_enc_create(struct rpc_rqst *req, __be32 *p, const struct nfs | |||
1474 | { | 1830 | { |
1475 | struct xdr_stream xdr; | 1831 | struct xdr_stream xdr; |
1476 | struct compound_hdr hdr = { | 1832 | struct compound_hdr hdr = { |
1477 | .nops = 0, | 1833 | .minorversion = nfs4_xdr_minorversion(&args->seq_args), |
1478 | }; | 1834 | }; |
1479 | 1835 | ||
1480 | xdr_init_encode(&xdr, &req->rq_snd_buf, p); | 1836 | xdr_init_encode(&xdr, &req->rq_snd_buf, p); |
1481 | encode_compound_hdr(&xdr, &hdr); | 1837 | encode_compound_hdr(&xdr, req, &hdr); |
1838 | encode_sequence(&xdr, &args->seq_args, &hdr); | ||
1482 | encode_putfh(&xdr, args->dir_fh, &hdr); | 1839 | encode_putfh(&xdr, args->dir_fh, &hdr); |
1483 | encode_savefh(&xdr, &hdr); | 1840 | encode_savefh(&xdr, &hdr); |
1484 | encode_create(&xdr, args, &hdr); | 1841 | encode_create(&xdr, args, &hdr); |
@@ -1505,11 +1862,12 @@ static int nfs4_xdr_enc_getattr(struct rpc_rqst *req, __be32 *p, const struct nf | |||
1505 | { | 1862 | { |
1506 | struct xdr_stream xdr; | 1863 | struct xdr_stream xdr; |
1507 | struct compound_hdr hdr = { | 1864 | struct compound_hdr hdr = { |
1508 | .nops = 0, | 1865 | .minorversion = nfs4_xdr_minorversion(&args->seq_args), |
1509 | }; | 1866 | }; |
1510 | 1867 | ||
1511 | xdr_init_encode(&xdr, &req->rq_snd_buf, p); | 1868 | xdr_init_encode(&xdr, &req->rq_snd_buf, p); |
1512 | encode_compound_hdr(&xdr, &hdr); | 1869 | encode_compound_hdr(&xdr, req, &hdr); |
1870 | encode_sequence(&xdr, &args->seq_args, &hdr); | ||
1513 | encode_putfh(&xdr, args->fh, &hdr); | 1871 | encode_putfh(&xdr, args->fh, &hdr); |
1514 | encode_getfattr(&xdr, args->bitmask, &hdr); | 1872 | encode_getfattr(&xdr, args->bitmask, &hdr); |
1515 | encode_nops(&hdr); | 1873 | encode_nops(&hdr); |
@@ -1523,11 +1881,12 @@ static int nfs4_xdr_enc_close(struct rpc_rqst *req, __be32 *p, struct nfs_closea | |||
1523 | { | 1881 | { |
1524 | struct xdr_stream xdr; | 1882 | struct xdr_stream xdr; |
1525 | struct compound_hdr hdr = { | 1883 | struct compound_hdr hdr = { |
1526 | .nops = 0, | 1884 | .minorversion = nfs4_xdr_minorversion(&args->seq_args), |
1527 | }; | 1885 | }; |
1528 | 1886 | ||
1529 | xdr_init_encode(&xdr, &req->rq_snd_buf, p); | 1887 | xdr_init_encode(&xdr, &req->rq_snd_buf, p); |
1530 | encode_compound_hdr(&xdr, &hdr); | 1888 | encode_compound_hdr(&xdr, req, &hdr); |
1889 | encode_sequence(&xdr, &args->seq_args, &hdr); | ||
1531 | encode_putfh(&xdr, args->fh, &hdr); | 1890 | encode_putfh(&xdr, args->fh, &hdr); |
1532 | encode_close(&xdr, args, &hdr); | 1891 | encode_close(&xdr, args, &hdr); |
1533 | encode_getfattr(&xdr, args->bitmask, &hdr); | 1892 | encode_getfattr(&xdr, args->bitmask, &hdr); |
@@ -1542,11 +1901,12 @@ static int nfs4_xdr_enc_open(struct rpc_rqst *req, __be32 *p, struct nfs_openarg | |||
1542 | { | 1901 | { |
1543 | struct xdr_stream xdr; | 1902 | struct xdr_stream xdr; |
1544 | struct compound_hdr hdr = { | 1903 | struct compound_hdr hdr = { |
1545 | .nops = 0, | 1904 | .minorversion = nfs4_xdr_minorversion(&args->seq_args), |
1546 | }; | 1905 | }; |
1547 | 1906 | ||
1548 | xdr_init_encode(&xdr, &req->rq_snd_buf, p); | 1907 | xdr_init_encode(&xdr, &req->rq_snd_buf, p); |
1549 | encode_compound_hdr(&xdr, &hdr); | 1908 | encode_compound_hdr(&xdr, req, &hdr); |
1909 | encode_sequence(&xdr, &args->seq_args, &hdr); | ||
1550 | encode_putfh(&xdr, args->fh, &hdr); | 1910 | encode_putfh(&xdr, args->fh, &hdr); |
1551 | encode_savefh(&xdr, &hdr); | 1911 | encode_savefh(&xdr, &hdr); |
1552 | encode_open(&xdr, args, &hdr); | 1912 | encode_open(&xdr, args, &hdr); |
@@ -1569,7 +1929,7 @@ static int nfs4_xdr_enc_open_confirm(struct rpc_rqst *req, __be32 *p, struct nfs | |||
1569 | }; | 1929 | }; |
1570 | 1930 | ||
1571 | xdr_init_encode(&xdr, &req->rq_snd_buf, p); | 1931 | xdr_init_encode(&xdr, &req->rq_snd_buf, p); |
1572 | encode_compound_hdr(&xdr, &hdr); | 1932 | encode_compound_hdr(&xdr, req, &hdr); |
1573 | encode_putfh(&xdr, args->fh, &hdr); | 1933 | encode_putfh(&xdr, args->fh, &hdr); |
1574 | encode_open_confirm(&xdr, args, &hdr); | 1934 | encode_open_confirm(&xdr, args, &hdr); |
1575 | encode_nops(&hdr); | 1935 | encode_nops(&hdr); |
@@ -1583,11 +1943,12 @@ static int nfs4_xdr_enc_open_noattr(struct rpc_rqst *req, __be32 *p, struct nfs_ | |||
1583 | { | 1943 | { |
1584 | struct xdr_stream xdr; | 1944 | struct xdr_stream xdr; |
1585 | struct compound_hdr hdr = { | 1945 | struct compound_hdr hdr = { |
1586 | .nops = 0, | 1946 | .minorversion = nfs4_xdr_minorversion(&args->seq_args), |
1587 | }; | 1947 | }; |
1588 | 1948 | ||
1589 | xdr_init_encode(&xdr, &req->rq_snd_buf, p); | 1949 | xdr_init_encode(&xdr, &req->rq_snd_buf, p); |
1590 | encode_compound_hdr(&xdr, &hdr); | 1950 | encode_compound_hdr(&xdr, req, &hdr); |
1951 | encode_sequence(&xdr, &args->seq_args, &hdr); | ||
1591 | encode_putfh(&xdr, args->fh, &hdr); | 1952 | encode_putfh(&xdr, args->fh, &hdr); |
1592 | encode_open(&xdr, args, &hdr); | 1953 | encode_open(&xdr, args, &hdr); |
1593 | encode_getfattr(&xdr, args->bitmask, &hdr); | 1954 | encode_getfattr(&xdr, args->bitmask, &hdr); |
@@ -1602,11 +1963,12 @@ static int nfs4_xdr_enc_open_downgrade(struct rpc_rqst *req, __be32 *p, struct n | |||
1602 | { | 1963 | { |
1603 | struct xdr_stream xdr; | 1964 | struct xdr_stream xdr; |
1604 | struct compound_hdr hdr = { | 1965 | struct compound_hdr hdr = { |
1605 | .nops = 0, | 1966 | .minorversion = nfs4_xdr_minorversion(&args->seq_args), |
1606 | }; | 1967 | }; |
1607 | 1968 | ||
1608 | xdr_init_encode(&xdr, &req->rq_snd_buf, p); | 1969 | xdr_init_encode(&xdr, &req->rq_snd_buf, p); |
1609 | encode_compound_hdr(&xdr, &hdr); | 1970 | encode_compound_hdr(&xdr, req, &hdr); |
1971 | encode_sequence(&xdr, &args->seq_args, &hdr); | ||
1610 | encode_putfh(&xdr, args->fh, &hdr); | 1972 | encode_putfh(&xdr, args->fh, &hdr); |
1611 | encode_open_downgrade(&xdr, args, &hdr); | 1973 | encode_open_downgrade(&xdr, args, &hdr); |
1612 | encode_getfattr(&xdr, args->bitmask, &hdr); | 1974 | encode_getfattr(&xdr, args->bitmask, &hdr); |
@@ -1621,11 +1983,12 @@ static int nfs4_xdr_enc_lock(struct rpc_rqst *req, __be32 *p, struct nfs_lock_ar | |||
1621 | { | 1983 | { |
1622 | struct xdr_stream xdr; | 1984 | struct xdr_stream xdr; |
1623 | struct compound_hdr hdr = { | 1985 | struct compound_hdr hdr = { |
1624 | .nops = 0, | 1986 | .minorversion = nfs4_xdr_minorversion(&args->seq_args), |
1625 | }; | 1987 | }; |
1626 | 1988 | ||
1627 | xdr_init_encode(&xdr, &req->rq_snd_buf, p); | 1989 | xdr_init_encode(&xdr, &req->rq_snd_buf, p); |
1628 | encode_compound_hdr(&xdr, &hdr); | 1990 | encode_compound_hdr(&xdr, req, &hdr); |
1991 | encode_sequence(&xdr, &args->seq_args, &hdr); | ||
1629 | encode_putfh(&xdr, args->fh, &hdr); | 1992 | encode_putfh(&xdr, args->fh, &hdr); |
1630 | encode_lock(&xdr, args, &hdr); | 1993 | encode_lock(&xdr, args, &hdr); |
1631 | encode_nops(&hdr); | 1994 | encode_nops(&hdr); |
@@ -1639,11 +2002,12 @@ static int nfs4_xdr_enc_lockt(struct rpc_rqst *req, __be32 *p, struct nfs_lockt_ | |||
1639 | { | 2002 | { |
1640 | struct xdr_stream xdr; | 2003 | struct xdr_stream xdr; |
1641 | struct compound_hdr hdr = { | 2004 | struct compound_hdr hdr = { |
1642 | .nops = 0, | 2005 | .minorversion = nfs4_xdr_minorversion(&args->seq_args), |
1643 | }; | 2006 | }; |
1644 | 2007 | ||
1645 | xdr_init_encode(&xdr, &req->rq_snd_buf, p); | 2008 | xdr_init_encode(&xdr, &req->rq_snd_buf, p); |
1646 | encode_compound_hdr(&xdr, &hdr); | 2009 | encode_compound_hdr(&xdr, req, &hdr); |
2010 | encode_sequence(&xdr, &args->seq_args, &hdr); | ||
1647 | encode_putfh(&xdr, args->fh, &hdr); | 2011 | encode_putfh(&xdr, args->fh, &hdr); |
1648 | encode_lockt(&xdr, args, &hdr); | 2012 | encode_lockt(&xdr, args, &hdr); |
1649 | encode_nops(&hdr); | 2013 | encode_nops(&hdr); |
@@ -1657,11 +2021,12 @@ static int nfs4_xdr_enc_locku(struct rpc_rqst *req, __be32 *p, struct nfs_locku_ | |||
1657 | { | 2021 | { |
1658 | struct xdr_stream xdr; | 2022 | struct xdr_stream xdr; |
1659 | struct compound_hdr hdr = { | 2023 | struct compound_hdr hdr = { |
1660 | .nops = 0, | 2024 | .minorversion = nfs4_xdr_minorversion(&args->seq_args), |
1661 | }; | 2025 | }; |
1662 | 2026 | ||
1663 | xdr_init_encode(&xdr, &req->rq_snd_buf, p); | 2027 | xdr_init_encode(&xdr, &req->rq_snd_buf, p); |
1664 | encode_compound_hdr(&xdr, &hdr); | 2028 | encode_compound_hdr(&xdr, req, &hdr); |
2029 | encode_sequence(&xdr, &args->seq_args, &hdr); | ||
1665 | encode_putfh(&xdr, args->fh, &hdr); | 2030 | encode_putfh(&xdr, args->fh, &hdr); |
1666 | encode_locku(&xdr, args, &hdr); | 2031 | encode_locku(&xdr, args, &hdr); |
1667 | encode_nops(&hdr); | 2032 | encode_nops(&hdr); |
@@ -1675,22 +2040,16 @@ static int nfs4_xdr_enc_readlink(struct rpc_rqst *req, __be32 *p, const struct n | |||
1675 | { | 2040 | { |
1676 | struct xdr_stream xdr; | 2041 | struct xdr_stream xdr; |
1677 | struct compound_hdr hdr = { | 2042 | struct compound_hdr hdr = { |
1678 | .nops = 0, | 2043 | .minorversion = nfs4_xdr_minorversion(&args->seq_args), |
1679 | }; | 2044 | }; |
1680 | struct rpc_auth *auth = req->rq_task->tk_msg.rpc_cred->cr_auth; | ||
1681 | unsigned int replen; | ||
1682 | 2045 | ||
1683 | xdr_init_encode(&xdr, &req->rq_snd_buf, p); | 2046 | xdr_init_encode(&xdr, &req->rq_snd_buf, p); |
1684 | encode_compound_hdr(&xdr, &hdr); | 2047 | encode_compound_hdr(&xdr, req, &hdr); |
2048 | encode_sequence(&xdr, &args->seq_args, &hdr); | ||
1685 | encode_putfh(&xdr, args->fh, &hdr); | 2049 | encode_putfh(&xdr, args->fh, &hdr); |
1686 | encode_readlink(&xdr, args, req, &hdr); | 2050 | encode_readlink(&xdr, args, req, &hdr); |
1687 | 2051 | ||
1688 | /* set up reply kvec | 2052 | xdr_inline_pages(&req->rq_rcv_buf, hdr.replen << 2, args->pages, |
1689 | * toplevel_status + taglen + rescount + OP_PUTFH + status | ||
1690 | * + OP_READLINK + status + string length = 8 | ||
1691 | */ | ||
1692 | replen = (RPC_REPHDRSIZE + auth->au_rslack + NFS4_dec_readlink_sz) << 2; | ||
1693 | xdr_inline_pages(&req->rq_rcv_buf, replen, args->pages, | ||
1694 | args->pgbase, args->pglen); | 2053 | args->pgbase, args->pglen); |
1695 | encode_nops(&hdr); | 2054 | encode_nops(&hdr); |
1696 | return 0; | 2055 | return 0; |
@@ -1703,25 +2062,19 @@ static int nfs4_xdr_enc_readdir(struct rpc_rqst *req, __be32 *p, const struct nf | |||
1703 | { | 2062 | { |
1704 | struct xdr_stream xdr; | 2063 | struct xdr_stream xdr; |
1705 | struct compound_hdr hdr = { | 2064 | struct compound_hdr hdr = { |
1706 | .nops = 0, | 2065 | .minorversion = nfs4_xdr_minorversion(&args->seq_args), |
1707 | }; | 2066 | }; |
1708 | struct rpc_auth *auth = req->rq_task->tk_msg.rpc_cred->cr_auth; | ||
1709 | int replen; | ||
1710 | 2067 | ||
1711 | xdr_init_encode(&xdr, &req->rq_snd_buf, p); | 2068 | xdr_init_encode(&xdr, &req->rq_snd_buf, p); |
1712 | encode_compound_hdr(&xdr, &hdr); | 2069 | encode_compound_hdr(&xdr, req, &hdr); |
2070 | encode_sequence(&xdr, &args->seq_args, &hdr); | ||
1713 | encode_putfh(&xdr, args->fh, &hdr); | 2071 | encode_putfh(&xdr, args->fh, &hdr); |
1714 | encode_readdir(&xdr, args, req, &hdr); | 2072 | encode_readdir(&xdr, args, req, &hdr); |
1715 | 2073 | ||
1716 | /* set up reply kvec | 2074 | xdr_inline_pages(&req->rq_rcv_buf, hdr.replen << 2, args->pages, |
1717 | * toplevel_status + taglen + rescount + OP_PUTFH + status | ||
1718 | * + OP_READDIR + status + verifer(2) = 9 | ||
1719 | */ | ||
1720 | replen = (RPC_REPHDRSIZE + auth->au_rslack + NFS4_dec_readdir_sz) << 2; | ||
1721 | xdr_inline_pages(&req->rq_rcv_buf, replen, args->pages, | ||
1722 | args->pgbase, args->count); | 2075 | args->pgbase, args->count); |
1723 | dprintk("%s: inlined page args = (%u, %p, %u, %u)\n", | 2076 | dprintk("%s: inlined page args = (%u, %p, %u, %u)\n", |
1724 | __func__, replen, args->pages, | 2077 | __func__, hdr.replen << 2, args->pages, |
1725 | args->pgbase, args->count); | 2078 | args->pgbase, args->count); |
1726 | encode_nops(&hdr); | 2079 | encode_nops(&hdr); |
1727 | return 0; | 2080 | return 0; |
@@ -1732,24 +2085,18 @@ static int nfs4_xdr_enc_readdir(struct rpc_rqst *req, __be32 *p, const struct nf | |||
1732 | */ | 2085 | */ |
1733 | static int nfs4_xdr_enc_read(struct rpc_rqst *req, __be32 *p, struct nfs_readargs *args) | 2086 | static int nfs4_xdr_enc_read(struct rpc_rqst *req, __be32 *p, struct nfs_readargs *args) |
1734 | { | 2087 | { |
1735 | struct rpc_auth *auth = req->rq_task->tk_msg.rpc_cred->cr_auth; | ||
1736 | struct xdr_stream xdr; | 2088 | struct xdr_stream xdr; |
1737 | struct compound_hdr hdr = { | 2089 | struct compound_hdr hdr = { |
1738 | .nops = 0, | 2090 | .minorversion = nfs4_xdr_minorversion(&args->seq_args), |
1739 | }; | 2091 | }; |
1740 | int replen; | ||
1741 | 2092 | ||
1742 | xdr_init_encode(&xdr, &req->rq_snd_buf, p); | 2093 | xdr_init_encode(&xdr, &req->rq_snd_buf, p); |
1743 | encode_compound_hdr(&xdr, &hdr); | 2094 | encode_compound_hdr(&xdr, req, &hdr); |
2095 | encode_sequence(&xdr, &args->seq_args, &hdr); | ||
1744 | encode_putfh(&xdr, args->fh, &hdr); | 2096 | encode_putfh(&xdr, args->fh, &hdr); |
1745 | encode_read(&xdr, args, &hdr); | 2097 | encode_read(&xdr, args, &hdr); |
1746 | 2098 | ||
1747 | /* set up reply kvec | 2099 | xdr_inline_pages(&req->rq_rcv_buf, hdr.replen << 2, |
1748 | * toplevel status + taglen=0 + rescount + OP_PUTFH + status | ||
1749 | * + OP_READ + status + eof + datalen = 9 | ||
1750 | */ | ||
1751 | replen = (RPC_REPHDRSIZE + auth->au_rslack + NFS4_dec_read_sz) << 2; | ||
1752 | xdr_inline_pages(&req->rq_rcv_buf, replen, | ||
1753 | args->pages, args->pgbase, args->count); | 2100 | args->pages, args->pgbase, args->count); |
1754 | req->rq_rcv_buf.flags |= XDRBUF_READ; | 2101 | req->rq_rcv_buf.flags |= XDRBUF_READ; |
1755 | encode_nops(&hdr); | 2102 | encode_nops(&hdr); |
@@ -1763,11 +2110,12 @@ static int nfs4_xdr_enc_setattr(struct rpc_rqst *req, __be32 *p, struct nfs_seta | |||
1763 | { | 2110 | { |
1764 | struct xdr_stream xdr; | 2111 | struct xdr_stream xdr; |
1765 | struct compound_hdr hdr = { | 2112 | struct compound_hdr hdr = { |
1766 | .nops = 0, | 2113 | .minorversion = nfs4_xdr_minorversion(&args->seq_args), |
1767 | }; | 2114 | }; |
1768 | 2115 | ||
1769 | xdr_init_encode(&xdr, &req->rq_snd_buf, p); | 2116 | xdr_init_encode(&xdr, &req->rq_snd_buf, p); |
1770 | encode_compound_hdr(&xdr, &hdr); | 2117 | encode_compound_hdr(&xdr, req, &hdr); |
2118 | encode_sequence(&xdr, &args->seq_args, &hdr); | ||
1771 | encode_putfh(&xdr, args->fh, &hdr); | 2119 | encode_putfh(&xdr, args->fh, &hdr); |
1772 | encode_setattr(&xdr, args, args->server, &hdr); | 2120 | encode_setattr(&xdr, args, args->server, &hdr); |
1773 | encode_getfattr(&xdr, args->bitmask, &hdr); | 2121 | encode_getfattr(&xdr, args->bitmask, &hdr); |
@@ -1783,20 +2131,19 @@ nfs4_xdr_enc_getacl(struct rpc_rqst *req, __be32 *p, | |||
1783 | struct nfs_getaclargs *args) | 2131 | struct nfs_getaclargs *args) |
1784 | { | 2132 | { |
1785 | struct xdr_stream xdr; | 2133 | struct xdr_stream xdr; |
1786 | struct rpc_auth *auth = req->rq_task->tk_msg.rpc_cred->cr_auth; | ||
1787 | struct compound_hdr hdr = { | 2134 | struct compound_hdr hdr = { |
1788 | .nops = 0, | 2135 | .minorversion = nfs4_xdr_minorversion(&args->seq_args), |
1789 | }; | 2136 | }; |
1790 | int replen; | 2137 | uint32_t replen; |
1791 | 2138 | ||
1792 | xdr_init_encode(&xdr, &req->rq_snd_buf, p); | 2139 | xdr_init_encode(&xdr, &req->rq_snd_buf, p); |
1793 | encode_compound_hdr(&xdr, &hdr); | 2140 | encode_compound_hdr(&xdr, req, &hdr); |
2141 | encode_sequence(&xdr, &args->seq_args, &hdr); | ||
1794 | encode_putfh(&xdr, args->fh, &hdr); | 2142 | encode_putfh(&xdr, args->fh, &hdr); |
2143 | replen = hdr.replen + nfs4_fattr_bitmap_maxsz + 1; | ||
1795 | encode_getattr_two(&xdr, FATTR4_WORD0_ACL, 0, &hdr); | 2144 | encode_getattr_two(&xdr, FATTR4_WORD0_ACL, 0, &hdr); |
1796 | 2145 | ||
1797 | /* set up reply buffer: */ | 2146 | xdr_inline_pages(&req->rq_rcv_buf, replen << 2, |
1798 | replen = (RPC_REPHDRSIZE + auth->au_rslack + NFS4_dec_getacl_sz) << 2; | ||
1799 | xdr_inline_pages(&req->rq_rcv_buf, replen, | ||
1800 | args->acl_pages, args->acl_pgbase, args->acl_len); | 2147 | args->acl_pages, args->acl_pgbase, args->acl_len); |
1801 | encode_nops(&hdr); | 2148 | encode_nops(&hdr); |
1802 | return 0; | 2149 | return 0; |
@@ -1809,11 +2156,12 @@ static int nfs4_xdr_enc_write(struct rpc_rqst *req, __be32 *p, struct nfs_writea | |||
1809 | { | 2156 | { |
1810 | struct xdr_stream xdr; | 2157 | struct xdr_stream xdr; |
1811 | struct compound_hdr hdr = { | 2158 | struct compound_hdr hdr = { |
1812 | .nops = 0, | 2159 | .minorversion = nfs4_xdr_minorversion(&args->seq_args), |
1813 | }; | 2160 | }; |
1814 | 2161 | ||
1815 | xdr_init_encode(&xdr, &req->rq_snd_buf, p); | 2162 | xdr_init_encode(&xdr, &req->rq_snd_buf, p); |
1816 | encode_compound_hdr(&xdr, &hdr); | 2163 | encode_compound_hdr(&xdr, req, &hdr); |
2164 | encode_sequence(&xdr, &args->seq_args, &hdr); | ||
1817 | encode_putfh(&xdr, args->fh, &hdr); | 2165 | encode_putfh(&xdr, args->fh, &hdr); |
1818 | encode_write(&xdr, args, &hdr); | 2166 | encode_write(&xdr, args, &hdr); |
1819 | req->rq_snd_buf.flags |= XDRBUF_WRITE; | 2167 | req->rq_snd_buf.flags |= XDRBUF_WRITE; |
@@ -1829,11 +2177,12 @@ static int nfs4_xdr_enc_commit(struct rpc_rqst *req, __be32 *p, struct nfs_write | |||
1829 | { | 2177 | { |
1830 | struct xdr_stream xdr; | 2178 | struct xdr_stream xdr; |
1831 | struct compound_hdr hdr = { | 2179 | struct compound_hdr hdr = { |
1832 | .nops = 0, | 2180 | .minorversion = nfs4_xdr_minorversion(&args->seq_args), |
1833 | }; | 2181 | }; |
1834 | 2182 | ||
1835 | xdr_init_encode(&xdr, &req->rq_snd_buf, p); | 2183 | xdr_init_encode(&xdr, &req->rq_snd_buf, p); |
1836 | encode_compound_hdr(&xdr, &hdr); | 2184 | encode_compound_hdr(&xdr, req, &hdr); |
2185 | encode_sequence(&xdr, &args->seq_args, &hdr); | ||
1837 | encode_putfh(&xdr, args->fh, &hdr); | 2186 | encode_putfh(&xdr, args->fh, &hdr); |
1838 | encode_commit(&xdr, args, &hdr); | 2187 | encode_commit(&xdr, args, &hdr); |
1839 | encode_getfattr(&xdr, args->bitmask, &hdr); | 2188 | encode_getfattr(&xdr, args->bitmask, &hdr); |
@@ -1848,11 +2197,12 @@ static int nfs4_xdr_enc_fsinfo(struct rpc_rqst *req, __be32 *p, struct nfs4_fsin | |||
1848 | { | 2197 | { |
1849 | struct xdr_stream xdr; | 2198 | struct xdr_stream xdr; |
1850 | struct compound_hdr hdr = { | 2199 | struct compound_hdr hdr = { |
1851 | .nops = 0, | 2200 | .minorversion = nfs4_xdr_minorversion(&args->seq_args), |
1852 | }; | 2201 | }; |
1853 | 2202 | ||
1854 | xdr_init_encode(&xdr, &req->rq_snd_buf, p); | 2203 | xdr_init_encode(&xdr, &req->rq_snd_buf, p); |
1855 | encode_compound_hdr(&xdr, &hdr); | 2204 | encode_compound_hdr(&xdr, req, &hdr); |
2205 | encode_sequence(&xdr, &args->seq_args, &hdr); | ||
1856 | encode_putfh(&xdr, args->fh, &hdr); | 2206 | encode_putfh(&xdr, args->fh, &hdr); |
1857 | encode_fsinfo(&xdr, args->bitmask, &hdr); | 2207 | encode_fsinfo(&xdr, args->bitmask, &hdr); |
1858 | encode_nops(&hdr); | 2208 | encode_nops(&hdr); |
@@ -1866,11 +2216,12 @@ static int nfs4_xdr_enc_pathconf(struct rpc_rqst *req, __be32 *p, const struct n | |||
1866 | { | 2216 | { |
1867 | struct xdr_stream xdr; | 2217 | struct xdr_stream xdr; |
1868 | struct compound_hdr hdr = { | 2218 | struct compound_hdr hdr = { |
1869 | .nops = 0, | 2219 | .minorversion = nfs4_xdr_minorversion(&args->seq_args), |
1870 | }; | 2220 | }; |
1871 | 2221 | ||
1872 | xdr_init_encode(&xdr, &req->rq_snd_buf, p); | 2222 | xdr_init_encode(&xdr, &req->rq_snd_buf, p); |
1873 | encode_compound_hdr(&xdr, &hdr); | 2223 | encode_compound_hdr(&xdr, req, &hdr); |
2224 | encode_sequence(&xdr, &args->seq_args, &hdr); | ||
1874 | encode_putfh(&xdr, args->fh, &hdr); | 2225 | encode_putfh(&xdr, args->fh, &hdr); |
1875 | encode_getattr_one(&xdr, args->bitmask[0] & nfs4_pathconf_bitmap[0], | 2226 | encode_getattr_one(&xdr, args->bitmask[0] & nfs4_pathconf_bitmap[0], |
1876 | &hdr); | 2227 | &hdr); |
@@ -1885,11 +2236,12 @@ static int nfs4_xdr_enc_statfs(struct rpc_rqst *req, __be32 *p, const struct nfs | |||
1885 | { | 2236 | { |
1886 | struct xdr_stream xdr; | 2237 | struct xdr_stream xdr; |
1887 | struct compound_hdr hdr = { | 2238 | struct compound_hdr hdr = { |
1888 | .nops = 0, | 2239 | .minorversion = nfs4_xdr_minorversion(&args->seq_args), |
1889 | }; | 2240 | }; |
1890 | 2241 | ||
1891 | xdr_init_encode(&xdr, &req->rq_snd_buf, p); | 2242 | xdr_init_encode(&xdr, &req->rq_snd_buf, p); |
1892 | encode_compound_hdr(&xdr, &hdr); | 2243 | encode_compound_hdr(&xdr, req, &hdr); |
2244 | encode_sequence(&xdr, &args->seq_args, &hdr); | ||
1893 | encode_putfh(&xdr, args->fh, &hdr); | 2245 | encode_putfh(&xdr, args->fh, &hdr); |
1894 | encode_getattr_two(&xdr, args->bitmask[0] & nfs4_statfs_bitmap[0], | 2246 | encode_getattr_two(&xdr, args->bitmask[0] & nfs4_statfs_bitmap[0], |
1895 | args->bitmask[1] & nfs4_statfs_bitmap[1], &hdr); | 2247 | args->bitmask[1] & nfs4_statfs_bitmap[1], &hdr); |
@@ -1900,16 +2252,18 @@ static int nfs4_xdr_enc_statfs(struct rpc_rqst *req, __be32 *p, const struct nfs | |||
1900 | /* | 2252 | /* |
1901 | * GETATTR_BITMAP request | 2253 | * GETATTR_BITMAP request |
1902 | */ | 2254 | */ |
1903 | static int nfs4_xdr_enc_server_caps(struct rpc_rqst *req, __be32 *p, const struct nfs_fh *fhandle) | 2255 | static int nfs4_xdr_enc_server_caps(struct rpc_rqst *req, __be32 *p, |
2256 | struct nfs4_server_caps_arg *args) | ||
1904 | { | 2257 | { |
1905 | struct xdr_stream xdr; | 2258 | struct xdr_stream xdr; |
1906 | struct compound_hdr hdr = { | 2259 | struct compound_hdr hdr = { |
1907 | .nops = 0, | 2260 | .minorversion = nfs4_xdr_minorversion(&args->seq_args), |
1908 | }; | 2261 | }; |
1909 | 2262 | ||
1910 | xdr_init_encode(&xdr, &req->rq_snd_buf, p); | 2263 | xdr_init_encode(&xdr, &req->rq_snd_buf, p); |
1911 | encode_compound_hdr(&xdr, &hdr); | 2264 | encode_compound_hdr(&xdr, req, &hdr); |
1912 | encode_putfh(&xdr, fhandle, &hdr); | 2265 | encode_sequence(&xdr, &args->seq_args, &hdr); |
2266 | encode_putfh(&xdr, args->fhandle, &hdr); | ||
1913 | encode_getattr_one(&xdr, FATTR4_WORD0_SUPPORTED_ATTRS| | 2267 | encode_getattr_one(&xdr, FATTR4_WORD0_SUPPORTED_ATTRS| |
1914 | FATTR4_WORD0_LINK_SUPPORT| | 2268 | FATTR4_WORD0_LINK_SUPPORT| |
1915 | FATTR4_WORD0_SYMLINK_SUPPORT| | 2269 | FATTR4_WORD0_SYMLINK_SUPPORT| |
@@ -1929,7 +2283,7 @@ static int nfs4_xdr_enc_renew(struct rpc_rqst *req, __be32 *p, struct nfs_client | |||
1929 | }; | 2283 | }; |
1930 | 2284 | ||
1931 | xdr_init_encode(&xdr, &req->rq_snd_buf, p); | 2285 | xdr_init_encode(&xdr, &req->rq_snd_buf, p); |
1932 | encode_compound_hdr(&xdr, &hdr); | 2286 | encode_compound_hdr(&xdr, req, &hdr); |
1933 | encode_renew(&xdr, clp, &hdr); | 2287 | encode_renew(&xdr, clp, &hdr); |
1934 | encode_nops(&hdr); | 2288 | encode_nops(&hdr); |
1935 | return 0; | 2289 | return 0; |
@@ -1946,7 +2300,7 @@ static int nfs4_xdr_enc_setclientid(struct rpc_rqst *req, __be32 *p, struct nfs4 | |||
1946 | }; | 2300 | }; |
1947 | 2301 | ||
1948 | xdr_init_encode(&xdr, &req->rq_snd_buf, p); | 2302 | xdr_init_encode(&xdr, &req->rq_snd_buf, p); |
1949 | encode_compound_hdr(&xdr, &hdr); | 2303 | encode_compound_hdr(&xdr, req, &hdr); |
1950 | encode_setclientid(&xdr, sc, &hdr); | 2304 | encode_setclientid(&xdr, sc, &hdr); |
1951 | encode_nops(&hdr); | 2305 | encode_nops(&hdr); |
1952 | return 0; | 2306 | return 0; |
@@ -1964,7 +2318,7 @@ static int nfs4_xdr_enc_setclientid_confirm(struct rpc_rqst *req, __be32 *p, str | |||
1964 | const u32 lease_bitmap[2] = { FATTR4_WORD0_LEASE_TIME, 0 }; | 2318 | const u32 lease_bitmap[2] = { FATTR4_WORD0_LEASE_TIME, 0 }; |
1965 | 2319 | ||
1966 | xdr_init_encode(&xdr, &req->rq_snd_buf, p); | 2320 | xdr_init_encode(&xdr, &req->rq_snd_buf, p); |
1967 | encode_compound_hdr(&xdr, &hdr); | 2321 | encode_compound_hdr(&xdr, req, &hdr); |
1968 | encode_setclientid_confirm(&xdr, clp, &hdr); | 2322 | encode_setclientid_confirm(&xdr, clp, &hdr); |
1969 | encode_putrootfh(&xdr, &hdr); | 2323 | encode_putrootfh(&xdr, &hdr); |
1970 | encode_fsinfo(&xdr, lease_bitmap, &hdr); | 2324 | encode_fsinfo(&xdr, lease_bitmap, &hdr); |
@@ -1979,11 +2333,12 @@ static int nfs4_xdr_enc_delegreturn(struct rpc_rqst *req, __be32 *p, const struc | |||
1979 | { | 2333 | { |
1980 | struct xdr_stream xdr; | 2334 | struct xdr_stream xdr; |
1981 | struct compound_hdr hdr = { | 2335 | struct compound_hdr hdr = { |
1982 | .nops = 0, | 2336 | .minorversion = nfs4_xdr_minorversion(&args->seq_args), |
1983 | }; | 2337 | }; |
1984 | 2338 | ||
1985 | xdr_init_encode(&xdr, &req->rq_snd_buf, p); | 2339 | xdr_init_encode(&xdr, &req->rq_snd_buf, p); |
1986 | encode_compound_hdr(&xdr, &hdr); | 2340 | encode_compound_hdr(&xdr, req, &hdr); |
2341 | encode_sequence(&xdr, &args->seq_args, &hdr); | ||
1987 | encode_putfh(&xdr, args->fhandle, &hdr); | 2342 | encode_putfh(&xdr, args->fhandle, &hdr); |
1988 | encode_delegreturn(&xdr, args->stateid, &hdr); | 2343 | encode_delegreturn(&xdr, args->stateid, &hdr); |
1989 | encode_getfattr(&xdr, args->bitmask, &hdr); | 2344 | encode_getfattr(&xdr, args->bitmask, &hdr); |
@@ -1998,28 +2353,119 @@ static int nfs4_xdr_enc_fs_locations(struct rpc_rqst *req, __be32 *p, struct nfs | |||
1998 | { | 2353 | { |
1999 | struct xdr_stream xdr; | 2354 | struct xdr_stream xdr; |
2000 | struct compound_hdr hdr = { | 2355 | struct compound_hdr hdr = { |
2001 | .nops = 0, | 2356 | .minorversion = nfs4_xdr_minorversion(&args->seq_args), |
2002 | }; | 2357 | }; |
2003 | struct rpc_auth *auth = req->rq_task->tk_msg.rpc_cred->cr_auth; | 2358 | uint32_t replen; |
2004 | int replen; | ||
2005 | 2359 | ||
2006 | xdr_init_encode(&xdr, &req->rq_snd_buf, p); | 2360 | xdr_init_encode(&xdr, &req->rq_snd_buf, p); |
2007 | encode_compound_hdr(&xdr, &hdr); | 2361 | encode_compound_hdr(&xdr, req, &hdr); |
2362 | encode_sequence(&xdr, &args->seq_args, &hdr); | ||
2008 | encode_putfh(&xdr, args->dir_fh, &hdr); | 2363 | encode_putfh(&xdr, args->dir_fh, &hdr); |
2009 | encode_lookup(&xdr, args->name, &hdr); | 2364 | encode_lookup(&xdr, args->name, &hdr); |
2365 | replen = hdr.replen; /* get the attribute into args->page */ | ||
2010 | encode_fs_locations(&xdr, args->bitmask, &hdr); | 2366 | encode_fs_locations(&xdr, args->bitmask, &hdr); |
2011 | 2367 | ||
2012 | /* set up reply | 2368 | xdr_inline_pages(&req->rq_rcv_buf, replen << 2, &args->page, |
2013 | * toplevel_status + OP_PUTFH + status | ||
2014 | * + OP_LOOKUP + status + OP_GETATTR + status = 7 | ||
2015 | */ | ||
2016 | replen = (RPC_REPHDRSIZE + auth->au_rslack + 7) << 2; | ||
2017 | xdr_inline_pages(&req->rq_rcv_buf, replen, &args->page, | ||
2018 | 0, PAGE_SIZE); | 2369 | 0, PAGE_SIZE); |
2019 | encode_nops(&hdr); | 2370 | encode_nops(&hdr); |
2020 | return 0; | 2371 | return 0; |
2021 | } | 2372 | } |
2022 | 2373 | ||
2374 | #if defined(CONFIG_NFS_V4_1) | ||
2375 | /* | ||
2376 | * EXCHANGE_ID request | ||
2377 | */ | ||
2378 | static int nfs4_xdr_enc_exchange_id(struct rpc_rqst *req, uint32_t *p, | ||
2379 | struct nfs41_exchange_id_args *args) | ||
2380 | { | ||
2381 | struct xdr_stream xdr; | ||
2382 | struct compound_hdr hdr = { | ||
2383 | .minorversion = args->client->cl_minorversion, | ||
2384 | }; | ||
2385 | |||
2386 | xdr_init_encode(&xdr, &req->rq_snd_buf, p); | ||
2387 | encode_compound_hdr(&xdr, req, &hdr); | ||
2388 | encode_exchange_id(&xdr, args, &hdr); | ||
2389 | encode_nops(&hdr); | ||
2390 | return 0; | ||
2391 | } | ||
2392 | |||
2393 | /* | ||
2394 | * a CREATE_SESSION request | ||
2395 | */ | ||
2396 | static int nfs4_xdr_enc_create_session(struct rpc_rqst *req, uint32_t *p, | ||
2397 | struct nfs41_create_session_args *args) | ||
2398 | { | ||
2399 | struct xdr_stream xdr; | ||
2400 | struct compound_hdr hdr = { | ||
2401 | .minorversion = args->client->cl_minorversion, | ||
2402 | }; | ||
2403 | |||
2404 | xdr_init_encode(&xdr, &req->rq_snd_buf, p); | ||
2405 | encode_compound_hdr(&xdr, req, &hdr); | ||
2406 | encode_create_session(&xdr, args, &hdr); | ||
2407 | encode_nops(&hdr); | ||
2408 | return 0; | ||
2409 | } | ||
2410 | |||
2411 | /* | ||
2412 | * a DESTROY_SESSION request | ||
2413 | */ | ||
2414 | static int nfs4_xdr_enc_destroy_session(struct rpc_rqst *req, uint32_t *p, | ||
2415 | struct nfs4_session *session) | ||
2416 | { | ||
2417 | struct xdr_stream xdr; | ||
2418 | struct compound_hdr hdr = { | ||
2419 | .minorversion = session->clp->cl_minorversion, | ||
2420 | }; | ||
2421 | |||
2422 | xdr_init_encode(&xdr, &req->rq_snd_buf, p); | ||
2423 | encode_compound_hdr(&xdr, req, &hdr); | ||
2424 | encode_destroy_session(&xdr, session, &hdr); | ||
2425 | encode_nops(&hdr); | ||
2426 | return 0; | ||
2427 | } | ||
2428 | |||
2429 | /* | ||
2430 | * a SEQUENCE request | ||
2431 | */ | ||
2432 | static int nfs4_xdr_enc_sequence(struct rpc_rqst *req, uint32_t *p, | ||
2433 | struct nfs4_sequence_args *args) | ||
2434 | { | ||
2435 | struct xdr_stream xdr; | ||
2436 | struct compound_hdr hdr = { | ||
2437 | .minorversion = nfs4_xdr_minorversion(args), | ||
2438 | }; | ||
2439 | |||
2440 | xdr_init_encode(&xdr, &req->rq_snd_buf, p); | ||
2441 | encode_compound_hdr(&xdr, req, &hdr); | ||
2442 | encode_sequence(&xdr, args, &hdr); | ||
2443 | encode_nops(&hdr); | ||
2444 | return 0; | ||
2445 | } | ||
2446 | |||
2447 | /* | ||
2448 | * a GET_LEASE_TIME request | ||
2449 | */ | ||
2450 | static int nfs4_xdr_enc_get_lease_time(struct rpc_rqst *req, uint32_t *p, | ||
2451 | struct nfs4_get_lease_time_args *args) | ||
2452 | { | ||
2453 | struct xdr_stream xdr; | ||
2454 | struct compound_hdr hdr = { | ||
2455 | .minorversion = nfs4_xdr_minorversion(&args->la_seq_args), | ||
2456 | }; | ||
2457 | const u32 lease_bitmap[2] = { FATTR4_WORD0_LEASE_TIME, 0 }; | ||
2458 | |||
2459 | xdr_init_encode(&xdr, &req->rq_snd_buf, p); | ||
2460 | encode_compound_hdr(&xdr, req, &hdr); | ||
2461 | encode_sequence(&xdr, &args->la_seq_args, &hdr); | ||
2462 | encode_putrootfh(&xdr, &hdr); | ||
2463 | encode_fsinfo(&xdr, lease_bitmap, &hdr); | ||
2464 | encode_nops(&hdr); | ||
2465 | return 0; | ||
2466 | } | ||
2467 | #endif /* CONFIG_NFS_V4_1 */ | ||
2468 | |||
2023 | /* | 2469 | /* |
2024 | * START OF "GENERIC" DECODE ROUTINES. | 2470 | * START OF "GENERIC" DECODE ROUTINES. |
2025 | * These may look a little ugly since they are imported from a "generic" | 2471 | * These may look a little ugly since they are imported from a "generic" |
@@ -3657,7 +4103,7 @@ decode_savefh(struct xdr_stream *xdr) | |||
3657 | return decode_op_hdr(xdr, OP_SAVEFH); | 4103 | return decode_op_hdr(xdr, OP_SAVEFH); |
3658 | } | 4104 | } |
3659 | 4105 | ||
3660 | static int decode_setattr(struct xdr_stream *xdr, struct nfs_setattrres *res) | 4106 | static int decode_setattr(struct xdr_stream *xdr) |
3661 | { | 4107 | { |
3662 | __be32 *p; | 4108 | __be32 *p; |
3663 | uint32_t bmlen; | 4109 | uint32_t bmlen; |
@@ -3735,6 +4181,169 @@ static int decode_delegreturn(struct xdr_stream *xdr) | |||
3735 | return decode_op_hdr(xdr, OP_DELEGRETURN); | 4181 | return decode_op_hdr(xdr, OP_DELEGRETURN); |
3736 | } | 4182 | } |
3737 | 4183 | ||
4184 | #if defined(CONFIG_NFS_V4_1) | ||
4185 | static int decode_exchange_id(struct xdr_stream *xdr, | ||
4186 | struct nfs41_exchange_id_res *res) | ||
4187 | { | ||
4188 | __be32 *p; | ||
4189 | uint32_t dummy; | ||
4190 | int status; | ||
4191 | struct nfs_client *clp = res->client; | ||
4192 | |||
4193 | status = decode_op_hdr(xdr, OP_EXCHANGE_ID); | ||
4194 | if (status) | ||
4195 | return status; | ||
4196 | |||
4197 | READ_BUF(8); | ||
4198 | READ64(clp->cl_ex_clid); | ||
4199 | READ_BUF(12); | ||
4200 | READ32(clp->cl_seqid); | ||
4201 | READ32(clp->cl_exchange_flags); | ||
4202 | |||
4203 | /* We ask for SP4_NONE */ | ||
4204 | READ32(dummy); | ||
4205 | if (dummy != SP4_NONE) | ||
4206 | return -EIO; | ||
4207 | |||
4208 | /* Throw away minor_id */ | ||
4209 | READ_BUF(8); | ||
4210 | |||
4211 | /* Throw away Major id */ | ||
4212 | READ_BUF(4); | ||
4213 | READ32(dummy); | ||
4214 | READ_BUF(dummy); | ||
4215 | |||
4216 | /* Throw away server_scope */ | ||
4217 | READ_BUF(4); | ||
4218 | READ32(dummy); | ||
4219 | READ_BUF(dummy); | ||
4220 | |||
4221 | /* Throw away Implementation id array */ | ||
4222 | READ_BUF(4); | ||
4223 | READ32(dummy); | ||
4224 | READ_BUF(dummy); | ||
4225 | |||
4226 | return 0; | ||
4227 | } | ||
4228 | |||
4229 | static int decode_chan_attrs(struct xdr_stream *xdr, | ||
4230 | struct nfs4_channel_attrs *attrs) | ||
4231 | { | ||
4232 | __be32 *p; | ||
4233 | u32 nr_attrs; | ||
4234 | |||
4235 | READ_BUF(28); | ||
4236 | READ32(attrs->headerpadsz); | ||
4237 | READ32(attrs->max_rqst_sz); | ||
4238 | READ32(attrs->max_resp_sz); | ||
4239 | READ32(attrs->max_resp_sz_cached); | ||
4240 | READ32(attrs->max_ops); | ||
4241 | READ32(attrs->max_reqs); | ||
4242 | READ32(nr_attrs); | ||
4243 | if (unlikely(nr_attrs > 1)) { | ||
4244 | printk(KERN_WARNING "%s: Invalid rdma channel attrs count %u\n", | ||
4245 | __func__, nr_attrs); | ||
4246 | return -EINVAL; | ||
4247 | } | ||
4248 | if (nr_attrs == 1) | ||
4249 | READ_BUF(4); /* skip rdma_attrs */ | ||
4250 | return 0; | ||
4251 | } | ||
4252 | |||
4253 | static int decode_create_session(struct xdr_stream *xdr, | ||
4254 | struct nfs41_create_session_res *res) | ||
4255 | { | ||
4256 | __be32 *p; | ||
4257 | int status; | ||
4258 | struct nfs_client *clp = res->client; | ||
4259 | struct nfs4_session *session = clp->cl_session; | ||
4260 | |||
4261 | status = decode_op_hdr(xdr, OP_CREATE_SESSION); | ||
4262 | |||
4263 | if (status) | ||
4264 | return status; | ||
4265 | |||
4266 | /* sessionid */ | ||
4267 | READ_BUF(NFS4_MAX_SESSIONID_LEN); | ||
4268 | COPYMEM(&session->sess_id, NFS4_MAX_SESSIONID_LEN); | ||
4269 | |||
4270 | /* seqid, flags */ | ||
4271 | READ_BUF(8); | ||
4272 | READ32(clp->cl_seqid); | ||
4273 | READ32(session->flags); | ||
4274 | |||
4275 | /* Channel attributes */ | ||
4276 | status = decode_chan_attrs(xdr, &session->fc_attrs); | ||
4277 | if (!status) | ||
4278 | status = decode_chan_attrs(xdr, &session->bc_attrs); | ||
4279 | return status; | ||
4280 | } | ||
4281 | |||
4282 | static int decode_destroy_session(struct xdr_stream *xdr, void *dummy) | ||
4283 | { | ||
4284 | return decode_op_hdr(xdr, OP_DESTROY_SESSION); | ||
4285 | } | ||
4286 | #endif /* CONFIG_NFS_V4_1 */ | ||
4287 | |||
4288 | static int decode_sequence(struct xdr_stream *xdr, | ||
4289 | struct nfs4_sequence_res *res, | ||
4290 | struct rpc_rqst *rqstp) | ||
4291 | { | ||
4292 | #if defined(CONFIG_NFS_V4_1) | ||
4293 | struct nfs4_slot *slot; | ||
4294 | struct nfs4_sessionid id; | ||
4295 | u32 dummy; | ||
4296 | int status; | ||
4297 | __be32 *p; | ||
4298 | |||
4299 | if (!res->sr_session) | ||
4300 | return 0; | ||
4301 | |||
4302 | status = decode_op_hdr(xdr, OP_SEQUENCE); | ||
4303 | if (status) | ||
4304 | goto out_err; | ||
4305 | |||
4306 | /* | ||
4307 | * If the server returns different values for sessionID, slotID or | ||
4308 | * sequence number, the server is looney tunes. | ||
4309 | */ | ||
4310 | status = -ESERVERFAULT; | ||
4311 | |||
4312 | slot = &res->sr_session->fc_slot_table.slots[res->sr_slotid]; | ||
4313 | READ_BUF(NFS4_MAX_SESSIONID_LEN + 20); | ||
4314 | COPYMEM(id.data, NFS4_MAX_SESSIONID_LEN); | ||
4315 | if (memcmp(id.data, res->sr_session->sess_id.data, | ||
4316 | NFS4_MAX_SESSIONID_LEN)) { | ||
4317 | dprintk("%s Invalid session id\n", __func__); | ||
4318 | goto out_err; | ||
4319 | } | ||
4320 | /* seqid */ | ||
4321 | READ32(dummy); | ||
4322 | if (dummy != slot->seq_nr) { | ||
4323 | dprintk("%s Invalid sequence number\n", __func__); | ||
4324 | goto out_err; | ||
4325 | } | ||
4326 | /* slot id */ | ||
4327 | READ32(dummy); | ||
4328 | if (dummy != res->sr_slotid) { | ||
4329 | dprintk("%s Invalid slot id\n", __func__); | ||
4330 | goto out_err; | ||
4331 | } | ||
4332 | /* highest slot id - currently not processed */ | ||
4333 | READ32(dummy); | ||
4334 | /* target highest slot id - currently not processed */ | ||
4335 | READ32(dummy); | ||
4336 | /* result flags - currently not processed */ | ||
4337 | READ32(dummy); | ||
4338 | status = 0; | ||
4339 | out_err: | ||
4340 | res->sr_status = status; | ||
4341 | return status; | ||
4342 | #else /* CONFIG_NFS_V4_1 */ | ||
4343 | return 0; | ||
4344 | #endif /* CONFIG_NFS_V4_1 */ | ||
4345 | } | ||
4346 | |||
3738 | /* | 4347 | /* |
3739 | * END OF "GENERIC" DECODE ROUTINES. | 4348 | * END OF "GENERIC" DECODE ROUTINES. |
3740 | */ | 4349 | */ |
@@ -3752,6 +4361,9 @@ static int nfs4_xdr_dec_open_downgrade(struct rpc_rqst *rqstp, __be32 *p, struct | |||
3752 | status = decode_compound_hdr(&xdr, &hdr); | 4361 | status = decode_compound_hdr(&xdr, &hdr); |
3753 | if (status) | 4362 | if (status) |
3754 | goto out; | 4363 | goto out; |
4364 | status = decode_sequence(&xdr, &res->seq_res, rqstp); | ||
4365 | if (status) | ||
4366 | goto out; | ||
3755 | status = decode_putfh(&xdr); | 4367 | status = decode_putfh(&xdr); |
3756 | if (status) | 4368 | if (status) |
3757 | goto out; | 4369 | goto out; |
@@ -3773,7 +4385,11 @@ static int nfs4_xdr_dec_access(struct rpc_rqst *rqstp, __be32 *p, struct nfs4_ac | |||
3773 | int status; | 4385 | int status; |
3774 | 4386 | ||
3775 | xdr_init_decode(&xdr, &rqstp->rq_rcv_buf, p); | 4387 | xdr_init_decode(&xdr, &rqstp->rq_rcv_buf, p); |
3776 | if ((status = decode_compound_hdr(&xdr, &hdr)) != 0) | 4388 | status = decode_compound_hdr(&xdr, &hdr); |
4389 | if (status) | ||
4390 | goto out; | ||
4391 | status = decode_sequence(&xdr, &res->seq_res, rqstp); | ||
4392 | if (status) | ||
3777 | goto out; | 4393 | goto out; |
3778 | status = decode_putfh(&xdr); | 4394 | status = decode_putfh(&xdr); |
3779 | if (status != 0) | 4395 | if (status != 0) |
@@ -3796,7 +4412,11 @@ static int nfs4_xdr_dec_lookup(struct rpc_rqst *rqstp, __be32 *p, struct nfs4_lo | |||
3796 | int status; | 4412 | int status; |
3797 | 4413 | ||
3798 | xdr_init_decode(&xdr, &rqstp->rq_rcv_buf, p); | 4414 | xdr_init_decode(&xdr, &rqstp->rq_rcv_buf, p); |
3799 | if ((status = decode_compound_hdr(&xdr, &hdr)) != 0) | 4415 | status = decode_compound_hdr(&xdr, &hdr); |
4416 | if (status) | ||
4417 | goto out; | ||
4418 | status = decode_sequence(&xdr, &res->seq_res, rqstp); | ||
4419 | if (status) | ||
3800 | goto out; | 4420 | goto out; |
3801 | if ((status = decode_putfh(&xdr)) != 0) | 4421 | if ((status = decode_putfh(&xdr)) != 0) |
3802 | goto out; | 4422 | goto out; |
@@ -3819,7 +4439,11 @@ static int nfs4_xdr_dec_lookup_root(struct rpc_rqst *rqstp, __be32 *p, struct nf | |||
3819 | int status; | 4439 | int status; |
3820 | 4440 | ||
3821 | xdr_init_decode(&xdr, &rqstp->rq_rcv_buf, p); | 4441 | xdr_init_decode(&xdr, &rqstp->rq_rcv_buf, p); |
3822 | if ((status = decode_compound_hdr(&xdr, &hdr)) != 0) | 4442 | status = decode_compound_hdr(&xdr, &hdr); |
4443 | if (status) | ||
4444 | goto out; | ||
4445 | status = decode_sequence(&xdr, &res->seq_res, rqstp); | ||
4446 | if (status) | ||
3823 | goto out; | 4447 | goto out; |
3824 | if ((status = decode_putrootfh(&xdr)) != 0) | 4448 | if ((status = decode_putrootfh(&xdr)) != 0) |
3825 | goto out; | 4449 | goto out; |
@@ -3839,7 +4463,11 @@ static int nfs4_xdr_dec_remove(struct rpc_rqst *rqstp, __be32 *p, struct nfs_rem | |||
3839 | int status; | 4463 | int status; |
3840 | 4464 | ||
3841 | xdr_init_decode(&xdr, &rqstp->rq_rcv_buf, p); | 4465 | xdr_init_decode(&xdr, &rqstp->rq_rcv_buf, p); |
3842 | if ((status = decode_compound_hdr(&xdr, &hdr)) != 0) | 4466 | status = decode_compound_hdr(&xdr, &hdr); |
4467 | if (status) | ||
4468 | goto out; | ||
4469 | status = decode_sequence(&xdr, &res->seq_res, rqstp); | ||
4470 | if (status) | ||
3843 | goto out; | 4471 | goto out; |
3844 | if ((status = decode_putfh(&xdr)) != 0) | 4472 | if ((status = decode_putfh(&xdr)) != 0) |
3845 | goto out; | 4473 | goto out; |
@@ -3860,7 +4488,11 @@ static int nfs4_xdr_dec_rename(struct rpc_rqst *rqstp, __be32 *p, struct nfs4_re | |||
3860 | int status; | 4488 | int status; |
3861 | 4489 | ||
3862 | xdr_init_decode(&xdr, &rqstp->rq_rcv_buf, p); | 4490 | xdr_init_decode(&xdr, &rqstp->rq_rcv_buf, p); |
3863 | if ((status = decode_compound_hdr(&xdr, &hdr)) != 0) | 4491 | status = decode_compound_hdr(&xdr, &hdr); |
4492 | if (status) | ||
4493 | goto out; | ||
4494 | status = decode_sequence(&xdr, &res->seq_res, rqstp); | ||
4495 | if (status) | ||
3864 | goto out; | 4496 | goto out; |
3865 | if ((status = decode_putfh(&xdr)) != 0) | 4497 | if ((status = decode_putfh(&xdr)) != 0) |
3866 | goto out; | 4498 | goto out; |
@@ -3890,7 +4522,11 @@ static int nfs4_xdr_dec_link(struct rpc_rqst *rqstp, __be32 *p, struct nfs4_link | |||
3890 | int status; | 4522 | int status; |
3891 | 4523 | ||
3892 | xdr_init_decode(&xdr, &rqstp->rq_rcv_buf, p); | 4524 | xdr_init_decode(&xdr, &rqstp->rq_rcv_buf, p); |
3893 | if ((status = decode_compound_hdr(&xdr, &hdr)) != 0) | 4525 | status = decode_compound_hdr(&xdr, &hdr); |
4526 | if (status) | ||
4527 | goto out; | ||
4528 | status = decode_sequence(&xdr, &res->seq_res, rqstp); | ||
4529 | if (status) | ||
3894 | goto out; | 4530 | goto out; |
3895 | if ((status = decode_putfh(&xdr)) != 0) | 4531 | if ((status = decode_putfh(&xdr)) != 0) |
3896 | goto out; | 4532 | goto out; |
@@ -3923,7 +4559,11 @@ static int nfs4_xdr_dec_create(struct rpc_rqst *rqstp, __be32 *p, struct nfs4_cr | |||
3923 | int status; | 4559 | int status; |
3924 | 4560 | ||
3925 | xdr_init_decode(&xdr, &rqstp->rq_rcv_buf, p); | 4561 | xdr_init_decode(&xdr, &rqstp->rq_rcv_buf, p); |
3926 | if ((status = decode_compound_hdr(&xdr, &hdr)) != 0) | 4562 | status = decode_compound_hdr(&xdr, &hdr); |
4563 | if (status) | ||
4564 | goto out; | ||
4565 | status = decode_sequence(&xdr, &res->seq_res, rqstp); | ||
4566 | if (status) | ||
3927 | goto out; | 4567 | goto out; |
3928 | if ((status = decode_putfh(&xdr)) != 0) | 4568 | if ((status = decode_putfh(&xdr)) != 0) |
3929 | goto out; | 4569 | goto out; |
@@ -3963,6 +4603,9 @@ static int nfs4_xdr_dec_getattr(struct rpc_rqst *rqstp, __be32 *p, struct nfs4_g | |||
3963 | status = decode_compound_hdr(&xdr, &hdr); | 4603 | status = decode_compound_hdr(&xdr, &hdr); |
3964 | if (status) | 4604 | if (status) |
3965 | goto out; | 4605 | goto out; |
4606 | status = decode_sequence(&xdr, &res->seq_res, rqstp); | ||
4607 | if (status) | ||
4608 | goto out; | ||
3966 | status = decode_putfh(&xdr); | 4609 | status = decode_putfh(&xdr); |
3967 | if (status) | 4610 | if (status) |
3968 | goto out; | 4611 | goto out; |
@@ -3979,12 +4622,13 @@ nfs4_xdr_enc_setacl(struct rpc_rqst *req, __be32 *p, struct nfs_setaclargs *args | |||
3979 | { | 4622 | { |
3980 | struct xdr_stream xdr; | 4623 | struct xdr_stream xdr; |
3981 | struct compound_hdr hdr = { | 4624 | struct compound_hdr hdr = { |
3982 | .nops = 0, | 4625 | .minorversion = nfs4_xdr_minorversion(&args->seq_args), |
3983 | }; | 4626 | }; |
3984 | int status; | 4627 | int status; |
3985 | 4628 | ||
3986 | xdr_init_encode(&xdr, &req->rq_snd_buf, p); | 4629 | xdr_init_encode(&xdr, &req->rq_snd_buf, p); |
3987 | encode_compound_hdr(&xdr, &hdr); | 4630 | encode_compound_hdr(&xdr, req, &hdr); |
4631 | encode_sequence(&xdr, &args->seq_args, &hdr); | ||
3988 | encode_putfh(&xdr, args->fh, &hdr); | 4632 | encode_putfh(&xdr, args->fh, &hdr); |
3989 | status = encode_setacl(&xdr, args, &hdr); | 4633 | status = encode_setacl(&xdr, args, &hdr); |
3990 | encode_nops(&hdr); | 4634 | encode_nops(&hdr); |
@@ -3995,7 +4639,8 @@ nfs4_xdr_enc_setacl(struct rpc_rqst *req, __be32 *p, struct nfs_setaclargs *args | |||
3995 | * Decode SETACL response | 4639 | * Decode SETACL response |
3996 | */ | 4640 | */ |
3997 | static int | 4641 | static int |
3998 | nfs4_xdr_dec_setacl(struct rpc_rqst *rqstp, __be32 *p, void *res) | 4642 | nfs4_xdr_dec_setacl(struct rpc_rqst *rqstp, __be32 *p, |
4643 | struct nfs_setaclres *res) | ||
3999 | { | 4644 | { |
4000 | struct xdr_stream xdr; | 4645 | struct xdr_stream xdr; |
4001 | struct compound_hdr hdr; | 4646 | struct compound_hdr hdr; |
@@ -4005,10 +4650,13 @@ nfs4_xdr_dec_setacl(struct rpc_rqst *rqstp, __be32 *p, void *res) | |||
4005 | status = decode_compound_hdr(&xdr, &hdr); | 4650 | status = decode_compound_hdr(&xdr, &hdr); |
4006 | if (status) | 4651 | if (status) |
4007 | goto out; | 4652 | goto out; |
4653 | status = decode_sequence(&xdr, &res->seq_res, rqstp); | ||
4654 | if (status) | ||
4655 | goto out; | ||
4008 | status = decode_putfh(&xdr); | 4656 | status = decode_putfh(&xdr); |
4009 | if (status) | 4657 | if (status) |
4010 | goto out; | 4658 | goto out; |
4011 | status = decode_setattr(&xdr, res); | 4659 | status = decode_setattr(&xdr); |
4012 | out: | 4660 | out: |
4013 | return status; | 4661 | return status; |
4014 | } | 4662 | } |
@@ -4017,7 +4665,8 @@ out: | |||
4017 | * Decode GETACL response | 4665 | * Decode GETACL response |
4018 | */ | 4666 | */ |
4019 | static int | 4667 | static int |
4020 | nfs4_xdr_dec_getacl(struct rpc_rqst *rqstp, __be32 *p, size_t *acl_len) | 4668 | nfs4_xdr_dec_getacl(struct rpc_rqst *rqstp, __be32 *p, |
4669 | struct nfs_getaclres *res) | ||
4021 | { | 4670 | { |
4022 | struct xdr_stream xdr; | 4671 | struct xdr_stream xdr; |
4023 | struct compound_hdr hdr; | 4672 | struct compound_hdr hdr; |
@@ -4027,10 +4676,13 @@ nfs4_xdr_dec_getacl(struct rpc_rqst *rqstp, __be32 *p, size_t *acl_len) | |||
4027 | status = decode_compound_hdr(&xdr, &hdr); | 4676 | status = decode_compound_hdr(&xdr, &hdr); |
4028 | if (status) | 4677 | if (status) |
4029 | goto out; | 4678 | goto out; |
4679 | status = decode_sequence(&xdr, &res->seq_res, rqstp); | ||
4680 | if (status) | ||
4681 | goto out; | ||
4030 | status = decode_putfh(&xdr); | 4682 | status = decode_putfh(&xdr); |
4031 | if (status) | 4683 | if (status) |
4032 | goto out; | 4684 | goto out; |
4033 | status = decode_getacl(&xdr, rqstp, acl_len); | 4685 | status = decode_getacl(&xdr, rqstp, &res->acl_len); |
4034 | 4686 | ||
4035 | out: | 4687 | out: |
4036 | return status; | 4688 | return status; |
@@ -4049,6 +4701,9 @@ static int nfs4_xdr_dec_close(struct rpc_rqst *rqstp, __be32 *p, struct nfs_clos | |||
4049 | status = decode_compound_hdr(&xdr, &hdr); | 4701 | status = decode_compound_hdr(&xdr, &hdr); |
4050 | if (status) | 4702 | if (status) |
4051 | goto out; | 4703 | goto out; |
4704 | status = decode_sequence(&xdr, &res->seq_res, rqstp); | ||
4705 | if (status) | ||
4706 | goto out; | ||
4052 | status = decode_putfh(&xdr); | 4707 | status = decode_putfh(&xdr); |
4053 | if (status) | 4708 | if (status) |
4054 | goto out; | 4709 | goto out; |
@@ -4079,6 +4734,9 @@ static int nfs4_xdr_dec_open(struct rpc_rqst *rqstp, __be32 *p, struct nfs_openr | |||
4079 | status = decode_compound_hdr(&xdr, &hdr); | 4734 | status = decode_compound_hdr(&xdr, &hdr); |
4080 | if (status) | 4735 | if (status) |
4081 | goto out; | 4736 | goto out; |
4737 | status = decode_sequence(&xdr, &res->seq_res, rqstp); | ||
4738 | if (status) | ||
4739 | goto out; | ||
4082 | status = decode_putfh(&xdr); | 4740 | status = decode_putfh(&xdr); |
4083 | if (status) | 4741 | if (status) |
4084 | goto out; | 4742 | goto out; |
@@ -4133,6 +4791,9 @@ static int nfs4_xdr_dec_open_noattr(struct rpc_rqst *rqstp, __be32 *p, struct nf | |||
4133 | status = decode_compound_hdr(&xdr, &hdr); | 4791 | status = decode_compound_hdr(&xdr, &hdr); |
4134 | if (status) | 4792 | if (status) |
4135 | goto out; | 4793 | goto out; |
4794 | status = decode_sequence(&xdr, &res->seq_res, rqstp); | ||
4795 | if (status) | ||
4796 | goto out; | ||
4136 | status = decode_putfh(&xdr); | 4797 | status = decode_putfh(&xdr); |
4137 | if (status) | 4798 | if (status) |
4138 | goto out; | 4799 | goto out; |
@@ -4157,10 +4818,13 @@ static int nfs4_xdr_dec_setattr(struct rpc_rqst *rqstp, __be32 *p, struct nfs_se | |||
4157 | status = decode_compound_hdr(&xdr, &hdr); | 4818 | status = decode_compound_hdr(&xdr, &hdr); |
4158 | if (status) | 4819 | if (status) |
4159 | goto out; | 4820 | goto out; |
4821 | status = decode_sequence(&xdr, &res->seq_res, rqstp); | ||
4822 | if (status) | ||
4823 | goto out; | ||
4160 | status = decode_putfh(&xdr); | 4824 | status = decode_putfh(&xdr); |
4161 | if (status) | 4825 | if (status) |
4162 | goto out; | 4826 | goto out; |
4163 | status = decode_setattr(&xdr, res); | 4827 | status = decode_setattr(&xdr); |
4164 | if (status) | 4828 | if (status) |
4165 | goto out; | 4829 | goto out; |
4166 | decode_getfattr(&xdr, res->fattr, res->server); | 4830 | decode_getfattr(&xdr, res->fattr, res->server); |
@@ -4181,6 +4845,9 @@ static int nfs4_xdr_dec_lock(struct rpc_rqst *rqstp, __be32 *p, struct nfs_lock_ | |||
4181 | status = decode_compound_hdr(&xdr, &hdr); | 4845 | status = decode_compound_hdr(&xdr, &hdr); |
4182 | if (status) | 4846 | if (status) |
4183 | goto out; | 4847 | goto out; |
4848 | status = decode_sequence(&xdr, &res->seq_res, rqstp); | ||
4849 | if (status) | ||
4850 | goto out; | ||
4184 | status = decode_putfh(&xdr); | 4851 | status = decode_putfh(&xdr); |
4185 | if (status) | 4852 | if (status) |
4186 | goto out; | 4853 | goto out; |
@@ -4202,6 +4869,9 @@ static int nfs4_xdr_dec_lockt(struct rpc_rqst *rqstp, __be32 *p, struct nfs_lock | |||
4202 | status = decode_compound_hdr(&xdr, &hdr); | 4869 | status = decode_compound_hdr(&xdr, &hdr); |
4203 | if (status) | 4870 | if (status) |
4204 | goto out; | 4871 | goto out; |
4872 | status = decode_sequence(&xdr, &res->seq_res, rqstp); | ||
4873 | if (status) | ||
4874 | goto out; | ||
4205 | status = decode_putfh(&xdr); | 4875 | status = decode_putfh(&xdr); |
4206 | if (status) | 4876 | if (status) |
4207 | goto out; | 4877 | goto out; |
@@ -4223,6 +4893,9 @@ static int nfs4_xdr_dec_locku(struct rpc_rqst *rqstp, __be32 *p, struct nfs_lock | |||
4223 | status = decode_compound_hdr(&xdr, &hdr); | 4893 | status = decode_compound_hdr(&xdr, &hdr); |
4224 | if (status) | 4894 | if (status) |
4225 | goto out; | 4895 | goto out; |
4896 | status = decode_sequence(&xdr, &res->seq_res, rqstp); | ||
4897 | if (status) | ||
4898 | goto out; | ||
4226 | status = decode_putfh(&xdr); | 4899 | status = decode_putfh(&xdr); |
4227 | if (status) | 4900 | if (status) |
4228 | goto out; | 4901 | goto out; |
@@ -4234,7 +4907,8 @@ out: | |||
4234 | /* | 4907 | /* |
4235 | * Decode READLINK response | 4908 | * Decode READLINK response |
4236 | */ | 4909 | */ |
4237 | static int nfs4_xdr_dec_readlink(struct rpc_rqst *rqstp, __be32 *p, void *res) | 4910 | static int nfs4_xdr_dec_readlink(struct rpc_rqst *rqstp, __be32 *p, |
4911 | struct nfs4_readlink_res *res) | ||
4238 | { | 4912 | { |
4239 | struct xdr_stream xdr; | 4913 | struct xdr_stream xdr; |
4240 | struct compound_hdr hdr; | 4914 | struct compound_hdr hdr; |
@@ -4244,6 +4918,9 @@ static int nfs4_xdr_dec_readlink(struct rpc_rqst *rqstp, __be32 *p, void *res) | |||
4244 | status = decode_compound_hdr(&xdr, &hdr); | 4918 | status = decode_compound_hdr(&xdr, &hdr); |
4245 | if (status) | 4919 | if (status) |
4246 | goto out; | 4920 | goto out; |
4921 | status = decode_sequence(&xdr, &res->seq_res, rqstp); | ||
4922 | if (status) | ||
4923 | goto out; | ||
4247 | status = decode_putfh(&xdr); | 4924 | status = decode_putfh(&xdr); |
4248 | if (status) | 4925 | if (status) |
4249 | goto out; | 4926 | goto out; |
@@ -4265,6 +4942,9 @@ static int nfs4_xdr_dec_readdir(struct rpc_rqst *rqstp, __be32 *p, struct nfs4_r | |||
4265 | status = decode_compound_hdr(&xdr, &hdr); | 4942 | status = decode_compound_hdr(&xdr, &hdr); |
4266 | if (status) | 4943 | if (status) |
4267 | goto out; | 4944 | goto out; |
4945 | status = decode_sequence(&xdr, &res->seq_res, rqstp); | ||
4946 | if (status) | ||
4947 | goto out; | ||
4268 | status = decode_putfh(&xdr); | 4948 | status = decode_putfh(&xdr); |
4269 | if (status) | 4949 | if (status) |
4270 | goto out; | 4950 | goto out; |
@@ -4286,6 +4966,9 @@ static int nfs4_xdr_dec_read(struct rpc_rqst *rqstp, __be32 *p, struct nfs_readr | |||
4286 | status = decode_compound_hdr(&xdr, &hdr); | 4966 | status = decode_compound_hdr(&xdr, &hdr); |
4287 | if (status) | 4967 | if (status) |
4288 | goto out; | 4968 | goto out; |
4969 | status = decode_sequence(&xdr, &res->seq_res, rqstp); | ||
4970 | if (status) | ||
4971 | goto out; | ||
4289 | status = decode_putfh(&xdr); | 4972 | status = decode_putfh(&xdr); |
4290 | if (status) | 4973 | if (status) |
4291 | goto out; | 4974 | goto out; |
@@ -4309,6 +4992,9 @@ static int nfs4_xdr_dec_write(struct rpc_rqst *rqstp, __be32 *p, struct nfs_writ | |||
4309 | status = decode_compound_hdr(&xdr, &hdr); | 4992 | status = decode_compound_hdr(&xdr, &hdr); |
4310 | if (status) | 4993 | if (status) |
4311 | goto out; | 4994 | goto out; |
4995 | status = decode_sequence(&xdr, &res->seq_res, rqstp); | ||
4996 | if (status) | ||
4997 | goto out; | ||
4312 | status = decode_putfh(&xdr); | 4998 | status = decode_putfh(&xdr); |
4313 | if (status) | 4999 | if (status) |
4314 | goto out; | 5000 | goto out; |
@@ -4335,6 +5021,9 @@ static int nfs4_xdr_dec_commit(struct rpc_rqst *rqstp, __be32 *p, struct nfs_wri | |||
4335 | status = decode_compound_hdr(&xdr, &hdr); | 5021 | status = decode_compound_hdr(&xdr, &hdr); |
4336 | if (status) | 5022 | if (status) |
4337 | goto out; | 5023 | goto out; |
5024 | status = decode_sequence(&xdr, &res->seq_res, rqstp); | ||
5025 | if (status) | ||
5026 | goto out; | ||
4338 | status = decode_putfh(&xdr); | 5027 | status = decode_putfh(&xdr); |
4339 | if (status) | 5028 | if (status) |
4340 | goto out; | 5029 | goto out; |
@@ -4349,7 +5038,8 @@ out: | |||
4349 | /* | 5038 | /* |
4350 | * FSINFO request | 5039 | * FSINFO request |
4351 | */ | 5040 | */ |
4352 | static int nfs4_xdr_dec_fsinfo(struct rpc_rqst *req, __be32 *p, struct nfs_fsinfo *fsinfo) | 5041 | static int nfs4_xdr_dec_fsinfo(struct rpc_rqst *req, __be32 *p, |
5042 | struct nfs4_fsinfo_res *res) | ||
4353 | { | 5043 | { |
4354 | struct xdr_stream xdr; | 5044 | struct xdr_stream xdr; |
4355 | struct compound_hdr hdr; | 5045 | struct compound_hdr hdr; |
@@ -4358,16 +5048,19 @@ static int nfs4_xdr_dec_fsinfo(struct rpc_rqst *req, __be32 *p, struct nfs_fsinf | |||
4358 | xdr_init_decode(&xdr, &req->rq_rcv_buf, p); | 5048 | xdr_init_decode(&xdr, &req->rq_rcv_buf, p); |
4359 | status = decode_compound_hdr(&xdr, &hdr); | 5049 | status = decode_compound_hdr(&xdr, &hdr); |
4360 | if (!status) | 5050 | if (!status) |
5051 | status = decode_sequence(&xdr, &res->seq_res, req); | ||
5052 | if (!status) | ||
4361 | status = decode_putfh(&xdr); | 5053 | status = decode_putfh(&xdr); |
4362 | if (!status) | 5054 | if (!status) |
4363 | status = decode_fsinfo(&xdr, fsinfo); | 5055 | status = decode_fsinfo(&xdr, res->fsinfo); |
4364 | return status; | 5056 | return status; |
4365 | } | 5057 | } |
4366 | 5058 | ||
4367 | /* | 5059 | /* |
4368 | * PATHCONF request | 5060 | * PATHCONF request |
4369 | */ | 5061 | */ |
4370 | static int nfs4_xdr_dec_pathconf(struct rpc_rqst *req, __be32 *p, struct nfs_pathconf *pathconf) | 5062 | static int nfs4_xdr_dec_pathconf(struct rpc_rqst *req, __be32 *p, |
5063 | struct nfs4_pathconf_res *res) | ||
4371 | { | 5064 | { |
4372 | struct xdr_stream xdr; | 5065 | struct xdr_stream xdr; |
4373 | struct compound_hdr hdr; | 5066 | struct compound_hdr hdr; |
@@ -4376,16 +5069,19 @@ static int nfs4_xdr_dec_pathconf(struct rpc_rqst *req, __be32 *p, struct nfs_pat | |||
4376 | xdr_init_decode(&xdr, &req->rq_rcv_buf, p); | 5069 | xdr_init_decode(&xdr, &req->rq_rcv_buf, p); |
4377 | status = decode_compound_hdr(&xdr, &hdr); | 5070 | status = decode_compound_hdr(&xdr, &hdr); |
4378 | if (!status) | 5071 | if (!status) |
5072 | status = decode_sequence(&xdr, &res->seq_res, req); | ||
5073 | if (!status) | ||
4379 | status = decode_putfh(&xdr); | 5074 | status = decode_putfh(&xdr); |
4380 | if (!status) | 5075 | if (!status) |
4381 | status = decode_pathconf(&xdr, pathconf); | 5076 | status = decode_pathconf(&xdr, res->pathconf); |
4382 | return status; | 5077 | return status; |
4383 | } | 5078 | } |
4384 | 5079 | ||
4385 | /* | 5080 | /* |
4386 | * STATFS request | 5081 | * STATFS request |
4387 | */ | 5082 | */ |
4388 | static int nfs4_xdr_dec_statfs(struct rpc_rqst *req, __be32 *p, struct nfs_fsstat *fsstat) | 5083 | static int nfs4_xdr_dec_statfs(struct rpc_rqst *req, __be32 *p, |
5084 | struct nfs4_statfs_res *res) | ||
4389 | { | 5085 | { |
4390 | struct xdr_stream xdr; | 5086 | struct xdr_stream xdr; |
4391 | struct compound_hdr hdr; | 5087 | struct compound_hdr hdr; |
@@ -4394,9 +5090,11 @@ static int nfs4_xdr_dec_statfs(struct rpc_rqst *req, __be32 *p, struct nfs_fssta | |||
4394 | xdr_init_decode(&xdr, &req->rq_rcv_buf, p); | 5090 | xdr_init_decode(&xdr, &req->rq_rcv_buf, p); |
4395 | status = decode_compound_hdr(&xdr, &hdr); | 5091 | status = decode_compound_hdr(&xdr, &hdr); |
4396 | if (!status) | 5092 | if (!status) |
5093 | status = decode_sequence(&xdr, &res->seq_res, req); | ||
5094 | if (!status) | ||
4397 | status = decode_putfh(&xdr); | 5095 | status = decode_putfh(&xdr); |
4398 | if (!status) | 5096 | if (!status) |
4399 | status = decode_statfs(&xdr, fsstat); | 5097 | status = decode_statfs(&xdr, res->fsstat); |
4400 | return status; | 5098 | return status; |
4401 | } | 5099 | } |
4402 | 5100 | ||
@@ -4410,7 +5108,11 @@ static int nfs4_xdr_dec_server_caps(struct rpc_rqst *req, __be32 *p, struct nfs4 | |||
4410 | int status; | 5108 | int status; |
4411 | 5109 | ||
4412 | xdr_init_decode(&xdr, &req->rq_rcv_buf, p); | 5110 | xdr_init_decode(&xdr, &req->rq_rcv_buf, p); |
4413 | if ((status = decode_compound_hdr(&xdr, &hdr)) != 0) | 5111 | status = decode_compound_hdr(&xdr, &hdr); |
5112 | if (status) | ||
5113 | goto out; | ||
5114 | status = decode_sequence(&xdr, &res->seq_res, req); | ||
5115 | if (status) | ||
4414 | goto out; | 5116 | goto out; |
4415 | if ((status = decode_putfh(&xdr)) != 0) | 5117 | if ((status = decode_putfh(&xdr)) != 0) |
4416 | goto out; | 5118 | goto out; |
@@ -4483,7 +5185,10 @@ static int nfs4_xdr_dec_delegreturn(struct rpc_rqst *rqstp, __be32 *p, struct nf | |||
4483 | 5185 | ||
4484 | xdr_init_decode(&xdr, &rqstp->rq_rcv_buf, p); | 5186 | xdr_init_decode(&xdr, &rqstp->rq_rcv_buf, p); |
4485 | status = decode_compound_hdr(&xdr, &hdr); | 5187 | status = decode_compound_hdr(&xdr, &hdr); |
4486 | if (status != 0) | 5188 | if (status) |
5189 | goto out; | ||
5190 | status = decode_sequence(&xdr, &res->seq_res, rqstp); | ||
5191 | if (status) | ||
4487 | goto out; | 5192 | goto out; |
4488 | status = decode_putfh(&xdr); | 5193 | status = decode_putfh(&xdr); |
4489 | if (status != 0) | 5194 | if (status != 0) |
@@ -4497,7 +5202,8 @@ out: | |||
4497 | /* | 5202 | /* |
4498 | * FS_LOCATIONS request | 5203 | * FS_LOCATIONS request |
4499 | */ | 5204 | */ |
4500 | static int nfs4_xdr_dec_fs_locations(struct rpc_rqst *req, __be32 *p, struct nfs4_fs_locations *res) | 5205 | static int nfs4_xdr_dec_fs_locations(struct rpc_rqst *req, __be32 *p, |
5206 | struct nfs4_fs_locations_res *res) | ||
4501 | { | 5207 | { |
4502 | struct xdr_stream xdr; | 5208 | struct xdr_stream xdr; |
4503 | struct compound_hdr hdr; | 5209 | struct compound_hdr hdr; |
@@ -4505,18 +5211,113 @@ static int nfs4_xdr_dec_fs_locations(struct rpc_rqst *req, __be32 *p, struct nfs | |||
4505 | 5211 | ||
4506 | xdr_init_decode(&xdr, &req->rq_rcv_buf, p); | 5212 | xdr_init_decode(&xdr, &req->rq_rcv_buf, p); |
4507 | status = decode_compound_hdr(&xdr, &hdr); | 5213 | status = decode_compound_hdr(&xdr, &hdr); |
4508 | if (status != 0) | 5214 | if (status) |
5215 | goto out; | ||
5216 | status = decode_sequence(&xdr, &res->seq_res, req); | ||
5217 | if (status) | ||
4509 | goto out; | 5218 | goto out; |
4510 | if ((status = decode_putfh(&xdr)) != 0) | 5219 | if ((status = decode_putfh(&xdr)) != 0) |
4511 | goto out; | 5220 | goto out; |
4512 | if ((status = decode_lookup(&xdr)) != 0) | 5221 | if ((status = decode_lookup(&xdr)) != 0) |
4513 | goto out; | 5222 | goto out; |
4514 | xdr_enter_page(&xdr, PAGE_SIZE); | 5223 | xdr_enter_page(&xdr, PAGE_SIZE); |
4515 | status = decode_getfattr(&xdr, &res->fattr, res->server); | 5224 | status = decode_getfattr(&xdr, &res->fs_locations->fattr, |
5225 | res->fs_locations->server); | ||
4516 | out: | 5226 | out: |
4517 | return status; | 5227 | return status; |
4518 | } | 5228 | } |
4519 | 5229 | ||
5230 | #if defined(CONFIG_NFS_V4_1) | ||
5231 | /* | ||
5232 | * EXCHANGE_ID request | ||
5233 | */ | ||
5234 | static int nfs4_xdr_dec_exchange_id(struct rpc_rqst *rqstp, uint32_t *p, | ||
5235 | void *res) | ||
5236 | { | ||
5237 | struct xdr_stream xdr; | ||
5238 | struct compound_hdr hdr; | ||
5239 | int status; | ||
5240 | |||
5241 | xdr_init_decode(&xdr, &rqstp->rq_rcv_buf, p); | ||
5242 | status = decode_compound_hdr(&xdr, &hdr); | ||
5243 | if (!status) | ||
5244 | status = decode_exchange_id(&xdr, res); | ||
5245 | return status; | ||
5246 | } | ||
5247 | |||
5248 | /* | ||
5249 | * a CREATE_SESSION request | ||
5250 | */ | ||
5251 | static int nfs4_xdr_dec_create_session(struct rpc_rqst *rqstp, uint32_t *p, | ||
5252 | struct nfs41_create_session_res *res) | ||
5253 | { | ||
5254 | struct xdr_stream xdr; | ||
5255 | struct compound_hdr hdr; | ||
5256 | int status; | ||
5257 | |||
5258 | xdr_init_decode(&xdr, &rqstp->rq_rcv_buf, p); | ||
5259 | status = decode_compound_hdr(&xdr, &hdr); | ||
5260 | if (!status) | ||
5261 | status = decode_create_session(&xdr, res); | ||
5262 | return status; | ||
5263 | } | ||
5264 | |||
5265 | /* | ||
5266 | * a DESTROY_SESSION request | ||
5267 | */ | ||
5268 | static int nfs4_xdr_dec_destroy_session(struct rpc_rqst *rqstp, uint32_t *p, | ||
5269 | void *dummy) | ||
5270 | { | ||
5271 | struct xdr_stream xdr; | ||
5272 | struct compound_hdr hdr; | ||
5273 | int status; | ||
5274 | |||
5275 | xdr_init_decode(&xdr, &rqstp->rq_rcv_buf, p); | ||
5276 | status = decode_compound_hdr(&xdr, &hdr); | ||
5277 | if (!status) | ||
5278 | status = decode_destroy_session(&xdr, dummy); | ||
5279 | return status; | ||
5280 | } | ||
5281 | |||
5282 | /* | ||
5283 | * a SEQUENCE request | ||
5284 | */ | ||
5285 | static int nfs4_xdr_dec_sequence(struct rpc_rqst *rqstp, uint32_t *p, | ||
5286 | struct nfs4_sequence_res *res) | ||
5287 | { | ||
5288 | struct xdr_stream xdr; | ||
5289 | struct compound_hdr hdr; | ||
5290 | int status; | ||
5291 | |||
5292 | xdr_init_decode(&xdr, &rqstp->rq_rcv_buf, p); | ||
5293 | status = decode_compound_hdr(&xdr, &hdr); | ||
5294 | if (!status) | ||
5295 | status = decode_sequence(&xdr, res, rqstp); | ||
5296 | return status; | ||
5297 | } | ||
5298 | |||
5299 | /* | ||
5300 | * a GET_LEASE_TIME request | ||
5301 | */ | ||
5302 | static int nfs4_xdr_dec_get_lease_time(struct rpc_rqst *rqstp, uint32_t *p, | ||
5303 | struct nfs4_get_lease_time_res *res) | ||
5304 | { | ||
5305 | struct xdr_stream xdr; | ||
5306 | struct compound_hdr hdr; | ||
5307 | int status; | ||
5308 | |||
5309 | xdr_init_decode(&xdr, &rqstp->rq_rcv_buf, p); | ||
5310 | status = decode_compound_hdr(&xdr, &hdr); | ||
5311 | if (!status) | ||
5312 | status = decode_sequence(&xdr, &res->lr_seq_res, rqstp); | ||
5313 | if (!status) | ||
5314 | status = decode_putrootfh(&xdr); | ||
5315 | if (!status) | ||
5316 | status = decode_fsinfo(&xdr, res->lr_fsinfo); | ||
5317 | return status; | ||
5318 | } | ||
5319 | #endif /* CONFIG_NFS_V4_1 */ | ||
5320 | |||
4520 | __be32 *nfs4_decode_dirent(__be32 *p, struct nfs_entry *entry, int plus) | 5321 | __be32 *nfs4_decode_dirent(__be32 *p, struct nfs_entry *entry, int plus) |
4521 | { | 5322 | { |
4522 | uint32_t bitmap[2] = {0}; | 5323 | uint32_t bitmap[2] = {0}; |
@@ -4686,6 +5487,13 @@ struct rpc_procinfo nfs4_procedures[] = { | |||
4686 | PROC(GETACL, enc_getacl, dec_getacl), | 5487 | PROC(GETACL, enc_getacl, dec_getacl), |
4687 | PROC(SETACL, enc_setacl, dec_setacl), | 5488 | PROC(SETACL, enc_setacl, dec_setacl), |
4688 | PROC(FS_LOCATIONS, enc_fs_locations, dec_fs_locations), | 5489 | PROC(FS_LOCATIONS, enc_fs_locations, dec_fs_locations), |
5490 | #if defined(CONFIG_NFS_V4_1) | ||
5491 | PROC(EXCHANGE_ID, enc_exchange_id, dec_exchange_id), | ||
5492 | PROC(CREATE_SESSION, enc_create_session, dec_create_session), | ||
5493 | PROC(DESTROY_SESSION, enc_destroy_session, dec_destroy_session), | ||
5494 | PROC(SEQUENCE, enc_sequence, dec_sequence), | ||
5495 | PROC(GET_LEASE_TIME, enc_get_lease_time, dec_get_lease_time), | ||
5496 | #endif /* CONFIG_NFS_V4_1 */ | ||
4689 | }; | 5497 | }; |
4690 | 5498 | ||
4691 | struct rpc_version nfs_version4 = { | 5499 | struct rpc_version nfs_version4 = { |
diff --git a/fs/nfs/nfsroot.c b/fs/nfs/nfsroot.c index e3ed5908820b..8c55b27c0de4 100644 --- a/fs/nfs/nfsroot.c +++ b/fs/nfs/nfsroot.c | |||
@@ -92,6 +92,9 @@ | |||
92 | #undef NFSROOT_DEBUG | 92 | #undef NFSROOT_DEBUG |
93 | #define NFSDBG_FACILITY NFSDBG_ROOT | 93 | #define NFSDBG_FACILITY NFSDBG_ROOT |
94 | 94 | ||
95 | /* Default port to use if server is not running a portmapper */ | ||
96 | #define NFS_MNT_PORT 627 | ||
97 | |||
95 | /* Default path we try to mount. "%s" gets replaced by our IP address */ | 98 | /* Default path we try to mount. "%s" gets replaced by our IP address */ |
96 | #define NFS_ROOT "/tftpboot/%s" | 99 | #define NFS_ROOT "/tftpboot/%s" |
97 | 100 | ||
@@ -487,6 +490,7 @@ static int __init root_nfs_get_handle(void) | |||
487 | { | 490 | { |
488 | struct nfs_fh fh; | 491 | struct nfs_fh fh; |
489 | struct sockaddr_in sin; | 492 | struct sockaddr_in sin; |
493 | unsigned int auth_flav_len = 0; | ||
490 | struct nfs_mount_request request = { | 494 | struct nfs_mount_request request = { |
491 | .sap = (struct sockaddr *)&sin, | 495 | .sap = (struct sockaddr *)&sin, |
492 | .salen = sizeof(sin), | 496 | .salen = sizeof(sin), |
@@ -496,6 +500,7 @@ static int __init root_nfs_get_handle(void) | |||
496 | .protocol = (nfs_data.flags & NFS_MOUNT_TCP) ? | 500 | .protocol = (nfs_data.flags & NFS_MOUNT_TCP) ? |
497 | XPRT_TRANSPORT_TCP : XPRT_TRANSPORT_UDP, | 501 | XPRT_TRANSPORT_TCP : XPRT_TRANSPORT_UDP, |
498 | .fh = &fh, | 502 | .fh = &fh, |
503 | .auth_flav_len = &auth_flav_len, | ||
499 | }; | 504 | }; |
500 | int status; | 505 | int status; |
501 | 506 | ||
diff --git a/fs/nfs/read.c b/fs/nfs/read.c index 4ace3c50a8eb..96c4ebfa46f4 100644 --- a/fs/nfs/read.c +++ b/fs/nfs/read.c | |||
@@ -22,6 +22,7 @@ | |||
22 | 22 | ||
23 | #include <asm/system.h> | 23 | #include <asm/system.h> |
24 | 24 | ||
25 | #include "nfs4_fs.h" | ||
25 | #include "internal.h" | 26 | #include "internal.h" |
26 | #include "iostat.h" | 27 | #include "iostat.h" |
27 | #include "fscache.h" | 28 | #include "fscache.h" |
@@ -46,6 +47,7 @@ struct nfs_read_data *nfs_readdata_alloc(unsigned int pagecount) | |||
46 | memset(p, 0, sizeof(*p)); | 47 | memset(p, 0, sizeof(*p)); |
47 | INIT_LIST_HEAD(&p->pages); | 48 | INIT_LIST_HEAD(&p->pages); |
48 | p->npages = pagecount; | 49 | p->npages = pagecount; |
50 | p->res.seq_res.sr_slotid = NFS4_MAX_SLOT_TABLE; | ||
49 | if (pagecount <= ARRAY_SIZE(p->page_array)) | 51 | if (pagecount <= ARRAY_SIZE(p->page_array)) |
50 | p->pagevec = p->page_array; | 52 | p->pagevec = p->page_array; |
51 | else { | 53 | else { |
@@ -357,19 +359,25 @@ static void nfs_readpage_retry(struct rpc_task *task, struct nfs_read_data *data | |||
357 | struct nfs_readres *resp = &data->res; | 359 | struct nfs_readres *resp = &data->res; |
358 | 360 | ||
359 | if (resp->eof || resp->count == argp->count) | 361 | if (resp->eof || resp->count == argp->count) |
360 | return; | 362 | goto out; |
361 | 363 | ||
362 | /* This is a short read! */ | 364 | /* This is a short read! */ |
363 | nfs_inc_stats(data->inode, NFSIOS_SHORTREAD); | 365 | nfs_inc_stats(data->inode, NFSIOS_SHORTREAD); |
364 | /* Has the server at least made some progress? */ | 366 | /* Has the server at least made some progress? */ |
365 | if (resp->count == 0) | 367 | if (resp->count == 0) |
366 | return; | 368 | goto out; |
367 | 369 | ||
368 | /* Yes, so retry the read at the end of the data */ | 370 | /* Yes, so retry the read at the end of the data */ |
369 | argp->offset += resp->count; | 371 | argp->offset += resp->count; |
370 | argp->pgbase += resp->count; | 372 | argp->pgbase += resp->count; |
371 | argp->count -= resp->count; | 373 | argp->count -= resp->count; |
372 | rpc_restart_call(task); | 374 | nfs4_restart_rpc(task, NFS_SERVER(data->inode)->nfs_client); |
375 | return; | ||
376 | out: | ||
377 | nfs4_sequence_free_slot(NFS_SERVER(data->inode)->nfs_client, | ||
378 | &data->res.seq_res); | ||
379 | return; | ||
380 | |||
373 | } | 381 | } |
374 | 382 | ||
375 | /* | 383 | /* |
@@ -406,7 +414,23 @@ static void nfs_readpage_release_partial(void *calldata) | |||
406 | nfs_readdata_release(calldata); | 414 | nfs_readdata_release(calldata); |
407 | } | 415 | } |
408 | 416 | ||
417 | #if defined(CONFIG_NFS_V4_1) | ||
418 | void nfs_read_prepare(struct rpc_task *task, void *calldata) | ||
419 | { | ||
420 | struct nfs_read_data *data = calldata; | ||
421 | |||
422 | if (nfs4_setup_sequence(NFS_SERVER(data->inode)->nfs_client, | ||
423 | &data->args.seq_args, &data->res.seq_res, | ||
424 | 0, task)) | ||
425 | return; | ||
426 | rpc_call_start(task); | ||
427 | } | ||
428 | #endif /* CONFIG_NFS_V4_1 */ | ||
429 | |||
409 | static const struct rpc_call_ops nfs_read_partial_ops = { | 430 | static const struct rpc_call_ops nfs_read_partial_ops = { |
431 | #if defined(CONFIG_NFS_V4_1) | ||
432 | .rpc_call_prepare = nfs_read_prepare, | ||
433 | #endif /* CONFIG_NFS_V4_1 */ | ||
410 | .rpc_call_done = nfs_readpage_result_partial, | 434 | .rpc_call_done = nfs_readpage_result_partial, |
411 | .rpc_release = nfs_readpage_release_partial, | 435 | .rpc_release = nfs_readpage_release_partial, |
412 | }; | 436 | }; |
@@ -470,6 +494,9 @@ static void nfs_readpage_release_full(void *calldata) | |||
470 | } | 494 | } |
471 | 495 | ||
472 | static const struct rpc_call_ops nfs_read_full_ops = { | 496 | static const struct rpc_call_ops nfs_read_full_ops = { |
497 | #if defined(CONFIG_NFS_V4_1) | ||
498 | .rpc_call_prepare = nfs_read_prepare, | ||
499 | #endif /* CONFIG_NFS_V4_1 */ | ||
473 | .rpc_call_done = nfs_readpage_result_full, | 500 | .rpc_call_done = nfs_readpage_result_full, |
474 | .rpc_release = nfs_readpage_release_full, | 501 | .rpc_release = nfs_readpage_release_full, |
475 | }; | 502 | }; |
diff --git a/fs/nfs/super.c b/fs/nfs/super.c index 26127b69a275..0b4cbdc60abd 100644 --- a/fs/nfs/super.c +++ b/fs/nfs/super.c | |||
@@ -42,6 +42,8 @@ | |||
42 | #include <linux/smp_lock.h> | 42 | #include <linux/smp_lock.h> |
43 | #include <linux/seq_file.h> | 43 | #include <linux/seq_file.h> |
44 | #include <linux/mount.h> | 44 | #include <linux/mount.h> |
45 | #include <linux/mnt_namespace.h> | ||
46 | #include <linux/namei.h> | ||
45 | #include <linux/nfs_idmap.h> | 47 | #include <linux/nfs_idmap.h> |
46 | #include <linux/vfs.h> | 48 | #include <linux/vfs.h> |
47 | #include <linux/inet.h> | 49 | #include <linux/inet.h> |
@@ -90,6 +92,7 @@ enum { | |||
90 | Opt_mountport, | 92 | Opt_mountport, |
91 | Opt_mountvers, | 93 | Opt_mountvers, |
92 | Opt_nfsvers, | 94 | Opt_nfsvers, |
95 | Opt_minorversion, | ||
93 | 96 | ||
94 | /* Mount options that take string arguments */ | 97 | /* Mount options that take string arguments */ |
95 | Opt_sec, Opt_proto, Opt_mountproto, Opt_mounthost, | 98 | Opt_sec, Opt_proto, Opt_mountproto, Opt_mounthost, |
@@ -139,22 +142,23 @@ static const match_table_t nfs_mount_option_tokens = { | |||
139 | { Opt_fscache_uniq, "fsc=%s" }, | 142 | { Opt_fscache_uniq, "fsc=%s" }, |
140 | { Opt_nofscache, "nofsc" }, | 143 | { Opt_nofscache, "nofsc" }, |
141 | 144 | ||
142 | { Opt_port, "port=%u" }, | 145 | { Opt_port, "port=%s" }, |
143 | { Opt_rsize, "rsize=%u" }, | 146 | { Opt_rsize, "rsize=%s" }, |
144 | { Opt_wsize, "wsize=%u" }, | 147 | { Opt_wsize, "wsize=%s" }, |
145 | { Opt_bsize, "bsize=%u" }, | 148 | { Opt_bsize, "bsize=%s" }, |
146 | { Opt_timeo, "timeo=%u" }, | 149 | { Opt_timeo, "timeo=%s" }, |
147 | { Opt_retrans, "retrans=%u" }, | 150 | { Opt_retrans, "retrans=%s" }, |
148 | { Opt_acregmin, "acregmin=%u" }, | 151 | { Opt_acregmin, "acregmin=%s" }, |
149 | { Opt_acregmax, "acregmax=%u" }, | 152 | { Opt_acregmax, "acregmax=%s" }, |
150 | { Opt_acdirmin, "acdirmin=%u" }, | 153 | { Opt_acdirmin, "acdirmin=%s" }, |
151 | { Opt_acdirmax, "acdirmax=%u" }, | 154 | { Opt_acdirmax, "acdirmax=%s" }, |
152 | { Opt_actimeo, "actimeo=%u" }, | 155 | { Opt_actimeo, "actimeo=%s" }, |
153 | { Opt_namelen, "namlen=%u" }, | 156 | { Opt_namelen, "namlen=%s" }, |
154 | { Opt_mountport, "mountport=%u" }, | 157 | { Opt_mountport, "mountport=%s" }, |
155 | { Opt_mountvers, "mountvers=%u" }, | 158 | { Opt_mountvers, "mountvers=%s" }, |
156 | { Opt_nfsvers, "nfsvers=%u" }, | 159 | { Opt_nfsvers, "nfsvers=%s" }, |
157 | { Opt_nfsvers, "vers=%u" }, | 160 | { Opt_nfsvers, "vers=%s" }, |
161 | { Opt_minorversion, "minorversion=%u" }, | ||
158 | 162 | ||
159 | { Opt_sec, "sec=%s" }, | 163 | { Opt_sec, "sec=%s" }, |
160 | { Opt_proto, "proto=%s" }, | 164 | { Opt_proto, "proto=%s" }, |
@@ -270,10 +274,14 @@ static const struct super_operations nfs_sops = { | |||
270 | #ifdef CONFIG_NFS_V4 | 274 | #ifdef CONFIG_NFS_V4 |
271 | static int nfs4_get_sb(struct file_system_type *fs_type, | 275 | static int nfs4_get_sb(struct file_system_type *fs_type, |
272 | int flags, const char *dev_name, void *raw_data, struct vfsmount *mnt); | 276 | int flags, const char *dev_name, void *raw_data, struct vfsmount *mnt); |
277 | static int nfs4_remote_get_sb(struct file_system_type *fs_type, | ||
278 | int flags, const char *dev_name, void *raw_data, struct vfsmount *mnt); | ||
273 | static int nfs4_xdev_get_sb(struct file_system_type *fs_type, | 279 | static int nfs4_xdev_get_sb(struct file_system_type *fs_type, |
274 | int flags, const char *dev_name, void *raw_data, struct vfsmount *mnt); | 280 | int flags, const char *dev_name, void *raw_data, struct vfsmount *mnt); |
275 | static int nfs4_referral_get_sb(struct file_system_type *fs_type, | 281 | static int nfs4_referral_get_sb(struct file_system_type *fs_type, |
276 | int flags, const char *dev_name, void *raw_data, struct vfsmount *mnt); | 282 | int flags, const char *dev_name, void *raw_data, struct vfsmount *mnt); |
283 | static int nfs4_remote_referral_get_sb(struct file_system_type *fs_type, | ||
284 | int flags, const char *dev_name, void *raw_data, struct vfsmount *mnt); | ||
277 | static void nfs4_kill_super(struct super_block *sb); | 285 | static void nfs4_kill_super(struct super_block *sb); |
278 | 286 | ||
279 | static struct file_system_type nfs4_fs_type = { | 287 | static struct file_system_type nfs4_fs_type = { |
@@ -284,6 +292,14 @@ static struct file_system_type nfs4_fs_type = { | |||
284 | .fs_flags = FS_RENAME_DOES_D_MOVE|FS_REVAL_DOT|FS_BINARY_MOUNTDATA, | 292 | .fs_flags = FS_RENAME_DOES_D_MOVE|FS_REVAL_DOT|FS_BINARY_MOUNTDATA, |
285 | }; | 293 | }; |
286 | 294 | ||
295 | static struct file_system_type nfs4_remote_fs_type = { | ||
296 | .owner = THIS_MODULE, | ||
297 | .name = "nfs4", | ||
298 | .get_sb = nfs4_remote_get_sb, | ||
299 | .kill_sb = nfs4_kill_super, | ||
300 | .fs_flags = FS_RENAME_DOES_D_MOVE|FS_REVAL_DOT|FS_BINARY_MOUNTDATA, | ||
301 | }; | ||
302 | |||
287 | struct file_system_type nfs4_xdev_fs_type = { | 303 | struct file_system_type nfs4_xdev_fs_type = { |
288 | .owner = THIS_MODULE, | 304 | .owner = THIS_MODULE, |
289 | .name = "nfs4", | 305 | .name = "nfs4", |
@@ -292,6 +308,14 @@ struct file_system_type nfs4_xdev_fs_type = { | |||
292 | .fs_flags = FS_RENAME_DOES_D_MOVE|FS_REVAL_DOT|FS_BINARY_MOUNTDATA, | 308 | .fs_flags = FS_RENAME_DOES_D_MOVE|FS_REVAL_DOT|FS_BINARY_MOUNTDATA, |
293 | }; | 309 | }; |
294 | 310 | ||
311 | static struct file_system_type nfs4_remote_referral_fs_type = { | ||
312 | .owner = THIS_MODULE, | ||
313 | .name = "nfs4", | ||
314 | .get_sb = nfs4_remote_referral_get_sb, | ||
315 | .kill_sb = nfs4_kill_super, | ||
316 | .fs_flags = FS_RENAME_DOES_D_MOVE|FS_REVAL_DOT|FS_BINARY_MOUNTDATA, | ||
317 | }; | ||
318 | |||
295 | struct file_system_type nfs4_referral_fs_type = { | 319 | struct file_system_type nfs4_referral_fs_type = { |
296 | .owner = THIS_MODULE, | 320 | .owner = THIS_MODULE, |
297 | .name = "nfs4", | 321 | .name = "nfs4", |
@@ -514,7 +538,6 @@ static void nfs_show_mount_options(struct seq_file *m, struct nfs_server *nfss, | |||
514 | const char *nostr; | 538 | const char *nostr; |
515 | } nfs_info[] = { | 539 | } nfs_info[] = { |
516 | { NFS_MOUNT_SOFT, ",soft", ",hard" }, | 540 | { NFS_MOUNT_SOFT, ",soft", ",hard" }, |
517 | { NFS_MOUNT_INTR, ",intr", ",nointr" }, | ||
518 | { NFS_MOUNT_POSIX, ",posix", "" }, | 541 | { NFS_MOUNT_POSIX, ",posix", "" }, |
519 | { NFS_MOUNT_NOCTO, ",nocto", "" }, | 542 | { NFS_MOUNT_NOCTO, ",nocto", "" }, |
520 | { NFS_MOUNT_NOAC, ",noac", "" }, | 543 | { NFS_MOUNT_NOAC, ",noac", "" }, |
@@ -943,11 +966,6 @@ static int nfs_parse_security_flavors(char *value, | |||
943 | return 1; | 966 | return 1; |
944 | } | 967 | } |
945 | 968 | ||
946 | static void nfs_parse_invalid_value(const char *option) | ||
947 | { | ||
948 | dfprintk(MOUNT, "NFS: bad value specified for %s option\n", option); | ||
949 | } | ||
950 | |||
951 | /* | 969 | /* |
952 | * Error-check and convert a string of mount options from user space into | 970 | * Error-check and convert a string of mount options from user space into |
953 | * a data structure. The whole mount string is processed; bad options are | 971 | * a data structure. The whole mount string is processed; bad options are |
@@ -958,7 +976,7 @@ static int nfs_parse_mount_options(char *raw, | |||
958 | struct nfs_parsed_mount_data *mnt) | 976 | struct nfs_parsed_mount_data *mnt) |
959 | { | 977 | { |
960 | char *p, *string, *secdata; | 978 | char *p, *string, *secdata; |
961 | int rc, sloppy = 0, errors = 0; | 979 | int rc, sloppy = 0, invalid_option = 0; |
962 | 980 | ||
963 | if (!raw) { | 981 | if (!raw) { |
964 | dfprintk(MOUNT, "NFS: mount options string was NULL.\n"); | 982 | dfprintk(MOUNT, "NFS: mount options string was NULL.\n"); |
@@ -982,7 +1000,9 @@ static int nfs_parse_mount_options(char *raw, | |||
982 | 1000 | ||
983 | while ((p = strsep(&raw, ",")) != NULL) { | 1001 | while ((p = strsep(&raw, ",")) != NULL) { |
984 | substring_t args[MAX_OPT_ARGS]; | 1002 | substring_t args[MAX_OPT_ARGS]; |
985 | int option, token; | 1003 | unsigned long option; |
1004 | int int_option; | ||
1005 | int token; | ||
986 | 1006 | ||
987 | if (!*p) | 1007 | if (!*p) |
988 | continue; | 1008 | continue; |
@@ -1091,114 +1111,156 @@ static int nfs_parse_mount_options(char *raw, | |||
1091 | * options that take numeric values | 1111 | * options that take numeric values |
1092 | */ | 1112 | */ |
1093 | case Opt_port: | 1113 | case Opt_port: |
1094 | if (match_int(args, &option) || | 1114 | string = match_strdup(args); |
1095 | option < 0 || option > USHORT_MAX) { | 1115 | if (string == NULL) |
1096 | errors++; | 1116 | goto out_nomem; |
1097 | nfs_parse_invalid_value("port"); | 1117 | rc = strict_strtoul(string, 10, &option); |
1098 | } else | 1118 | kfree(string); |
1099 | mnt->nfs_server.port = option; | 1119 | if (rc != 0 || option > USHORT_MAX) |
1120 | goto out_invalid_value; | ||
1121 | mnt->nfs_server.port = option; | ||
1100 | break; | 1122 | break; |
1101 | case Opt_rsize: | 1123 | case Opt_rsize: |
1102 | if (match_int(args, &option) || option < 0) { | 1124 | string = match_strdup(args); |
1103 | errors++; | 1125 | if (string == NULL) |
1104 | nfs_parse_invalid_value("rsize"); | 1126 | goto out_nomem; |
1105 | } else | 1127 | rc = strict_strtoul(string, 10, &option); |
1106 | mnt->rsize = option; | 1128 | kfree(string); |
1129 | if (rc != 0) | ||
1130 | goto out_invalid_value; | ||
1131 | mnt->rsize = option; | ||
1107 | break; | 1132 | break; |
1108 | case Opt_wsize: | 1133 | case Opt_wsize: |
1109 | if (match_int(args, &option) || option < 0) { | 1134 | string = match_strdup(args); |
1110 | errors++; | 1135 | if (string == NULL) |
1111 | nfs_parse_invalid_value("wsize"); | 1136 | goto out_nomem; |
1112 | } else | 1137 | rc = strict_strtoul(string, 10, &option); |
1113 | mnt->wsize = option; | 1138 | kfree(string); |
1139 | if (rc != 0) | ||
1140 | goto out_invalid_value; | ||
1141 | mnt->wsize = option; | ||
1114 | break; | 1142 | break; |
1115 | case Opt_bsize: | 1143 | case Opt_bsize: |
1116 | if (match_int(args, &option) || option < 0) { | 1144 | string = match_strdup(args); |
1117 | errors++; | 1145 | if (string == NULL) |
1118 | nfs_parse_invalid_value("bsize"); | 1146 | goto out_nomem; |
1119 | } else | 1147 | rc = strict_strtoul(string, 10, &option); |
1120 | mnt->bsize = option; | 1148 | kfree(string); |
1149 | if (rc != 0) | ||
1150 | goto out_invalid_value; | ||
1151 | mnt->bsize = option; | ||
1121 | break; | 1152 | break; |
1122 | case Opt_timeo: | 1153 | case Opt_timeo: |
1123 | if (match_int(args, &option) || option <= 0) { | 1154 | string = match_strdup(args); |
1124 | errors++; | 1155 | if (string == NULL) |
1125 | nfs_parse_invalid_value("timeo"); | 1156 | goto out_nomem; |
1126 | } else | 1157 | rc = strict_strtoul(string, 10, &option); |
1127 | mnt->timeo = option; | 1158 | kfree(string); |
1159 | if (rc != 0 || option == 0) | ||
1160 | goto out_invalid_value; | ||
1161 | mnt->timeo = option; | ||
1128 | break; | 1162 | break; |
1129 | case Opt_retrans: | 1163 | case Opt_retrans: |
1130 | if (match_int(args, &option) || option <= 0) { | 1164 | string = match_strdup(args); |
1131 | errors++; | 1165 | if (string == NULL) |
1132 | nfs_parse_invalid_value("retrans"); | 1166 | goto out_nomem; |
1133 | } else | 1167 | rc = strict_strtoul(string, 10, &option); |
1134 | mnt->retrans = option; | 1168 | kfree(string); |
1169 | if (rc != 0 || option == 0) | ||
1170 | goto out_invalid_value; | ||
1171 | mnt->retrans = option; | ||
1135 | break; | 1172 | break; |
1136 | case Opt_acregmin: | 1173 | case Opt_acregmin: |
1137 | if (match_int(args, &option) || option < 0) { | 1174 | string = match_strdup(args); |
1138 | errors++; | 1175 | if (string == NULL) |
1139 | nfs_parse_invalid_value("acregmin"); | 1176 | goto out_nomem; |
1140 | } else | 1177 | rc = strict_strtoul(string, 10, &option); |
1141 | mnt->acregmin = option; | 1178 | kfree(string); |
1179 | if (rc != 0) | ||
1180 | goto out_invalid_value; | ||
1181 | mnt->acregmin = option; | ||
1142 | break; | 1182 | break; |
1143 | case Opt_acregmax: | 1183 | case Opt_acregmax: |
1144 | if (match_int(args, &option) || option < 0) { | 1184 | string = match_strdup(args); |
1145 | errors++; | 1185 | if (string == NULL) |
1146 | nfs_parse_invalid_value("acregmax"); | 1186 | goto out_nomem; |
1147 | } else | 1187 | rc = strict_strtoul(string, 10, &option); |
1148 | mnt->acregmax = option; | 1188 | kfree(string); |
1189 | if (rc != 0) | ||
1190 | goto out_invalid_value; | ||
1191 | mnt->acregmax = option; | ||
1149 | break; | 1192 | break; |
1150 | case Opt_acdirmin: | 1193 | case Opt_acdirmin: |
1151 | if (match_int(args, &option) || option < 0) { | 1194 | string = match_strdup(args); |
1152 | errors++; | 1195 | if (string == NULL) |
1153 | nfs_parse_invalid_value("acdirmin"); | 1196 | goto out_nomem; |
1154 | } else | 1197 | rc = strict_strtoul(string, 10, &option); |
1155 | mnt->acdirmin = option; | 1198 | kfree(string); |
1199 | if (rc != 0) | ||
1200 | goto out_invalid_value; | ||
1201 | mnt->acdirmin = option; | ||
1156 | break; | 1202 | break; |
1157 | case Opt_acdirmax: | 1203 | case Opt_acdirmax: |
1158 | if (match_int(args, &option) || option < 0) { | 1204 | string = match_strdup(args); |
1159 | errors++; | 1205 | if (string == NULL) |
1160 | nfs_parse_invalid_value("acdirmax"); | 1206 | goto out_nomem; |
1161 | } else | 1207 | rc = strict_strtoul(string, 10, &option); |
1162 | mnt->acdirmax = option; | 1208 | kfree(string); |
1209 | if (rc != 0) | ||
1210 | goto out_invalid_value; | ||
1211 | mnt->acdirmax = option; | ||
1163 | break; | 1212 | break; |
1164 | case Opt_actimeo: | 1213 | case Opt_actimeo: |
1165 | if (match_int(args, &option) || option < 0) { | 1214 | string = match_strdup(args); |
1166 | errors++; | 1215 | if (string == NULL) |
1167 | nfs_parse_invalid_value("actimeo"); | 1216 | goto out_nomem; |
1168 | } else | 1217 | rc = strict_strtoul(string, 10, &option); |
1169 | mnt->acregmin = mnt->acregmax = | 1218 | kfree(string); |
1170 | mnt->acdirmin = mnt->acdirmax = option; | 1219 | if (rc != 0) |
1220 | goto out_invalid_value; | ||
1221 | mnt->acregmin = mnt->acregmax = | ||
1222 | mnt->acdirmin = mnt->acdirmax = option; | ||
1171 | break; | 1223 | break; |
1172 | case Opt_namelen: | 1224 | case Opt_namelen: |
1173 | if (match_int(args, &option) || option < 0) { | 1225 | string = match_strdup(args); |
1174 | errors++; | 1226 | if (string == NULL) |
1175 | nfs_parse_invalid_value("namlen"); | 1227 | goto out_nomem; |
1176 | } else | 1228 | rc = strict_strtoul(string, 10, &option); |
1177 | mnt->namlen = option; | 1229 | kfree(string); |
1230 | if (rc != 0) | ||
1231 | goto out_invalid_value; | ||
1232 | mnt->namlen = option; | ||
1178 | break; | 1233 | break; |
1179 | case Opt_mountport: | 1234 | case Opt_mountport: |
1180 | if (match_int(args, &option) || | 1235 | string = match_strdup(args); |
1181 | option < 0 || option > USHORT_MAX) { | 1236 | if (string == NULL) |
1182 | errors++; | 1237 | goto out_nomem; |
1183 | nfs_parse_invalid_value("mountport"); | 1238 | rc = strict_strtoul(string, 10, &option); |
1184 | } else | 1239 | kfree(string); |
1185 | mnt->mount_server.port = option; | 1240 | if (rc != 0 || option > USHORT_MAX) |
1241 | goto out_invalid_value; | ||
1242 | mnt->mount_server.port = option; | ||
1186 | break; | 1243 | break; |
1187 | case Opt_mountvers: | 1244 | case Opt_mountvers: |
1188 | if (match_int(args, &option) || | 1245 | string = match_strdup(args); |
1246 | if (string == NULL) | ||
1247 | goto out_nomem; | ||
1248 | rc = strict_strtoul(string, 10, &option); | ||
1249 | kfree(string); | ||
1250 | if (rc != 0 || | ||
1189 | option < NFS_MNT_VERSION || | 1251 | option < NFS_MNT_VERSION || |
1190 | option > NFS_MNT3_VERSION) { | 1252 | option > NFS_MNT3_VERSION) |
1191 | errors++; | 1253 | goto out_invalid_value; |
1192 | nfs_parse_invalid_value("mountvers"); | 1254 | mnt->mount_server.version = option; |
1193 | } else | ||
1194 | mnt->mount_server.version = option; | ||
1195 | break; | 1255 | break; |
1196 | case Opt_nfsvers: | 1256 | case Opt_nfsvers: |
1197 | if (match_int(args, &option)) { | 1257 | string = match_strdup(args); |
1198 | errors++; | 1258 | if (string == NULL) |
1199 | nfs_parse_invalid_value("nfsvers"); | 1259 | goto out_nomem; |
1200 | break; | 1260 | rc = strict_strtoul(string, 10, &option); |
1201 | } | 1261 | kfree(string); |
1262 | if (rc != 0) | ||
1263 | goto out_invalid_value; | ||
1202 | switch (option) { | 1264 | switch (option) { |
1203 | case NFS2_VERSION: | 1265 | case NFS2_VERSION: |
1204 | mnt->flags &= ~NFS_MOUNT_VER3; | 1266 | mnt->flags &= ~NFS_MOUNT_VER3; |
@@ -1207,10 +1269,16 @@ static int nfs_parse_mount_options(char *raw, | |||
1207 | mnt->flags |= NFS_MOUNT_VER3; | 1269 | mnt->flags |= NFS_MOUNT_VER3; |
1208 | break; | 1270 | break; |
1209 | default: | 1271 | default: |
1210 | errors++; | 1272 | goto out_invalid_value; |
1211 | nfs_parse_invalid_value("nfsvers"); | ||
1212 | } | 1273 | } |
1213 | break; | 1274 | break; |
1275 | case Opt_minorversion: | ||
1276 | if (match_int(args, &int_option)) | ||
1277 | return 0; | ||
1278 | if (int_option < 0 || int_option > NFS4_MAX_MINOR_VERSION) | ||
1279 | return 0; | ||
1280 | mnt->minorversion = int_option; | ||
1281 | break; | ||
1214 | 1282 | ||
1215 | /* | 1283 | /* |
1216 | * options that take text values | 1284 | * options that take text values |
@@ -1222,9 +1290,9 @@ static int nfs_parse_mount_options(char *raw, | |||
1222 | rc = nfs_parse_security_flavors(string, mnt); | 1290 | rc = nfs_parse_security_flavors(string, mnt); |
1223 | kfree(string); | 1291 | kfree(string); |
1224 | if (!rc) { | 1292 | if (!rc) { |
1225 | errors++; | ||
1226 | dfprintk(MOUNT, "NFS: unrecognized " | 1293 | dfprintk(MOUNT, "NFS: unrecognized " |
1227 | "security flavor\n"); | 1294 | "security flavor\n"); |
1295 | return 0; | ||
1228 | } | 1296 | } |
1229 | break; | 1297 | break; |
1230 | case Opt_proto: | 1298 | case Opt_proto: |
@@ -1238,23 +1306,25 @@ static int nfs_parse_mount_options(char *raw, | |||
1238 | case Opt_xprt_udp: | 1306 | case Opt_xprt_udp: |
1239 | mnt->flags &= ~NFS_MOUNT_TCP; | 1307 | mnt->flags &= ~NFS_MOUNT_TCP; |
1240 | mnt->nfs_server.protocol = XPRT_TRANSPORT_UDP; | 1308 | mnt->nfs_server.protocol = XPRT_TRANSPORT_UDP; |
1309 | kfree(string); | ||
1241 | break; | 1310 | break; |
1242 | case Opt_xprt_tcp: | 1311 | case Opt_xprt_tcp: |
1243 | mnt->flags |= NFS_MOUNT_TCP; | 1312 | mnt->flags |= NFS_MOUNT_TCP; |
1244 | mnt->nfs_server.protocol = XPRT_TRANSPORT_TCP; | 1313 | mnt->nfs_server.protocol = XPRT_TRANSPORT_TCP; |
1314 | kfree(string); | ||
1245 | break; | 1315 | break; |
1246 | case Opt_xprt_rdma: | 1316 | case Opt_xprt_rdma: |
1247 | /* vector side protocols to TCP */ | 1317 | /* vector side protocols to TCP */ |
1248 | mnt->flags |= NFS_MOUNT_TCP; | 1318 | mnt->flags |= NFS_MOUNT_TCP; |
1249 | mnt->nfs_server.protocol = XPRT_TRANSPORT_RDMA; | 1319 | mnt->nfs_server.protocol = XPRT_TRANSPORT_RDMA; |
1250 | xprt_load_transport(string); | 1320 | xprt_load_transport(string); |
1321 | kfree(string); | ||
1251 | break; | 1322 | break; |
1252 | default: | 1323 | default: |
1253 | errors++; | ||
1254 | dfprintk(MOUNT, "NFS: unrecognized " | 1324 | dfprintk(MOUNT, "NFS: unrecognized " |
1255 | "transport protocol\n"); | 1325 | "transport protocol\n"); |
1326 | return 0; | ||
1256 | } | 1327 | } |
1257 | kfree(string); | ||
1258 | break; | 1328 | break; |
1259 | case Opt_mountproto: | 1329 | case Opt_mountproto: |
1260 | string = match_strdup(args); | 1330 | string = match_strdup(args); |
@@ -1273,9 +1343,9 @@ static int nfs_parse_mount_options(char *raw, | |||
1273 | break; | 1343 | break; |
1274 | case Opt_xprt_rdma: /* not used for side protocols */ | 1344 | case Opt_xprt_rdma: /* not used for side protocols */ |
1275 | default: | 1345 | default: |
1276 | errors++; | ||
1277 | dfprintk(MOUNT, "NFS: unrecognized " | 1346 | dfprintk(MOUNT, "NFS: unrecognized " |
1278 | "transport protocol\n"); | 1347 | "transport protocol\n"); |
1348 | return 0; | ||
1279 | } | 1349 | } |
1280 | break; | 1350 | break; |
1281 | case Opt_addr: | 1351 | case Opt_addr: |
@@ -1331,9 +1401,9 @@ static int nfs_parse_mount_options(char *raw, | |||
1331 | mnt->flags |= NFS_MOUNT_LOOKUP_CACHE_NONEG|NFS_MOUNT_LOOKUP_CACHE_NONE; | 1401 | mnt->flags |= NFS_MOUNT_LOOKUP_CACHE_NONEG|NFS_MOUNT_LOOKUP_CACHE_NONE; |
1332 | break; | 1402 | break; |
1333 | default: | 1403 | default: |
1334 | errors++; | ||
1335 | dfprintk(MOUNT, "NFS: invalid " | 1404 | dfprintk(MOUNT, "NFS: invalid " |
1336 | "lookupcache argument\n"); | 1405 | "lookupcache argument\n"); |
1406 | return 0; | ||
1337 | }; | 1407 | }; |
1338 | break; | 1408 | break; |
1339 | 1409 | ||
@@ -1351,20 +1421,20 @@ static int nfs_parse_mount_options(char *raw, | |||
1351 | break; | 1421 | break; |
1352 | 1422 | ||
1353 | default: | 1423 | default: |
1354 | errors++; | 1424 | invalid_option = 1; |
1355 | dfprintk(MOUNT, "NFS: unrecognized mount option " | 1425 | dfprintk(MOUNT, "NFS: unrecognized mount option " |
1356 | "'%s'\n", p); | 1426 | "'%s'\n", p); |
1357 | } | 1427 | } |
1358 | } | 1428 | } |
1359 | 1429 | ||
1360 | if (errors > 0) { | 1430 | if (!sloppy && invalid_option) |
1361 | dfprintk(MOUNT, "NFS: parsing encountered %d error%s\n", | 1431 | return 0; |
1362 | errors, (errors == 1 ? "" : "s")); | 1432 | |
1363 | if (!sloppy) | ||
1364 | return 0; | ||
1365 | } | ||
1366 | return 1; | 1433 | return 1; |
1367 | 1434 | ||
1435 | out_invalid_value: | ||
1436 | printk(KERN_INFO "NFS: bad mount option value specified: %s \n", p); | ||
1437 | return 0; | ||
1368 | out_nomem: | 1438 | out_nomem: |
1369 | printk(KERN_INFO "NFS: not enough memory to parse option\n"); | 1439 | printk(KERN_INFO "NFS: not enough memory to parse option\n"); |
1370 | return 0; | 1440 | return 0; |
@@ -1381,6 +1451,7 @@ out_security_failure: | |||
1381 | static int nfs_try_mount(struct nfs_parsed_mount_data *args, | 1451 | static int nfs_try_mount(struct nfs_parsed_mount_data *args, |
1382 | struct nfs_fh *root_fh) | 1452 | struct nfs_fh *root_fh) |
1383 | { | 1453 | { |
1454 | unsigned int auth_flavor_len = 0; | ||
1384 | struct nfs_mount_request request = { | 1455 | struct nfs_mount_request request = { |
1385 | .sap = (struct sockaddr *) | 1456 | .sap = (struct sockaddr *) |
1386 | &args->mount_server.address, | 1457 | &args->mount_server.address, |
@@ -1388,6 +1459,7 @@ static int nfs_try_mount(struct nfs_parsed_mount_data *args, | |||
1388 | .protocol = args->mount_server.protocol, | 1459 | .protocol = args->mount_server.protocol, |
1389 | .fh = root_fh, | 1460 | .fh = root_fh, |
1390 | .noresvport = args->flags & NFS_MOUNT_NORESVPORT, | 1461 | .noresvport = args->flags & NFS_MOUNT_NORESVPORT, |
1462 | .auth_flav_len = &auth_flavor_len, | ||
1391 | }; | 1463 | }; |
1392 | int status; | 1464 | int status; |
1393 | 1465 | ||
@@ -2240,6 +2312,11 @@ static void nfs4_fill_super(struct super_block *sb) | |||
2240 | nfs_initialise_sb(sb); | 2312 | nfs_initialise_sb(sb); |
2241 | } | 2313 | } |
2242 | 2314 | ||
2315 | static void nfs4_validate_mount_flags(struct nfs_parsed_mount_data *args) | ||
2316 | { | ||
2317 | args->flags &= ~(NFS_MOUNT_NONLM|NFS_MOUNT_NOACL|NFS_MOUNT_VER3); | ||
2318 | } | ||
2319 | |||
2243 | /* | 2320 | /* |
2244 | * Validate NFSv4 mount options | 2321 | * Validate NFSv4 mount options |
2245 | */ | 2322 | */ |
@@ -2263,6 +2340,7 @@ static int nfs4_validate_mount_data(void *options, | |||
2263 | args->nfs_server.port = NFS_PORT; /* 2049 unless user set port= */ | 2340 | args->nfs_server.port = NFS_PORT; /* 2049 unless user set port= */ |
2264 | args->auth_flavors[0] = RPC_AUTH_UNIX; | 2341 | args->auth_flavors[0] = RPC_AUTH_UNIX; |
2265 | args->auth_flavor_len = 0; | 2342 | args->auth_flavor_len = 0; |
2343 | args->minorversion = 0; | ||
2266 | 2344 | ||
2267 | switch (data->version) { | 2345 | switch (data->version) { |
2268 | case 1: | 2346 | case 1: |
@@ -2336,6 +2414,8 @@ static int nfs4_validate_mount_data(void *options, | |||
2336 | 2414 | ||
2337 | nfs_validate_transport_protocol(args); | 2415 | nfs_validate_transport_protocol(args); |
2338 | 2416 | ||
2417 | nfs4_validate_mount_flags(args); | ||
2418 | |||
2339 | if (args->auth_flavor_len > 1) | 2419 | if (args->auth_flavor_len > 1) |
2340 | goto out_inval_auth; | 2420 | goto out_inval_auth; |
2341 | 2421 | ||
@@ -2375,12 +2455,12 @@ out_no_client_address: | |||
2375 | } | 2455 | } |
2376 | 2456 | ||
2377 | /* | 2457 | /* |
2378 | * Get the superblock for an NFS4 mountpoint | 2458 | * Get the superblock for the NFS4 root partition |
2379 | */ | 2459 | */ |
2380 | static int nfs4_get_sb(struct file_system_type *fs_type, | 2460 | static int nfs4_remote_get_sb(struct file_system_type *fs_type, |
2381 | int flags, const char *dev_name, void *raw_data, struct vfsmount *mnt) | 2461 | int flags, const char *dev_name, void *raw_data, struct vfsmount *mnt) |
2382 | { | 2462 | { |
2383 | struct nfs_parsed_mount_data *data; | 2463 | struct nfs_parsed_mount_data *data = raw_data; |
2384 | struct super_block *s; | 2464 | struct super_block *s; |
2385 | struct nfs_server *server; | 2465 | struct nfs_server *server; |
2386 | struct nfs_fh *mntfh; | 2466 | struct nfs_fh *mntfh; |
@@ -2391,18 +2471,12 @@ static int nfs4_get_sb(struct file_system_type *fs_type, | |||
2391 | }; | 2471 | }; |
2392 | int error = -ENOMEM; | 2472 | int error = -ENOMEM; |
2393 | 2473 | ||
2394 | data = kzalloc(sizeof(*data), GFP_KERNEL); | ||
2395 | mntfh = kzalloc(sizeof(*mntfh), GFP_KERNEL); | 2474 | mntfh = kzalloc(sizeof(*mntfh), GFP_KERNEL); |
2396 | if (data == NULL || mntfh == NULL) | 2475 | if (data == NULL || mntfh == NULL) |
2397 | goto out_free_fh; | 2476 | goto out_free_fh; |
2398 | 2477 | ||
2399 | security_init_mnt_opts(&data->lsm_opts); | 2478 | security_init_mnt_opts(&data->lsm_opts); |
2400 | 2479 | ||
2401 | /* Validate the mount data */ | ||
2402 | error = nfs4_validate_mount_data(raw_data, data, dev_name); | ||
2403 | if (error < 0) | ||
2404 | goto out; | ||
2405 | |||
2406 | /* Get a volume representation */ | 2480 | /* Get a volume representation */ |
2407 | server = nfs4_create_server(data, mntfh); | 2481 | server = nfs4_create_server(data, mntfh); |
2408 | if (IS_ERR(server)) { | 2482 | if (IS_ERR(server)) { |
@@ -2415,7 +2489,7 @@ static int nfs4_get_sb(struct file_system_type *fs_type, | |||
2415 | compare_super = NULL; | 2489 | compare_super = NULL; |
2416 | 2490 | ||
2417 | /* Get a superblock - note that we may end up sharing one that already exists */ | 2491 | /* Get a superblock - note that we may end up sharing one that already exists */ |
2418 | s = sget(fs_type, compare_super, nfs_set_super, &sb_mntdata); | 2492 | s = sget(&nfs4_fs_type, compare_super, nfs_set_super, &sb_mntdata); |
2419 | if (IS_ERR(s)) { | 2493 | if (IS_ERR(s)) { |
2420 | error = PTR_ERR(s); | 2494 | error = PTR_ERR(s); |
2421 | goto out_free; | 2495 | goto out_free; |
@@ -2452,14 +2526,9 @@ static int nfs4_get_sb(struct file_system_type *fs_type, | |||
2452 | error = 0; | 2526 | error = 0; |
2453 | 2527 | ||
2454 | out: | 2528 | out: |
2455 | kfree(data->client_address); | ||
2456 | kfree(data->nfs_server.export_path); | ||
2457 | kfree(data->nfs_server.hostname); | ||
2458 | kfree(data->fscache_uniq); | ||
2459 | security_free_mnt_opts(&data->lsm_opts); | 2529 | security_free_mnt_opts(&data->lsm_opts); |
2460 | out_free_fh: | 2530 | out_free_fh: |
2461 | kfree(mntfh); | 2531 | kfree(mntfh); |
2462 | kfree(data); | ||
2463 | return error; | 2532 | return error; |
2464 | 2533 | ||
2465 | out_free: | 2534 | out_free: |
@@ -2473,16 +2542,137 @@ error_splat_super: | |||
2473 | goto out; | 2542 | goto out; |
2474 | } | 2543 | } |
2475 | 2544 | ||
2545 | static struct vfsmount *nfs_do_root_mount(struct file_system_type *fs_type, | ||
2546 | int flags, void *data, const char *hostname) | ||
2547 | { | ||
2548 | struct vfsmount *root_mnt; | ||
2549 | char *root_devname; | ||
2550 | size_t len; | ||
2551 | |||
2552 | len = strlen(hostname) + 3; | ||
2553 | root_devname = kmalloc(len, GFP_KERNEL); | ||
2554 | if (root_devname == NULL) | ||
2555 | return ERR_PTR(-ENOMEM); | ||
2556 | snprintf(root_devname, len, "%s:/", hostname); | ||
2557 | root_mnt = vfs_kern_mount(fs_type, flags, root_devname, data); | ||
2558 | kfree(root_devname); | ||
2559 | return root_mnt; | ||
2560 | } | ||
2561 | |||
2562 | static void nfs_fix_devname(const struct path *path, struct vfsmount *mnt) | ||
2563 | { | ||
2564 | char *page = (char *) __get_free_page(GFP_KERNEL); | ||
2565 | char *devname, *tmp; | ||
2566 | |||
2567 | if (page == NULL) | ||
2568 | return; | ||
2569 | devname = nfs_path(path->mnt->mnt_devname, | ||
2570 | path->mnt->mnt_root, path->dentry, | ||
2571 | page, PAGE_SIZE); | ||
2572 | if (devname == NULL) | ||
2573 | goto out_freepage; | ||
2574 | tmp = kstrdup(devname, GFP_KERNEL); | ||
2575 | if (tmp == NULL) | ||
2576 | goto out_freepage; | ||
2577 | kfree(mnt->mnt_devname); | ||
2578 | mnt->mnt_devname = tmp; | ||
2579 | out_freepage: | ||
2580 | free_page((unsigned long)page); | ||
2581 | } | ||
2582 | |||
2583 | static int nfs_follow_remote_path(struct vfsmount *root_mnt, | ||
2584 | const char *export_path, struct vfsmount *mnt_target) | ||
2585 | { | ||
2586 | struct mnt_namespace *ns_private; | ||
2587 | struct nameidata nd; | ||
2588 | struct super_block *s; | ||
2589 | int ret; | ||
2590 | |||
2591 | ns_private = create_mnt_ns(root_mnt); | ||
2592 | ret = PTR_ERR(ns_private); | ||
2593 | if (IS_ERR(ns_private)) | ||
2594 | goto out_mntput; | ||
2595 | |||
2596 | ret = vfs_path_lookup(root_mnt->mnt_root, root_mnt, | ||
2597 | export_path, LOOKUP_FOLLOW, &nd); | ||
2598 | |||
2599 | put_mnt_ns(ns_private); | ||
2600 | |||
2601 | if (ret != 0) | ||
2602 | goto out_err; | ||
2603 | |||
2604 | s = nd.path.mnt->mnt_sb; | ||
2605 | atomic_inc(&s->s_active); | ||
2606 | mnt_target->mnt_sb = s; | ||
2607 | mnt_target->mnt_root = dget(nd.path.dentry); | ||
2608 | |||
2609 | /* Correct the device pathname */ | ||
2610 | nfs_fix_devname(&nd.path, mnt_target); | ||
2611 | |||
2612 | path_put(&nd.path); | ||
2613 | down_write(&s->s_umount); | ||
2614 | return 0; | ||
2615 | out_mntput: | ||
2616 | mntput(root_mnt); | ||
2617 | out_err: | ||
2618 | return ret; | ||
2619 | } | ||
2620 | |||
2621 | /* | ||
2622 | * Get the superblock for an NFS4 mountpoint | ||
2623 | */ | ||
2624 | static int nfs4_get_sb(struct file_system_type *fs_type, | ||
2625 | int flags, const char *dev_name, void *raw_data, struct vfsmount *mnt) | ||
2626 | { | ||
2627 | struct nfs_parsed_mount_data *data; | ||
2628 | char *export_path; | ||
2629 | struct vfsmount *root_mnt; | ||
2630 | int error = -ENOMEM; | ||
2631 | |||
2632 | data = kzalloc(sizeof(*data), GFP_KERNEL); | ||
2633 | if (data == NULL) | ||
2634 | goto out_free_data; | ||
2635 | |||
2636 | /* Validate the mount data */ | ||
2637 | error = nfs4_validate_mount_data(raw_data, data, dev_name); | ||
2638 | if (error < 0) | ||
2639 | goto out; | ||
2640 | |||
2641 | export_path = data->nfs_server.export_path; | ||
2642 | data->nfs_server.export_path = "/"; | ||
2643 | root_mnt = nfs_do_root_mount(&nfs4_remote_fs_type, flags, data, | ||
2644 | data->nfs_server.hostname); | ||
2645 | data->nfs_server.export_path = export_path; | ||
2646 | |||
2647 | error = PTR_ERR(root_mnt); | ||
2648 | if (IS_ERR(root_mnt)) | ||
2649 | goto out; | ||
2650 | |||
2651 | error = nfs_follow_remote_path(root_mnt, export_path, mnt); | ||
2652 | |||
2653 | out: | ||
2654 | kfree(data->client_address); | ||
2655 | kfree(data->nfs_server.export_path); | ||
2656 | kfree(data->nfs_server.hostname); | ||
2657 | kfree(data->fscache_uniq); | ||
2658 | out_free_data: | ||
2659 | kfree(data); | ||
2660 | dprintk("<-- nfs4_get_sb() = %d%s\n", error, | ||
2661 | error != 0 ? " [error]" : ""); | ||
2662 | return error; | ||
2663 | } | ||
2664 | |||
2476 | static void nfs4_kill_super(struct super_block *sb) | 2665 | static void nfs4_kill_super(struct super_block *sb) |
2477 | { | 2666 | { |
2478 | struct nfs_server *server = NFS_SB(sb); | 2667 | struct nfs_server *server = NFS_SB(sb); |
2479 | 2668 | ||
2669 | dprintk("--> %s\n", __func__); | ||
2480 | nfs_super_return_all_delegations(sb); | 2670 | nfs_super_return_all_delegations(sb); |
2481 | kill_anon_super(sb); | 2671 | kill_anon_super(sb); |
2482 | |||
2483 | nfs4_renewd_prepare_shutdown(server); | 2672 | nfs4_renewd_prepare_shutdown(server); |
2484 | nfs_fscache_release_super_cookie(sb); | 2673 | nfs_fscache_release_super_cookie(sb); |
2485 | nfs_free_server(server); | 2674 | nfs_free_server(server); |
2675 | dprintk("<-- %s\n", __func__); | ||
2486 | } | 2676 | } |
2487 | 2677 | ||
2488 | /* | 2678 | /* |
@@ -2568,12 +2758,9 @@ error_splat_super: | |||
2568 | return error; | 2758 | return error; |
2569 | } | 2759 | } |
2570 | 2760 | ||
2571 | /* | 2761 | static int nfs4_remote_referral_get_sb(struct file_system_type *fs_type, |
2572 | * Create an NFS4 server record on referral traversal | 2762 | int flags, const char *dev_name, void *raw_data, |
2573 | */ | 2763 | struct vfsmount *mnt) |
2574 | static int nfs4_referral_get_sb(struct file_system_type *fs_type, int flags, | ||
2575 | const char *dev_name, void *raw_data, | ||
2576 | struct vfsmount *mnt) | ||
2577 | { | 2764 | { |
2578 | struct nfs_clone_mount *data = raw_data; | 2765 | struct nfs_clone_mount *data = raw_data; |
2579 | struct super_block *s; | 2766 | struct super_block *s; |
@@ -2652,4 +2839,36 @@ error_splat_super: | |||
2652 | return error; | 2839 | return error; |
2653 | } | 2840 | } |
2654 | 2841 | ||
2842 | /* | ||
2843 | * Create an NFS4 server record on referral traversal | ||
2844 | */ | ||
2845 | static int nfs4_referral_get_sb(struct file_system_type *fs_type, | ||
2846 | int flags, const char *dev_name, void *raw_data, | ||
2847 | struct vfsmount *mnt) | ||
2848 | { | ||
2849 | struct nfs_clone_mount *data = raw_data; | ||
2850 | char *export_path; | ||
2851 | struct vfsmount *root_mnt; | ||
2852 | int error; | ||
2853 | |||
2854 | dprintk("--> nfs4_referral_get_sb()\n"); | ||
2855 | |||
2856 | export_path = data->mnt_path; | ||
2857 | data->mnt_path = "/"; | ||
2858 | |||
2859 | root_mnt = nfs_do_root_mount(&nfs4_remote_referral_fs_type, | ||
2860 | flags, data, data->hostname); | ||
2861 | data->mnt_path = export_path; | ||
2862 | |||
2863 | error = PTR_ERR(root_mnt); | ||
2864 | if (IS_ERR(root_mnt)) | ||
2865 | goto out; | ||
2866 | |||
2867 | error = nfs_follow_remote_path(root_mnt, export_path, mnt); | ||
2868 | out: | ||
2869 | dprintk("<-- nfs4_referral_get_sb() = %d%s\n", error, | ||
2870 | error != 0 ? " [error]" : ""); | ||
2871 | return error; | ||
2872 | } | ||
2873 | |||
2655 | #endif /* CONFIG_NFS_V4 */ | 2874 | #endif /* CONFIG_NFS_V4 */ |
diff --git a/fs/nfs/unlink.c b/fs/nfs/unlink.c index ecc295347775..1064c91ae810 100644 --- a/fs/nfs/unlink.c +++ b/fs/nfs/unlink.c | |||
@@ -15,6 +15,7 @@ | |||
15 | #include <linux/wait.h> | 15 | #include <linux/wait.h> |
16 | 16 | ||
17 | #include "internal.h" | 17 | #include "internal.h" |
18 | #include "nfs4_fs.h" | ||
18 | 19 | ||
19 | struct nfs_unlinkdata { | 20 | struct nfs_unlinkdata { |
20 | struct hlist_node list; | 21 | struct hlist_node list; |
@@ -82,7 +83,7 @@ static void nfs_async_unlink_done(struct rpc_task *task, void *calldata) | |||
82 | struct inode *dir = data->dir; | 83 | struct inode *dir = data->dir; |
83 | 84 | ||
84 | if (!NFS_PROTO(dir)->unlink_done(task, dir)) | 85 | if (!NFS_PROTO(dir)->unlink_done(task, dir)) |
85 | rpc_restart_call(task); | 86 | nfs4_restart_rpc(task, NFS_SERVER(dir)->nfs_client); |
86 | } | 87 | } |
87 | 88 | ||
88 | /** | 89 | /** |
@@ -102,9 +103,25 @@ static void nfs_async_unlink_release(void *calldata) | |||
102 | nfs_sb_deactive(sb); | 103 | nfs_sb_deactive(sb); |
103 | } | 104 | } |
104 | 105 | ||
106 | #if defined(CONFIG_NFS_V4_1) | ||
107 | void nfs_unlink_prepare(struct rpc_task *task, void *calldata) | ||
108 | { | ||
109 | struct nfs_unlinkdata *data = calldata; | ||
110 | struct nfs_server *server = NFS_SERVER(data->dir); | ||
111 | |||
112 | if (nfs4_setup_sequence(server->nfs_client, &data->args.seq_args, | ||
113 | &data->res.seq_res, 1, task)) | ||
114 | return; | ||
115 | rpc_call_start(task); | ||
116 | } | ||
117 | #endif /* CONFIG_NFS_V4_1 */ | ||
118 | |||
105 | static const struct rpc_call_ops nfs_unlink_ops = { | 119 | static const struct rpc_call_ops nfs_unlink_ops = { |
106 | .rpc_call_done = nfs_async_unlink_done, | 120 | .rpc_call_done = nfs_async_unlink_done, |
107 | .rpc_release = nfs_async_unlink_release, | 121 | .rpc_release = nfs_async_unlink_release, |
122 | #if defined(CONFIG_NFS_V4_1) | ||
123 | .rpc_call_prepare = nfs_unlink_prepare, | ||
124 | #endif /* CONFIG_NFS_V4_1 */ | ||
108 | }; | 125 | }; |
109 | 126 | ||
110 | static int nfs_do_call_unlink(struct dentry *parent, struct inode *dir, struct nfs_unlinkdata *data) | 127 | static int nfs_do_call_unlink(struct dentry *parent, struct inode *dir, struct nfs_unlinkdata *data) |
@@ -241,6 +258,7 @@ nfs_async_unlink(struct inode *dir, struct dentry *dentry) | |||
241 | status = PTR_ERR(data->cred); | 258 | status = PTR_ERR(data->cred); |
242 | goto out_free; | 259 | goto out_free; |
243 | } | 260 | } |
261 | data->res.seq_res.sr_slotid = NFS4_MAX_SLOT_TABLE; | ||
244 | 262 | ||
245 | status = -EBUSY; | 263 | status = -EBUSY; |
246 | spin_lock(&dentry->d_lock); | 264 | spin_lock(&dentry->d_lock); |
diff --git a/fs/nfs/write.c b/fs/nfs/write.c index e560a78995a3..ce728829f79a 100644 --- a/fs/nfs/write.c +++ b/fs/nfs/write.c | |||
@@ -25,6 +25,7 @@ | |||
25 | #include "delegation.h" | 25 | #include "delegation.h" |
26 | #include "internal.h" | 26 | #include "internal.h" |
27 | #include "iostat.h" | 27 | #include "iostat.h" |
28 | #include "nfs4_fs.h" | ||
28 | 29 | ||
29 | #define NFSDBG_FACILITY NFSDBG_PAGECACHE | 30 | #define NFSDBG_FACILITY NFSDBG_PAGECACHE |
30 | 31 | ||
@@ -52,6 +53,7 @@ struct nfs_write_data *nfs_commitdata_alloc(void) | |||
52 | if (p) { | 53 | if (p) { |
53 | memset(p, 0, sizeof(*p)); | 54 | memset(p, 0, sizeof(*p)); |
54 | INIT_LIST_HEAD(&p->pages); | 55 | INIT_LIST_HEAD(&p->pages); |
56 | p->res.seq_res.sr_slotid = NFS4_MAX_SLOT_TABLE; | ||
55 | } | 57 | } |
56 | return p; | 58 | return p; |
57 | } | 59 | } |
@@ -71,6 +73,7 @@ struct nfs_write_data *nfs_writedata_alloc(unsigned int pagecount) | |||
71 | memset(p, 0, sizeof(*p)); | 73 | memset(p, 0, sizeof(*p)); |
72 | INIT_LIST_HEAD(&p->pages); | 74 | INIT_LIST_HEAD(&p->pages); |
73 | p->npages = pagecount; | 75 | p->npages = pagecount; |
76 | p->res.seq_res.sr_slotid = NFS4_MAX_SLOT_TABLE; | ||
74 | if (pagecount <= ARRAY_SIZE(p->page_array)) | 77 | if (pagecount <= ARRAY_SIZE(p->page_array)) |
75 | p->pagevec = p->page_array; | 78 | p->pagevec = p->page_array; |
76 | else { | 79 | else { |
@@ -1048,7 +1051,23 @@ out: | |||
1048 | nfs_writedata_release(calldata); | 1051 | nfs_writedata_release(calldata); |
1049 | } | 1052 | } |
1050 | 1053 | ||
1054 | #if defined(CONFIG_NFS_V4_1) | ||
1055 | void nfs_write_prepare(struct rpc_task *task, void *calldata) | ||
1056 | { | ||
1057 | struct nfs_write_data *data = calldata; | ||
1058 | struct nfs_client *clp = (NFS_SERVER(data->inode))->nfs_client; | ||
1059 | |||
1060 | if (nfs4_setup_sequence(clp, &data->args.seq_args, | ||
1061 | &data->res.seq_res, 1, task)) | ||
1062 | return; | ||
1063 | rpc_call_start(task); | ||
1064 | } | ||
1065 | #endif /* CONFIG_NFS_V4_1 */ | ||
1066 | |||
1051 | static const struct rpc_call_ops nfs_write_partial_ops = { | 1067 | static const struct rpc_call_ops nfs_write_partial_ops = { |
1068 | #if defined(CONFIG_NFS_V4_1) | ||
1069 | .rpc_call_prepare = nfs_write_prepare, | ||
1070 | #endif /* CONFIG_NFS_V4_1 */ | ||
1052 | .rpc_call_done = nfs_writeback_done_partial, | 1071 | .rpc_call_done = nfs_writeback_done_partial, |
1053 | .rpc_release = nfs_writeback_release_partial, | 1072 | .rpc_release = nfs_writeback_release_partial, |
1054 | }; | 1073 | }; |
@@ -1111,6 +1130,9 @@ remove_request: | |||
1111 | } | 1130 | } |
1112 | 1131 | ||
1113 | static const struct rpc_call_ops nfs_write_full_ops = { | 1132 | static const struct rpc_call_ops nfs_write_full_ops = { |
1133 | #if defined(CONFIG_NFS_V4_1) | ||
1134 | .rpc_call_prepare = nfs_write_prepare, | ||
1135 | #endif /* CONFIG_NFS_V4_1 */ | ||
1114 | .rpc_call_done = nfs_writeback_done_full, | 1136 | .rpc_call_done = nfs_writeback_done_full, |
1115 | .rpc_release = nfs_writeback_release_full, | 1137 | .rpc_release = nfs_writeback_release_full, |
1116 | }; | 1138 | }; |
@@ -1123,6 +1145,7 @@ int nfs_writeback_done(struct rpc_task *task, struct nfs_write_data *data) | |||
1123 | { | 1145 | { |
1124 | struct nfs_writeargs *argp = &data->args; | 1146 | struct nfs_writeargs *argp = &data->args; |
1125 | struct nfs_writeres *resp = &data->res; | 1147 | struct nfs_writeres *resp = &data->res; |
1148 | struct nfs_server *server = NFS_SERVER(data->inode); | ||
1126 | int status; | 1149 | int status; |
1127 | 1150 | ||
1128 | dprintk("NFS: %5u nfs_writeback_done (status %d)\n", | 1151 | dprintk("NFS: %5u nfs_writeback_done (status %d)\n", |
@@ -1155,7 +1178,7 @@ int nfs_writeback_done(struct rpc_task *task, struct nfs_write_data *data) | |||
1155 | if (time_before(complain, jiffies)) { | 1178 | if (time_before(complain, jiffies)) { |
1156 | dprintk("NFS: faulty NFS server %s:" | 1179 | dprintk("NFS: faulty NFS server %s:" |
1157 | " (committed = %d) != (stable = %d)\n", | 1180 | " (committed = %d) != (stable = %d)\n", |
1158 | NFS_SERVER(data->inode)->nfs_client->cl_hostname, | 1181 | server->nfs_client->cl_hostname, |
1159 | resp->verf->committed, argp->stable); | 1182 | resp->verf->committed, argp->stable); |
1160 | complain = jiffies + 300 * HZ; | 1183 | complain = jiffies + 300 * HZ; |
1161 | } | 1184 | } |
@@ -1181,7 +1204,7 @@ int nfs_writeback_done(struct rpc_task *task, struct nfs_write_data *data) | |||
1181 | */ | 1204 | */ |
1182 | argp->stable = NFS_FILE_SYNC; | 1205 | argp->stable = NFS_FILE_SYNC; |
1183 | } | 1206 | } |
1184 | rpc_restart_call(task); | 1207 | nfs4_restart_rpc(task, server->nfs_client); |
1185 | return -EAGAIN; | 1208 | return -EAGAIN; |
1186 | } | 1209 | } |
1187 | if (time_before(complain, jiffies)) { | 1210 | if (time_before(complain, jiffies)) { |
@@ -1193,6 +1216,7 @@ int nfs_writeback_done(struct rpc_task *task, struct nfs_write_data *data) | |||
1193 | /* Can't do anything about it except throw an error. */ | 1216 | /* Can't do anything about it except throw an error. */ |
1194 | task->tk_status = -EIO; | 1217 | task->tk_status = -EIO; |
1195 | } | 1218 | } |
1219 | nfs4_sequence_free_slot(server->nfs_client, &data->res.seq_res); | ||
1196 | return 0; | 1220 | return 0; |
1197 | } | 1221 | } |
1198 | 1222 | ||
@@ -1349,6 +1373,9 @@ static void nfs_commit_release(void *calldata) | |||
1349 | } | 1373 | } |
1350 | 1374 | ||
1351 | static const struct rpc_call_ops nfs_commit_ops = { | 1375 | static const struct rpc_call_ops nfs_commit_ops = { |
1376 | #if defined(CONFIG_NFS_V4_1) | ||
1377 | .rpc_call_prepare = nfs_write_prepare, | ||
1378 | #endif /* CONFIG_NFS_V4_1 */ | ||
1352 | .rpc_call_done = nfs_commit_done, | 1379 | .rpc_call_done = nfs_commit_done, |
1353 | .rpc_release = nfs_commit_release, | 1380 | .rpc_release = nfs_commit_release, |
1354 | }; | 1381 | }; |
diff --git a/fs/nfsd/export.c b/fs/nfsd/export.c index 8b1f8efb4690..b92a27629fb7 100644 --- a/fs/nfsd/export.c +++ b/fs/nfsd/export.c | |||
@@ -464,16 +464,11 @@ static int secinfo_parse(char **mesg, char *buf, struct svc_export *exp) | |||
464 | if (err) | 464 | if (err) |
465 | return err; | 465 | return err; |
466 | /* | 466 | /* |
467 | * Just a quick sanity check; we could also try to check | 467 | * XXX: It would be nice to also check whether this |
468 | * whether this pseudoflavor is supported, but at worst | 468 | * pseudoflavor is supported, so we can discover the |
469 | * an unsupported pseudoflavor on the export would just | 469 | * problem at export time instead of when a client fails |
470 | * be a pseudoflavor that won't match the flavor of any | 470 | * to authenticate. |
471 | * authenticated request. The administrator will | ||
472 | * probably discover the problem when someone fails to | ||
473 | * authenticate. | ||
474 | */ | 471 | */ |
475 | if (f->pseudoflavor < 0) | ||
476 | return -EINVAL; | ||
477 | err = get_int(mesg, &f->flags); | 472 | err = get_int(mesg, &f->flags); |
478 | if (err) | 473 | if (err) |
479 | return err; | 474 | return err; |
diff --git a/fs/nfsd/nfs3proc.c b/fs/nfsd/nfs3proc.c index 7c9fe838f038..a713c418a922 100644 --- a/fs/nfsd/nfs3proc.c +++ b/fs/nfsd/nfs3proc.c | |||
@@ -652,8 +652,6 @@ nfsd3_proc_commit(struct svc_rqst * rqstp, struct nfsd3_commitargs *argp, | |||
652 | * NFSv3 Server procedures. | 652 | * NFSv3 Server procedures. |
653 | * Only the results of non-idempotent operations are cached. | 653 | * Only the results of non-idempotent operations are cached. |
654 | */ | 654 | */ |
655 | #define nfs3svc_decode_voidargs NULL | ||
656 | #define nfs3svc_release_void NULL | ||
657 | #define nfs3svc_decode_fhandleargs nfs3svc_decode_fhandle | 655 | #define nfs3svc_decode_fhandleargs nfs3svc_decode_fhandle |
658 | #define nfs3svc_encode_attrstatres nfs3svc_encode_attrstat | 656 | #define nfs3svc_encode_attrstatres nfs3svc_encode_attrstat |
659 | #define nfs3svc_encode_wccstatres nfs3svc_encode_wccstat | 657 | #define nfs3svc_encode_wccstatres nfs3svc_encode_wccstat |
@@ -686,28 +684,219 @@ struct nfsd3_voidargs { int dummy; }; | |||
686 | #define WC (7+pAT) /* WCC attributes */ | 684 | #define WC (7+pAT) /* WCC attributes */ |
687 | 685 | ||
688 | static struct svc_procedure nfsd_procedures3[22] = { | 686 | static struct svc_procedure nfsd_procedures3[22] = { |
689 | PROC(null, void, void, void, RC_NOCACHE, ST), | 687 | [NFS3PROC_NULL] = { |
690 | PROC(getattr, fhandle, attrstat, fhandle, RC_NOCACHE, ST+AT), | 688 | .pc_func = (svc_procfunc) nfsd3_proc_null, |
691 | PROC(setattr, sattr, wccstat, fhandle, RC_REPLBUFF, ST+WC), | 689 | .pc_encode = (kxdrproc_t) nfs3svc_encode_voidres, |
692 | PROC(lookup, dirop, dirop, fhandle2, RC_NOCACHE, ST+FH+pAT+pAT), | 690 | .pc_argsize = sizeof(struct nfsd3_voidargs), |
693 | PROC(access, access, access, fhandle, RC_NOCACHE, ST+pAT+1), | 691 | .pc_ressize = sizeof(struct nfsd3_voidres), |
694 | PROC(readlink, readlink, readlink, fhandle, RC_NOCACHE, ST+pAT+1+NFS3_MAXPATHLEN/4), | 692 | .pc_cachetype = RC_NOCACHE, |
695 | PROC(read, read, read, fhandle, RC_NOCACHE, ST+pAT+4+NFSSVC_MAXBLKSIZE/4), | 693 | .pc_xdrressize = ST, |
696 | PROC(write, write, write, fhandle, RC_REPLBUFF, ST+WC+4), | 694 | }, |
697 | PROC(create, create, create, fhandle2, RC_REPLBUFF, ST+(1+FH+pAT)+WC), | 695 | [NFS3PROC_GETATTR] = { |
698 | PROC(mkdir, mkdir, create, fhandle2, RC_REPLBUFF, ST+(1+FH+pAT)+WC), | 696 | .pc_func = (svc_procfunc) nfsd3_proc_getattr, |
699 | PROC(symlink, symlink, create, fhandle2, RC_REPLBUFF, ST+(1+FH+pAT)+WC), | 697 | .pc_decode = (kxdrproc_t) nfs3svc_decode_fhandleargs, |
700 | PROC(mknod, mknod, create, fhandle2, RC_REPLBUFF, ST+(1+FH+pAT)+WC), | 698 | .pc_encode = (kxdrproc_t) nfs3svc_encode_attrstatres, |
701 | PROC(remove, dirop, wccstat, fhandle, RC_REPLBUFF, ST+WC), | 699 | .pc_release = (kxdrproc_t) nfs3svc_release_fhandle, |
702 | PROC(rmdir, dirop, wccstat, fhandle, RC_REPLBUFF, ST+WC), | 700 | .pc_argsize = sizeof(struct nfsd3_fhandleargs), |
703 | PROC(rename, rename, rename, fhandle2, RC_REPLBUFF, ST+WC+WC), | 701 | .pc_ressize = sizeof(struct nfsd3_attrstatres), |
704 | PROC(link, link, link, fhandle2, RC_REPLBUFF, ST+pAT+WC), | 702 | .pc_cachetype = RC_NOCACHE, |
705 | PROC(readdir, readdir, readdir, fhandle, RC_NOCACHE, 0), | 703 | .pc_xdrressize = ST+AT, |
706 | PROC(readdirplus,readdirplus, readdir, fhandle, RC_NOCACHE, 0), | 704 | }, |
707 | PROC(fsstat, fhandle, fsstat, void, RC_NOCACHE, ST+pAT+2*6+1), | 705 | [NFS3PROC_SETATTR] = { |
708 | PROC(fsinfo, fhandle, fsinfo, void, RC_NOCACHE, ST+pAT+12), | 706 | .pc_func = (svc_procfunc) nfsd3_proc_setattr, |
709 | PROC(pathconf, fhandle, pathconf, void, RC_NOCACHE, ST+pAT+6), | 707 | .pc_decode = (kxdrproc_t) nfs3svc_decode_sattrargs, |
710 | PROC(commit, commit, commit, fhandle, RC_NOCACHE, ST+WC+2), | 708 | .pc_encode = (kxdrproc_t) nfs3svc_encode_wccstatres, |
709 | .pc_release = (kxdrproc_t) nfs3svc_release_fhandle, | ||
710 | .pc_argsize = sizeof(struct nfsd3_sattrargs), | ||
711 | .pc_ressize = sizeof(struct nfsd3_wccstatres), | ||
712 | .pc_cachetype = RC_REPLBUFF, | ||
713 | .pc_xdrressize = ST+WC, | ||
714 | }, | ||
715 | [NFS3PROC_LOOKUP] = { | ||
716 | .pc_func = (svc_procfunc) nfsd3_proc_lookup, | ||
717 | .pc_decode = (kxdrproc_t) nfs3svc_decode_diropargs, | ||
718 | .pc_encode = (kxdrproc_t) nfs3svc_encode_diropres, | ||
719 | .pc_release = (kxdrproc_t) nfs3svc_release_fhandle2, | ||
720 | .pc_argsize = sizeof(struct nfsd3_diropargs), | ||
721 | .pc_ressize = sizeof(struct nfsd3_diropres), | ||
722 | .pc_cachetype = RC_NOCACHE, | ||
723 | .pc_xdrressize = ST+FH+pAT+pAT, | ||
724 | }, | ||
725 | [NFS3PROC_ACCESS] = { | ||
726 | .pc_func = (svc_procfunc) nfsd3_proc_access, | ||
727 | .pc_decode = (kxdrproc_t) nfs3svc_decode_accessargs, | ||
728 | .pc_encode = (kxdrproc_t) nfs3svc_encode_accessres, | ||
729 | .pc_release = (kxdrproc_t) nfs3svc_release_fhandle, | ||
730 | .pc_argsize = sizeof(struct nfsd3_accessargs), | ||
731 | .pc_ressize = sizeof(struct nfsd3_accessres), | ||
732 | .pc_cachetype = RC_NOCACHE, | ||
733 | .pc_xdrressize = ST+pAT+1, | ||
734 | }, | ||
735 | [NFS3PROC_READLINK] = { | ||
736 | .pc_func = (svc_procfunc) nfsd3_proc_readlink, | ||
737 | .pc_decode = (kxdrproc_t) nfs3svc_decode_readlinkargs, | ||
738 | .pc_encode = (kxdrproc_t) nfs3svc_encode_readlinkres, | ||
739 | .pc_release = (kxdrproc_t) nfs3svc_release_fhandle, | ||
740 | .pc_argsize = sizeof(struct nfsd3_readlinkargs), | ||
741 | .pc_ressize = sizeof(struct nfsd3_readlinkres), | ||
742 | .pc_cachetype = RC_NOCACHE, | ||
743 | .pc_xdrressize = ST+pAT+1+NFS3_MAXPATHLEN/4, | ||
744 | }, | ||
745 | [NFS3PROC_READ] = { | ||
746 | .pc_func = (svc_procfunc) nfsd3_proc_read, | ||
747 | .pc_decode = (kxdrproc_t) nfs3svc_decode_readargs, | ||
748 | .pc_encode = (kxdrproc_t) nfs3svc_encode_readres, | ||
749 | .pc_release = (kxdrproc_t) nfs3svc_release_fhandle, | ||
750 | .pc_argsize = sizeof(struct nfsd3_readargs), | ||
751 | .pc_ressize = sizeof(struct nfsd3_readres), | ||
752 | .pc_cachetype = RC_NOCACHE, | ||
753 | .pc_xdrressize = ST+pAT+4+NFSSVC_MAXBLKSIZE/4, | ||
754 | }, | ||
755 | [NFS3PROC_WRITE] = { | ||
756 | .pc_func = (svc_procfunc) nfsd3_proc_write, | ||
757 | .pc_decode = (kxdrproc_t) nfs3svc_decode_writeargs, | ||
758 | .pc_encode = (kxdrproc_t) nfs3svc_encode_writeres, | ||
759 | .pc_release = (kxdrproc_t) nfs3svc_release_fhandle, | ||
760 | .pc_argsize = sizeof(struct nfsd3_writeargs), | ||
761 | .pc_ressize = sizeof(struct nfsd3_writeres), | ||
762 | .pc_cachetype = RC_REPLBUFF, | ||
763 | .pc_xdrressize = ST+WC+4, | ||
764 | }, | ||
765 | [NFS3PROC_CREATE] = { | ||
766 | .pc_func = (svc_procfunc) nfsd3_proc_create, | ||
767 | .pc_decode = (kxdrproc_t) nfs3svc_decode_createargs, | ||
768 | .pc_encode = (kxdrproc_t) nfs3svc_encode_createres, | ||
769 | .pc_release = (kxdrproc_t) nfs3svc_release_fhandle2, | ||
770 | .pc_argsize = sizeof(struct nfsd3_createargs), | ||
771 | .pc_ressize = sizeof(struct nfsd3_createres), | ||
772 | .pc_cachetype = RC_REPLBUFF, | ||
773 | .pc_xdrressize = ST+(1+FH+pAT)+WC, | ||
774 | }, | ||
775 | [NFS3PROC_MKDIR] = { | ||
776 | .pc_func = (svc_procfunc) nfsd3_proc_mkdir, | ||
777 | .pc_decode = (kxdrproc_t) nfs3svc_decode_mkdirargs, | ||
778 | .pc_encode = (kxdrproc_t) nfs3svc_encode_createres, | ||
779 | .pc_release = (kxdrproc_t) nfs3svc_release_fhandle2, | ||
780 | .pc_argsize = sizeof(struct nfsd3_mkdirargs), | ||
781 | .pc_ressize = sizeof(struct nfsd3_createres), | ||
782 | .pc_cachetype = RC_REPLBUFF, | ||
783 | .pc_xdrressize = ST+(1+FH+pAT)+WC, | ||
784 | }, | ||
785 | [NFS3PROC_SYMLINK] = { | ||
786 | .pc_func = (svc_procfunc) nfsd3_proc_symlink, | ||
787 | .pc_decode = (kxdrproc_t) nfs3svc_decode_symlinkargs, | ||
788 | .pc_encode = (kxdrproc_t) nfs3svc_encode_createres, | ||
789 | .pc_release = (kxdrproc_t) nfs3svc_release_fhandle2, | ||
790 | .pc_argsize = sizeof(struct nfsd3_symlinkargs), | ||
791 | .pc_ressize = sizeof(struct nfsd3_createres), | ||
792 | .pc_cachetype = RC_REPLBUFF, | ||
793 | .pc_xdrressize = ST+(1+FH+pAT)+WC, | ||
794 | }, | ||
795 | [NFS3PROC_MKNOD] = { | ||
796 | .pc_func = (svc_procfunc) nfsd3_proc_mknod, | ||
797 | .pc_decode = (kxdrproc_t) nfs3svc_decode_mknodargs, | ||
798 | .pc_encode = (kxdrproc_t) nfs3svc_encode_createres, | ||
799 | .pc_release = (kxdrproc_t) nfs3svc_release_fhandle2, | ||
800 | .pc_argsize = sizeof(struct nfsd3_mknodargs), | ||
801 | .pc_ressize = sizeof(struct nfsd3_createres), | ||
802 | .pc_cachetype = RC_REPLBUFF, | ||
803 | .pc_xdrressize = ST+(1+FH+pAT)+WC, | ||
804 | }, | ||
805 | [NFS3PROC_REMOVE] = { | ||
806 | .pc_func = (svc_procfunc) nfsd3_proc_remove, | ||
807 | .pc_decode = (kxdrproc_t) nfs3svc_decode_diropargs, | ||
808 | .pc_encode = (kxdrproc_t) nfs3svc_encode_wccstatres, | ||
809 | .pc_release = (kxdrproc_t) nfs3svc_release_fhandle, | ||
810 | .pc_argsize = sizeof(struct nfsd3_diropargs), | ||
811 | .pc_ressize = sizeof(struct nfsd3_wccstatres), | ||
812 | .pc_cachetype = RC_REPLBUFF, | ||
813 | .pc_xdrressize = ST+WC, | ||
814 | }, | ||
815 | [NFS3PROC_RMDIR] = { | ||
816 | .pc_func = (svc_procfunc) nfsd3_proc_rmdir, | ||
817 | .pc_decode = (kxdrproc_t) nfs3svc_decode_diropargs, | ||
818 | .pc_encode = (kxdrproc_t) nfs3svc_encode_wccstatres, | ||
819 | .pc_release = (kxdrproc_t) nfs3svc_release_fhandle, | ||
820 | .pc_argsize = sizeof(struct nfsd3_diropargs), | ||
821 | .pc_ressize = sizeof(struct nfsd3_wccstatres), | ||
822 | .pc_cachetype = RC_REPLBUFF, | ||
823 | .pc_xdrressize = ST+WC, | ||
824 | }, | ||
825 | [NFS3PROC_RENAME] = { | ||
826 | .pc_func = (svc_procfunc) nfsd3_proc_rename, | ||
827 | .pc_decode = (kxdrproc_t) nfs3svc_decode_renameargs, | ||
828 | .pc_encode = (kxdrproc_t) nfs3svc_encode_renameres, | ||
829 | .pc_release = (kxdrproc_t) nfs3svc_release_fhandle2, | ||
830 | .pc_argsize = sizeof(struct nfsd3_renameargs), | ||
831 | .pc_ressize = sizeof(struct nfsd3_renameres), | ||
832 | .pc_cachetype = RC_REPLBUFF, | ||
833 | .pc_xdrressize = ST+WC+WC, | ||
834 | }, | ||
835 | [NFS3PROC_LINK] = { | ||
836 | .pc_func = (svc_procfunc) nfsd3_proc_link, | ||
837 | .pc_decode = (kxdrproc_t) nfs3svc_decode_linkargs, | ||
838 | .pc_encode = (kxdrproc_t) nfs3svc_encode_linkres, | ||
839 | .pc_release = (kxdrproc_t) nfs3svc_release_fhandle2, | ||
840 | .pc_argsize = sizeof(struct nfsd3_linkargs), | ||
841 | .pc_ressize = sizeof(struct nfsd3_linkres), | ||
842 | .pc_cachetype = RC_REPLBUFF, | ||
843 | .pc_xdrressize = ST+pAT+WC, | ||
844 | }, | ||
845 | [NFS3PROC_READDIR] = { | ||
846 | .pc_func = (svc_procfunc) nfsd3_proc_readdir, | ||
847 | .pc_decode = (kxdrproc_t) nfs3svc_decode_readdirargs, | ||
848 | .pc_encode = (kxdrproc_t) nfs3svc_encode_readdirres, | ||
849 | .pc_release = (kxdrproc_t) nfs3svc_release_fhandle, | ||
850 | .pc_argsize = sizeof(struct nfsd3_readdirargs), | ||
851 | .pc_ressize = sizeof(struct nfsd3_readdirres), | ||
852 | .pc_cachetype = RC_NOCACHE, | ||
853 | }, | ||
854 | [NFS3PROC_READDIRPLUS] = { | ||
855 | .pc_func = (svc_procfunc) nfsd3_proc_readdirplus, | ||
856 | .pc_decode = (kxdrproc_t) nfs3svc_decode_readdirplusargs, | ||
857 | .pc_encode = (kxdrproc_t) nfs3svc_encode_readdirres, | ||
858 | .pc_release = (kxdrproc_t) nfs3svc_release_fhandle, | ||
859 | .pc_argsize = sizeof(struct nfsd3_readdirplusargs), | ||
860 | .pc_ressize = sizeof(struct nfsd3_readdirres), | ||
861 | .pc_cachetype = RC_NOCACHE, | ||
862 | }, | ||
863 | [NFS3PROC_FSSTAT] = { | ||
864 | .pc_func = (svc_procfunc) nfsd3_proc_fsstat, | ||
865 | .pc_decode = (kxdrproc_t) nfs3svc_decode_fhandleargs, | ||
866 | .pc_encode = (kxdrproc_t) nfs3svc_encode_fsstatres, | ||
867 | .pc_argsize = sizeof(struct nfsd3_fhandleargs), | ||
868 | .pc_ressize = sizeof(struct nfsd3_fsstatres), | ||
869 | .pc_cachetype = RC_NOCACHE, | ||
870 | .pc_xdrressize = ST+pAT+2*6+1, | ||
871 | }, | ||
872 | [NFS3PROC_FSINFO] = { | ||
873 | .pc_func = (svc_procfunc) nfsd3_proc_fsinfo, | ||
874 | .pc_decode = (kxdrproc_t) nfs3svc_decode_fhandleargs, | ||
875 | .pc_encode = (kxdrproc_t) nfs3svc_encode_fsinfores, | ||
876 | .pc_argsize = sizeof(struct nfsd3_fhandleargs), | ||
877 | .pc_ressize = sizeof(struct nfsd3_fsinfores), | ||
878 | .pc_cachetype = RC_NOCACHE, | ||
879 | .pc_xdrressize = ST+pAT+12, | ||
880 | }, | ||
881 | [NFS3PROC_PATHCONF] = { | ||
882 | .pc_func = (svc_procfunc) nfsd3_proc_pathconf, | ||
883 | .pc_decode = (kxdrproc_t) nfs3svc_decode_fhandleargs, | ||
884 | .pc_encode = (kxdrproc_t) nfs3svc_encode_pathconfres, | ||
885 | .pc_argsize = sizeof(struct nfsd3_fhandleargs), | ||
886 | .pc_ressize = sizeof(struct nfsd3_pathconfres), | ||
887 | .pc_cachetype = RC_NOCACHE, | ||
888 | .pc_xdrressize = ST+pAT+6, | ||
889 | }, | ||
890 | [NFS3PROC_COMMIT] = { | ||
891 | .pc_func = (svc_procfunc) nfsd3_proc_commit, | ||
892 | .pc_decode = (kxdrproc_t) nfs3svc_decode_commitargs, | ||
893 | .pc_encode = (kxdrproc_t) nfs3svc_encode_commitres, | ||
894 | .pc_release = (kxdrproc_t) nfs3svc_release_fhandle, | ||
895 | .pc_argsize = sizeof(struct nfsd3_commitargs), | ||
896 | .pc_ressize = sizeof(struct nfsd3_commitres), | ||
897 | .pc_cachetype = RC_NOCACHE, | ||
898 | .pc_xdrressize = ST+WC+2, | ||
899 | }, | ||
711 | }; | 900 | }; |
712 | 901 | ||
713 | struct svc_version nfsd_version3 = { | 902 | struct svc_version nfsd_version3 = { |
diff --git a/fs/nfsd/nfs3xdr.c b/fs/nfsd/nfs3xdr.c index 17d0dd997204..01d4ec1c88e0 100644 --- a/fs/nfsd/nfs3xdr.c +++ b/fs/nfsd/nfs3xdr.c | |||
@@ -272,6 +272,7 @@ void fill_post_wcc(struct svc_fh *fhp) | |||
272 | 272 | ||
273 | err = vfs_getattr(fhp->fh_export->ex_path.mnt, fhp->fh_dentry, | 273 | err = vfs_getattr(fhp->fh_export->ex_path.mnt, fhp->fh_dentry, |
274 | &fhp->fh_post_attr); | 274 | &fhp->fh_post_attr); |
275 | fhp->fh_post_change = fhp->fh_dentry->d_inode->i_version; | ||
275 | if (err) | 276 | if (err) |
276 | fhp->fh_post_saved = 0; | 277 | fhp->fh_post_saved = 0; |
277 | else | 278 | else |
diff --git a/fs/nfsd/nfs4callback.c b/fs/nfsd/nfs4callback.c index 290289bd44f7..3fd23f7aceca 100644 --- a/fs/nfsd/nfs4callback.c +++ b/fs/nfsd/nfs4callback.c | |||
@@ -140,8 +140,10 @@ struct nfs4_cb_compound_hdr { | |||
140 | int status; | 140 | int status; |
141 | u32 ident; | 141 | u32 ident; |
142 | u32 nops; | 142 | u32 nops; |
143 | __be32 *nops_p; | ||
144 | u32 minorversion; | ||
143 | u32 taglen; | 145 | u32 taglen; |
144 | char * tag; | 146 | char *tag; |
145 | }; | 147 | }; |
146 | 148 | ||
147 | static struct { | 149 | static struct { |
@@ -201,33 +203,39 @@ nfs_cb_stat_to_errno(int stat) | |||
201 | * XDR encode | 203 | * XDR encode |
202 | */ | 204 | */ |
203 | 205 | ||
204 | static int | 206 | static void |
205 | encode_cb_compound_hdr(struct xdr_stream *xdr, struct nfs4_cb_compound_hdr *hdr) | 207 | encode_cb_compound_hdr(struct xdr_stream *xdr, struct nfs4_cb_compound_hdr *hdr) |
206 | { | 208 | { |
207 | __be32 * p; | 209 | __be32 * p; |
208 | 210 | ||
209 | RESERVE_SPACE(16); | 211 | RESERVE_SPACE(16); |
210 | WRITE32(0); /* tag length is always 0 */ | 212 | WRITE32(0); /* tag length is always 0 */ |
211 | WRITE32(NFS4_MINOR_VERSION); | 213 | WRITE32(hdr->minorversion); |
212 | WRITE32(hdr->ident); | 214 | WRITE32(hdr->ident); |
215 | hdr->nops_p = p; | ||
213 | WRITE32(hdr->nops); | 216 | WRITE32(hdr->nops); |
214 | return 0; | ||
215 | } | 217 | } |
216 | 218 | ||
217 | static int | 219 | static void encode_cb_nops(struct nfs4_cb_compound_hdr *hdr) |
218 | encode_cb_recall(struct xdr_stream *xdr, struct nfs4_cb_recall *cb_rec) | 220 | { |
221 | *hdr->nops_p = htonl(hdr->nops); | ||
222 | } | ||
223 | |||
224 | static void | ||
225 | encode_cb_recall(struct xdr_stream *xdr, struct nfs4_delegation *dp, | ||
226 | struct nfs4_cb_compound_hdr *hdr) | ||
219 | { | 227 | { |
220 | __be32 *p; | 228 | __be32 *p; |
221 | int len = cb_rec->cbr_fh.fh_size; | 229 | int len = dp->dl_fh.fh_size; |
222 | 230 | ||
223 | RESERVE_SPACE(12+sizeof(cb_rec->cbr_stateid) + len); | 231 | RESERVE_SPACE(12+sizeof(dp->dl_stateid) + len); |
224 | WRITE32(OP_CB_RECALL); | 232 | WRITE32(OP_CB_RECALL); |
225 | WRITE32(cb_rec->cbr_stateid.si_generation); | 233 | WRITE32(dp->dl_stateid.si_generation); |
226 | WRITEMEM(&cb_rec->cbr_stateid.si_opaque, sizeof(stateid_opaque_t)); | 234 | WRITEMEM(&dp->dl_stateid.si_opaque, sizeof(stateid_opaque_t)); |
227 | WRITE32(cb_rec->cbr_trunc); | 235 | WRITE32(0); /* truncate optimization not implemented */ |
228 | WRITE32(len); | 236 | WRITE32(len); |
229 | WRITEMEM(&cb_rec->cbr_fh.fh_base, len); | 237 | WRITEMEM(&dp->dl_fh.fh_base, len); |
230 | return 0; | 238 | hdr->nops++; |
231 | } | 239 | } |
232 | 240 | ||
233 | static int | 241 | static int |
@@ -241,17 +249,18 @@ nfs4_xdr_enc_cb_null(struct rpc_rqst *req, __be32 *p) | |||
241 | } | 249 | } |
242 | 250 | ||
243 | static int | 251 | static int |
244 | nfs4_xdr_enc_cb_recall(struct rpc_rqst *req, __be32 *p, struct nfs4_cb_recall *args) | 252 | nfs4_xdr_enc_cb_recall(struct rpc_rqst *req, __be32 *p, struct nfs4_delegation *args) |
245 | { | 253 | { |
246 | struct xdr_stream xdr; | 254 | struct xdr_stream xdr; |
247 | struct nfs4_cb_compound_hdr hdr = { | 255 | struct nfs4_cb_compound_hdr hdr = { |
248 | .ident = args->cbr_ident, | 256 | .ident = args->dl_ident, |
249 | .nops = 1, | ||
250 | }; | 257 | }; |
251 | 258 | ||
252 | xdr_init_encode(&xdr, &req->rq_snd_buf, p); | 259 | xdr_init_encode(&xdr, &req->rq_snd_buf, p); |
253 | encode_cb_compound_hdr(&xdr, &hdr); | 260 | encode_cb_compound_hdr(&xdr, &hdr); |
254 | return (encode_cb_recall(&xdr, args)); | 261 | encode_cb_recall(&xdr, args, &hdr); |
262 | encode_cb_nops(&hdr); | ||
263 | return 0; | ||
255 | } | 264 | } |
256 | 265 | ||
257 | 266 | ||
@@ -358,18 +367,21 @@ static struct rpc_program cb_program = { | |||
358 | .pipe_dir_name = "/nfsd4_cb", | 367 | .pipe_dir_name = "/nfsd4_cb", |
359 | }; | 368 | }; |
360 | 369 | ||
370 | static int max_cb_time(void) | ||
371 | { | ||
372 | return max(NFSD_LEASE_TIME/10, (time_t)1) * HZ; | ||
373 | } | ||
374 | |||
361 | /* Reference counting, callback cleanup, etc., all look racy as heck. | 375 | /* Reference counting, callback cleanup, etc., all look racy as heck. |
362 | * And why is cb_set an atomic? */ | 376 | * And why is cb_set an atomic? */ |
363 | 377 | ||
364 | static struct rpc_clnt *setup_callback_client(struct nfs4_client *clp) | 378 | int setup_callback_client(struct nfs4_client *clp) |
365 | { | 379 | { |
366 | struct sockaddr_in addr; | 380 | struct sockaddr_in addr; |
367 | struct nfs4_callback *cb = &clp->cl_callback; | 381 | struct nfs4_cb_conn *cb = &clp->cl_cb_conn; |
368 | struct rpc_timeout timeparms = { | 382 | struct rpc_timeout timeparms = { |
369 | .to_initval = (NFSD_LEASE_TIME/4) * HZ, | 383 | .to_initval = max_cb_time(), |
370 | .to_retries = 5, | 384 | .to_retries = 0, |
371 | .to_maxval = (NFSD_LEASE_TIME/2) * HZ, | ||
372 | .to_exponential = 1, | ||
373 | }; | 385 | }; |
374 | struct rpc_create_args args = { | 386 | struct rpc_create_args args = { |
375 | .protocol = IPPROTO_TCP, | 387 | .protocol = IPPROTO_TCP, |
@@ -386,7 +398,7 @@ static struct rpc_clnt *setup_callback_client(struct nfs4_client *clp) | |||
386 | struct rpc_clnt *client; | 398 | struct rpc_clnt *client; |
387 | 399 | ||
388 | if (!clp->cl_principal && (clp->cl_flavor >= RPC_AUTH_GSS_KRB5)) | 400 | if (!clp->cl_principal && (clp->cl_flavor >= RPC_AUTH_GSS_KRB5)) |
389 | return ERR_PTR(-EINVAL); | 401 | return -EINVAL; |
390 | 402 | ||
391 | /* Initialize address */ | 403 | /* Initialize address */ |
392 | memset(&addr, 0, sizeof(addr)); | 404 | memset(&addr, 0, sizeof(addr)); |
@@ -396,48 +408,77 @@ static struct rpc_clnt *setup_callback_client(struct nfs4_client *clp) | |||
396 | 408 | ||
397 | /* Create RPC client */ | 409 | /* Create RPC client */ |
398 | client = rpc_create(&args); | 410 | client = rpc_create(&args); |
399 | if (IS_ERR(client)) | 411 | if (IS_ERR(client)) { |
400 | dprintk("NFSD: couldn't create callback client: %ld\n", | 412 | dprintk("NFSD: couldn't create callback client: %ld\n", |
401 | PTR_ERR(client)); | 413 | PTR_ERR(client)); |
402 | return client; | 414 | return PTR_ERR(client); |
415 | } | ||
416 | cb->cb_client = client; | ||
417 | return 0; | ||
418 | |||
419 | } | ||
420 | |||
421 | static void warn_no_callback_path(struct nfs4_client *clp, int reason) | ||
422 | { | ||
423 | dprintk("NFSD: warning: no callback path to client %.*s: error %d\n", | ||
424 | (int)clp->cl_name.len, clp->cl_name.data, reason); | ||
425 | } | ||
426 | |||
427 | static void nfsd4_cb_probe_done(struct rpc_task *task, void *calldata) | ||
428 | { | ||
429 | struct nfs4_client *clp = calldata; | ||
430 | |||
431 | if (task->tk_status) | ||
432 | warn_no_callback_path(clp, task->tk_status); | ||
433 | else | ||
434 | atomic_set(&clp->cl_cb_conn.cb_set, 1); | ||
435 | put_nfs4_client(clp); | ||
436 | } | ||
437 | |||
438 | static const struct rpc_call_ops nfsd4_cb_probe_ops = { | ||
439 | .rpc_call_done = nfsd4_cb_probe_done, | ||
440 | }; | ||
403 | 441 | ||
442 | static struct rpc_cred *lookup_cb_cred(struct nfs4_cb_conn *cb) | ||
443 | { | ||
444 | struct auth_cred acred = { | ||
445 | .machine_cred = 1 | ||
446 | }; | ||
447 | |||
448 | /* | ||
449 | * Note in the gss case this doesn't actually have to wait for a | ||
450 | * gss upcall (or any calls to the client); this just creates a | ||
451 | * non-uptodate cred which the rpc state machine will fill in with | ||
452 | * a refresh_upcall later. | ||
453 | */ | ||
454 | return rpcauth_lookup_credcache(cb->cb_client->cl_auth, &acred, | ||
455 | RPCAUTH_LOOKUP_NEW); | ||
404 | } | 456 | } |
405 | 457 | ||
406 | static int do_probe_callback(void *data) | 458 | void do_probe_callback(struct nfs4_client *clp) |
407 | { | 459 | { |
408 | struct nfs4_client *clp = data; | 460 | struct nfs4_cb_conn *cb = &clp->cl_cb_conn; |
409 | struct nfs4_callback *cb = &clp->cl_callback; | ||
410 | struct rpc_message msg = { | 461 | struct rpc_message msg = { |
411 | .rpc_proc = &nfs4_cb_procedures[NFSPROC4_CLNT_CB_NULL], | 462 | .rpc_proc = &nfs4_cb_procedures[NFSPROC4_CLNT_CB_NULL], |
412 | .rpc_argp = clp, | 463 | .rpc_argp = clp, |
413 | }; | 464 | }; |
414 | struct rpc_clnt *client; | 465 | struct rpc_cred *cred; |
415 | int status; | 466 | int status; |
416 | 467 | ||
417 | client = setup_callback_client(clp); | 468 | cred = lookup_cb_cred(cb); |
418 | if (IS_ERR(client)) { | 469 | if (IS_ERR(cred)) { |
419 | status = PTR_ERR(client); | 470 | status = PTR_ERR(cred); |
420 | dprintk("NFSD: couldn't create callback client: %d\n", | 471 | goto out; |
421 | status); | 472 | } |
422 | goto out_err; | 473 | cb->cb_cred = cred; |
474 | msg.rpc_cred = cb->cb_cred; | ||
475 | status = rpc_call_async(cb->cb_client, &msg, RPC_TASK_SOFT, | ||
476 | &nfsd4_cb_probe_ops, (void *)clp); | ||
477 | out: | ||
478 | if (status) { | ||
479 | warn_no_callback_path(clp, status); | ||
480 | put_nfs4_client(clp); | ||
423 | } | 481 | } |
424 | |||
425 | status = rpc_call_sync(client, &msg, RPC_TASK_SOFT); | ||
426 | |||
427 | if (status) | ||
428 | goto out_release_client; | ||
429 | |||
430 | cb->cb_client = client; | ||
431 | atomic_set(&cb->cb_set, 1); | ||
432 | put_nfs4_client(clp); | ||
433 | return 0; | ||
434 | out_release_client: | ||
435 | rpc_shutdown_client(client); | ||
436 | out_err: | ||
437 | dprintk("NFSD: warning: no callback path to client %.*s: error %d\n", | ||
438 | (int)clp->cl_name.len, clp->cl_name.data, status); | ||
439 | put_nfs4_client(clp); | ||
440 | return 0; | ||
441 | } | 482 | } |
442 | 483 | ||
443 | /* | 484 | /* |
@@ -446,21 +487,65 @@ out_err: | |||
446 | void | 487 | void |
447 | nfsd4_probe_callback(struct nfs4_client *clp) | 488 | nfsd4_probe_callback(struct nfs4_client *clp) |
448 | { | 489 | { |
449 | struct task_struct *t; | 490 | int status; |
450 | 491 | ||
451 | BUG_ON(atomic_read(&clp->cl_callback.cb_set)); | 492 | BUG_ON(atomic_read(&clp->cl_cb_conn.cb_set)); |
493 | |||
494 | status = setup_callback_client(clp); | ||
495 | if (status) { | ||
496 | warn_no_callback_path(clp, status); | ||
497 | return; | ||
498 | } | ||
452 | 499 | ||
453 | /* the task holds a reference to the nfs4_client struct */ | 500 | /* the task holds a reference to the nfs4_client struct */ |
454 | atomic_inc(&clp->cl_count); | 501 | atomic_inc(&clp->cl_count); |
455 | 502 | ||
456 | t = kthread_run(do_probe_callback, clp, "nfs4_cb_probe"); | 503 | do_probe_callback(clp); |
504 | } | ||
457 | 505 | ||
458 | if (IS_ERR(t)) | 506 | static void nfsd4_cb_recall_done(struct rpc_task *task, void *calldata) |
459 | atomic_dec(&clp->cl_count); | 507 | { |
508 | struct nfs4_delegation *dp = calldata; | ||
509 | struct nfs4_client *clp = dp->dl_client; | ||
460 | 510 | ||
461 | return; | 511 | switch (task->tk_status) { |
512 | case -EIO: | ||
513 | /* Network partition? */ | ||
514 | atomic_set(&clp->cl_cb_conn.cb_set, 0); | ||
515 | warn_no_callback_path(clp, task->tk_status); | ||
516 | case -EBADHANDLE: | ||
517 | case -NFS4ERR_BAD_STATEID: | ||
518 | /* Race: client probably got cb_recall | ||
519 | * before open reply granting delegation */ | ||
520 | break; | ||
521 | default: | ||
522 | /* success, or error we can't handle */ | ||
523 | return; | ||
524 | } | ||
525 | if (dp->dl_retries--) { | ||
526 | rpc_delay(task, 2*HZ); | ||
527 | task->tk_status = 0; | ||
528 | rpc_restart_call(task); | ||
529 | } else { | ||
530 | atomic_set(&clp->cl_cb_conn.cb_set, 0); | ||
531 | warn_no_callback_path(clp, task->tk_status); | ||
532 | } | ||
533 | } | ||
534 | |||
535 | static void nfsd4_cb_recall_release(void *calldata) | ||
536 | { | ||
537 | struct nfs4_delegation *dp = calldata; | ||
538 | struct nfs4_client *clp = dp->dl_client; | ||
539 | |||
540 | nfs4_put_delegation(dp); | ||
541 | put_nfs4_client(clp); | ||
462 | } | 542 | } |
463 | 543 | ||
544 | static const struct rpc_call_ops nfsd4_cb_recall_ops = { | ||
545 | .rpc_call_done = nfsd4_cb_recall_done, | ||
546 | .rpc_release = nfsd4_cb_recall_release, | ||
547 | }; | ||
548 | |||
464 | /* | 549 | /* |
465 | * called with dp->dl_count inc'ed. | 550 | * called with dp->dl_count inc'ed. |
466 | */ | 551 | */ |
@@ -468,41 +553,19 @@ void | |||
468 | nfsd4_cb_recall(struct nfs4_delegation *dp) | 553 | nfsd4_cb_recall(struct nfs4_delegation *dp) |
469 | { | 554 | { |
470 | struct nfs4_client *clp = dp->dl_client; | 555 | struct nfs4_client *clp = dp->dl_client; |
471 | struct rpc_clnt *clnt = clp->cl_callback.cb_client; | 556 | struct rpc_clnt *clnt = clp->cl_cb_conn.cb_client; |
472 | struct nfs4_cb_recall *cbr = &dp->dl_recall; | ||
473 | struct rpc_message msg = { | 557 | struct rpc_message msg = { |
474 | .rpc_proc = &nfs4_cb_procedures[NFSPROC4_CLNT_CB_RECALL], | 558 | .rpc_proc = &nfs4_cb_procedures[NFSPROC4_CLNT_CB_RECALL], |
475 | .rpc_argp = cbr, | 559 | .rpc_argp = dp, |
560 | .rpc_cred = clp->cl_cb_conn.cb_cred | ||
476 | }; | 561 | }; |
477 | int retries = 1; | 562 | int status; |
478 | int status = 0; | 563 | |
479 | 564 | dp->dl_retries = 1; | |
480 | cbr->cbr_trunc = 0; /* XXX need to implement truncate optimization */ | 565 | status = rpc_call_async(clnt, &msg, RPC_TASK_SOFT, |
481 | cbr->cbr_dp = dp; | 566 | &nfsd4_cb_recall_ops, dp); |
482 | 567 | if (status) { | |
483 | status = rpc_call_sync(clnt, &msg, RPC_TASK_SOFT); | 568 | put_nfs4_client(clp); |
484 | while (retries--) { | 569 | nfs4_put_delegation(dp); |
485 | switch (status) { | ||
486 | case -EIO: | ||
487 | /* Network partition? */ | ||
488 | atomic_set(&clp->cl_callback.cb_set, 0); | ||
489 | case -EBADHANDLE: | ||
490 | case -NFS4ERR_BAD_STATEID: | ||
491 | /* Race: client probably got cb_recall | ||
492 | * before open reply granting delegation */ | ||
493 | break; | ||
494 | default: | ||
495 | goto out_put_cred; | ||
496 | } | ||
497 | ssleep(2); | ||
498 | status = rpc_call_sync(clnt, &msg, RPC_TASK_SOFT); | ||
499 | } | 570 | } |
500 | out_put_cred: | ||
501 | /* | ||
502 | * Success or failure, now we're either waiting for lease expiration | ||
503 | * or deleg_return. | ||
504 | */ | ||
505 | put_nfs4_client(clp); | ||
506 | nfs4_put_delegation(dp); | ||
507 | return; | ||
508 | } | 571 | } |
diff --git a/fs/nfsd/nfs4proc.c b/fs/nfsd/nfs4proc.c index b2883e9c6381..7c8801769a3c 100644 --- a/fs/nfsd/nfs4proc.c +++ b/fs/nfsd/nfs4proc.c | |||
@@ -51,6 +51,78 @@ | |||
51 | 51 | ||
52 | #define NFSDDBG_FACILITY NFSDDBG_PROC | 52 | #define NFSDDBG_FACILITY NFSDDBG_PROC |
53 | 53 | ||
54 | static u32 nfsd_attrmask[] = { | ||
55 | NFSD_WRITEABLE_ATTRS_WORD0, | ||
56 | NFSD_WRITEABLE_ATTRS_WORD1, | ||
57 | NFSD_WRITEABLE_ATTRS_WORD2 | ||
58 | }; | ||
59 | |||
60 | static u32 nfsd41_ex_attrmask[] = { | ||
61 | NFSD_SUPPATTR_EXCLCREAT_WORD0, | ||
62 | NFSD_SUPPATTR_EXCLCREAT_WORD1, | ||
63 | NFSD_SUPPATTR_EXCLCREAT_WORD2 | ||
64 | }; | ||
65 | |||
66 | static __be32 | ||
67 | check_attr_support(struct svc_rqst *rqstp, struct nfsd4_compound_state *cstate, | ||
68 | u32 *bmval, u32 *writable) | ||
69 | { | ||
70 | struct dentry *dentry = cstate->current_fh.fh_dentry; | ||
71 | struct svc_export *exp = cstate->current_fh.fh_export; | ||
72 | |||
73 | /* | ||
74 | * Check about attributes are supported by the NFSv4 server or not. | ||
75 | * According to spec, unsupported attributes return ERR_ATTRNOTSUPP. | ||
76 | */ | ||
77 | if ((bmval[0] & ~nfsd_suppattrs0(cstate->minorversion)) || | ||
78 | (bmval[1] & ~nfsd_suppattrs1(cstate->minorversion)) || | ||
79 | (bmval[2] & ~nfsd_suppattrs2(cstate->minorversion))) | ||
80 | return nfserr_attrnotsupp; | ||
81 | |||
82 | /* | ||
83 | * Check FATTR4_WORD0_ACL & FATTR4_WORD0_FS_LOCATIONS can be supported | ||
84 | * in current environment or not. | ||
85 | */ | ||
86 | if (bmval[0] & FATTR4_WORD0_ACL) { | ||
87 | if (!IS_POSIXACL(dentry->d_inode)) | ||
88 | return nfserr_attrnotsupp; | ||
89 | } | ||
90 | if (bmval[0] & FATTR4_WORD0_FS_LOCATIONS) { | ||
91 | if (exp->ex_fslocs.locations == NULL) | ||
92 | return nfserr_attrnotsupp; | ||
93 | } | ||
94 | |||
95 | /* | ||
96 | * According to spec, read-only attributes return ERR_INVAL. | ||
97 | */ | ||
98 | if (writable) { | ||
99 | if ((bmval[0] & ~writable[0]) || (bmval[1] & ~writable[1]) || | ||
100 | (bmval[2] & ~writable[2])) | ||
101 | return nfserr_inval; | ||
102 | } | ||
103 | |||
104 | return nfs_ok; | ||
105 | } | ||
106 | |||
107 | static __be32 | ||
108 | nfsd4_check_open_attributes(struct svc_rqst *rqstp, | ||
109 | struct nfsd4_compound_state *cstate, struct nfsd4_open *open) | ||
110 | { | ||
111 | __be32 status = nfs_ok; | ||
112 | |||
113 | if (open->op_create == NFS4_OPEN_CREATE) { | ||
114 | if (open->op_createmode == NFS4_CREATE_UNCHECKED | ||
115 | || open->op_createmode == NFS4_CREATE_GUARDED) | ||
116 | status = check_attr_support(rqstp, cstate, | ||
117 | open->op_bmval, nfsd_attrmask); | ||
118 | else if (open->op_createmode == NFS4_CREATE_EXCLUSIVE4_1) | ||
119 | status = check_attr_support(rqstp, cstate, | ||
120 | open->op_bmval, nfsd41_ex_attrmask); | ||
121 | } | ||
122 | |||
123 | return status; | ||
124 | } | ||
125 | |||
54 | static inline void | 126 | static inline void |
55 | fh_dup2(struct svc_fh *dst, struct svc_fh *src) | 127 | fh_dup2(struct svc_fh *dst, struct svc_fh *src) |
56 | { | 128 | { |
@@ -225,6 +297,10 @@ nfsd4_open(struct svc_rqst *rqstp, struct nfsd4_compound_state *cstate, | |||
225 | if (status) | 297 | if (status) |
226 | goto out; | 298 | goto out; |
227 | 299 | ||
300 | status = nfsd4_check_open_attributes(rqstp, cstate, open); | ||
301 | if (status) | ||
302 | goto out; | ||
303 | |||
228 | /* Openowner is now set, so sequence id will get bumped. Now we need | 304 | /* Openowner is now set, so sequence id will get bumped. Now we need |
229 | * these checks before we do any creates: */ | 305 | * these checks before we do any creates: */ |
230 | status = nfserr_grace; | 306 | status = nfserr_grace; |
@@ -395,6 +471,11 @@ nfsd4_create(struct svc_rqst *rqstp, struct nfsd4_compound_state *cstate, | |||
395 | if (status) | 471 | if (status) |
396 | return status; | 472 | return status; |
397 | 473 | ||
474 | status = check_attr_support(rqstp, cstate, create->cr_bmval, | ||
475 | nfsd_attrmask); | ||
476 | if (status) | ||
477 | return status; | ||
478 | |||
398 | switch (create->cr_type) { | 479 | switch (create->cr_type) { |
399 | case NF4LNK: | 480 | case NF4LNK: |
400 | /* ugh! we have to null-terminate the linktext, or | 481 | /* ugh! we have to null-terminate the linktext, or |
@@ -689,6 +770,12 @@ nfsd4_setattr(struct svc_rqst *rqstp, struct nfsd4_compound_state *cstate, | |||
689 | if (status) | 770 | if (status) |
690 | return status; | 771 | return status; |
691 | status = nfs_ok; | 772 | status = nfs_ok; |
773 | |||
774 | status = check_attr_support(rqstp, cstate, setattr->sa_bmval, | ||
775 | nfsd_attrmask); | ||
776 | if (status) | ||
777 | goto out; | ||
778 | |||
692 | if (setattr->sa_acl != NULL) | 779 | if (setattr->sa_acl != NULL) |
693 | status = nfsd4_set_nfs4_acl(rqstp, &cstate->current_fh, | 780 | status = nfsd4_set_nfs4_acl(rqstp, &cstate->current_fh, |
694 | setattr->sa_acl); | 781 | setattr->sa_acl); |
@@ -763,10 +850,10 @@ _nfsd4_verify(struct svc_rqst *rqstp, struct nfsd4_compound_state *cstate, | |||
763 | if (status) | 850 | if (status) |
764 | return status; | 851 | return status; |
765 | 852 | ||
766 | if ((verify->ve_bmval[0] & ~nfsd_suppattrs0(cstate->minorversion)) | 853 | status = check_attr_support(rqstp, cstate, verify->ve_bmval, NULL); |
767 | || (verify->ve_bmval[1] & ~nfsd_suppattrs1(cstate->minorversion)) | 854 | if (status) |
768 | || (verify->ve_bmval[2] & ~nfsd_suppattrs2(cstate->minorversion))) | 855 | return status; |
769 | return nfserr_attrnotsupp; | 856 | |
770 | if ((verify->ve_bmval[0] & FATTR4_WORD0_RDATTR_ERROR) | 857 | if ((verify->ve_bmval[0] & FATTR4_WORD0_RDATTR_ERROR) |
771 | || (verify->ve_bmval[1] & NFSD_WRITEONLY_ATTRS_WORD1)) | 858 | || (verify->ve_bmval[1] & NFSD_WRITEONLY_ATTRS_WORD1)) |
772 | return nfserr_inval; | 859 | return nfserr_inval; |
@@ -1226,24 +1313,9 @@ static const char *nfsd4_op_name(unsigned opnum) | |||
1226 | return "unknown_operation"; | 1313 | return "unknown_operation"; |
1227 | } | 1314 | } |
1228 | 1315 | ||
1229 | #define nfs4svc_decode_voidargs NULL | ||
1230 | #define nfs4svc_release_void NULL | ||
1231 | #define nfsd4_voidres nfsd4_voidargs | 1316 | #define nfsd4_voidres nfsd4_voidargs |
1232 | #define nfs4svc_release_compound NULL | ||
1233 | struct nfsd4_voidargs { int dummy; }; | 1317 | struct nfsd4_voidargs { int dummy; }; |
1234 | 1318 | ||
1235 | #define PROC(name, argt, rest, relt, cache, respsize) \ | ||
1236 | { (svc_procfunc) nfsd4_proc_##name, \ | ||
1237 | (kxdrproc_t) nfs4svc_decode_##argt##args, \ | ||
1238 | (kxdrproc_t) nfs4svc_encode_##rest##res, \ | ||
1239 | (kxdrproc_t) nfs4svc_release_##relt, \ | ||
1240 | sizeof(struct nfsd4_##argt##args), \ | ||
1241 | sizeof(struct nfsd4_##rest##res), \ | ||
1242 | 0, \ | ||
1243 | cache, \ | ||
1244 | respsize, \ | ||
1245 | } | ||
1246 | |||
1247 | /* | 1319 | /* |
1248 | * TODO: At the present time, the NFSv4 server does not do XID caching | 1320 | * TODO: At the present time, the NFSv4 server does not do XID caching |
1249 | * of requests. Implementing XID caching would not be a serious problem, | 1321 | * of requests. Implementing XID caching would not be a serious problem, |
@@ -1255,8 +1327,23 @@ struct nfsd4_voidargs { int dummy; }; | |||
1255 | * better XID's. | 1327 | * better XID's. |
1256 | */ | 1328 | */ |
1257 | static struct svc_procedure nfsd_procedures4[2] = { | 1329 | static struct svc_procedure nfsd_procedures4[2] = { |
1258 | PROC(null, void, void, void, RC_NOCACHE, 1), | 1330 | [NFSPROC4_NULL] = { |
1259 | PROC(compound, compound, compound, compound, RC_NOCACHE, NFSD_BUFSIZE/4) | 1331 | .pc_func = (svc_procfunc) nfsd4_proc_null, |
1332 | .pc_encode = (kxdrproc_t) nfs4svc_encode_voidres, | ||
1333 | .pc_argsize = sizeof(struct nfsd4_voidargs), | ||
1334 | .pc_ressize = sizeof(struct nfsd4_voidres), | ||
1335 | .pc_cachetype = RC_NOCACHE, | ||
1336 | .pc_xdrressize = 1, | ||
1337 | }, | ||
1338 | [NFSPROC4_COMPOUND] = { | ||
1339 | .pc_func = (svc_procfunc) nfsd4_proc_compound, | ||
1340 | .pc_decode = (kxdrproc_t) nfs4svc_decode_compoundargs, | ||
1341 | .pc_encode = (kxdrproc_t) nfs4svc_encode_compoundres, | ||
1342 | .pc_argsize = sizeof(struct nfsd4_compoundargs), | ||
1343 | .pc_ressize = sizeof(struct nfsd4_compoundres), | ||
1344 | .pc_cachetype = RC_NOCACHE, | ||
1345 | .pc_xdrressize = NFSD_BUFSIZE/4, | ||
1346 | }, | ||
1260 | }; | 1347 | }; |
1261 | 1348 | ||
1262 | struct svc_version nfsd_version4 = { | 1349 | struct svc_version nfsd_version4 = { |
diff --git a/fs/nfsd/nfs4state.c b/fs/nfsd/nfs4state.c index 3b711f5147a7..980a216a48c8 100644 --- a/fs/nfsd/nfs4state.c +++ b/fs/nfsd/nfs4state.c | |||
@@ -182,7 +182,7 @@ alloc_init_deleg(struct nfs4_client *clp, struct nfs4_stateid *stp, struct svc_f | |||
182 | { | 182 | { |
183 | struct nfs4_delegation *dp; | 183 | struct nfs4_delegation *dp; |
184 | struct nfs4_file *fp = stp->st_file; | 184 | struct nfs4_file *fp = stp->st_file; |
185 | struct nfs4_callback *cb = &stp->st_stateowner->so_client->cl_callback; | 185 | struct nfs4_cb_conn *cb = &stp->st_stateowner->so_client->cl_cb_conn; |
186 | 186 | ||
187 | dprintk("NFSD alloc_init_deleg\n"); | 187 | dprintk("NFSD alloc_init_deleg\n"); |
188 | if (fp->fi_had_conflict) | 188 | if (fp->fi_had_conflict) |
@@ -203,10 +203,8 @@ alloc_init_deleg(struct nfs4_client *clp, struct nfs4_stateid *stp, struct svc_f | |||
203 | get_file(stp->st_vfs_file); | 203 | get_file(stp->st_vfs_file); |
204 | dp->dl_vfs_file = stp->st_vfs_file; | 204 | dp->dl_vfs_file = stp->st_vfs_file; |
205 | dp->dl_type = type; | 205 | dp->dl_type = type; |
206 | dp->dl_recall.cbr_dp = NULL; | 206 | dp->dl_ident = cb->cb_ident; |
207 | dp->dl_recall.cbr_ident = cb->cb_ident; | 207 | dp->dl_stateid.si_boot = get_seconds(); |
208 | dp->dl_recall.cbr_trunc = 0; | ||
209 | dp->dl_stateid.si_boot = boot_time; | ||
210 | dp->dl_stateid.si_stateownerid = current_delegid++; | 208 | dp->dl_stateid.si_stateownerid = current_delegid++; |
211 | dp->dl_stateid.si_fileid = 0; | 209 | dp->dl_stateid.si_fileid = 0; |
212 | dp->dl_stateid.si_generation = 0; | 210 | dp->dl_stateid.si_generation = 0; |
@@ -427,6 +425,11 @@ static int set_forechannel_maxreqs(struct nfsd4_channel_attrs *fchan) | |||
427 | { | 425 | { |
428 | int status = 0, np = fchan->maxreqs * NFSD_PAGES_PER_SLOT; | 426 | int status = 0, np = fchan->maxreqs * NFSD_PAGES_PER_SLOT; |
429 | 427 | ||
428 | if (fchan->maxreqs < 1) | ||
429 | return nfserr_inval; | ||
430 | else if (fchan->maxreqs > NFSD_MAX_SLOTS_PER_SESSION) | ||
431 | fchan->maxreqs = NFSD_MAX_SLOTS_PER_SESSION; | ||
432 | |||
430 | spin_lock(&nfsd_serv->sv_lock); | 433 | spin_lock(&nfsd_serv->sv_lock); |
431 | if (np + nfsd_serv->sv_drc_pages_used > nfsd_serv->sv_drc_max_pages) | 434 | if (np + nfsd_serv->sv_drc_pages_used > nfsd_serv->sv_drc_max_pages) |
432 | np = nfsd_serv->sv_drc_max_pages - nfsd_serv->sv_drc_pages_used; | 435 | np = nfsd_serv->sv_drc_max_pages - nfsd_serv->sv_drc_pages_used; |
@@ -446,8 +449,8 @@ static int set_forechannel_maxreqs(struct nfsd4_channel_attrs *fchan) | |||
446 | * fchan holds the client values on input, and the server values on output | 449 | * fchan holds the client values on input, and the server values on output |
447 | */ | 450 | */ |
448 | static int init_forechannel_attrs(struct svc_rqst *rqstp, | 451 | static int init_forechannel_attrs(struct svc_rqst *rqstp, |
449 | struct nfsd4_session *session, | 452 | struct nfsd4_channel_attrs *session_fchan, |
450 | struct nfsd4_channel_attrs *fchan) | 453 | struct nfsd4_channel_attrs *fchan) |
451 | { | 454 | { |
452 | int status = 0; | 455 | int status = 0; |
453 | __u32 maxcount = svc_max_payload(rqstp); | 456 | __u32 maxcount = svc_max_payload(rqstp); |
@@ -457,21 +460,21 @@ static int init_forechannel_attrs(struct svc_rqst *rqstp, | |||
457 | /* Use the client's max request and max response size if possible */ | 460 | /* Use the client's max request and max response size if possible */ |
458 | if (fchan->maxreq_sz > maxcount) | 461 | if (fchan->maxreq_sz > maxcount) |
459 | fchan->maxreq_sz = maxcount; | 462 | fchan->maxreq_sz = maxcount; |
460 | session->se_fmaxreq_sz = fchan->maxreq_sz; | 463 | session_fchan->maxreq_sz = fchan->maxreq_sz; |
461 | 464 | ||
462 | if (fchan->maxresp_sz > maxcount) | 465 | if (fchan->maxresp_sz > maxcount) |
463 | fchan->maxresp_sz = maxcount; | 466 | fchan->maxresp_sz = maxcount; |
464 | session->se_fmaxresp_sz = fchan->maxresp_sz; | 467 | session_fchan->maxresp_sz = fchan->maxresp_sz; |
465 | 468 | ||
466 | /* Set the max response cached size our default which is | 469 | /* Set the max response cached size our default which is |
467 | * a multiple of PAGE_SIZE and small */ | 470 | * a multiple of PAGE_SIZE and small */ |
468 | session->se_fmaxresp_cached = NFSD_PAGES_PER_SLOT * PAGE_SIZE; | 471 | session_fchan->maxresp_cached = NFSD_PAGES_PER_SLOT * PAGE_SIZE; |
469 | fchan->maxresp_cached = session->se_fmaxresp_cached; | 472 | fchan->maxresp_cached = session_fchan->maxresp_cached; |
470 | 473 | ||
471 | /* Use the client's maxops if possible */ | 474 | /* Use the client's maxops if possible */ |
472 | if (fchan->maxops > NFSD_MAX_OPS_PER_COMPOUND) | 475 | if (fchan->maxops > NFSD_MAX_OPS_PER_COMPOUND) |
473 | fchan->maxops = NFSD_MAX_OPS_PER_COMPOUND; | 476 | fchan->maxops = NFSD_MAX_OPS_PER_COMPOUND; |
474 | session->se_fmaxops = fchan->maxops; | 477 | session_fchan->maxops = fchan->maxops; |
475 | 478 | ||
476 | /* try to use the client requested number of slots */ | 479 | /* try to use the client requested number of slots */ |
477 | if (fchan->maxreqs > NFSD_MAX_SLOTS_PER_SESSION) | 480 | if (fchan->maxreqs > NFSD_MAX_SLOTS_PER_SESSION) |
@@ -483,7 +486,7 @@ static int init_forechannel_attrs(struct svc_rqst *rqstp, | |||
483 | */ | 486 | */ |
484 | status = set_forechannel_maxreqs(fchan); | 487 | status = set_forechannel_maxreqs(fchan); |
485 | 488 | ||
486 | session->se_fnumslots = fchan->maxreqs; | 489 | session_fchan->maxreqs = fchan->maxreqs; |
487 | return status; | 490 | return status; |
488 | } | 491 | } |
489 | 492 | ||
@@ -497,12 +500,14 @@ alloc_init_session(struct svc_rqst *rqstp, struct nfs4_client *clp, | |||
497 | memset(&tmp, 0, sizeof(tmp)); | 500 | memset(&tmp, 0, sizeof(tmp)); |
498 | 501 | ||
499 | /* FIXME: For now, we just accept the client back channel attributes. */ | 502 | /* FIXME: For now, we just accept the client back channel attributes. */ |
500 | status = init_forechannel_attrs(rqstp, &tmp, &cses->fore_channel); | 503 | tmp.se_bchannel = cses->back_channel; |
504 | status = init_forechannel_attrs(rqstp, &tmp.se_fchannel, | ||
505 | &cses->fore_channel); | ||
501 | if (status) | 506 | if (status) |
502 | goto out; | 507 | goto out; |
503 | 508 | ||
504 | /* allocate struct nfsd4_session and slot table in one piece */ | 509 | /* allocate struct nfsd4_session and slot table in one piece */ |
505 | slotsize = tmp.se_fnumslots * sizeof(struct nfsd4_slot); | 510 | slotsize = tmp.se_fchannel.maxreqs * sizeof(struct nfsd4_slot); |
506 | new = kzalloc(sizeof(*new) + slotsize, GFP_KERNEL); | 511 | new = kzalloc(sizeof(*new) + slotsize, GFP_KERNEL); |
507 | if (!new) | 512 | if (!new) |
508 | goto out; | 513 | goto out; |
@@ -576,7 +581,7 @@ free_session(struct kref *kref) | |||
576 | int i; | 581 | int i; |
577 | 582 | ||
578 | ses = container_of(kref, struct nfsd4_session, se_ref); | 583 | ses = container_of(kref, struct nfsd4_session, se_ref); |
579 | for (i = 0; i < ses->se_fnumslots; i++) { | 584 | for (i = 0; i < ses->se_fchannel.maxreqs; i++) { |
580 | struct nfsd4_cache_entry *e = &ses->se_slots[i].sl_cache_entry; | 585 | struct nfsd4_cache_entry *e = &ses->se_slots[i].sl_cache_entry; |
581 | nfsd4_release_respages(e->ce_respages, e->ce_resused); | 586 | nfsd4_release_respages(e->ce_respages, e->ce_resused); |
582 | } | 587 | } |
@@ -632,16 +637,20 @@ static struct nfs4_client *alloc_client(struct xdr_netobj name) | |||
632 | static void | 637 | static void |
633 | shutdown_callback_client(struct nfs4_client *clp) | 638 | shutdown_callback_client(struct nfs4_client *clp) |
634 | { | 639 | { |
635 | struct rpc_clnt *clnt = clp->cl_callback.cb_client; | 640 | struct rpc_clnt *clnt = clp->cl_cb_conn.cb_client; |
636 | 641 | ||
637 | if (clnt) { | 642 | if (clnt) { |
638 | /* | 643 | /* |
639 | * Callback threads take a reference on the client, so there | 644 | * Callback threads take a reference on the client, so there |
640 | * should be no outstanding callbacks at this point. | 645 | * should be no outstanding callbacks at this point. |
641 | */ | 646 | */ |
642 | clp->cl_callback.cb_client = NULL; | 647 | clp->cl_cb_conn.cb_client = NULL; |
643 | rpc_shutdown_client(clnt); | 648 | rpc_shutdown_client(clnt); |
644 | } | 649 | } |
650 | if (clp->cl_cb_conn.cb_cred) { | ||
651 | put_rpccred(clp->cl_cb_conn.cb_cred); | ||
652 | clp->cl_cb_conn.cb_cred = NULL; | ||
653 | } | ||
645 | } | 654 | } |
646 | 655 | ||
647 | static inline void | 656 | static inline void |
@@ -714,7 +723,7 @@ static struct nfs4_client *create_client(struct xdr_netobj name, char *recdir) | |||
714 | return NULL; | 723 | return NULL; |
715 | memcpy(clp->cl_recdir, recdir, HEXDIR_LEN); | 724 | memcpy(clp->cl_recdir, recdir, HEXDIR_LEN); |
716 | atomic_set(&clp->cl_count, 1); | 725 | atomic_set(&clp->cl_count, 1); |
717 | atomic_set(&clp->cl_callback.cb_set, 0); | 726 | atomic_set(&clp->cl_cb_conn.cb_set, 0); |
718 | INIT_LIST_HEAD(&clp->cl_idhash); | 727 | INIT_LIST_HEAD(&clp->cl_idhash); |
719 | INIT_LIST_HEAD(&clp->cl_strhash); | 728 | INIT_LIST_HEAD(&clp->cl_strhash); |
720 | INIT_LIST_HEAD(&clp->cl_openowners); | 729 | INIT_LIST_HEAD(&clp->cl_openowners); |
@@ -966,7 +975,7 @@ parse_ipv4(unsigned int addr_len, char *addr_val, unsigned int *cbaddrp, unsigne | |||
966 | static void | 975 | static void |
967 | gen_callback(struct nfs4_client *clp, struct nfsd4_setclientid *se) | 976 | gen_callback(struct nfs4_client *clp, struct nfsd4_setclientid *se) |
968 | { | 977 | { |
969 | struct nfs4_callback *cb = &clp->cl_callback; | 978 | struct nfs4_cb_conn *cb = &clp->cl_cb_conn; |
970 | 979 | ||
971 | /* Currently, we only support tcp for the callback channel */ | 980 | /* Currently, we only support tcp for the callback channel */ |
972 | if ((se->se_callback_netid_len != 3) || memcmp((char *)se->se_callback_netid_val, "tcp", 3)) | 981 | if ((se->se_callback_netid_len != 3) || memcmp((char *)se->se_callback_netid_val, "tcp", 3)) |
@@ -975,6 +984,7 @@ gen_callback(struct nfs4_client *clp, struct nfsd4_setclientid *se) | |||
975 | if ( !(parse_ipv4(se->se_callback_addr_len, se->se_callback_addr_val, | 984 | if ( !(parse_ipv4(se->se_callback_addr_len, se->se_callback_addr_val, |
976 | &cb->cb_addr, &cb->cb_port))) | 985 | &cb->cb_addr, &cb->cb_port))) |
977 | goto out_err; | 986 | goto out_err; |
987 | cb->cb_minorversion = 0; | ||
978 | cb->cb_prog = se->se_callback_prog; | 988 | cb->cb_prog = se->se_callback_prog; |
979 | cb->cb_ident = se->se_callback_ident; | 989 | cb->cb_ident = se->se_callback_ident; |
980 | return; | 990 | return; |
@@ -1128,7 +1138,7 @@ nfsd4_replay_cache_entry(struct nfsd4_compoundres *resp, | |||
1128 | * is sent (lease renewal). | 1138 | * is sent (lease renewal). |
1129 | */ | 1139 | */ |
1130 | if (seq && nfsd4_not_cached(resp)) { | 1140 | if (seq && nfsd4_not_cached(resp)) { |
1131 | seq->maxslots = resp->cstate.session->se_fnumslots; | 1141 | seq->maxslots = resp->cstate.session->se_fchannel.maxreqs; |
1132 | return nfs_ok; | 1142 | return nfs_ok; |
1133 | } | 1143 | } |
1134 | 1144 | ||
@@ -1238,12 +1248,6 @@ nfsd4_exchange_id(struct svc_rqst *rqstp, | |||
1238 | expire_client(conf); | 1248 | expire_client(conf); |
1239 | goto out_new; | 1249 | goto out_new; |
1240 | } | 1250 | } |
1241 | if (ip_addr != conf->cl_addr && | ||
1242 | !(exid->flags & EXCHGID4_FLAG_UPD_CONFIRMED_REC_A)) { | ||
1243 | /* Client collision. 18.35.4 case 3 */ | ||
1244 | status = nfserr_clid_inuse; | ||
1245 | goto out; | ||
1246 | } | ||
1247 | /* | 1251 | /* |
1248 | * Set bit when the owner id and verifier map to an already | 1252 | * Set bit when the owner id and verifier map to an already |
1249 | * confirmed client id (18.35.3). | 1253 | * confirmed client id (18.35.3). |
@@ -1257,12 +1261,12 @@ nfsd4_exchange_id(struct svc_rqst *rqstp, | |||
1257 | copy_verf(conf, &verf); | 1261 | copy_verf(conf, &verf); |
1258 | new = conf; | 1262 | new = conf; |
1259 | goto out_copy; | 1263 | goto out_copy; |
1260 | } else { | 1264 | } |
1261 | /* 18.35.4 case 7 */ | 1265 | |
1262 | if (exid->flags & EXCHGID4_FLAG_UPD_CONFIRMED_REC_A) { | 1266 | /* 18.35.4 case 7 */ |
1263 | status = nfserr_noent; | 1267 | if (exid->flags & EXCHGID4_FLAG_UPD_CONFIRMED_REC_A) { |
1264 | goto out; | 1268 | status = nfserr_noent; |
1265 | } | 1269 | goto out; |
1266 | } | 1270 | } |
1267 | 1271 | ||
1268 | unconf = find_unconfirmed_client_by_str(dname, strhashval, true); | 1272 | unconf = find_unconfirmed_client_by_str(dname, strhashval, true); |
@@ -1471,7 +1475,7 @@ nfsd4_sequence(struct svc_rqst *rqstp, | |||
1471 | goto out; | 1475 | goto out; |
1472 | 1476 | ||
1473 | status = nfserr_badslot; | 1477 | status = nfserr_badslot; |
1474 | if (seq->slotid >= session->se_fnumslots) | 1478 | if (seq->slotid >= session->se_fchannel.maxreqs) |
1475 | goto out; | 1479 | goto out; |
1476 | 1480 | ||
1477 | slot = &session->se_slots[seq->slotid]; | 1481 | slot = &session->se_slots[seq->slotid]; |
@@ -1686,9 +1690,7 @@ nfsd4_setclientid_confirm(struct svc_rqst *rqstp, | |||
1686 | else { | 1690 | else { |
1687 | /* XXX: We just turn off callbacks until we can handle | 1691 | /* XXX: We just turn off callbacks until we can handle |
1688 | * change request correctly. */ | 1692 | * change request correctly. */ |
1689 | atomic_set(&conf->cl_callback.cb_set, 0); | 1693 | atomic_set(&conf->cl_cb_conn.cb_set, 0); |
1690 | gen_confirm(conf); | ||
1691 | nfsd4_remove_clid_dir(unconf); | ||
1692 | expire_client(unconf); | 1694 | expire_client(unconf); |
1693 | status = nfs_ok; | 1695 | status = nfs_ok; |
1694 | 1696 | ||
@@ -1882,7 +1884,7 @@ init_stateid(struct nfs4_stateid *stp, struct nfs4_file *fp, struct nfsd4_open * | |||
1882 | stp->st_stateowner = sop; | 1884 | stp->st_stateowner = sop; |
1883 | get_nfs4_file(fp); | 1885 | get_nfs4_file(fp); |
1884 | stp->st_file = fp; | 1886 | stp->st_file = fp; |
1885 | stp->st_stateid.si_boot = boot_time; | 1887 | stp->st_stateid.si_boot = get_seconds(); |
1886 | stp->st_stateid.si_stateownerid = sop->so_id; | 1888 | stp->st_stateid.si_stateownerid = sop->so_id; |
1887 | stp->st_stateid.si_fileid = fp->fi_id; | 1889 | stp->st_stateid.si_fileid = fp->fi_id; |
1888 | stp->st_stateid.si_generation = 0; | 1890 | stp->st_stateid.si_generation = 0; |
@@ -2059,19 +2061,6 @@ nfs4_file_downgrade(struct file *filp, unsigned int share_access) | |||
2059 | } | 2061 | } |
2060 | 2062 | ||
2061 | /* | 2063 | /* |
2062 | * Recall a delegation | ||
2063 | */ | ||
2064 | static int | ||
2065 | do_recall(void *__dp) | ||
2066 | { | ||
2067 | struct nfs4_delegation *dp = __dp; | ||
2068 | |||
2069 | dp->dl_file->fi_had_conflict = true; | ||
2070 | nfsd4_cb_recall(dp); | ||
2071 | return 0; | ||
2072 | } | ||
2073 | |||
2074 | /* | ||
2075 | * Spawn a thread to perform a recall on the delegation represented | 2064 | * Spawn a thread to perform a recall on the delegation represented |
2076 | * by the lease (file_lock) | 2065 | * by the lease (file_lock) |
2077 | * | 2066 | * |
@@ -2082,8 +2071,7 @@ do_recall(void *__dp) | |||
2082 | static | 2071 | static |
2083 | void nfsd_break_deleg_cb(struct file_lock *fl) | 2072 | void nfsd_break_deleg_cb(struct file_lock *fl) |
2084 | { | 2073 | { |
2085 | struct nfs4_delegation *dp= (struct nfs4_delegation *)fl->fl_owner; | 2074 | struct nfs4_delegation *dp = (struct nfs4_delegation *)fl->fl_owner; |
2086 | struct task_struct *t; | ||
2087 | 2075 | ||
2088 | dprintk("NFSD nfsd_break_deleg_cb: dp %p fl %p\n",dp,fl); | 2076 | dprintk("NFSD nfsd_break_deleg_cb: dp %p fl %p\n",dp,fl); |
2089 | if (!dp) | 2077 | if (!dp) |
@@ -2111,16 +2099,8 @@ void nfsd_break_deleg_cb(struct file_lock *fl) | |||
2111 | */ | 2099 | */ |
2112 | fl->fl_break_time = 0; | 2100 | fl->fl_break_time = 0; |
2113 | 2101 | ||
2114 | t = kthread_run(do_recall, dp, "%s", "nfs4_cb_recall"); | 2102 | dp->dl_file->fi_had_conflict = true; |
2115 | if (IS_ERR(t)) { | 2103 | nfsd4_cb_recall(dp); |
2116 | struct nfs4_client *clp = dp->dl_client; | ||
2117 | |||
2118 | printk(KERN_INFO "NFSD: Callback thread failed for " | ||
2119 | "for client (clientid %08x/%08x)\n", | ||
2120 | clp->cl_clientid.cl_boot, clp->cl_clientid.cl_id); | ||
2121 | put_nfs4_client(dp->dl_client); | ||
2122 | nfs4_put_delegation(dp); | ||
2123 | } | ||
2124 | } | 2104 | } |
2125 | 2105 | ||
2126 | /* | 2106 | /* |
@@ -2422,7 +2402,7 @@ nfs4_open_delegation(struct svc_fh *fh, struct nfsd4_open *open, struct nfs4_sta | |||
2422 | { | 2402 | { |
2423 | struct nfs4_delegation *dp; | 2403 | struct nfs4_delegation *dp; |
2424 | struct nfs4_stateowner *sop = stp->st_stateowner; | 2404 | struct nfs4_stateowner *sop = stp->st_stateowner; |
2425 | struct nfs4_callback *cb = &sop->so_client->cl_callback; | 2405 | struct nfs4_cb_conn *cb = &sop->so_client->cl_cb_conn; |
2426 | struct file_lock fl, *flp = &fl; | 2406 | struct file_lock fl, *flp = &fl; |
2427 | int status, flag = 0; | 2407 | int status, flag = 0; |
2428 | 2408 | ||
@@ -2614,7 +2594,7 @@ nfsd4_renew(struct svc_rqst *rqstp, struct nfsd4_compound_state *cstate, | |||
2614 | renew_client(clp); | 2594 | renew_client(clp); |
2615 | status = nfserr_cb_path_down; | 2595 | status = nfserr_cb_path_down; |
2616 | if (!list_empty(&clp->cl_delegations) | 2596 | if (!list_empty(&clp->cl_delegations) |
2617 | && !atomic_read(&clp->cl_callback.cb_set)) | 2597 | && !atomic_read(&clp->cl_cb_conn.cb_set)) |
2618 | goto out; | 2598 | goto out; |
2619 | status = nfs_ok; | 2599 | status = nfs_ok; |
2620 | out: | 2600 | out: |
@@ -2738,12 +2718,42 @@ nfs4_check_fh(struct svc_fh *fhp, struct nfs4_stateid *stp) | |||
2738 | static int | 2718 | static int |
2739 | STALE_STATEID(stateid_t *stateid) | 2719 | STALE_STATEID(stateid_t *stateid) |
2740 | { | 2720 | { |
2741 | if (stateid->si_boot == boot_time) | 2721 | if (time_after((unsigned long)boot_time, |
2742 | return 0; | 2722 | (unsigned long)stateid->si_boot)) { |
2743 | dprintk("NFSD: stale stateid (%08x/%08x/%08x/%08x)!\n", | 2723 | dprintk("NFSD: stale stateid (%08x/%08x/%08x/%08x)!\n", |
2744 | stateid->si_boot, stateid->si_stateownerid, stateid->si_fileid, | 2724 | stateid->si_boot, stateid->si_stateownerid, |
2745 | stateid->si_generation); | 2725 | stateid->si_fileid, stateid->si_generation); |
2746 | return 1; | 2726 | return 1; |
2727 | } | ||
2728 | return 0; | ||
2729 | } | ||
2730 | |||
2731 | static int | ||
2732 | EXPIRED_STATEID(stateid_t *stateid) | ||
2733 | { | ||
2734 | if (time_before((unsigned long)boot_time, | ||
2735 | ((unsigned long)stateid->si_boot)) && | ||
2736 | time_before((unsigned long)(stateid->si_boot + lease_time), get_seconds())) { | ||
2737 | dprintk("NFSD: expired stateid (%08x/%08x/%08x/%08x)!\n", | ||
2738 | stateid->si_boot, stateid->si_stateownerid, | ||
2739 | stateid->si_fileid, stateid->si_generation); | ||
2740 | return 1; | ||
2741 | } | ||
2742 | return 0; | ||
2743 | } | ||
2744 | |||
2745 | static __be32 | ||
2746 | stateid_error_map(stateid_t *stateid) | ||
2747 | { | ||
2748 | if (STALE_STATEID(stateid)) | ||
2749 | return nfserr_stale_stateid; | ||
2750 | if (EXPIRED_STATEID(stateid)) | ||
2751 | return nfserr_expired; | ||
2752 | |||
2753 | dprintk("NFSD: bad stateid (%08x/%08x/%08x/%08x)!\n", | ||
2754 | stateid->si_boot, stateid->si_stateownerid, | ||
2755 | stateid->si_fileid, stateid->si_generation); | ||
2756 | return nfserr_bad_stateid; | ||
2747 | } | 2757 | } |
2748 | 2758 | ||
2749 | static inline int | 2759 | static inline int |
@@ -2867,8 +2877,10 @@ nfs4_preprocess_stateid_op(struct nfsd4_compound_state *cstate, | |||
2867 | status = nfserr_bad_stateid; | 2877 | status = nfserr_bad_stateid; |
2868 | if (is_delegation_stateid(stateid)) { | 2878 | if (is_delegation_stateid(stateid)) { |
2869 | dp = find_delegation_stateid(ino, stateid); | 2879 | dp = find_delegation_stateid(ino, stateid); |
2870 | if (!dp) | 2880 | if (!dp) { |
2881 | status = stateid_error_map(stateid); | ||
2871 | goto out; | 2882 | goto out; |
2883 | } | ||
2872 | status = check_stateid_generation(stateid, &dp->dl_stateid, | 2884 | status = check_stateid_generation(stateid, &dp->dl_stateid, |
2873 | flags); | 2885 | flags); |
2874 | if (status) | 2886 | if (status) |
@@ -2881,8 +2893,10 @@ nfs4_preprocess_stateid_op(struct nfsd4_compound_state *cstate, | |||
2881 | *filpp = dp->dl_vfs_file; | 2893 | *filpp = dp->dl_vfs_file; |
2882 | } else { /* open or lock stateid */ | 2894 | } else { /* open or lock stateid */ |
2883 | stp = find_stateid(stateid, flags); | 2895 | stp = find_stateid(stateid, flags); |
2884 | if (!stp) | 2896 | if (!stp) { |
2897 | status = stateid_error_map(stateid); | ||
2885 | goto out; | 2898 | goto out; |
2899 | } | ||
2886 | if (nfs4_check_fh(current_fh, stp)) | 2900 | if (nfs4_check_fh(current_fh, stp)) |
2887 | goto out; | 2901 | goto out; |
2888 | if (!stp->st_stateowner->so_confirmed) | 2902 | if (!stp->st_stateowner->so_confirmed) |
@@ -2956,7 +2970,7 @@ nfs4_preprocess_seqid_op(struct nfsd4_compound_state *cstate, u32 seqid, | |||
2956 | */ | 2970 | */ |
2957 | sop = search_close_lru(stateid->si_stateownerid, flags); | 2971 | sop = search_close_lru(stateid->si_stateownerid, flags); |
2958 | if (sop == NULL) | 2972 | if (sop == NULL) |
2959 | return nfserr_bad_stateid; | 2973 | return stateid_error_map(stateid); |
2960 | *sopp = sop; | 2974 | *sopp = sop; |
2961 | goto check_replay; | 2975 | goto check_replay; |
2962 | } | 2976 | } |
@@ -3227,8 +3241,10 @@ nfsd4_delegreturn(struct svc_rqst *rqstp, struct nfsd4_compound_state *cstate, | |||
3227 | if (!is_delegation_stateid(stateid)) | 3241 | if (!is_delegation_stateid(stateid)) |
3228 | goto out; | 3242 | goto out; |
3229 | dp = find_delegation_stateid(inode, stateid); | 3243 | dp = find_delegation_stateid(inode, stateid); |
3230 | if (!dp) | 3244 | if (!dp) { |
3245 | status = stateid_error_map(stateid); | ||
3231 | goto out; | 3246 | goto out; |
3247 | } | ||
3232 | status = check_stateid_generation(stateid, &dp->dl_stateid, flags); | 3248 | status = check_stateid_generation(stateid, &dp->dl_stateid, flags); |
3233 | if (status) | 3249 | if (status) |
3234 | goto out; | 3250 | goto out; |
@@ -3455,7 +3471,7 @@ alloc_init_lock_stateid(struct nfs4_stateowner *sop, struct nfs4_file *fp, struc | |||
3455 | stp->st_stateowner = sop; | 3471 | stp->st_stateowner = sop; |
3456 | get_nfs4_file(fp); | 3472 | get_nfs4_file(fp); |
3457 | stp->st_file = fp; | 3473 | stp->st_file = fp; |
3458 | stp->st_stateid.si_boot = boot_time; | 3474 | stp->st_stateid.si_boot = get_seconds(); |
3459 | stp->st_stateid.si_stateownerid = sop->so_id; | 3475 | stp->st_stateid.si_stateownerid = sop->so_id; |
3460 | stp->st_stateid.si_fileid = fp->fi_id; | 3476 | stp->st_stateid.si_fileid = fp->fi_id; |
3461 | stp->st_stateid.si_generation = 0; | 3477 | stp->st_stateid.si_generation = 0; |
@@ -3987,6 +4003,7 @@ nfs4_state_init(void) | |||
3987 | INIT_LIST_HEAD(&conf_str_hashtbl[i]); | 4003 | INIT_LIST_HEAD(&conf_str_hashtbl[i]); |
3988 | INIT_LIST_HEAD(&unconf_str_hashtbl[i]); | 4004 | INIT_LIST_HEAD(&unconf_str_hashtbl[i]); |
3989 | INIT_LIST_HEAD(&unconf_id_hashtbl[i]); | 4005 | INIT_LIST_HEAD(&unconf_id_hashtbl[i]); |
4006 | INIT_LIST_HEAD(&reclaim_str_hashtbl[i]); | ||
3990 | } | 4007 | } |
3991 | for (i = 0; i < SESSION_HASH_SIZE; i++) | 4008 | for (i = 0; i < SESSION_HASH_SIZE; i++) |
3992 | INIT_LIST_HEAD(&sessionid_hashtbl[i]); | 4009 | INIT_LIST_HEAD(&sessionid_hashtbl[i]); |
@@ -4009,8 +4026,6 @@ nfs4_state_init(void) | |||
4009 | INIT_LIST_HEAD(&close_lru); | 4026 | INIT_LIST_HEAD(&close_lru); |
4010 | INIT_LIST_HEAD(&client_lru); | 4027 | INIT_LIST_HEAD(&client_lru); |
4011 | INIT_LIST_HEAD(&del_recall_lru); | 4028 | INIT_LIST_HEAD(&del_recall_lru); |
4012 | for (i = 0; i < CLIENT_HASH_SIZE; i++) | ||
4013 | INIT_LIST_HEAD(&reclaim_str_hashtbl[i]); | ||
4014 | reclaim_str_hashtbl_size = 0; | 4029 | reclaim_str_hashtbl_size = 0; |
4015 | return 0; | 4030 | return 0; |
4016 | } | 4031 | } |
diff --git a/fs/nfsd/nfs4xdr.c b/fs/nfsd/nfs4xdr.c index b73549d293be..2dcc7feaa6ff 100644 --- a/fs/nfsd/nfs4xdr.c +++ b/fs/nfsd/nfs4xdr.c | |||
@@ -83,16 +83,6 @@ check_filename(char *str, int len, __be32 err) | |||
83 | return 0; | 83 | return 0; |
84 | } | 84 | } |
85 | 85 | ||
86 | /* | ||
87 | * START OF "GENERIC" DECODE ROUTINES. | ||
88 | * These may look a little ugly since they are imported from a "generic" | ||
89 | * set of XDR encode/decode routines which are intended to be shared by | ||
90 | * all of our NFSv4 implementations (OpenBSD, MacOS X...). | ||
91 | * | ||
92 | * If the pain of reading these is too great, it should be a straightforward | ||
93 | * task to translate them into Linux-specific versions which are more | ||
94 | * consistent with the style used in NFSv2/v3... | ||
95 | */ | ||
96 | #define DECODE_HEAD \ | 86 | #define DECODE_HEAD \ |
97 | __be32 *p; \ | 87 | __be32 *p; \ |
98 | __be32 status | 88 | __be32 status |
@@ -254,20 +244,8 @@ nfsd4_decode_bitmap(struct nfsd4_compoundargs *argp, u32 *bmval) | |||
254 | DECODE_TAIL; | 244 | DECODE_TAIL; |
255 | } | 245 | } |
256 | 246 | ||
257 | static u32 nfsd_attrmask[] = { | ||
258 | NFSD_WRITEABLE_ATTRS_WORD0, | ||
259 | NFSD_WRITEABLE_ATTRS_WORD1, | ||
260 | NFSD_WRITEABLE_ATTRS_WORD2 | ||
261 | }; | ||
262 | |||
263 | static u32 nfsd41_ex_attrmask[] = { | ||
264 | NFSD_SUPPATTR_EXCLCREAT_WORD0, | ||
265 | NFSD_SUPPATTR_EXCLCREAT_WORD1, | ||
266 | NFSD_SUPPATTR_EXCLCREAT_WORD2 | ||
267 | }; | ||
268 | |||
269 | static __be32 | 247 | static __be32 |
270 | nfsd4_decode_fattr(struct nfsd4_compoundargs *argp, u32 *bmval, u32 *writable, | 248 | nfsd4_decode_fattr(struct nfsd4_compoundargs *argp, u32 *bmval, |
271 | struct iattr *iattr, struct nfs4_acl **acl) | 249 | struct iattr *iattr, struct nfs4_acl **acl) |
272 | { | 250 | { |
273 | int expected_len, len = 0; | 251 | int expected_len, len = 0; |
@@ -280,18 +258,6 @@ nfsd4_decode_fattr(struct nfsd4_compoundargs *argp, u32 *bmval, u32 *writable, | |||
280 | if ((status = nfsd4_decode_bitmap(argp, bmval))) | 258 | if ((status = nfsd4_decode_bitmap(argp, bmval))) |
281 | return status; | 259 | return status; |
282 | 260 | ||
283 | /* | ||
284 | * According to spec, unsupported attributes return ERR_ATTRNOTSUPP; | ||
285 | * read-only attributes return ERR_INVAL. | ||
286 | */ | ||
287 | if ((bmval[0] & ~nfsd_suppattrs0(argp->minorversion)) || | ||
288 | (bmval[1] & ~nfsd_suppattrs1(argp->minorversion)) || | ||
289 | (bmval[2] & ~nfsd_suppattrs2(argp->minorversion))) | ||
290 | return nfserr_attrnotsupp; | ||
291 | if ((bmval[0] & ~writable[0]) || (bmval[1] & ~writable[1]) || | ||
292 | (bmval[2] & ~writable[2])) | ||
293 | return nfserr_inval; | ||
294 | |||
295 | READ_BUF(4); | 261 | READ_BUF(4); |
296 | READ32(expected_len); | 262 | READ32(expected_len); |
297 | 263 | ||
@@ -424,8 +390,11 @@ nfsd4_decode_fattr(struct nfsd4_compoundargs *argp, u32 *bmval, u32 *writable, | |||
424 | goto xdr_error; | 390 | goto xdr_error; |
425 | } | 391 | } |
426 | } | 392 | } |
427 | BUG_ON(bmval[2]); /* no such writeable attr supported yet */ | 393 | if (bmval[0] & ~NFSD_WRITEABLE_ATTRS_WORD0 |
428 | if (len != expected_len) | 394 | || bmval[1] & ~NFSD_WRITEABLE_ATTRS_WORD1 |
395 | || bmval[2] & ~NFSD_WRITEABLE_ATTRS_WORD2) | ||
396 | READ_BUF(expected_len - len); | ||
397 | else if (len != expected_len) | ||
429 | goto xdr_error; | 398 | goto xdr_error; |
430 | 399 | ||
431 | DECODE_TAIL; | 400 | DECODE_TAIL; |
@@ -518,8 +487,8 @@ nfsd4_decode_create(struct nfsd4_compoundargs *argp, struct nfsd4_create *create | |||
518 | if ((status = check_filename(create->cr_name, create->cr_namelen, nfserr_inval))) | 487 | if ((status = check_filename(create->cr_name, create->cr_namelen, nfserr_inval))) |
519 | return status; | 488 | return status; |
520 | 489 | ||
521 | status = nfsd4_decode_fattr(argp, create->cr_bmval, nfsd_attrmask, | 490 | status = nfsd4_decode_fattr(argp, create->cr_bmval, &create->cr_iattr, |
522 | &create->cr_iattr, &create->cr_acl); | 491 | &create->cr_acl); |
523 | if (status) | 492 | if (status) |
524 | goto out; | 493 | goto out; |
525 | 494 | ||
@@ -682,7 +651,7 @@ nfsd4_decode_open(struct nfsd4_compoundargs *argp, struct nfsd4_open *open) | |||
682 | case NFS4_CREATE_UNCHECKED: | 651 | case NFS4_CREATE_UNCHECKED: |
683 | case NFS4_CREATE_GUARDED: | 652 | case NFS4_CREATE_GUARDED: |
684 | status = nfsd4_decode_fattr(argp, open->op_bmval, | 653 | status = nfsd4_decode_fattr(argp, open->op_bmval, |
685 | nfsd_attrmask, &open->op_iattr, &open->op_acl); | 654 | &open->op_iattr, &open->op_acl); |
686 | if (status) | 655 | if (status) |
687 | goto out; | 656 | goto out; |
688 | break; | 657 | break; |
@@ -696,8 +665,7 @@ nfsd4_decode_open(struct nfsd4_compoundargs *argp, struct nfsd4_open *open) | |||
696 | READ_BUF(8); | 665 | READ_BUF(8); |
697 | COPYMEM(open->op_verf.data, 8); | 666 | COPYMEM(open->op_verf.data, 8); |
698 | status = nfsd4_decode_fattr(argp, open->op_bmval, | 667 | status = nfsd4_decode_fattr(argp, open->op_bmval, |
699 | nfsd41_ex_attrmask, &open->op_iattr, | 668 | &open->op_iattr, &open->op_acl); |
700 | &open->op_acl); | ||
701 | if (status) | 669 | if (status) |
702 | goto out; | 670 | goto out; |
703 | break; | 671 | break; |
@@ -893,8 +861,8 @@ nfsd4_decode_setattr(struct nfsd4_compoundargs *argp, struct nfsd4_setattr *seta | |||
893 | status = nfsd4_decode_stateid(argp, &setattr->sa_stateid); | 861 | status = nfsd4_decode_stateid(argp, &setattr->sa_stateid); |
894 | if (status) | 862 | if (status) |
895 | return status; | 863 | return status; |
896 | return nfsd4_decode_fattr(argp, setattr->sa_bmval, nfsd_attrmask, | 864 | return nfsd4_decode_fattr(argp, setattr->sa_bmval, &setattr->sa_iattr, |
897 | &setattr->sa_iattr, &setattr->sa_acl); | 865 | &setattr->sa_acl); |
898 | } | 866 | } |
899 | 867 | ||
900 | static __be32 | 868 | static __be32 |
@@ -1328,64 +1296,64 @@ static nfsd4_dec nfsd4_dec_ops[] = { | |||
1328 | }; | 1296 | }; |
1329 | 1297 | ||
1330 | static nfsd4_dec nfsd41_dec_ops[] = { | 1298 | static nfsd4_dec nfsd41_dec_ops[] = { |
1331 | [OP_ACCESS] (nfsd4_dec)nfsd4_decode_access, | 1299 | [OP_ACCESS] = (nfsd4_dec)nfsd4_decode_access, |
1332 | [OP_CLOSE] (nfsd4_dec)nfsd4_decode_close, | 1300 | [OP_CLOSE] = (nfsd4_dec)nfsd4_decode_close, |
1333 | [OP_COMMIT] (nfsd4_dec)nfsd4_decode_commit, | 1301 | [OP_COMMIT] = (nfsd4_dec)nfsd4_decode_commit, |
1334 | [OP_CREATE] (nfsd4_dec)nfsd4_decode_create, | 1302 | [OP_CREATE] = (nfsd4_dec)nfsd4_decode_create, |
1335 | [OP_DELEGPURGE] (nfsd4_dec)nfsd4_decode_notsupp, | 1303 | [OP_DELEGPURGE] = (nfsd4_dec)nfsd4_decode_notsupp, |
1336 | [OP_DELEGRETURN] (nfsd4_dec)nfsd4_decode_delegreturn, | 1304 | [OP_DELEGRETURN] = (nfsd4_dec)nfsd4_decode_delegreturn, |
1337 | [OP_GETATTR] (nfsd4_dec)nfsd4_decode_getattr, | 1305 | [OP_GETATTR] = (nfsd4_dec)nfsd4_decode_getattr, |
1338 | [OP_GETFH] (nfsd4_dec)nfsd4_decode_noop, | 1306 | [OP_GETFH] = (nfsd4_dec)nfsd4_decode_noop, |
1339 | [OP_LINK] (nfsd4_dec)nfsd4_decode_link, | 1307 | [OP_LINK] = (nfsd4_dec)nfsd4_decode_link, |
1340 | [OP_LOCK] (nfsd4_dec)nfsd4_decode_lock, | 1308 | [OP_LOCK] = (nfsd4_dec)nfsd4_decode_lock, |
1341 | [OP_LOCKT] (nfsd4_dec)nfsd4_decode_lockt, | 1309 | [OP_LOCKT] = (nfsd4_dec)nfsd4_decode_lockt, |
1342 | [OP_LOCKU] (nfsd4_dec)nfsd4_decode_locku, | 1310 | [OP_LOCKU] = (nfsd4_dec)nfsd4_decode_locku, |
1343 | [OP_LOOKUP] (nfsd4_dec)nfsd4_decode_lookup, | 1311 | [OP_LOOKUP] = (nfsd4_dec)nfsd4_decode_lookup, |
1344 | [OP_LOOKUPP] (nfsd4_dec)nfsd4_decode_noop, | 1312 | [OP_LOOKUPP] = (nfsd4_dec)nfsd4_decode_noop, |
1345 | [OP_NVERIFY] (nfsd4_dec)nfsd4_decode_verify, | 1313 | [OP_NVERIFY] = (nfsd4_dec)nfsd4_decode_verify, |
1346 | [OP_OPEN] (nfsd4_dec)nfsd4_decode_open, | 1314 | [OP_OPEN] = (nfsd4_dec)nfsd4_decode_open, |
1347 | [OP_OPENATTR] (nfsd4_dec)nfsd4_decode_notsupp, | 1315 | [OP_OPENATTR] = (nfsd4_dec)nfsd4_decode_notsupp, |
1348 | [OP_OPEN_CONFIRM] (nfsd4_dec)nfsd4_decode_notsupp, | 1316 | [OP_OPEN_CONFIRM] = (nfsd4_dec)nfsd4_decode_notsupp, |
1349 | [OP_OPEN_DOWNGRADE] (nfsd4_dec)nfsd4_decode_open_downgrade, | 1317 | [OP_OPEN_DOWNGRADE] = (nfsd4_dec)nfsd4_decode_open_downgrade, |
1350 | [OP_PUTFH] (nfsd4_dec)nfsd4_decode_putfh, | 1318 | [OP_PUTFH] = (nfsd4_dec)nfsd4_decode_putfh, |
1351 | [OP_PUTPUBFH] (nfsd4_dec)nfsd4_decode_notsupp, | 1319 | [OP_PUTPUBFH] = (nfsd4_dec)nfsd4_decode_notsupp, |
1352 | [OP_PUTROOTFH] (nfsd4_dec)nfsd4_decode_noop, | 1320 | [OP_PUTROOTFH] = (nfsd4_dec)nfsd4_decode_noop, |
1353 | [OP_READ] (nfsd4_dec)nfsd4_decode_read, | 1321 | [OP_READ] = (nfsd4_dec)nfsd4_decode_read, |
1354 | [OP_READDIR] (nfsd4_dec)nfsd4_decode_readdir, | 1322 | [OP_READDIR] = (nfsd4_dec)nfsd4_decode_readdir, |
1355 | [OP_READLINK] (nfsd4_dec)nfsd4_decode_noop, | 1323 | [OP_READLINK] = (nfsd4_dec)nfsd4_decode_noop, |
1356 | [OP_REMOVE] (nfsd4_dec)nfsd4_decode_remove, | 1324 | [OP_REMOVE] = (nfsd4_dec)nfsd4_decode_remove, |
1357 | [OP_RENAME] (nfsd4_dec)nfsd4_decode_rename, | 1325 | [OP_RENAME] = (nfsd4_dec)nfsd4_decode_rename, |
1358 | [OP_RENEW] (nfsd4_dec)nfsd4_decode_notsupp, | 1326 | [OP_RENEW] = (nfsd4_dec)nfsd4_decode_notsupp, |
1359 | [OP_RESTOREFH] (nfsd4_dec)nfsd4_decode_noop, | 1327 | [OP_RESTOREFH] = (nfsd4_dec)nfsd4_decode_noop, |
1360 | [OP_SAVEFH] (nfsd4_dec)nfsd4_decode_noop, | 1328 | [OP_SAVEFH] = (nfsd4_dec)nfsd4_decode_noop, |
1361 | [OP_SECINFO] (nfsd4_dec)nfsd4_decode_secinfo, | 1329 | [OP_SECINFO] = (nfsd4_dec)nfsd4_decode_secinfo, |
1362 | [OP_SETATTR] (nfsd4_dec)nfsd4_decode_setattr, | 1330 | [OP_SETATTR] = (nfsd4_dec)nfsd4_decode_setattr, |
1363 | [OP_SETCLIENTID] (nfsd4_dec)nfsd4_decode_notsupp, | 1331 | [OP_SETCLIENTID] = (nfsd4_dec)nfsd4_decode_notsupp, |
1364 | [OP_SETCLIENTID_CONFIRM](nfsd4_dec)nfsd4_decode_notsupp, | 1332 | [OP_SETCLIENTID_CONFIRM]= (nfsd4_dec)nfsd4_decode_notsupp, |
1365 | [OP_VERIFY] (nfsd4_dec)nfsd4_decode_verify, | 1333 | [OP_VERIFY] = (nfsd4_dec)nfsd4_decode_verify, |
1366 | [OP_WRITE] (nfsd4_dec)nfsd4_decode_write, | 1334 | [OP_WRITE] = (nfsd4_dec)nfsd4_decode_write, |
1367 | [OP_RELEASE_LOCKOWNER] (nfsd4_dec)nfsd4_decode_notsupp, | 1335 | [OP_RELEASE_LOCKOWNER] = (nfsd4_dec)nfsd4_decode_notsupp, |
1368 | 1336 | ||
1369 | /* new operations for NFSv4.1 */ | 1337 | /* new operations for NFSv4.1 */ |
1370 | [OP_BACKCHANNEL_CTL] (nfsd4_dec)nfsd4_decode_notsupp, | 1338 | [OP_BACKCHANNEL_CTL] = (nfsd4_dec)nfsd4_decode_notsupp, |
1371 | [OP_BIND_CONN_TO_SESSION](nfsd4_dec)nfsd4_decode_notsupp, | 1339 | [OP_BIND_CONN_TO_SESSION]= (nfsd4_dec)nfsd4_decode_notsupp, |
1372 | [OP_EXCHANGE_ID] (nfsd4_dec)nfsd4_decode_exchange_id, | 1340 | [OP_EXCHANGE_ID] = (nfsd4_dec)nfsd4_decode_exchange_id, |
1373 | [OP_CREATE_SESSION] (nfsd4_dec)nfsd4_decode_create_session, | 1341 | [OP_CREATE_SESSION] = (nfsd4_dec)nfsd4_decode_create_session, |
1374 | [OP_DESTROY_SESSION] (nfsd4_dec)nfsd4_decode_destroy_session, | 1342 | [OP_DESTROY_SESSION] = (nfsd4_dec)nfsd4_decode_destroy_session, |
1375 | [OP_FREE_STATEID] (nfsd4_dec)nfsd4_decode_notsupp, | 1343 | [OP_FREE_STATEID] = (nfsd4_dec)nfsd4_decode_notsupp, |
1376 | [OP_GET_DIR_DELEGATION] (nfsd4_dec)nfsd4_decode_notsupp, | 1344 | [OP_GET_DIR_DELEGATION] = (nfsd4_dec)nfsd4_decode_notsupp, |
1377 | [OP_GETDEVICEINFO] (nfsd4_dec)nfsd4_decode_notsupp, | 1345 | [OP_GETDEVICEINFO] = (nfsd4_dec)nfsd4_decode_notsupp, |
1378 | [OP_GETDEVICELIST] (nfsd4_dec)nfsd4_decode_notsupp, | 1346 | [OP_GETDEVICELIST] = (nfsd4_dec)nfsd4_decode_notsupp, |
1379 | [OP_LAYOUTCOMMIT] (nfsd4_dec)nfsd4_decode_notsupp, | 1347 | [OP_LAYOUTCOMMIT] = (nfsd4_dec)nfsd4_decode_notsupp, |
1380 | [OP_LAYOUTGET] (nfsd4_dec)nfsd4_decode_notsupp, | 1348 | [OP_LAYOUTGET] = (nfsd4_dec)nfsd4_decode_notsupp, |
1381 | [OP_LAYOUTRETURN] (nfsd4_dec)nfsd4_decode_notsupp, | 1349 | [OP_LAYOUTRETURN] = (nfsd4_dec)nfsd4_decode_notsupp, |
1382 | [OP_SECINFO_NO_NAME] (nfsd4_dec)nfsd4_decode_notsupp, | 1350 | [OP_SECINFO_NO_NAME] = (nfsd4_dec)nfsd4_decode_notsupp, |
1383 | [OP_SEQUENCE] (nfsd4_dec)nfsd4_decode_sequence, | 1351 | [OP_SEQUENCE] = (nfsd4_dec)nfsd4_decode_sequence, |
1384 | [OP_SET_SSV] (nfsd4_dec)nfsd4_decode_notsupp, | 1352 | [OP_SET_SSV] = (nfsd4_dec)nfsd4_decode_notsupp, |
1385 | [OP_TEST_STATEID] (nfsd4_dec)nfsd4_decode_notsupp, | 1353 | [OP_TEST_STATEID] = (nfsd4_dec)nfsd4_decode_notsupp, |
1386 | [OP_WANT_DELEGATION] (nfsd4_dec)nfsd4_decode_notsupp, | 1354 | [OP_WANT_DELEGATION] = (nfsd4_dec)nfsd4_decode_notsupp, |
1387 | [OP_DESTROY_CLIENTID] (nfsd4_dec)nfsd4_decode_notsupp, | 1355 | [OP_DESTROY_CLIENTID] = (nfsd4_dec)nfsd4_decode_notsupp, |
1388 | [OP_RECLAIM_COMPLETE] (nfsd4_dec)nfsd4_decode_notsupp, | 1356 | [OP_RECLAIM_COMPLETE] = (nfsd4_dec)nfsd4_decode_notsupp, |
1389 | }; | 1357 | }; |
1390 | 1358 | ||
1391 | struct nfsd4_minorversion_ops { | 1359 | struct nfsd4_minorversion_ops { |
@@ -1489,21 +1457,6 @@ nfsd4_decode_compound(struct nfsd4_compoundargs *argp) | |||
1489 | 1457 | ||
1490 | DECODE_TAIL; | 1458 | DECODE_TAIL; |
1491 | } | 1459 | } |
1492 | /* | ||
1493 | * END OF "GENERIC" DECODE ROUTINES. | ||
1494 | */ | ||
1495 | |||
1496 | /* | ||
1497 | * START OF "GENERIC" ENCODE ROUTINES. | ||
1498 | * These may look a little ugly since they are imported from a "generic" | ||
1499 | * set of XDR encode/decode routines which are intended to be shared by | ||
1500 | * all of our NFSv4 implementations (OpenBSD, MacOS X...). | ||
1501 | * | ||
1502 | * If the pain of reading these is too great, it should be a straightforward | ||
1503 | * task to translate them into Linux-specific versions which are more | ||
1504 | * consistent with the style used in NFSv2/v3... | ||
1505 | */ | ||
1506 | #define ENCODE_HEAD __be32 *p | ||
1507 | 1460 | ||
1508 | #define WRITE32(n) *p++ = htonl(n) | 1461 | #define WRITE32(n) *p++ = htonl(n) |
1509 | #define WRITE64(n) do { \ | 1462 | #define WRITE64(n) do { \ |
@@ -1515,13 +1468,41 @@ nfsd4_decode_compound(struct nfsd4_compoundargs *argp) | |||
1515 | memcpy(p, ptr, nbytes); \ | 1468 | memcpy(p, ptr, nbytes); \ |
1516 | p += XDR_QUADLEN(nbytes); \ | 1469 | p += XDR_QUADLEN(nbytes); \ |
1517 | }} while (0) | 1470 | }} while (0) |
1518 | #define WRITECINFO(c) do { \ | 1471 | |
1519 | *p++ = htonl(c.atomic); \ | 1472 | static void write32(__be32 **p, u32 n) |
1520 | *p++ = htonl(c.before_ctime_sec); \ | 1473 | { |
1521 | *p++ = htonl(c.before_ctime_nsec); \ | 1474 | *(*p)++ = n; |
1522 | *p++ = htonl(c.after_ctime_sec); \ | 1475 | } |
1523 | *p++ = htonl(c.after_ctime_nsec); \ | 1476 | |
1524 | } while (0) | 1477 | static void write64(__be32 **p, u64 n) |
1478 | { | ||
1479 | write32(p, (u32)(n >> 32)); | ||
1480 | write32(p, (u32)n); | ||
1481 | } | ||
1482 | |||
1483 | static void write_change(__be32 **p, struct kstat *stat, struct inode *inode) | ||
1484 | { | ||
1485 | if (IS_I_VERSION(inode)) { | ||
1486 | write64(p, inode->i_version); | ||
1487 | } else { | ||
1488 | write32(p, stat->ctime.tv_sec); | ||
1489 | write32(p, stat->ctime.tv_nsec); | ||
1490 | } | ||
1491 | } | ||
1492 | |||
1493 | static void write_cinfo(__be32 **p, struct nfsd4_change_info *c) | ||
1494 | { | ||
1495 | write32(p, c->atomic); | ||
1496 | if (c->change_supported) { | ||
1497 | write64(p, c->before_change); | ||
1498 | write64(p, c->after_change); | ||
1499 | } else { | ||
1500 | write32(p, c->before_ctime_sec); | ||
1501 | write32(p, c->before_ctime_nsec); | ||
1502 | write32(p, c->after_ctime_sec); | ||
1503 | write32(p, c->after_ctime_nsec); | ||
1504 | } | ||
1505 | } | ||
1525 | 1506 | ||
1526 | #define RESERVE_SPACE(nbytes) do { \ | 1507 | #define RESERVE_SPACE(nbytes) do { \ |
1527 | p = resp->p; \ | 1508 | p = resp->p; \ |
@@ -1874,16 +1855,9 @@ nfsd4_encode_fattr(struct svc_fh *fhp, struct svc_export *exp, | |||
1874 | WRITE32(NFS4_FH_PERSISTENT|NFS4_FH_VOL_RENAME); | 1855 | WRITE32(NFS4_FH_PERSISTENT|NFS4_FH_VOL_RENAME); |
1875 | } | 1856 | } |
1876 | if (bmval0 & FATTR4_WORD0_CHANGE) { | 1857 | if (bmval0 & FATTR4_WORD0_CHANGE) { |
1877 | /* | ||
1878 | * Note: This _must_ be consistent with the scheme for writing | ||
1879 | * change_info, so any changes made here must be reflected there | ||
1880 | * as well. (See xdr4.h:set_change_info() and the WRITECINFO() | ||
1881 | * macro above.) | ||
1882 | */ | ||
1883 | if ((buflen -= 8) < 0) | 1858 | if ((buflen -= 8) < 0) |
1884 | goto out_resource; | 1859 | goto out_resource; |
1885 | WRITE32(stat.ctime.tv_sec); | 1860 | write_change(&p, &stat, dentry->d_inode); |
1886 | WRITE32(stat.ctime.tv_nsec); | ||
1887 | } | 1861 | } |
1888 | if (bmval0 & FATTR4_WORD0_SIZE) { | 1862 | if (bmval0 & FATTR4_WORD0_SIZE) { |
1889 | if ((buflen -= 8) < 0) | 1863 | if ((buflen -= 8) < 0) |
@@ -2348,7 +2322,7 @@ fail: | |||
2348 | static void | 2322 | static void |
2349 | nfsd4_encode_stateid(struct nfsd4_compoundres *resp, stateid_t *sid) | 2323 | nfsd4_encode_stateid(struct nfsd4_compoundres *resp, stateid_t *sid) |
2350 | { | 2324 | { |
2351 | ENCODE_HEAD; | 2325 | __be32 *p; |
2352 | 2326 | ||
2353 | RESERVE_SPACE(sizeof(stateid_t)); | 2327 | RESERVE_SPACE(sizeof(stateid_t)); |
2354 | WRITE32(sid->si_generation); | 2328 | WRITE32(sid->si_generation); |
@@ -2359,7 +2333,7 @@ nfsd4_encode_stateid(struct nfsd4_compoundres *resp, stateid_t *sid) | |||
2359 | static __be32 | 2333 | static __be32 |
2360 | nfsd4_encode_access(struct nfsd4_compoundres *resp, __be32 nfserr, struct nfsd4_access *access) | 2334 | nfsd4_encode_access(struct nfsd4_compoundres *resp, __be32 nfserr, struct nfsd4_access *access) |
2361 | { | 2335 | { |
2362 | ENCODE_HEAD; | 2336 | __be32 *p; |
2363 | 2337 | ||
2364 | if (!nfserr) { | 2338 | if (!nfserr) { |
2365 | RESERVE_SPACE(8); | 2339 | RESERVE_SPACE(8); |
@@ -2386,7 +2360,7 @@ nfsd4_encode_close(struct nfsd4_compoundres *resp, __be32 nfserr, struct nfsd4_c | |||
2386 | static __be32 | 2360 | static __be32 |
2387 | nfsd4_encode_commit(struct nfsd4_compoundres *resp, __be32 nfserr, struct nfsd4_commit *commit) | 2361 | nfsd4_encode_commit(struct nfsd4_compoundres *resp, __be32 nfserr, struct nfsd4_commit *commit) |
2388 | { | 2362 | { |
2389 | ENCODE_HEAD; | 2363 | __be32 *p; |
2390 | 2364 | ||
2391 | if (!nfserr) { | 2365 | if (!nfserr) { |
2392 | RESERVE_SPACE(8); | 2366 | RESERVE_SPACE(8); |
@@ -2399,11 +2373,11 @@ nfsd4_encode_commit(struct nfsd4_compoundres *resp, __be32 nfserr, struct nfsd4_ | |||
2399 | static __be32 | 2373 | static __be32 |
2400 | nfsd4_encode_create(struct nfsd4_compoundres *resp, __be32 nfserr, struct nfsd4_create *create) | 2374 | nfsd4_encode_create(struct nfsd4_compoundres *resp, __be32 nfserr, struct nfsd4_create *create) |
2401 | { | 2375 | { |
2402 | ENCODE_HEAD; | 2376 | __be32 *p; |
2403 | 2377 | ||
2404 | if (!nfserr) { | 2378 | if (!nfserr) { |
2405 | RESERVE_SPACE(32); | 2379 | RESERVE_SPACE(32); |
2406 | WRITECINFO(create->cr_cinfo); | 2380 | write_cinfo(&p, &create->cr_cinfo); |
2407 | WRITE32(2); | 2381 | WRITE32(2); |
2408 | WRITE32(create->cr_bmval[0]); | 2382 | WRITE32(create->cr_bmval[0]); |
2409 | WRITE32(create->cr_bmval[1]); | 2383 | WRITE32(create->cr_bmval[1]); |
@@ -2435,7 +2409,7 @@ nfsd4_encode_getfh(struct nfsd4_compoundres *resp, __be32 nfserr, struct svc_fh | |||
2435 | { | 2409 | { |
2436 | struct svc_fh *fhp = *fhpp; | 2410 | struct svc_fh *fhp = *fhpp; |
2437 | unsigned int len; | 2411 | unsigned int len; |
2438 | ENCODE_HEAD; | 2412 | __be32 *p; |
2439 | 2413 | ||
2440 | if (!nfserr) { | 2414 | if (!nfserr) { |
2441 | len = fhp->fh_handle.fh_size; | 2415 | len = fhp->fh_handle.fh_size; |
@@ -2454,7 +2428,7 @@ nfsd4_encode_getfh(struct nfsd4_compoundres *resp, __be32 nfserr, struct svc_fh | |||
2454 | static void | 2428 | static void |
2455 | nfsd4_encode_lock_denied(struct nfsd4_compoundres *resp, struct nfsd4_lock_denied *ld) | 2429 | nfsd4_encode_lock_denied(struct nfsd4_compoundres *resp, struct nfsd4_lock_denied *ld) |
2456 | { | 2430 | { |
2457 | ENCODE_HEAD; | 2431 | __be32 *p; |
2458 | 2432 | ||
2459 | RESERVE_SPACE(32 + XDR_LEN(ld->ld_sop ? ld->ld_sop->so_owner.len : 0)); | 2433 | RESERVE_SPACE(32 + XDR_LEN(ld->ld_sop ? ld->ld_sop->so_owner.len : 0)); |
2460 | WRITE64(ld->ld_start); | 2434 | WRITE64(ld->ld_start); |
@@ -2510,11 +2484,11 @@ nfsd4_encode_locku(struct nfsd4_compoundres *resp, __be32 nfserr, struct nfsd4_l | |||
2510 | static __be32 | 2484 | static __be32 |
2511 | nfsd4_encode_link(struct nfsd4_compoundres *resp, __be32 nfserr, struct nfsd4_link *link) | 2485 | nfsd4_encode_link(struct nfsd4_compoundres *resp, __be32 nfserr, struct nfsd4_link *link) |
2512 | { | 2486 | { |
2513 | ENCODE_HEAD; | 2487 | __be32 *p; |
2514 | 2488 | ||
2515 | if (!nfserr) { | 2489 | if (!nfserr) { |
2516 | RESERVE_SPACE(20); | 2490 | RESERVE_SPACE(20); |
2517 | WRITECINFO(link->li_cinfo); | 2491 | write_cinfo(&p, &link->li_cinfo); |
2518 | ADJUST_ARGS(); | 2492 | ADJUST_ARGS(); |
2519 | } | 2493 | } |
2520 | return nfserr; | 2494 | return nfserr; |
@@ -2524,7 +2498,7 @@ nfsd4_encode_link(struct nfsd4_compoundres *resp, __be32 nfserr, struct nfsd4_li | |||
2524 | static __be32 | 2498 | static __be32 |
2525 | nfsd4_encode_open(struct nfsd4_compoundres *resp, __be32 nfserr, struct nfsd4_open *open) | 2499 | nfsd4_encode_open(struct nfsd4_compoundres *resp, __be32 nfserr, struct nfsd4_open *open) |
2526 | { | 2500 | { |
2527 | ENCODE_HEAD; | 2501 | __be32 *p; |
2528 | ENCODE_SEQID_OP_HEAD; | 2502 | ENCODE_SEQID_OP_HEAD; |
2529 | 2503 | ||
2530 | if (nfserr) | 2504 | if (nfserr) |
@@ -2532,7 +2506,7 @@ nfsd4_encode_open(struct nfsd4_compoundres *resp, __be32 nfserr, struct nfsd4_op | |||
2532 | 2506 | ||
2533 | nfsd4_encode_stateid(resp, &open->op_stateid); | 2507 | nfsd4_encode_stateid(resp, &open->op_stateid); |
2534 | RESERVE_SPACE(40); | 2508 | RESERVE_SPACE(40); |
2535 | WRITECINFO(open->op_cinfo); | 2509 | write_cinfo(&p, &open->op_cinfo); |
2536 | WRITE32(open->op_rflags); | 2510 | WRITE32(open->op_rflags); |
2537 | WRITE32(2); | 2511 | WRITE32(2); |
2538 | WRITE32(open->op_bmval[0]); | 2512 | WRITE32(open->op_bmval[0]); |
@@ -2619,7 +2593,7 @@ nfsd4_encode_read(struct nfsd4_compoundres *resp, __be32 nfserr, | |||
2619 | int v, pn; | 2593 | int v, pn; |
2620 | unsigned long maxcount; | 2594 | unsigned long maxcount; |
2621 | long len; | 2595 | long len; |
2622 | ENCODE_HEAD; | 2596 | __be32 *p; |
2623 | 2597 | ||
2624 | if (nfserr) | 2598 | if (nfserr) |
2625 | return nfserr; | 2599 | return nfserr; |
@@ -2681,7 +2655,7 @@ nfsd4_encode_readlink(struct nfsd4_compoundres *resp, __be32 nfserr, struct nfsd | |||
2681 | { | 2655 | { |
2682 | int maxcount; | 2656 | int maxcount; |
2683 | char *page; | 2657 | char *page; |
2684 | ENCODE_HEAD; | 2658 | __be32 *p; |
2685 | 2659 | ||
2686 | if (nfserr) | 2660 | if (nfserr) |
2687 | return nfserr; | 2661 | return nfserr; |
@@ -2730,7 +2704,7 @@ nfsd4_encode_readdir(struct nfsd4_compoundres *resp, __be32 nfserr, struct nfsd4 | |||
2730 | int maxcount; | 2704 | int maxcount; |
2731 | loff_t offset; | 2705 | loff_t offset; |
2732 | __be32 *page, *savep, *tailbase; | 2706 | __be32 *page, *savep, *tailbase; |
2733 | ENCODE_HEAD; | 2707 | __be32 *p; |
2734 | 2708 | ||
2735 | if (nfserr) | 2709 | if (nfserr) |
2736 | return nfserr; | 2710 | return nfserr; |
@@ -2806,11 +2780,11 @@ err_no_verf: | |||
2806 | static __be32 | 2780 | static __be32 |
2807 | nfsd4_encode_remove(struct nfsd4_compoundres *resp, __be32 nfserr, struct nfsd4_remove *remove) | 2781 | nfsd4_encode_remove(struct nfsd4_compoundres *resp, __be32 nfserr, struct nfsd4_remove *remove) |
2808 | { | 2782 | { |
2809 | ENCODE_HEAD; | 2783 | __be32 *p; |
2810 | 2784 | ||
2811 | if (!nfserr) { | 2785 | if (!nfserr) { |
2812 | RESERVE_SPACE(20); | 2786 | RESERVE_SPACE(20); |
2813 | WRITECINFO(remove->rm_cinfo); | 2787 | write_cinfo(&p, &remove->rm_cinfo); |
2814 | ADJUST_ARGS(); | 2788 | ADJUST_ARGS(); |
2815 | } | 2789 | } |
2816 | return nfserr; | 2790 | return nfserr; |
@@ -2819,12 +2793,12 @@ nfsd4_encode_remove(struct nfsd4_compoundres *resp, __be32 nfserr, struct nfsd4_ | |||
2819 | static __be32 | 2793 | static __be32 |
2820 | nfsd4_encode_rename(struct nfsd4_compoundres *resp, __be32 nfserr, struct nfsd4_rename *rename) | 2794 | nfsd4_encode_rename(struct nfsd4_compoundres *resp, __be32 nfserr, struct nfsd4_rename *rename) |
2821 | { | 2795 | { |
2822 | ENCODE_HEAD; | 2796 | __be32 *p; |
2823 | 2797 | ||
2824 | if (!nfserr) { | 2798 | if (!nfserr) { |
2825 | RESERVE_SPACE(40); | 2799 | RESERVE_SPACE(40); |
2826 | WRITECINFO(rename->rn_sinfo); | 2800 | write_cinfo(&p, &rename->rn_sinfo); |
2827 | WRITECINFO(rename->rn_tinfo); | 2801 | write_cinfo(&p, &rename->rn_tinfo); |
2828 | ADJUST_ARGS(); | 2802 | ADJUST_ARGS(); |
2829 | } | 2803 | } |
2830 | return nfserr; | 2804 | return nfserr; |
@@ -2839,7 +2813,7 @@ nfsd4_encode_secinfo(struct nfsd4_compoundres *resp, __be32 nfserr, | |||
2839 | u32 nflavs; | 2813 | u32 nflavs; |
2840 | struct exp_flavor_info *flavs; | 2814 | struct exp_flavor_info *flavs; |
2841 | struct exp_flavor_info def_flavs[2]; | 2815 | struct exp_flavor_info def_flavs[2]; |
2842 | ENCODE_HEAD; | 2816 | __be32 *p; |
2843 | 2817 | ||
2844 | if (nfserr) | 2818 | if (nfserr) |
2845 | goto out; | 2819 | goto out; |
@@ -2904,7 +2878,7 @@ out: | |||
2904 | static __be32 | 2878 | static __be32 |
2905 | nfsd4_encode_setattr(struct nfsd4_compoundres *resp, __be32 nfserr, struct nfsd4_setattr *setattr) | 2879 | nfsd4_encode_setattr(struct nfsd4_compoundres *resp, __be32 nfserr, struct nfsd4_setattr *setattr) |
2906 | { | 2880 | { |
2907 | ENCODE_HEAD; | 2881 | __be32 *p; |
2908 | 2882 | ||
2909 | RESERVE_SPACE(12); | 2883 | RESERVE_SPACE(12); |
2910 | if (nfserr) { | 2884 | if (nfserr) { |
@@ -2924,7 +2898,7 @@ nfsd4_encode_setattr(struct nfsd4_compoundres *resp, __be32 nfserr, struct nfsd4 | |||
2924 | static __be32 | 2898 | static __be32 |
2925 | nfsd4_encode_setclientid(struct nfsd4_compoundres *resp, __be32 nfserr, struct nfsd4_setclientid *scd) | 2899 | nfsd4_encode_setclientid(struct nfsd4_compoundres *resp, __be32 nfserr, struct nfsd4_setclientid *scd) |
2926 | { | 2900 | { |
2927 | ENCODE_HEAD; | 2901 | __be32 *p; |
2928 | 2902 | ||
2929 | if (!nfserr) { | 2903 | if (!nfserr) { |
2930 | RESERVE_SPACE(8 + sizeof(nfs4_verifier)); | 2904 | RESERVE_SPACE(8 + sizeof(nfs4_verifier)); |
@@ -2944,7 +2918,7 @@ nfsd4_encode_setclientid(struct nfsd4_compoundres *resp, __be32 nfserr, struct n | |||
2944 | static __be32 | 2918 | static __be32 |
2945 | nfsd4_encode_write(struct nfsd4_compoundres *resp, __be32 nfserr, struct nfsd4_write *write) | 2919 | nfsd4_encode_write(struct nfsd4_compoundres *resp, __be32 nfserr, struct nfsd4_write *write) |
2946 | { | 2920 | { |
2947 | ENCODE_HEAD; | 2921 | __be32 *p; |
2948 | 2922 | ||
2949 | if (!nfserr) { | 2923 | if (!nfserr) { |
2950 | RESERVE_SPACE(16); | 2924 | RESERVE_SPACE(16); |
@@ -2960,7 +2934,7 @@ static __be32 | |||
2960 | nfsd4_encode_exchange_id(struct nfsd4_compoundres *resp, int nfserr, | 2934 | nfsd4_encode_exchange_id(struct nfsd4_compoundres *resp, int nfserr, |
2961 | struct nfsd4_exchange_id *exid) | 2935 | struct nfsd4_exchange_id *exid) |
2962 | { | 2936 | { |
2963 | ENCODE_HEAD; | 2937 | __be32 *p; |
2964 | char *major_id; | 2938 | char *major_id; |
2965 | char *server_scope; | 2939 | char *server_scope; |
2966 | int major_id_sz; | 2940 | int major_id_sz; |
@@ -3015,7 +2989,7 @@ static __be32 | |||
3015 | nfsd4_encode_create_session(struct nfsd4_compoundres *resp, int nfserr, | 2989 | nfsd4_encode_create_session(struct nfsd4_compoundres *resp, int nfserr, |
3016 | struct nfsd4_create_session *sess) | 2990 | struct nfsd4_create_session *sess) |
3017 | { | 2991 | { |
3018 | ENCODE_HEAD; | 2992 | __be32 *p; |
3019 | 2993 | ||
3020 | if (nfserr) | 2994 | if (nfserr) |
3021 | return nfserr; | 2995 | return nfserr; |
@@ -3071,7 +3045,7 @@ __be32 | |||
3071 | nfsd4_encode_sequence(struct nfsd4_compoundres *resp, int nfserr, | 3045 | nfsd4_encode_sequence(struct nfsd4_compoundres *resp, int nfserr, |
3072 | struct nfsd4_sequence *seq) | 3046 | struct nfsd4_sequence *seq) |
3073 | { | 3047 | { |
3074 | ENCODE_HEAD; | 3048 | __be32 *p; |
3075 | 3049 | ||
3076 | if (nfserr) | 3050 | if (nfserr) |
3077 | return nfserr; | 3051 | return nfserr; |
@@ -3209,7 +3183,7 @@ static int nfsd4_check_drc_limit(struct nfsd4_compoundres *resp) | |||
3209 | dprintk("%s length %u, xb->page_len %u tlen %u pad %u\n", __func__, | 3183 | dprintk("%s length %u, xb->page_len %u tlen %u pad %u\n", __func__, |
3210 | length, xb->page_len, tlen, pad); | 3184 | length, xb->page_len, tlen, pad); |
3211 | 3185 | ||
3212 | if (length <= session->se_fmaxresp_cached) | 3186 | if (length <= session->se_fchannel.maxresp_cached) |
3213 | return status; | 3187 | return status; |
3214 | else | 3188 | else |
3215 | return nfserr_rep_too_big_to_cache; | 3189 | return nfserr_rep_too_big_to_cache; |
@@ -3219,7 +3193,7 @@ void | |||
3219 | nfsd4_encode_operation(struct nfsd4_compoundres *resp, struct nfsd4_op *op) | 3193 | nfsd4_encode_operation(struct nfsd4_compoundres *resp, struct nfsd4_op *op) |
3220 | { | 3194 | { |
3221 | __be32 *statp; | 3195 | __be32 *statp; |
3222 | ENCODE_HEAD; | 3196 | __be32 *p; |
3223 | 3197 | ||
3224 | RESERVE_SPACE(8); | 3198 | RESERVE_SPACE(8); |
3225 | WRITE32(op->opnum); | 3199 | WRITE32(op->opnum); |
@@ -3253,7 +3227,7 @@ status: | |||
3253 | void | 3227 | void |
3254 | nfsd4_encode_replay(struct nfsd4_compoundres *resp, struct nfsd4_op *op) | 3228 | nfsd4_encode_replay(struct nfsd4_compoundres *resp, struct nfsd4_op *op) |
3255 | { | 3229 | { |
3256 | ENCODE_HEAD; | 3230 | __be32 *p; |
3257 | struct nfs4_replay *rp = op->replay; | 3231 | struct nfs4_replay *rp = op->replay; |
3258 | 3232 | ||
3259 | BUG_ON(!rp); | 3233 | BUG_ON(!rp); |
@@ -3268,10 +3242,6 @@ nfsd4_encode_replay(struct nfsd4_compoundres *resp, struct nfsd4_op *op) | |||
3268 | ADJUST_ARGS(); | 3242 | ADJUST_ARGS(); |
3269 | } | 3243 | } |
3270 | 3244 | ||
3271 | /* | ||
3272 | * END OF "GENERIC" ENCODE ROUTINES. | ||
3273 | */ | ||
3274 | |||
3275 | int | 3245 | int |
3276 | nfs4svc_encode_voidres(struct svc_rqst *rqstp, __be32 *p, void *dummy) | 3246 | nfs4svc_encode_voidres(struct svc_rqst *rqstp, __be32 *p, void *dummy) |
3277 | { | 3247 | { |
diff --git a/fs/nfsd/nfscache.c b/fs/nfsd/nfscache.c index 5bfc2ac60d54..4638635c5d87 100644 --- a/fs/nfsd/nfscache.c +++ b/fs/nfsd/nfscache.c | |||
@@ -29,15 +29,24 @@ | |||
29 | */ | 29 | */ |
30 | #define CACHESIZE 1024 | 30 | #define CACHESIZE 1024 |
31 | #define HASHSIZE 64 | 31 | #define HASHSIZE 64 |
32 | #define REQHASH(xid) (((((__force __u32)xid) >> 24) ^ ((__force __u32)xid)) & (HASHSIZE-1)) | ||
33 | 32 | ||
34 | static struct hlist_head * hash_list; | 33 | static struct hlist_head * cache_hash; |
35 | static struct list_head lru_head; | 34 | static struct list_head lru_head; |
36 | static int cache_disabled = 1; | 35 | static int cache_disabled = 1; |
37 | 36 | ||
37 | /* | ||
38 | * Calculate the hash index from an XID. | ||
39 | */ | ||
40 | static inline u32 request_hash(u32 xid) | ||
41 | { | ||
42 | u32 h = xid; | ||
43 | h ^= (xid >> 24); | ||
44 | return h & (HASHSIZE-1); | ||
45 | } | ||
46 | |||
38 | static int nfsd_cache_append(struct svc_rqst *rqstp, struct kvec *vec); | 47 | static int nfsd_cache_append(struct svc_rqst *rqstp, struct kvec *vec); |
39 | 48 | ||
40 | /* | 49 | /* |
41 | * locking for the reply cache: | 50 | * locking for the reply cache: |
42 | * A cache entry is "single use" if c_state == RC_INPROG | 51 | * A cache entry is "single use" if c_state == RC_INPROG |
43 | * Otherwise, it when accessing _prev or _next, the lock must be held. | 52 | * Otherwise, it when accessing _prev or _next, the lock must be held. |
@@ -62,8 +71,8 @@ int nfsd_reply_cache_init(void) | |||
62 | i--; | 71 | i--; |
63 | } | 72 | } |
64 | 73 | ||
65 | hash_list = kcalloc (HASHSIZE, sizeof(struct hlist_head), GFP_KERNEL); | 74 | cache_hash = kcalloc (HASHSIZE, sizeof(struct hlist_head), GFP_KERNEL); |
66 | if (!hash_list) | 75 | if (!cache_hash) |
67 | goto out_nomem; | 76 | goto out_nomem; |
68 | 77 | ||
69 | cache_disabled = 0; | 78 | cache_disabled = 0; |
@@ -88,8 +97,8 @@ void nfsd_reply_cache_shutdown(void) | |||
88 | 97 | ||
89 | cache_disabled = 1; | 98 | cache_disabled = 1; |
90 | 99 | ||
91 | kfree (hash_list); | 100 | kfree (cache_hash); |
92 | hash_list = NULL; | 101 | cache_hash = NULL; |
93 | } | 102 | } |
94 | 103 | ||
95 | /* | 104 | /* |
@@ -108,7 +117,7 @@ static void | |||
108 | hash_refile(struct svc_cacherep *rp) | 117 | hash_refile(struct svc_cacherep *rp) |
109 | { | 118 | { |
110 | hlist_del_init(&rp->c_hash); | 119 | hlist_del_init(&rp->c_hash); |
111 | hlist_add_head(&rp->c_hash, hash_list + REQHASH(rp->c_xid)); | 120 | hlist_add_head(&rp->c_hash, cache_hash + request_hash(rp->c_xid)); |
112 | } | 121 | } |
113 | 122 | ||
114 | /* | 123 | /* |
@@ -138,7 +147,7 @@ nfsd_cache_lookup(struct svc_rqst *rqstp, int type) | |||
138 | spin_lock(&cache_lock); | 147 | spin_lock(&cache_lock); |
139 | rtn = RC_DOIT; | 148 | rtn = RC_DOIT; |
140 | 149 | ||
141 | rh = &hash_list[REQHASH(xid)]; | 150 | rh = &cache_hash[request_hash(xid)]; |
142 | hlist_for_each_entry(rp, hn, rh, c_hash) { | 151 | hlist_for_each_entry(rp, hn, rh, c_hash) { |
143 | if (rp->c_state != RC_UNUSED && | 152 | if (rp->c_state != RC_UNUSED && |
144 | xid == rp->c_xid && proc == rp->c_proc && | 153 | xid == rp->c_xid && proc == rp->c_proc && |
@@ -165,8 +174,8 @@ nfsd_cache_lookup(struct svc_rqst *rqstp, int type) | |||
165 | } | 174 | } |
166 | } | 175 | } |
167 | 176 | ||
168 | /* This should not happen */ | 177 | /* All entries on the LRU are in-progress. This should not happen */ |
169 | if (rp == NULL) { | 178 | if (&rp->c_lru == &lru_head) { |
170 | static int complaints; | 179 | static int complaints; |
171 | 180 | ||
172 | printk(KERN_WARNING "nfsd: all repcache entries locked!\n"); | 181 | printk(KERN_WARNING "nfsd: all repcache entries locked!\n"); |
@@ -264,7 +273,7 @@ nfsd_cache_update(struct svc_rqst *rqstp, int cachetype, __be32 *statp) | |||
264 | 273 | ||
265 | len = resv->iov_len - ((char*)statp - (char*)resv->iov_base); | 274 | len = resv->iov_len - ((char*)statp - (char*)resv->iov_base); |
266 | len >>= 2; | 275 | len >>= 2; |
267 | 276 | ||
268 | /* Don't cache excessive amounts of data and XDR failures */ | 277 | /* Don't cache excessive amounts of data and XDR failures */ |
269 | if (!statp || len > (256 >> 2)) { | 278 | if (!statp || len > (256 >> 2)) { |
270 | rp->c_state = RC_UNUSED; | 279 | rp->c_state = RC_UNUSED; |
diff --git a/fs/nfsd/nfsctl.c b/fs/nfsd/nfsctl.c index af16849d243a..1250fb978ac1 100644 --- a/fs/nfsd/nfsctl.c +++ b/fs/nfsd/nfsctl.c | |||
@@ -207,10 +207,14 @@ static struct file_operations pool_stats_operations = { | |||
207 | static ssize_t write_svc(struct file *file, char *buf, size_t size) | 207 | static ssize_t write_svc(struct file *file, char *buf, size_t size) |
208 | { | 208 | { |
209 | struct nfsctl_svc *data; | 209 | struct nfsctl_svc *data; |
210 | int err; | ||
210 | if (size < sizeof(*data)) | 211 | if (size < sizeof(*data)) |
211 | return -EINVAL; | 212 | return -EINVAL; |
212 | data = (struct nfsctl_svc*) buf; | 213 | data = (struct nfsctl_svc*) buf; |
213 | return nfsd_svc(data->svc_port, data->svc_nthreads); | 214 | err = nfsd_svc(data->svc_port, data->svc_nthreads); |
215 | if (err < 0) | ||
216 | return err; | ||
217 | return 0; | ||
214 | } | 218 | } |
215 | 219 | ||
216 | /** | 220 | /** |
@@ -692,11 +696,12 @@ static ssize_t write_threads(struct file *file, char *buf, size_t size) | |||
692 | if (newthreads < 0) | 696 | if (newthreads < 0) |
693 | return -EINVAL; | 697 | return -EINVAL; |
694 | rv = nfsd_svc(NFS_PORT, newthreads); | 698 | rv = nfsd_svc(NFS_PORT, newthreads); |
695 | if (rv) | 699 | if (rv < 0) |
696 | return rv; | 700 | return rv; |
697 | } | 701 | } else |
698 | sprintf(buf, "%d\n", nfsd_nrthreads()); | 702 | rv = nfsd_nrthreads(); |
699 | return strlen(buf); | 703 | |
704 | return scnprintf(buf, SIMPLE_TRANSACTION_LIMIT, "%d\n", rv); | ||
700 | } | 705 | } |
701 | 706 | ||
702 | /** | 707 | /** |
@@ -793,7 +798,7 @@ static ssize_t __write_versions(struct file *file, char *buf, size_t size) | |||
793 | { | 798 | { |
794 | char *mesg = buf; | 799 | char *mesg = buf; |
795 | char *vers, *minorp, sign; | 800 | char *vers, *minorp, sign; |
796 | int len, num; | 801 | int len, num, remaining; |
797 | unsigned minor; | 802 | unsigned minor; |
798 | ssize_t tlen = 0; | 803 | ssize_t tlen = 0; |
799 | char *sep; | 804 | char *sep; |
@@ -840,32 +845,50 @@ static ssize_t __write_versions(struct file *file, char *buf, size_t size) | |||
840 | } | 845 | } |
841 | next: | 846 | next: |
842 | vers += len + 1; | 847 | vers += len + 1; |
843 | tlen += len; | ||
844 | } while ((len = qword_get(&mesg, vers, size)) > 0); | 848 | } while ((len = qword_get(&mesg, vers, size)) > 0); |
845 | /* If all get turned off, turn them back on, as | 849 | /* If all get turned off, turn them back on, as |
846 | * having no versions is BAD | 850 | * having no versions is BAD |
847 | */ | 851 | */ |
848 | nfsd_reset_versions(); | 852 | nfsd_reset_versions(); |
849 | } | 853 | } |
854 | |||
850 | /* Now write current state into reply buffer */ | 855 | /* Now write current state into reply buffer */ |
851 | len = 0; | 856 | len = 0; |
852 | sep = ""; | 857 | sep = ""; |
858 | remaining = SIMPLE_TRANSACTION_LIMIT; | ||
853 | for (num=2 ; num <= 4 ; num++) | 859 | for (num=2 ; num <= 4 ; num++) |
854 | if (nfsd_vers(num, NFSD_AVAIL)) { | 860 | if (nfsd_vers(num, NFSD_AVAIL)) { |
855 | len += sprintf(buf+len, "%s%c%d", sep, | 861 | len = snprintf(buf, remaining, "%s%c%d", sep, |
856 | nfsd_vers(num, NFSD_TEST)?'+':'-', | 862 | nfsd_vers(num, NFSD_TEST)?'+':'-', |
857 | num); | 863 | num); |
858 | sep = " "; | 864 | sep = " "; |
865 | |||
866 | if (len > remaining) | ||
867 | break; | ||
868 | remaining -= len; | ||
869 | buf += len; | ||
870 | tlen += len; | ||
859 | } | 871 | } |
860 | if (nfsd_vers(4, NFSD_AVAIL)) | 872 | if (nfsd_vers(4, NFSD_AVAIL)) |
861 | for (minor = 1; minor <= NFSD_SUPPORTED_MINOR_VERSION; minor++) | 873 | for (minor = 1; minor <= NFSD_SUPPORTED_MINOR_VERSION; |
862 | len += sprintf(buf+len, " %c4.%u", | 874 | minor++) { |
875 | len = snprintf(buf, remaining, " %c4.%u", | ||
863 | (nfsd_vers(4, NFSD_TEST) && | 876 | (nfsd_vers(4, NFSD_TEST) && |
864 | nfsd_minorversion(minor, NFSD_TEST)) ? | 877 | nfsd_minorversion(minor, NFSD_TEST)) ? |
865 | '+' : '-', | 878 | '+' : '-', |
866 | minor); | 879 | minor); |
867 | len += sprintf(buf+len, "\n"); | 880 | |
868 | return len; | 881 | if (len > remaining) |
882 | break; | ||
883 | remaining -= len; | ||
884 | buf += len; | ||
885 | tlen += len; | ||
886 | } | ||
887 | |||
888 | len = snprintf(buf, remaining, "\n"); | ||
889 | if (len > remaining) | ||
890 | return -EINVAL; | ||
891 | return tlen + len; | ||
869 | } | 892 | } |
870 | 893 | ||
871 | /** | 894 | /** |
@@ -910,104 +933,143 @@ static ssize_t write_versions(struct file *file, char *buf, size_t size) | |||
910 | return rv; | 933 | return rv; |
911 | } | 934 | } |
912 | 935 | ||
913 | static ssize_t __write_ports(struct file *file, char *buf, size_t size) | 936 | /* |
937 | * Zero-length write. Return a list of NFSD's current listener | ||
938 | * transports. | ||
939 | */ | ||
940 | static ssize_t __write_ports_names(char *buf) | ||
914 | { | 941 | { |
915 | if (size == 0) { | 942 | if (nfsd_serv == NULL) |
916 | int len = 0; | 943 | return 0; |
944 | return svc_xprt_names(nfsd_serv, buf, SIMPLE_TRANSACTION_LIMIT); | ||
945 | } | ||
917 | 946 | ||
918 | if (nfsd_serv) | 947 | /* |
919 | len = svc_xprt_names(nfsd_serv, buf, 0); | 948 | * A single 'fd' number was written, in which case it must be for |
920 | return len; | 949 | * a socket of a supported family/protocol, and we use it as an |
921 | } | 950 | * nfsd listener. |
922 | /* Either a single 'fd' number is written, in which | 951 | */ |
923 | * case it must be for a socket of a supported family/protocol, | 952 | static ssize_t __write_ports_addfd(char *buf) |
924 | * and we use it as an nfsd socket, or | 953 | { |
925 | * A '-' followed by the 'name' of a socket in which case | 954 | char *mesg = buf; |
926 | * we close the socket. | 955 | int fd, err; |
927 | */ | 956 | |
928 | if (isdigit(buf[0])) { | 957 | err = get_int(&mesg, &fd); |
929 | char *mesg = buf; | 958 | if (err != 0 || fd < 0) |
930 | int fd; | 959 | return -EINVAL; |
931 | int err; | 960 | |
932 | err = get_int(&mesg, &fd); | 961 | err = nfsd_create_serv(); |
933 | if (err) | 962 | if (err != 0) |
934 | return -EINVAL; | 963 | return err; |
935 | if (fd < 0) | 964 | |
936 | return -EINVAL; | 965 | err = lockd_up(); |
937 | err = nfsd_create_serv(); | 966 | if (err != 0) |
938 | if (!err) { | 967 | goto out; |
939 | err = svc_addsock(nfsd_serv, fd, buf); | 968 | |
940 | if (err >= 0) { | 969 | err = svc_addsock(nfsd_serv, fd, buf, SIMPLE_TRANSACTION_LIMIT); |
941 | err = lockd_up(); | 970 | if (err < 0) |
942 | if (err < 0) | 971 | lockd_down(); |
943 | svc_sock_names(buf+strlen(buf)+1, nfsd_serv, buf); | 972 | |
944 | } | 973 | out: |
945 | /* Decrease the count, but don't shutdown the | 974 | /* Decrease the count, but don't shut down the service */ |
946 | * the service | 975 | nfsd_serv->sv_nrthreads--; |
947 | */ | 976 | return err; |
948 | nfsd_serv->sv_nrthreads--; | 977 | } |
949 | } | 978 | |
950 | return err < 0 ? err : 0; | 979 | /* |
951 | } | 980 | * A '-' followed by the 'name' of a socket means we close the socket. |
952 | if (buf[0] == '-' && isdigit(buf[1])) { | 981 | */ |
953 | char *toclose = kstrdup(buf+1, GFP_KERNEL); | 982 | static ssize_t __write_ports_delfd(char *buf) |
954 | int len = 0; | 983 | { |
955 | if (!toclose) | 984 | char *toclose; |
956 | return -ENOMEM; | 985 | int len = 0; |
957 | if (nfsd_serv) | 986 | |
958 | len = svc_sock_names(buf, nfsd_serv, toclose); | 987 | toclose = kstrdup(buf + 1, GFP_KERNEL); |
959 | if (len >= 0) | 988 | if (toclose == NULL) |
960 | lockd_down(); | 989 | return -ENOMEM; |
961 | kfree(toclose); | 990 | |
962 | return len; | 991 | if (nfsd_serv != NULL) |
963 | } | 992 | len = svc_sock_names(nfsd_serv, buf, |
964 | /* | 993 | SIMPLE_TRANSACTION_LIMIT, toclose); |
965 | * Add a transport listener by writing it's transport name | 994 | if (len >= 0) |
966 | */ | 995 | lockd_down(); |
967 | if (isalpha(buf[0])) { | 996 | |
968 | int err; | 997 | kfree(toclose); |
969 | char transport[16]; | 998 | return len; |
970 | int port; | 999 | } |
971 | if (sscanf(buf, "%15s %4d", transport, &port) == 2) { | 1000 | |
972 | if (port < 1 || port > 65535) | 1001 | /* |
973 | return -EINVAL; | 1002 | * A transport listener is added by writing it's transport name and |
974 | err = nfsd_create_serv(); | 1003 | * a port number. |
975 | if (!err) { | 1004 | */ |
976 | err = svc_create_xprt(nfsd_serv, | 1005 | static ssize_t __write_ports_addxprt(char *buf) |
977 | transport, PF_INET, port, | 1006 | { |
978 | SVC_SOCK_ANONYMOUS); | 1007 | char transport[16]; |
979 | if (err == -ENOENT) | 1008 | int port, err; |
980 | /* Give a reasonable perror msg for | 1009 | |
981 | * bad transport string */ | 1010 | if (sscanf(buf, "%15s %4u", transport, &port) != 2) |
982 | err = -EPROTONOSUPPORT; | 1011 | return -EINVAL; |
983 | } | 1012 | |
984 | return err < 0 ? err : 0; | 1013 | if (port < 1 || port > USHORT_MAX) |
985 | } | 1014 | return -EINVAL; |
986 | } | 1015 | |
987 | /* | 1016 | err = nfsd_create_serv(); |
988 | * Remove a transport by writing it's transport name and port number | 1017 | if (err != 0) |
989 | */ | 1018 | return err; |
990 | if (buf[0] == '-' && isalpha(buf[1])) { | 1019 | |
991 | struct svc_xprt *xprt; | 1020 | err = svc_create_xprt(nfsd_serv, transport, |
992 | int err = -EINVAL; | 1021 | PF_INET, port, SVC_SOCK_ANONYMOUS); |
993 | char transport[16]; | 1022 | if (err < 0) { |
994 | int port; | 1023 | /* Give a reasonable perror msg for bad transport string */ |
995 | if (sscanf(&buf[1], "%15s %4d", transport, &port) == 2) { | 1024 | if (err == -ENOENT) |
996 | if (port < 1 || port > 65535) | 1025 | err = -EPROTONOSUPPORT; |
997 | return -EINVAL; | 1026 | return err; |
998 | if (nfsd_serv) { | ||
999 | xprt = svc_find_xprt(nfsd_serv, transport, | ||
1000 | AF_UNSPEC, port); | ||
1001 | if (xprt) { | ||
1002 | svc_close_xprt(xprt); | ||
1003 | svc_xprt_put(xprt); | ||
1004 | err = 0; | ||
1005 | } else | ||
1006 | err = -ENOTCONN; | ||
1007 | } | ||
1008 | return err < 0 ? err : 0; | ||
1009 | } | ||
1010 | } | 1027 | } |
1028 | return 0; | ||
1029 | } | ||
1030 | |||
1031 | /* | ||
1032 | * A transport listener is removed by writing a "-", it's transport | ||
1033 | * name, and it's port number. | ||
1034 | */ | ||
1035 | static ssize_t __write_ports_delxprt(char *buf) | ||
1036 | { | ||
1037 | struct svc_xprt *xprt; | ||
1038 | char transport[16]; | ||
1039 | int port; | ||
1040 | |||
1041 | if (sscanf(&buf[1], "%15s %4u", transport, &port) != 2) | ||
1042 | return -EINVAL; | ||
1043 | |||
1044 | if (port < 1 || port > USHORT_MAX || nfsd_serv == NULL) | ||
1045 | return -EINVAL; | ||
1046 | |||
1047 | xprt = svc_find_xprt(nfsd_serv, transport, AF_UNSPEC, port); | ||
1048 | if (xprt == NULL) | ||
1049 | return -ENOTCONN; | ||
1050 | |||
1051 | svc_close_xprt(xprt); | ||
1052 | svc_xprt_put(xprt); | ||
1053 | return 0; | ||
1054 | } | ||
1055 | |||
1056 | static ssize_t __write_ports(struct file *file, char *buf, size_t size) | ||
1057 | { | ||
1058 | if (size == 0) | ||
1059 | return __write_ports_names(buf); | ||
1060 | |||
1061 | if (isdigit(buf[0])) | ||
1062 | return __write_ports_addfd(buf); | ||
1063 | |||
1064 | if (buf[0] == '-' && isdigit(buf[1])) | ||
1065 | return __write_ports_delfd(buf); | ||
1066 | |||
1067 | if (isalpha(buf[0])) | ||
1068 | return __write_ports_addxprt(buf); | ||
1069 | |||
1070 | if (buf[0] == '-' && isalpha(buf[1])) | ||
1071 | return __write_ports_delxprt(buf); | ||
1072 | |||
1011 | return -EINVAL; | 1073 | return -EINVAL; |
1012 | } | 1074 | } |
1013 | 1075 | ||
@@ -1030,7 +1092,9 @@ static ssize_t __write_ports(struct file *file, char *buf, size_t size) | |||
1030 | * buf: C string containing an unsigned | 1092 | * buf: C string containing an unsigned |
1031 | * integer value representing a bound | 1093 | * integer value representing a bound |
1032 | * but unconnected socket that is to be | 1094 | * but unconnected socket that is to be |
1033 | * used as an NFSD listener | 1095 | * used as an NFSD listener; listen(3) |
1096 | * must be called for a SOCK_STREAM | ||
1097 | * socket, otherwise it is ignored | ||
1034 | * size: non-zero length of C string in @buf | 1098 | * size: non-zero length of C string in @buf |
1035 | * Output: | 1099 | * Output: |
1036 | * On success: NFS service is started; | 1100 | * On success: NFS service is started; |
@@ -1138,7 +1202,9 @@ static ssize_t write_maxblksize(struct file *file, char *buf, size_t size) | |||
1138 | nfsd_max_blksize = bsize; | 1202 | nfsd_max_blksize = bsize; |
1139 | mutex_unlock(&nfsd_mutex); | 1203 | mutex_unlock(&nfsd_mutex); |
1140 | } | 1204 | } |
1141 | return sprintf(buf, "%d\n", nfsd_max_blksize); | 1205 | |
1206 | return scnprintf(buf, SIMPLE_TRANSACTION_LIMIT, "%d\n", | ||
1207 | nfsd_max_blksize); | ||
1142 | } | 1208 | } |
1143 | 1209 | ||
1144 | #ifdef CONFIG_NFSD_V4 | 1210 | #ifdef CONFIG_NFSD_V4 |
@@ -1162,8 +1228,9 @@ static ssize_t __write_leasetime(struct file *file, char *buf, size_t size) | |||
1162 | return -EINVAL; | 1228 | return -EINVAL; |
1163 | nfs4_reset_lease(lease); | 1229 | nfs4_reset_lease(lease); |
1164 | } | 1230 | } |
1165 | sprintf(buf, "%ld\n", nfs4_lease_time()); | 1231 | |
1166 | return strlen(buf); | 1232 | return scnprintf(buf, SIMPLE_TRANSACTION_LIMIT, "%ld\n", |
1233 | nfs4_lease_time()); | ||
1167 | } | 1234 | } |
1168 | 1235 | ||
1169 | /** | 1236 | /** |
@@ -1219,8 +1286,9 @@ static ssize_t __write_recoverydir(struct file *file, char *buf, size_t size) | |||
1219 | 1286 | ||
1220 | status = nfs4_reset_recoverydir(recdir); | 1287 | status = nfs4_reset_recoverydir(recdir); |
1221 | } | 1288 | } |
1222 | sprintf(buf, "%s\n", nfs4_recoverydir()); | 1289 | |
1223 | return strlen(buf); | 1290 | return scnprintf(buf, SIMPLE_TRANSACTION_LIMIT, "%s\n", |
1291 | nfs4_recoverydir()); | ||
1224 | } | 1292 | } |
1225 | 1293 | ||
1226 | /** | 1294 | /** |
diff --git a/fs/nfsd/nfsfh.c b/fs/nfsd/nfsfh.c index 9f1ca17293d3..8847f3fbfc1e 100644 --- a/fs/nfsd/nfsfh.c +++ b/fs/nfsd/nfsfh.c | |||
@@ -27,9 +27,6 @@ | |||
27 | #define NFSDDBG_FACILITY NFSDDBG_FH | 27 | #define NFSDDBG_FACILITY NFSDDBG_FH |
28 | 28 | ||
29 | 29 | ||
30 | static int nfsd_nr_verified; | ||
31 | static int nfsd_nr_put; | ||
32 | |||
33 | /* | 30 | /* |
34 | * our acceptability function. | 31 | * our acceptability function. |
35 | * if NOSUBTREECHECK, accept anything | 32 | * if NOSUBTREECHECK, accept anything |
@@ -251,7 +248,6 @@ static __be32 nfsd_set_fh_dentry(struct svc_rqst *rqstp, struct svc_fh *fhp) | |||
251 | 248 | ||
252 | fhp->fh_dentry = dentry; | 249 | fhp->fh_dentry = dentry; |
253 | fhp->fh_export = exp; | 250 | fhp->fh_export = exp; |
254 | nfsd_nr_verified++; | ||
255 | return 0; | 251 | return 0; |
256 | out: | 252 | out: |
257 | exp_put(exp); | 253 | exp_put(exp); |
@@ -552,7 +548,6 @@ fh_compose(struct svc_fh *fhp, struct svc_export *exp, struct dentry *dentry, | |||
552 | return nfserr_opnotsupp; | 548 | return nfserr_opnotsupp; |
553 | } | 549 | } |
554 | 550 | ||
555 | nfsd_nr_verified++; | ||
556 | return 0; | 551 | return 0; |
557 | } | 552 | } |
558 | 553 | ||
@@ -609,7 +604,6 @@ fh_put(struct svc_fh *fhp) | |||
609 | fhp->fh_pre_saved = 0; | 604 | fhp->fh_pre_saved = 0; |
610 | fhp->fh_post_saved = 0; | 605 | fhp->fh_post_saved = 0; |
611 | #endif | 606 | #endif |
612 | nfsd_nr_put++; | ||
613 | } | 607 | } |
614 | if (exp) { | 608 | if (exp) { |
615 | cache_put(&exp->h, &svc_export_cache); | 609 | cache_put(&exp->h, &svc_export_cache); |
diff --git a/fs/nfsd/nfsproc.c b/fs/nfsd/nfsproc.c index e298e260b5f1..0eb9c820b7a6 100644 --- a/fs/nfsd/nfsproc.c +++ b/fs/nfsd/nfsproc.c | |||
@@ -533,45 +533,179 @@ nfsd_proc_statfs(struct svc_rqst * rqstp, struct nfsd_fhandle *argp, | |||
533 | * NFSv2 Server procedures. | 533 | * NFSv2 Server procedures. |
534 | * Only the results of non-idempotent operations are cached. | 534 | * Only the results of non-idempotent operations are cached. |
535 | */ | 535 | */ |
536 | #define nfsd_proc_none NULL | ||
537 | #define nfssvc_release_none NULL | ||
538 | struct nfsd_void { int dummy; }; | 536 | struct nfsd_void { int dummy; }; |
539 | 537 | ||
540 | #define PROC(name, argt, rest, relt, cache, respsize) \ | ||
541 | { (svc_procfunc) nfsd_proc_##name, \ | ||
542 | (kxdrproc_t) nfssvc_decode_##argt, \ | ||
543 | (kxdrproc_t) nfssvc_encode_##rest, \ | ||
544 | (kxdrproc_t) nfssvc_release_##relt, \ | ||
545 | sizeof(struct nfsd_##argt), \ | ||
546 | sizeof(struct nfsd_##rest), \ | ||
547 | 0, \ | ||
548 | cache, \ | ||
549 | respsize, \ | ||
550 | } | ||
551 | |||
552 | #define ST 1 /* status */ | 538 | #define ST 1 /* status */ |
553 | #define FH 8 /* filehandle */ | 539 | #define FH 8 /* filehandle */ |
554 | #define AT 18 /* attributes */ | 540 | #define AT 18 /* attributes */ |
555 | 541 | ||
556 | static struct svc_procedure nfsd_procedures2[18] = { | 542 | static struct svc_procedure nfsd_procedures2[18] = { |
557 | PROC(null, void, void, none, RC_NOCACHE, ST), | 543 | [NFSPROC_NULL] = { |
558 | PROC(getattr, fhandle, attrstat, fhandle, RC_NOCACHE, ST+AT), | 544 | .pc_func = (svc_procfunc) nfsd_proc_null, |
559 | PROC(setattr, sattrargs, attrstat, fhandle, RC_REPLBUFF, ST+AT), | 545 | .pc_decode = (kxdrproc_t) nfssvc_decode_void, |
560 | PROC(none, void, void, none, RC_NOCACHE, ST), | 546 | .pc_encode = (kxdrproc_t) nfssvc_encode_void, |
561 | PROC(lookup, diropargs, diropres, fhandle, RC_NOCACHE, ST+FH+AT), | 547 | .pc_argsize = sizeof(struct nfsd_void), |
562 | PROC(readlink, readlinkargs, readlinkres, none, RC_NOCACHE, ST+1+NFS_MAXPATHLEN/4), | 548 | .pc_ressize = sizeof(struct nfsd_void), |
563 | PROC(read, readargs, readres, fhandle, RC_NOCACHE, ST+AT+1+NFSSVC_MAXBLKSIZE_V2/4), | 549 | .pc_cachetype = RC_NOCACHE, |
564 | PROC(none, void, void, none, RC_NOCACHE, ST), | 550 | .pc_xdrressize = ST, |
565 | PROC(write, writeargs, attrstat, fhandle, RC_REPLBUFF, ST+AT), | 551 | }, |
566 | PROC(create, createargs, diropres, fhandle, RC_REPLBUFF, ST+FH+AT), | 552 | [NFSPROC_GETATTR] = { |
567 | PROC(remove, diropargs, void, none, RC_REPLSTAT, ST), | 553 | .pc_func = (svc_procfunc) nfsd_proc_getattr, |
568 | PROC(rename, renameargs, void, none, RC_REPLSTAT, ST), | 554 | .pc_decode = (kxdrproc_t) nfssvc_decode_fhandle, |
569 | PROC(link, linkargs, void, none, RC_REPLSTAT, ST), | 555 | .pc_encode = (kxdrproc_t) nfssvc_encode_attrstat, |
570 | PROC(symlink, symlinkargs, void, none, RC_REPLSTAT, ST), | 556 | .pc_release = (kxdrproc_t) nfssvc_release_fhandle, |
571 | PROC(mkdir, createargs, diropres, fhandle, RC_REPLBUFF, ST+FH+AT), | 557 | .pc_argsize = sizeof(struct nfsd_fhandle), |
572 | PROC(rmdir, diropargs, void, none, RC_REPLSTAT, ST), | 558 | .pc_ressize = sizeof(struct nfsd_attrstat), |
573 | PROC(readdir, readdirargs, readdirres, none, RC_NOCACHE, 0), | 559 | .pc_cachetype = RC_NOCACHE, |
574 | PROC(statfs, fhandle, statfsres, none, RC_NOCACHE, ST+5), | 560 | .pc_xdrressize = ST+AT, |
561 | }, | ||
562 | [NFSPROC_SETATTR] = { | ||
563 | .pc_func = (svc_procfunc) nfsd_proc_setattr, | ||
564 | .pc_decode = (kxdrproc_t) nfssvc_decode_sattrargs, | ||
565 | .pc_encode = (kxdrproc_t) nfssvc_encode_attrstat, | ||
566 | .pc_release = (kxdrproc_t) nfssvc_release_fhandle, | ||
567 | .pc_argsize = sizeof(struct nfsd_sattrargs), | ||
568 | .pc_ressize = sizeof(struct nfsd_attrstat), | ||
569 | .pc_cachetype = RC_REPLBUFF, | ||
570 | .pc_xdrressize = ST+AT, | ||
571 | }, | ||
572 | [NFSPROC_ROOT] = { | ||
573 | .pc_decode = (kxdrproc_t) nfssvc_decode_void, | ||
574 | .pc_encode = (kxdrproc_t) nfssvc_encode_void, | ||
575 | .pc_argsize = sizeof(struct nfsd_void), | ||
576 | .pc_ressize = sizeof(struct nfsd_void), | ||
577 | .pc_cachetype = RC_NOCACHE, | ||
578 | .pc_xdrressize = ST, | ||
579 | }, | ||
580 | [NFSPROC_LOOKUP] = { | ||
581 | .pc_func = (svc_procfunc) nfsd_proc_lookup, | ||
582 | .pc_decode = (kxdrproc_t) nfssvc_decode_diropargs, | ||
583 | .pc_encode = (kxdrproc_t) nfssvc_encode_diropres, | ||
584 | .pc_release = (kxdrproc_t) nfssvc_release_fhandle, | ||
585 | .pc_argsize = sizeof(struct nfsd_diropargs), | ||
586 | .pc_ressize = sizeof(struct nfsd_diropres), | ||
587 | .pc_cachetype = RC_NOCACHE, | ||
588 | .pc_xdrressize = ST+FH+AT, | ||
589 | }, | ||
590 | [NFSPROC_READLINK] = { | ||
591 | .pc_func = (svc_procfunc) nfsd_proc_readlink, | ||
592 | .pc_decode = (kxdrproc_t) nfssvc_decode_readlinkargs, | ||
593 | .pc_encode = (kxdrproc_t) nfssvc_encode_readlinkres, | ||
594 | .pc_argsize = sizeof(struct nfsd_readlinkargs), | ||
595 | .pc_ressize = sizeof(struct nfsd_readlinkres), | ||
596 | .pc_cachetype = RC_NOCACHE, | ||
597 | .pc_xdrressize = ST+1+NFS_MAXPATHLEN/4, | ||
598 | }, | ||
599 | [NFSPROC_READ] = { | ||
600 | .pc_func = (svc_procfunc) nfsd_proc_read, | ||
601 | .pc_decode = (kxdrproc_t) nfssvc_decode_readargs, | ||
602 | .pc_encode = (kxdrproc_t) nfssvc_encode_readres, | ||
603 | .pc_release = (kxdrproc_t) nfssvc_release_fhandle, | ||
604 | .pc_argsize = sizeof(struct nfsd_readargs), | ||
605 | .pc_ressize = sizeof(struct nfsd_readres), | ||
606 | .pc_cachetype = RC_NOCACHE, | ||
607 | .pc_xdrressize = ST+AT+1+NFSSVC_MAXBLKSIZE_V2/4, | ||
608 | }, | ||
609 | [NFSPROC_WRITECACHE] = { | ||
610 | .pc_decode = (kxdrproc_t) nfssvc_decode_void, | ||
611 | .pc_encode = (kxdrproc_t) nfssvc_encode_void, | ||
612 | .pc_argsize = sizeof(struct nfsd_void), | ||
613 | .pc_ressize = sizeof(struct nfsd_void), | ||
614 | .pc_cachetype = RC_NOCACHE, | ||
615 | .pc_xdrressize = ST, | ||
616 | }, | ||
617 | [NFSPROC_WRITE] = { | ||
618 | .pc_func = (svc_procfunc) nfsd_proc_write, | ||
619 | .pc_decode = (kxdrproc_t) nfssvc_decode_writeargs, | ||
620 | .pc_encode = (kxdrproc_t) nfssvc_encode_attrstat, | ||
621 | .pc_release = (kxdrproc_t) nfssvc_release_fhandle, | ||
622 | .pc_argsize = sizeof(struct nfsd_writeargs), | ||
623 | .pc_ressize = sizeof(struct nfsd_attrstat), | ||
624 | .pc_cachetype = RC_REPLBUFF, | ||
625 | .pc_xdrressize = ST+AT, | ||
626 | }, | ||
627 | [NFSPROC_CREATE] = { | ||
628 | .pc_func = (svc_procfunc) nfsd_proc_create, | ||
629 | .pc_decode = (kxdrproc_t) nfssvc_decode_createargs, | ||
630 | .pc_encode = (kxdrproc_t) nfssvc_encode_diropres, | ||
631 | .pc_release = (kxdrproc_t) nfssvc_release_fhandle, | ||
632 | .pc_argsize = sizeof(struct nfsd_createargs), | ||
633 | .pc_ressize = sizeof(struct nfsd_diropres), | ||
634 | .pc_cachetype = RC_REPLBUFF, | ||
635 | .pc_xdrressize = ST+FH+AT, | ||
636 | }, | ||
637 | [NFSPROC_REMOVE] = { | ||
638 | .pc_func = (svc_procfunc) nfsd_proc_remove, | ||
639 | .pc_decode = (kxdrproc_t) nfssvc_decode_diropargs, | ||
640 | .pc_encode = (kxdrproc_t) nfssvc_encode_void, | ||
641 | .pc_argsize = sizeof(struct nfsd_diropargs), | ||
642 | .pc_ressize = sizeof(struct nfsd_void), | ||
643 | .pc_cachetype = RC_REPLSTAT, | ||
644 | .pc_xdrressize = ST, | ||
645 | }, | ||
646 | [NFSPROC_RENAME] = { | ||
647 | .pc_func = (svc_procfunc) nfsd_proc_rename, | ||
648 | .pc_decode = (kxdrproc_t) nfssvc_decode_renameargs, | ||
649 | .pc_encode = (kxdrproc_t) nfssvc_encode_void, | ||
650 | .pc_argsize = sizeof(struct nfsd_renameargs), | ||
651 | .pc_ressize = sizeof(struct nfsd_void), | ||
652 | .pc_cachetype = RC_REPLSTAT, | ||
653 | .pc_xdrressize = ST, | ||
654 | }, | ||
655 | [NFSPROC_LINK] = { | ||
656 | .pc_func = (svc_procfunc) nfsd_proc_link, | ||
657 | .pc_decode = (kxdrproc_t) nfssvc_decode_linkargs, | ||
658 | .pc_encode = (kxdrproc_t) nfssvc_encode_void, | ||
659 | .pc_argsize = sizeof(struct nfsd_linkargs), | ||
660 | .pc_ressize = sizeof(struct nfsd_void), | ||
661 | .pc_cachetype = RC_REPLSTAT, | ||
662 | .pc_xdrressize = ST, | ||
663 | }, | ||
664 | [NFSPROC_SYMLINK] = { | ||
665 | .pc_func = (svc_procfunc) nfsd_proc_symlink, | ||
666 | .pc_decode = (kxdrproc_t) nfssvc_decode_symlinkargs, | ||
667 | .pc_encode = (kxdrproc_t) nfssvc_encode_void, | ||
668 | .pc_argsize = sizeof(struct nfsd_symlinkargs), | ||
669 | .pc_ressize = sizeof(struct nfsd_void), | ||
670 | .pc_cachetype = RC_REPLSTAT, | ||
671 | .pc_xdrressize = ST, | ||
672 | }, | ||
673 | [NFSPROC_MKDIR] = { | ||
674 | .pc_func = (svc_procfunc) nfsd_proc_mkdir, | ||
675 | .pc_decode = (kxdrproc_t) nfssvc_decode_createargs, | ||
676 | .pc_encode = (kxdrproc_t) nfssvc_encode_diropres, | ||
677 | .pc_release = (kxdrproc_t) nfssvc_release_fhandle, | ||
678 | .pc_argsize = sizeof(struct nfsd_createargs), | ||
679 | .pc_ressize = sizeof(struct nfsd_diropres), | ||
680 | .pc_cachetype = RC_REPLBUFF, | ||
681 | .pc_xdrressize = ST+FH+AT, | ||
682 | }, | ||
683 | [NFSPROC_RMDIR] = { | ||
684 | .pc_func = (svc_procfunc) nfsd_proc_rmdir, | ||
685 | .pc_decode = (kxdrproc_t) nfssvc_decode_diropargs, | ||
686 | .pc_encode = (kxdrproc_t) nfssvc_encode_void, | ||
687 | .pc_argsize = sizeof(struct nfsd_diropargs), | ||
688 | .pc_ressize = sizeof(struct nfsd_void), | ||
689 | .pc_cachetype = RC_REPLSTAT, | ||
690 | .pc_xdrressize = ST, | ||
691 | }, | ||
692 | [NFSPROC_READDIR] = { | ||
693 | .pc_func = (svc_procfunc) nfsd_proc_readdir, | ||
694 | .pc_decode = (kxdrproc_t) nfssvc_decode_readdirargs, | ||
695 | .pc_encode = (kxdrproc_t) nfssvc_encode_readdirres, | ||
696 | .pc_argsize = sizeof(struct nfsd_readdirargs), | ||
697 | .pc_ressize = sizeof(struct nfsd_readdirres), | ||
698 | .pc_cachetype = RC_NOCACHE, | ||
699 | }, | ||
700 | [NFSPROC_STATFS] = { | ||
701 | .pc_func = (svc_procfunc) nfsd_proc_statfs, | ||
702 | .pc_decode = (kxdrproc_t) nfssvc_decode_fhandle, | ||
703 | .pc_encode = (kxdrproc_t) nfssvc_encode_statfsres, | ||
704 | .pc_argsize = sizeof(struct nfsd_fhandle), | ||
705 | .pc_ressize = sizeof(struct nfsd_statfsres), | ||
706 | .pc_cachetype = RC_NOCACHE, | ||
707 | .pc_xdrressize = ST+5, | ||
708 | }, | ||
575 | }; | 709 | }; |
576 | 710 | ||
577 | 711 | ||
diff --git a/fs/nfsd/nfssvc.c b/fs/nfsd/nfssvc.c index cbba4a935786..d4c9884cd54b 100644 --- a/fs/nfsd/nfssvc.c +++ b/fs/nfsd/nfssvc.c | |||
@@ -390,12 +390,14 @@ nfsd_svc(unsigned short port, int nrservs) | |||
390 | 390 | ||
391 | mutex_lock(&nfsd_mutex); | 391 | mutex_lock(&nfsd_mutex); |
392 | dprintk("nfsd: creating service\n"); | 392 | dprintk("nfsd: creating service\n"); |
393 | error = -EINVAL; | ||
394 | if (nrservs <= 0) | 393 | if (nrservs <= 0) |
395 | nrservs = 0; | 394 | nrservs = 0; |
396 | if (nrservs > NFSD_MAXSERVS) | 395 | if (nrservs > NFSD_MAXSERVS) |
397 | nrservs = NFSD_MAXSERVS; | 396 | nrservs = NFSD_MAXSERVS; |
398 | 397 | error = 0; | |
398 | if (nrservs == 0 && nfsd_serv == NULL) | ||
399 | goto out; | ||
400 | |||
399 | /* Readahead param cache - will no-op if it already exists */ | 401 | /* Readahead param cache - will no-op if it already exists */ |
400 | error = nfsd_racache_init(2*nrservs); | 402 | error = nfsd_racache_init(2*nrservs); |
401 | if (error<0) | 403 | if (error<0) |
@@ -413,6 +415,12 @@ nfsd_svc(unsigned short port, int nrservs) | |||
413 | goto failure; | 415 | goto failure; |
414 | 416 | ||
415 | error = svc_set_num_threads(nfsd_serv, NULL, nrservs); | 417 | error = svc_set_num_threads(nfsd_serv, NULL, nrservs); |
418 | if (error == 0) | ||
419 | /* We are holding a reference to nfsd_serv which | ||
420 | * we don't want to count in the return value, | ||
421 | * so subtract 1 | ||
422 | */ | ||
423 | error = nfsd_serv->sv_nrthreads - 1; | ||
416 | failure: | 424 | failure: |
417 | svc_destroy(nfsd_serv); /* Release server */ | 425 | svc_destroy(nfsd_serv); /* Release server */ |
418 | out: | 426 | out: |
diff --git a/fs/nfsd/vfs.c b/fs/nfsd/vfs.c index 99f835753596..4145083dcf88 100644 --- a/fs/nfsd/vfs.c +++ b/fs/nfsd/vfs.c | |||
@@ -966,6 +966,43 @@ static void kill_suid(struct dentry *dentry) | |||
966 | mutex_unlock(&dentry->d_inode->i_mutex); | 966 | mutex_unlock(&dentry->d_inode->i_mutex); |
967 | } | 967 | } |
968 | 968 | ||
969 | /* | ||
970 | * Gathered writes: If another process is currently writing to the file, | ||
971 | * there's a high chance this is another nfsd (triggered by a bulk write | ||
972 | * from a client's biod). Rather than syncing the file with each write | ||
973 | * request, we sleep for 10 msec. | ||
974 | * | ||
975 | * I don't know if this roughly approximates C. Juszak's idea of | ||
976 | * gathered writes, but it's a nice and simple solution (IMHO), and it | ||
977 | * seems to work:-) | ||
978 | * | ||
979 | * Note: we do this only in the NFSv2 case, since v3 and higher have a | ||
980 | * better tool (separate unstable writes and commits) for solving this | ||
981 | * problem. | ||
982 | */ | ||
983 | static int wait_for_concurrent_writes(struct file *file) | ||
984 | { | ||
985 | struct inode *inode = file->f_path.dentry->d_inode; | ||
986 | static ino_t last_ino; | ||
987 | static dev_t last_dev; | ||
988 | int err = 0; | ||
989 | |||
990 | if (atomic_read(&inode->i_writecount) > 1 | ||
991 | || (last_ino == inode->i_ino && last_dev == inode->i_sb->s_dev)) { | ||
992 | dprintk("nfsd: write defer %d\n", task_pid_nr(current)); | ||
993 | msleep(10); | ||
994 | dprintk("nfsd: write resume %d\n", task_pid_nr(current)); | ||
995 | } | ||
996 | |||
997 | if (inode->i_state & I_DIRTY) { | ||
998 | dprintk("nfsd: write sync %d\n", task_pid_nr(current)); | ||
999 | err = nfsd_sync(file); | ||
1000 | } | ||
1001 | last_ino = inode->i_ino; | ||
1002 | last_dev = inode->i_sb->s_dev; | ||
1003 | return err; | ||
1004 | } | ||
1005 | |||
969 | static __be32 | 1006 | static __be32 |
970 | nfsd_vfs_write(struct svc_rqst *rqstp, struct svc_fh *fhp, struct file *file, | 1007 | nfsd_vfs_write(struct svc_rqst *rqstp, struct svc_fh *fhp, struct file *file, |
971 | loff_t offset, struct kvec *vec, int vlen, | 1008 | loff_t offset, struct kvec *vec, int vlen, |
@@ -978,6 +1015,7 @@ nfsd_vfs_write(struct svc_rqst *rqstp, struct svc_fh *fhp, struct file *file, | |||
978 | __be32 err = 0; | 1015 | __be32 err = 0; |
979 | int host_err; | 1016 | int host_err; |
980 | int stable = *stablep; | 1017 | int stable = *stablep; |
1018 | int use_wgather; | ||
981 | 1019 | ||
982 | #ifdef MSNFS | 1020 | #ifdef MSNFS |
983 | err = nfserr_perm; | 1021 | err = nfserr_perm; |
@@ -996,9 +1034,10 @@ nfsd_vfs_write(struct svc_rqst *rqstp, struct svc_fh *fhp, struct file *file, | |||
996 | * - the sync export option has been set, or | 1034 | * - the sync export option has been set, or |
997 | * - the client requested O_SYNC behavior (NFSv3 feature). | 1035 | * - the client requested O_SYNC behavior (NFSv3 feature). |
998 | * - The file system doesn't support fsync(). | 1036 | * - The file system doesn't support fsync(). |
999 | * When gathered writes have been configured for this volume, | 1037 | * When NFSv2 gathered writes have been configured for this volume, |
1000 | * flushing the data to disk is handled separately below. | 1038 | * flushing the data to disk is handled separately below. |
1001 | */ | 1039 | */ |
1040 | use_wgather = (rqstp->rq_vers == 2) && EX_WGATHER(exp); | ||
1002 | 1041 | ||
1003 | if (!file->f_op->fsync) {/* COMMIT3 cannot work */ | 1042 | if (!file->f_op->fsync) {/* COMMIT3 cannot work */ |
1004 | stable = 2; | 1043 | stable = 2; |
@@ -1007,7 +1046,7 @@ nfsd_vfs_write(struct svc_rqst *rqstp, struct svc_fh *fhp, struct file *file, | |||
1007 | 1046 | ||
1008 | if (!EX_ISSYNC(exp)) | 1047 | if (!EX_ISSYNC(exp)) |
1009 | stable = 0; | 1048 | stable = 0; |
1010 | if (stable && !EX_WGATHER(exp)) { | 1049 | if (stable && !use_wgather) { |
1011 | spin_lock(&file->f_lock); | 1050 | spin_lock(&file->f_lock); |
1012 | file->f_flags |= O_SYNC; | 1051 | file->f_flags |= O_SYNC; |
1013 | spin_unlock(&file->f_lock); | 1052 | spin_unlock(&file->f_lock); |
@@ -1017,52 +1056,20 @@ nfsd_vfs_write(struct svc_rqst *rqstp, struct svc_fh *fhp, struct file *file, | |||
1017 | oldfs = get_fs(); set_fs(KERNEL_DS); | 1056 | oldfs = get_fs(); set_fs(KERNEL_DS); |
1018 | host_err = vfs_writev(file, (struct iovec __user *)vec, vlen, &offset); | 1057 | host_err = vfs_writev(file, (struct iovec __user *)vec, vlen, &offset); |
1019 | set_fs(oldfs); | 1058 | set_fs(oldfs); |
1020 | if (host_err >= 0) { | 1059 | if (host_err < 0) |
1021 | *cnt = host_err; | 1060 | goto out_nfserr; |
1022 | nfsdstats.io_write += host_err; | 1061 | *cnt = host_err; |
1023 | fsnotify_modify(file->f_path.dentry); | 1062 | nfsdstats.io_write += host_err; |
1024 | } | 1063 | fsnotify_modify(file->f_path.dentry); |
1025 | 1064 | ||
1026 | /* clear setuid/setgid flag after write */ | 1065 | /* clear setuid/setgid flag after write */ |
1027 | if (host_err >= 0 && (inode->i_mode & (S_ISUID | S_ISGID))) | 1066 | if (inode->i_mode & (S_ISUID | S_ISGID)) |
1028 | kill_suid(dentry); | 1067 | kill_suid(dentry); |
1029 | 1068 | ||
1030 | if (host_err >= 0 && stable) { | 1069 | if (stable && use_wgather) |
1031 | static ino_t last_ino; | 1070 | host_err = wait_for_concurrent_writes(file); |
1032 | static dev_t last_dev; | ||
1033 | |||
1034 | /* | ||
1035 | * Gathered writes: If another process is currently | ||
1036 | * writing to the file, there's a high chance | ||
1037 | * this is another nfsd (triggered by a bulk write | ||
1038 | * from a client's biod). Rather than syncing the | ||
1039 | * file with each write request, we sleep for 10 msec. | ||
1040 | * | ||
1041 | * I don't know if this roughly approximates | ||
1042 | * C. Juszak's idea of gathered writes, but it's a | ||
1043 | * nice and simple solution (IMHO), and it seems to | ||
1044 | * work:-) | ||
1045 | */ | ||
1046 | if (EX_WGATHER(exp)) { | ||
1047 | if (atomic_read(&inode->i_writecount) > 1 | ||
1048 | || (last_ino == inode->i_ino && last_dev == inode->i_sb->s_dev)) { | ||
1049 | dprintk("nfsd: write defer %d\n", task_pid_nr(current)); | ||
1050 | msleep(10); | ||
1051 | dprintk("nfsd: write resume %d\n", task_pid_nr(current)); | ||
1052 | } | ||
1053 | |||
1054 | if (inode->i_state & I_DIRTY) { | ||
1055 | dprintk("nfsd: write sync %d\n", task_pid_nr(current)); | ||
1056 | host_err=nfsd_sync(file); | ||
1057 | } | ||
1058 | #if 0 | ||
1059 | wake_up(&inode->i_wait); | ||
1060 | #endif | ||
1061 | } | ||
1062 | last_ino = inode->i_ino; | ||
1063 | last_dev = inode->i_sb->s_dev; | ||
1064 | } | ||
1065 | 1071 | ||
1072 | out_nfserr: | ||
1066 | dprintk("nfsd: write complete host_err=%d\n", host_err); | 1073 | dprintk("nfsd: write complete host_err=%d\n", host_err); |
1067 | if (host_err >= 0) | 1074 | if (host_err >= 0) |
1068 | err = 0; | 1075 | err = 0; |
diff --git a/fs/notify/inotify/inotify.h b/fs/notify/inotify/inotify.h index ea2605a58b8a..f234f3a4c8ca 100644 --- a/fs/notify/inotify/inotify.h +++ b/fs/notify/inotify/inotify.h | |||
@@ -15,7 +15,8 @@ struct inotify_inode_mark_entry { | |||
15 | int wd; | 15 | int wd; |
16 | }; | 16 | }; |
17 | 17 | ||
18 | extern void inotify_destroy_mark_entry(struct fsnotify_mark_entry *entry, struct fsnotify_group *group); | 18 | extern void inotify_ignored_and_remove_idr(struct fsnotify_mark_entry *entry, |
19 | struct fsnotify_group *group); | ||
19 | extern void inotify_free_event_priv(struct fsnotify_event_private_data *event_priv); | 20 | extern void inotify_free_event_priv(struct fsnotify_event_private_data *event_priv); |
20 | 21 | ||
21 | extern const struct fsnotify_ops inotify_fsnotify_ops; | 22 | extern const struct fsnotify_ops inotify_fsnotify_ops; |
diff --git a/fs/notify/inotify/inotify_fsnotify.c b/fs/notify/inotify/inotify_fsnotify.c index 7ef75b83247e..47cd258fd24d 100644 --- a/fs/notify/inotify/inotify_fsnotify.c +++ b/fs/notify/inotify/inotify_fsnotify.c | |||
@@ -81,7 +81,7 @@ static int inotify_handle_event(struct fsnotify_group *group, struct fsnotify_ev | |||
81 | 81 | ||
82 | static void inotify_freeing_mark(struct fsnotify_mark_entry *entry, struct fsnotify_group *group) | 82 | static void inotify_freeing_mark(struct fsnotify_mark_entry *entry, struct fsnotify_group *group) |
83 | { | 83 | { |
84 | inotify_destroy_mark_entry(entry, group); | 84 | inotify_ignored_and_remove_idr(entry, group); |
85 | } | 85 | } |
86 | 86 | ||
87 | static bool inotify_should_send_event(struct fsnotify_group *group, struct inode *inode, __u32 mask) | 87 | static bool inotify_should_send_event(struct fsnotify_group *group, struct inode *inode, __u32 mask) |
diff --git a/fs/notify/inotify/inotify_user.c b/fs/notify/inotify/inotify_user.c index 982a412ac5bc..ff231ad23895 100644 --- a/fs/notify/inotify/inotify_user.c +++ b/fs/notify/inotify/inotify_user.c | |||
@@ -363,39 +363,17 @@ static int inotify_find_inode(const char __user *dirname, struct path *path, uns | |||
363 | } | 363 | } |
364 | 364 | ||
365 | /* | 365 | /* |
366 | * When, for whatever reason, inotify is done with a mark (or what used to be a | 366 | * Send IN_IGNORED for this wd, remove this wd from the idr, and drop the |
367 | * watch) we need to remove that watch from the idr and we need to send IN_IGNORED | 367 | * internal reference help on the mark because it is in the idr. |
368 | * for the given wd. | ||
369 | * | ||
370 | * There is a bit of recursion here. The loop looks like: | ||
371 | * inotify_destroy_mark_entry -> fsnotify_destroy_mark_by_entry -> | ||
372 | * inotify_freeing_mark -> inotify_destory_mark_entry -> restart | ||
373 | * But the loop is broken in 2 places. fsnotify_destroy_mark_by_entry sets | ||
374 | * entry->group = NULL before the call to inotify_freeing_mark, so the if (egroup) | ||
375 | * test below will not call back to fsnotify again. But even if that test wasn't | ||
376 | * there this would still be safe since fsnotify_destroy_mark_by_entry() is | ||
377 | * safe from recursion. | ||
378 | */ | 368 | */ |
379 | void inotify_destroy_mark_entry(struct fsnotify_mark_entry *entry, struct fsnotify_group *group) | 369 | void inotify_ignored_and_remove_idr(struct fsnotify_mark_entry *entry, |
370 | struct fsnotify_group *group) | ||
380 | { | 371 | { |
381 | struct inotify_inode_mark_entry *ientry; | 372 | struct inotify_inode_mark_entry *ientry; |
382 | struct inotify_event_private_data *event_priv; | 373 | struct inotify_event_private_data *event_priv; |
383 | struct fsnotify_event_private_data *fsn_event_priv; | 374 | struct fsnotify_event_private_data *fsn_event_priv; |
384 | struct fsnotify_group *egroup; | ||
385 | struct idr *idr; | 375 | struct idr *idr; |
386 | 376 | ||
387 | spin_lock(&entry->lock); | ||
388 | egroup = entry->group; | ||
389 | |||
390 | /* if egroup we aren't really done and something might still send events | ||
391 | * for this inode, on the callback we'll send the IN_IGNORED */ | ||
392 | if (egroup) { | ||
393 | spin_unlock(&entry->lock); | ||
394 | fsnotify_destroy_mark_by_entry(entry); | ||
395 | return; | ||
396 | } | ||
397 | spin_unlock(&entry->lock); | ||
398 | |||
399 | ientry = container_of(entry, struct inotify_inode_mark_entry, fsn_entry); | 377 | ientry = container_of(entry, struct inotify_inode_mark_entry, fsn_entry); |
400 | 378 | ||
401 | event_priv = kmem_cache_alloc(event_priv_cachep, GFP_KERNEL); | 379 | event_priv = kmem_cache_alloc(event_priv_cachep, GFP_KERNEL); |
@@ -699,7 +677,7 @@ SYSCALL_DEFINE2(inotify_rm_watch, int, fd, __s32, wd) | |||
699 | fsnotify_get_mark(entry); | 677 | fsnotify_get_mark(entry); |
700 | spin_unlock(&group->inotify_data.idr_lock); | 678 | spin_unlock(&group->inotify_data.idr_lock); |
701 | 679 | ||
702 | inotify_destroy_mark_entry(entry, group); | 680 | fsnotify_destroy_mark_by_entry(entry); |
703 | fsnotify_put_mark(entry); | 681 | fsnotify_put_mark(entry); |
704 | 682 | ||
705 | out: | 683 | out: |
diff --git a/fs/ocfs2/dlmglue.c b/fs/ocfs2/dlmglue.c index 6cdeaa76f27f..110bb57c46ab 100644 --- a/fs/ocfs2/dlmglue.c +++ b/fs/ocfs2/dlmglue.c | |||
@@ -92,6 +92,9 @@ struct ocfs2_unblock_ctl { | |||
92 | enum ocfs2_unblock_action unblock_action; | 92 | enum ocfs2_unblock_action unblock_action; |
93 | }; | 93 | }; |
94 | 94 | ||
95 | /* Lockdep class keys */ | ||
96 | struct lock_class_key lockdep_keys[OCFS2_NUM_LOCK_TYPES]; | ||
97 | |||
95 | static int ocfs2_check_meta_downconvert(struct ocfs2_lock_res *lockres, | 98 | static int ocfs2_check_meta_downconvert(struct ocfs2_lock_res *lockres, |
96 | int new_level); | 99 | int new_level); |
97 | static void ocfs2_set_meta_lvb(struct ocfs2_lock_res *lockres); | 100 | static void ocfs2_set_meta_lvb(struct ocfs2_lock_res *lockres); |
@@ -317,9 +320,16 @@ static int ocfs2_lock_create(struct ocfs2_super *osb, | |||
317 | u32 dlm_flags); | 320 | u32 dlm_flags); |
318 | static inline int ocfs2_may_continue_on_blocked_lock(struct ocfs2_lock_res *lockres, | 321 | static inline int ocfs2_may_continue_on_blocked_lock(struct ocfs2_lock_res *lockres, |
319 | int wanted); | 322 | int wanted); |
320 | static void ocfs2_cluster_unlock(struct ocfs2_super *osb, | 323 | static void __ocfs2_cluster_unlock(struct ocfs2_super *osb, |
321 | struct ocfs2_lock_res *lockres, | 324 | struct ocfs2_lock_res *lockres, |
322 | int level); | 325 | int level, unsigned long caller_ip); |
326 | static inline void ocfs2_cluster_unlock(struct ocfs2_super *osb, | ||
327 | struct ocfs2_lock_res *lockres, | ||
328 | int level) | ||
329 | { | ||
330 | __ocfs2_cluster_unlock(osb, lockres, level, _RET_IP_); | ||
331 | } | ||
332 | |||
323 | static inline void ocfs2_generic_handle_downconvert_action(struct ocfs2_lock_res *lockres); | 333 | static inline void ocfs2_generic_handle_downconvert_action(struct ocfs2_lock_res *lockres); |
324 | static inline void ocfs2_generic_handle_convert_action(struct ocfs2_lock_res *lockres); | 334 | static inline void ocfs2_generic_handle_convert_action(struct ocfs2_lock_res *lockres); |
325 | static inline void ocfs2_generic_handle_attach_action(struct ocfs2_lock_res *lockres); | 335 | static inline void ocfs2_generic_handle_attach_action(struct ocfs2_lock_res *lockres); |
@@ -489,6 +499,13 @@ static void ocfs2_lock_res_init_common(struct ocfs2_super *osb, | |||
489 | ocfs2_add_lockres_tracking(res, osb->osb_dlm_debug); | 499 | ocfs2_add_lockres_tracking(res, osb->osb_dlm_debug); |
490 | 500 | ||
491 | ocfs2_init_lock_stats(res); | 501 | ocfs2_init_lock_stats(res); |
502 | #ifdef CONFIG_DEBUG_LOCK_ALLOC | ||
503 | if (type != OCFS2_LOCK_TYPE_OPEN) | ||
504 | lockdep_init_map(&res->l_lockdep_map, ocfs2_lock_type_strings[type], | ||
505 | &lockdep_keys[type], 0); | ||
506 | else | ||
507 | res->l_lockdep_map.key = NULL; | ||
508 | #endif | ||
492 | } | 509 | } |
493 | 510 | ||
494 | void ocfs2_lock_res_init_once(struct ocfs2_lock_res *res) | 511 | void ocfs2_lock_res_init_once(struct ocfs2_lock_res *res) |
@@ -644,14 +661,10 @@ static void ocfs2_nfs_sync_lock_res_init(struct ocfs2_lock_res *res, | |||
644 | static void ocfs2_orphan_scan_lock_res_init(struct ocfs2_lock_res *res, | 661 | static void ocfs2_orphan_scan_lock_res_init(struct ocfs2_lock_res *res, |
645 | struct ocfs2_super *osb) | 662 | struct ocfs2_super *osb) |
646 | { | 663 | { |
647 | struct ocfs2_orphan_scan_lvb *lvb; | ||
648 | |||
649 | ocfs2_lock_res_init_once(res); | 664 | ocfs2_lock_res_init_once(res); |
650 | ocfs2_build_lock_name(OCFS2_LOCK_TYPE_ORPHAN_SCAN, 0, 0, res->l_name); | 665 | ocfs2_build_lock_name(OCFS2_LOCK_TYPE_ORPHAN_SCAN, 0, 0, res->l_name); |
651 | ocfs2_lock_res_init_common(osb, res, OCFS2_LOCK_TYPE_ORPHAN_SCAN, | 666 | ocfs2_lock_res_init_common(osb, res, OCFS2_LOCK_TYPE_ORPHAN_SCAN, |
652 | &ocfs2_orphan_scan_lops, osb); | 667 | &ocfs2_orphan_scan_lops, osb); |
653 | lvb = ocfs2_dlm_lvb(&res->l_lksb); | ||
654 | lvb->lvb_version = OCFS2_ORPHAN_LVB_VERSION; | ||
655 | } | 668 | } |
656 | 669 | ||
657 | void ocfs2_file_lock_res_init(struct ocfs2_lock_res *lockres, | 670 | void ocfs2_file_lock_res_init(struct ocfs2_lock_res *lockres, |
@@ -1256,11 +1269,13 @@ static int ocfs2_wait_for_mask_interruptible(struct ocfs2_mask_waiter *mw, | |||
1256 | return ret; | 1269 | return ret; |
1257 | } | 1270 | } |
1258 | 1271 | ||
1259 | static int ocfs2_cluster_lock(struct ocfs2_super *osb, | 1272 | static int __ocfs2_cluster_lock(struct ocfs2_super *osb, |
1260 | struct ocfs2_lock_res *lockres, | 1273 | struct ocfs2_lock_res *lockres, |
1261 | int level, | 1274 | int level, |
1262 | u32 lkm_flags, | 1275 | u32 lkm_flags, |
1263 | int arg_flags) | 1276 | int arg_flags, |
1277 | int l_subclass, | ||
1278 | unsigned long caller_ip) | ||
1264 | { | 1279 | { |
1265 | struct ocfs2_mask_waiter mw; | 1280 | struct ocfs2_mask_waiter mw; |
1266 | int wait, catch_signals = !(osb->s_mount_opt & OCFS2_MOUNT_NOINTR); | 1281 | int wait, catch_signals = !(osb->s_mount_opt & OCFS2_MOUNT_NOINTR); |
@@ -1403,13 +1418,37 @@ out: | |||
1403 | } | 1418 | } |
1404 | ocfs2_update_lock_stats(lockres, level, &mw, ret); | 1419 | ocfs2_update_lock_stats(lockres, level, &mw, ret); |
1405 | 1420 | ||
1421 | #ifdef CONFIG_DEBUG_LOCK_ALLOC | ||
1422 | if (!ret && lockres->l_lockdep_map.key != NULL) { | ||
1423 | if (level == DLM_LOCK_PR) | ||
1424 | rwsem_acquire_read(&lockres->l_lockdep_map, l_subclass, | ||
1425 | !!(arg_flags & OCFS2_META_LOCK_NOQUEUE), | ||
1426 | caller_ip); | ||
1427 | else | ||
1428 | rwsem_acquire(&lockres->l_lockdep_map, l_subclass, | ||
1429 | !!(arg_flags & OCFS2_META_LOCK_NOQUEUE), | ||
1430 | caller_ip); | ||
1431 | } | ||
1432 | #endif | ||
1406 | mlog_exit(ret); | 1433 | mlog_exit(ret); |
1407 | return ret; | 1434 | return ret; |
1408 | } | 1435 | } |
1409 | 1436 | ||
1410 | static void ocfs2_cluster_unlock(struct ocfs2_super *osb, | 1437 | static inline int ocfs2_cluster_lock(struct ocfs2_super *osb, |
1411 | struct ocfs2_lock_res *lockres, | 1438 | struct ocfs2_lock_res *lockres, |
1412 | int level) | 1439 | int level, |
1440 | u32 lkm_flags, | ||
1441 | int arg_flags) | ||
1442 | { | ||
1443 | return __ocfs2_cluster_lock(osb, lockres, level, lkm_flags, arg_flags, | ||
1444 | 0, _RET_IP_); | ||
1445 | } | ||
1446 | |||
1447 | |||
1448 | static void __ocfs2_cluster_unlock(struct ocfs2_super *osb, | ||
1449 | struct ocfs2_lock_res *lockres, | ||
1450 | int level, | ||
1451 | unsigned long caller_ip) | ||
1413 | { | 1452 | { |
1414 | unsigned long flags; | 1453 | unsigned long flags; |
1415 | 1454 | ||
@@ -1418,6 +1457,10 @@ static void ocfs2_cluster_unlock(struct ocfs2_super *osb, | |||
1418 | ocfs2_dec_holders(lockres, level); | 1457 | ocfs2_dec_holders(lockres, level); |
1419 | ocfs2_downconvert_on_unlock(osb, lockres); | 1458 | ocfs2_downconvert_on_unlock(osb, lockres); |
1420 | spin_unlock_irqrestore(&lockres->l_lock, flags); | 1459 | spin_unlock_irqrestore(&lockres->l_lock, flags); |
1460 | #ifdef CONFIG_DEBUG_LOCK_ALLOC | ||
1461 | if (lockres->l_lockdep_map.key != NULL) | ||
1462 | rwsem_release(&lockres->l_lockdep_map, 1, caller_ip); | ||
1463 | #endif | ||
1421 | mlog_exit_void(); | 1464 | mlog_exit_void(); |
1422 | } | 1465 | } |
1423 | 1466 | ||
@@ -1989,7 +2032,8 @@ static inline int ocfs2_meta_lvb_is_trustable(struct inode *inode, | |||
1989 | { | 2032 | { |
1990 | struct ocfs2_meta_lvb *lvb = ocfs2_dlm_lvb(&lockres->l_lksb); | 2033 | struct ocfs2_meta_lvb *lvb = ocfs2_dlm_lvb(&lockres->l_lksb); |
1991 | 2034 | ||
1992 | if (lvb->lvb_version == OCFS2_LVB_VERSION | 2035 | if (ocfs2_dlm_lvb_valid(&lockres->l_lksb) |
2036 | && lvb->lvb_version == OCFS2_LVB_VERSION | ||
1993 | && be32_to_cpu(lvb->lvb_igeneration) == inode->i_generation) | 2037 | && be32_to_cpu(lvb->lvb_igeneration) == inode->i_generation) |
1994 | return 1; | 2038 | return 1; |
1995 | return 0; | 2039 | return 0; |
@@ -2162,10 +2206,11 @@ static int ocfs2_assign_bh(struct inode *inode, | |||
2162 | * returns < 0 error if the callback will never be called, otherwise | 2206 | * returns < 0 error if the callback will never be called, otherwise |
2163 | * the result of the lock will be communicated via the callback. | 2207 | * the result of the lock will be communicated via the callback. |
2164 | */ | 2208 | */ |
2165 | int ocfs2_inode_lock_full(struct inode *inode, | 2209 | int ocfs2_inode_lock_full_nested(struct inode *inode, |
2166 | struct buffer_head **ret_bh, | 2210 | struct buffer_head **ret_bh, |
2167 | int ex, | 2211 | int ex, |
2168 | int arg_flags) | 2212 | int arg_flags, |
2213 | int subclass) | ||
2169 | { | 2214 | { |
2170 | int status, level, acquired; | 2215 | int status, level, acquired; |
2171 | u32 dlm_flags; | 2216 | u32 dlm_flags; |
@@ -2203,7 +2248,8 @@ int ocfs2_inode_lock_full(struct inode *inode, | |||
2203 | if (arg_flags & OCFS2_META_LOCK_NOQUEUE) | 2248 | if (arg_flags & OCFS2_META_LOCK_NOQUEUE) |
2204 | dlm_flags |= DLM_LKF_NOQUEUE; | 2249 | dlm_flags |= DLM_LKF_NOQUEUE; |
2205 | 2250 | ||
2206 | status = ocfs2_cluster_lock(osb, lockres, level, dlm_flags, arg_flags); | 2251 | status = __ocfs2_cluster_lock(osb, lockres, level, dlm_flags, |
2252 | arg_flags, subclass, _RET_IP_); | ||
2207 | if (status < 0) { | 2253 | if (status < 0) { |
2208 | if (status != -EAGAIN && status != -EIOCBRETRY) | 2254 | if (status != -EAGAIN && status != -EIOCBRETRY) |
2209 | mlog_errno(status); | 2255 | mlog_errno(status); |
@@ -2369,35 +2415,45 @@ void ocfs2_inode_unlock(struct inode *inode, | |||
2369 | mlog_exit_void(); | 2415 | mlog_exit_void(); |
2370 | } | 2416 | } |
2371 | 2417 | ||
2372 | int ocfs2_orphan_scan_lock(struct ocfs2_super *osb, u32 *seqno, int ex) | 2418 | int ocfs2_orphan_scan_lock(struct ocfs2_super *osb, u32 *seqno) |
2373 | { | 2419 | { |
2374 | struct ocfs2_lock_res *lockres; | 2420 | struct ocfs2_lock_res *lockres; |
2375 | struct ocfs2_orphan_scan_lvb *lvb; | 2421 | struct ocfs2_orphan_scan_lvb *lvb; |
2376 | int level = ex ? DLM_LOCK_EX : DLM_LOCK_PR; | ||
2377 | int status = 0; | 2422 | int status = 0; |
2378 | 2423 | ||
2424 | if (ocfs2_is_hard_readonly(osb)) | ||
2425 | return -EROFS; | ||
2426 | |||
2427 | if (ocfs2_mount_local(osb)) | ||
2428 | return 0; | ||
2429 | |||
2379 | lockres = &osb->osb_orphan_scan.os_lockres; | 2430 | lockres = &osb->osb_orphan_scan.os_lockres; |
2380 | status = ocfs2_cluster_lock(osb, lockres, level, 0, 0); | 2431 | status = ocfs2_cluster_lock(osb, lockres, DLM_LOCK_EX, 0, 0); |
2381 | if (status < 0) | 2432 | if (status < 0) |
2382 | return status; | 2433 | return status; |
2383 | 2434 | ||
2384 | lvb = ocfs2_dlm_lvb(&lockres->l_lksb); | 2435 | lvb = ocfs2_dlm_lvb(&lockres->l_lksb); |
2385 | if (lvb->lvb_version == OCFS2_ORPHAN_LVB_VERSION) | 2436 | if (ocfs2_dlm_lvb_valid(&lockres->l_lksb) && |
2437 | lvb->lvb_version == OCFS2_ORPHAN_LVB_VERSION) | ||
2386 | *seqno = be32_to_cpu(lvb->lvb_os_seqno); | 2438 | *seqno = be32_to_cpu(lvb->lvb_os_seqno); |
2439 | else | ||
2440 | *seqno = osb->osb_orphan_scan.os_seqno + 1; | ||
2441 | |||
2387 | return status; | 2442 | return status; |
2388 | } | 2443 | } |
2389 | 2444 | ||
2390 | void ocfs2_orphan_scan_unlock(struct ocfs2_super *osb, u32 seqno, int ex) | 2445 | void ocfs2_orphan_scan_unlock(struct ocfs2_super *osb, u32 seqno) |
2391 | { | 2446 | { |
2392 | struct ocfs2_lock_res *lockres; | 2447 | struct ocfs2_lock_res *lockres; |
2393 | struct ocfs2_orphan_scan_lvb *lvb; | 2448 | struct ocfs2_orphan_scan_lvb *lvb; |
2394 | int level = ex ? DLM_LOCK_EX : DLM_LOCK_PR; | ||
2395 | 2449 | ||
2396 | lockres = &osb->osb_orphan_scan.os_lockres; | 2450 | if (!ocfs2_is_hard_readonly(osb) && !ocfs2_mount_local(osb)) { |
2397 | lvb = ocfs2_dlm_lvb(&lockres->l_lksb); | 2451 | lockres = &osb->osb_orphan_scan.os_lockres; |
2398 | lvb->lvb_version = OCFS2_ORPHAN_LVB_VERSION; | 2452 | lvb = ocfs2_dlm_lvb(&lockres->l_lksb); |
2399 | lvb->lvb_os_seqno = cpu_to_be32(seqno); | 2453 | lvb->lvb_version = OCFS2_ORPHAN_LVB_VERSION; |
2400 | ocfs2_cluster_unlock(osb, lockres, level); | 2454 | lvb->lvb_os_seqno = cpu_to_be32(seqno); |
2455 | ocfs2_cluster_unlock(osb, lockres, DLM_LOCK_EX); | ||
2456 | } | ||
2401 | } | 2457 | } |
2402 | 2458 | ||
2403 | int ocfs2_super_lock(struct ocfs2_super *osb, | 2459 | int ocfs2_super_lock(struct ocfs2_super *osb, |
@@ -3627,7 +3683,8 @@ static int ocfs2_refresh_qinfo(struct ocfs2_mem_dqinfo *oinfo) | |||
3627 | struct ocfs2_global_disk_dqinfo *gdinfo; | 3683 | struct ocfs2_global_disk_dqinfo *gdinfo; |
3628 | int status = 0; | 3684 | int status = 0; |
3629 | 3685 | ||
3630 | if (lvb->lvb_version == OCFS2_QINFO_LVB_VERSION) { | 3686 | if (ocfs2_dlm_lvb_valid(&lockres->l_lksb) && |
3687 | lvb->lvb_version == OCFS2_QINFO_LVB_VERSION) { | ||
3631 | info->dqi_bgrace = be32_to_cpu(lvb->lvb_bgrace); | 3688 | info->dqi_bgrace = be32_to_cpu(lvb->lvb_bgrace); |
3632 | info->dqi_igrace = be32_to_cpu(lvb->lvb_igrace); | 3689 | info->dqi_igrace = be32_to_cpu(lvb->lvb_igrace); |
3633 | oinfo->dqi_syncms = be32_to_cpu(lvb->lvb_syncms); | 3690 | oinfo->dqi_syncms = be32_to_cpu(lvb->lvb_syncms); |
diff --git a/fs/ocfs2/dlmglue.h b/fs/ocfs2/dlmglue.h index 31b90d7b8f51..7553836931de 100644 --- a/fs/ocfs2/dlmglue.h +++ b/fs/ocfs2/dlmglue.h | |||
@@ -78,6 +78,14 @@ struct ocfs2_orphan_scan_lvb { | |||
78 | /* don't block waiting for the downconvert thread, instead return -EAGAIN */ | 78 | /* don't block waiting for the downconvert thread, instead return -EAGAIN */ |
79 | #define OCFS2_LOCK_NONBLOCK (0x04) | 79 | #define OCFS2_LOCK_NONBLOCK (0x04) |
80 | 80 | ||
81 | /* Locking subclasses of inode cluster lock */ | ||
82 | enum { | ||
83 | OI_LS_NORMAL = 0, | ||
84 | OI_LS_PARENT, | ||
85 | OI_LS_RENAME1, | ||
86 | OI_LS_RENAME2, | ||
87 | }; | ||
88 | |||
81 | int ocfs2_dlm_init(struct ocfs2_super *osb); | 89 | int ocfs2_dlm_init(struct ocfs2_super *osb); |
82 | void ocfs2_dlm_shutdown(struct ocfs2_super *osb, int hangup_pending); | 90 | void ocfs2_dlm_shutdown(struct ocfs2_super *osb, int hangup_pending); |
83 | void ocfs2_lock_res_init_once(struct ocfs2_lock_res *res); | 91 | void ocfs2_lock_res_init_once(struct ocfs2_lock_res *res); |
@@ -104,25 +112,31 @@ void ocfs2_open_unlock(struct inode *inode); | |||
104 | int ocfs2_inode_lock_atime(struct inode *inode, | 112 | int ocfs2_inode_lock_atime(struct inode *inode, |
105 | struct vfsmount *vfsmnt, | 113 | struct vfsmount *vfsmnt, |
106 | int *level); | 114 | int *level); |
107 | int ocfs2_inode_lock_full(struct inode *inode, | 115 | int ocfs2_inode_lock_full_nested(struct inode *inode, |
108 | struct buffer_head **ret_bh, | 116 | struct buffer_head **ret_bh, |
109 | int ex, | 117 | int ex, |
110 | int arg_flags); | 118 | int arg_flags, |
119 | int subclass); | ||
111 | int ocfs2_inode_lock_with_page(struct inode *inode, | 120 | int ocfs2_inode_lock_with_page(struct inode *inode, |
112 | struct buffer_head **ret_bh, | 121 | struct buffer_head **ret_bh, |
113 | int ex, | 122 | int ex, |
114 | struct page *page); | 123 | struct page *page); |
124 | /* Variants without special locking class or flags */ | ||
125 | #define ocfs2_inode_lock_full(i, r, e, f)\ | ||
126 | ocfs2_inode_lock_full_nested(i, r, e, f, OI_LS_NORMAL) | ||
127 | #define ocfs2_inode_lock_nested(i, b, e, s)\ | ||
128 | ocfs2_inode_lock_full_nested(i, b, e, 0, s) | ||
115 | /* 99% of the time we don't want to supply any additional flags -- | 129 | /* 99% of the time we don't want to supply any additional flags -- |
116 | * those are for very specific cases only. */ | 130 | * those are for very specific cases only. */ |
117 | #define ocfs2_inode_lock(i, b, e) ocfs2_inode_lock_full(i, b, e, 0) | 131 | #define ocfs2_inode_lock(i, b, e) ocfs2_inode_lock_full_nested(i, b, e, 0, OI_LS_NORMAL) |
118 | void ocfs2_inode_unlock(struct inode *inode, | 132 | void ocfs2_inode_unlock(struct inode *inode, |
119 | int ex); | 133 | int ex); |
120 | int ocfs2_super_lock(struct ocfs2_super *osb, | 134 | int ocfs2_super_lock(struct ocfs2_super *osb, |
121 | int ex); | 135 | int ex); |
122 | void ocfs2_super_unlock(struct ocfs2_super *osb, | 136 | void ocfs2_super_unlock(struct ocfs2_super *osb, |
123 | int ex); | 137 | int ex); |
124 | int ocfs2_orphan_scan_lock(struct ocfs2_super *osb, u32 *seqno, int ex); | 138 | int ocfs2_orphan_scan_lock(struct ocfs2_super *osb, u32 *seqno); |
125 | void ocfs2_orphan_scan_unlock(struct ocfs2_super *osb, u32 seqno, int ex); | 139 | void ocfs2_orphan_scan_unlock(struct ocfs2_super *osb, u32 seqno); |
126 | 140 | ||
127 | int ocfs2_rename_lock(struct ocfs2_super *osb); | 141 | int ocfs2_rename_lock(struct ocfs2_super *osb); |
128 | void ocfs2_rename_unlock(struct ocfs2_super *osb); | 142 | void ocfs2_rename_unlock(struct ocfs2_super *osb); |
diff --git a/fs/ocfs2/file.c b/fs/ocfs2/file.c index 07267e0da909..62442e413a00 100644 --- a/fs/ocfs2/file.c +++ b/fs/ocfs2/file.c | |||
@@ -2026,7 +2026,7 @@ static ssize_t ocfs2_file_splice_read(struct file *in, | |||
2026 | size_t len, | 2026 | size_t len, |
2027 | unsigned int flags) | 2027 | unsigned int flags) |
2028 | { | 2028 | { |
2029 | int ret = 0; | 2029 | int ret = 0, lock_level = 0; |
2030 | struct inode *inode = in->f_path.dentry->d_inode; | 2030 | struct inode *inode = in->f_path.dentry->d_inode; |
2031 | 2031 | ||
2032 | mlog_entry("(0x%p, 0x%p, %u, '%.*s')\n", in, pipe, | 2032 | mlog_entry("(0x%p, 0x%p, %u, '%.*s')\n", in, pipe, |
@@ -2037,12 +2037,12 @@ static ssize_t ocfs2_file_splice_read(struct file *in, | |||
2037 | /* | 2037 | /* |
2038 | * See the comment in ocfs2_file_aio_read() | 2038 | * See the comment in ocfs2_file_aio_read() |
2039 | */ | 2039 | */ |
2040 | ret = ocfs2_inode_lock(inode, NULL, 0); | 2040 | ret = ocfs2_inode_lock_atime(inode, in->f_vfsmnt, &lock_level); |
2041 | if (ret < 0) { | 2041 | if (ret < 0) { |
2042 | mlog_errno(ret); | 2042 | mlog_errno(ret); |
2043 | goto bail; | 2043 | goto bail; |
2044 | } | 2044 | } |
2045 | ocfs2_inode_unlock(inode, 0); | 2045 | ocfs2_inode_unlock(inode, lock_level); |
2046 | 2046 | ||
2047 | ret = generic_file_splice_read(in, ppos, pipe, len, flags); | 2047 | ret = generic_file_splice_read(in, ppos, pipe, len, flags); |
2048 | 2048 | ||
diff --git a/fs/ocfs2/inode.c b/fs/ocfs2/inode.c index 10e1fa87396a..4dc8890ba316 100644 --- a/fs/ocfs2/inode.c +++ b/fs/ocfs2/inode.c | |||
@@ -215,6 +215,8 @@ bail: | |||
215 | static int ocfs2_init_locked_inode(struct inode *inode, void *opaque) | 215 | static int ocfs2_init_locked_inode(struct inode *inode, void *opaque) |
216 | { | 216 | { |
217 | struct ocfs2_find_inode_args *args = opaque; | 217 | struct ocfs2_find_inode_args *args = opaque; |
218 | static struct lock_class_key ocfs2_quota_ip_alloc_sem_key, | ||
219 | ocfs2_file_ip_alloc_sem_key; | ||
218 | 220 | ||
219 | mlog_entry("inode = %p, opaque = %p\n", inode, opaque); | 221 | mlog_entry("inode = %p, opaque = %p\n", inode, opaque); |
220 | 222 | ||
@@ -223,6 +225,15 @@ static int ocfs2_init_locked_inode(struct inode *inode, void *opaque) | |||
223 | if (args->fi_sysfile_type != 0) | 225 | if (args->fi_sysfile_type != 0) |
224 | lockdep_set_class(&inode->i_mutex, | 226 | lockdep_set_class(&inode->i_mutex, |
225 | &ocfs2_sysfile_lock_key[args->fi_sysfile_type]); | 227 | &ocfs2_sysfile_lock_key[args->fi_sysfile_type]); |
228 | if (args->fi_sysfile_type == USER_QUOTA_SYSTEM_INODE || | ||
229 | args->fi_sysfile_type == GROUP_QUOTA_SYSTEM_INODE || | ||
230 | args->fi_sysfile_type == LOCAL_USER_QUOTA_SYSTEM_INODE || | ||
231 | args->fi_sysfile_type == LOCAL_GROUP_QUOTA_SYSTEM_INODE) | ||
232 | lockdep_set_class(&OCFS2_I(inode)->ip_alloc_sem, | ||
233 | &ocfs2_quota_ip_alloc_sem_key); | ||
234 | else | ||
235 | lockdep_set_class(&OCFS2_I(inode)->ip_alloc_sem, | ||
236 | &ocfs2_file_ip_alloc_sem_key); | ||
226 | 237 | ||
227 | mlog_exit(0); | 238 | mlog_exit(0); |
228 | return 0; | 239 | return 0; |
diff --git a/fs/ocfs2/journal.c b/fs/ocfs2/journal.c index 4a3b9e6b31ad..f033760ecbea 100644 --- a/fs/ocfs2/journal.c +++ b/fs/ocfs2/journal.c | |||
@@ -1880,13 +1880,20 @@ void ocfs2_queue_orphan_scan(struct ocfs2_super *osb) | |||
1880 | 1880 | ||
1881 | os = &osb->osb_orphan_scan; | 1881 | os = &osb->osb_orphan_scan; |
1882 | 1882 | ||
1883 | status = ocfs2_orphan_scan_lock(osb, &seqno, DLM_LOCK_EX); | 1883 | if (atomic_read(&os->os_state) == ORPHAN_SCAN_INACTIVE) |
1884 | goto out; | ||
1885 | |||
1886 | status = ocfs2_orphan_scan_lock(osb, &seqno); | ||
1884 | if (status < 0) { | 1887 | if (status < 0) { |
1885 | if (status != -EAGAIN) | 1888 | if (status != -EAGAIN) |
1886 | mlog_errno(status); | 1889 | mlog_errno(status); |
1887 | goto out; | 1890 | goto out; |
1888 | } | 1891 | } |
1889 | 1892 | ||
1893 | /* Do no queue the tasks if the volume is being umounted */ | ||
1894 | if (atomic_read(&os->os_state) == ORPHAN_SCAN_INACTIVE) | ||
1895 | goto unlock; | ||
1896 | |||
1890 | if (os->os_seqno != seqno) { | 1897 | if (os->os_seqno != seqno) { |
1891 | os->os_seqno = seqno; | 1898 | os->os_seqno = seqno; |
1892 | goto unlock; | 1899 | goto unlock; |
@@ -1903,7 +1910,7 @@ void ocfs2_queue_orphan_scan(struct ocfs2_super *osb) | |||
1903 | os->os_count++; | 1910 | os->os_count++; |
1904 | os->os_scantime = CURRENT_TIME; | 1911 | os->os_scantime = CURRENT_TIME; |
1905 | unlock: | 1912 | unlock: |
1906 | ocfs2_orphan_scan_unlock(osb, seqno, DLM_LOCK_EX); | 1913 | ocfs2_orphan_scan_unlock(osb, seqno); |
1907 | out: | 1914 | out: |
1908 | return; | 1915 | return; |
1909 | } | 1916 | } |
@@ -1920,8 +1927,9 @@ void ocfs2_orphan_scan_work(struct work_struct *work) | |||
1920 | 1927 | ||
1921 | mutex_lock(&os->os_lock); | 1928 | mutex_lock(&os->os_lock); |
1922 | ocfs2_queue_orphan_scan(osb); | 1929 | ocfs2_queue_orphan_scan(osb); |
1923 | schedule_delayed_work(&os->os_orphan_scan_work, | 1930 | if (atomic_read(&os->os_state) == ORPHAN_SCAN_ACTIVE) |
1924 | ocfs2_orphan_scan_timeout()); | 1931 | schedule_delayed_work(&os->os_orphan_scan_work, |
1932 | ocfs2_orphan_scan_timeout()); | ||
1925 | mutex_unlock(&os->os_lock); | 1933 | mutex_unlock(&os->os_lock); |
1926 | } | 1934 | } |
1927 | 1935 | ||
@@ -1930,26 +1938,33 @@ void ocfs2_orphan_scan_stop(struct ocfs2_super *osb) | |||
1930 | struct ocfs2_orphan_scan *os; | 1938 | struct ocfs2_orphan_scan *os; |
1931 | 1939 | ||
1932 | os = &osb->osb_orphan_scan; | 1940 | os = &osb->osb_orphan_scan; |
1933 | mutex_lock(&os->os_lock); | 1941 | if (atomic_read(&os->os_state) == ORPHAN_SCAN_ACTIVE) { |
1934 | cancel_delayed_work(&os->os_orphan_scan_work); | 1942 | atomic_set(&os->os_state, ORPHAN_SCAN_INACTIVE); |
1935 | mutex_unlock(&os->os_lock); | 1943 | mutex_lock(&os->os_lock); |
1944 | cancel_delayed_work(&os->os_orphan_scan_work); | ||
1945 | mutex_unlock(&os->os_lock); | ||
1946 | } | ||
1936 | } | 1947 | } |
1937 | 1948 | ||
1938 | int ocfs2_orphan_scan_init(struct ocfs2_super *osb) | 1949 | void ocfs2_orphan_scan_init(struct ocfs2_super *osb) |
1939 | { | 1950 | { |
1940 | struct ocfs2_orphan_scan *os; | 1951 | struct ocfs2_orphan_scan *os; |
1941 | 1952 | ||
1942 | os = &osb->osb_orphan_scan; | 1953 | os = &osb->osb_orphan_scan; |
1943 | os->os_osb = osb; | 1954 | os->os_osb = osb; |
1944 | os->os_count = 0; | 1955 | os->os_count = 0; |
1956 | os->os_seqno = 0; | ||
1945 | os->os_scantime = CURRENT_TIME; | 1957 | os->os_scantime = CURRENT_TIME; |
1946 | mutex_init(&os->os_lock); | 1958 | mutex_init(&os->os_lock); |
1947 | 1959 | INIT_DELAYED_WORK(&os->os_orphan_scan_work, ocfs2_orphan_scan_work); | |
1948 | INIT_DELAYED_WORK(&os->os_orphan_scan_work, | 1960 | |
1949 | ocfs2_orphan_scan_work); | 1961 | if (ocfs2_is_hard_readonly(osb) || ocfs2_mount_local(osb)) |
1950 | schedule_delayed_work(&os->os_orphan_scan_work, | 1962 | atomic_set(&os->os_state, ORPHAN_SCAN_INACTIVE); |
1951 | ocfs2_orphan_scan_timeout()); | 1963 | else { |
1952 | return 0; | 1964 | atomic_set(&os->os_state, ORPHAN_SCAN_ACTIVE); |
1965 | schedule_delayed_work(&os->os_orphan_scan_work, | ||
1966 | ocfs2_orphan_scan_timeout()); | ||
1967 | } | ||
1953 | } | 1968 | } |
1954 | 1969 | ||
1955 | struct ocfs2_orphan_filldir_priv { | 1970 | struct ocfs2_orphan_filldir_priv { |
diff --git a/fs/ocfs2/journal.h b/fs/ocfs2/journal.h index 61045eeb3f6e..5432c7f79cc6 100644 --- a/fs/ocfs2/journal.h +++ b/fs/ocfs2/journal.h | |||
@@ -144,7 +144,7 @@ static inline void ocfs2_inode_set_new(struct ocfs2_super *osb, | |||
144 | } | 144 | } |
145 | 145 | ||
146 | /* Exported only for the journal struct init code in super.c. Do not call. */ | 146 | /* Exported only for the journal struct init code in super.c. Do not call. */ |
147 | int ocfs2_orphan_scan_init(struct ocfs2_super *osb); | 147 | void ocfs2_orphan_scan_init(struct ocfs2_super *osb); |
148 | void ocfs2_orphan_scan_stop(struct ocfs2_super *osb); | 148 | void ocfs2_orphan_scan_stop(struct ocfs2_super *osb); |
149 | void ocfs2_orphan_scan_exit(struct ocfs2_super *osb); | 149 | void ocfs2_orphan_scan_exit(struct ocfs2_super *osb); |
150 | 150 | ||
diff --git a/fs/ocfs2/namei.c b/fs/ocfs2/namei.c index 33464c6b60a2..8601f934010b 100644 --- a/fs/ocfs2/namei.c +++ b/fs/ocfs2/namei.c | |||
@@ -118,7 +118,7 @@ static struct dentry *ocfs2_lookup(struct inode *dir, struct dentry *dentry, | |||
118 | mlog(0, "find name %.*s in directory %llu\n", dentry->d_name.len, | 118 | mlog(0, "find name %.*s in directory %llu\n", dentry->d_name.len, |
119 | dentry->d_name.name, (unsigned long long)OCFS2_I(dir)->ip_blkno); | 119 | dentry->d_name.name, (unsigned long long)OCFS2_I(dir)->ip_blkno); |
120 | 120 | ||
121 | status = ocfs2_inode_lock(dir, NULL, 0); | 121 | status = ocfs2_inode_lock_nested(dir, NULL, 0, OI_LS_PARENT); |
122 | if (status < 0) { | 122 | if (status < 0) { |
123 | if (status != -ENOENT) | 123 | if (status != -ENOENT) |
124 | mlog_errno(status); | 124 | mlog_errno(status); |
@@ -636,7 +636,7 @@ static int ocfs2_link(struct dentry *old_dentry, | |||
636 | if (S_ISDIR(inode->i_mode)) | 636 | if (S_ISDIR(inode->i_mode)) |
637 | return -EPERM; | 637 | return -EPERM; |
638 | 638 | ||
639 | err = ocfs2_inode_lock(dir, &parent_fe_bh, 1); | 639 | err = ocfs2_inode_lock_nested(dir, &parent_fe_bh, 1, OI_LS_PARENT); |
640 | if (err < 0) { | 640 | if (err < 0) { |
641 | if (err != -ENOENT) | 641 | if (err != -ENOENT) |
642 | mlog_errno(err); | 642 | mlog_errno(err); |
@@ -800,7 +800,8 @@ static int ocfs2_unlink(struct inode *dir, | |||
800 | return -EPERM; | 800 | return -EPERM; |
801 | } | 801 | } |
802 | 802 | ||
803 | status = ocfs2_inode_lock(dir, &parent_node_bh, 1); | 803 | status = ocfs2_inode_lock_nested(dir, &parent_node_bh, 1, |
804 | OI_LS_PARENT); | ||
804 | if (status < 0) { | 805 | if (status < 0) { |
805 | if (status != -ENOENT) | 806 | if (status != -ENOENT) |
806 | mlog_errno(status); | 807 | mlog_errno(status); |
@@ -978,7 +979,8 @@ static int ocfs2_double_lock(struct ocfs2_super *osb, | |||
978 | inode1 = tmpinode; | 979 | inode1 = tmpinode; |
979 | } | 980 | } |
980 | /* lock id2 */ | 981 | /* lock id2 */ |
981 | status = ocfs2_inode_lock(inode2, bh2, 1); | 982 | status = ocfs2_inode_lock_nested(inode2, bh2, 1, |
983 | OI_LS_RENAME1); | ||
982 | if (status < 0) { | 984 | if (status < 0) { |
983 | if (status != -ENOENT) | 985 | if (status != -ENOENT) |
984 | mlog_errno(status); | 986 | mlog_errno(status); |
@@ -987,7 +989,7 @@ static int ocfs2_double_lock(struct ocfs2_super *osb, | |||
987 | } | 989 | } |
988 | 990 | ||
989 | /* lock id1 */ | 991 | /* lock id1 */ |
990 | status = ocfs2_inode_lock(inode1, bh1, 1); | 992 | status = ocfs2_inode_lock_nested(inode1, bh1, 1, OI_LS_RENAME2); |
991 | if (status < 0) { | 993 | if (status < 0) { |
992 | /* | 994 | /* |
993 | * An error return must mean that no cluster locks | 995 | * An error return must mean that no cluster locks |
@@ -1103,7 +1105,8 @@ static int ocfs2_rename(struct inode *old_dir, | |||
1103 | * won't have to concurrently downconvert the inode and the | 1105 | * won't have to concurrently downconvert the inode and the |
1104 | * dentry locks. | 1106 | * dentry locks. |
1105 | */ | 1107 | */ |
1106 | status = ocfs2_inode_lock(old_inode, &old_inode_bh, 1); | 1108 | status = ocfs2_inode_lock_nested(old_inode, &old_inode_bh, 1, |
1109 | OI_LS_PARENT); | ||
1107 | if (status < 0) { | 1110 | if (status < 0) { |
1108 | if (status != -ENOENT) | 1111 | if (status != -ENOENT) |
1109 | mlog_errno(status); | 1112 | mlog_errno(status); |
diff --git a/fs/ocfs2/ocfs2.h b/fs/ocfs2/ocfs2.h index 18c1d9ec1c93..c9345ebb8493 100644 --- a/fs/ocfs2/ocfs2.h +++ b/fs/ocfs2/ocfs2.h | |||
@@ -34,6 +34,7 @@ | |||
34 | #include <linux/workqueue.h> | 34 | #include <linux/workqueue.h> |
35 | #include <linux/kref.h> | 35 | #include <linux/kref.h> |
36 | #include <linux/mutex.h> | 36 | #include <linux/mutex.h> |
37 | #include <linux/lockdep.h> | ||
37 | #ifndef CONFIG_OCFS2_COMPAT_JBD | 38 | #ifndef CONFIG_OCFS2_COMPAT_JBD |
38 | # include <linux/jbd2.h> | 39 | # include <linux/jbd2.h> |
39 | #else | 40 | #else |
@@ -152,6 +153,14 @@ struct ocfs2_lock_res { | |||
152 | unsigned int l_lock_max_exmode; /* Max wait for EX */ | 153 | unsigned int l_lock_max_exmode; /* Max wait for EX */ |
153 | unsigned int l_lock_refresh; /* Disk refreshes */ | 154 | unsigned int l_lock_refresh; /* Disk refreshes */ |
154 | #endif | 155 | #endif |
156 | #ifdef CONFIG_DEBUG_LOCK_ALLOC | ||
157 | struct lockdep_map l_lockdep_map; | ||
158 | #endif | ||
159 | }; | ||
160 | |||
161 | enum ocfs2_orphan_scan_state { | ||
162 | ORPHAN_SCAN_ACTIVE, | ||
163 | ORPHAN_SCAN_INACTIVE | ||
155 | }; | 164 | }; |
156 | 165 | ||
157 | struct ocfs2_orphan_scan { | 166 | struct ocfs2_orphan_scan { |
@@ -162,6 +171,7 @@ struct ocfs2_orphan_scan { | |||
162 | struct timespec os_scantime; /* time this node ran the scan */ | 171 | struct timespec os_scantime; /* time this node ran the scan */ |
163 | u32 os_count; /* tracks node specific scans */ | 172 | u32 os_count; /* tracks node specific scans */ |
164 | u32 os_seqno; /* tracks cluster wide scans */ | 173 | u32 os_seqno; /* tracks cluster wide scans */ |
174 | atomic_t os_state; /* ACTIVE or INACTIVE */ | ||
165 | }; | 175 | }; |
166 | 176 | ||
167 | struct ocfs2_dlm_debug { | 177 | struct ocfs2_dlm_debug { |
diff --git a/fs/ocfs2/stack_o2cb.c b/fs/ocfs2/stack_o2cb.c index fcd120f1493a..3f661376a2de 100644 --- a/fs/ocfs2/stack_o2cb.c +++ b/fs/ocfs2/stack_o2cb.c | |||
@@ -236,6 +236,16 @@ static int o2cb_dlm_lock_status(union ocfs2_dlm_lksb *lksb) | |||
236 | return dlm_status_to_errno(lksb->lksb_o2dlm.status); | 236 | return dlm_status_to_errno(lksb->lksb_o2dlm.status); |
237 | } | 237 | } |
238 | 238 | ||
239 | /* | ||
240 | * o2dlm aways has a "valid" LVB. If the dlm loses track of the LVB | ||
241 | * contents, it will zero out the LVB. Thus the caller can always trust | ||
242 | * the contents. | ||
243 | */ | ||
244 | static int o2cb_dlm_lvb_valid(union ocfs2_dlm_lksb *lksb) | ||
245 | { | ||
246 | return 1; | ||
247 | } | ||
248 | |||
239 | static void *o2cb_dlm_lvb(union ocfs2_dlm_lksb *lksb) | 249 | static void *o2cb_dlm_lvb(union ocfs2_dlm_lksb *lksb) |
240 | { | 250 | { |
241 | return (void *)(lksb->lksb_o2dlm.lvb); | 251 | return (void *)(lksb->lksb_o2dlm.lvb); |
@@ -354,6 +364,7 @@ static struct ocfs2_stack_operations o2cb_stack_ops = { | |||
354 | .dlm_lock = o2cb_dlm_lock, | 364 | .dlm_lock = o2cb_dlm_lock, |
355 | .dlm_unlock = o2cb_dlm_unlock, | 365 | .dlm_unlock = o2cb_dlm_unlock, |
356 | .lock_status = o2cb_dlm_lock_status, | 366 | .lock_status = o2cb_dlm_lock_status, |
367 | .lvb_valid = o2cb_dlm_lvb_valid, | ||
357 | .lock_lvb = o2cb_dlm_lvb, | 368 | .lock_lvb = o2cb_dlm_lvb, |
358 | .dump_lksb = o2cb_dump_lksb, | 369 | .dump_lksb = o2cb_dump_lksb, |
359 | }; | 370 | }; |
diff --git a/fs/ocfs2/stack_user.c b/fs/ocfs2/stack_user.c index 9b76d41a8ac6..ff4c798a5635 100644 --- a/fs/ocfs2/stack_user.c +++ b/fs/ocfs2/stack_user.c | |||
@@ -738,6 +738,13 @@ static int user_dlm_lock_status(union ocfs2_dlm_lksb *lksb) | |||
738 | return lksb->lksb_fsdlm.sb_status; | 738 | return lksb->lksb_fsdlm.sb_status; |
739 | } | 739 | } |
740 | 740 | ||
741 | static int user_dlm_lvb_valid(union ocfs2_dlm_lksb *lksb) | ||
742 | { | ||
743 | int invalid = lksb->lksb_fsdlm.sb_flags & DLM_SBF_VALNOTVALID; | ||
744 | |||
745 | return !invalid; | ||
746 | } | ||
747 | |||
741 | static void *user_dlm_lvb(union ocfs2_dlm_lksb *lksb) | 748 | static void *user_dlm_lvb(union ocfs2_dlm_lksb *lksb) |
742 | { | 749 | { |
743 | if (!lksb->lksb_fsdlm.sb_lvbptr) | 750 | if (!lksb->lksb_fsdlm.sb_lvbptr) |
@@ -873,6 +880,7 @@ static struct ocfs2_stack_operations ocfs2_user_plugin_ops = { | |||
873 | .dlm_lock = user_dlm_lock, | 880 | .dlm_lock = user_dlm_lock, |
874 | .dlm_unlock = user_dlm_unlock, | 881 | .dlm_unlock = user_dlm_unlock, |
875 | .lock_status = user_dlm_lock_status, | 882 | .lock_status = user_dlm_lock_status, |
883 | .lvb_valid = user_dlm_lvb_valid, | ||
876 | .lock_lvb = user_dlm_lvb, | 884 | .lock_lvb = user_dlm_lvb, |
877 | .plock = user_plock, | 885 | .plock = user_plock, |
878 | .dump_lksb = user_dlm_dump_lksb, | 886 | .dump_lksb = user_dlm_dump_lksb, |
diff --git a/fs/ocfs2/stackglue.c b/fs/ocfs2/stackglue.c index 68b668b0e60a..3f2f1c45b7b6 100644 --- a/fs/ocfs2/stackglue.c +++ b/fs/ocfs2/stackglue.c | |||
@@ -6,7 +6,7 @@ | |||
6 | * Code which implements an OCFS2 specific interface to underlying | 6 | * Code which implements an OCFS2 specific interface to underlying |
7 | * cluster stacks. | 7 | * cluster stacks. |
8 | * | 8 | * |
9 | * Copyright (C) 2007 Oracle. All rights reserved. | 9 | * Copyright (C) 2007, 2009 Oracle. All rights reserved. |
10 | * | 10 | * |
11 | * This program is free software; you can redistribute it and/or | 11 | * This program is free software; you can redistribute it and/or |
12 | * modify it under the terms of the GNU General Public | 12 | * modify it under the terms of the GNU General Public |
@@ -271,11 +271,12 @@ int ocfs2_dlm_lock_status(union ocfs2_dlm_lksb *lksb) | |||
271 | } | 271 | } |
272 | EXPORT_SYMBOL_GPL(ocfs2_dlm_lock_status); | 272 | EXPORT_SYMBOL_GPL(ocfs2_dlm_lock_status); |
273 | 273 | ||
274 | /* | 274 | int ocfs2_dlm_lvb_valid(union ocfs2_dlm_lksb *lksb) |
275 | * Why don't we cast to ocfs2_meta_lvb? The "clean" answer is that we | 275 | { |
276 | * don't cast at the glue level. The real answer is that the header | 276 | return active_stack->sp_ops->lvb_valid(lksb); |
277 | * ordering is nigh impossible. | 277 | } |
278 | */ | 278 | EXPORT_SYMBOL_GPL(ocfs2_dlm_lvb_valid); |
279 | |||
279 | void *ocfs2_dlm_lvb(union ocfs2_dlm_lksb *lksb) | 280 | void *ocfs2_dlm_lvb(union ocfs2_dlm_lksb *lksb) |
280 | { | 281 | { |
281 | return active_stack->sp_ops->lock_lvb(lksb); | 282 | return active_stack->sp_ops->lock_lvb(lksb); |
diff --git a/fs/ocfs2/stackglue.h b/fs/ocfs2/stackglue.h index c571af375ef8..03a44d60eac9 100644 --- a/fs/ocfs2/stackglue.h +++ b/fs/ocfs2/stackglue.h | |||
@@ -186,6 +186,11 @@ struct ocfs2_stack_operations { | |||
186 | int (*lock_status)(union ocfs2_dlm_lksb *lksb); | 186 | int (*lock_status)(union ocfs2_dlm_lksb *lksb); |
187 | 187 | ||
188 | /* | 188 | /* |
189 | * Return non-zero if the LVB is valid. | ||
190 | */ | ||
191 | int (*lvb_valid)(union ocfs2_dlm_lksb *lksb); | ||
192 | |||
193 | /* | ||
189 | * Pull the lvb pointer off of the stack-specific lksb. | 194 | * Pull the lvb pointer off of the stack-specific lksb. |
190 | */ | 195 | */ |
191 | void *(*lock_lvb)(union ocfs2_dlm_lksb *lksb); | 196 | void *(*lock_lvb)(union ocfs2_dlm_lksb *lksb); |
@@ -252,6 +257,7 @@ int ocfs2_dlm_unlock(struct ocfs2_cluster_connection *conn, | |||
252 | struct ocfs2_lock_res *astarg); | 257 | struct ocfs2_lock_res *astarg); |
253 | 258 | ||
254 | int ocfs2_dlm_lock_status(union ocfs2_dlm_lksb *lksb); | 259 | int ocfs2_dlm_lock_status(union ocfs2_dlm_lksb *lksb); |
260 | int ocfs2_dlm_lvb_valid(union ocfs2_dlm_lksb *lksb); | ||
255 | void *ocfs2_dlm_lvb(union ocfs2_dlm_lksb *lksb); | 261 | void *ocfs2_dlm_lvb(union ocfs2_dlm_lksb *lksb); |
256 | void ocfs2_dlm_dump_lksb(union ocfs2_dlm_lksb *lksb); | 262 | void ocfs2_dlm_dump_lksb(union ocfs2_dlm_lksb *lksb); |
257 | 263 | ||
diff --git a/fs/ocfs2/suballoc.c b/fs/ocfs2/suballoc.c index 8439f6b324b9..73a16d4666dc 100644 --- a/fs/ocfs2/suballoc.c +++ b/fs/ocfs2/suballoc.c | |||
@@ -923,14 +923,23 @@ static int ocfs2_test_bg_bit_allocatable(struct buffer_head *bg_bh, | |||
923 | int nr) | 923 | int nr) |
924 | { | 924 | { |
925 | struct ocfs2_group_desc *bg = (struct ocfs2_group_desc *) bg_bh->b_data; | 925 | struct ocfs2_group_desc *bg = (struct ocfs2_group_desc *) bg_bh->b_data; |
926 | int ret; | ||
926 | 927 | ||
927 | if (ocfs2_test_bit(nr, (unsigned long *)bg->bg_bitmap)) | 928 | if (ocfs2_test_bit(nr, (unsigned long *)bg->bg_bitmap)) |
928 | return 0; | 929 | return 0; |
929 | if (!buffer_jbd(bg_bh) || !bh2jh(bg_bh)->b_committed_data) | 930 | |
931 | if (!buffer_jbd(bg_bh)) | ||
930 | return 1; | 932 | return 1; |
931 | 933 | ||
934 | jbd_lock_bh_state(bg_bh); | ||
932 | bg = (struct ocfs2_group_desc *) bh2jh(bg_bh)->b_committed_data; | 935 | bg = (struct ocfs2_group_desc *) bh2jh(bg_bh)->b_committed_data; |
933 | return !ocfs2_test_bit(nr, (unsigned long *)bg->bg_bitmap); | 936 | if (bg) |
937 | ret = !ocfs2_test_bit(nr, (unsigned long *)bg->bg_bitmap); | ||
938 | else | ||
939 | ret = 1; | ||
940 | jbd_unlock_bh_state(bg_bh); | ||
941 | |||
942 | return ret; | ||
934 | } | 943 | } |
935 | 944 | ||
936 | static int ocfs2_block_group_find_clear_bits(struct ocfs2_super *osb, | 945 | static int ocfs2_block_group_find_clear_bits(struct ocfs2_super *osb, |
@@ -1885,6 +1894,7 @@ static inline int ocfs2_block_group_clear_bits(handle_t *handle, | |||
1885 | unsigned int tmp; | 1894 | unsigned int tmp; |
1886 | int journal_type = OCFS2_JOURNAL_ACCESS_WRITE; | 1895 | int journal_type = OCFS2_JOURNAL_ACCESS_WRITE; |
1887 | struct ocfs2_group_desc *undo_bg = NULL; | 1896 | struct ocfs2_group_desc *undo_bg = NULL; |
1897 | int cluster_bitmap = 0; | ||
1888 | 1898 | ||
1889 | mlog_entry_void(); | 1899 | mlog_entry_void(); |
1890 | 1900 | ||
@@ -1905,18 +1915,28 @@ static inline int ocfs2_block_group_clear_bits(handle_t *handle, | |||
1905 | } | 1915 | } |
1906 | 1916 | ||
1907 | if (ocfs2_is_cluster_bitmap(alloc_inode)) | 1917 | if (ocfs2_is_cluster_bitmap(alloc_inode)) |
1908 | undo_bg = (struct ocfs2_group_desc *) bh2jh(group_bh)->b_committed_data; | 1918 | cluster_bitmap = 1; |
1919 | |||
1920 | if (cluster_bitmap) { | ||
1921 | jbd_lock_bh_state(group_bh); | ||
1922 | undo_bg = (struct ocfs2_group_desc *) | ||
1923 | bh2jh(group_bh)->b_committed_data; | ||
1924 | BUG_ON(!undo_bg); | ||
1925 | } | ||
1909 | 1926 | ||
1910 | tmp = num_bits; | 1927 | tmp = num_bits; |
1911 | while(tmp--) { | 1928 | while(tmp--) { |
1912 | ocfs2_clear_bit((bit_off + tmp), | 1929 | ocfs2_clear_bit((bit_off + tmp), |
1913 | (unsigned long *) bg->bg_bitmap); | 1930 | (unsigned long *) bg->bg_bitmap); |
1914 | if (ocfs2_is_cluster_bitmap(alloc_inode)) | 1931 | if (cluster_bitmap) |
1915 | ocfs2_set_bit(bit_off + tmp, | 1932 | ocfs2_set_bit(bit_off + tmp, |
1916 | (unsigned long *) undo_bg->bg_bitmap); | 1933 | (unsigned long *) undo_bg->bg_bitmap); |
1917 | } | 1934 | } |
1918 | le16_add_cpu(&bg->bg_free_bits_count, num_bits); | 1935 | le16_add_cpu(&bg->bg_free_bits_count, num_bits); |
1919 | 1936 | ||
1937 | if (cluster_bitmap) | ||
1938 | jbd_unlock_bh_state(group_bh); | ||
1939 | |||
1920 | status = ocfs2_journal_dirty(handle, group_bh); | 1940 | status = ocfs2_journal_dirty(handle, group_bh); |
1921 | if (status < 0) | 1941 | if (status < 0) |
1922 | mlog_errno(status); | 1942 | mlog_errno(status); |
diff --git a/fs/ocfs2/super.c b/fs/ocfs2/super.c index d33767f17ba3..7efb349fb9bd 100644 --- a/fs/ocfs2/super.c +++ b/fs/ocfs2/super.c | |||
@@ -205,11 +205,10 @@ static const match_table_t tokens = { | |||
205 | #ifdef CONFIG_DEBUG_FS | 205 | #ifdef CONFIG_DEBUG_FS |
206 | static int ocfs2_osb_dump(struct ocfs2_super *osb, char *buf, int len) | 206 | static int ocfs2_osb_dump(struct ocfs2_super *osb, char *buf, int len) |
207 | { | 207 | { |
208 | int out = 0; | ||
209 | int i; | ||
210 | struct ocfs2_cluster_connection *cconn = osb->cconn; | 208 | struct ocfs2_cluster_connection *cconn = osb->cconn; |
211 | struct ocfs2_recovery_map *rm = osb->recovery_map; | 209 | struct ocfs2_recovery_map *rm = osb->recovery_map; |
212 | struct ocfs2_orphan_scan *os; | 210 | struct ocfs2_orphan_scan *os = &osb->osb_orphan_scan; |
211 | int i, out = 0; | ||
213 | 212 | ||
214 | out += snprintf(buf + out, len - out, | 213 | out += snprintf(buf + out, len - out, |
215 | "%10s => Id: %-s Uuid: %-s Gen: 0x%X Label: %-s\n", | 214 | "%10s => Id: %-s Uuid: %-s Gen: 0x%X Label: %-s\n", |
@@ -234,20 +233,24 @@ static int ocfs2_osb_dump(struct ocfs2_super *osb, char *buf, int len) | |||
234 | "%10s => Opts: 0x%lX AtimeQuanta: %u\n", "Mount", | 233 | "%10s => Opts: 0x%lX AtimeQuanta: %u\n", "Mount", |
235 | osb->s_mount_opt, osb->s_atime_quantum); | 234 | osb->s_mount_opt, osb->s_atime_quantum); |
236 | 235 | ||
237 | out += snprintf(buf + out, len - out, | 236 | if (cconn) { |
238 | "%10s => Stack: %s Name: %*s Version: %d.%d\n", | 237 | out += snprintf(buf + out, len - out, |
239 | "Cluster", | 238 | "%10s => Stack: %s Name: %*s " |
240 | (*osb->osb_cluster_stack == '\0' ? | 239 | "Version: %d.%d\n", "Cluster", |
241 | "o2cb" : osb->osb_cluster_stack), | 240 | (*osb->osb_cluster_stack == '\0' ? |
242 | cconn->cc_namelen, cconn->cc_name, | 241 | "o2cb" : osb->osb_cluster_stack), |
243 | cconn->cc_version.pv_major, cconn->cc_version.pv_minor); | 242 | cconn->cc_namelen, cconn->cc_name, |
243 | cconn->cc_version.pv_major, | ||
244 | cconn->cc_version.pv_minor); | ||
245 | } | ||
244 | 246 | ||
245 | spin_lock(&osb->dc_task_lock); | 247 | spin_lock(&osb->dc_task_lock); |
246 | out += snprintf(buf + out, len - out, | 248 | out += snprintf(buf + out, len - out, |
247 | "%10s => Pid: %d Count: %lu WakeSeq: %lu " | 249 | "%10s => Pid: %d Count: %lu WakeSeq: %lu " |
248 | "WorkSeq: %lu\n", "DownCnvt", | 250 | "WorkSeq: %lu\n", "DownCnvt", |
249 | task_pid_nr(osb->dc_task), osb->blocked_lock_count, | 251 | (osb->dc_task ? task_pid_nr(osb->dc_task) : -1), |
250 | osb->dc_wake_sequence, osb->dc_work_sequence); | 252 | osb->blocked_lock_count, osb->dc_wake_sequence, |
253 | osb->dc_work_sequence); | ||
251 | spin_unlock(&osb->dc_task_lock); | 254 | spin_unlock(&osb->dc_task_lock); |
252 | 255 | ||
253 | spin_lock(&osb->osb_lock); | 256 | spin_lock(&osb->osb_lock); |
@@ -267,14 +270,15 @@ static int ocfs2_osb_dump(struct ocfs2_super *osb, char *buf, int len) | |||
267 | 270 | ||
268 | out += snprintf(buf + out, len - out, | 271 | out += snprintf(buf + out, len - out, |
269 | "%10s => Pid: %d Interval: %lu Needs: %d\n", "Commit", | 272 | "%10s => Pid: %d Interval: %lu Needs: %d\n", "Commit", |
270 | task_pid_nr(osb->commit_task), osb->osb_commit_interval, | 273 | (osb->commit_task ? task_pid_nr(osb->commit_task) : -1), |
274 | osb->osb_commit_interval, | ||
271 | atomic_read(&osb->needs_checkpoint)); | 275 | atomic_read(&osb->needs_checkpoint)); |
272 | 276 | ||
273 | out += snprintf(buf + out, len - out, | 277 | out += snprintf(buf + out, len - out, |
274 | "%10s => State: %d NumTxns: %d TxnId: %lu\n", | 278 | "%10s => State: %d TxnId: %lu NumTxns: %d\n", |
275 | "Journal", osb->journal->j_state, | 279 | "Journal", osb->journal->j_state, |
276 | atomic_read(&osb->journal->j_num_trans), | 280 | osb->journal->j_trans_id, |
277 | osb->journal->j_trans_id); | 281 | atomic_read(&osb->journal->j_num_trans)); |
278 | 282 | ||
279 | out += snprintf(buf + out, len - out, | 283 | out += snprintf(buf + out, len - out, |
280 | "%10s => GlobalAllocs: %d LocalAllocs: %d " | 284 | "%10s => GlobalAllocs: %d LocalAllocs: %d " |
@@ -300,9 +304,18 @@ static int ocfs2_osb_dump(struct ocfs2_super *osb, char *buf, int len) | |||
300 | atomic_read(&osb->s_num_inodes_stolen)); | 304 | atomic_read(&osb->s_num_inodes_stolen)); |
301 | spin_unlock(&osb->osb_lock); | 305 | spin_unlock(&osb->osb_lock); |
302 | 306 | ||
307 | out += snprintf(buf + out, len - out, "OrphanScan => "); | ||
308 | out += snprintf(buf + out, len - out, "Local: %u Global: %u ", | ||
309 | os->os_count, os->os_seqno); | ||
310 | out += snprintf(buf + out, len - out, " Last Scan: "); | ||
311 | if (atomic_read(&os->os_state) == ORPHAN_SCAN_INACTIVE) | ||
312 | out += snprintf(buf + out, len - out, "Disabled\n"); | ||
313 | else | ||
314 | out += snprintf(buf + out, len - out, "%lu seconds ago\n", | ||
315 | (get_seconds() - os->os_scantime.tv_sec)); | ||
316 | |||
303 | out += snprintf(buf + out, len - out, "%10s => %3s %10s\n", | 317 | out += snprintf(buf + out, len - out, "%10s => %3s %10s\n", |
304 | "Slots", "Num", "RecoGen"); | 318 | "Slots", "Num", "RecoGen"); |
305 | |||
306 | for (i = 0; i < osb->max_slots; ++i) { | 319 | for (i = 0; i < osb->max_slots; ++i) { |
307 | out += snprintf(buf + out, len - out, | 320 | out += snprintf(buf + out, len - out, |
308 | "%10s %c %3d %10d\n", | 321 | "%10s %c %3d %10d\n", |
@@ -311,13 +324,6 @@ static int ocfs2_osb_dump(struct ocfs2_super *osb, char *buf, int len) | |||
311 | i, osb->slot_recovery_generations[i]); | 324 | i, osb->slot_recovery_generations[i]); |
312 | } | 325 | } |
313 | 326 | ||
314 | os = &osb->osb_orphan_scan; | ||
315 | out += snprintf(buf + out, len - out, "Orphan Scan=> "); | ||
316 | out += snprintf(buf + out, len - out, "Local: %u Global: %u ", | ||
317 | os->os_count, os->os_seqno); | ||
318 | out += snprintf(buf + out, len - out, " Last Scan: %lu seconds ago\n", | ||
319 | (get_seconds() - os->os_scantime.tv_sec)); | ||
320 | |||
321 | return out; | 327 | return out; |
322 | } | 328 | } |
323 | 329 | ||
@@ -552,7 +558,7 @@ static unsigned long long ocfs2_max_file_offset(unsigned int bbits, | |||
552 | */ | 558 | */ |
553 | 559 | ||
554 | #if BITS_PER_LONG == 32 | 560 | #if BITS_PER_LONG == 32 |
555 | # if defined(CONFIG_LBD) | 561 | # if defined(CONFIG_LBDAF) |
556 | BUILD_BUG_ON(sizeof(sector_t) != 8); | 562 | BUILD_BUG_ON(sizeof(sector_t) != 8); |
557 | /* | 563 | /* |
558 | * We might be limited by page cache size. | 564 | * We might be limited by page cache size. |
@@ -1175,6 +1181,9 @@ static int ocfs2_fill_super(struct super_block *sb, void *data, int silent) | |||
1175 | atomic_set(&osb->vol_state, VOLUME_MOUNTED_QUOTAS); | 1181 | atomic_set(&osb->vol_state, VOLUME_MOUNTED_QUOTAS); |
1176 | wake_up(&osb->osb_mount_event); | 1182 | wake_up(&osb->osb_mount_event); |
1177 | 1183 | ||
1184 | /* Start this when the mount is almost sure of being successful */ | ||
1185 | ocfs2_orphan_scan_init(osb); | ||
1186 | |||
1178 | mlog_exit(status); | 1187 | mlog_exit(status); |
1179 | return status; | 1188 | return status; |
1180 | 1189 | ||
@@ -1810,14 +1819,15 @@ static void ocfs2_dismount_volume(struct super_block *sb, int mnt_err) | |||
1810 | 1819 | ||
1811 | debugfs_remove(osb->osb_ctxt); | 1820 | debugfs_remove(osb->osb_ctxt); |
1812 | 1821 | ||
1822 | /* Orphan scan should be stopped as early as possible */ | ||
1823 | ocfs2_orphan_scan_stop(osb); | ||
1824 | |||
1813 | ocfs2_disable_quotas(osb); | 1825 | ocfs2_disable_quotas(osb); |
1814 | 1826 | ||
1815 | ocfs2_shutdown_local_alloc(osb); | 1827 | ocfs2_shutdown_local_alloc(osb); |
1816 | 1828 | ||
1817 | ocfs2_truncate_log_shutdown(osb); | 1829 | ocfs2_truncate_log_shutdown(osb); |
1818 | 1830 | ||
1819 | ocfs2_orphan_scan_stop(osb); | ||
1820 | |||
1821 | /* This will disable recovery and flush any recovery work. */ | 1831 | /* This will disable recovery and flush any recovery work. */ |
1822 | ocfs2_recovery_exit(osb); | 1832 | ocfs2_recovery_exit(osb); |
1823 | 1833 | ||
@@ -1978,13 +1988,6 @@ static int ocfs2_initialize_super(struct super_block *sb, | |||
1978 | goto bail; | 1988 | goto bail; |
1979 | } | 1989 | } |
1980 | 1990 | ||
1981 | status = ocfs2_orphan_scan_init(osb); | ||
1982 | if (status) { | ||
1983 | mlog(ML_ERROR, "Unable to initialize delayed orphan scan\n"); | ||
1984 | mlog_errno(status); | ||
1985 | goto bail; | ||
1986 | } | ||
1987 | |||
1988 | init_waitqueue_head(&osb->checkpoint_event); | 1991 | init_waitqueue_head(&osb->checkpoint_event); |
1989 | atomic_set(&osb->needs_checkpoint, 0); | 1992 | atomic_set(&osb->needs_checkpoint, 0); |
1990 | 1993 | ||
diff --git a/fs/ocfs2/sysfile.c b/fs/ocfs2/sysfile.c index ab713ebdd546..40e53702948c 100644 --- a/fs/ocfs2/sysfile.c +++ b/fs/ocfs2/sysfile.c | |||
@@ -50,6 +50,10 @@ static inline int is_in_system_inode_array(struct ocfs2_super *osb, | |||
50 | int type, | 50 | int type, |
51 | u32 slot); | 51 | u32 slot); |
52 | 52 | ||
53 | #ifdef CONFIG_DEBUG_LOCK_ALLOC | ||
54 | static struct lock_class_key ocfs2_sysfile_cluster_lock_key[NUM_SYSTEM_INODES]; | ||
55 | #endif | ||
56 | |||
53 | static inline int is_global_system_inode(int type) | 57 | static inline int is_global_system_inode(int type) |
54 | { | 58 | { |
55 | return type >= OCFS2_FIRST_ONLINE_SYSTEM_INODE && | 59 | return type >= OCFS2_FIRST_ONLINE_SYSTEM_INODE && |
@@ -118,6 +122,21 @@ static struct inode * _ocfs2_get_system_file_inode(struct ocfs2_super *osb, | |||
118 | inode = NULL; | 122 | inode = NULL; |
119 | goto bail; | 123 | goto bail; |
120 | } | 124 | } |
125 | #ifdef CONFIG_DEBUG_LOCK_ALLOC | ||
126 | if (type == LOCAL_USER_QUOTA_SYSTEM_INODE || | ||
127 | type == LOCAL_GROUP_QUOTA_SYSTEM_INODE || | ||
128 | type == JOURNAL_SYSTEM_INODE) { | ||
129 | /* Ignore inode lock on these inodes as the lock does not | ||
130 | * really belong to any process and lockdep cannot handle | ||
131 | * that */ | ||
132 | OCFS2_I(inode)->ip_inode_lockres.l_lockdep_map.key = NULL; | ||
133 | } else { | ||
134 | lockdep_init_map(&OCFS2_I(inode)->ip_inode_lockres. | ||
135 | l_lockdep_map, | ||
136 | ocfs2_system_inodes[type].si_name, | ||
137 | &ocfs2_sysfile_cluster_lock_key[type], 0); | ||
138 | } | ||
139 | #endif | ||
121 | bail: | 140 | bail: |
122 | 141 | ||
123 | return inode; | 142 | return inode; |
diff --git a/fs/proc/Makefile b/fs/proc/Makefile index 63d965193b22..11a7b5c68153 100644 --- a/fs/proc/Makefile +++ b/fs/proc/Makefile | |||
@@ -18,6 +18,7 @@ proc-y += meminfo.o | |||
18 | proc-y += stat.o | 18 | proc-y += stat.o |
19 | proc-y += uptime.o | 19 | proc-y += uptime.o |
20 | proc-y += version.o | 20 | proc-y += version.o |
21 | proc-y += softirqs.o | ||
21 | proc-$(CONFIG_PROC_SYSCTL) += proc_sysctl.o | 22 | proc-$(CONFIG_PROC_SYSCTL) += proc_sysctl.o |
22 | proc-$(CONFIG_NET) += proc_net.o | 23 | proc-$(CONFIG_NET) += proc_net.o |
23 | proc-$(CONFIG_PROC_KCORE) += kcore.o | 24 | proc-$(CONFIG_PROC_KCORE) += kcore.o |
diff --git a/fs/proc/proc_devtree.c b/fs/proc/proc_devtree.c index fc6c3025befd..7ba79a54948c 100644 --- a/fs/proc/proc_devtree.c +++ b/fs/proc/proc_devtree.c | |||
@@ -195,20 +195,20 @@ void proc_device_tree_add_node(struct device_node *np, | |||
195 | p = fixup_name(np, de, p); | 195 | p = fixup_name(np, de, p); |
196 | 196 | ||
197 | ent = proc_mkdir(p, de); | 197 | ent = proc_mkdir(p, de); |
198 | if (ent == 0) | 198 | if (ent == NULL) |
199 | break; | 199 | break; |
200 | proc_device_tree_add_node(child, ent); | 200 | proc_device_tree_add_node(child, ent); |
201 | } | 201 | } |
202 | of_node_put(child); | 202 | of_node_put(child); |
203 | 203 | ||
204 | for (pp = np->properties; pp != 0; pp = pp->next) { | 204 | for (pp = np->properties; pp != NULL; pp = pp->next) { |
205 | p = pp->name; | 205 | p = pp->name; |
206 | 206 | ||
207 | if (duplicate_name(de, p)) | 207 | if (duplicate_name(de, p)) |
208 | p = fixup_name(np, de, p); | 208 | p = fixup_name(np, de, p); |
209 | 209 | ||
210 | ent = __proc_device_tree_add_prop(de, pp, p); | 210 | ent = __proc_device_tree_add_prop(de, pp, p); |
211 | if (ent == 0) | 211 | if (ent == NULL) |
212 | break; | 212 | break; |
213 | } | 213 | } |
214 | } | 214 | } |
@@ -221,10 +221,10 @@ void __init proc_device_tree_init(void) | |||
221 | struct device_node *root; | 221 | struct device_node *root; |
222 | 222 | ||
223 | proc_device_tree = proc_mkdir("device-tree", NULL); | 223 | proc_device_tree = proc_mkdir("device-tree", NULL); |
224 | if (proc_device_tree == 0) | 224 | if (proc_device_tree == NULL) |
225 | return; | 225 | return; |
226 | root = of_find_node_by_path("/"); | 226 | root = of_find_node_by_path("/"); |
227 | if (root == 0) { | 227 | if (root == NULL) { |
228 | printk(KERN_ERR "/proc/device-tree: can't find root\n"); | 228 | printk(KERN_ERR "/proc/device-tree: can't find root\n"); |
229 | return; | 229 | return; |
230 | } | 230 | } |
diff --git a/fs/proc/softirqs.c b/fs/proc/softirqs.c new file mode 100644 index 000000000000..1807c2419f17 --- /dev/null +++ b/fs/proc/softirqs.c | |||
@@ -0,0 +1,44 @@ | |||
1 | #include <linux/init.h> | ||
2 | #include <linux/kernel_stat.h> | ||
3 | #include <linux/proc_fs.h> | ||
4 | #include <linux/seq_file.h> | ||
5 | |||
6 | /* | ||
7 | * /proc/softirqs ... display the number of softirqs | ||
8 | */ | ||
9 | static int show_softirqs(struct seq_file *p, void *v) | ||
10 | { | ||
11 | int i, j; | ||
12 | |||
13 | seq_printf(p, " "); | ||
14 | for_each_possible_cpu(i) | ||
15 | seq_printf(p, "CPU%-8d", i); | ||
16 | seq_printf(p, "\n"); | ||
17 | |||
18 | for (i = 0; i < NR_SOFTIRQS; i++) { | ||
19 | seq_printf(p, "%8s:", softirq_to_name[i]); | ||
20 | for_each_possible_cpu(j) | ||
21 | seq_printf(p, " %10u", kstat_softirqs_cpu(i, j)); | ||
22 | seq_printf(p, "\n"); | ||
23 | } | ||
24 | return 0; | ||
25 | } | ||
26 | |||
27 | static int softirqs_open(struct inode *inode, struct file *file) | ||
28 | { | ||
29 | return single_open(file, show_softirqs, NULL); | ||
30 | } | ||
31 | |||
32 | static const struct file_operations proc_softirqs_operations = { | ||
33 | .open = softirqs_open, | ||
34 | .read = seq_read, | ||
35 | .llseek = seq_lseek, | ||
36 | .release = single_release, | ||
37 | }; | ||
38 | |||
39 | static int __init proc_softirqs_init(void) | ||
40 | { | ||
41 | proc_create("softirqs", 0, NULL, &proc_softirqs_operations); | ||
42 | return 0; | ||
43 | } | ||
44 | module_init(proc_softirqs_init); | ||
diff --git a/fs/proc/stat.c b/fs/proc/stat.c index 81e4eb60972e..7cc726c6d70a 100644 --- a/fs/proc/stat.c +++ b/fs/proc/stat.c | |||
@@ -29,6 +29,8 @@ static int show_stat(struct seq_file *p, void *v) | |||
29 | cputime64_t user, nice, system, idle, iowait, irq, softirq, steal; | 29 | cputime64_t user, nice, system, idle, iowait, irq, softirq, steal; |
30 | cputime64_t guest; | 30 | cputime64_t guest; |
31 | u64 sum = 0; | 31 | u64 sum = 0; |
32 | u64 sum_softirq = 0; | ||
33 | unsigned int per_softirq_sums[NR_SOFTIRQS] = {0}; | ||
32 | struct timespec boottime; | 34 | struct timespec boottime; |
33 | unsigned int per_irq_sum; | 35 | unsigned int per_irq_sum; |
34 | 36 | ||
@@ -53,6 +55,13 @@ static int show_stat(struct seq_file *p, void *v) | |||
53 | sum += kstat_irqs_cpu(j, i); | 55 | sum += kstat_irqs_cpu(j, i); |
54 | } | 56 | } |
55 | sum += arch_irq_stat_cpu(i); | 57 | sum += arch_irq_stat_cpu(i); |
58 | |||
59 | for (j = 0; j < NR_SOFTIRQS; j++) { | ||
60 | unsigned int softirq_stat = kstat_softirqs_cpu(j, i); | ||
61 | |||
62 | per_softirq_sums[j] += softirq_stat; | ||
63 | sum_softirq += softirq_stat; | ||
64 | } | ||
56 | } | 65 | } |
57 | sum += arch_irq_stat(); | 66 | sum += arch_irq_stat(); |
58 | 67 | ||
@@ -115,6 +124,12 @@ static int show_stat(struct seq_file *p, void *v) | |||
115 | nr_running(), | 124 | nr_running(), |
116 | nr_iowait()); | 125 | nr_iowait()); |
117 | 126 | ||
127 | seq_printf(p, "softirq %llu", (unsigned long long)sum_softirq); | ||
128 | |||
129 | for (i = 0; i < NR_SOFTIRQS; i++) | ||
130 | seq_printf(p, " %u", per_softirq_sums[i]); | ||
131 | seq_printf(p, "\n"); | ||
132 | |||
118 | return 0; | 133 | return 0; |
119 | } | 134 | } |
120 | 135 | ||
diff --git a/fs/proc/vmcore.c b/fs/proc/vmcore.c index 5edcc3f92ba7..0872afa58d39 100644 --- a/fs/proc/vmcore.c +++ b/fs/proc/vmcore.c | |||
@@ -166,12 +166,7 @@ static const struct file_operations proc_vmcore_operations = { | |||
166 | 166 | ||
167 | static struct vmcore* __init get_new_element(void) | 167 | static struct vmcore* __init get_new_element(void) |
168 | { | 168 | { |
169 | struct vmcore *p; | 169 | return kzalloc(sizeof(struct vmcore), GFP_KERNEL); |
170 | |||
171 | p = kmalloc(sizeof(*p), GFP_KERNEL); | ||
172 | if (p) | ||
173 | memset(p, 0, sizeof(*p)); | ||
174 | return p; | ||
175 | } | 170 | } |
176 | 171 | ||
177 | static u64 __init get_vmcore_size_elf64(char *elfptr) | 172 | static u64 __init get_vmcore_size_elf64(char *elfptr) |
diff --git a/fs/reiserfs/do_balan.c b/fs/reiserfs/do_balan.c index 4beb964a2a3e..128d3f7c8aa5 100644 --- a/fs/reiserfs/do_balan.c +++ b/fs/reiserfs/do_balan.c | |||
@@ -1270,9 +1270,8 @@ static int balance_leaf(struct tree_balance *tb, struct item_head *ih, /* item h | |||
1270 | 1270 | ||
1271 | RFALSE(ih, "PAP-12210: ih must be 0"); | 1271 | RFALSE(ih, "PAP-12210: ih must be 0"); |
1272 | 1272 | ||
1273 | if (is_direntry_le_ih | 1273 | aux_ih = B_N_PITEM_HEAD(tbS0, item_pos); |
1274 | (aux_ih = | 1274 | if (is_direntry_le_ih(aux_ih)) { |
1275 | B_N_PITEM_HEAD(tbS0, item_pos))) { | ||
1276 | /* we append to directory item */ | 1275 | /* we append to directory item */ |
1277 | 1276 | ||
1278 | int entry_count; | 1277 | int entry_count; |
diff --git a/fs/reiserfs/lbalance.c b/fs/reiserfs/lbalance.c index 381750a155f6..03d85cbf90bf 100644 --- a/fs/reiserfs/lbalance.c +++ b/fs/reiserfs/lbalance.c | |||
@@ -390,7 +390,8 @@ static void leaf_item_bottle(struct buffer_info *dest_bi, | |||
390 | 390 | ||
391 | if (last_first == FIRST_TO_LAST) { | 391 | if (last_first == FIRST_TO_LAST) { |
392 | /* if ( if item in position item_num in buffer SOURCE is directory item ) */ | 392 | /* if ( if item in position item_num in buffer SOURCE is directory item ) */ |
393 | if (is_direntry_le_ih(ih = B_N_PITEM_HEAD(src, item_num))) | 393 | ih = B_N_PITEM_HEAD(src, item_num); |
394 | if (is_direntry_le_ih(ih)) | ||
394 | leaf_copy_dir_entries(dest_bi, src, FIRST_TO_LAST, | 395 | leaf_copy_dir_entries(dest_bi, src, FIRST_TO_LAST, |
395 | item_num, 0, cpy_bytes); | 396 | item_num, 0, cpy_bytes); |
396 | else { | 397 | else { |
@@ -418,7 +419,8 @@ static void leaf_item_bottle(struct buffer_info *dest_bi, | |||
418 | } | 419 | } |
419 | } else { | 420 | } else { |
420 | /* if ( if item in position item_num in buffer SOURCE is directory item ) */ | 421 | /* if ( if item in position item_num in buffer SOURCE is directory item ) */ |
421 | if (is_direntry_le_ih(ih = B_N_PITEM_HEAD(src, item_num))) | 422 | ih = B_N_PITEM_HEAD(src, item_num); |
423 | if (is_direntry_le_ih(ih)) | ||
422 | leaf_copy_dir_entries(dest_bi, src, LAST_TO_FIRST, | 424 | leaf_copy_dir_entries(dest_bi, src, LAST_TO_FIRST, |
423 | item_num, | 425 | item_num, |
424 | I_ENTRY_COUNT(ih) - cpy_bytes, | 426 | I_ENTRY_COUNT(ih) - cpy_bytes, |
@@ -774,8 +776,8 @@ void leaf_delete_items(struct buffer_info *cur_bi, int last_first, | |||
774 | leaf_delete_items_entirely(cur_bi, first + 1, | 776 | leaf_delete_items_entirely(cur_bi, first + 1, |
775 | del_num - 1); | 777 | del_num - 1); |
776 | 778 | ||
777 | if (is_direntry_le_ih | 779 | ih = B_N_PITEM_HEAD(bh, B_NR_ITEMS(bh) - 1); |
778 | (ih = B_N_PITEM_HEAD(bh, B_NR_ITEMS(bh) - 1))) | 780 | if (is_direntry_le_ih(ih)) |
779 | /* the last item is directory */ | 781 | /* the last item is directory */ |
780 | /* len = numbers of directory entries in this item */ | 782 | /* len = numbers of directory entries in this item */ |
781 | len = ih_entry_count(ih); | 783 | len = ih_entry_count(ih); |
diff --git a/fs/seq_file.c b/fs/seq_file.c index 7f40f30c55c5..6c959275f2d0 100644 --- a/fs/seq_file.c +++ b/fs/seq_file.c | |||
@@ -640,6 +640,26 @@ int seq_puts(struct seq_file *m, const char *s) | |||
640 | } | 640 | } |
641 | EXPORT_SYMBOL(seq_puts); | 641 | EXPORT_SYMBOL(seq_puts); |
642 | 642 | ||
643 | /** | ||
644 | * seq_write - write arbitrary data to buffer | ||
645 | * @seq: seq_file identifying the buffer to which data should be written | ||
646 | * @data: data address | ||
647 | * @len: number of bytes | ||
648 | * | ||
649 | * Return 0 on success, non-zero otherwise. | ||
650 | */ | ||
651 | int seq_write(struct seq_file *seq, const void *data, size_t len) | ||
652 | { | ||
653 | if (seq->count + len < seq->size) { | ||
654 | memcpy(seq->buf + seq->count, data, len); | ||
655 | seq->count += len; | ||
656 | return 0; | ||
657 | } | ||
658 | seq->count = seq->size; | ||
659 | return -1; | ||
660 | } | ||
661 | EXPORT_SYMBOL(seq_write); | ||
662 | |||
643 | struct list_head *seq_list_start(struct list_head *head, loff_t pos) | 663 | struct list_head *seq_list_start(struct list_head *head, loff_t pos) |
644 | { | 664 | { |
645 | struct list_head *lh; | 665 | struct list_head *lh; |
diff --git a/fs/ufs/inode.c b/fs/ufs/inode.c index 3d2512c21f05..7cf33379fd46 100644 --- a/fs/ufs/inode.c +++ b/fs/ufs/inode.c | |||
@@ -56,9 +56,7 @@ static int ufs_block_to_path(struct inode *inode, sector_t i_block, sector_t off | |||
56 | 56 | ||
57 | 57 | ||
58 | UFSD("ptrs=uspi->s_apb = %d,double_blocks=%ld \n",ptrs,double_blocks); | 58 | UFSD("ptrs=uspi->s_apb = %d,double_blocks=%ld \n",ptrs,double_blocks); |
59 | if (i_block < 0) { | 59 | if (i_block < direct_blocks) { |
60 | ufs_warning(inode->i_sb, "ufs_block_to_path", "block < 0"); | ||
61 | } else if (i_block < direct_blocks) { | ||
62 | offsets[n++] = i_block; | 60 | offsets[n++] = i_block; |
63 | } else if ((i_block -= direct_blocks) < indirect_blocks) { | 61 | } else if ((i_block -= direct_blocks) < indirect_blocks) { |
64 | offsets[n++] = UFS_IND_BLOCK; | 62 | offsets[n++] = UFS_IND_BLOCK; |
@@ -440,8 +438,6 @@ int ufs_getfrag_block(struct inode *inode, sector_t fragment, struct buffer_head | |||
440 | lock_kernel(); | 438 | lock_kernel(); |
441 | 439 | ||
442 | UFSD("ENTER, ino %lu, fragment %llu\n", inode->i_ino, (unsigned long long)fragment); | 440 | UFSD("ENTER, ino %lu, fragment %llu\n", inode->i_ino, (unsigned long long)fragment); |
443 | if (fragment < 0) | ||
444 | goto abort_negative; | ||
445 | if (fragment > | 441 | if (fragment > |
446 | ((UFS_NDADDR + uspi->s_apb + uspi->s_2apb + uspi->s_3apb) | 442 | ((UFS_NDADDR + uspi->s_apb + uspi->s_2apb + uspi->s_3apb) |
447 | << uspi->s_fpbshift)) | 443 | << uspi->s_fpbshift)) |
@@ -504,10 +500,6 @@ abort: | |||
504 | unlock_kernel(); | 500 | unlock_kernel(); |
505 | return err; | 501 | return err; |
506 | 502 | ||
507 | abort_negative: | ||
508 | ufs_warning(sb, "ufs_get_block", "block < 0"); | ||
509 | goto abort; | ||
510 | |||
511 | abort_too_big: | 503 | abort_too_big: |
512 | ufs_warning(sb, "ufs_get_block", "block > big"); | 504 | ufs_warning(sb, "ufs_get_block", "block > big"); |
513 | goto abort; | 505 | goto abort; |
diff --git a/fs/xfs/linux-2.6/xfs_linux.h b/fs/xfs/linux-2.6/xfs_linux.h index f65a53f8752f..6127e24062d0 100644 --- a/fs/xfs/linux-2.6/xfs_linux.h +++ b/fs/xfs/linux-2.6/xfs_linux.h | |||
@@ -24,7 +24,7 @@ | |||
24 | * XFS_BIG_BLKNOS needs block layer disk addresses to be 64 bits. | 24 | * XFS_BIG_BLKNOS needs block layer disk addresses to be 64 bits. |
25 | * XFS_BIG_INUMS requires XFS_BIG_BLKNOS to be set. | 25 | * XFS_BIG_INUMS requires XFS_BIG_BLKNOS to be set. |
26 | */ | 26 | */ |
27 | #if defined(CONFIG_LBD) || (BITS_PER_LONG == 64) | 27 | #if defined(CONFIG_LBDAF) || (BITS_PER_LONG == 64) |
28 | # define XFS_BIG_BLKNOS 1 | 28 | # define XFS_BIG_BLKNOS 1 |
29 | # define XFS_BIG_INUMS 1 | 29 | # define XFS_BIG_INUMS 1 |
30 | #else | 30 | #else |
diff --git a/fs/xfs/linux-2.6/xfs_super.c b/fs/xfs/linux-2.6/xfs_super.c index 2e09efbca8db..a220d36f789b 100644 --- a/fs/xfs/linux-2.6/xfs_super.c +++ b/fs/xfs/linux-2.6/xfs_super.c | |||
@@ -616,7 +616,7 @@ xfs_max_file_offset( | |||
616 | */ | 616 | */ |
617 | 617 | ||
618 | #if BITS_PER_LONG == 32 | 618 | #if BITS_PER_LONG == 32 |
619 | # if defined(CONFIG_LBD) | 619 | # if defined(CONFIG_LBDAF) |
620 | ASSERT(sizeof(sector_t) == 8); | 620 | ASSERT(sizeof(sector_t) == 8); |
621 | pagefactor = PAGE_CACHE_SIZE; | 621 | pagefactor = PAGE_CACHE_SIZE; |
622 | bitshift = BITS_PER_LONG; | 622 | bitshift = BITS_PER_LONG; |