diff options
Diffstat (limited to 'fs')
57 files changed, 2274 insertions, 1212 deletions
diff --git a/fs/Kconfig.binfmt b/fs/Kconfig.binfmt index d4fc6095466d..7c3d5f923da1 100644 --- a/fs/Kconfig.binfmt +++ b/fs/Kconfig.binfmt | |||
@@ -23,6 +23,10 @@ config BINFMT_ELF | |||
23 | ld.so (check the file <file:Documentation/Changes> for location and | 23 | ld.so (check the file <file:Documentation/Changes> for location and |
24 | latest version). | 24 | latest version). |
25 | 25 | ||
26 | config COMPAT_BINFMT_ELF | ||
27 | bool | ||
28 | depends on COMPAT && MMU | ||
29 | |||
26 | config BINFMT_ELF_FDPIC | 30 | config BINFMT_ELF_FDPIC |
27 | bool "Kernel support for FDPIC ELF binaries" | 31 | bool "Kernel support for FDPIC ELF binaries" |
28 | default y | 32 | default y |
diff --git a/fs/Makefile b/fs/Makefile index 500cf15cdb4b..1e7a11bd4da1 100644 --- a/fs/Makefile +++ b/fs/Makefile | |||
@@ -39,6 +39,7 @@ obj-$(CONFIG_BINFMT_MISC) += binfmt_misc.o | |||
39 | obj-y += binfmt_script.o | 39 | obj-y += binfmt_script.o |
40 | 40 | ||
41 | obj-$(CONFIG_BINFMT_ELF) += binfmt_elf.o | 41 | obj-$(CONFIG_BINFMT_ELF) += binfmt_elf.o |
42 | obj-$(CONFIG_COMPAT_BINFMT_ELF) += compat_binfmt_elf.o | ||
42 | obj-$(CONFIG_BINFMT_ELF_FDPIC) += binfmt_elf_fdpic.o | 43 | obj-$(CONFIG_BINFMT_ELF_FDPIC) += binfmt_elf_fdpic.o |
43 | obj-$(CONFIG_BINFMT_SOM) += binfmt_som.o | 44 | obj-$(CONFIG_BINFMT_SOM) += binfmt_som.o |
44 | obj-$(CONFIG_BINFMT_FLAT) += binfmt_flat.o | 45 | obj-$(CONFIG_BINFMT_FLAT) += binfmt_flat.o |
@@ -397,7 +397,7 @@ void fastcall __put_ioctx(struct kioctx *ctx) | |||
397 | * This prevents races between the aio code path referencing the | 397 | * This prevents races between the aio code path referencing the |
398 | * req (after submitting it) and aio_complete() freeing the req. | 398 | * req (after submitting it) and aio_complete() freeing the req. |
399 | */ | 399 | */ |
400 | static struct kiocb *FASTCALL(__aio_get_req(struct kioctx *ctx)); | 400 | static struct kiocb *__aio_get_req(struct kioctx *ctx); |
401 | static struct kiocb fastcall *__aio_get_req(struct kioctx *ctx) | 401 | static struct kiocb fastcall *__aio_get_req(struct kioctx *ctx) |
402 | { | 402 | { |
403 | struct kiocb *req = NULL; | 403 | struct kiocb *req = NULL; |
diff --git a/fs/binfmt_elf.c b/fs/binfmt_elf.c index f0b3171842f2..18ed6dd906c1 100644 --- a/fs/binfmt_elf.c +++ b/fs/binfmt_elf.c | |||
@@ -45,7 +45,8 @@ | |||
45 | 45 | ||
46 | static int load_elf_binary(struct linux_binprm *bprm, struct pt_regs *regs); | 46 | static int load_elf_binary(struct linux_binprm *bprm, struct pt_regs *regs); |
47 | static int load_elf_library(struct file *); | 47 | static int load_elf_library(struct file *); |
48 | static unsigned long elf_map (struct file *, unsigned long, struct elf_phdr *, int, int); | 48 | static unsigned long elf_map(struct file *, unsigned long, struct elf_phdr *, |
49 | int, int, unsigned long); | ||
49 | 50 | ||
50 | /* | 51 | /* |
51 | * If we don't support core dumping, then supply a NULL so we | 52 | * If we don't support core dumping, then supply a NULL so we |
@@ -298,33 +299,70 @@ create_elf_tables(struct linux_binprm *bprm, struct elfhdr *exec, | |||
298 | #ifndef elf_map | 299 | #ifndef elf_map |
299 | 300 | ||
300 | static unsigned long elf_map(struct file *filep, unsigned long addr, | 301 | static unsigned long elf_map(struct file *filep, unsigned long addr, |
301 | struct elf_phdr *eppnt, int prot, int type) | 302 | struct elf_phdr *eppnt, int prot, int type, |
303 | unsigned long total_size) | ||
302 | { | 304 | { |
303 | unsigned long map_addr; | 305 | unsigned long map_addr; |
304 | unsigned long pageoffset = ELF_PAGEOFFSET(eppnt->p_vaddr); | 306 | unsigned long size = eppnt->p_filesz + ELF_PAGEOFFSET(eppnt->p_vaddr); |
307 | unsigned long off = eppnt->p_offset - ELF_PAGEOFFSET(eppnt->p_vaddr); | ||
308 | addr = ELF_PAGESTART(addr); | ||
309 | size = ELF_PAGEALIGN(size); | ||
305 | 310 | ||
306 | down_write(¤t->mm->mmap_sem); | ||
307 | /* mmap() will return -EINVAL if given a zero size, but a | 311 | /* mmap() will return -EINVAL if given a zero size, but a |
308 | * segment with zero filesize is perfectly valid */ | 312 | * segment with zero filesize is perfectly valid */ |
309 | if (eppnt->p_filesz + pageoffset) | 313 | if (!size) |
310 | map_addr = do_mmap(filep, ELF_PAGESTART(addr), | 314 | return addr; |
311 | eppnt->p_filesz + pageoffset, prot, type, | 315 | |
312 | eppnt->p_offset - pageoffset); | 316 | down_write(¤t->mm->mmap_sem); |
313 | else | 317 | /* |
314 | map_addr = ELF_PAGESTART(addr); | 318 | * total_size is the size of the ELF (interpreter) image. |
319 | * The _first_ mmap needs to know the full size, otherwise | ||
320 | * randomization might put this image into an overlapping | ||
321 | * position with the ELF binary image. (since size < total_size) | ||
322 | * So we first map the 'big' image - and unmap the remainder at | ||
323 | * the end. (which unmap is needed for ELF images with holes.) | ||
324 | */ | ||
325 | if (total_size) { | ||
326 | total_size = ELF_PAGEALIGN(total_size); | ||
327 | map_addr = do_mmap(filep, addr, total_size, prot, type, off); | ||
328 | if (!BAD_ADDR(map_addr)) | ||
329 | do_munmap(current->mm, map_addr+size, total_size-size); | ||
330 | } else | ||
331 | map_addr = do_mmap(filep, addr, size, prot, type, off); | ||
332 | |||
315 | up_write(¤t->mm->mmap_sem); | 333 | up_write(¤t->mm->mmap_sem); |
316 | return(map_addr); | 334 | return(map_addr); |
317 | } | 335 | } |
318 | 336 | ||
319 | #endif /* !elf_map */ | 337 | #endif /* !elf_map */ |
320 | 338 | ||
339 | static unsigned long total_mapping_size(struct elf_phdr *cmds, int nr) | ||
340 | { | ||
341 | int i, first_idx = -1, last_idx = -1; | ||
342 | |||
343 | for (i = 0; i < nr; i++) { | ||
344 | if (cmds[i].p_type == PT_LOAD) { | ||
345 | last_idx = i; | ||
346 | if (first_idx == -1) | ||
347 | first_idx = i; | ||
348 | } | ||
349 | } | ||
350 | if (first_idx == -1) | ||
351 | return 0; | ||
352 | |||
353 | return cmds[last_idx].p_vaddr + cmds[last_idx].p_memsz - | ||
354 | ELF_PAGESTART(cmds[first_idx].p_vaddr); | ||
355 | } | ||
356 | |||
357 | |||
321 | /* This is much more generalized than the library routine read function, | 358 | /* This is much more generalized than the library routine read function, |
322 | so we keep this separate. Technically the library read function | 359 | so we keep this separate. Technically the library read function |
323 | is only provided so that we can read a.out libraries that have | 360 | is only provided so that we can read a.out libraries that have |
324 | an ELF header */ | 361 | an ELF header */ |
325 | 362 | ||
326 | static unsigned long load_elf_interp(struct elfhdr *interp_elf_ex, | 363 | static unsigned long load_elf_interp(struct elfhdr *interp_elf_ex, |
327 | struct file *interpreter, unsigned long *interp_load_addr) | 364 | struct file *interpreter, unsigned long *interp_map_addr, |
365 | unsigned long no_base) | ||
328 | { | 366 | { |
329 | struct elf_phdr *elf_phdata; | 367 | struct elf_phdr *elf_phdata; |
330 | struct elf_phdr *eppnt; | 368 | struct elf_phdr *eppnt; |
@@ -332,6 +370,7 @@ static unsigned long load_elf_interp(struct elfhdr *interp_elf_ex, | |||
332 | int load_addr_set = 0; | 370 | int load_addr_set = 0; |
333 | unsigned long last_bss = 0, elf_bss = 0; | 371 | unsigned long last_bss = 0, elf_bss = 0; |
334 | unsigned long error = ~0UL; | 372 | unsigned long error = ~0UL; |
373 | unsigned long total_size; | ||
335 | int retval, i, size; | 374 | int retval, i, size; |
336 | 375 | ||
337 | /* First of all, some simple consistency checks */ | 376 | /* First of all, some simple consistency checks */ |
@@ -370,6 +409,12 @@ static unsigned long load_elf_interp(struct elfhdr *interp_elf_ex, | |||
370 | goto out_close; | 409 | goto out_close; |
371 | } | 410 | } |
372 | 411 | ||
412 | total_size = total_mapping_size(elf_phdata, interp_elf_ex->e_phnum); | ||
413 | if (!total_size) { | ||
414 | error = -EINVAL; | ||
415 | goto out_close; | ||
416 | } | ||
417 | |||
373 | eppnt = elf_phdata; | 418 | eppnt = elf_phdata; |
374 | for (i = 0; i < interp_elf_ex->e_phnum; i++, eppnt++) { | 419 | for (i = 0; i < interp_elf_ex->e_phnum; i++, eppnt++) { |
375 | if (eppnt->p_type == PT_LOAD) { | 420 | if (eppnt->p_type == PT_LOAD) { |
@@ -387,9 +432,14 @@ static unsigned long load_elf_interp(struct elfhdr *interp_elf_ex, | |||
387 | vaddr = eppnt->p_vaddr; | 432 | vaddr = eppnt->p_vaddr; |
388 | if (interp_elf_ex->e_type == ET_EXEC || load_addr_set) | 433 | if (interp_elf_ex->e_type == ET_EXEC || load_addr_set) |
389 | elf_type |= MAP_FIXED; | 434 | elf_type |= MAP_FIXED; |
435 | else if (no_base && interp_elf_ex->e_type == ET_DYN) | ||
436 | load_addr = -vaddr; | ||
390 | 437 | ||
391 | map_addr = elf_map(interpreter, load_addr + vaddr, | 438 | map_addr = elf_map(interpreter, load_addr + vaddr, |
392 | eppnt, elf_prot, elf_type); | 439 | eppnt, elf_prot, elf_type, total_size); |
440 | total_size = 0; | ||
441 | if (!*interp_map_addr) | ||
442 | *interp_map_addr = map_addr; | ||
393 | error = map_addr; | 443 | error = map_addr; |
394 | if (BAD_ADDR(map_addr)) | 444 | if (BAD_ADDR(map_addr)) |
395 | goto out_close; | 445 | goto out_close; |
@@ -455,8 +505,7 @@ static unsigned long load_elf_interp(struct elfhdr *interp_elf_ex, | |||
455 | goto out_close; | 505 | goto out_close; |
456 | } | 506 | } |
457 | 507 | ||
458 | *interp_load_addr = load_addr; | 508 | error = load_addr; |
459 | error = ((unsigned long)interp_elf_ex->e_entry) + load_addr; | ||
460 | 509 | ||
461 | out_close: | 510 | out_close: |
462 | kfree(elf_phdata); | 511 | kfree(elf_phdata); |
@@ -546,14 +595,14 @@ static int load_elf_binary(struct linux_binprm *bprm, struct pt_regs *regs) | |||
546 | int load_addr_set = 0; | 595 | int load_addr_set = 0; |
547 | char * elf_interpreter = NULL; | 596 | char * elf_interpreter = NULL; |
548 | unsigned int interpreter_type = INTERPRETER_NONE; | 597 | unsigned int interpreter_type = INTERPRETER_NONE; |
549 | unsigned char ibcs2_interpreter = 0; | ||
550 | unsigned long error; | 598 | unsigned long error; |
551 | struct elf_phdr *elf_ppnt, *elf_phdata; | 599 | struct elf_phdr *elf_ppnt, *elf_phdata; |
552 | unsigned long elf_bss, elf_brk; | 600 | unsigned long elf_bss, elf_brk; |
553 | int elf_exec_fileno; | 601 | int elf_exec_fileno; |
554 | int retval, i; | 602 | int retval, i; |
555 | unsigned int size; | 603 | unsigned int size; |
556 | unsigned long elf_entry, interp_load_addr = 0; | 604 | unsigned long elf_entry; |
605 | unsigned long interp_load_addr = 0; | ||
557 | unsigned long start_code, end_code, start_data, end_data; | 606 | unsigned long start_code, end_code, start_data, end_data; |
558 | unsigned long reloc_func_desc = 0; | 607 | unsigned long reloc_func_desc = 0; |
559 | char passed_fileno[6]; | 608 | char passed_fileno[6]; |
@@ -663,14 +712,6 @@ static int load_elf_binary(struct linux_binprm *bprm, struct pt_regs *regs) | |||
663 | if (elf_interpreter[elf_ppnt->p_filesz - 1] != '\0') | 712 | if (elf_interpreter[elf_ppnt->p_filesz - 1] != '\0') |
664 | goto out_free_interp; | 713 | goto out_free_interp; |
665 | 714 | ||
666 | /* If the program interpreter is one of these two, | ||
667 | * then assume an iBCS2 image. Otherwise assume | ||
668 | * a native linux image. | ||
669 | */ | ||
670 | if (strcmp(elf_interpreter,"/usr/lib/libc.so.1") == 0 || | ||
671 | strcmp(elf_interpreter,"/usr/lib/ld.so.1") == 0) | ||
672 | ibcs2_interpreter = 1; | ||
673 | |||
674 | /* | 715 | /* |
675 | * The early SET_PERSONALITY here is so that the lookup | 716 | * The early SET_PERSONALITY here is so that the lookup |
676 | * for the interpreter happens in the namespace of the | 717 | * for the interpreter happens in the namespace of the |
@@ -690,7 +731,7 @@ static int load_elf_binary(struct linux_binprm *bprm, struct pt_regs *regs) | |||
690 | * switch really is going to happen - do this in | 731 | * switch really is going to happen - do this in |
691 | * flush_thread(). - akpm | 732 | * flush_thread(). - akpm |
692 | */ | 733 | */ |
693 | SET_PERSONALITY(loc->elf_ex, ibcs2_interpreter); | 734 | SET_PERSONALITY(loc->elf_ex, 0); |
694 | 735 | ||
695 | interpreter = open_exec(elf_interpreter); | 736 | interpreter = open_exec(elf_interpreter); |
696 | retval = PTR_ERR(interpreter); | 737 | retval = PTR_ERR(interpreter); |
@@ -769,7 +810,7 @@ static int load_elf_binary(struct linux_binprm *bprm, struct pt_regs *regs) | |||
769 | goto out_free_dentry; | 810 | goto out_free_dentry; |
770 | } else { | 811 | } else { |
771 | /* Executables without an interpreter also need a personality */ | 812 | /* Executables without an interpreter also need a personality */ |
772 | SET_PERSONALITY(loc->elf_ex, ibcs2_interpreter); | 813 | SET_PERSONALITY(loc->elf_ex, 0); |
773 | } | 814 | } |
774 | 815 | ||
775 | /* OK, we are done with that, now set up the arg stuff, | 816 | /* OK, we are done with that, now set up the arg stuff, |
@@ -803,7 +844,7 @@ static int load_elf_binary(struct linux_binprm *bprm, struct pt_regs *regs) | |||
803 | 844 | ||
804 | /* Do this immediately, since STACK_TOP as used in setup_arg_pages | 845 | /* Do this immediately, since STACK_TOP as used in setup_arg_pages |
805 | may depend on the personality. */ | 846 | may depend on the personality. */ |
806 | SET_PERSONALITY(loc->elf_ex, ibcs2_interpreter); | 847 | SET_PERSONALITY(loc->elf_ex, 0); |
807 | if (elf_read_implies_exec(loc->elf_ex, executable_stack)) | 848 | if (elf_read_implies_exec(loc->elf_ex, executable_stack)) |
808 | current->personality |= READ_IMPLIES_EXEC; | 849 | current->personality |= READ_IMPLIES_EXEC; |
809 | 850 | ||
@@ -825,9 +866,7 @@ static int load_elf_binary(struct linux_binprm *bprm, struct pt_regs *regs) | |||
825 | current->mm->start_stack = bprm->p; | 866 | current->mm->start_stack = bprm->p; |
826 | 867 | ||
827 | /* Now we do a little grungy work by mmaping the ELF image into | 868 | /* Now we do a little grungy work by mmaping the ELF image into |
828 | the correct location in memory. At this point, we assume that | 869 | the correct location in memory. */ |
829 | the image should be loaded at fixed address, not at a variable | ||
830 | address. */ | ||
831 | for(i = 0, elf_ppnt = elf_phdata; | 870 | for(i = 0, elf_ppnt = elf_phdata; |
832 | i < loc->elf_ex.e_phnum; i++, elf_ppnt++) { | 871 | i < loc->elf_ex.e_phnum; i++, elf_ppnt++) { |
833 | int elf_prot = 0, elf_flags; | 872 | int elf_prot = 0, elf_flags; |
@@ -881,11 +920,15 @@ static int load_elf_binary(struct linux_binprm *bprm, struct pt_regs *regs) | |||
881 | * default mmap base, as well as whatever program they | 920 | * default mmap base, as well as whatever program they |
882 | * might try to exec. This is because the brk will | 921 | * might try to exec. This is because the brk will |
883 | * follow the loader, and is not movable. */ | 922 | * follow the loader, and is not movable. */ |
923 | #ifdef CONFIG_X86 | ||
924 | load_bias = 0; | ||
925 | #else | ||
884 | load_bias = ELF_PAGESTART(ELF_ET_DYN_BASE - vaddr); | 926 | load_bias = ELF_PAGESTART(ELF_ET_DYN_BASE - vaddr); |
927 | #endif | ||
885 | } | 928 | } |
886 | 929 | ||
887 | error = elf_map(bprm->file, load_bias + vaddr, elf_ppnt, | 930 | error = elf_map(bprm->file, load_bias + vaddr, elf_ppnt, |
888 | elf_prot, elf_flags); | 931 | elf_prot, elf_flags, 0); |
889 | if (BAD_ADDR(error)) { | 932 | if (BAD_ADDR(error)) { |
890 | send_sig(SIGKILL, current, 0); | 933 | send_sig(SIGKILL, current, 0); |
891 | retval = IS_ERR((void *)error) ? | 934 | retval = IS_ERR((void *)error) ? |
@@ -961,13 +1004,25 @@ static int load_elf_binary(struct linux_binprm *bprm, struct pt_regs *regs) | |||
961 | } | 1004 | } |
962 | 1005 | ||
963 | if (elf_interpreter) { | 1006 | if (elf_interpreter) { |
964 | if (interpreter_type == INTERPRETER_AOUT) | 1007 | if (interpreter_type == INTERPRETER_AOUT) { |
965 | elf_entry = load_aout_interp(&loc->interp_ex, | 1008 | elf_entry = load_aout_interp(&loc->interp_ex, |
966 | interpreter); | 1009 | interpreter); |
967 | else | 1010 | } else { |
1011 | unsigned long uninitialized_var(interp_map_addr); | ||
1012 | |||
968 | elf_entry = load_elf_interp(&loc->interp_elf_ex, | 1013 | elf_entry = load_elf_interp(&loc->interp_elf_ex, |
969 | interpreter, | 1014 | interpreter, |
970 | &interp_load_addr); | 1015 | &interp_map_addr, |
1016 | load_bias); | ||
1017 | if (!IS_ERR((void *)elf_entry)) { | ||
1018 | /* | ||
1019 | * load_elf_interp() returns relocation | ||
1020 | * adjustment | ||
1021 | */ | ||
1022 | interp_load_addr = elf_entry; | ||
1023 | elf_entry += loc->interp_elf_ex.e_entry; | ||
1024 | } | ||
1025 | } | ||
971 | if (BAD_ADDR(elf_entry)) { | 1026 | if (BAD_ADDR(elf_entry)) { |
972 | force_sig(SIGSEGV, current); | 1027 | force_sig(SIGSEGV, current); |
973 | retval = IS_ERR((void *)elf_entry) ? | 1028 | retval = IS_ERR((void *)elf_entry) ? |
@@ -1021,6 +1076,12 @@ static int load_elf_binary(struct linux_binprm *bprm, struct pt_regs *regs) | |||
1021 | current->mm->end_data = end_data; | 1076 | current->mm->end_data = end_data; |
1022 | current->mm->start_stack = bprm->p; | 1077 | current->mm->start_stack = bprm->p; |
1023 | 1078 | ||
1079 | #ifdef arch_randomize_brk | ||
1080 | if (current->flags & PF_RANDOMIZE) | ||
1081 | current->mm->brk = current->mm->start_brk = | ||
1082 | arch_randomize_brk(current->mm); | ||
1083 | #endif | ||
1084 | |||
1024 | if (current->personality & MMAP_PAGE_ZERO) { | 1085 | if (current->personality & MMAP_PAGE_ZERO) { |
1025 | /* Why this, you ask??? Well SVr4 maps page 0 as read-only, | 1086 | /* Why this, you ask??? Well SVr4 maps page 0 as read-only, |
1026 | and some applications "depend" upon this behavior. | 1087 | and some applications "depend" upon this behavior. |
@@ -1325,7 +1386,8 @@ static int writenote(struct memelfnote *men, struct file *file, | |||
1325 | if (!dump_seek(file, (off))) \ | 1386 | if (!dump_seek(file, (off))) \ |
1326 | goto end_coredump; | 1387 | goto end_coredump; |
1327 | 1388 | ||
1328 | static void fill_elf_header(struct elfhdr *elf, int segs) | 1389 | static void fill_elf_header(struct elfhdr *elf, int segs, |
1390 | u16 machine, u32 flags, u8 osabi) | ||
1329 | { | 1391 | { |
1330 | memcpy(elf->e_ident, ELFMAG, SELFMAG); | 1392 | memcpy(elf->e_ident, ELFMAG, SELFMAG); |
1331 | elf->e_ident[EI_CLASS] = ELF_CLASS; | 1393 | elf->e_ident[EI_CLASS] = ELF_CLASS; |
@@ -1335,12 +1397,12 @@ static void fill_elf_header(struct elfhdr *elf, int segs) | |||
1335 | memset(elf->e_ident+EI_PAD, 0, EI_NIDENT-EI_PAD); | 1397 | memset(elf->e_ident+EI_PAD, 0, EI_NIDENT-EI_PAD); |
1336 | 1398 | ||
1337 | elf->e_type = ET_CORE; | 1399 | elf->e_type = ET_CORE; |
1338 | elf->e_machine = ELF_ARCH; | 1400 | elf->e_machine = machine; |
1339 | elf->e_version = EV_CURRENT; | 1401 | elf->e_version = EV_CURRENT; |
1340 | elf->e_entry = 0; | 1402 | elf->e_entry = 0; |
1341 | elf->e_phoff = sizeof(struct elfhdr); | 1403 | elf->e_phoff = sizeof(struct elfhdr); |
1342 | elf->e_shoff = 0; | 1404 | elf->e_shoff = 0; |
1343 | elf->e_flags = ELF_CORE_EFLAGS; | 1405 | elf->e_flags = flags; |
1344 | elf->e_ehsize = sizeof(struct elfhdr); | 1406 | elf->e_ehsize = sizeof(struct elfhdr); |
1345 | elf->e_phentsize = sizeof(struct elf_phdr); | 1407 | elf->e_phentsize = sizeof(struct elf_phdr); |
1346 | elf->e_phnum = segs; | 1408 | elf->e_phnum = segs; |
@@ -1447,6 +1509,238 @@ static int fill_psinfo(struct elf_prpsinfo *psinfo, struct task_struct *p, | |||
1447 | return 0; | 1509 | return 0; |
1448 | } | 1510 | } |
1449 | 1511 | ||
1512 | static void fill_auxv_note(struct memelfnote *note, struct mm_struct *mm) | ||
1513 | { | ||
1514 | elf_addr_t *auxv = (elf_addr_t *) mm->saved_auxv; | ||
1515 | int i = 0; | ||
1516 | do | ||
1517 | i += 2; | ||
1518 | while (auxv[i - 2] != AT_NULL); | ||
1519 | fill_note(note, "CORE", NT_AUXV, i * sizeof(elf_addr_t), auxv); | ||
1520 | } | ||
1521 | |||
1522 | #ifdef CORE_DUMP_USE_REGSET | ||
1523 | #include <linux/regset.h> | ||
1524 | |||
1525 | struct elf_thread_core_info { | ||
1526 | struct elf_thread_core_info *next; | ||
1527 | struct task_struct *task; | ||
1528 | struct elf_prstatus prstatus; | ||
1529 | struct memelfnote notes[0]; | ||
1530 | }; | ||
1531 | |||
1532 | struct elf_note_info { | ||
1533 | struct elf_thread_core_info *thread; | ||
1534 | struct memelfnote psinfo; | ||
1535 | struct memelfnote auxv; | ||
1536 | size_t size; | ||
1537 | int thread_notes; | ||
1538 | }; | ||
1539 | |||
1540 | static int fill_thread_core_info(struct elf_thread_core_info *t, | ||
1541 | const struct user_regset_view *view, | ||
1542 | long signr, size_t *total) | ||
1543 | { | ||
1544 | unsigned int i; | ||
1545 | |||
1546 | /* | ||
1547 | * NT_PRSTATUS is the one special case, because the regset data | ||
1548 | * goes into the pr_reg field inside the note contents, rather | ||
1549 | * than being the whole note contents. We fill the reset in here. | ||
1550 | * We assume that regset 0 is NT_PRSTATUS. | ||
1551 | */ | ||
1552 | fill_prstatus(&t->prstatus, t->task, signr); | ||
1553 | (void) view->regsets[0].get(t->task, &view->regsets[0], | ||
1554 | 0, sizeof(t->prstatus.pr_reg), | ||
1555 | &t->prstatus.pr_reg, NULL); | ||
1556 | |||
1557 | fill_note(&t->notes[0], "CORE", NT_PRSTATUS, | ||
1558 | sizeof(t->prstatus), &t->prstatus); | ||
1559 | *total += notesize(&t->notes[0]); | ||
1560 | |||
1561 | /* | ||
1562 | * Each other regset might generate a note too. For each regset | ||
1563 | * that has no core_note_type or is inactive, we leave t->notes[i] | ||
1564 | * all zero and we'll know to skip writing it later. | ||
1565 | */ | ||
1566 | for (i = 1; i < view->n; ++i) { | ||
1567 | const struct user_regset *regset = &view->regsets[i]; | ||
1568 | if (regset->core_note_type && | ||
1569 | (!regset->active || regset->active(t->task, regset))) { | ||
1570 | int ret; | ||
1571 | size_t size = regset->n * regset->size; | ||
1572 | void *data = kmalloc(size, GFP_KERNEL); | ||
1573 | if (unlikely(!data)) | ||
1574 | return 0; | ||
1575 | ret = regset->get(t->task, regset, | ||
1576 | 0, size, data, NULL); | ||
1577 | if (unlikely(ret)) | ||
1578 | kfree(data); | ||
1579 | else { | ||
1580 | if (regset->core_note_type != NT_PRFPREG) | ||
1581 | fill_note(&t->notes[i], "LINUX", | ||
1582 | regset->core_note_type, | ||
1583 | size, data); | ||
1584 | else { | ||
1585 | t->prstatus.pr_fpvalid = 1; | ||
1586 | fill_note(&t->notes[i], "CORE", | ||
1587 | NT_PRFPREG, size, data); | ||
1588 | } | ||
1589 | *total += notesize(&t->notes[i]); | ||
1590 | } | ||
1591 | } | ||
1592 | } | ||
1593 | |||
1594 | return 1; | ||
1595 | } | ||
1596 | |||
1597 | static int fill_note_info(struct elfhdr *elf, int phdrs, | ||
1598 | struct elf_note_info *info, | ||
1599 | long signr, struct pt_regs *regs) | ||
1600 | { | ||
1601 | struct task_struct *dump_task = current; | ||
1602 | const struct user_regset_view *view = task_user_regset_view(dump_task); | ||
1603 | struct elf_thread_core_info *t; | ||
1604 | struct elf_prpsinfo *psinfo; | ||
1605 | struct task_struct *g, *p; | ||
1606 | unsigned int i; | ||
1607 | |||
1608 | info->size = 0; | ||
1609 | info->thread = NULL; | ||
1610 | |||
1611 | psinfo = kmalloc(sizeof(*psinfo), GFP_KERNEL); | ||
1612 | fill_note(&info->psinfo, "CORE", NT_PRPSINFO, sizeof(*psinfo), psinfo); | ||
1613 | |||
1614 | if (psinfo == NULL) | ||
1615 | return 0; | ||
1616 | |||
1617 | /* | ||
1618 | * Figure out how many notes we're going to need for each thread. | ||
1619 | */ | ||
1620 | info->thread_notes = 0; | ||
1621 | for (i = 0; i < view->n; ++i) | ||
1622 | if (view->regsets[i].core_note_type != 0) | ||
1623 | ++info->thread_notes; | ||
1624 | |||
1625 | /* | ||
1626 | * Sanity check. We rely on regset 0 being in NT_PRSTATUS, | ||
1627 | * since it is our one special case. | ||
1628 | */ | ||
1629 | if (unlikely(info->thread_notes == 0) || | ||
1630 | unlikely(view->regsets[0].core_note_type != NT_PRSTATUS)) { | ||
1631 | WARN_ON(1); | ||
1632 | return 0; | ||
1633 | } | ||
1634 | |||
1635 | /* | ||
1636 | * Initialize the ELF file header. | ||
1637 | */ | ||
1638 | fill_elf_header(elf, phdrs, | ||
1639 | view->e_machine, view->e_flags, view->ei_osabi); | ||
1640 | |||
1641 | /* | ||
1642 | * Allocate a structure for each thread. | ||
1643 | */ | ||
1644 | rcu_read_lock(); | ||
1645 | do_each_thread(g, p) | ||
1646 | if (p->mm == dump_task->mm) { | ||
1647 | t = kzalloc(offsetof(struct elf_thread_core_info, | ||
1648 | notes[info->thread_notes]), | ||
1649 | GFP_ATOMIC); | ||
1650 | if (unlikely(!t)) { | ||
1651 | rcu_read_unlock(); | ||
1652 | return 0; | ||
1653 | } | ||
1654 | t->task = p; | ||
1655 | if (p == dump_task || !info->thread) { | ||
1656 | t->next = info->thread; | ||
1657 | info->thread = t; | ||
1658 | } else { | ||
1659 | /* | ||
1660 | * Make sure to keep the original task at | ||
1661 | * the head of the list. | ||
1662 | */ | ||
1663 | t->next = info->thread->next; | ||
1664 | info->thread->next = t; | ||
1665 | } | ||
1666 | } | ||
1667 | while_each_thread(g, p); | ||
1668 | rcu_read_unlock(); | ||
1669 | |||
1670 | /* | ||
1671 | * Now fill in each thread's information. | ||
1672 | */ | ||
1673 | for (t = info->thread; t != NULL; t = t->next) | ||
1674 | if (!fill_thread_core_info(t, view, signr, &info->size)) | ||
1675 | return 0; | ||
1676 | |||
1677 | /* | ||
1678 | * Fill in the two process-wide notes. | ||
1679 | */ | ||
1680 | fill_psinfo(psinfo, dump_task->group_leader, dump_task->mm); | ||
1681 | info->size += notesize(&info->psinfo); | ||
1682 | |||
1683 | fill_auxv_note(&info->auxv, current->mm); | ||
1684 | info->size += notesize(&info->auxv); | ||
1685 | |||
1686 | return 1; | ||
1687 | } | ||
1688 | |||
1689 | static size_t get_note_info_size(struct elf_note_info *info) | ||
1690 | { | ||
1691 | return info->size; | ||
1692 | } | ||
1693 | |||
1694 | /* | ||
1695 | * Write all the notes for each thread. When writing the first thread, the | ||
1696 | * process-wide notes are interleaved after the first thread-specific note. | ||
1697 | */ | ||
1698 | static int write_note_info(struct elf_note_info *info, | ||
1699 | struct file *file, loff_t *foffset) | ||
1700 | { | ||
1701 | bool first = 1; | ||
1702 | struct elf_thread_core_info *t = info->thread; | ||
1703 | |||
1704 | do { | ||
1705 | int i; | ||
1706 | |||
1707 | if (!writenote(&t->notes[0], file, foffset)) | ||
1708 | return 0; | ||
1709 | |||
1710 | if (first && !writenote(&info->psinfo, file, foffset)) | ||
1711 | return 0; | ||
1712 | if (first && !writenote(&info->auxv, file, foffset)) | ||
1713 | return 0; | ||
1714 | |||
1715 | for (i = 1; i < info->thread_notes; ++i) | ||
1716 | if (t->notes[i].data && | ||
1717 | !writenote(&t->notes[i], file, foffset)) | ||
1718 | return 0; | ||
1719 | |||
1720 | first = 0; | ||
1721 | t = t->next; | ||
1722 | } while (t); | ||
1723 | |||
1724 | return 1; | ||
1725 | } | ||
1726 | |||
1727 | static void free_note_info(struct elf_note_info *info) | ||
1728 | { | ||
1729 | struct elf_thread_core_info *threads = info->thread; | ||
1730 | while (threads) { | ||
1731 | unsigned int i; | ||
1732 | struct elf_thread_core_info *t = threads; | ||
1733 | threads = t->next; | ||
1734 | WARN_ON(t->notes[0].data && t->notes[0].data != &t->prstatus); | ||
1735 | for (i = 1; i < info->thread_notes; ++i) | ||
1736 | kfree(t->notes[i].data); | ||
1737 | kfree(t); | ||
1738 | } | ||
1739 | kfree(info->psinfo.data); | ||
1740 | } | ||
1741 | |||
1742 | #else | ||
1743 | |||
1450 | /* Here is the structure in which status of each thread is captured. */ | 1744 | /* Here is the structure in which status of each thread is captured. */ |
1451 | struct elf_thread_status | 1745 | struct elf_thread_status |
1452 | { | 1746 | { |
@@ -1499,6 +1793,176 @@ static int elf_dump_thread_status(long signr, struct elf_thread_status *t) | |||
1499 | return sz; | 1793 | return sz; |
1500 | } | 1794 | } |
1501 | 1795 | ||
1796 | struct elf_note_info { | ||
1797 | struct memelfnote *notes; | ||
1798 | struct elf_prstatus *prstatus; /* NT_PRSTATUS */ | ||
1799 | struct elf_prpsinfo *psinfo; /* NT_PRPSINFO */ | ||
1800 | struct list_head thread_list; | ||
1801 | elf_fpregset_t *fpu; | ||
1802 | #ifdef ELF_CORE_COPY_XFPREGS | ||
1803 | elf_fpxregset_t *xfpu; | ||
1804 | #endif | ||
1805 | int thread_status_size; | ||
1806 | int numnote; | ||
1807 | }; | ||
1808 | |||
1809 | static int fill_note_info(struct elfhdr *elf, int phdrs, | ||
1810 | struct elf_note_info *info, | ||
1811 | long signr, struct pt_regs *regs) | ||
1812 | { | ||
1813 | #define NUM_NOTES 6 | ||
1814 | struct list_head *t; | ||
1815 | struct task_struct *g, *p; | ||
1816 | |||
1817 | info->notes = NULL; | ||
1818 | info->prstatus = NULL; | ||
1819 | info->psinfo = NULL; | ||
1820 | info->fpu = NULL; | ||
1821 | #ifdef ELF_CORE_COPY_XFPREGS | ||
1822 | info->xfpu = NULL; | ||
1823 | #endif | ||
1824 | INIT_LIST_HEAD(&info->thread_list); | ||
1825 | |||
1826 | info->notes = kmalloc(NUM_NOTES * sizeof(struct memelfnote), | ||
1827 | GFP_KERNEL); | ||
1828 | if (!info->notes) | ||
1829 | return 0; | ||
1830 | info->psinfo = kmalloc(sizeof(*info->psinfo), GFP_KERNEL); | ||
1831 | if (!info->psinfo) | ||
1832 | return 0; | ||
1833 | info->prstatus = kmalloc(sizeof(*info->prstatus), GFP_KERNEL); | ||
1834 | if (!info->prstatus) | ||
1835 | return 0; | ||
1836 | info->fpu = kmalloc(sizeof(*info->fpu), GFP_KERNEL); | ||
1837 | if (!info->fpu) | ||
1838 | return 0; | ||
1839 | #ifdef ELF_CORE_COPY_XFPREGS | ||
1840 | info->xfpu = kmalloc(sizeof(*info->xfpu), GFP_KERNEL); | ||
1841 | if (!info->xfpu) | ||
1842 | return 0; | ||
1843 | #endif | ||
1844 | |||
1845 | info->thread_status_size = 0; | ||
1846 | if (signr) { | ||
1847 | struct elf_thread_status *tmp; | ||
1848 | rcu_read_lock(); | ||
1849 | do_each_thread(g, p) | ||
1850 | if (current->mm == p->mm && current != p) { | ||
1851 | tmp = kzalloc(sizeof(*tmp), GFP_ATOMIC); | ||
1852 | if (!tmp) { | ||
1853 | rcu_read_unlock(); | ||
1854 | return 0; | ||
1855 | } | ||
1856 | tmp->thread = p; | ||
1857 | list_add(&tmp->list, &info->thread_list); | ||
1858 | } | ||
1859 | while_each_thread(g, p); | ||
1860 | rcu_read_unlock(); | ||
1861 | list_for_each(t, &info->thread_list) { | ||
1862 | struct elf_thread_status *tmp; | ||
1863 | int sz; | ||
1864 | |||
1865 | tmp = list_entry(t, struct elf_thread_status, list); | ||
1866 | sz = elf_dump_thread_status(signr, tmp); | ||
1867 | info->thread_status_size += sz; | ||
1868 | } | ||
1869 | } | ||
1870 | /* now collect the dump for the current */ | ||
1871 | memset(info->prstatus, 0, sizeof(*info->prstatus)); | ||
1872 | fill_prstatus(info->prstatus, current, signr); | ||
1873 | elf_core_copy_regs(&info->prstatus->pr_reg, regs); | ||
1874 | |||
1875 | /* Set up header */ | ||
1876 | fill_elf_header(elf, phdrs, ELF_ARCH, ELF_CORE_EFLAGS, ELF_OSABI); | ||
1877 | |||
1878 | /* | ||
1879 | * Set up the notes in similar form to SVR4 core dumps made | ||
1880 | * with info from their /proc. | ||
1881 | */ | ||
1882 | |||
1883 | fill_note(info->notes + 0, "CORE", NT_PRSTATUS, | ||
1884 | sizeof(*info->prstatus), info->prstatus); | ||
1885 | fill_psinfo(info->psinfo, current->group_leader, current->mm); | ||
1886 | fill_note(info->notes + 1, "CORE", NT_PRPSINFO, | ||
1887 | sizeof(*info->psinfo), info->psinfo); | ||
1888 | |||
1889 | info->numnote = 2; | ||
1890 | |||
1891 | fill_auxv_note(&info->notes[info->numnote++], current->mm); | ||
1892 | |||
1893 | /* Try to dump the FPU. */ | ||
1894 | info->prstatus->pr_fpvalid = elf_core_copy_task_fpregs(current, regs, | ||
1895 | info->fpu); | ||
1896 | if (info->prstatus->pr_fpvalid) | ||
1897 | fill_note(info->notes + info->numnote++, | ||
1898 | "CORE", NT_PRFPREG, sizeof(*info->fpu), info->fpu); | ||
1899 | #ifdef ELF_CORE_COPY_XFPREGS | ||
1900 | if (elf_core_copy_task_xfpregs(current, info->xfpu)) | ||
1901 | fill_note(info->notes + info->numnote++, | ||
1902 | "LINUX", ELF_CORE_XFPREG_TYPE, | ||
1903 | sizeof(*info->xfpu), info->xfpu); | ||
1904 | #endif | ||
1905 | |||
1906 | return 1; | ||
1907 | |||
1908 | #undef NUM_NOTES | ||
1909 | } | ||
1910 | |||
1911 | static size_t get_note_info_size(struct elf_note_info *info) | ||
1912 | { | ||
1913 | int sz = 0; | ||
1914 | int i; | ||
1915 | |||
1916 | for (i = 0; i < info->numnote; i++) | ||
1917 | sz += notesize(info->notes + i); | ||
1918 | |||
1919 | sz += info->thread_status_size; | ||
1920 | |||
1921 | return sz; | ||
1922 | } | ||
1923 | |||
1924 | static int write_note_info(struct elf_note_info *info, | ||
1925 | struct file *file, loff_t *foffset) | ||
1926 | { | ||
1927 | int i; | ||
1928 | struct list_head *t; | ||
1929 | |||
1930 | for (i = 0; i < info->numnote; i++) | ||
1931 | if (!writenote(info->notes + i, file, foffset)) | ||
1932 | return 0; | ||
1933 | |||
1934 | /* write out the thread status notes section */ | ||
1935 | list_for_each(t, &info->thread_list) { | ||
1936 | struct elf_thread_status *tmp = | ||
1937 | list_entry(t, struct elf_thread_status, list); | ||
1938 | |||
1939 | for (i = 0; i < tmp->num_notes; i++) | ||
1940 | if (!writenote(&tmp->notes[i], file, foffset)) | ||
1941 | return 0; | ||
1942 | } | ||
1943 | |||
1944 | return 1; | ||
1945 | } | ||
1946 | |||
1947 | static void free_note_info(struct elf_note_info *info) | ||
1948 | { | ||
1949 | while (!list_empty(&info->thread_list)) { | ||
1950 | struct list_head *tmp = info->thread_list.next; | ||
1951 | list_del(tmp); | ||
1952 | kfree(list_entry(tmp, struct elf_thread_status, list)); | ||
1953 | } | ||
1954 | |||
1955 | kfree(info->prstatus); | ||
1956 | kfree(info->psinfo); | ||
1957 | kfree(info->notes); | ||
1958 | kfree(info->fpu); | ||
1959 | #ifdef ELF_CORE_COPY_XFPREGS | ||
1960 | kfree(info->xfpu); | ||
1961 | #endif | ||
1962 | } | ||
1963 | |||
1964 | #endif | ||
1965 | |||
1502 | static struct vm_area_struct *first_vma(struct task_struct *tsk, | 1966 | static struct vm_area_struct *first_vma(struct task_struct *tsk, |
1503 | struct vm_area_struct *gate_vma) | 1967 | struct vm_area_struct *gate_vma) |
1504 | { | 1968 | { |
@@ -1534,29 +1998,15 @@ static struct vm_area_struct *next_vma(struct vm_area_struct *this_vma, | |||
1534 | */ | 1998 | */ |
1535 | static int elf_core_dump(long signr, struct pt_regs *regs, struct file *file, unsigned long limit) | 1999 | static int elf_core_dump(long signr, struct pt_regs *regs, struct file *file, unsigned long limit) |
1536 | { | 2000 | { |
1537 | #define NUM_NOTES 6 | ||
1538 | int has_dumped = 0; | 2001 | int has_dumped = 0; |
1539 | mm_segment_t fs; | 2002 | mm_segment_t fs; |
1540 | int segs; | 2003 | int segs; |
1541 | size_t size = 0; | 2004 | size_t size = 0; |
1542 | int i; | ||
1543 | struct vm_area_struct *vma, *gate_vma; | 2005 | struct vm_area_struct *vma, *gate_vma; |
1544 | struct elfhdr *elf = NULL; | 2006 | struct elfhdr *elf = NULL; |
1545 | loff_t offset = 0, dataoff, foffset; | 2007 | loff_t offset = 0, dataoff, foffset; |
1546 | int numnote; | ||
1547 | struct memelfnote *notes = NULL; | ||
1548 | struct elf_prstatus *prstatus = NULL; /* NT_PRSTATUS */ | ||
1549 | struct elf_prpsinfo *psinfo = NULL; /* NT_PRPSINFO */ | ||
1550 | struct task_struct *g, *p; | ||
1551 | LIST_HEAD(thread_list); | ||
1552 | struct list_head *t; | ||
1553 | elf_fpregset_t *fpu = NULL; | ||
1554 | #ifdef ELF_CORE_COPY_XFPREGS | ||
1555 | elf_fpxregset_t *xfpu = NULL; | ||
1556 | #endif | ||
1557 | int thread_status_size = 0; | ||
1558 | elf_addr_t *auxv; | ||
1559 | unsigned long mm_flags; | 2008 | unsigned long mm_flags; |
2009 | struct elf_note_info info; | ||
1560 | 2010 | ||
1561 | /* | 2011 | /* |
1562 | * We no longer stop all VM operations. | 2012 | * We no longer stop all VM operations. |
@@ -1574,52 +2024,6 @@ static int elf_core_dump(long signr, struct pt_regs *regs, struct file *file, un | |||
1574 | elf = kmalloc(sizeof(*elf), GFP_KERNEL); | 2024 | elf = kmalloc(sizeof(*elf), GFP_KERNEL); |
1575 | if (!elf) | 2025 | if (!elf) |
1576 | goto cleanup; | 2026 | goto cleanup; |
1577 | prstatus = kmalloc(sizeof(*prstatus), GFP_KERNEL); | ||
1578 | if (!prstatus) | ||
1579 | goto cleanup; | ||
1580 | psinfo = kmalloc(sizeof(*psinfo), GFP_KERNEL); | ||
1581 | if (!psinfo) | ||
1582 | goto cleanup; | ||
1583 | notes = kmalloc(NUM_NOTES * sizeof(struct memelfnote), GFP_KERNEL); | ||
1584 | if (!notes) | ||
1585 | goto cleanup; | ||
1586 | fpu = kmalloc(sizeof(*fpu), GFP_KERNEL); | ||
1587 | if (!fpu) | ||
1588 | goto cleanup; | ||
1589 | #ifdef ELF_CORE_COPY_XFPREGS | ||
1590 | xfpu = kmalloc(sizeof(*xfpu), GFP_KERNEL); | ||
1591 | if (!xfpu) | ||
1592 | goto cleanup; | ||
1593 | #endif | ||
1594 | |||
1595 | if (signr) { | ||
1596 | struct elf_thread_status *tmp; | ||
1597 | rcu_read_lock(); | ||
1598 | do_each_thread(g,p) | ||
1599 | if (current->mm == p->mm && current != p) { | ||
1600 | tmp = kzalloc(sizeof(*tmp), GFP_ATOMIC); | ||
1601 | if (!tmp) { | ||
1602 | rcu_read_unlock(); | ||
1603 | goto cleanup; | ||
1604 | } | ||
1605 | tmp->thread = p; | ||
1606 | list_add(&tmp->list, &thread_list); | ||
1607 | } | ||
1608 | while_each_thread(g,p); | ||
1609 | rcu_read_unlock(); | ||
1610 | list_for_each(t, &thread_list) { | ||
1611 | struct elf_thread_status *tmp; | ||
1612 | int sz; | ||
1613 | |||
1614 | tmp = list_entry(t, struct elf_thread_status, list); | ||
1615 | sz = elf_dump_thread_status(signr, tmp); | ||
1616 | thread_status_size += sz; | ||
1617 | } | ||
1618 | } | ||
1619 | /* now collect the dump for the current */ | ||
1620 | memset(prstatus, 0, sizeof(*prstatus)); | ||
1621 | fill_prstatus(prstatus, current, signr); | ||
1622 | elf_core_copy_regs(&prstatus->pr_reg, regs); | ||
1623 | 2027 | ||
1624 | segs = current->mm->map_count; | 2028 | segs = current->mm->map_count; |
1625 | #ifdef ELF_CORE_EXTRA_PHDRS | 2029 | #ifdef ELF_CORE_EXTRA_PHDRS |
@@ -1630,42 +2034,16 @@ static int elf_core_dump(long signr, struct pt_regs *regs, struct file *file, un | |||
1630 | if (gate_vma != NULL) | 2034 | if (gate_vma != NULL) |
1631 | segs++; | 2035 | segs++; |
1632 | 2036 | ||
1633 | /* Set up header */ | ||
1634 | fill_elf_header(elf, segs + 1); /* including notes section */ | ||
1635 | |||
1636 | has_dumped = 1; | ||
1637 | current->flags |= PF_DUMPCORE; | ||
1638 | |||
1639 | /* | 2037 | /* |
1640 | * Set up the notes in similar form to SVR4 core dumps made | 2038 | * Collect all the non-memory information about the process for the |
1641 | * with info from their /proc. | 2039 | * notes. This also sets up the file header. |
1642 | */ | 2040 | */ |
2041 | if (!fill_note_info(elf, segs + 1, /* including notes section */ | ||
2042 | &info, signr, regs)) | ||
2043 | goto cleanup; | ||
1643 | 2044 | ||
1644 | fill_note(notes + 0, "CORE", NT_PRSTATUS, sizeof(*prstatus), prstatus); | 2045 | has_dumped = 1; |
1645 | fill_psinfo(psinfo, current->group_leader, current->mm); | 2046 | current->flags |= PF_DUMPCORE; |
1646 | fill_note(notes + 1, "CORE", NT_PRPSINFO, sizeof(*psinfo), psinfo); | ||
1647 | |||
1648 | numnote = 2; | ||
1649 | |||
1650 | auxv = (elf_addr_t *)current->mm->saved_auxv; | ||
1651 | |||
1652 | i = 0; | ||
1653 | do | ||
1654 | i += 2; | ||
1655 | while (auxv[i - 2] != AT_NULL); | ||
1656 | fill_note(¬es[numnote++], "CORE", NT_AUXV, | ||
1657 | i * sizeof(elf_addr_t), auxv); | ||
1658 | |||
1659 | /* Try to dump the FPU. */ | ||
1660 | if ((prstatus->pr_fpvalid = | ||
1661 | elf_core_copy_task_fpregs(current, regs, fpu))) | ||
1662 | fill_note(notes + numnote++, | ||
1663 | "CORE", NT_PRFPREG, sizeof(*fpu), fpu); | ||
1664 | #ifdef ELF_CORE_COPY_XFPREGS | ||
1665 | if (elf_core_copy_task_xfpregs(current, xfpu)) | ||
1666 | fill_note(notes + numnote++, | ||
1667 | "LINUX", ELF_CORE_XFPREG_TYPE, sizeof(*xfpu), xfpu); | ||
1668 | #endif | ||
1669 | 2047 | ||
1670 | fs = get_fs(); | 2048 | fs = get_fs(); |
1671 | set_fs(KERNEL_DS); | 2049 | set_fs(KERNEL_DS); |
@@ -1678,12 +2056,7 @@ static int elf_core_dump(long signr, struct pt_regs *regs, struct file *file, un | |||
1678 | /* Write notes phdr entry */ | 2056 | /* Write notes phdr entry */ |
1679 | { | 2057 | { |
1680 | struct elf_phdr phdr; | 2058 | struct elf_phdr phdr; |
1681 | int sz = 0; | 2059 | size_t sz = get_note_info_size(&info); |
1682 | |||
1683 | for (i = 0; i < numnote; i++) | ||
1684 | sz += notesize(notes + i); | ||
1685 | |||
1686 | sz += thread_status_size; | ||
1687 | 2060 | ||
1688 | sz += elf_coredump_extra_notes_size(); | 2061 | sz += elf_coredump_extra_notes_size(); |
1689 | 2062 | ||
@@ -1728,23 +2101,12 @@ static int elf_core_dump(long signr, struct pt_regs *regs, struct file *file, un | |||
1728 | #endif | 2101 | #endif |
1729 | 2102 | ||
1730 | /* write out the notes section */ | 2103 | /* write out the notes section */ |
1731 | for (i = 0; i < numnote; i++) | 2104 | if (!write_note_info(&info, file, &foffset)) |
1732 | if (!writenote(notes + i, file, &foffset)) | 2105 | goto end_coredump; |
1733 | goto end_coredump; | ||
1734 | 2106 | ||
1735 | if (elf_coredump_extra_notes_write(file, &foffset)) | 2107 | if (elf_coredump_extra_notes_write(file, &foffset)) |
1736 | goto end_coredump; | 2108 | goto end_coredump; |
1737 | 2109 | ||
1738 | /* write out the thread status notes section */ | ||
1739 | list_for_each(t, &thread_list) { | ||
1740 | struct elf_thread_status *tmp = | ||
1741 | list_entry(t, struct elf_thread_status, list); | ||
1742 | |||
1743 | for (i = 0; i < tmp->num_notes; i++) | ||
1744 | if (!writenote(&tmp->notes[i], file, &foffset)) | ||
1745 | goto end_coredump; | ||
1746 | } | ||
1747 | |||
1748 | /* Align to page */ | 2110 | /* Align to page */ |
1749 | DUMP_SEEK(dataoff - foffset); | 2111 | DUMP_SEEK(dataoff - foffset); |
1750 | 2112 | ||
@@ -1795,22 +2157,9 @@ end_coredump: | |||
1795 | set_fs(fs); | 2157 | set_fs(fs); |
1796 | 2158 | ||
1797 | cleanup: | 2159 | cleanup: |
1798 | while (!list_empty(&thread_list)) { | ||
1799 | struct list_head *tmp = thread_list.next; | ||
1800 | list_del(tmp); | ||
1801 | kfree(list_entry(tmp, struct elf_thread_status, list)); | ||
1802 | } | ||
1803 | |||
1804 | kfree(elf); | 2160 | kfree(elf); |
1805 | kfree(prstatus); | 2161 | free_note_info(&info); |
1806 | kfree(psinfo); | ||
1807 | kfree(notes); | ||
1808 | kfree(fpu); | ||
1809 | #ifdef ELF_CORE_COPY_XFPREGS | ||
1810 | kfree(xfpu); | ||
1811 | #endif | ||
1812 | return has_dumped; | 2162 | return has_dumped; |
1813 | #undef NUM_NOTES | ||
1814 | } | 2163 | } |
1815 | 2164 | ||
1816 | #endif /* USE_ELF_CORE_DUMP */ | 2165 | #endif /* USE_ELF_CORE_DUMP */ |
diff --git a/fs/compat_binfmt_elf.c b/fs/compat_binfmt_elf.c new file mode 100644 index 000000000000..0adced2f296f --- /dev/null +++ b/fs/compat_binfmt_elf.c | |||
@@ -0,0 +1,131 @@ | |||
1 | /* | ||
2 | * 32-bit compatibility support for ELF format executables and core dumps. | ||
3 | * | ||
4 | * Copyright (C) 2007 Red Hat, Inc. All rights reserved. | ||
5 | * | ||
6 | * This copyrighted material is made available to anyone wishing to use, | ||
7 | * modify, copy, or redistribute it subject to the terms and conditions | ||
8 | * of the GNU General Public License v.2. | ||
9 | * | ||
10 | * Red Hat Author: Roland McGrath. | ||
11 | * | ||
12 | * This file is used in a 64-bit kernel that wants to support 32-bit ELF. | ||
13 | * asm/elf.h is responsible for defining the compat_* and COMPAT_* macros | ||
14 | * used below, with definitions appropriate for 32-bit ABI compatibility. | ||
15 | * | ||
16 | * We use macros to rename the ABI types and machine-dependent | ||
17 | * functions used in binfmt_elf.c to compat versions. | ||
18 | */ | ||
19 | |||
20 | #include <linux/elfcore-compat.h> | ||
21 | #include <linux/time.h> | ||
22 | |||
23 | /* | ||
24 | * Rename the basic ELF layout types to refer to the 32-bit class of files. | ||
25 | */ | ||
26 | #undef ELF_CLASS | ||
27 | #define ELF_CLASS ELFCLASS32 | ||
28 | |||
29 | #undef elfhdr | ||
30 | #undef elf_phdr | ||
31 | #undef elf_note | ||
32 | #undef elf_addr_t | ||
33 | #define elfhdr elf32_hdr | ||
34 | #define elf_phdr elf32_phdr | ||
35 | #define elf_note elf32_note | ||
36 | #define elf_addr_t Elf32_Addr | ||
37 | |||
38 | /* | ||
39 | * The machine-dependent core note format types are defined in elfcore-compat.h, | ||
40 | * which requires asm/elf.h to define compat_elf_gregset_t et al. | ||
41 | */ | ||
42 | #define elf_prstatus compat_elf_prstatus | ||
43 | #define elf_prpsinfo compat_elf_prpsinfo | ||
44 | |||
45 | /* | ||
46 | * Compat version of cputime_to_compat_timeval, perhaps this | ||
47 | * should be an inline in <linux/compat.h>. | ||
48 | */ | ||
49 | static void cputime_to_compat_timeval(const cputime_t cputime, | ||
50 | struct compat_timeval *value) | ||
51 | { | ||
52 | struct timeval tv; | ||
53 | cputime_to_timeval(cputime, &tv); | ||
54 | value->tv_sec = tv.tv_sec; | ||
55 | value->tv_usec = tv.tv_usec; | ||
56 | } | ||
57 | |||
58 | #undef cputime_to_timeval | ||
59 | #define cputime_to_timeval cputime_to_compat_timeval | ||
60 | |||
61 | |||
62 | /* | ||
63 | * To use this file, asm/elf.h must define compat_elf_check_arch. | ||
64 | * The other following macros can be defined if the compat versions | ||
65 | * differ from the native ones, or omitted when they match. | ||
66 | */ | ||
67 | |||
68 | #undef ELF_ARCH | ||
69 | #undef elf_check_arch | ||
70 | #define elf_check_arch compat_elf_check_arch | ||
71 | |||
72 | #ifdef COMPAT_ELF_PLATFORM | ||
73 | #undef ELF_PLATFORM | ||
74 | #define ELF_PLATFORM COMPAT_ELF_PLATFORM | ||
75 | #endif | ||
76 | |||
77 | #ifdef COMPAT_ELF_HWCAP | ||
78 | #undef ELF_HWCAP | ||
79 | #define ELF_HWCAP COMPAT_ELF_HWCAP | ||
80 | #endif | ||
81 | |||
82 | #ifdef COMPAT_ARCH_DLINFO | ||
83 | #undef ARCH_DLINFO | ||
84 | #define ARCH_DLINFO COMPAT_ARCH_DLINFO | ||
85 | #endif | ||
86 | |||
87 | #ifdef COMPAT_ELF_ET_DYN_BASE | ||
88 | #undef ELF_ET_DYN_BASE | ||
89 | #define ELF_ET_DYN_BASE COMPAT_ELF_ET_DYN_BASE | ||
90 | #endif | ||
91 | |||
92 | #ifdef COMPAT_ELF_EXEC_PAGESIZE | ||
93 | #undef ELF_EXEC_PAGESIZE | ||
94 | #define ELF_EXEC_PAGESIZE COMPAT_ELF_EXEC_PAGESIZE | ||
95 | #endif | ||
96 | |||
97 | #ifdef COMPAT_ELF_PLAT_INIT | ||
98 | #undef ELF_PLAT_INIT | ||
99 | #define ELF_PLAT_INIT COMPAT_ELF_PLAT_INIT | ||
100 | #endif | ||
101 | |||
102 | #ifdef COMPAT_SET_PERSONALITY | ||
103 | #undef SET_PERSONALITY | ||
104 | #define SET_PERSONALITY COMPAT_SET_PERSONALITY | ||
105 | #endif | ||
106 | |||
107 | #ifdef compat_start_thread | ||
108 | #undef start_thread | ||
109 | #define start_thread compat_start_thread | ||
110 | #endif | ||
111 | |||
112 | #ifdef compat_arch_setup_additional_pages | ||
113 | #undef ARCH_HAS_SETUP_ADDITIONAL_PAGES | ||
114 | #define ARCH_HAS_SETUP_ADDITIONAL_PAGES 1 | ||
115 | #undef arch_setup_additional_pages | ||
116 | #define arch_setup_additional_pages compat_arch_setup_additional_pages | ||
117 | #endif | ||
118 | |||
119 | /* | ||
120 | * Rename a few of the symbols that binfmt_elf.c will define. | ||
121 | * These are all local so the names don't really matter, but it | ||
122 | * might make some debugging less confusing not to duplicate them. | ||
123 | */ | ||
124 | #define elf_format compat_elf_format | ||
125 | #define init_elf_binfmt init_compat_elf_binfmt | ||
126 | #define exit_elf_binfmt exit_compat_elf_binfmt | ||
127 | |||
128 | /* | ||
129 | * We share all the actual code with the native (64-bit) version. | ||
130 | */ | ||
131 | #include "binfmt_elf.c" | ||
diff --git a/fs/dlm/dir.c b/fs/dlm/dir.c index 46754553fdcc..ff97ba924333 100644 --- a/fs/dlm/dir.c +++ b/fs/dlm/dir.c | |||
@@ -49,7 +49,7 @@ static struct dlm_direntry *get_free_de(struct dlm_ls *ls, int len) | |||
49 | spin_unlock(&ls->ls_recover_list_lock); | 49 | spin_unlock(&ls->ls_recover_list_lock); |
50 | 50 | ||
51 | if (!found) | 51 | if (!found) |
52 | de = allocate_direntry(ls, len); | 52 | de = kzalloc(sizeof(struct dlm_direntry) + len, GFP_KERNEL); |
53 | return de; | 53 | return de; |
54 | } | 54 | } |
55 | 55 | ||
@@ -62,7 +62,7 @@ void dlm_clear_free_entries(struct dlm_ls *ls) | |||
62 | de = list_entry(ls->ls_recover_list.next, struct dlm_direntry, | 62 | de = list_entry(ls->ls_recover_list.next, struct dlm_direntry, |
63 | list); | 63 | list); |
64 | list_del(&de->list); | 64 | list_del(&de->list); |
65 | free_direntry(de); | 65 | kfree(de); |
66 | } | 66 | } |
67 | spin_unlock(&ls->ls_recover_list_lock); | 67 | spin_unlock(&ls->ls_recover_list_lock); |
68 | } | 68 | } |
@@ -171,7 +171,7 @@ void dlm_dir_remove_entry(struct dlm_ls *ls, int nodeid, char *name, int namelen | |||
171 | } | 171 | } |
172 | 172 | ||
173 | list_del(&de->list); | 173 | list_del(&de->list); |
174 | free_direntry(de); | 174 | kfree(de); |
175 | out: | 175 | out: |
176 | write_unlock(&ls->ls_dirtbl[bucket].lock); | 176 | write_unlock(&ls->ls_dirtbl[bucket].lock); |
177 | } | 177 | } |
@@ -302,7 +302,7 @@ static int get_entry(struct dlm_ls *ls, int nodeid, char *name, | |||
302 | 302 | ||
303 | write_unlock(&ls->ls_dirtbl[bucket].lock); | 303 | write_unlock(&ls->ls_dirtbl[bucket].lock); |
304 | 304 | ||
305 | de = allocate_direntry(ls, namelen); | 305 | de = kzalloc(sizeof(struct dlm_direntry) + namelen, GFP_KERNEL); |
306 | if (!de) | 306 | if (!de) |
307 | return -ENOMEM; | 307 | return -ENOMEM; |
308 | 308 | ||
@@ -313,7 +313,7 @@ static int get_entry(struct dlm_ls *ls, int nodeid, char *name, | |||
313 | write_lock(&ls->ls_dirtbl[bucket].lock); | 313 | write_lock(&ls->ls_dirtbl[bucket].lock); |
314 | tmp = search_bucket(ls, name, namelen, bucket); | 314 | tmp = search_bucket(ls, name, namelen, bucket); |
315 | if (tmp) { | 315 | if (tmp) { |
316 | free_direntry(de); | 316 | kfree(de); |
317 | de = tmp; | 317 | de = tmp; |
318 | } else { | 318 | } else { |
319 | list_add_tail(&de->list, &ls->ls_dirtbl[bucket].list); | 319 | list_add_tail(&de->list, &ls->ls_dirtbl[bucket].list); |
@@ -329,49 +329,47 @@ int dlm_dir_lookup(struct dlm_ls *ls, int nodeid, char *name, int namelen, | |||
329 | return get_entry(ls, nodeid, name, namelen, r_nodeid); | 329 | return get_entry(ls, nodeid, name, namelen, r_nodeid); |
330 | } | 330 | } |
331 | 331 | ||
332 | /* Copy the names of master rsb's into the buffer provided. | 332 | static struct dlm_rsb *find_rsb_root(struct dlm_ls *ls, char *name, int len) |
333 | Only select names whose dir node is the given nodeid. */ | 333 | { |
334 | struct dlm_rsb *r; | ||
335 | |||
336 | down_read(&ls->ls_root_sem); | ||
337 | list_for_each_entry(r, &ls->ls_root_list, res_root_list) { | ||
338 | if (len == r->res_length && !memcmp(name, r->res_name, len)) { | ||
339 | up_read(&ls->ls_root_sem); | ||
340 | return r; | ||
341 | } | ||
342 | } | ||
343 | up_read(&ls->ls_root_sem); | ||
344 | return NULL; | ||
345 | } | ||
346 | |||
347 | /* Find the rsb where we left off (or start again), then send rsb names | ||
348 | for rsb's we're master of and whose directory node matches the requesting | ||
349 | node. inbuf is the rsb name last sent, inlen is the name's length */ | ||
334 | 350 | ||
335 | void dlm_copy_master_names(struct dlm_ls *ls, char *inbuf, int inlen, | 351 | void dlm_copy_master_names(struct dlm_ls *ls, char *inbuf, int inlen, |
336 | char *outbuf, int outlen, int nodeid) | 352 | char *outbuf, int outlen, int nodeid) |
337 | { | 353 | { |
338 | struct list_head *list; | 354 | struct list_head *list; |
339 | struct dlm_rsb *start_r = NULL, *r = NULL; | 355 | struct dlm_rsb *r; |
340 | int offset = 0, start_namelen, error, dir_nodeid; | 356 | int offset = 0, dir_nodeid; |
341 | char *start_name; | ||
342 | uint16_t be_namelen; | 357 | uint16_t be_namelen; |
343 | 358 | ||
344 | /* | ||
345 | * Find the rsb where we left off (or start again) | ||
346 | */ | ||
347 | |||
348 | start_namelen = inlen; | ||
349 | start_name = inbuf; | ||
350 | |||
351 | if (start_namelen > 1) { | ||
352 | /* | ||
353 | * We could also use a find_rsb_root() function here that | ||
354 | * searched the ls_root_list. | ||
355 | */ | ||
356 | error = dlm_find_rsb(ls, start_name, start_namelen, R_MASTER, | ||
357 | &start_r); | ||
358 | DLM_ASSERT(!error && start_r, | ||
359 | printk("error %d\n", error);); | ||
360 | DLM_ASSERT(!list_empty(&start_r->res_root_list), | ||
361 | dlm_print_rsb(start_r);); | ||
362 | dlm_put_rsb(start_r); | ||
363 | } | ||
364 | |||
365 | /* | ||
366 | * Send rsb names for rsb's we're master of and whose directory node | ||
367 | * matches the requesting node. | ||
368 | */ | ||
369 | |||
370 | down_read(&ls->ls_root_sem); | 359 | down_read(&ls->ls_root_sem); |
371 | if (start_r) | 360 | |
372 | list = start_r->res_root_list.next; | 361 | if (inlen > 1) { |
373 | else | 362 | r = find_rsb_root(ls, inbuf, inlen); |
363 | if (!r) { | ||
364 | inbuf[inlen - 1] = '\0'; | ||
365 | log_error(ls, "copy_master_names from %d start %d %s", | ||
366 | nodeid, inlen, inbuf); | ||
367 | goto out; | ||
368 | } | ||
369 | list = r->res_root_list.next; | ||
370 | } else { | ||
374 | list = ls->ls_root_list.next; | 371 | list = ls->ls_root_list.next; |
372 | } | ||
375 | 373 | ||
376 | for (offset = 0; list != &ls->ls_root_list; list = list->next) { | 374 | for (offset = 0; list != &ls->ls_root_list; list = list->next) { |
377 | r = list_entry(list, struct dlm_rsb, res_root_list); | 375 | r = list_entry(list, struct dlm_rsb, res_root_list); |
diff --git a/fs/dlm/dlm_internal.h b/fs/dlm/dlm_internal.h index d2fc2384c3be..ec61bbaf25df 100644 --- a/fs/dlm/dlm_internal.h +++ b/fs/dlm/dlm_internal.h | |||
@@ -570,5 +570,21 @@ static inline int dlm_no_directory(struct dlm_ls *ls) | |||
570 | return (ls->ls_exflags & DLM_LSFL_NODIR) ? 1 : 0; | 570 | return (ls->ls_exflags & DLM_LSFL_NODIR) ? 1 : 0; |
571 | } | 571 | } |
572 | 572 | ||
573 | int dlm_netlink_init(void); | ||
574 | void dlm_netlink_exit(void); | ||
575 | void dlm_timeout_warn(struct dlm_lkb *lkb); | ||
576 | |||
577 | #ifdef CONFIG_DLM_DEBUG | ||
578 | int dlm_register_debugfs(void); | ||
579 | void dlm_unregister_debugfs(void); | ||
580 | int dlm_create_debug_file(struct dlm_ls *ls); | ||
581 | void dlm_delete_debug_file(struct dlm_ls *ls); | ||
582 | #else | ||
583 | static inline int dlm_register_debugfs(void) { return 0; } | ||
584 | static inline void dlm_unregister_debugfs(void) { } | ||
585 | static inline int dlm_create_debug_file(struct dlm_ls *ls) { return 0; } | ||
586 | static inline void dlm_delete_debug_file(struct dlm_ls *ls) { } | ||
587 | #endif | ||
588 | |||
573 | #endif /* __DLM_INTERNAL_DOT_H__ */ | 589 | #endif /* __DLM_INTERNAL_DOT_H__ */ |
574 | 590 | ||
diff --git a/fs/dlm/lock.c b/fs/dlm/lock.c index 3915b8e14146..ff4a198fa677 100644 --- a/fs/dlm/lock.c +++ b/fs/dlm/lock.c | |||
@@ -1,7 +1,7 @@ | |||
1 | /****************************************************************************** | 1 | /****************************************************************************** |
2 | ******************************************************************************* | 2 | ******************************************************************************* |
3 | ** | 3 | ** |
4 | ** Copyright (C) 2005-2007 Red Hat, Inc. All rights reserved. | 4 | ** Copyright (C) 2005-2008 Red Hat, Inc. All rights reserved. |
5 | ** | 5 | ** |
6 | ** This copyrighted material is made available to anyone wishing to use, | 6 | ** This copyrighted material is made available to anyone wishing to use, |
7 | ** modify, copy, or redistribute it subject to the terms and conditions | 7 | ** modify, copy, or redistribute it subject to the terms and conditions |
@@ -88,7 +88,6 @@ static void __receive_convert_reply(struct dlm_rsb *r, struct dlm_lkb *lkb, | |||
88 | static int receive_extralen(struct dlm_message *ms); | 88 | static int receive_extralen(struct dlm_message *ms); |
89 | static void do_purge(struct dlm_ls *ls, int nodeid, int pid); | 89 | static void do_purge(struct dlm_ls *ls, int nodeid, int pid); |
90 | static void del_timeout(struct dlm_lkb *lkb); | 90 | static void del_timeout(struct dlm_lkb *lkb); |
91 | void dlm_timeout_warn(struct dlm_lkb *lkb); | ||
92 | 91 | ||
93 | /* | 92 | /* |
94 | * Lock compatibilty matrix - thanks Steve | 93 | * Lock compatibilty matrix - thanks Steve |
@@ -335,7 +334,7 @@ static struct dlm_rsb *create_rsb(struct dlm_ls *ls, char *name, int len) | |||
335 | { | 334 | { |
336 | struct dlm_rsb *r; | 335 | struct dlm_rsb *r; |
337 | 336 | ||
338 | r = allocate_rsb(ls, len); | 337 | r = dlm_allocate_rsb(ls, len); |
339 | if (!r) | 338 | if (!r) |
340 | return NULL; | 339 | return NULL; |
341 | 340 | ||
@@ -478,7 +477,7 @@ static int find_rsb(struct dlm_ls *ls, char *name, int namelen, | |||
478 | error = _search_rsb(ls, name, namelen, bucket, 0, &tmp); | 477 | error = _search_rsb(ls, name, namelen, bucket, 0, &tmp); |
479 | if (!error) { | 478 | if (!error) { |
480 | write_unlock(&ls->ls_rsbtbl[bucket].lock); | 479 | write_unlock(&ls->ls_rsbtbl[bucket].lock); |
481 | free_rsb(r); | 480 | dlm_free_rsb(r); |
482 | r = tmp; | 481 | r = tmp; |
483 | goto out; | 482 | goto out; |
484 | } | 483 | } |
@@ -490,12 +489,6 @@ static int find_rsb(struct dlm_ls *ls, char *name, int namelen, | |||
490 | return error; | 489 | return error; |
491 | } | 490 | } |
492 | 491 | ||
493 | int dlm_find_rsb(struct dlm_ls *ls, char *name, int namelen, | ||
494 | unsigned int flags, struct dlm_rsb **r_ret) | ||
495 | { | ||
496 | return find_rsb(ls, name, namelen, flags, r_ret); | ||
497 | } | ||
498 | |||
499 | /* This is only called to add a reference when the code already holds | 492 | /* This is only called to add a reference when the code already holds |
500 | a valid reference to the rsb, so there's no need for locking. */ | 493 | a valid reference to the rsb, so there's no need for locking. */ |
501 | 494 | ||
@@ -519,7 +512,7 @@ static void toss_rsb(struct kref *kref) | |||
519 | list_move(&r->res_hashchain, &ls->ls_rsbtbl[r->res_bucket].toss); | 512 | list_move(&r->res_hashchain, &ls->ls_rsbtbl[r->res_bucket].toss); |
520 | r->res_toss_time = jiffies; | 513 | r->res_toss_time = jiffies; |
521 | if (r->res_lvbptr) { | 514 | if (r->res_lvbptr) { |
522 | free_lvb(r->res_lvbptr); | 515 | dlm_free_lvb(r->res_lvbptr); |
523 | r->res_lvbptr = NULL; | 516 | r->res_lvbptr = NULL; |
524 | } | 517 | } |
525 | } | 518 | } |
@@ -589,7 +582,7 @@ static int create_lkb(struct dlm_ls *ls, struct dlm_lkb **lkb_ret) | |||
589 | uint32_t lkid = 0; | 582 | uint32_t lkid = 0; |
590 | uint16_t bucket; | 583 | uint16_t bucket; |
591 | 584 | ||
592 | lkb = allocate_lkb(ls); | 585 | lkb = dlm_allocate_lkb(ls); |
593 | if (!lkb) | 586 | if (!lkb) |
594 | return -ENOMEM; | 587 | return -ENOMEM; |
595 | 588 | ||
@@ -683,8 +676,8 @@ static int __put_lkb(struct dlm_ls *ls, struct dlm_lkb *lkb) | |||
683 | 676 | ||
684 | /* for local/process lkbs, lvbptr points to caller's lksb */ | 677 | /* for local/process lkbs, lvbptr points to caller's lksb */ |
685 | if (lkb->lkb_lvbptr && is_master_copy(lkb)) | 678 | if (lkb->lkb_lvbptr && is_master_copy(lkb)) |
686 | free_lvb(lkb->lkb_lvbptr); | 679 | dlm_free_lvb(lkb->lkb_lvbptr); |
687 | free_lkb(lkb); | 680 | dlm_free_lkb(lkb); |
688 | return 1; | 681 | return 1; |
689 | } else { | 682 | } else { |
690 | write_unlock(&ls->ls_lkbtbl[bucket].lock); | 683 | write_unlock(&ls->ls_lkbtbl[bucket].lock); |
@@ -988,7 +981,7 @@ static int shrink_bucket(struct dlm_ls *ls, int b) | |||
988 | 981 | ||
989 | if (is_master(r)) | 982 | if (is_master(r)) |
990 | dir_remove(r); | 983 | dir_remove(r); |
991 | free_rsb(r); | 984 | dlm_free_rsb(r); |
992 | count++; | 985 | count++; |
993 | } else { | 986 | } else { |
994 | write_unlock(&ls->ls_rsbtbl[b].lock); | 987 | write_unlock(&ls->ls_rsbtbl[b].lock); |
@@ -1171,7 +1164,7 @@ static void set_lvb_lock(struct dlm_rsb *r, struct dlm_lkb *lkb) | |||
1171 | return; | 1164 | return; |
1172 | 1165 | ||
1173 | if (!r->res_lvbptr) | 1166 | if (!r->res_lvbptr) |
1174 | r->res_lvbptr = allocate_lvb(r->res_ls); | 1167 | r->res_lvbptr = dlm_allocate_lvb(r->res_ls); |
1175 | 1168 | ||
1176 | if (!r->res_lvbptr) | 1169 | if (!r->res_lvbptr) |
1177 | return; | 1170 | return; |
@@ -1203,7 +1196,7 @@ static void set_lvb_unlock(struct dlm_rsb *r, struct dlm_lkb *lkb) | |||
1203 | return; | 1196 | return; |
1204 | 1197 | ||
1205 | if (!r->res_lvbptr) | 1198 | if (!r->res_lvbptr) |
1206 | r->res_lvbptr = allocate_lvb(r->res_ls); | 1199 | r->res_lvbptr = dlm_allocate_lvb(r->res_ls); |
1207 | 1200 | ||
1208 | if (!r->res_lvbptr) | 1201 | if (!r->res_lvbptr) |
1209 | return; | 1202 | return; |
@@ -1852,7 +1845,7 @@ static void send_blocking_asts_all(struct dlm_rsb *r, struct dlm_lkb *lkb) | |||
1852 | static int set_master(struct dlm_rsb *r, struct dlm_lkb *lkb) | 1845 | static int set_master(struct dlm_rsb *r, struct dlm_lkb *lkb) |
1853 | { | 1846 | { |
1854 | struct dlm_ls *ls = r->res_ls; | 1847 | struct dlm_ls *ls = r->res_ls; |
1855 | int error, dir_nodeid, ret_nodeid, our_nodeid = dlm_our_nodeid(); | 1848 | int i, error, dir_nodeid, ret_nodeid, our_nodeid = dlm_our_nodeid(); |
1856 | 1849 | ||
1857 | if (rsb_flag(r, RSB_MASTER_UNCERTAIN)) { | 1850 | if (rsb_flag(r, RSB_MASTER_UNCERTAIN)) { |
1858 | rsb_clear_flag(r, RSB_MASTER_UNCERTAIN); | 1851 | rsb_clear_flag(r, RSB_MASTER_UNCERTAIN); |
@@ -1886,7 +1879,7 @@ static int set_master(struct dlm_rsb *r, struct dlm_lkb *lkb) | |||
1886 | return 1; | 1879 | return 1; |
1887 | } | 1880 | } |
1888 | 1881 | ||
1889 | for (;;) { | 1882 | for (i = 0; i < 2; i++) { |
1890 | /* It's possible for dlm_scand to remove an old rsb for | 1883 | /* It's possible for dlm_scand to remove an old rsb for |
1891 | this same resource from the toss list, us to create | 1884 | this same resource from the toss list, us to create |
1892 | a new one, look up the master locally, and find it | 1885 | a new one, look up the master locally, and find it |
@@ -1900,6 +1893,8 @@ static int set_master(struct dlm_rsb *r, struct dlm_lkb *lkb) | |||
1900 | log_debug(ls, "dir_lookup error %d %s", error, r->res_name); | 1893 | log_debug(ls, "dir_lookup error %d %s", error, r->res_name); |
1901 | schedule(); | 1894 | schedule(); |
1902 | } | 1895 | } |
1896 | if (error && error != -EEXIST) | ||
1897 | return error; | ||
1903 | 1898 | ||
1904 | if (ret_nodeid == our_nodeid) { | 1899 | if (ret_nodeid == our_nodeid) { |
1905 | r->res_first_lkid = 0; | 1900 | r->res_first_lkid = 0; |
@@ -1941,8 +1936,11 @@ static void confirm_master(struct dlm_rsb *r, int error) | |||
1941 | break; | 1936 | break; |
1942 | 1937 | ||
1943 | case -EAGAIN: | 1938 | case -EAGAIN: |
1944 | /* the remote master didn't queue our NOQUEUE request; | 1939 | case -EBADR: |
1945 | make a waiting lkb the first_lkid */ | 1940 | case -ENOTBLK: |
1941 | /* the remote request failed and won't be retried (it was | ||
1942 | a NOQUEUE, or has been canceled/unlocked); make a waiting | ||
1943 | lkb the first_lkid */ | ||
1946 | 1944 | ||
1947 | r->res_first_lkid = 0; | 1945 | r->res_first_lkid = 0; |
1948 | 1946 | ||
@@ -2108,17 +2106,18 @@ static int validate_unlock_args(struct dlm_lkb *lkb, struct dlm_args *args) | |||
2108 | /* an lkb may be waiting for an rsb lookup to complete where the | 2106 | /* an lkb may be waiting for an rsb lookup to complete where the |
2109 | lookup was initiated by another lock */ | 2107 | lookup was initiated by another lock */ |
2110 | 2108 | ||
2111 | if (args->flags & (DLM_LKF_CANCEL | DLM_LKF_FORCEUNLOCK)) { | 2109 | if (!list_empty(&lkb->lkb_rsb_lookup)) { |
2112 | if (!list_empty(&lkb->lkb_rsb_lookup)) { | 2110 | if (args->flags & (DLM_LKF_CANCEL | DLM_LKF_FORCEUNLOCK)) { |
2113 | log_debug(ls, "unlock on rsb_lookup %x", lkb->lkb_id); | 2111 | log_debug(ls, "unlock on rsb_lookup %x", lkb->lkb_id); |
2114 | list_del_init(&lkb->lkb_rsb_lookup); | 2112 | list_del_init(&lkb->lkb_rsb_lookup); |
2115 | queue_cast(lkb->lkb_resource, lkb, | 2113 | queue_cast(lkb->lkb_resource, lkb, |
2116 | args->flags & DLM_LKF_CANCEL ? | 2114 | args->flags & DLM_LKF_CANCEL ? |
2117 | -DLM_ECANCEL : -DLM_EUNLOCK); | 2115 | -DLM_ECANCEL : -DLM_EUNLOCK); |
2118 | unhold_lkb(lkb); /* undoes create_lkb() */ | 2116 | unhold_lkb(lkb); /* undoes create_lkb() */ |
2119 | rv = -EBUSY; | ||
2120 | goto out; | ||
2121 | } | 2117 | } |
2118 | /* caller changes -EBUSY to 0 for CANCEL and FORCEUNLOCK */ | ||
2119 | rv = -EBUSY; | ||
2120 | goto out; | ||
2122 | } | 2121 | } |
2123 | 2122 | ||
2124 | /* cancel not allowed with another cancel/unlock in progress */ | 2123 | /* cancel not allowed with another cancel/unlock in progress */ |
@@ -2986,7 +2985,7 @@ static int receive_lvb(struct dlm_ls *ls, struct dlm_lkb *lkb, | |||
2986 | 2985 | ||
2987 | if (lkb->lkb_exflags & DLM_LKF_VALBLK) { | 2986 | if (lkb->lkb_exflags & DLM_LKF_VALBLK) { |
2988 | if (!lkb->lkb_lvbptr) | 2987 | if (!lkb->lkb_lvbptr) |
2989 | lkb->lkb_lvbptr = allocate_lvb(ls); | 2988 | lkb->lkb_lvbptr = dlm_allocate_lvb(ls); |
2990 | if (!lkb->lkb_lvbptr) | 2989 | if (!lkb->lkb_lvbptr) |
2991 | return -ENOMEM; | 2990 | return -ENOMEM; |
2992 | len = receive_extralen(ms); | 2991 | len = receive_extralen(ms); |
@@ -3006,11 +3005,9 @@ static int receive_request_args(struct dlm_ls *ls, struct dlm_lkb *lkb, | |||
3006 | lkb->lkb_bastaddr = (void *) (long) (ms->m_asts & AST_BAST); | 3005 | lkb->lkb_bastaddr = (void *) (long) (ms->m_asts & AST_BAST); |
3007 | lkb->lkb_astaddr = (void *) (long) (ms->m_asts & AST_COMP); | 3006 | lkb->lkb_astaddr = (void *) (long) (ms->m_asts & AST_COMP); |
3008 | 3007 | ||
3009 | DLM_ASSERT(is_master_copy(lkb), dlm_print_lkb(lkb);); | ||
3010 | |||
3011 | if (lkb->lkb_exflags & DLM_LKF_VALBLK) { | 3008 | if (lkb->lkb_exflags & DLM_LKF_VALBLK) { |
3012 | /* lkb was just created so there won't be an lvb yet */ | 3009 | /* lkb was just created so there won't be an lvb yet */ |
3013 | lkb->lkb_lvbptr = allocate_lvb(ls); | 3010 | lkb->lkb_lvbptr = dlm_allocate_lvb(ls); |
3014 | if (!lkb->lkb_lvbptr) | 3011 | if (!lkb->lkb_lvbptr) |
3015 | return -ENOMEM; | 3012 | return -ENOMEM; |
3016 | } | 3013 | } |
@@ -3021,16 +3018,6 @@ static int receive_request_args(struct dlm_ls *ls, struct dlm_lkb *lkb, | |||
3021 | static int receive_convert_args(struct dlm_ls *ls, struct dlm_lkb *lkb, | 3018 | static int receive_convert_args(struct dlm_ls *ls, struct dlm_lkb *lkb, |
3022 | struct dlm_message *ms) | 3019 | struct dlm_message *ms) |
3023 | { | 3020 | { |
3024 | if (lkb->lkb_nodeid != ms->m_header.h_nodeid) { | ||
3025 | log_error(ls, "convert_args nodeid %d %d lkid %x %x", | ||
3026 | lkb->lkb_nodeid, ms->m_header.h_nodeid, | ||
3027 | lkb->lkb_id, lkb->lkb_remid); | ||
3028 | return -EINVAL; | ||
3029 | } | ||
3030 | |||
3031 | if (!is_master_copy(lkb)) | ||
3032 | return -EINVAL; | ||
3033 | |||
3034 | if (lkb->lkb_status != DLM_LKSTS_GRANTED) | 3021 | if (lkb->lkb_status != DLM_LKSTS_GRANTED) |
3035 | return -EBUSY; | 3022 | return -EBUSY; |
3036 | 3023 | ||
@@ -3046,8 +3033,6 @@ static int receive_convert_args(struct dlm_ls *ls, struct dlm_lkb *lkb, | |||
3046 | static int receive_unlock_args(struct dlm_ls *ls, struct dlm_lkb *lkb, | 3033 | static int receive_unlock_args(struct dlm_ls *ls, struct dlm_lkb *lkb, |
3047 | struct dlm_message *ms) | 3034 | struct dlm_message *ms) |
3048 | { | 3035 | { |
3049 | if (!is_master_copy(lkb)) | ||
3050 | return -EINVAL; | ||
3051 | if (receive_lvb(ls, lkb, ms)) | 3036 | if (receive_lvb(ls, lkb, ms)) |
3052 | return -ENOMEM; | 3037 | return -ENOMEM; |
3053 | return 0; | 3038 | return 0; |
@@ -3063,6 +3048,50 @@ static void setup_stub_lkb(struct dlm_ls *ls, struct dlm_message *ms) | |||
3063 | lkb->lkb_remid = ms->m_lkid; | 3048 | lkb->lkb_remid = ms->m_lkid; |
3064 | } | 3049 | } |
3065 | 3050 | ||
3051 | /* This is called after the rsb is locked so that we can safely inspect | ||
3052 | fields in the lkb. */ | ||
3053 | |||
3054 | static int validate_message(struct dlm_lkb *lkb, struct dlm_message *ms) | ||
3055 | { | ||
3056 | int from = ms->m_header.h_nodeid; | ||
3057 | int error = 0; | ||
3058 | |||
3059 | switch (ms->m_type) { | ||
3060 | case DLM_MSG_CONVERT: | ||
3061 | case DLM_MSG_UNLOCK: | ||
3062 | case DLM_MSG_CANCEL: | ||
3063 | if (!is_master_copy(lkb) || lkb->lkb_nodeid != from) | ||
3064 | error = -EINVAL; | ||
3065 | break; | ||
3066 | |||
3067 | case DLM_MSG_CONVERT_REPLY: | ||
3068 | case DLM_MSG_UNLOCK_REPLY: | ||
3069 | case DLM_MSG_CANCEL_REPLY: | ||
3070 | case DLM_MSG_GRANT: | ||
3071 | case DLM_MSG_BAST: | ||
3072 | if (!is_process_copy(lkb) || lkb->lkb_nodeid != from) | ||
3073 | error = -EINVAL; | ||
3074 | break; | ||
3075 | |||
3076 | case DLM_MSG_REQUEST_REPLY: | ||
3077 | if (!is_process_copy(lkb)) | ||
3078 | error = -EINVAL; | ||
3079 | else if (lkb->lkb_nodeid != -1 && lkb->lkb_nodeid != from) | ||
3080 | error = -EINVAL; | ||
3081 | break; | ||
3082 | |||
3083 | default: | ||
3084 | error = -EINVAL; | ||
3085 | } | ||
3086 | |||
3087 | if (error) | ||
3088 | log_error(lkb->lkb_resource->res_ls, | ||
3089 | "ignore invalid message %d from %d %x %x %x %d", | ||
3090 | ms->m_type, from, lkb->lkb_id, lkb->lkb_remid, | ||
3091 | lkb->lkb_flags, lkb->lkb_nodeid); | ||
3092 | return error; | ||
3093 | } | ||
3094 | |||
3066 | static void receive_request(struct dlm_ls *ls, struct dlm_message *ms) | 3095 | static void receive_request(struct dlm_ls *ls, struct dlm_message *ms) |
3067 | { | 3096 | { |
3068 | struct dlm_lkb *lkb; | 3097 | struct dlm_lkb *lkb; |
@@ -3124,17 +3153,21 @@ static void receive_convert(struct dlm_ls *ls, struct dlm_message *ms) | |||
3124 | hold_rsb(r); | 3153 | hold_rsb(r); |
3125 | lock_rsb(r); | 3154 | lock_rsb(r); |
3126 | 3155 | ||
3156 | error = validate_message(lkb, ms); | ||
3157 | if (error) | ||
3158 | goto out; | ||
3159 | |||
3127 | receive_flags(lkb, ms); | 3160 | receive_flags(lkb, ms); |
3128 | error = receive_convert_args(ls, lkb, ms); | 3161 | error = receive_convert_args(ls, lkb, ms); |
3129 | if (error) | 3162 | if (error) |
3130 | goto out; | 3163 | goto out_reply; |
3131 | reply = !down_conversion(lkb); | 3164 | reply = !down_conversion(lkb); |
3132 | 3165 | ||
3133 | error = do_convert(r, lkb); | 3166 | error = do_convert(r, lkb); |
3134 | out: | 3167 | out_reply: |
3135 | if (reply) | 3168 | if (reply) |
3136 | send_convert_reply(r, lkb, error); | 3169 | send_convert_reply(r, lkb, error); |
3137 | 3170 | out: | |
3138 | unlock_rsb(r); | 3171 | unlock_rsb(r); |
3139 | put_rsb(r); | 3172 | put_rsb(r); |
3140 | dlm_put_lkb(lkb); | 3173 | dlm_put_lkb(lkb); |
@@ -3160,15 +3193,19 @@ static void receive_unlock(struct dlm_ls *ls, struct dlm_message *ms) | |||
3160 | hold_rsb(r); | 3193 | hold_rsb(r); |
3161 | lock_rsb(r); | 3194 | lock_rsb(r); |
3162 | 3195 | ||
3196 | error = validate_message(lkb, ms); | ||
3197 | if (error) | ||
3198 | goto out; | ||
3199 | |||
3163 | receive_flags(lkb, ms); | 3200 | receive_flags(lkb, ms); |
3164 | error = receive_unlock_args(ls, lkb, ms); | 3201 | error = receive_unlock_args(ls, lkb, ms); |
3165 | if (error) | 3202 | if (error) |
3166 | goto out; | 3203 | goto out_reply; |
3167 | 3204 | ||
3168 | error = do_unlock(r, lkb); | 3205 | error = do_unlock(r, lkb); |
3169 | out: | 3206 | out_reply: |
3170 | send_unlock_reply(r, lkb, error); | 3207 | send_unlock_reply(r, lkb, error); |
3171 | 3208 | out: | |
3172 | unlock_rsb(r); | 3209 | unlock_rsb(r); |
3173 | put_rsb(r); | 3210 | put_rsb(r); |
3174 | dlm_put_lkb(lkb); | 3211 | dlm_put_lkb(lkb); |
@@ -3196,9 +3233,13 @@ static void receive_cancel(struct dlm_ls *ls, struct dlm_message *ms) | |||
3196 | hold_rsb(r); | 3233 | hold_rsb(r); |
3197 | lock_rsb(r); | 3234 | lock_rsb(r); |
3198 | 3235 | ||
3236 | error = validate_message(lkb, ms); | ||
3237 | if (error) | ||
3238 | goto out; | ||
3239 | |||
3199 | error = do_cancel(r, lkb); | 3240 | error = do_cancel(r, lkb); |
3200 | send_cancel_reply(r, lkb, error); | 3241 | send_cancel_reply(r, lkb, error); |
3201 | 3242 | out: | |
3202 | unlock_rsb(r); | 3243 | unlock_rsb(r); |
3203 | put_rsb(r); | 3244 | put_rsb(r); |
3204 | dlm_put_lkb(lkb); | 3245 | dlm_put_lkb(lkb); |
@@ -3217,22 +3258,26 @@ static void receive_grant(struct dlm_ls *ls, struct dlm_message *ms) | |||
3217 | 3258 | ||
3218 | error = find_lkb(ls, ms->m_remid, &lkb); | 3259 | error = find_lkb(ls, ms->m_remid, &lkb); |
3219 | if (error) { | 3260 | if (error) { |
3220 | log_error(ls, "receive_grant no lkb"); | 3261 | log_debug(ls, "receive_grant from %d no lkb %x", |
3262 | ms->m_header.h_nodeid, ms->m_remid); | ||
3221 | return; | 3263 | return; |
3222 | } | 3264 | } |
3223 | DLM_ASSERT(is_process_copy(lkb), dlm_print_lkb(lkb);); | ||
3224 | 3265 | ||
3225 | r = lkb->lkb_resource; | 3266 | r = lkb->lkb_resource; |
3226 | 3267 | ||
3227 | hold_rsb(r); | 3268 | hold_rsb(r); |
3228 | lock_rsb(r); | 3269 | lock_rsb(r); |
3229 | 3270 | ||
3271 | error = validate_message(lkb, ms); | ||
3272 | if (error) | ||
3273 | goto out; | ||
3274 | |||
3230 | receive_flags_reply(lkb, ms); | 3275 | receive_flags_reply(lkb, ms); |
3231 | if (is_altmode(lkb)) | 3276 | if (is_altmode(lkb)) |
3232 | munge_altmode(lkb, ms); | 3277 | munge_altmode(lkb, ms); |
3233 | grant_lock_pc(r, lkb, ms); | 3278 | grant_lock_pc(r, lkb, ms); |
3234 | queue_cast(r, lkb, 0); | 3279 | queue_cast(r, lkb, 0); |
3235 | 3280 | out: | |
3236 | unlock_rsb(r); | 3281 | unlock_rsb(r); |
3237 | put_rsb(r); | 3282 | put_rsb(r); |
3238 | dlm_put_lkb(lkb); | 3283 | dlm_put_lkb(lkb); |
@@ -3246,18 +3291,22 @@ static void receive_bast(struct dlm_ls *ls, struct dlm_message *ms) | |||
3246 | 3291 | ||
3247 | error = find_lkb(ls, ms->m_remid, &lkb); | 3292 | error = find_lkb(ls, ms->m_remid, &lkb); |
3248 | if (error) { | 3293 | if (error) { |
3249 | log_error(ls, "receive_bast no lkb"); | 3294 | log_debug(ls, "receive_bast from %d no lkb %x", |
3295 | ms->m_header.h_nodeid, ms->m_remid); | ||
3250 | return; | 3296 | return; |
3251 | } | 3297 | } |
3252 | DLM_ASSERT(is_process_copy(lkb), dlm_print_lkb(lkb);); | ||
3253 | 3298 | ||
3254 | r = lkb->lkb_resource; | 3299 | r = lkb->lkb_resource; |
3255 | 3300 | ||
3256 | hold_rsb(r); | 3301 | hold_rsb(r); |
3257 | lock_rsb(r); | 3302 | lock_rsb(r); |
3258 | 3303 | ||
3259 | queue_bast(r, lkb, ms->m_bastmode); | 3304 | error = validate_message(lkb, ms); |
3305 | if (error) | ||
3306 | goto out; | ||
3260 | 3307 | ||
3308 | queue_bast(r, lkb, ms->m_bastmode); | ||
3309 | out: | ||
3261 | unlock_rsb(r); | 3310 | unlock_rsb(r); |
3262 | put_rsb(r); | 3311 | put_rsb(r); |
3263 | dlm_put_lkb(lkb); | 3312 | dlm_put_lkb(lkb); |
@@ -3323,15 +3372,19 @@ static void receive_request_reply(struct dlm_ls *ls, struct dlm_message *ms) | |||
3323 | 3372 | ||
3324 | error = find_lkb(ls, ms->m_remid, &lkb); | 3373 | error = find_lkb(ls, ms->m_remid, &lkb); |
3325 | if (error) { | 3374 | if (error) { |
3326 | log_error(ls, "receive_request_reply no lkb"); | 3375 | log_debug(ls, "receive_request_reply from %d no lkb %x", |
3376 | ms->m_header.h_nodeid, ms->m_remid); | ||
3327 | return; | 3377 | return; |
3328 | } | 3378 | } |
3329 | DLM_ASSERT(is_process_copy(lkb), dlm_print_lkb(lkb);); | ||
3330 | 3379 | ||
3331 | r = lkb->lkb_resource; | 3380 | r = lkb->lkb_resource; |
3332 | hold_rsb(r); | 3381 | hold_rsb(r); |
3333 | lock_rsb(r); | 3382 | lock_rsb(r); |
3334 | 3383 | ||
3384 | error = validate_message(lkb, ms); | ||
3385 | if (error) | ||
3386 | goto out; | ||
3387 | |||
3335 | mstype = lkb->lkb_wait_type; | 3388 | mstype = lkb->lkb_wait_type; |
3336 | error = remove_from_waiters(lkb, DLM_MSG_REQUEST_REPLY); | 3389 | error = remove_from_waiters(lkb, DLM_MSG_REQUEST_REPLY); |
3337 | if (error) | 3390 | if (error) |
@@ -3383,6 +3436,7 @@ static void receive_request_reply(struct dlm_ls *ls, struct dlm_message *ms) | |||
3383 | if (is_overlap(lkb)) { | 3436 | if (is_overlap(lkb)) { |
3384 | /* we'll ignore error in cancel/unlock reply */ | 3437 | /* we'll ignore error in cancel/unlock reply */ |
3385 | queue_cast_overlap(r, lkb); | 3438 | queue_cast_overlap(r, lkb); |
3439 | confirm_master(r, result); | ||
3386 | unhold_lkb(lkb); /* undoes create_lkb() */ | 3440 | unhold_lkb(lkb); /* undoes create_lkb() */ |
3387 | } else | 3441 | } else |
3388 | _request_lock(r, lkb); | 3442 | _request_lock(r, lkb); |
@@ -3463,6 +3517,10 @@ static void _receive_convert_reply(struct dlm_lkb *lkb, struct dlm_message *ms) | |||
3463 | hold_rsb(r); | 3517 | hold_rsb(r); |
3464 | lock_rsb(r); | 3518 | lock_rsb(r); |
3465 | 3519 | ||
3520 | error = validate_message(lkb, ms); | ||
3521 | if (error) | ||
3522 | goto out; | ||
3523 | |||
3466 | /* stub reply can happen with waiters_mutex held */ | 3524 | /* stub reply can happen with waiters_mutex held */ |
3467 | error = remove_from_waiters_ms(lkb, ms); | 3525 | error = remove_from_waiters_ms(lkb, ms); |
3468 | if (error) | 3526 | if (error) |
@@ -3481,10 +3539,10 @@ static void receive_convert_reply(struct dlm_ls *ls, struct dlm_message *ms) | |||
3481 | 3539 | ||
3482 | error = find_lkb(ls, ms->m_remid, &lkb); | 3540 | error = find_lkb(ls, ms->m_remid, &lkb); |
3483 | if (error) { | 3541 | if (error) { |
3484 | log_error(ls, "receive_convert_reply no lkb"); | 3542 | log_debug(ls, "receive_convert_reply from %d no lkb %x", |
3543 | ms->m_header.h_nodeid, ms->m_remid); | ||
3485 | return; | 3544 | return; |
3486 | } | 3545 | } |
3487 | DLM_ASSERT(is_process_copy(lkb), dlm_print_lkb(lkb);); | ||
3488 | 3546 | ||
3489 | _receive_convert_reply(lkb, ms); | 3547 | _receive_convert_reply(lkb, ms); |
3490 | dlm_put_lkb(lkb); | 3548 | dlm_put_lkb(lkb); |
@@ -3498,6 +3556,10 @@ static void _receive_unlock_reply(struct dlm_lkb *lkb, struct dlm_message *ms) | |||
3498 | hold_rsb(r); | 3556 | hold_rsb(r); |
3499 | lock_rsb(r); | 3557 | lock_rsb(r); |
3500 | 3558 | ||
3559 | error = validate_message(lkb, ms); | ||
3560 | if (error) | ||
3561 | goto out; | ||
3562 | |||
3501 | /* stub reply can happen with waiters_mutex held */ | 3563 | /* stub reply can happen with waiters_mutex held */ |
3502 | error = remove_from_waiters_ms(lkb, ms); | 3564 | error = remove_from_waiters_ms(lkb, ms); |
3503 | if (error) | 3565 | if (error) |
@@ -3529,10 +3591,10 @@ static void receive_unlock_reply(struct dlm_ls *ls, struct dlm_message *ms) | |||
3529 | 3591 | ||
3530 | error = find_lkb(ls, ms->m_remid, &lkb); | 3592 | error = find_lkb(ls, ms->m_remid, &lkb); |
3531 | if (error) { | 3593 | if (error) { |
3532 | log_error(ls, "receive_unlock_reply no lkb"); | 3594 | log_debug(ls, "receive_unlock_reply from %d no lkb %x", |
3595 | ms->m_header.h_nodeid, ms->m_remid); | ||
3533 | return; | 3596 | return; |
3534 | } | 3597 | } |
3535 | DLM_ASSERT(is_process_copy(lkb), dlm_print_lkb(lkb);); | ||
3536 | 3598 | ||
3537 | _receive_unlock_reply(lkb, ms); | 3599 | _receive_unlock_reply(lkb, ms); |
3538 | dlm_put_lkb(lkb); | 3600 | dlm_put_lkb(lkb); |
@@ -3546,6 +3608,10 @@ static void _receive_cancel_reply(struct dlm_lkb *lkb, struct dlm_message *ms) | |||
3546 | hold_rsb(r); | 3608 | hold_rsb(r); |
3547 | lock_rsb(r); | 3609 | lock_rsb(r); |
3548 | 3610 | ||
3611 | error = validate_message(lkb, ms); | ||
3612 | if (error) | ||
3613 | goto out; | ||
3614 | |||
3549 | /* stub reply can happen with waiters_mutex held */ | 3615 | /* stub reply can happen with waiters_mutex held */ |
3550 | error = remove_from_waiters_ms(lkb, ms); | 3616 | error = remove_from_waiters_ms(lkb, ms); |
3551 | if (error) | 3617 | if (error) |
@@ -3577,10 +3643,10 @@ static void receive_cancel_reply(struct dlm_ls *ls, struct dlm_message *ms) | |||
3577 | 3643 | ||
3578 | error = find_lkb(ls, ms->m_remid, &lkb); | 3644 | error = find_lkb(ls, ms->m_remid, &lkb); |
3579 | if (error) { | 3645 | if (error) { |
3580 | log_error(ls, "receive_cancel_reply no lkb"); | 3646 | log_debug(ls, "receive_cancel_reply from %d no lkb %x", |
3647 | ms->m_header.h_nodeid, ms->m_remid); | ||
3581 | return; | 3648 | return; |
3582 | } | 3649 | } |
3583 | DLM_ASSERT(is_process_copy(lkb), dlm_print_lkb(lkb);); | ||
3584 | 3650 | ||
3585 | _receive_cancel_reply(lkb, ms); | 3651 | _receive_cancel_reply(lkb, ms); |
3586 | dlm_put_lkb(lkb); | 3652 | dlm_put_lkb(lkb); |
@@ -3640,6 +3706,13 @@ static void receive_lookup_reply(struct dlm_ls *ls, struct dlm_message *ms) | |||
3640 | 3706 | ||
3641 | static void _receive_message(struct dlm_ls *ls, struct dlm_message *ms) | 3707 | static void _receive_message(struct dlm_ls *ls, struct dlm_message *ms) |
3642 | { | 3708 | { |
3709 | if (!dlm_is_member(ls, ms->m_header.h_nodeid)) { | ||
3710 | log_debug(ls, "ignore non-member message %d from %d %x %x %d", | ||
3711 | ms->m_type, ms->m_header.h_nodeid, ms->m_lkid, | ||
3712 | ms->m_remid, ms->m_result); | ||
3713 | return; | ||
3714 | } | ||
3715 | |||
3643 | switch (ms->m_type) { | 3716 | switch (ms->m_type) { |
3644 | 3717 | ||
3645 | /* messages sent to a master node */ | 3718 | /* messages sent to a master node */ |
@@ -3778,8 +3851,9 @@ void dlm_receive_buffer(struct dlm_header *hd, int nodeid) | |||
3778 | 3851 | ||
3779 | ls = dlm_find_lockspace_global(hd->h_lockspace); | 3852 | ls = dlm_find_lockspace_global(hd->h_lockspace); |
3780 | if (!ls) { | 3853 | if (!ls) { |
3781 | log_print("invalid h_lockspace %x from %d cmd %d type %d", | 3854 | if (dlm_config.ci_log_debug) |
3782 | hd->h_lockspace, nodeid, hd->h_cmd, type); | 3855 | log_print("invalid lockspace %x from %d cmd %d type %d", |
3856 | hd->h_lockspace, nodeid, hd->h_cmd, type); | ||
3783 | 3857 | ||
3784 | if (hd->h_cmd == DLM_RCOM && type == DLM_RCOM_STATUS) | 3858 | if (hd->h_cmd == DLM_RCOM && type == DLM_RCOM_STATUS) |
3785 | dlm_send_ls_not_ready(nodeid, rc); | 3859 | dlm_send_ls_not_ready(nodeid, rc); |
@@ -3806,6 +3880,7 @@ static void recover_convert_waiter(struct dlm_ls *ls, struct dlm_lkb *lkb) | |||
3806 | ls->ls_stub_ms.m_type = DLM_MSG_CONVERT_REPLY; | 3880 | ls->ls_stub_ms.m_type = DLM_MSG_CONVERT_REPLY; |
3807 | ls->ls_stub_ms.m_result = -EINPROGRESS; | 3881 | ls->ls_stub_ms.m_result = -EINPROGRESS; |
3808 | ls->ls_stub_ms.m_flags = lkb->lkb_flags; | 3882 | ls->ls_stub_ms.m_flags = lkb->lkb_flags; |
3883 | ls->ls_stub_ms.m_header.h_nodeid = lkb->lkb_nodeid; | ||
3809 | _receive_convert_reply(lkb, &ls->ls_stub_ms); | 3884 | _receive_convert_reply(lkb, &ls->ls_stub_ms); |
3810 | 3885 | ||
3811 | /* Same special case as in receive_rcom_lock_args() */ | 3886 | /* Same special case as in receive_rcom_lock_args() */ |
@@ -3847,6 +3922,7 @@ static int waiter_needs_recovery(struct dlm_ls *ls, struct dlm_lkb *lkb) | |||
3847 | void dlm_recover_waiters_pre(struct dlm_ls *ls) | 3922 | void dlm_recover_waiters_pre(struct dlm_ls *ls) |
3848 | { | 3923 | { |
3849 | struct dlm_lkb *lkb, *safe; | 3924 | struct dlm_lkb *lkb, *safe; |
3925 | int wait_type, stub_unlock_result, stub_cancel_result; | ||
3850 | 3926 | ||
3851 | mutex_lock(&ls->ls_waiters_mutex); | 3927 | mutex_lock(&ls->ls_waiters_mutex); |
3852 | 3928 | ||
@@ -3865,7 +3941,33 @@ void dlm_recover_waiters_pre(struct dlm_ls *ls) | |||
3865 | if (!waiter_needs_recovery(ls, lkb)) | 3941 | if (!waiter_needs_recovery(ls, lkb)) |
3866 | continue; | 3942 | continue; |
3867 | 3943 | ||
3868 | switch (lkb->lkb_wait_type) { | 3944 | wait_type = lkb->lkb_wait_type; |
3945 | stub_unlock_result = -DLM_EUNLOCK; | ||
3946 | stub_cancel_result = -DLM_ECANCEL; | ||
3947 | |||
3948 | /* Main reply may have been received leaving a zero wait_type, | ||
3949 | but a reply for the overlapping op may not have been | ||
3950 | received. In that case we need to fake the appropriate | ||
3951 | reply for the overlap op. */ | ||
3952 | |||
3953 | if (!wait_type) { | ||
3954 | if (is_overlap_cancel(lkb)) { | ||
3955 | wait_type = DLM_MSG_CANCEL; | ||
3956 | if (lkb->lkb_grmode == DLM_LOCK_IV) | ||
3957 | stub_cancel_result = 0; | ||
3958 | } | ||
3959 | if (is_overlap_unlock(lkb)) { | ||
3960 | wait_type = DLM_MSG_UNLOCK; | ||
3961 | if (lkb->lkb_grmode == DLM_LOCK_IV) | ||
3962 | stub_unlock_result = -ENOENT; | ||
3963 | } | ||
3964 | |||
3965 | log_debug(ls, "rwpre overlap %x %x %d %d %d", | ||
3966 | lkb->lkb_id, lkb->lkb_flags, wait_type, | ||
3967 | stub_cancel_result, stub_unlock_result); | ||
3968 | } | ||
3969 | |||
3970 | switch (wait_type) { | ||
3869 | 3971 | ||
3870 | case DLM_MSG_REQUEST: | 3972 | case DLM_MSG_REQUEST: |
3871 | lkb->lkb_flags |= DLM_IFL_RESEND; | 3973 | lkb->lkb_flags |= DLM_IFL_RESEND; |
@@ -3878,8 +3980,9 @@ void dlm_recover_waiters_pre(struct dlm_ls *ls) | |||
3878 | case DLM_MSG_UNLOCK: | 3980 | case DLM_MSG_UNLOCK: |
3879 | hold_lkb(lkb); | 3981 | hold_lkb(lkb); |
3880 | ls->ls_stub_ms.m_type = DLM_MSG_UNLOCK_REPLY; | 3982 | ls->ls_stub_ms.m_type = DLM_MSG_UNLOCK_REPLY; |
3881 | ls->ls_stub_ms.m_result = -DLM_EUNLOCK; | 3983 | ls->ls_stub_ms.m_result = stub_unlock_result; |
3882 | ls->ls_stub_ms.m_flags = lkb->lkb_flags; | 3984 | ls->ls_stub_ms.m_flags = lkb->lkb_flags; |
3985 | ls->ls_stub_ms.m_header.h_nodeid = lkb->lkb_nodeid; | ||
3883 | _receive_unlock_reply(lkb, &ls->ls_stub_ms); | 3986 | _receive_unlock_reply(lkb, &ls->ls_stub_ms); |
3884 | dlm_put_lkb(lkb); | 3987 | dlm_put_lkb(lkb); |
3885 | break; | 3988 | break; |
@@ -3887,15 +3990,16 @@ void dlm_recover_waiters_pre(struct dlm_ls *ls) | |||
3887 | case DLM_MSG_CANCEL: | 3990 | case DLM_MSG_CANCEL: |
3888 | hold_lkb(lkb); | 3991 | hold_lkb(lkb); |
3889 | ls->ls_stub_ms.m_type = DLM_MSG_CANCEL_REPLY; | 3992 | ls->ls_stub_ms.m_type = DLM_MSG_CANCEL_REPLY; |
3890 | ls->ls_stub_ms.m_result = -DLM_ECANCEL; | 3993 | ls->ls_stub_ms.m_result = stub_cancel_result; |
3891 | ls->ls_stub_ms.m_flags = lkb->lkb_flags; | 3994 | ls->ls_stub_ms.m_flags = lkb->lkb_flags; |
3995 | ls->ls_stub_ms.m_header.h_nodeid = lkb->lkb_nodeid; | ||
3892 | _receive_cancel_reply(lkb, &ls->ls_stub_ms); | 3996 | _receive_cancel_reply(lkb, &ls->ls_stub_ms); |
3893 | dlm_put_lkb(lkb); | 3997 | dlm_put_lkb(lkb); |
3894 | break; | 3998 | break; |
3895 | 3999 | ||
3896 | default: | 4000 | default: |
3897 | log_error(ls, "invalid lkb wait_type %d", | 4001 | log_error(ls, "invalid lkb wait_type %d %d", |
3898 | lkb->lkb_wait_type); | 4002 | lkb->lkb_wait_type, wait_type); |
3899 | } | 4003 | } |
3900 | schedule(); | 4004 | schedule(); |
3901 | } | 4005 | } |
@@ -4184,7 +4288,7 @@ static int receive_rcom_lock_args(struct dlm_ls *ls, struct dlm_lkb *lkb, | |||
4184 | lkb->lkb_astaddr = (void *) (long) (rl->rl_asts & AST_COMP); | 4288 | lkb->lkb_astaddr = (void *) (long) (rl->rl_asts & AST_COMP); |
4185 | 4289 | ||
4186 | if (lkb->lkb_exflags & DLM_LKF_VALBLK) { | 4290 | if (lkb->lkb_exflags & DLM_LKF_VALBLK) { |
4187 | lkb->lkb_lvbptr = allocate_lvb(ls); | 4291 | lkb->lkb_lvbptr = dlm_allocate_lvb(ls); |
4188 | if (!lkb->lkb_lvbptr) | 4292 | if (!lkb->lkb_lvbptr) |
4189 | return -ENOMEM; | 4293 | return -ENOMEM; |
4190 | lvblen = rc->rc_header.h_length - sizeof(struct dlm_rcom) - | 4294 | lvblen = rc->rc_header.h_length - sizeof(struct dlm_rcom) - |
@@ -4259,7 +4363,7 @@ int dlm_recover_master_copy(struct dlm_ls *ls, struct dlm_rcom *rc) | |||
4259 | put_rsb(r); | 4363 | put_rsb(r); |
4260 | out: | 4364 | out: |
4261 | if (error) | 4365 | if (error) |
4262 | log_print("recover_master_copy %d %x", error, rl->rl_lkid); | 4366 | log_debug(ls, "recover_master_copy %d %x", error, rl->rl_lkid); |
4263 | rl->rl_result = error; | 4367 | rl->rl_result = error; |
4264 | return error; | 4368 | return error; |
4265 | } | 4369 | } |
@@ -4342,7 +4446,7 @@ int dlm_user_request(struct dlm_ls *ls, struct dlm_user_args *ua, | |||
4342 | } | 4446 | } |
4343 | } | 4447 | } |
4344 | 4448 | ||
4345 | /* After ua is attached to lkb it will be freed by free_lkb(). | 4449 | /* After ua is attached to lkb it will be freed by dlm_free_lkb(). |
4346 | When DLM_IFL_USER is set, the dlm knows that this is a userspace | 4450 | When DLM_IFL_USER is set, the dlm knows that this is a userspace |
4347 | lock and that lkb_astparam is the dlm_user_args structure. */ | 4451 | lock and that lkb_astparam is the dlm_user_args structure. */ |
4348 | 4452 | ||
@@ -4679,6 +4783,7 @@ void dlm_clear_proc_locks(struct dlm_ls *ls, struct dlm_user_proc *proc) | |||
4679 | } | 4783 | } |
4680 | 4784 | ||
4681 | list_for_each_entry_safe(lkb, safe, &proc->asts, lkb_astqueue) { | 4785 | list_for_each_entry_safe(lkb, safe, &proc->asts, lkb_astqueue) { |
4786 | lkb->lkb_ast_type = 0; | ||
4682 | list_del(&lkb->lkb_astqueue); | 4787 | list_del(&lkb->lkb_astqueue); |
4683 | dlm_put_lkb(lkb); | 4788 | dlm_put_lkb(lkb); |
4684 | } | 4789 | } |
diff --git a/fs/dlm/lock.h b/fs/dlm/lock.h index ada04680a1e5..27b6ed302911 100644 --- a/fs/dlm/lock.h +++ b/fs/dlm/lock.h | |||
@@ -19,8 +19,6 @@ void dlm_print_lkb(struct dlm_lkb *lkb); | |||
19 | void dlm_receive_message_saved(struct dlm_ls *ls, struct dlm_message *ms); | 19 | void dlm_receive_message_saved(struct dlm_ls *ls, struct dlm_message *ms); |
20 | void dlm_receive_buffer(struct dlm_header *hd, int nodeid); | 20 | void dlm_receive_buffer(struct dlm_header *hd, int nodeid); |
21 | int dlm_modes_compat(int mode1, int mode2); | 21 | int dlm_modes_compat(int mode1, int mode2); |
22 | int dlm_find_rsb(struct dlm_ls *ls, char *name, int namelen, | ||
23 | unsigned int flags, struct dlm_rsb **r_ret); | ||
24 | void dlm_put_rsb(struct dlm_rsb *r); | 22 | void dlm_put_rsb(struct dlm_rsb *r); |
25 | void dlm_hold_rsb(struct dlm_rsb *r); | 23 | void dlm_hold_rsb(struct dlm_rsb *r); |
26 | int dlm_put_lkb(struct dlm_lkb *lkb); | 24 | int dlm_put_lkb(struct dlm_lkb *lkb); |
diff --git a/fs/dlm/lockspace.c b/fs/dlm/lockspace.c index 5c108c49cb8c..b180fdc51085 100644 --- a/fs/dlm/lockspace.c +++ b/fs/dlm/lockspace.c | |||
@@ -24,14 +24,6 @@ | |||
24 | #include "recover.h" | 24 | #include "recover.h" |
25 | #include "requestqueue.h" | 25 | #include "requestqueue.h" |
26 | 26 | ||
27 | #ifdef CONFIG_DLM_DEBUG | ||
28 | int dlm_create_debug_file(struct dlm_ls *ls); | ||
29 | void dlm_delete_debug_file(struct dlm_ls *ls); | ||
30 | #else | ||
31 | static inline int dlm_create_debug_file(struct dlm_ls *ls) { return 0; } | ||
32 | static inline void dlm_delete_debug_file(struct dlm_ls *ls) { } | ||
33 | #endif | ||
34 | |||
35 | static int ls_count; | 27 | static int ls_count; |
36 | static struct mutex ls_lock; | 28 | static struct mutex ls_lock; |
37 | static struct list_head lslist; | 29 | static struct list_head lslist; |
@@ -684,9 +676,9 @@ static int release_lockspace(struct dlm_ls *ls, int force) | |||
684 | dlm_del_ast(lkb); | 676 | dlm_del_ast(lkb); |
685 | 677 | ||
686 | if (lkb->lkb_lvbptr && lkb->lkb_flags & DLM_IFL_MSTCPY) | 678 | if (lkb->lkb_lvbptr && lkb->lkb_flags & DLM_IFL_MSTCPY) |
687 | free_lvb(lkb->lkb_lvbptr); | 679 | dlm_free_lvb(lkb->lkb_lvbptr); |
688 | 680 | ||
689 | free_lkb(lkb); | 681 | dlm_free_lkb(lkb); |
690 | } | 682 | } |
691 | } | 683 | } |
692 | dlm_astd_resume(); | 684 | dlm_astd_resume(); |
@@ -704,7 +696,7 @@ static int release_lockspace(struct dlm_ls *ls, int force) | |||
704 | res_hashchain); | 696 | res_hashchain); |
705 | 697 | ||
706 | list_del(&rsb->res_hashchain); | 698 | list_del(&rsb->res_hashchain); |
707 | free_rsb(rsb); | 699 | dlm_free_rsb(rsb); |
708 | } | 700 | } |
709 | 701 | ||
710 | head = &ls->ls_rsbtbl[i].toss; | 702 | head = &ls->ls_rsbtbl[i].toss; |
@@ -712,7 +704,7 @@ static int release_lockspace(struct dlm_ls *ls, int force) | |||
712 | rsb = list_entry(head->next, struct dlm_rsb, | 704 | rsb = list_entry(head->next, struct dlm_rsb, |
713 | res_hashchain); | 705 | res_hashchain); |
714 | list_del(&rsb->res_hashchain); | 706 | list_del(&rsb->res_hashchain); |
715 | free_rsb(rsb); | 707 | dlm_free_rsb(rsb); |
716 | } | 708 | } |
717 | } | 709 | } |
718 | 710 | ||
diff --git a/fs/dlm/lowcomms.c b/fs/dlm/lowcomms.c index e9923ca9c2d9..7c1e5e5cccd8 100644 --- a/fs/dlm/lowcomms.c +++ b/fs/dlm/lowcomms.c | |||
@@ -864,7 +864,7 @@ static void sctp_init_assoc(struct connection *con) | |||
864 | static void tcp_connect_to_sock(struct connection *con) | 864 | static void tcp_connect_to_sock(struct connection *con) |
865 | { | 865 | { |
866 | int result = -EHOSTUNREACH; | 866 | int result = -EHOSTUNREACH; |
867 | struct sockaddr_storage saddr; | 867 | struct sockaddr_storage saddr, src_addr; |
868 | int addr_len; | 868 | int addr_len; |
869 | struct socket *sock; | 869 | struct socket *sock; |
870 | 870 | ||
@@ -898,6 +898,17 @@ static void tcp_connect_to_sock(struct connection *con) | |||
898 | con->connect_action = tcp_connect_to_sock; | 898 | con->connect_action = tcp_connect_to_sock; |
899 | add_sock(sock, con); | 899 | add_sock(sock, con); |
900 | 900 | ||
901 | /* Bind to our cluster-known address connecting to avoid | ||
902 | routing problems */ | ||
903 | memcpy(&src_addr, dlm_local_addr[0], sizeof(src_addr)); | ||
904 | make_sockaddr(&src_addr, 0, &addr_len); | ||
905 | result = sock->ops->bind(sock, (struct sockaddr *) &src_addr, | ||
906 | addr_len); | ||
907 | if (result < 0) { | ||
908 | log_print("could not bind for connect: %d", result); | ||
909 | /* This *may* not indicate a critical error */ | ||
910 | } | ||
911 | |||
901 | make_sockaddr(&saddr, dlm_config.ci_tcp_port, &addr_len); | 912 | make_sockaddr(&saddr, dlm_config.ci_tcp_port, &addr_len); |
902 | 913 | ||
903 | log_print("connecting to %d", con->nodeid); | 914 | log_print("connecting to %d", con->nodeid); |
@@ -1426,6 +1437,8 @@ void dlm_lowcomms_stop(void) | |||
1426 | con = __nodeid2con(i, 0); | 1437 | con = __nodeid2con(i, 0); |
1427 | if (con) { | 1438 | if (con) { |
1428 | close_connection(con, true); | 1439 | close_connection(con, true); |
1440 | if (con->othercon) | ||
1441 | kmem_cache_free(con_cache, con->othercon); | ||
1429 | kmem_cache_free(con_cache, con); | 1442 | kmem_cache_free(con_cache, con); |
1430 | } | 1443 | } |
1431 | } | 1444 | } |
diff --git a/fs/dlm/main.c b/fs/dlm/main.c index eca2907f2386..58487fb95a4c 100644 --- a/fs/dlm/main.c +++ b/fs/dlm/main.c | |||
@@ -18,16 +18,6 @@ | |||
18 | #include "memory.h" | 18 | #include "memory.h" |
19 | #include "config.h" | 19 | #include "config.h" |
20 | 20 | ||
21 | #ifdef CONFIG_DLM_DEBUG | ||
22 | int dlm_register_debugfs(void); | ||
23 | void dlm_unregister_debugfs(void); | ||
24 | #else | ||
25 | static inline int dlm_register_debugfs(void) { return 0; } | ||
26 | static inline void dlm_unregister_debugfs(void) { } | ||
27 | #endif | ||
28 | int dlm_netlink_init(void); | ||
29 | void dlm_netlink_exit(void); | ||
30 | |||
31 | static int __init init_dlm(void) | 21 | static int __init init_dlm(void) |
32 | { | 22 | { |
33 | int error; | 23 | int error; |
diff --git a/fs/dlm/member.c b/fs/dlm/member.c index e9cdcab306e2..fa17f5a27883 100644 --- a/fs/dlm/member.c +++ b/fs/dlm/member.c | |||
@@ -1,7 +1,7 @@ | |||
1 | /****************************************************************************** | 1 | /****************************************************************************** |
2 | ******************************************************************************* | 2 | ******************************************************************************* |
3 | ** | 3 | ** |
4 | ** Copyright (C) 2005-2007 Red Hat, Inc. All rights reserved. | 4 | ** Copyright (C) 2005-2008 Red Hat, Inc. All rights reserved. |
5 | ** | 5 | ** |
6 | ** This copyrighted material is made available to anyone wishing to use, | 6 | ** This copyrighted material is made available to anyone wishing to use, |
7 | ** modify, copy, or redistribute it subject to the terms and conditions | 7 | ** modify, copy, or redistribute it subject to the terms and conditions |
@@ -70,7 +70,7 @@ static void dlm_remove_member(struct dlm_ls *ls, struct dlm_member *memb) | |||
70 | ls->ls_num_nodes--; | 70 | ls->ls_num_nodes--; |
71 | } | 71 | } |
72 | 72 | ||
73 | static int dlm_is_member(struct dlm_ls *ls, int nodeid) | 73 | int dlm_is_member(struct dlm_ls *ls, int nodeid) |
74 | { | 74 | { |
75 | struct dlm_member *memb; | 75 | struct dlm_member *memb; |
76 | 76 | ||
diff --git a/fs/dlm/member.h b/fs/dlm/member.h index 927c08c19214..7a26fca1e0b5 100644 --- a/fs/dlm/member.h +++ b/fs/dlm/member.h | |||
@@ -1,7 +1,7 @@ | |||
1 | /****************************************************************************** | 1 | /****************************************************************************** |
2 | ******************************************************************************* | 2 | ******************************************************************************* |
3 | ** | 3 | ** |
4 | ** Copyright (C) 2005 Red Hat, Inc. All rights reserved. | 4 | ** Copyright (C) 2005-2008 Red Hat, Inc. All rights reserved. |
5 | ** | 5 | ** |
6 | ** This copyrighted material is made available to anyone wishing to use, | 6 | ** This copyrighted material is made available to anyone wishing to use, |
7 | ** modify, copy, or redistribute it subject to the terms and conditions | 7 | ** modify, copy, or redistribute it subject to the terms and conditions |
@@ -19,6 +19,7 @@ void dlm_clear_members(struct dlm_ls *ls); | |||
19 | void dlm_clear_members_gone(struct dlm_ls *ls); | 19 | void dlm_clear_members_gone(struct dlm_ls *ls); |
20 | int dlm_recover_members(struct dlm_ls *ls, struct dlm_recover *rv,int *neg_out); | 20 | int dlm_recover_members(struct dlm_ls *ls, struct dlm_recover *rv,int *neg_out); |
21 | int dlm_is_removed(struct dlm_ls *ls, int nodeid); | 21 | int dlm_is_removed(struct dlm_ls *ls, int nodeid); |
22 | int dlm_is_member(struct dlm_ls *ls, int nodeid); | ||
22 | 23 | ||
23 | #endif /* __MEMBER_DOT_H__ */ | 24 | #endif /* __MEMBER_DOT_H__ */ |
24 | 25 | ||
diff --git a/fs/dlm/memory.c b/fs/dlm/memory.c index ecf0e5cb2035..f7783867491a 100644 --- a/fs/dlm/memory.c +++ b/fs/dlm/memory.c | |||
@@ -2,7 +2,7 @@ | |||
2 | ******************************************************************************* | 2 | ******************************************************************************* |
3 | ** | 3 | ** |
4 | ** Copyright (C) Sistina Software, Inc. 1997-2003 All rights reserved. | 4 | ** Copyright (C) Sistina Software, Inc. 1997-2003 All rights reserved. |
5 | ** Copyright (C) 2004-2005 Red Hat, Inc. All rights reserved. | 5 | ** Copyright (C) 2004-2007 Red Hat, Inc. All rights reserved. |
6 | ** | 6 | ** |
7 | ** This copyrighted material is made available to anyone wishing to use, | 7 | ** This copyrighted material is made available to anyone wishing to use, |
8 | ** modify, copy, or redistribute it subject to the terms and conditions | 8 | ** modify, copy, or redistribute it subject to the terms and conditions |
@@ -35,7 +35,7 @@ void dlm_memory_exit(void) | |||
35 | kmem_cache_destroy(lkb_cache); | 35 | kmem_cache_destroy(lkb_cache); |
36 | } | 36 | } |
37 | 37 | ||
38 | char *allocate_lvb(struct dlm_ls *ls) | 38 | char *dlm_allocate_lvb(struct dlm_ls *ls) |
39 | { | 39 | { |
40 | char *p; | 40 | char *p; |
41 | 41 | ||
@@ -43,7 +43,7 @@ char *allocate_lvb(struct dlm_ls *ls) | |||
43 | return p; | 43 | return p; |
44 | } | 44 | } |
45 | 45 | ||
46 | void free_lvb(char *p) | 46 | void dlm_free_lvb(char *p) |
47 | { | 47 | { |
48 | kfree(p); | 48 | kfree(p); |
49 | } | 49 | } |
@@ -51,7 +51,7 @@ void free_lvb(char *p) | |||
51 | /* FIXME: have some minimal space built-in to rsb for the name and | 51 | /* FIXME: have some minimal space built-in to rsb for the name and |
52 | kmalloc a separate name if needed, like dentries are done */ | 52 | kmalloc a separate name if needed, like dentries are done */ |
53 | 53 | ||
54 | struct dlm_rsb *allocate_rsb(struct dlm_ls *ls, int namelen) | 54 | struct dlm_rsb *dlm_allocate_rsb(struct dlm_ls *ls, int namelen) |
55 | { | 55 | { |
56 | struct dlm_rsb *r; | 56 | struct dlm_rsb *r; |
57 | 57 | ||
@@ -61,14 +61,14 @@ struct dlm_rsb *allocate_rsb(struct dlm_ls *ls, int namelen) | |||
61 | return r; | 61 | return r; |
62 | } | 62 | } |
63 | 63 | ||
64 | void free_rsb(struct dlm_rsb *r) | 64 | void dlm_free_rsb(struct dlm_rsb *r) |
65 | { | 65 | { |
66 | if (r->res_lvbptr) | 66 | if (r->res_lvbptr) |
67 | free_lvb(r->res_lvbptr); | 67 | dlm_free_lvb(r->res_lvbptr); |
68 | kfree(r); | 68 | kfree(r); |
69 | } | 69 | } |
70 | 70 | ||
71 | struct dlm_lkb *allocate_lkb(struct dlm_ls *ls) | 71 | struct dlm_lkb *dlm_allocate_lkb(struct dlm_ls *ls) |
72 | { | 72 | { |
73 | struct dlm_lkb *lkb; | 73 | struct dlm_lkb *lkb; |
74 | 74 | ||
@@ -76,7 +76,7 @@ struct dlm_lkb *allocate_lkb(struct dlm_ls *ls) | |||
76 | return lkb; | 76 | return lkb; |
77 | } | 77 | } |
78 | 78 | ||
79 | void free_lkb(struct dlm_lkb *lkb) | 79 | void dlm_free_lkb(struct dlm_lkb *lkb) |
80 | { | 80 | { |
81 | if (lkb->lkb_flags & DLM_IFL_USER) { | 81 | if (lkb->lkb_flags & DLM_IFL_USER) { |
82 | struct dlm_user_args *ua; | 82 | struct dlm_user_args *ua; |
@@ -90,19 +90,3 @@ void free_lkb(struct dlm_lkb *lkb) | |||
90 | kmem_cache_free(lkb_cache, lkb); | 90 | kmem_cache_free(lkb_cache, lkb); |
91 | } | 91 | } |
92 | 92 | ||
93 | struct dlm_direntry *allocate_direntry(struct dlm_ls *ls, int namelen) | ||
94 | { | ||
95 | struct dlm_direntry *de; | ||
96 | |||
97 | DLM_ASSERT(namelen <= DLM_RESNAME_MAXLEN, | ||
98 | printk("namelen = %d\n", namelen);); | ||
99 | |||
100 | de = kzalloc(sizeof(*de) + namelen, GFP_KERNEL); | ||
101 | return de; | ||
102 | } | ||
103 | |||
104 | void free_direntry(struct dlm_direntry *de) | ||
105 | { | ||
106 | kfree(de); | ||
107 | } | ||
108 | |||
diff --git a/fs/dlm/memory.h b/fs/dlm/memory.h index 6ead158ccc5c..485fb29143bd 100644 --- a/fs/dlm/memory.h +++ b/fs/dlm/memory.h | |||
@@ -2,7 +2,7 @@ | |||
2 | ******************************************************************************* | 2 | ******************************************************************************* |
3 | ** | 3 | ** |
4 | ** Copyright (C) Sistina Software, Inc. 1997-2003 All rights reserved. | 4 | ** Copyright (C) Sistina Software, Inc. 1997-2003 All rights reserved. |
5 | ** Copyright (C) 2004-2005 Red Hat, Inc. All rights reserved. | 5 | ** Copyright (C) 2004-2007 Red Hat, Inc. All rights reserved. |
6 | ** | 6 | ** |
7 | ** This copyrighted material is made available to anyone wishing to use, | 7 | ** This copyrighted material is made available to anyone wishing to use, |
8 | ** modify, copy, or redistribute it subject to the terms and conditions | 8 | ** modify, copy, or redistribute it subject to the terms and conditions |
@@ -16,14 +16,12 @@ | |||
16 | 16 | ||
17 | int dlm_memory_init(void); | 17 | int dlm_memory_init(void); |
18 | void dlm_memory_exit(void); | 18 | void dlm_memory_exit(void); |
19 | struct dlm_rsb *allocate_rsb(struct dlm_ls *ls, int namelen); | 19 | struct dlm_rsb *dlm_allocate_rsb(struct dlm_ls *ls, int namelen); |
20 | void free_rsb(struct dlm_rsb *r); | 20 | void dlm_free_rsb(struct dlm_rsb *r); |
21 | struct dlm_lkb *allocate_lkb(struct dlm_ls *ls); | 21 | struct dlm_lkb *dlm_allocate_lkb(struct dlm_ls *ls); |
22 | void free_lkb(struct dlm_lkb *l); | 22 | void dlm_free_lkb(struct dlm_lkb *l); |
23 | struct dlm_direntry *allocate_direntry(struct dlm_ls *ls, int namelen); | 23 | char *dlm_allocate_lvb(struct dlm_ls *ls); |
24 | void free_direntry(struct dlm_direntry *de); | 24 | void dlm_free_lvb(char *l); |
25 | char *allocate_lvb(struct dlm_ls *ls); | ||
26 | void free_lvb(char *l); | ||
27 | 25 | ||
28 | #endif /* __MEMORY_DOT_H__ */ | 26 | #endif /* __MEMORY_DOT_H__ */ |
29 | 27 | ||
diff --git a/fs/dlm/midcomms.c b/fs/dlm/midcomms.c index f8c69dda16a0..e69926e984db 100644 --- a/fs/dlm/midcomms.c +++ b/fs/dlm/midcomms.c | |||
@@ -2,7 +2,7 @@ | |||
2 | ******************************************************************************* | 2 | ******************************************************************************* |
3 | ** | 3 | ** |
4 | ** Copyright (C) Sistina Software, Inc. 1997-2003 All rights reserved. | 4 | ** Copyright (C) Sistina Software, Inc. 1997-2003 All rights reserved. |
5 | ** Copyright (C) 2004-2007 Red Hat, Inc. All rights reserved. | 5 | ** Copyright (C) 2004-2008 Red Hat, Inc. All rights reserved. |
6 | ** | 6 | ** |
7 | ** This copyrighted material is made available to anyone wishing to use, | 7 | ** This copyrighted material is made available to anyone wishing to use, |
8 | ** modify, copy, or redistribute it subject to the terms and conditions | 8 | ** modify, copy, or redistribute it subject to the terms and conditions |
@@ -58,8 +58,12 @@ static void copy_from_cb(void *dst, const void *base, unsigned offset, | |||
58 | int dlm_process_incoming_buffer(int nodeid, const void *base, | 58 | int dlm_process_incoming_buffer(int nodeid, const void *base, |
59 | unsigned offset, unsigned len, unsigned limit) | 59 | unsigned offset, unsigned len, unsigned limit) |
60 | { | 60 | { |
61 | unsigned char __tmp[DLM_INBUF_LEN]; | 61 | union { |
62 | struct dlm_header *msg = (struct dlm_header *) __tmp; | 62 | unsigned char __buf[DLM_INBUF_LEN]; |
63 | /* this is to force proper alignment on some arches */ | ||
64 | struct dlm_header dlm; | ||
65 | } __tmp; | ||
66 | struct dlm_header *msg = &__tmp.dlm; | ||
63 | int ret = 0; | 67 | int ret = 0; |
64 | int err = 0; | 68 | int err = 0; |
65 | uint16_t msglen; | 69 | uint16_t msglen; |
@@ -100,8 +104,7 @@ int dlm_process_incoming_buffer(int nodeid, const void *base, | |||
100 | in the buffer on the stack (which should work for most | 104 | in the buffer on the stack (which should work for most |
101 | ordinary messages). */ | 105 | ordinary messages). */ |
102 | 106 | ||
103 | if (msglen > sizeof(__tmp) && | 107 | if (msglen > DLM_INBUF_LEN && msg == &__tmp.dlm) { |
104 | msg == (struct dlm_header *) __tmp) { | ||
105 | msg = kmalloc(dlm_config.ci_buffer_size, GFP_KERNEL); | 108 | msg = kmalloc(dlm_config.ci_buffer_size, GFP_KERNEL); |
106 | if (msg == NULL) | 109 | if (msg == NULL) |
107 | return ret; | 110 | return ret; |
@@ -119,7 +122,7 @@ int dlm_process_incoming_buffer(int nodeid, const void *base, | |||
119 | dlm_receive_buffer(msg, nodeid); | 122 | dlm_receive_buffer(msg, nodeid); |
120 | } | 123 | } |
121 | 124 | ||
122 | if (msg != (struct dlm_header *) __tmp) | 125 | if (msg != &__tmp.dlm) |
123 | kfree(msg); | 126 | kfree(msg); |
124 | 127 | ||
125 | return err ? err : ret; | 128 | return err ? err : ret; |
diff --git a/fs/dlm/rcom.c b/fs/dlm/rcom.c index ae2fd97fa4ad..026824cd3acb 100644 --- a/fs/dlm/rcom.c +++ b/fs/dlm/rcom.c | |||
@@ -2,7 +2,7 @@ | |||
2 | ******************************************************************************* | 2 | ******************************************************************************* |
3 | ** | 3 | ** |
4 | ** Copyright (C) Sistina Software, Inc. 1997-2003 All rights reserved. | 4 | ** Copyright (C) Sistina Software, Inc. 1997-2003 All rights reserved. |
5 | ** Copyright (C) 2005-2007 Red Hat, Inc. All rights reserved. | 5 | ** Copyright (C) 2005-2008 Red Hat, Inc. All rights reserved. |
6 | ** | 6 | ** |
7 | ** This copyrighted material is made available to anyone wishing to use, | 7 | ** This copyrighted material is made available to anyone wishing to use, |
8 | ** modify, copy, or redistribute it subject to the terms and conditions | 8 | ** modify, copy, or redistribute it subject to the terms and conditions |
@@ -197,11 +197,6 @@ static void receive_sync_reply(struct dlm_ls *ls, struct dlm_rcom *rc_in) | |||
197 | spin_unlock(&ls->ls_rcom_spin); | 197 | spin_unlock(&ls->ls_rcom_spin); |
198 | } | 198 | } |
199 | 199 | ||
200 | static void receive_rcom_status_reply(struct dlm_ls *ls, struct dlm_rcom *rc_in) | ||
201 | { | ||
202 | receive_sync_reply(ls, rc_in); | ||
203 | } | ||
204 | |||
205 | int dlm_rcom_names(struct dlm_ls *ls, int nodeid, char *last_name, int last_len) | 200 | int dlm_rcom_names(struct dlm_ls *ls, int nodeid, char *last_name, int last_len) |
206 | { | 201 | { |
207 | struct dlm_rcom *rc; | 202 | struct dlm_rcom *rc; |
@@ -254,11 +249,6 @@ static void receive_rcom_names(struct dlm_ls *ls, struct dlm_rcom *rc_in) | |||
254 | send_rcom(ls, mh, rc); | 249 | send_rcom(ls, mh, rc); |
255 | } | 250 | } |
256 | 251 | ||
257 | static void receive_rcom_names_reply(struct dlm_ls *ls, struct dlm_rcom *rc_in) | ||
258 | { | ||
259 | receive_sync_reply(ls, rc_in); | ||
260 | } | ||
261 | |||
262 | int dlm_send_rcom_lookup(struct dlm_rsb *r, int dir_nodeid) | 252 | int dlm_send_rcom_lookup(struct dlm_rsb *r, int dir_nodeid) |
263 | { | 253 | { |
264 | struct dlm_rcom *rc; | 254 | struct dlm_rcom *rc; |
@@ -381,11 +371,6 @@ static void receive_rcom_lock(struct dlm_ls *ls, struct dlm_rcom *rc_in) | |||
381 | send_rcom(ls, mh, rc); | 371 | send_rcom(ls, mh, rc); |
382 | } | 372 | } |
383 | 373 | ||
384 | static void receive_rcom_lock_reply(struct dlm_ls *ls, struct dlm_rcom *rc_in) | ||
385 | { | ||
386 | dlm_recover_process_copy(ls, rc_in); | ||
387 | } | ||
388 | |||
389 | /* If the lockspace doesn't exist then still send a status message | 374 | /* If the lockspace doesn't exist then still send a status message |
390 | back; it's possible that it just doesn't have its global_id yet. */ | 375 | back; it's possible that it just doesn't have its global_id yet. */ |
391 | 376 | ||
@@ -481,11 +466,11 @@ void dlm_receive_rcom(struct dlm_ls *ls, struct dlm_rcom *rc, int nodeid) | |||
481 | break; | 466 | break; |
482 | 467 | ||
483 | case DLM_RCOM_STATUS_REPLY: | 468 | case DLM_RCOM_STATUS_REPLY: |
484 | receive_rcom_status_reply(ls, rc); | 469 | receive_sync_reply(ls, rc); |
485 | break; | 470 | break; |
486 | 471 | ||
487 | case DLM_RCOM_NAMES_REPLY: | 472 | case DLM_RCOM_NAMES_REPLY: |
488 | receive_rcom_names_reply(ls, rc); | 473 | receive_sync_reply(ls, rc); |
489 | break; | 474 | break; |
490 | 475 | ||
491 | case DLM_RCOM_LOOKUP_REPLY: | 476 | case DLM_RCOM_LOOKUP_REPLY: |
@@ -493,11 +478,11 @@ void dlm_receive_rcom(struct dlm_ls *ls, struct dlm_rcom *rc, int nodeid) | |||
493 | break; | 478 | break; |
494 | 479 | ||
495 | case DLM_RCOM_LOCK_REPLY: | 480 | case DLM_RCOM_LOCK_REPLY: |
496 | receive_rcom_lock_reply(ls, rc); | 481 | dlm_recover_process_copy(ls, rc); |
497 | break; | 482 | break; |
498 | 483 | ||
499 | default: | 484 | default: |
500 | DLM_ASSERT(0, printk("rc_type=%x\n", rc->rc_type);); | 485 | log_error(ls, "receive_rcom bad type %d", rc->rc_type); |
501 | } | 486 | } |
502 | out: | 487 | out: |
503 | return; | 488 | return; |
diff --git a/fs/dlm/recover.c b/fs/dlm/recover.c index c2cc7694cd16..df075dc300fa 100644 --- a/fs/dlm/recover.c +++ b/fs/dlm/recover.c | |||
@@ -629,7 +629,7 @@ static void recover_lvb(struct dlm_rsb *r) | |||
629 | goto out; | 629 | goto out; |
630 | 630 | ||
631 | if (!r->res_lvbptr) { | 631 | if (!r->res_lvbptr) { |
632 | r->res_lvbptr = allocate_lvb(r->res_ls); | 632 | r->res_lvbptr = dlm_allocate_lvb(r->res_ls); |
633 | if (!r->res_lvbptr) | 633 | if (!r->res_lvbptr) |
634 | goto out; | 634 | goto out; |
635 | } | 635 | } |
@@ -731,6 +731,20 @@ int dlm_create_root_list(struct dlm_ls *ls) | |||
731 | list_add(&r->res_root_list, &ls->ls_root_list); | 731 | list_add(&r->res_root_list, &ls->ls_root_list); |
732 | dlm_hold_rsb(r); | 732 | dlm_hold_rsb(r); |
733 | } | 733 | } |
734 | |||
735 | /* If we're using a directory, add tossed rsbs to the root | ||
736 | list; they'll have entries created in the new directory, | ||
737 | but no other recovery steps should do anything with them. */ | ||
738 | |||
739 | if (dlm_no_directory(ls)) { | ||
740 | read_unlock(&ls->ls_rsbtbl[i].lock); | ||
741 | continue; | ||
742 | } | ||
743 | |||
744 | list_for_each_entry(r, &ls->ls_rsbtbl[i].toss, res_hashchain) { | ||
745 | list_add(&r->res_root_list, &ls->ls_root_list); | ||
746 | dlm_hold_rsb(r); | ||
747 | } | ||
734 | read_unlock(&ls->ls_rsbtbl[i].lock); | 748 | read_unlock(&ls->ls_rsbtbl[i].lock); |
735 | } | 749 | } |
736 | out: | 750 | out: |
@@ -750,6 +764,11 @@ void dlm_release_root_list(struct dlm_ls *ls) | |||
750 | up_write(&ls->ls_root_sem); | 764 | up_write(&ls->ls_root_sem); |
751 | } | 765 | } |
752 | 766 | ||
767 | /* If not using a directory, clear the entire toss list, there's no benefit to | ||
768 | caching the master value since it's fixed. If we are using a dir, keep the | ||
769 | rsb's we're the master of. Recovery will add them to the root list and from | ||
770 | there they'll be entered in the rebuilt directory. */ | ||
771 | |||
753 | void dlm_clear_toss_list(struct dlm_ls *ls) | 772 | void dlm_clear_toss_list(struct dlm_ls *ls) |
754 | { | 773 | { |
755 | struct dlm_rsb *r, *safe; | 774 | struct dlm_rsb *r, *safe; |
@@ -759,8 +778,10 @@ void dlm_clear_toss_list(struct dlm_ls *ls) | |||
759 | write_lock(&ls->ls_rsbtbl[i].lock); | 778 | write_lock(&ls->ls_rsbtbl[i].lock); |
760 | list_for_each_entry_safe(r, safe, &ls->ls_rsbtbl[i].toss, | 779 | list_for_each_entry_safe(r, safe, &ls->ls_rsbtbl[i].toss, |
761 | res_hashchain) { | 780 | res_hashchain) { |
762 | list_del(&r->res_hashchain); | 781 | if (dlm_no_directory(ls) || !is_master(r)) { |
763 | free_rsb(r); | 782 | list_del(&r->res_hashchain); |
783 | dlm_free_rsb(r); | ||
784 | } | ||
764 | } | 785 | } |
765 | write_unlock(&ls->ls_rsbtbl[i].lock); | 786 | write_unlock(&ls->ls_rsbtbl[i].lock); |
766 | } | 787 | } |
diff --git a/fs/dlm/recoverd.c b/fs/dlm/recoverd.c index 4b89e20eebe7..997f9531d594 100644 --- a/fs/dlm/recoverd.c +++ b/fs/dlm/recoverd.c | |||
@@ -67,17 +67,18 @@ static int ls_recover(struct dlm_ls *ls, struct dlm_recover *rv) | |||
67 | dlm_astd_resume(); | 67 | dlm_astd_resume(); |
68 | 68 | ||
69 | /* | 69 | /* |
70 | * This list of root rsb's will be the basis of most of the recovery | 70 | * Free non-master tossed rsb's. Master rsb's are kept on toss |
71 | * routines. | 71 | * list and put on root list to be included in resdir recovery. |
72 | */ | 72 | */ |
73 | 73 | ||
74 | dlm_create_root_list(ls); | 74 | dlm_clear_toss_list(ls); |
75 | 75 | ||
76 | /* | 76 | /* |
77 | * Free all the tossed rsb's so we don't have to recover them. | 77 | * This list of root rsb's will be the basis of most of the recovery |
78 | * routines. | ||
78 | */ | 79 | */ |
79 | 80 | ||
80 | dlm_clear_toss_list(ls); | 81 | dlm_create_root_list(ls); |
81 | 82 | ||
82 | /* | 83 | /* |
83 | * Add or remove nodes from the lockspace's ls_nodes list. | 84 | * Add or remove nodes from the lockspace's ls_nodes list. |
diff --git a/fs/dlm/user.c b/fs/dlm/user.c index 4f741546f4bb..7cbc6826239b 100644 --- a/fs/dlm/user.c +++ b/fs/dlm/user.c | |||
@@ -24,8 +24,7 @@ | |||
24 | #include "lvb_table.h" | 24 | #include "lvb_table.h" |
25 | #include "user.h" | 25 | #include "user.h" |
26 | 26 | ||
27 | static const char *name_prefix="dlm"; | 27 | static const char name_prefix[] = "dlm"; |
28 | static struct miscdevice ctl_device; | ||
29 | static const struct file_operations device_fops; | 28 | static const struct file_operations device_fops; |
30 | 29 | ||
31 | #ifdef CONFIG_COMPAT | 30 | #ifdef CONFIG_COMPAT |
@@ -82,7 +81,8 @@ struct dlm_lock_result32 { | |||
82 | }; | 81 | }; |
83 | 82 | ||
84 | static void compat_input(struct dlm_write_request *kb, | 83 | static void compat_input(struct dlm_write_request *kb, |
85 | struct dlm_write_request32 *kb32) | 84 | struct dlm_write_request32 *kb32, |
85 | int max_namelen) | ||
86 | { | 86 | { |
87 | kb->version[0] = kb32->version[0]; | 87 | kb->version[0] = kb32->version[0]; |
88 | kb->version[1] = kb32->version[1]; | 88 | kb->version[1] = kb32->version[1]; |
@@ -112,7 +112,11 @@ static void compat_input(struct dlm_write_request *kb, | |||
112 | kb->i.lock.bastaddr = (void *)(long)kb32->i.lock.bastaddr; | 112 | kb->i.lock.bastaddr = (void *)(long)kb32->i.lock.bastaddr; |
113 | kb->i.lock.lksb = (void *)(long)kb32->i.lock.lksb; | 113 | kb->i.lock.lksb = (void *)(long)kb32->i.lock.lksb; |
114 | memcpy(kb->i.lock.lvb, kb32->i.lock.lvb, DLM_USER_LVB_LEN); | 114 | memcpy(kb->i.lock.lvb, kb32->i.lock.lvb, DLM_USER_LVB_LEN); |
115 | memcpy(kb->i.lock.name, kb32->i.lock.name, kb->i.lock.namelen); | 115 | if (kb->i.lock.namelen <= max_namelen) |
116 | memcpy(kb->i.lock.name, kb32->i.lock.name, | ||
117 | kb->i.lock.namelen); | ||
118 | else | ||
119 | kb->i.lock.namelen = max_namelen; | ||
116 | } | 120 | } |
117 | } | 121 | } |
118 | 122 | ||
@@ -236,12 +240,12 @@ void dlm_user_add_ast(struct dlm_lkb *lkb, int type) | |||
236 | spin_unlock(&proc->asts_spin); | 240 | spin_unlock(&proc->asts_spin); |
237 | 241 | ||
238 | if (eol) { | 242 | if (eol) { |
239 | spin_lock(&ua->proc->locks_spin); | 243 | spin_lock(&proc->locks_spin); |
240 | if (!list_empty(&lkb->lkb_ownqueue)) { | 244 | if (!list_empty(&lkb->lkb_ownqueue)) { |
241 | list_del_init(&lkb->lkb_ownqueue); | 245 | list_del_init(&lkb->lkb_ownqueue); |
242 | dlm_put_lkb(lkb); | 246 | dlm_put_lkb(lkb); |
243 | } | 247 | } |
244 | spin_unlock(&ua->proc->locks_spin); | 248 | spin_unlock(&proc->locks_spin); |
245 | } | 249 | } |
246 | out: | 250 | out: |
247 | mutex_unlock(&ls->ls_clear_proc_locks); | 251 | mutex_unlock(&ls->ls_clear_proc_locks); |
@@ -529,7 +533,8 @@ static ssize_t device_write(struct file *file, const char __user *buf, | |||
529 | 533 | ||
530 | if (proc) | 534 | if (proc) |
531 | set_bit(DLM_PROC_FLAGS_COMPAT, &proc->flags); | 535 | set_bit(DLM_PROC_FLAGS_COMPAT, &proc->flags); |
532 | compat_input(kbuf, k32buf); | 536 | compat_input(kbuf, k32buf, |
537 | count - sizeof(struct dlm_write_request32)); | ||
533 | kfree(k32buf); | 538 | kfree(k32buf); |
534 | } | 539 | } |
535 | #endif | 540 | #endif |
@@ -896,14 +901,16 @@ static const struct file_operations ctl_device_fops = { | |||
896 | .owner = THIS_MODULE, | 901 | .owner = THIS_MODULE, |
897 | }; | 902 | }; |
898 | 903 | ||
904 | static struct miscdevice ctl_device = { | ||
905 | .name = "dlm-control", | ||
906 | .fops = &ctl_device_fops, | ||
907 | .minor = MISC_DYNAMIC_MINOR, | ||
908 | }; | ||
909 | |||
899 | int dlm_user_init(void) | 910 | int dlm_user_init(void) |
900 | { | 911 | { |
901 | int error; | 912 | int error; |
902 | 913 | ||
903 | ctl_device.name = "dlm-control"; | ||
904 | ctl_device.fops = &ctl_device_fops; | ||
905 | ctl_device.minor = MISC_DYNAMIC_MINOR; | ||
906 | |||
907 | error = misc_register(&ctl_device); | 914 | error = misc_register(&ctl_device); |
908 | if (error) | 915 | if (error) |
909 | log_print("misc_register failed for control device"); | 916 | log_print("misc_register failed for control device"); |
diff --git a/fs/dlm/util.c b/fs/dlm/util.c index 963889cf6740..4d9c1f4e1bd1 100644 --- a/fs/dlm/util.c +++ b/fs/dlm/util.c | |||
@@ -1,7 +1,7 @@ | |||
1 | /****************************************************************************** | 1 | /****************************************************************************** |
2 | ******************************************************************************* | 2 | ******************************************************************************* |
3 | ** | 3 | ** |
4 | ** Copyright (C) 2005 Red Hat, Inc. All rights reserved. | 4 | ** Copyright (C) 2005-2008 Red Hat, Inc. All rights reserved. |
5 | ** | 5 | ** |
6 | ** This copyrighted material is made available to anyone wishing to use, | 6 | ** This copyrighted material is made available to anyone wishing to use, |
7 | ** modify, copy, or redistribute it subject to the terms and conditions | 7 | ** modify, copy, or redistribute it subject to the terms and conditions |
@@ -14,6 +14,14 @@ | |||
14 | #include "rcom.h" | 14 | #include "rcom.h" |
15 | #include "util.h" | 15 | #include "util.h" |
16 | 16 | ||
17 | #define DLM_ERRNO_EDEADLK 35 | ||
18 | #define DLM_ERRNO_EBADR 53 | ||
19 | #define DLM_ERRNO_EBADSLT 57 | ||
20 | #define DLM_ERRNO_EPROTO 71 | ||
21 | #define DLM_ERRNO_EOPNOTSUPP 95 | ||
22 | #define DLM_ERRNO_ETIMEDOUT 110 | ||
23 | #define DLM_ERRNO_EINPROGRESS 115 | ||
24 | |||
17 | static void header_out(struct dlm_header *hd) | 25 | static void header_out(struct dlm_header *hd) |
18 | { | 26 | { |
19 | hd->h_version = cpu_to_le32(hd->h_version); | 27 | hd->h_version = cpu_to_le32(hd->h_version); |
@@ -30,11 +38,54 @@ static void header_in(struct dlm_header *hd) | |||
30 | hd->h_length = le16_to_cpu(hd->h_length); | 38 | hd->h_length = le16_to_cpu(hd->h_length); |
31 | } | 39 | } |
32 | 40 | ||
33 | void dlm_message_out(struct dlm_message *ms) | 41 | /* higher errno values are inconsistent across architectures, so select |
42 | one set of values for on the wire */ | ||
43 | |||
44 | static int to_dlm_errno(int err) | ||
45 | { | ||
46 | switch (err) { | ||
47 | case -EDEADLK: | ||
48 | return -DLM_ERRNO_EDEADLK; | ||
49 | case -EBADR: | ||
50 | return -DLM_ERRNO_EBADR; | ||
51 | case -EBADSLT: | ||
52 | return -DLM_ERRNO_EBADSLT; | ||
53 | case -EPROTO: | ||
54 | return -DLM_ERRNO_EPROTO; | ||
55 | case -EOPNOTSUPP: | ||
56 | return -DLM_ERRNO_EOPNOTSUPP; | ||
57 | case -ETIMEDOUT: | ||
58 | return -DLM_ERRNO_ETIMEDOUT; | ||
59 | case -EINPROGRESS: | ||
60 | return -DLM_ERRNO_EINPROGRESS; | ||
61 | } | ||
62 | return err; | ||
63 | } | ||
64 | |||
65 | static int from_dlm_errno(int err) | ||
34 | { | 66 | { |
35 | struct dlm_header *hd = (struct dlm_header *) ms; | 67 | switch (err) { |
68 | case -DLM_ERRNO_EDEADLK: | ||
69 | return -EDEADLK; | ||
70 | case -DLM_ERRNO_EBADR: | ||
71 | return -EBADR; | ||
72 | case -DLM_ERRNO_EBADSLT: | ||
73 | return -EBADSLT; | ||
74 | case -DLM_ERRNO_EPROTO: | ||
75 | return -EPROTO; | ||
76 | case -DLM_ERRNO_EOPNOTSUPP: | ||
77 | return -EOPNOTSUPP; | ||
78 | case -DLM_ERRNO_ETIMEDOUT: | ||
79 | return -ETIMEDOUT; | ||
80 | case -DLM_ERRNO_EINPROGRESS: | ||
81 | return -EINPROGRESS; | ||
82 | } | ||
83 | return err; | ||
84 | } | ||
36 | 85 | ||
37 | header_out(hd); | 86 | void dlm_message_out(struct dlm_message *ms) |
87 | { | ||
88 | header_out(&ms->m_header); | ||
38 | 89 | ||
39 | ms->m_type = cpu_to_le32(ms->m_type); | 90 | ms->m_type = cpu_to_le32(ms->m_type); |
40 | ms->m_nodeid = cpu_to_le32(ms->m_nodeid); | 91 | ms->m_nodeid = cpu_to_le32(ms->m_nodeid); |
@@ -53,14 +104,12 @@ void dlm_message_out(struct dlm_message *ms) | |||
53 | ms->m_rqmode = cpu_to_le32(ms->m_rqmode); | 104 | ms->m_rqmode = cpu_to_le32(ms->m_rqmode); |
54 | ms->m_bastmode = cpu_to_le32(ms->m_bastmode); | 105 | ms->m_bastmode = cpu_to_le32(ms->m_bastmode); |
55 | ms->m_asts = cpu_to_le32(ms->m_asts); | 106 | ms->m_asts = cpu_to_le32(ms->m_asts); |
56 | ms->m_result = cpu_to_le32(ms->m_result); | 107 | ms->m_result = cpu_to_le32(to_dlm_errno(ms->m_result)); |
57 | } | 108 | } |
58 | 109 | ||
59 | void dlm_message_in(struct dlm_message *ms) | 110 | void dlm_message_in(struct dlm_message *ms) |
60 | { | 111 | { |
61 | struct dlm_header *hd = (struct dlm_header *) ms; | 112 | header_in(&ms->m_header); |
62 | |||
63 | header_in(hd); | ||
64 | 113 | ||
65 | ms->m_type = le32_to_cpu(ms->m_type); | 114 | ms->m_type = le32_to_cpu(ms->m_type); |
66 | ms->m_nodeid = le32_to_cpu(ms->m_nodeid); | 115 | ms->m_nodeid = le32_to_cpu(ms->m_nodeid); |
@@ -79,7 +128,7 @@ void dlm_message_in(struct dlm_message *ms) | |||
79 | ms->m_rqmode = le32_to_cpu(ms->m_rqmode); | 128 | ms->m_rqmode = le32_to_cpu(ms->m_rqmode); |
80 | ms->m_bastmode = le32_to_cpu(ms->m_bastmode); | 129 | ms->m_bastmode = le32_to_cpu(ms->m_bastmode); |
81 | ms->m_asts = le32_to_cpu(ms->m_asts); | 130 | ms->m_asts = le32_to_cpu(ms->m_asts); |
82 | ms->m_result = le32_to_cpu(ms->m_result); | 131 | ms->m_result = from_dlm_errno(le32_to_cpu(ms->m_result)); |
83 | } | 132 | } |
84 | 133 | ||
85 | static void rcom_lock_out(struct rcom_lock *rl) | 134 | static void rcom_lock_out(struct rcom_lock *rl) |
@@ -126,10 +175,9 @@ static void rcom_config_in(struct rcom_config *rf) | |||
126 | 175 | ||
127 | void dlm_rcom_out(struct dlm_rcom *rc) | 176 | void dlm_rcom_out(struct dlm_rcom *rc) |
128 | { | 177 | { |
129 | struct dlm_header *hd = (struct dlm_header *) rc; | ||
130 | int type = rc->rc_type; | 178 | int type = rc->rc_type; |
131 | 179 | ||
132 | header_out(hd); | 180 | header_out(&rc->rc_header); |
133 | 181 | ||
134 | rc->rc_type = cpu_to_le32(rc->rc_type); | 182 | rc->rc_type = cpu_to_le32(rc->rc_type); |
135 | rc->rc_result = cpu_to_le32(rc->rc_result); | 183 | rc->rc_result = cpu_to_le32(rc->rc_result); |
@@ -137,7 +185,7 @@ void dlm_rcom_out(struct dlm_rcom *rc) | |||
137 | rc->rc_seq = cpu_to_le64(rc->rc_seq); | 185 | rc->rc_seq = cpu_to_le64(rc->rc_seq); |
138 | rc->rc_seq_reply = cpu_to_le64(rc->rc_seq_reply); | 186 | rc->rc_seq_reply = cpu_to_le64(rc->rc_seq_reply); |
139 | 187 | ||
140 | if (type == DLM_RCOM_LOCK) | 188 | if ((type == DLM_RCOM_LOCK) || (type == DLM_RCOM_LOCK_REPLY)) |
141 | rcom_lock_out((struct rcom_lock *) rc->rc_buf); | 189 | rcom_lock_out((struct rcom_lock *) rc->rc_buf); |
142 | 190 | ||
143 | else if (type == DLM_RCOM_STATUS_REPLY) | 191 | else if (type == DLM_RCOM_STATUS_REPLY) |
@@ -146,9 +194,9 @@ void dlm_rcom_out(struct dlm_rcom *rc) | |||
146 | 194 | ||
147 | void dlm_rcom_in(struct dlm_rcom *rc) | 195 | void dlm_rcom_in(struct dlm_rcom *rc) |
148 | { | 196 | { |
149 | struct dlm_header *hd = (struct dlm_header *) rc; | 197 | int type; |
150 | 198 | ||
151 | header_in(hd); | 199 | header_in(&rc->rc_header); |
152 | 200 | ||
153 | rc->rc_type = le32_to_cpu(rc->rc_type); | 201 | rc->rc_type = le32_to_cpu(rc->rc_type); |
154 | rc->rc_result = le32_to_cpu(rc->rc_result); | 202 | rc->rc_result = le32_to_cpu(rc->rc_result); |
@@ -156,10 +204,12 @@ void dlm_rcom_in(struct dlm_rcom *rc) | |||
156 | rc->rc_seq = le64_to_cpu(rc->rc_seq); | 204 | rc->rc_seq = le64_to_cpu(rc->rc_seq); |
157 | rc->rc_seq_reply = le64_to_cpu(rc->rc_seq_reply); | 205 | rc->rc_seq_reply = le64_to_cpu(rc->rc_seq_reply); |
158 | 206 | ||
159 | if (rc->rc_type == DLM_RCOM_LOCK) | 207 | type = rc->rc_type; |
208 | |||
209 | if ((type == DLM_RCOM_LOCK) || (type == DLM_RCOM_LOCK_REPLY)) | ||
160 | rcom_lock_in((struct rcom_lock *) rc->rc_buf); | 210 | rcom_lock_in((struct rcom_lock *) rc->rc_buf); |
161 | 211 | ||
162 | else if (rc->rc_type == DLM_RCOM_STATUS_REPLY) | 212 | else if (type == DLM_RCOM_STATUS_REPLY) |
163 | rcom_config_in((struct rcom_config *) rc->rc_buf); | 213 | rcom_config_in((struct rcom_config *) rc->rc_buf); |
164 | } | 214 | } |
165 | 215 | ||
diff --git a/fs/jbd/checkpoint.c b/fs/jbd/checkpoint.c index 0f69c416eebc..a5432bbbfb88 100644 --- a/fs/jbd/checkpoint.c +++ b/fs/jbd/checkpoint.c | |||
@@ -347,7 +347,8 @@ restart: | |||
347 | break; | 347 | break; |
348 | } | 348 | } |
349 | retry = __process_buffer(journal, jh, bhs,&batch_count); | 349 | retry = __process_buffer(journal, jh, bhs,&batch_count); |
350 | if (!retry && lock_need_resched(&journal->j_list_lock)){ | 350 | if (!retry && (need_resched() || |
351 | spin_needbreak(&journal->j_list_lock))) { | ||
351 | spin_unlock(&journal->j_list_lock); | 352 | spin_unlock(&journal->j_list_lock); |
352 | retry = 1; | 353 | retry = 1; |
353 | break; | 354 | break; |
diff --git a/fs/jbd/commit.c b/fs/jbd/commit.c index 610264b99a8e..31853eb65b4c 100644 --- a/fs/jbd/commit.c +++ b/fs/jbd/commit.c | |||
@@ -265,7 +265,7 @@ write_out_data: | |||
265 | put_bh(bh); | 265 | put_bh(bh); |
266 | } | 266 | } |
267 | 267 | ||
268 | if (lock_need_resched(&journal->j_list_lock)) { | 268 | if (need_resched() || spin_needbreak(&journal->j_list_lock)) { |
269 | spin_unlock(&journal->j_list_lock); | 269 | spin_unlock(&journal->j_list_lock); |
270 | goto write_out_data; | 270 | goto write_out_data; |
271 | } | 271 | } |
diff --git a/fs/jbd2/checkpoint.c b/fs/jbd2/checkpoint.c index 1b7f282c1ae9..6914598022ce 100644 --- a/fs/jbd2/checkpoint.c +++ b/fs/jbd2/checkpoint.c | |||
@@ -353,7 +353,8 @@ restart: | |||
353 | } | 353 | } |
354 | retry = __process_buffer(journal, jh, bhs, &batch_count, | 354 | retry = __process_buffer(journal, jh, bhs, &batch_count, |
355 | transaction); | 355 | transaction); |
356 | if (!retry && lock_need_resched(&journal->j_list_lock)){ | 356 | if (!retry && (need_resched() || |
357 | spin_needbreak(&journal->j_list_lock))) { | ||
357 | spin_unlock(&journal->j_list_lock); | 358 | spin_unlock(&journal->j_list_lock); |
358 | retry = 1; | 359 | retry = 1; |
359 | break; | 360 | break; |
diff --git a/fs/jbd2/commit.c b/fs/jbd2/commit.c index da8d0eb3b7b9..4f302d279279 100644 --- a/fs/jbd2/commit.c +++ b/fs/jbd2/commit.c | |||
@@ -341,7 +341,7 @@ write_out_data: | |||
341 | put_bh(bh); | 341 | put_bh(bh); |
342 | } | 342 | } |
343 | 343 | ||
344 | if (lock_need_resched(&journal->j_list_lock)) { | 344 | if (need_resched() || spin_needbreak(&journal->j_list_lock)) { |
345 | spin_unlock(&journal->j_list_lock); | 345 | spin_unlock(&journal->j_list_lock); |
346 | goto write_out_data; | 346 | goto write_out_data; |
347 | } | 347 | } |
diff --git a/fs/lockd/clntlock.c b/fs/lockd/clntlock.c index d070b18e539d..0b45fd3a4bfd 100644 --- a/fs/lockd/clntlock.c +++ b/fs/lockd/clntlock.c | |||
@@ -41,6 +41,48 @@ struct nlm_wait { | |||
41 | 41 | ||
42 | static LIST_HEAD(nlm_blocked); | 42 | static LIST_HEAD(nlm_blocked); |
43 | 43 | ||
44 | /** | ||
45 | * nlmclnt_init - Set up per-NFS mount point lockd data structures | ||
46 | * @nlm_init: pointer to arguments structure | ||
47 | * | ||
48 | * Returns pointer to an appropriate nlm_host struct, | ||
49 | * or an ERR_PTR value. | ||
50 | */ | ||
51 | struct nlm_host *nlmclnt_init(const struct nlmclnt_initdata *nlm_init) | ||
52 | { | ||
53 | struct nlm_host *host; | ||
54 | u32 nlm_version = (nlm_init->nfs_version == 2) ? 1 : 4; | ||
55 | int status; | ||
56 | |||
57 | status = lockd_up(nlm_init->protocol); | ||
58 | if (status < 0) | ||
59 | return ERR_PTR(status); | ||
60 | |||
61 | host = nlmclnt_lookup_host((struct sockaddr_in *)nlm_init->address, | ||
62 | nlm_init->protocol, nlm_version, | ||
63 | nlm_init->hostname, | ||
64 | strlen(nlm_init->hostname)); | ||
65 | if (host == NULL) { | ||
66 | lockd_down(); | ||
67 | return ERR_PTR(-ENOLCK); | ||
68 | } | ||
69 | |||
70 | return host; | ||
71 | } | ||
72 | EXPORT_SYMBOL_GPL(nlmclnt_init); | ||
73 | |||
74 | /** | ||
75 | * nlmclnt_done - Release resources allocated by nlmclnt_init() | ||
76 | * @host: nlm_host structure reserved by nlmclnt_init() | ||
77 | * | ||
78 | */ | ||
79 | void nlmclnt_done(struct nlm_host *host) | ||
80 | { | ||
81 | nlm_release_host(host); | ||
82 | lockd_down(); | ||
83 | } | ||
84 | EXPORT_SYMBOL_GPL(nlmclnt_done); | ||
85 | |||
44 | /* | 86 | /* |
45 | * Queue up a lock for blocking so that the GRANTED request can see it | 87 | * Queue up a lock for blocking so that the GRANTED request can see it |
46 | */ | 88 | */ |
diff --git a/fs/lockd/clntproc.c b/fs/lockd/clntproc.c index a10343bed160..b6b74a60e1eb 100644 --- a/fs/lockd/clntproc.c +++ b/fs/lockd/clntproc.c | |||
@@ -145,34 +145,21 @@ static void nlmclnt_release_lockargs(struct nlm_rqst *req) | |||
145 | BUG_ON(req->a_args.lock.fl.fl_ops != NULL); | 145 | BUG_ON(req->a_args.lock.fl.fl_ops != NULL); |
146 | } | 146 | } |
147 | 147 | ||
148 | /* | 148 | /** |
149 | * This is the main entry point for the NLM client. | 149 | * nlmclnt_proc - Perform a single client-side lock request |
150 | * @host: address of a valid nlm_host context representing the NLM server | ||
151 | * @cmd: fcntl-style file lock operation to perform | ||
152 | * @fl: address of arguments for the lock operation | ||
153 | * | ||
150 | */ | 154 | */ |
151 | int | 155 | int nlmclnt_proc(struct nlm_host *host, int cmd, struct file_lock *fl) |
152 | nlmclnt_proc(struct inode *inode, int cmd, struct file_lock *fl) | ||
153 | { | 156 | { |
154 | struct rpc_clnt *client = NFS_CLIENT(inode); | ||
155 | struct sockaddr_in addr; | ||
156 | struct nfs_server *nfssrv = NFS_SERVER(inode); | ||
157 | struct nlm_host *host; | ||
158 | struct nlm_rqst *call; | 157 | struct nlm_rqst *call; |
159 | sigset_t oldset; | 158 | sigset_t oldset; |
160 | unsigned long flags; | 159 | unsigned long flags; |
161 | int status, vers; | 160 | int status; |
162 | |||
163 | vers = (NFS_PROTO(inode)->version == 3) ? 4 : 1; | ||
164 | if (NFS_PROTO(inode)->version > 3) { | ||
165 | printk(KERN_NOTICE "NFSv4 file locking not implemented!\n"); | ||
166 | return -ENOLCK; | ||
167 | } | ||
168 | |||
169 | rpc_peeraddr(client, (struct sockaddr *) &addr, sizeof(addr)); | ||
170 | host = nlmclnt_lookup_host(&addr, client->cl_xprt->prot, vers, | ||
171 | nfssrv->nfs_client->cl_hostname, | ||
172 | strlen(nfssrv->nfs_client->cl_hostname)); | ||
173 | if (host == NULL) | ||
174 | return -ENOLCK; | ||
175 | 161 | ||
162 | nlm_get_host(host); | ||
176 | call = nlm_alloc_call(host); | 163 | call = nlm_alloc_call(host); |
177 | if (call == NULL) | 164 | if (call == NULL) |
178 | return -ENOMEM; | 165 | return -ENOMEM; |
@@ -219,7 +206,7 @@ nlmclnt_proc(struct inode *inode, int cmd, struct file_lock *fl) | |||
219 | dprintk("lockd: clnt proc returns %d\n", status); | 206 | dprintk("lockd: clnt proc returns %d\n", status); |
220 | return status; | 207 | return status; |
221 | } | 208 | } |
222 | EXPORT_SYMBOL(nlmclnt_proc); | 209 | EXPORT_SYMBOL_GPL(nlmclnt_proc); |
223 | 210 | ||
224 | /* | 211 | /* |
225 | * Allocate an NLM RPC call struct | 212 | * Allocate an NLM RPC call struct |
@@ -257,7 +244,7 @@ void nlm_release_call(struct nlm_rqst *call) | |||
257 | 244 | ||
258 | static void nlmclnt_rpc_release(void *data) | 245 | static void nlmclnt_rpc_release(void *data) |
259 | { | 246 | { |
260 | return nlm_release_call(data); | 247 | nlm_release_call(data); |
261 | } | 248 | } |
262 | 249 | ||
263 | static int nlm_wait_on_grace(wait_queue_head_t *queue) | 250 | static int nlm_wait_on_grace(wait_queue_head_t *queue) |
diff --git a/fs/lockd/xdr.c b/fs/lockd/xdr.c index 633653bff944..3e459e18cc31 100644 --- a/fs/lockd/xdr.c +++ b/fs/lockd/xdr.c | |||
@@ -612,8 +612,7 @@ const char *nlmdbg_cookie2a(const struct nlm_cookie *cookie) | |||
612 | * called with BKL held. | 612 | * called with BKL held. |
613 | */ | 613 | */ |
614 | static char buf[2*NLM_MAXCOOKIELEN+1]; | 614 | static char buf[2*NLM_MAXCOOKIELEN+1]; |
615 | int i; | 615 | unsigned int i, len = sizeof(buf); |
616 | int len = sizeof(buf); | ||
617 | char *p = buf; | 616 | char *p = buf; |
618 | 617 | ||
619 | len--; /* allow for trailing \0 */ | 618 | len--; /* allow for trailing \0 */ |
diff --git a/fs/nfs/callback.c b/fs/nfs/callback.c index a796be5051bf..9b6bbf1b9787 100644 --- a/fs/nfs/callback.c +++ b/fs/nfs/callback.c | |||
@@ -73,8 +73,6 @@ static void nfs_callback_svc(struct svc_rqst *rqstp) | |||
73 | complete(&nfs_callback_info.started); | 73 | complete(&nfs_callback_info.started); |
74 | 74 | ||
75 | for(;;) { | 75 | for(;;) { |
76 | char buf[RPC_MAX_ADDRBUFLEN]; | ||
77 | |||
78 | if (signalled()) { | 76 | if (signalled()) { |
79 | if (nfs_callback_info.users == 0) | 77 | if (nfs_callback_info.users == 0) |
80 | break; | 78 | break; |
@@ -92,8 +90,6 @@ static void nfs_callback_svc(struct svc_rqst *rqstp) | |||
92 | __FUNCTION__, -err); | 90 | __FUNCTION__, -err); |
93 | break; | 91 | break; |
94 | } | 92 | } |
95 | dprintk("%s: request from %s\n", __FUNCTION__, | ||
96 | svc_print_addr(rqstp, buf, sizeof(buf))); | ||
97 | svc_process(rqstp); | 93 | svc_process(rqstp); |
98 | } | 94 | } |
99 | 95 | ||
@@ -168,12 +164,11 @@ void nfs_callback_down(void) | |||
168 | 164 | ||
169 | static int nfs_callback_authenticate(struct svc_rqst *rqstp) | 165 | static int nfs_callback_authenticate(struct svc_rqst *rqstp) |
170 | { | 166 | { |
171 | struct sockaddr_in *addr = svc_addr_in(rqstp); | ||
172 | struct nfs_client *clp; | 167 | struct nfs_client *clp; |
173 | char buf[RPC_MAX_ADDRBUFLEN]; | 168 | char buf[RPC_MAX_ADDRBUFLEN]; |
174 | 169 | ||
175 | /* Don't talk to strangers */ | 170 | /* Don't talk to strangers */ |
176 | clp = nfs_find_client(addr, 4); | 171 | clp = nfs_find_client(svc_addr(rqstp), 4); |
177 | if (clp == NULL) | 172 | if (clp == NULL) |
178 | return SVC_DROP; | 173 | return SVC_DROP; |
179 | 174 | ||
diff --git a/fs/nfs/callback.h b/fs/nfs/callback.h index c2bb14e053e1..bb25d2135ff1 100644 --- a/fs/nfs/callback.h +++ b/fs/nfs/callback.h | |||
@@ -38,7 +38,7 @@ struct cb_compound_hdr_res { | |||
38 | }; | 38 | }; |
39 | 39 | ||
40 | struct cb_getattrargs { | 40 | struct cb_getattrargs { |
41 | struct sockaddr_in *addr; | 41 | struct sockaddr *addr; |
42 | struct nfs_fh fh; | 42 | struct nfs_fh fh; |
43 | uint32_t bitmap[2]; | 43 | uint32_t bitmap[2]; |
44 | }; | 44 | }; |
@@ -53,7 +53,7 @@ struct cb_getattrres { | |||
53 | }; | 53 | }; |
54 | 54 | ||
55 | struct cb_recallargs { | 55 | struct cb_recallargs { |
56 | struct sockaddr_in *addr; | 56 | struct sockaddr *addr; |
57 | struct nfs_fh fh; | 57 | struct nfs_fh fh; |
58 | nfs4_stateid stateid; | 58 | nfs4_stateid stateid; |
59 | uint32_t truncate; | 59 | uint32_t truncate; |
diff --git a/fs/nfs/callback_proc.c b/fs/nfs/callback_proc.c index 72e55d83756d..15f7785048d3 100644 --- a/fs/nfs/callback_proc.c +++ b/fs/nfs/callback_proc.c | |||
@@ -12,7 +12,9 @@ | |||
12 | #include "delegation.h" | 12 | #include "delegation.h" |
13 | #include "internal.h" | 13 | #include "internal.h" |
14 | 14 | ||
15 | #ifdef NFS_DEBUG | ||
15 | #define NFSDBG_FACILITY NFSDBG_CALLBACK | 16 | #define NFSDBG_FACILITY NFSDBG_CALLBACK |
17 | #endif | ||
16 | 18 | ||
17 | __be32 nfs4_callback_getattr(struct cb_getattrargs *args, struct cb_getattrres *res) | 19 | __be32 nfs4_callback_getattr(struct cb_getattrargs *args, struct cb_getattrres *res) |
18 | { | 20 | { |
@@ -20,12 +22,16 @@ __be32 nfs4_callback_getattr(struct cb_getattrargs *args, struct cb_getattrres * | |||
20 | struct nfs_delegation *delegation; | 22 | struct nfs_delegation *delegation; |
21 | struct nfs_inode *nfsi; | 23 | struct nfs_inode *nfsi; |
22 | struct inode *inode; | 24 | struct inode *inode; |
23 | 25 | ||
24 | res->bitmap[0] = res->bitmap[1] = 0; | 26 | res->bitmap[0] = res->bitmap[1] = 0; |
25 | res->status = htonl(NFS4ERR_BADHANDLE); | 27 | res->status = htonl(NFS4ERR_BADHANDLE); |
26 | clp = nfs_find_client(args->addr, 4); | 28 | clp = nfs_find_client(args->addr, 4); |
27 | if (clp == NULL) | 29 | if (clp == NULL) |
28 | goto out; | 30 | goto out; |
31 | |||
32 | dprintk("NFS: GETATTR callback request from %s\n", | ||
33 | rpc_peeraddr2str(clp->cl_rpcclient, RPC_DISPLAY_ADDR)); | ||
34 | |||
29 | inode = nfs_delegation_find_inode(clp, &args->fh); | 35 | inode = nfs_delegation_find_inode(clp, &args->fh); |
30 | if (inode == NULL) | 36 | if (inode == NULL) |
31 | goto out_putclient; | 37 | goto out_putclient; |
@@ -65,23 +71,32 @@ __be32 nfs4_callback_recall(struct cb_recallargs *args, void *dummy) | |||
65 | clp = nfs_find_client(args->addr, 4); | 71 | clp = nfs_find_client(args->addr, 4); |
66 | if (clp == NULL) | 72 | if (clp == NULL) |
67 | goto out; | 73 | goto out; |
68 | inode = nfs_delegation_find_inode(clp, &args->fh); | 74 | |
69 | if (inode == NULL) | 75 | dprintk("NFS: RECALL callback request from %s\n", |
70 | goto out_putclient; | 76 | rpc_peeraddr2str(clp->cl_rpcclient, RPC_DISPLAY_ADDR)); |
71 | /* Set up a helper thread to actually return the delegation */ | 77 | |
72 | switch(nfs_async_inode_return_delegation(inode, &args->stateid)) { | 78 | do { |
73 | case 0: | 79 | struct nfs_client *prev = clp; |
74 | res = 0; | 80 | |
75 | break; | 81 | inode = nfs_delegation_find_inode(clp, &args->fh); |
76 | case -ENOENT: | 82 | if (inode != NULL) { |
77 | res = htonl(NFS4ERR_BAD_STATEID); | 83 | /* Set up a helper thread to actually return the delegation */ |
78 | break; | 84 | switch(nfs_async_inode_return_delegation(inode, &args->stateid)) { |
79 | default: | 85 | case 0: |
80 | res = htonl(NFS4ERR_RESOURCE); | 86 | res = 0; |
81 | } | 87 | break; |
82 | iput(inode); | 88 | case -ENOENT: |
83 | out_putclient: | 89 | if (res != 0) |
84 | nfs_put_client(clp); | 90 | res = htonl(NFS4ERR_BAD_STATEID); |
91 | break; | ||
92 | default: | ||
93 | res = htonl(NFS4ERR_RESOURCE); | ||
94 | } | ||
95 | iput(inode); | ||
96 | } | ||
97 | clp = nfs_find_client_next(prev); | ||
98 | nfs_put_client(prev); | ||
99 | } while (clp != NULL); | ||
85 | out: | 100 | out: |
86 | dprintk("%s: exit with status = %d\n", __FUNCTION__, ntohl(res)); | 101 | dprintk("%s: exit with status = %d\n", __FUNCTION__, ntohl(res)); |
87 | return res; | 102 | return res; |
diff --git a/fs/nfs/callback_xdr.c b/fs/nfs/callback_xdr.c index 058ade7efe79..c63eb720b68b 100644 --- a/fs/nfs/callback_xdr.c +++ b/fs/nfs/callback_xdr.c | |||
@@ -139,7 +139,7 @@ static __be32 decode_compound_hdr_arg(struct xdr_stream *xdr, struct cb_compound | |||
139 | if (unlikely(status != 0)) | 139 | if (unlikely(status != 0)) |
140 | return status; | 140 | return status; |
141 | /* We do not like overly long tags! */ | 141 | /* We do not like overly long tags! */ |
142 | if (hdr->taglen > CB_OP_TAGLEN_MAXSZ-12 || hdr->taglen < 0) { | 142 | if (hdr->taglen > CB_OP_TAGLEN_MAXSZ - 12) { |
143 | printk("NFSv4 CALLBACK %s: client sent tag of length %u\n", | 143 | printk("NFSv4 CALLBACK %s: client sent tag of length %u\n", |
144 | __FUNCTION__, hdr->taglen); | 144 | __FUNCTION__, hdr->taglen); |
145 | return htonl(NFS4ERR_RESOURCE); | 145 | return htonl(NFS4ERR_RESOURCE); |
@@ -176,7 +176,7 @@ static __be32 decode_getattr_args(struct svc_rqst *rqstp, struct xdr_stream *xdr | |||
176 | status = decode_fh(xdr, &args->fh); | 176 | status = decode_fh(xdr, &args->fh); |
177 | if (unlikely(status != 0)) | 177 | if (unlikely(status != 0)) |
178 | goto out; | 178 | goto out; |
179 | args->addr = svc_addr_in(rqstp); | 179 | args->addr = svc_addr(rqstp); |
180 | status = decode_bitmap(xdr, args->bitmap); | 180 | status = decode_bitmap(xdr, args->bitmap); |
181 | out: | 181 | out: |
182 | dprintk("%s: exit with status = %d\n", __FUNCTION__, ntohl(status)); | 182 | dprintk("%s: exit with status = %d\n", __FUNCTION__, ntohl(status)); |
@@ -188,7 +188,7 @@ static __be32 decode_recall_args(struct svc_rqst *rqstp, struct xdr_stream *xdr, | |||
188 | __be32 *p; | 188 | __be32 *p; |
189 | __be32 status; | 189 | __be32 status; |
190 | 190 | ||
191 | args->addr = svc_addr_in(rqstp); | 191 | args->addr = svc_addr(rqstp); |
192 | status = decode_stateid(xdr, &args->stateid); | 192 | status = decode_stateid(xdr, &args->stateid); |
193 | if (unlikely(status != 0)) | 193 | if (unlikely(status != 0)) |
194 | goto out; | 194 | goto out; |
diff --git a/fs/nfs/client.c b/fs/nfs/client.c index a6f625497612..685c43f810c1 100644 --- a/fs/nfs/client.c +++ b/fs/nfs/client.c | |||
@@ -34,6 +34,8 @@ | |||
34 | #include <linux/nfs_idmap.h> | 34 | #include <linux/nfs_idmap.h> |
35 | #include <linux/vfs.h> | 35 | #include <linux/vfs.h> |
36 | #include <linux/inet.h> | 36 | #include <linux/inet.h> |
37 | #include <linux/in6.h> | ||
38 | #include <net/ipv6.h> | ||
37 | #include <linux/nfs_xdr.h> | 39 | #include <linux/nfs_xdr.h> |
38 | 40 | ||
39 | #include <asm/system.h> | 41 | #include <asm/system.h> |
@@ -93,22 +95,30 @@ struct rpc_program nfsacl_program = { | |||
93 | }; | 95 | }; |
94 | #endif /* CONFIG_NFS_V3_ACL */ | 96 | #endif /* CONFIG_NFS_V3_ACL */ |
95 | 97 | ||
98 | struct nfs_client_initdata { | ||
99 | const char *hostname; | ||
100 | const struct sockaddr *addr; | ||
101 | size_t addrlen; | ||
102 | const struct nfs_rpc_ops *rpc_ops; | ||
103 | int proto; | ||
104 | }; | ||
105 | |||
96 | /* | 106 | /* |
97 | * Allocate a shared client record | 107 | * Allocate a shared client record |
98 | * | 108 | * |
99 | * Since these are allocated/deallocated very rarely, we don't | 109 | * Since these are allocated/deallocated very rarely, we don't |
100 | * bother putting them in a slab cache... | 110 | * bother putting them in a slab cache... |
101 | */ | 111 | */ |
102 | static struct nfs_client *nfs_alloc_client(const char *hostname, | 112 | static struct nfs_client *nfs_alloc_client(const struct nfs_client_initdata *cl_init) |
103 | const struct sockaddr_in *addr, | ||
104 | int nfsversion) | ||
105 | { | 113 | { |
106 | struct nfs_client *clp; | 114 | struct nfs_client *clp; |
107 | 115 | ||
108 | if ((clp = kzalloc(sizeof(*clp), GFP_KERNEL)) == NULL) | 116 | if ((clp = kzalloc(sizeof(*clp), GFP_KERNEL)) == NULL) |
109 | goto error_0; | 117 | goto error_0; |
110 | 118 | ||
111 | if (nfsversion == 4) { | 119 | clp->rpc_ops = cl_init->rpc_ops; |
120 | |||
121 | if (cl_init->rpc_ops->version == 4) { | ||
112 | if (nfs_callback_up() < 0) | 122 | if (nfs_callback_up() < 0) |
113 | goto error_2; | 123 | goto error_2; |
114 | __set_bit(NFS_CS_CALLBACK, &clp->cl_res_state); | 124 | __set_bit(NFS_CS_CALLBACK, &clp->cl_res_state); |
@@ -117,11 +127,11 @@ static struct nfs_client *nfs_alloc_client(const char *hostname, | |||
117 | atomic_set(&clp->cl_count, 1); | 127 | atomic_set(&clp->cl_count, 1); |
118 | clp->cl_cons_state = NFS_CS_INITING; | 128 | clp->cl_cons_state = NFS_CS_INITING; |
119 | 129 | ||
120 | clp->cl_nfsversion = nfsversion; | 130 | memcpy(&clp->cl_addr, cl_init->addr, cl_init->addrlen); |
121 | memcpy(&clp->cl_addr, addr, sizeof(clp->cl_addr)); | 131 | clp->cl_addrlen = cl_init->addrlen; |
122 | 132 | ||
123 | if (hostname) { | 133 | if (cl_init->hostname) { |
124 | clp->cl_hostname = kstrdup(hostname, GFP_KERNEL); | 134 | clp->cl_hostname = kstrdup(cl_init->hostname, GFP_KERNEL); |
125 | if (!clp->cl_hostname) | 135 | if (!clp->cl_hostname) |
126 | goto error_3; | 136 | goto error_3; |
127 | } | 137 | } |
@@ -129,6 +139,8 @@ static struct nfs_client *nfs_alloc_client(const char *hostname, | |||
129 | INIT_LIST_HEAD(&clp->cl_superblocks); | 139 | INIT_LIST_HEAD(&clp->cl_superblocks); |
130 | clp->cl_rpcclient = ERR_PTR(-EINVAL); | 140 | clp->cl_rpcclient = ERR_PTR(-EINVAL); |
131 | 141 | ||
142 | clp->cl_proto = cl_init->proto; | ||
143 | |||
132 | #ifdef CONFIG_NFS_V4 | 144 | #ifdef CONFIG_NFS_V4 |
133 | init_rwsem(&clp->cl_sem); | 145 | init_rwsem(&clp->cl_sem); |
134 | INIT_LIST_HEAD(&clp->cl_delegations); | 146 | INIT_LIST_HEAD(&clp->cl_delegations); |
@@ -166,7 +178,7 @@ static void nfs4_shutdown_client(struct nfs_client *clp) | |||
166 | */ | 178 | */ |
167 | static void nfs_free_client(struct nfs_client *clp) | 179 | static void nfs_free_client(struct nfs_client *clp) |
168 | { | 180 | { |
169 | dprintk("--> nfs_free_client(%d)\n", clp->cl_nfsversion); | 181 | dprintk("--> nfs_free_client(%u)\n", clp->rpc_ops->version); |
170 | 182 | ||
171 | nfs4_shutdown_client(clp); | 183 | nfs4_shutdown_client(clp); |
172 | 184 | ||
@@ -203,76 +215,148 @@ void nfs_put_client(struct nfs_client *clp) | |||
203 | } | 215 | } |
204 | } | 216 | } |
205 | 217 | ||
218 | static int nfs_sockaddr_match_ipaddr4(const struct sockaddr_in *sa1, | ||
219 | const struct sockaddr_in *sa2) | ||
220 | { | ||
221 | return sa1->sin_addr.s_addr == sa2->sin_addr.s_addr; | ||
222 | } | ||
223 | |||
224 | static int nfs_sockaddr_match_ipaddr6(const struct sockaddr_in6 *sa1, | ||
225 | const struct sockaddr_in6 *sa2) | ||
226 | { | ||
227 | return ipv6_addr_equal(&sa1->sin6_addr, &sa2->sin6_addr); | ||
228 | } | ||
229 | |||
230 | static int nfs_sockaddr_match_ipaddr(const struct sockaddr *sa1, | ||
231 | const struct sockaddr *sa2) | ||
232 | { | ||
233 | switch (sa1->sa_family) { | ||
234 | case AF_INET: | ||
235 | return nfs_sockaddr_match_ipaddr4((const struct sockaddr_in *)sa1, | ||
236 | (const struct sockaddr_in *)sa2); | ||
237 | case AF_INET6: | ||
238 | return nfs_sockaddr_match_ipaddr6((const struct sockaddr_in6 *)sa1, | ||
239 | (const struct sockaddr_in6 *)sa2); | ||
240 | } | ||
241 | BUG(); | ||
242 | } | ||
243 | |||
206 | /* | 244 | /* |
207 | * Find a client by address | 245 | * Find a client by IP address and protocol version |
208 | * - caller must hold nfs_client_lock | 246 | * - returns NULL if no such client |
209 | */ | 247 | */ |
210 | static struct nfs_client *__nfs_find_client(const struct sockaddr_in *addr, int nfsversion, int match_port) | 248 | struct nfs_client *nfs_find_client(const struct sockaddr *addr, u32 nfsversion) |
211 | { | 249 | { |
212 | struct nfs_client *clp; | 250 | struct nfs_client *clp; |
213 | 251 | ||
252 | spin_lock(&nfs_client_lock); | ||
214 | list_for_each_entry(clp, &nfs_client_list, cl_share_link) { | 253 | list_for_each_entry(clp, &nfs_client_list, cl_share_link) { |
254 | struct sockaddr *clap = (struct sockaddr *)&clp->cl_addr; | ||
255 | |||
215 | /* Don't match clients that failed to initialise properly */ | 256 | /* Don't match clients that failed to initialise properly */ |
216 | if (clp->cl_cons_state < 0) | 257 | if (clp->cl_cons_state != NFS_CS_READY) |
217 | continue; | 258 | continue; |
218 | 259 | ||
219 | /* Different NFS versions cannot share the same nfs_client */ | 260 | /* Different NFS versions cannot share the same nfs_client */ |
220 | if (clp->cl_nfsversion != nfsversion) | 261 | if (clp->rpc_ops->version != nfsversion) |
221 | continue; | 262 | continue; |
222 | 263 | ||
223 | if (memcmp(&clp->cl_addr.sin_addr, &addr->sin_addr, | 264 | if (addr->sa_family != clap->sa_family) |
224 | sizeof(clp->cl_addr.sin_addr)) != 0) | 265 | continue; |
266 | /* Match only the IP address, not the port number */ | ||
267 | if (!nfs_sockaddr_match_ipaddr(addr, clap)) | ||
225 | continue; | 268 | continue; |
226 | 269 | ||
227 | if (!match_port || clp->cl_addr.sin_port == addr->sin_port) | 270 | atomic_inc(&clp->cl_count); |
228 | goto found; | 271 | spin_unlock(&nfs_client_lock); |
272 | return clp; | ||
229 | } | 273 | } |
230 | 274 | spin_unlock(&nfs_client_lock); | |
231 | return NULL; | 275 | return NULL; |
232 | |||
233 | found: | ||
234 | atomic_inc(&clp->cl_count); | ||
235 | return clp; | ||
236 | } | 276 | } |
237 | 277 | ||
238 | /* | 278 | /* |
239 | * Find a client by IP address and protocol version | 279 | * Find a client by IP address and protocol version |
240 | * - returns NULL if no such client | 280 | * - returns NULL if no such client |
241 | */ | 281 | */ |
242 | struct nfs_client *nfs_find_client(const struct sockaddr_in *addr, int nfsversion) | 282 | struct nfs_client *nfs_find_client_next(struct nfs_client *clp) |
243 | { | 283 | { |
244 | struct nfs_client *clp; | 284 | struct sockaddr *sap = (struct sockaddr *)&clp->cl_addr; |
285 | u32 nfsvers = clp->rpc_ops->version; | ||
245 | 286 | ||
246 | spin_lock(&nfs_client_lock); | 287 | spin_lock(&nfs_client_lock); |
247 | clp = __nfs_find_client(addr, nfsversion, 0); | 288 | list_for_each_entry_continue(clp, &nfs_client_list, cl_share_link) { |
289 | struct sockaddr *clap = (struct sockaddr *)&clp->cl_addr; | ||
290 | |||
291 | /* Don't match clients that failed to initialise properly */ | ||
292 | if (clp->cl_cons_state != NFS_CS_READY) | ||
293 | continue; | ||
294 | |||
295 | /* Different NFS versions cannot share the same nfs_client */ | ||
296 | if (clp->rpc_ops->version != nfsvers) | ||
297 | continue; | ||
298 | |||
299 | if (sap->sa_family != clap->sa_family) | ||
300 | continue; | ||
301 | /* Match only the IP address, not the port number */ | ||
302 | if (!nfs_sockaddr_match_ipaddr(sap, clap)) | ||
303 | continue; | ||
304 | |||
305 | atomic_inc(&clp->cl_count); | ||
306 | spin_unlock(&nfs_client_lock); | ||
307 | return clp; | ||
308 | } | ||
248 | spin_unlock(&nfs_client_lock); | 309 | spin_unlock(&nfs_client_lock); |
249 | if (clp != NULL && clp->cl_cons_state != NFS_CS_READY) { | 310 | return NULL; |
250 | nfs_put_client(clp); | 311 | } |
251 | clp = NULL; | 312 | |
313 | /* | ||
314 | * Find an nfs_client on the list that matches the initialisation data | ||
315 | * that is supplied. | ||
316 | */ | ||
317 | static struct nfs_client *nfs_match_client(const struct nfs_client_initdata *data) | ||
318 | { | ||
319 | struct nfs_client *clp; | ||
320 | |||
321 | list_for_each_entry(clp, &nfs_client_list, cl_share_link) { | ||
322 | /* Don't match clients that failed to initialise properly */ | ||
323 | if (clp->cl_cons_state < 0) | ||
324 | continue; | ||
325 | |||
326 | /* Different NFS versions cannot share the same nfs_client */ | ||
327 | if (clp->rpc_ops != data->rpc_ops) | ||
328 | continue; | ||
329 | |||
330 | if (clp->cl_proto != data->proto) | ||
331 | continue; | ||
332 | |||
333 | /* Match the full socket address */ | ||
334 | if (memcmp(&clp->cl_addr, data->addr, sizeof(clp->cl_addr)) != 0) | ||
335 | continue; | ||
336 | |||
337 | atomic_inc(&clp->cl_count); | ||
338 | return clp; | ||
252 | } | 339 | } |
253 | return clp; | 340 | return NULL; |
254 | } | 341 | } |
255 | 342 | ||
256 | /* | 343 | /* |
257 | * Look up a client by IP address and protocol version | 344 | * Look up a client by IP address and protocol version |
258 | * - creates a new record if one doesn't yet exist | 345 | * - creates a new record if one doesn't yet exist |
259 | */ | 346 | */ |
260 | static struct nfs_client *nfs_get_client(const char *hostname, | 347 | static struct nfs_client *nfs_get_client(const struct nfs_client_initdata *cl_init) |
261 | const struct sockaddr_in *addr, | ||
262 | int nfsversion) | ||
263 | { | 348 | { |
264 | struct nfs_client *clp, *new = NULL; | 349 | struct nfs_client *clp, *new = NULL; |
265 | int error; | 350 | int error; |
266 | 351 | ||
267 | dprintk("--> nfs_get_client(%s,"NIPQUAD_FMT":%d,%d)\n", | 352 | dprintk("--> nfs_get_client(%s,v%u)\n", |
268 | hostname ?: "", NIPQUAD(addr->sin_addr), | 353 | cl_init->hostname ?: "", cl_init->rpc_ops->version); |
269 | addr->sin_port, nfsversion); | ||
270 | 354 | ||
271 | /* see if the client already exists */ | 355 | /* see if the client already exists */ |
272 | do { | 356 | do { |
273 | spin_lock(&nfs_client_lock); | 357 | spin_lock(&nfs_client_lock); |
274 | 358 | ||
275 | clp = __nfs_find_client(addr, nfsversion, 1); | 359 | clp = nfs_match_client(cl_init); |
276 | if (clp) | 360 | if (clp) |
277 | goto found_client; | 361 | goto found_client; |
278 | if (new) | 362 | if (new) |
@@ -280,7 +364,7 @@ static struct nfs_client *nfs_get_client(const char *hostname, | |||
280 | 364 | ||
281 | spin_unlock(&nfs_client_lock); | 365 | spin_unlock(&nfs_client_lock); |
282 | 366 | ||
283 | new = nfs_alloc_client(hostname, addr, nfsversion); | 367 | new = nfs_alloc_client(cl_init); |
284 | } while (new); | 368 | } while (new); |
285 | 369 | ||
286 | return ERR_PTR(-ENOMEM); | 370 | return ERR_PTR(-ENOMEM); |
@@ -344,12 +428,16 @@ static void nfs_init_timeout_values(struct rpc_timeout *to, int proto, | |||
344 | switch (proto) { | 428 | switch (proto) { |
345 | case XPRT_TRANSPORT_TCP: | 429 | case XPRT_TRANSPORT_TCP: |
346 | case XPRT_TRANSPORT_RDMA: | 430 | case XPRT_TRANSPORT_RDMA: |
347 | if (!to->to_initval) | 431 | if (to->to_initval == 0) |
348 | to->to_initval = 60 * HZ; | 432 | to->to_initval = 60 * HZ; |
349 | if (to->to_initval > NFS_MAX_TCP_TIMEOUT) | 433 | if (to->to_initval > NFS_MAX_TCP_TIMEOUT) |
350 | to->to_initval = NFS_MAX_TCP_TIMEOUT; | 434 | to->to_initval = NFS_MAX_TCP_TIMEOUT; |
351 | to->to_increment = to->to_initval; | 435 | to->to_increment = to->to_initval; |
352 | to->to_maxval = to->to_initval + (to->to_increment * to->to_retries); | 436 | to->to_maxval = to->to_initval + (to->to_increment * to->to_retries); |
437 | if (to->to_maxval > NFS_MAX_TCP_TIMEOUT) | ||
438 | to->to_maxval = NFS_MAX_TCP_TIMEOUT; | ||
439 | if (to->to_maxval < to->to_initval) | ||
440 | to->to_maxval = to->to_initval; | ||
353 | to->to_exponential = 0; | 441 | to->to_exponential = 0; |
354 | break; | 442 | break; |
355 | case XPRT_TRANSPORT_UDP: | 443 | case XPRT_TRANSPORT_UDP: |
@@ -367,19 +455,17 @@ static void nfs_init_timeout_values(struct rpc_timeout *to, int proto, | |||
367 | /* | 455 | /* |
368 | * Create an RPC client handle | 456 | * Create an RPC client handle |
369 | */ | 457 | */ |
370 | static int nfs_create_rpc_client(struct nfs_client *clp, int proto, | 458 | static int nfs_create_rpc_client(struct nfs_client *clp, |
371 | unsigned int timeo, | 459 | const struct rpc_timeout *timeparms, |
372 | unsigned int retrans, | 460 | rpc_authflavor_t flavor, |
373 | rpc_authflavor_t flavor, | 461 | int flags) |
374 | int flags) | ||
375 | { | 462 | { |
376 | struct rpc_timeout timeparms; | ||
377 | struct rpc_clnt *clnt = NULL; | 463 | struct rpc_clnt *clnt = NULL; |
378 | struct rpc_create_args args = { | 464 | struct rpc_create_args args = { |
379 | .protocol = proto, | 465 | .protocol = clp->cl_proto, |
380 | .address = (struct sockaddr *)&clp->cl_addr, | 466 | .address = (struct sockaddr *)&clp->cl_addr, |
381 | .addrsize = sizeof(clp->cl_addr), | 467 | .addrsize = clp->cl_addrlen, |
382 | .timeout = &timeparms, | 468 | .timeout = timeparms, |
383 | .servername = clp->cl_hostname, | 469 | .servername = clp->cl_hostname, |
384 | .program = &nfs_program, | 470 | .program = &nfs_program, |
385 | .version = clp->rpc_ops->version, | 471 | .version = clp->rpc_ops->version, |
@@ -390,10 +476,6 @@ static int nfs_create_rpc_client(struct nfs_client *clp, int proto, | |||
390 | if (!IS_ERR(clp->cl_rpcclient)) | 476 | if (!IS_ERR(clp->cl_rpcclient)) |
391 | return 0; | 477 | return 0; |
392 | 478 | ||
393 | nfs_init_timeout_values(&timeparms, proto, timeo, retrans); | ||
394 | clp->retrans_timeo = timeparms.to_initval; | ||
395 | clp->retrans_count = timeparms.to_retries; | ||
396 | |||
397 | clnt = rpc_create(&args); | 479 | clnt = rpc_create(&args); |
398 | if (IS_ERR(clnt)) { | 480 | if (IS_ERR(clnt)) { |
399 | dprintk("%s: cannot create RPC client. Error = %ld\n", | 481 | dprintk("%s: cannot create RPC client. Error = %ld\n", |
@@ -411,7 +493,7 @@ static int nfs_create_rpc_client(struct nfs_client *clp, int proto, | |||
411 | static void nfs_destroy_server(struct nfs_server *server) | 493 | static void nfs_destroy_server(struct nfs_server *server) |
412 | { | 494 | { |
413 | if (!(server->flags & NFS_MOUNT_NONLM)) | 495 | if (!(server->flags & NFS_MOUNT_NONLM)) |
414 | lockd_down(); /* release rpc.lockd */ | 496 | nlmclnt_done(server->nlm_host); |
415 | } | 497 | } |
416 | 498 | ||
417 | /* | 499 | /* |
@@ -419,20 +501,29 @@ static void nfs_destroy_server(struct nfs_server *server) | |||
419 | */ | 501 | */ |
420 | static int nfs_start_lockd(struct nfs_server *server) | 502 | static int nfs_start_lockd(struct nfs_server *server) |
421 | { | 503 | { |
422 | int error = 0; | 504 | struct nlm_host *host; |
505 | struct nfs_client *clp = server->nfs_client; | ||
506 | struct nlmclnt_initdata nlm_init = { | ||
507 | .hostname = clp->cl_hostname, | ||
508 | .address = (struct sockaddr *)&clp->cl_addr, | ||
509 | .addrlen = clp->cl_addrlen, | ||
510 | .protocol = server->flags & NFS_MOUNT_TCP ? | ||
511 | IPPROTO_TCP : IPPROTO_UDP, | ||
512 | .nfs_version = clp->rpc_ops->version, | ||
513 | }; | ||
423 | 514 | ||
424 | if (server->nfs_client->cl_nfsversion > 3) | 515 | if (nlm_init.nfs_version > 3) |
425 | goto out; | 516 | return 0; |
426 | if (server->flags & NFS_MOUNT_NONLM) | 517 | if (server->flags & NFS_MOUNT_NONLM) |
427 | goto out; | 518 | return 0; |
428 | error = lockd_up((server->flags & NFS_MOUNT_TCP) ? | 519 | |
429 | IPPROTO_TCP : IPPROTO_UDP); | 520 | host = nlmclnt_init(&nlm_init); |
430 | if (error < 0) | 521 | if (IS_ERR(host)) |
431 | server->flags |= NFS_MOUNT_NONLM; | 522 | return PTR_ERR(host); |
432 | else | 523 | |
433 | server->destroy = nfs_destroy_server; | 524 | server->nlm_host = host; |
434 | out: | 525 | server->destroy = nfs_destroy_server; |
435 | return error; | 526 | return 0; |
436 | } | 527 | } |
437 | 528 | ||
438 | /* | 529 | /* |
@@ -441,7 +532,7 @@ out: | |||
441 | #ifdef CONFIG_NFS_V3_ACL | 532 | #ifdef CONFIG_NFS_V3_ACL |
442 | static void nfs_init_server_aclclient(struct nfs_server *server) | 533 | static void nfs_init_server_aclclient(struct nfs_server *server) |
443 | { | 534 | { |
444 | if (server->nfs_client->cl_nfsversion != 3) | 535 | if (server->nfs_client->rpc_ops->version != 3) |
445 | goto out_noacl; | 536 | goto out_noacl; |
446 | if (server->flags & NFS_MOUNT_NOACL) | 537 | if (server->flags & NFS_MOUNT_NOACL) |
447 | goto out_noacl; | 538 | goto out_noacl; |
@@ -468,7 +559,9 @@ static inline void nfs_init_server_aclclient(struct nfs_server *server) | |||
468 | /* | 559 | /* |
469 | * Create a general RPC client | 560 | * Create a general RPC client |
470 | */ | 561 | */ |
471 | static int nfs_init_server_rpcclient(struct nfs_server *server, rpc_authflavor_t pseudoflavour) | 562 | static int nfs_init_server_rpcclient(struct nfs_server *server, |
563 | const struct rpc_timeout *timeo, | ||
564 | rpc_authflavor_t pseudoflavour) | ||
472 | { | 565 | { |
473 | struct nfs_client *clp = server->nfs_client; | 566 | struct nfs_client *clp = server->nfs_client; |
474 | 567 | ||
@@ -478,6 +571,11 @@ static int nfs_init_server_rpcclient(struct nfs_server *server, rpc_authflavor_t | |||
478 | return PTR_ERR(server->client); | 571 | return PTR_ERR(server->client); |
479 | } | 572 | } |
480 | 573 | ||
574 | memcpy(&server->client->cl_timeout_default, | ||
575 | timeo, | ||
576 | sizeof(server->client->cl_timeout_default)); | ||
577 | server->client->cl_timeout = &server->client->cl_timeout_default; | ||
578 | |||
481 | if (pseudoflavour != clp->cl_rpcclient->cl_auth->au_flavor) { | 579 | if (pseudoflavour != clp->cl_rpcclient->cl_auth->au_flavor) { |
482 | struct rpc_auth *auth; | 580 | struct rpc_auth *auth; |
483 | 581 | ||
@@ -502,6 +600,7 @@ static int nfs_init_server_rpcclient(struct nfs_server *server, rpc_authflavor_t | |||
502 | * Initialise an NFS2 or NFS3 client | 600 | * Initialise an NFS2 or NFS3 client |
503 | */ | 601 | */ |
504 | static int nfs_init_client(struct nfs_client *clp, | 602 | static int nfs_init_client(struct nfs_client *clp, |
603 | const struct rpc_timeout *timeparms, | ||
505 | const struct nfs_parsed_mount_data *data) | 604 | const struct nfs_parsed_mount_data *data) |
506 | { | 605 | { |
507 | int error; | 606 | int error; |
@@ -512,18 +611,11 @@ static int nfs_init_client(struct nfs_client *clp, | |||
512 | return 0; | 611 | return 0; |
513 | } | 612 | } |
514 | 613 | ||
515 | /* Check NFS protocol revision and initialize RPC op vector */ | ||
516 | clp->rpc_ops = &nfs_v2_clientops; | ||
517 | #ifdef CONFIG_NFS_V3 | ||
518 | if (clp->cl_nfsversion == 3) | ||
519 | clp->rpc_ops = &nfs_v3_clientops; | ||
520 | #endif | ||
521 | /* | 614 | /* |
522 | * Create a client RPC handle for doing FSSTAT with UNIX auth only | 615 | * Create a client RPC handle for doing FSSTAT with UNIX auth only |
523 | * - RFC 2623, sec 2.3.2 | 616 | * - RFC 2623, sec 2.3.2 |
524 | */ | 617 | */ |
525 | error = nfs_create_rpc_client(clp, data->nfs_server.protocol, | 618 | error = nfs_create_rpc_client(clp, timeparms, RPC_AUTH_UNIX, 0); |
526 | data->timeo, data->retrans, RPC_AUTH_UNIX, 0); | ||
527 | if (error < 0) | 619 | if (error < 0) |
528 | goto error; | 620 | goto error; |
529 | nfs_mark_client_ready(clp, NFS_CS_READY); | 621 | nfs_mark_client_ready(clp, NFS_CS_READY); |
@@ -541,25 +633,34 @@ error: | |||
541 | static int nfs_init_server(struct nfs_server *server, | 633 | static int nfs_init_server(struct nfs_server *server, |
542 | const struct nfs_parsed_mount_data *data) | 634 | const struct nfs_parsed_mount_data *data) |
543 | { | 635 | { |
636 | struct nfs_client_initdata cl_init = { | ||
637 | .hostname = data->nfs_server.hostname, | ||
638 | .addr = (const struct sockaddr *)&data->nfs_server.address, | ||
639 | .addrlen = data->nfs_server.addrlen, | ||
640 | .rpc_ops = &nfs_v2_clientops, | ||
641 | .proto = data->nfs_server.protocol, | ||
642 | }; | ||
643 | struct rpc_timeout timeparms; | ||
544 | struct nfs_client *clp; | 644 | struct nfs_client *clp; |
545 | int error, nfsvers = 2; | 645 | int error; |
546 | 646 | ||
547 | dprintk("--> nfs_init_server()\n"); | 647 | dprintk("--> nfs_init_server()\n"); |
548 | 648 | ||
549 | #ifdef CONFIG_NFS_V3 | 649 | #ifdef CONFIG_NFS_V3 |
550 | if (data->flags & NFS_MOUNT_VER3) | 650 | if (data->flags & NFS_MOUNT_VER3) |
551 | nfsvers = 3; | 651 | cl_init.rpc_ops = &nfs_v3_clientops; |
552 | #endif | 652 | #endif |
553 | 653 | ||
554 | /* Allocate or find a client reference we can use */ | 654 | /* Allocate or find a client reference we can use */ |
555 | clp = nfs_get_client(data->nfs_server.hostname, | 655 | clp = nfs_get_client(&cl_init); |
556 | &data->nfs_server.address, nfsvers); | ||
557 | if (IS_ERR(clp)) { | 656 | if (IS_ERR(clp)) { |
558 | dprintk("<-- nfs_init_server() = error %ld\n", PTR_ERR(clp)); | 657 | dprintk("<-- nfs_init_server() = error %ld\n", PTR_ERR(clp)); |
559 | return PTR_ERR(clp); | 658 | return PTR_ERR(clp); |
560 | } | 659 | } |
561 | 660 | ||
562 | error = nfs_init_client(clp, data); | 661 | nfs_init_timeout_values(&timeparms, data->nfs_server.protocol, |
662 | data->timeo, data->retrans); | ||
663 | error = nfs_init_client(clp, &timeparms, data); | ||
563 | if (error < 0) | 664 | if (error < 0) |
564 | goto error; | 665 | goto error; |
565 | 666 | ||
@@ -583,7 +684,7 @@ static int nfs_init_server(struct nfs_server *server, | |||
583 | if (error < 0) | 684 | if (error < 0) |
584 | goto error; | 685 | goto error; |
585 | 686 | ||
586 | error = nfs_init_server_rpcclient(server, data->auth_flavors[0]); | 687 | error = nfs_init_server_rpcclient(server, &timeparms, data->auth_flavors[0]); |
587 | if (error < 0) | 688 | if (error < 0) |
588 | goto error; | 689 | goto error; |
589 | 690 | ||
@@ -729,6 +830,9 @@ static struct nfs_server *nfs_alloc_server(void) | |||
729 | INIT_LIST_HEAD(&server->client_link); | 830 | INIT_LIST_HEAD(&server->client_link); |
730 | INIT_LIST_HEAD(&server->master_link); | 831 | INIT_LIST_HEAD(&server->master_link); |
731 | 832 | ||
833 | init_waitqueue_head(&server->active_wq); | ||
834 | atomic_set(&server->active, 0); | ||
835 | |||
732 | server->io_stats = nfs_alloc_iostats(); | 836 | server->io_stats = nfs_alloc_iostats(); |
733 | if (!server->io_stats) { | 837 | if (!server->io_stats) { |
734 | kfree(server); | 838 | kfree(server); |
@@ -840,7 +944,7 @@ error: | |||
840 | * Initialise an NFS4 client record | 944 | * Initialise an NFS4 client record |
841 | */ | 945 | */ |
842 | static int nfs4_init_client(struct nfs_client *clp, | 946 | static int nfs4_init_client(struct nfs_client *clp, |
843 | int proto, int timeo, int retrans, | 947 | const struct rpc_timeout *timeparms, |
844 | const char *ip_addr, | 948 | const char *ip_addr, |
845 | rpc_authflavor_t authflavour) | 949 | rpc_authflavor_t authflavour) |
846 | { | 950 | { |
@@ -855,7 +959,7 @@ static int nfs4_init_client(struct nfs_client *clp, | |||
855 | /* Check NFS protocol revision and initialize RPC op vector */ | 959 | /* Check NFS protocol revision and initialize RPC op vector */ |
856 | clp->rpc_ops = &nfs_v4_clientops; | 960 | clp->rpc_ops = &nfs_v4_clientops; |
857 | 961 | ||
858 | error = nfs_create_rpc_client(clp, proto, timeo, retrans, authflavour, | 962 | error = nfs_create_rpc_client(clp, timeparms, authflavour, |
859 | RPC_CLNT_CREATE_DISCRTRY); | 963 | RPC_CLNT_CREATE_DISCRTRY); |
860 | if (error < 0) | 964 | if (error < 0) |
861 | goto error; | 965 | goto error; |
@@ -882,23 +986,32 @@ error: | |||
882 | * Set up an NFS4 client | 986 | * Set up an NFS4 client |
883 | */ | 987 | */ |
884 | static int nfs4_set_client(struct nfs_server *server, | 988 | static int nfs4_set_client(struct nfs_server *server, |
885 | const char *hostname, const struct sockaddr_in *addr, | 989 | const char *hostname, |
990 | const struct sockaddr *addr, | ||
991 | const size_t addrlen, | ||
886 | const char *ip_addr, | 992 | const char *ip_addr, |
887 | rpc_authflavor_t authflavour, | 993 | rpc_authflavor_t authflavour, |
888 | int proto, int timeo, int retrans) | 994 | int proto, const struct rpc_timeout *timeparms) |
889 | { | 995 | { |
996 | struct nfs_client_initdata cl_init = { | ||
997 | .hostname = hostname, | ||
998 | .addr = addr, | ||
999 | .addrlen = addrlen, | ||
1000 | .rpc_ops = &nfs_v4_clientops, | ||
1001 | .proto = proto, | ||
1002 | }; | ||
890 | struct nfs_client *clp; | 1003 | struct nfs_client *clp; |
891 | int error; | 1004 | int error; |
892 | 1005 | ||
893 | dprintk("--> nfs4_set_client()\n"); | 1006 | dprintk("--> nfs4_set_client()\n"); |
894 | 1007 | ||
895 | /* Allocate or find a client reference we can use */ | 1008 | /* Allocate or find a client reference we can use */ |
896 | clp = nfs_get_client(hostname, addr, 4); | 1009 | clp = nfs_get_client(&cl_init); |
897 | if (IS_ERR(clp)) { | 1010 | if (IS_ERR(clp)) { |
898 | error = PTR_ERR(clp); | 1011 | error = PTR_ERR(clp); |
899 | goto error; | 1012 | goto error; |
900 | } | 1013 | } |
901 | error = nfs4_init_client(clp, proto, timeo, retrans, ip_addr, authflavour); | 1014 | error = nfs4_init_client(clp, timeparms, ip_addr, authflavour); |
902 | if (error < 0) | 1015 | if (error < 0) |
903 | goto error_put; | 1016 | goto error_put; |
904 | 1017 | ||
@@ -919,10 +1032,26 @@ error: | |||
919 | static int nfs4_init_server(struct nfs_server *server, | 1032 | static int nfs4_init_server(struct nfs_server *server, |
920 | const struct nfs_parsed_mount_data *data) | 1033 | const struct nfs_parsed_mount_data *data) |
921 | { | 1034 | { |
1035 | struct rpc_timeout timeparms; | ||
922 | int error; | 1036 | int error; |
923 | 1037 | ||
924 | dprintk("--> nfs4_init_server()\n"); | 1038 | dprintk("--> nfs4_init_server()\n"); |
925 | 1039 | ||
1040 | nfs_init_timeout_values(&timeparms, data->nfs_server.protocol, | ||
1041 | data->timeo, data->retrans); | ||
1042 | |||
1043 | /* Get a client record */ | ||
1044 | error = nfs4_set_client(server, | ||
1045 | data->nfs_server.hostname, | ||
1046 | (const struct sockaddr *)&data->nfs_server.address, | ||
1047 | data->nfs_server.addrlen, | ||
1048 | data->client_address, | ||
1049 | data->auth_flavors[0], | ||
1050 | data->nfs_server.protocol, | ||
1051 | &timeparms); | ||
1052 | if (error < 0) | ||
1053 | goto error; | ||
1054 | |||
926 | /* Initialise the client representation from the mount data */ | 1055 | /* Initialise the client representation from the mount data */ |
927 | server->flags = data->flags & NFS_MOUNT_FLAGMASK; | 1056 | server->flags = data->flags & NFS_MOUNT_FLAGMASK; |
928 | server->caps |= NFS_CAP_ATOMIC_OPEN; | 1057 | server->caps |= NFS_CAP_ATOMIC_OPEN; |
@@ -937,8 +1066,9 @@ static int nfs4_init_server(struct nfs_server *server, | |||
937 | server->acdirmin = data->acdirmin * HZ; | 1066 | server->acdirmin = data->acdirmin * HZ; |
938 | server->acdirmax = data->acdirmax * HZ; | 1067 | server->acdirmax = data->acdirmax * HZ; |
939 | 1068 | ||
940 | error = nfs_init_server_rpcclient(server, data->auth_flavors[0]); | 1069 | error = nfs_init_server_rpcclient(server, &timeparms, data->auth_flavors[0]); |
941 | 1070 | ||
1071 | error: | ||
942 | /* Done */ | 1072 | /* Done */ |
943 | dprintk("<-- nfs4_init_server() = %d\n", error); | 1073 | dprintk("<-- nfs4_init_server() = %d\n", error); |
944 | return error; | 1074 | return error; |
@@ -961,17 +1091,6 @@ struct nfs_server *nfs4_create_server(const struct nfs_parsed_mount_data *data, | |||
961 | if (!server) | 1091 | if (!server) |
962 | return ERR_PTR(-ENOMEM); | 1092 | return ERR_PTR(-ENOMEM); |
963 | 1093 | ||
964 | /* Get a client record */ | ||
965 | error = nfs4_set_client(server, | ||
966 | data->nfs_server.hostname, | ||
967 | &data->nfs_server.address, | ||
968 | data->client_address, | ||
969 | data->auth_flavors[0], | ||
970 | data->nfs_server.protocol, | ||
971 | data->timeo, data->retrans); | ||
972 | if (error < 0) | ||
973 | goto error; | ||
974 | |||
975 | /* set up the general RPC client */ | 1094 | /* set up the general RPC client */ |
976 | error = nfs4_init_server(server, data); | 1095 | error = nfs4_init_server(server, data); |
977 | if (error < 0) | 1096 | if (error < 0) |
@@ -1039,12 +1158,13 @@ struct nfs_server *nfs4_create_referral_server(struct nfs_clone_mount *data, | |||
1039 | 1158 | ||
1040 | /* Get a client representation. | 1159 | /* Get a client representation. |
1041 | * Note: NFSv4 always uses TCP, */ | 1160 | * Note: NFSv4 always uses TCP, */ |
1042 | error = nfs4_set_client(server, data->hostname, data->addr, | 1161 | error = nfs4_set_client(server, data->hostname, |
1043 | parent_client->cl_ipaddr, | 1162 | data->addr, |
1044 | data->authflavor, | 1163 | data->addrlen, |
1045 | parent_server->client->cl_xprt->prot, | 1164 | parent_client->cl_ipaddr, |
1046 | parent_client->retrans_timeo, | 1165 | data->authflavor, |
1047 | parent_client->retrans_count); | 1166 | parent_server->client->cl_xprt->prot, |
1167 | parent_server->client->cl_timeout); | ||
1048 | if (error < 0) | 1168 | if (error < 0) |
1049 | goto error; | 1169 | goto error; |
1050 | 1170 | ||
@@ -1052,7 +1172,7 @@ struct nfs_server *nfs4_create_referral_server(struct nfs_clone_mount *data, | |||
1052 | nfs_server_copy_userdata(server, parent_server); | 1172 | nfs_server_copy_userdata(server, parent_server); |
1053 | server->caps |= NFS_CAP_ATOMIC_OPEN; | 1173 | server->caps |= NFS_CAP_ATOMIC_OPEN; |
1054 | 1174 | ||
1055 | error = nfs_init_server_rpcclient(server, data->authflavor); | 1175 | error = nfs_init_server_rpcclient(server, parent_server->client->cl_timeout, data->authflavor); |
1056 | if (error < 0) | 1176 | if (error < 0) |
1057 | goto error; | 1177 | goto error; |
1058 | 1178 | ||
@@ -1121,7 +1241,9 @@ struct nfs_server *nfs_clone_server(struct nfs_server *source, | |||
1121 | 1241 | ||
1122 | server->fsid = fattr->fsid; | 1242 | server->fsid = fattr->fsid; |
1123 | 1243 | ||
1124 | error = nfs_init_server_rpcclient(server, source->client->cl_auth->au_flavor); | 1244 | error = nfs_init_server_rpcclient(server, |
1245 | source->client->cl_timeout, | ||
1246 | source->client->cl_auth->au_flavor); | ||
1125 | if (error < 0) | 1247 | if (error < 0) |
1126 | goto out_free_server; | 1248 | goto out_free_server; |
1127 | if (!IS_ERR(source->client_acl)) | 1249 | if (!IS_ERR(source->client_acl)) |
@@ -1263,10 +1385,10 @@ static int nfs_server_list_show(struct seq_file *m, void *v) | |||
1263 | /* display one transport per line on subsequent lines */ | 1385 | /* display one transport per line on subsequent lines */ |
1264 | clp = list_entry(v, struct nfs_client, cl_share_link); | 1386 | clp = list_entry(v, struct nfs_client, cl_share_link); |
1265 | 1387 | ||
1266 | seq_printf(m, "v%d %02x%02x%02x%02x %4hx %3d %s\n", | 1388 | seq_printf(m, "v%u %s %s %3d %s\n", |
1267 | clp->cl_nfsversion, | 1389 | clp->rpc_ops->version, |
1268 | NIPQUAD(clp->cl_addr.sin_addr), | 1390 | rpc_peeraddr2str(clp->cl_rpcclient, RPC_DISPLAY_HEX_ADDR), |
1269 | ntohs(clp->cl_addr.sin_port), | 1391 | rpc_peeraddr2str(clp->cl_rpcclient, RPC_DISPLAY_HEX_PORT), |
1270 | atomic_read(&clp->cl_count), | 1392 | atomic_read(&clp->cl_count), |
1271 | clp->cl_hostname); | 1393 | clp->cl_hostname); |
1272 | 1394 | ||
@@ -1342,10 +1464,10 @@ static int nfs_volume_list_show(struct seq_file *m, void *v) | |||
1342 | (unsigned long long) server->fsid.major, | 1464 | (unsigned long long) server->fsid.major, |
1343 | (unsigned long long) server->fsid.minor); | 1465 | (unsigned long long) server->fsid.minor); |
1344 | 1466 | ||
1345 | seq_printf(m, "v%d %02x%02x%02x%02x %4hx %-7s %-17s\n", | 1467 | seq_printf(m, "v%u %s %s %-7s %-17s\n", |
1346 | clp->cl_nfsversion, | 1468 | clp->rpc_ops->version, |
1347 | NIPQUAD(clp->cl_addr.sin_addr), | 1469 | rpc_peeraddr2str(clp->cl_rpcclient, RPC_DISPLAY_HEX_ADDR), |
1348 | ntohs(clp->cl_addr.sin_port), | 1470 | rpc_peeraddr2str(clp->cl_rpcclient, RPC_DISPLAY_HEX_PORT), |
1349 | dev, | 1471 | dev, |
1350 | fsid); | 1472 | fsid); |
1351 | 1473 | ||
diff --git a/fs/nfs/delegation.c b/fs/nfs/delegation.c index 11833f4caeaa..b9eadd18ba70 100644 --- a/fs/nfs/delegation.c +++ b/fs/nfs/delegation.c | |||
@@ -125,6 +125,32 @@ void nfs_inode_reclaim_delegation(struct inode *inode, struct rpc_cred *cred, st | |||
125 | put_rpccred(oldcred); | 125 | put_rpccred(oldcred); |
126 | } | 126 | } |
127 | 127 | ||
128 | static int nfs_do_return_delegation(struct inode *inode, struct nfs_delegation *delegation, int issync) | ||
129 | { | ||
130 | int res = 0; | ||
131 | |||
132 | res = nfs4_proc_delegreturn(inode, delegation->cred, &delegation->stateid, issync); | ||
133 | nfs_free_delegation(delegation); | ||
134 | return res; | ||
135 | } | ||
136 | |||
137 | static struct nfs_delegation *nfs_detach_delegation_locked(struct nfs_inode *nfsi, const nfs4_stateid *stateid) | ||
138 | { | ||
139 | struct nfs_delegation *delegation = rcu_dereference(nfsi->delegation); | ||
140 | |||
141 | if (delegation == NULL) | ||
142 | goto nomatch; | ||
143 | if (stateid != NULL && memcmp(delegation->stateid.data, stateid->data, | ||
144 | sizeof(delegation->stateid.data)) != 0) | ||
145 | goto nomatch; | ||
146 | list_del_rcu(&delegation->super_list); | ||
147 | nfsi->delegation_state = 0; | ||
148 | rcu_assign_pointer(nfsi->delegation, NULL); | ||
149 | return delegation; | ||
150 | nomatch: | ||
151 | return NULL; | ||
152 | } | ||
153 | |||
128 | /* | 154 | /* |
129 | * Set up a delegation on an inode | 155 | * Set up a delegation on an inode |
130 | */ | 156 | */ |
@@ -133,6 +159,7 @@ int nfs_inode_set_delegation(struct inode *inode, struct rpc_cred *cred, struct | |||
133 | struct nfs_client *clp = NFS_SERVER(inode)->nfs_client; | 159 | struct nfs_client *clp = NFS_SERVER(inode)->nfs_client; |
134 | struct nfs_inode *nfsi = NFS_I(inode); | 160 | struct nfs_inode *nfsi = NFS_I(inode); |
135 | struct nfs_delegation *delegation; | 161 | struct nfs_delegation *delegation; |
162 | struct nfs_delegation *freeme = NULL; | ||
136 | int status = 0; | 163 | int status = 0; |
137 | 164 | ||
138 | delegation = kmalloc(sizeof(*delegation), GFP_KERNEL); | 165 | delegation = kmalloc(sizeof(*delegation), GFP_KERNEL); |
@@ -147,41 +174,45 @@ int nfs_inode_set_delegation(struct inode *inode, struct rpc_cred *cred, struct | |||
147 | delegation->inode = inode; | 174 | delegation->inode = inode; |
148 | 175 | ||
149 | spin_lock(&clp->cl_lock); | 176 | spin_lock(&clp->cl_lock); |
150 | if (rcu_dereference(nfsi->delegation) == NULL) { | 177 | if (rcu_dereference(nfsi->delegation) != NULL) { |
151 | list_add_rcu(&delegation->super_list, &clp->cl_delegations); | ||
152 | nfsi->delegation_state = delegation->type; | ||
153 | rcu_assign_pointer(nfsi->delegation, delegation); | ||
154 | delegation = NULL; | ||
155 | } else { | ||
156 | if (memcmp(&delegation->stateid, &nfsi->delegation->stateid, | 178 | if (memcmp(&delegation->stateid, &nfsi->delegation->stateid, |
157 | sizeof(delegation->stateid)) != 0 || | 179 | sizeof(delegation->stateid)) == 0 && |
158 | delegation->type != nfsi->delegation->type) { | 180 | delegation->type == nfsi->delegation->type) { |
159 | printk("%s: server %u.%u.%u.%u, handed out a duplicate delegation!\n", | 181 | goto out; |
160 | __FUNCTION__, NIPQUAD(clp->cl_addr.sin_addr)); | 182 | } |
161 | status = -EIO; | 183 | /* |
184 | * Deal with broken servers that hand out two | ||
185 | * delegations for the same file. | ||
186 | */ | ||
187 | dfprintk(FILE, "%s: server %s handed out " | ||
188 | "a duplicate delegation!\n", | ||
189 | __FUNCTION__, clp->cl_hostname); | ||
190 | if (delegation->type <= nfsi->delegation->type) { | ||
191 | freeme = delegation; | ||
192 | delegation = NULL; | ||
193 | goto out; | ||
162 | } | 194 | } |
195 | freeme = nfs_detach_delegation_locked(nfsi, NULL); | ||
163 | } | 196 | } |
197 | list_add_rcu(&delegation->super_list, &clp->cl_delegations); | ||
198 | nfsi->delegation_state = delegation->type; | ||
199 | rcu_assign_pointer(nfsi->delegation, delegation); | ||
200 | delegation = NULL; | ||
164 | 201 | ||
165 | /* Ensure we revalidate the attributes and page cache! */ | 202 | /* Ensure we revalidate the attributes and page cache! */ |
166 | spin_lock(&inode->i_lock); | 203 | spin_lock(&inode->i_lock); |
167 | nfsi->cache_validity |= NFS_INO_REVAL_FORCED; | 204 | nfsi->cache_validity |= NFS_INO_REVAL_FORCED; |
168 | spin_unlock(&inode->i_lock); | 205 | spin_unlock(&inode->i_lock); |
169 | 206 | ||
207 | out: | ||
170 | spin_unlock(&clp->cl_lock); | 208 | spin_unlock(&clp->cl_lock); |
171 | if (delegation != NULL) | 209 | if (delegation != NULL) |
172 | nfs_free_delegation(delegation); | 210 | nfs_free_delegation(delegation); |
211 | if (freeme != NULL) | ||
212 | nfs_do_return_delegation(inode, freeme, 0); | ||
173 | return status; | 213 | return status; |
174 | } | 214 | } |
175 | 215 | ||
176 | static int nfs_do_return_delegation(struct inode *inode, struct nfs_delegation *delegation) | ||
177 | { | ||
178 | int res = 0; | ||
179 | |||
180 | res = nfs4_proc_delegreturn(inode, delegation->cred, &delegation->stateid); | ||
181 | nfs_free_delegation(delegation); | ||
182 | return res; | ||
183 | } | ||
184 | |||
185 | /* Sync all data to disk upon delegation return */ | 216 | /* Sync all data to disk upon delegation return */ |
186 | static void nfs_msync_inode(struct inode *inode) | 217 | static void nfs_msync_inode(struct inode *inode) |
187 | { | 218 | { |
@@ -207,24 +238,28 @@ static int __nfs_inode_return_delegation(struct inode *inode, struct nfs_delegat | |||
207 | up_read(&clp->cl_sem); | 238 | up_read(&clp->cl_sem); |
208 | nfs_msync_inode(inode); | 239 | nfs_msync_inode(inode); |
209 | 240 | ||
210 | return nfs_do_return_delegation(inode, delegation); | 241 | return nfs_do_return_delegation(inode, delegation, 1); |
211 | } | 242 | } |
212 | 243 | ||
213 | static struct nfs_delegation *nfs_detach_delegation_locked(struct nfs_inode *nfsi, const nfs4_stateid *stateid) | 244 | /* |
245 | * This function returns the delegation without reclaiming opens | ||
246 | * or protecting against delegation reclaims. | ||
247 | * It is therefore really only safe to be called from | ||
248 | * nfs4_clear_inode() | ||
249 | */ | ||
250 | void nfs_inode_return_delegation_noreclaim(struct inode *inode) | ||
214 | { | 251 | { |
215 | struct nfs_delegation *delegation = rcu_dereference(nfsi->delegation); | 252 | struct nfs_client *clp = NFS_SERVER(inode)->nfs_client; |
253 | struct nfs_inode *nfsi = NFS_I(inode); | ||
254 | struct nfs_delegation *delegation; | ||
216 | 255 | ||
217 | if (delegation == NULL) | 256 | if (rcu_dereference(nfsi->delegation) != NULL) { |
218 | goto nomatch; | 257 | spin_lock(&clp->cl_lock); |
219 | if (stateid != NULL && memcmp(delegation->stateid.data, stateid->data, | 258 | delegation = nfs_detach_delegation_locked(nfsi, NULL); |
220 | sizeof(delegation->stateid.data)) != 0) | 259 | spin_unlock(&clp->cl_lock); |
221 | goto nomatch; | 260 | if (delegation != NULL) |
222 | list_del_rcu(&delegation->super_list); | 261 | nfs_do_return_delegation(inode, delegation, 0); |
223 | nfsi->delegation_state = 0; | 262 | } |
224 | rcu_assign_pointer(nfsi->delegation, NULL); | ||
225 | return delegation; | ||
226 | nomatch: | ||
227 | return NULL; | ||
228 | } | 263 | } |
229 | 264 | ||
230 | int nfs_inode_return_delegation(struct inode *inode) | 265 | int nfs_inode_return_delegation(struct inode *inode) |
@@ -314,8 +349,9 @@ void nfs_expire_all_delegations(struct nfs_client *clp) | |||
314 | __module_get(THIS_MODULE); | 349 | __module_get(THIS_MODULE); |
315 | atomic_inc(&clp->cl_count); | 350 | atomic_inc(&clp->cl_count); |
316 | task = kthread_run(nfs_do_expire_all_delegations, clp, | 351 | task = kthread_run(nfs_do_expire_all_delegations, clp, |
317 | "%u.%u.%u.%u-delegreturn", | 352 | "%s-delegreturn", |
318 | NIPQUAD(clp->cl_addr.sin_addr)); | 353 | rpc_peeraddr2str(clp->cl_rpcclient, |
354 | RPC_DISPLAY_ADDR)); | ||
319 | if (!IS_ERR(task)) | 355 | if (!IS_ERR(task)) |
320 | return; | 356 | return; |
321 | nfs_put_client(clp); | 357 | nfs_put_client(clp); |
@@ -386,7 +422,7 @@ static int recall_thread(void *data) | |||
386 | nfs_msync_inode(inode); | 422 | nfs_msync_inode(inode); |
387 | 423 | ||
388 | if (delegation != NULL) | 424 | if (delegation != NULL) |
389 | nfs_do_return_delegation(inode, delegation); | 425 | nfs_do_return_delegation(inode, delegation, 1); |
390 | iput(inode); | 426 | iput(inode); |
391 | module_put_and_exit(0); | 427 | module_put_and_exit(0); |
392 | } | 428 | } |
diff --git a/fs/nfs/delegation.h b/fs/nfs/delegation.h index 5874ce7fdbae..f1c5e2a5d88e 100644 --- a/fs/nfs/delegation.h +++ b/fs/nfs/delegation.h | |||
@@ -29,6 +29,7 @@ int nfs_inode_set_delegation(struct inode *inode, struct rpc_cred *cred, struct | |||
29 | void nfs_inode_reclaim_delegation(struct inode *inode, struct rpc_cred *cred, struct nfs_openres *res); | 29 | void nfs_inode_reclaim_delegation(struct inode *inode, struct rpc_cred *cred, struct nfs_openres *res); |
30 | int nfs_inode_return_delegation(struct inode *inode); | 30 | int nfs_inode_return_delegation(struct inode *inode); |
31 | int nfs_async_inode_return_delegation(struct inode *inode, const nfs4_stateid *stateid); | 31 | int nfs_async_inode_return_delegation(struct inode *inode, const nfs4_stateid *stateid); |
32 | void nfs_inode_return_delegation_noreclaim(struct inode *inode); | ||
32 | 33 | ||
33 | struct inode *nfs_delegation_find_inode(struct nfs_client *clp, const struct nfs_fh *fhandle); | 34 | struct inode *nfs_delegation_find_inode(struct nfs_client *clp, const struct nfs_fh *fhandle); |
34 | void nfs_return_all_delegations(struct super_block *sb); | 35 | void nfs_return_all_delegations(struct super_block *sb); |
@@ -39,7 +40,7 @@ void nfs_delegation_mark_reclaim(struct nfs_client *clp); | |||
39 | void nfs_delegation_reap_unclaimed(struct nfs_client *clp); | 40 | void nfs_delegation_reap_unclaimed(struct nfs_client *clp); |
40 | 41 | ||
41 | /* NFSv4 delegation-related procedures */ | 42 | /* NFSv4 delegation-related procedures */ |
42 | int nfs4_proc_delegreturn(struct inode *inode, struct rpc_cred *cred, const nfs4_stateid *stateid); | 43 | int nfs4_proc_delegreturn(struct inode *inode, struct rpc_cred *cred, const nfs4_stateid *stateid, int issync); |
43 | int nfs4_open_delegation_recall(struct nfs_open_context *ctx, struct nfs4_state *state, const nfs4_stateid *stateid); | 44 | int nfs4_open_delegation_recall(struct nfs_open_context *ctx, struct nfs4_state *state, const nfs4_stateid *stateid); |
44 | int nfs4_lock_delegation_recall(struct nfs4_state *state, struct file_lock *fl); | 45 | int nfs4_lock_delegation_recall(struct nfs4_state *state, struct file_lock *fl); |
45 | int nfs4_copy_delegation_stateid(nfs4_stateid *dst, struct inode *inode); | 46 | int nfs4_copy_delegation_stateid(nfs4_stateid *dst, struct inode *inode); |
diff --git a/fs/nfs/dir.c b/fs/nfs/dir.c index f697b5c74b7c..476cb0f837fd 100644 --- a/fs/nfs/dir.c +++ b/fs/nfs/dir.c | |||
@@ -192,7 +192,7 @@ int nfs_readdir_filler(nfs_readdir_descriptor_t *desc, struct page *page) | |||
192 | /* We requested READDIRPLUS, but the server doesn't grok it */ | 192 | /* We requested READDIRPLUS, but the server doesn't grok it */ |
193 | if (error == -ENOTSUPP && desc->plus) { | 193 | if (error == -ENOTSUPP && desc->plus) { |
194 | NFS_SERVER(inode)->caps &= ~NFS_CAP_READDIRPLUS; | 194 | NFS_SERVER(inode)->caps &= ~NFS_CAP_READDIRPLUS; |
195 | clear_bit(NFS_INO_ADVISE_RDPLUS, &NFS_FLAGS(inode)); | 195 | clear_bit(NFS_INO_ADVISE_RDPLUS, &NFS_I(inode)->flags); |
196 | desc->plus = 0; | 196 | desc->plus = 0; |
197 | goto again; | 197 | goto again; |
198 | } | 198 | } |
@@ -537,12 +537,6 @@ static int nfs_readdir(struct file *filp, void *dirent, filldir_t filldir) | |||
537 | 537 | ||
538 | lock_kernel(); | 538 | lock_kernel(); |
539 | 539 | ||
540 | res = nfs_revalidate_mapping_nolock(inode, filp->f_mapping); | ||
541 | if (res < 0) { | ||
542 | unlock_kernel(); | ||
543 | return res; | ||
544 | } | ||
545 | |||
546 | /* | 540 | /* |
547 | * filp->f_pos points to the dirent entry number. | 541 | * filp->f_pos points to the dirent entry number. |
548 | * *desc->dir_cookie has the cookie for the next entry. We have | 542 | * *desc->dir_cookie has the cookie for the next entry. We have |
@@ -564,6 +558,10 @@ static int nfs_readdir(struct file *filp, void *dirent, filldir_t filldir) | |||
564 | desc->entry = &my_entry; | 558 | desc->entry = &my_entry; |
565 | 559 | ||
566 | nfs_block_sillyrename(dentry); | 560 | nfs_block_sillyrename(dentry); |
561 | res = nfs_revalidate_mapping_nolock(inode, filp->f_mapping); | ||
562 | if (res < 0) | ||
563 | goto out; | ||
564 | |||
567 | while(!desc->entry->eof) { | 565 | while(!desc->entry->eof) { |
568 | res = readdir_search_pagecache(desc); | 566 | res = readdir_search_pagecache(desc); |
569 | 567 | ||
@@ -579,7 +577,7 @@ static int nfs_readdir(struct file *filp, void *dirent, filldir_t filldir) | |||
579 | break; | 577 | break; |
580 | } | 578 | } |
581 | if (res == -ETOOSMALL && desc->plus) { | 579 | if (res == -ETOOSMALL && desc->plus) { |
582 | clear_bit(NFS_INO_ADVISE_RDPLUS, &NFS_FLAGS(inode)); | 580 | clear_bit(NFS_INO_ADVISE_RDPLUS, &NFS_I(inode)->flags); |
583 | nfs_zap_caches(inode); | 581 | nfs_zap_caches(inode); |
584 | desc->plus = 0; | 582 | desc->plus = 0; |
585 | desc->entry->eof = 0; | 583 | desc->entry->eof = 0; |
@@ -594,6 +592,7 @@ static int nfs_readdir(struct file *filp, void *dirent, filldir_t filldir) | |||
594 | break; | 592 | break; |
595 | } | 593 | } |
596 | } | 594 | } |
595 | out: | ||
597 | nfs_unblock_sillyrename(dentry); | 596 | nfs_unblock_sillyrename(dentry); |
598 | unlock_kernel(); | 597 | unlock_kernel(); |
599 | if (res > 0) | 598 | if (res > 0) |
@@ -639,6 +638,21 @@ static int nfs_fsync_dir(struct file *filp, struct dentry *dentry, int datasync) | |||
639 | return 0; | 638 | return 0; |
640 | } | 639 | } |
641 | 640 | ||
641 | /** | ||
642 | * nfs_force_lookup_revalidate - Mark the directory as having changed | ||
643 | * @dir - pointer to directory inode | ||
644 | * | ||
645 | * This forces the revalidation code in nfs_lookup_revalidate() to do a | ||
646 | * full lookup on all child dentries of 'dir' whenever a change occurs | ||
647 | * on the server that might have invalidated our dcache. | ||
648 | * | ||
649 | * The caller should be holding dir->i_lock | ||
650 | */ | ||
651 | void nfs_force_lookup_revalidate(struct inode *dir) | ||
652 | { | ||
653 | NFS_I(dir)->cache_change_attribute = jiffies; | ||
654 | } | ||
655 | |||
642 | /* | 656 | /* |
643 | * A check for whether or not the parent directory has changed. | 657 | * A check for whether or not the parent directory has changed. |
644 | * In the case it has, we assume that the dentries are untrustworthy | 658 | * In the case it has, we assume that the dentries are untrustworthy |
@@ -827,6 +841,10 @@ static int nfs_dentry_delete(struct dentry *dentry) | |||
827 | dentry->d_parent->d_name.name, dentry->d_name.name, | 841 | dentry->d_parent->d_name.name, dentry->d_name.name, |
828 | dentry->d_flags); | 842 | dentry->d_flags); |
829 | 843 | ||
844 | /* Unhash any dentry with a stale inode */ | ||
845 | if (dentry->d_inode != NULL && NFS_STALE(dentry->d_inode)) | ||
846 | return 1; | ||
847 | |||
830 | if (dentry->d_flags & DCACHE_NFSFS_RENAMED) { | 848 | if (dentry->d_flags & DCACHE_NFSFS_RENAMED) { |
831 | /* Unhash it, so that ->d_iput() would be called */ | 849 | /* Unhash it, so that ->d_iput() would be called */ |
832 | return 1; | 850 | return 1; |
@@ -846,7 +864,6 @@ static int nfs_dentry_delete(struct dentry *dentry) | |||
846 | */ | 864 | */ |
847 | static void nfs_dentry_iput(struct dentry *dentry, struct inode *inode) | 865 | static void nfs_dentry_iput(struct dentry *dentry, struct inode *inode) |
848 | { | 866 | { |
849 | nfs_inode_return_delegation(inode); | ||
850 | if (S_ISDIR(inode->i_mode)) | 867 | if (S_ISDIR(inode->i_mode)) |
851 | /* drop any readdir cache as it could easily be old */ | 868 | /* drop any readdir cache as it could easily be old */ |
852 | NFS_I(inode)->cache_validity |= NFS_INO_INVALID_DATA; | 869 | NFS_I(inode)->cache_validity |= NFS_INO_INVALID_DATA; |
@@ -1268,6 +1285,12 @@ out_err: | |||
1268 | return error; | 1285 | return error; |
1269 | } | 1286 | } |
1270 | 1287 | ||
1288 | static void nfs_dentry_handle_enoent(struct dentry *dentry) | ||
1289 | { | ||
1290 | if (dentry->d_inode != NULL && !d_unhashed(dentry)) | ||
1291 | d_delete(dentry); | ||
1292 | } | ||
1293 | |||
1271 | static int nfs_rmdir(struct inode *dir, struct dentry *dentry) | 1294 | static int nfs_rmdir(struct inode *dir, struct dentry *dentry) |
1272 | { | 1295 | { |
1273 | int error; | 1296 | int error; |
@@ -1280,6 +1303,8 @@ static int nfs_rmdir(struct inode *dir, struct dentry *dentry) | |||
1280 | /* Ensure the VFS deletes this inode */ | 1303 | /* Ensure the VFS deletes this inode */ |
1281 | if (error == 0 && dentry->d_inode != NULL) | 1304 | if (error == 0 && dentry->d_inode != NULL) |
1282 | clear_nlink(dentry->d_inode); | 1305 | clear_nlink(dentry->d_inode); |
1306 | else if (error == -ENOENT) | ||
1307 | nfs_dentry_handle_enoent(dentry); | ||
1283 | unlock_kernel(); | 1308 | unlock_kernel(); |
1284 | 1309 | ||
1285 | return error; | 1310 | return error; |
@@ -1386,6 +1411,8 @@ static int nfs_safe_remove(struct dentry *dentry) | |||
1386 | nfs_mark_for_revalidate(inode); | 1411 | nfs_mark_for_revalidate(inode); |
1387 | } else | 1412 | } else |
1388 | error = NFS_PROTO(dir)->remove(dir, &dentry->d_name); | 1413 | error = NFS_PROTO(dir)->remove(dir, &dentry->d_name); |
1414 | if (error == -ENOENT) | ||
1415 | nfs_dentry_handle_enoent(dentry); | ||
1389 | out: | 1416 | out: |
1390 | return error; | 1417 | return error; |
1391 | } | 1418 | } |
@@ -1422,7 +1449,7 @@ static int nfs_unlink(struct inode *dir, struct dentry *dentry) | |||
1422 | spin_unlock(&dentry->d_lock); | 1449 | spin_unlock(&dentry->d_lock); |
1423 | spin_unlock(&dcache_lock); | 1450 | spin_unlock(&dcache_lock); |
1424 | error = nfs_safe_remove(dentry); | 1451 | error = nfs_safe_remove(dentry); |
1425 | if (!error) { | 1452 | if (!error || error == -ENOENT) { |
1426 | nfs_set_verifier(dentry, nfs_save_change_attribute(dir)); | 1453 | nfs_set_verifier(dentry, nfs_save_change_attribute(dir)); |
1427 | } else if (need_rehash) | 1454 | } else if (need_rehash) |
1428 | d_rehash(dentry); | 1455 | d_rehash(dentry); |
@@ -1635,7 +1662,8 @@ out: | |||
1635 | d_move(old_dentry, new_dentry); | 1662 | d_move(old_dentry, new_dentry); |
1636 | nfs_set_verifier(new_dentry, | 1663 | nfs_set_verifier(new_dentry, |
1637 | nfs_save_change_attribute(new_dir)); | 1664 | nfs_save_change_attribute(new_dir)); |
1638 | } | 1665 | } else if (error == -ENOENT) |
1666 | nfs_dentry_handle_enoent(old_dentry); | ||
1639 | 1667 | ||
1640 | /* new dentry created? */ | 1668 | /* new dentry created? */ |
1641 | if (dentry) | 1669 | if (dentry) |
@@ -1666,13 +1694,19 @@ int nfs_access_cache_shrinker(int nr_to_scan, gfp_t gfp_mask) | |||
1666 | restart: | 1694 | restart: |
1667 | spin_lock(&nfs_access_lru_lock); | 1695 | spin_lock(&nfs_access_lru_lock); |
1668 | list_for_each_entry(nfsi, &nfs_access_lru_list, access_cache_inode_lru) { | 1696 | list_for_each_entry(nfsi, &nfs_access_lru_list, access_cache_inode_lru) { |
1697 | struct rw_semaphore *s_umount; | ||
1669 | struct inode *inode; | 1698 | struct inode *inode; |
1670 | 1699 | ||
1671 | if (nr_to_scan-- == 0) | 1700 | if (nr_to_scan-- == 0) |
1672 | break; | 1701 | break; |
1702 | s_umount = &nfsi->vfs_inode.i_sb->s_umount; | ||
1703 | if (!down_read_trylock(s_umount)) | ||
1704 | continue; | ||
1673 | inode = igrab(&nfsi->vfs_inode); | 1705 | inode = igrab(&nfsi->vfs_inode); |
1674 | if (inode == NULL) | 1706 | if (inode == NULL) { |
1707 | up_read(s_umount); | ||
1675 | continue; | 1708 | continue; |
1709 | } | ||
1676 | spin_lock(&inode->i_lock); | 1710 | spin_lock(&inode->i_lock); |
1677 | if (list_empty(&nfsi->access_cache_entry_lru)) | 1711 | if (list_empty(&nfsi->access_cache_entry_lru)) |
1678 | goto remove_lru_entry; | 1712 | goto remove_lru_entry; |
@@ -1691,6 +1725,7 @@ remove_lru_entry: | |||
1691 | spin_unlock(&inode->i_lock); | 1725 | spin_unlock(&inode->i_lock); |
1692 | spin_unlock(&nfs_access_lru_lock); | 1726 | spin_unlock(&nfs_access_lru_lock); |
1693 | iput(inode); | 1727 | iput(inode); |
1728 | up_read(s_umount); | ||
1694 | goto restart; | 1729 | goto restart; |
1695 | } | 1730 | } |
1696 | spin_unlock(&nfs_access_lru_lock); | 1731 | spin_unlock(&nfs_access_lru_lock); |
@@ -1731,7 +1766,7 @@ static void __nfs_access_zap_cache(struct inode *inode) | |||
1731 | void nfs_access_zap_cache(struct inode *inode) | 1766 | void nfs_access_zap_cache(struct inode *inode) |
1732 | { | 1767 | { |
1733 | /* Remove from global LRU init */ | 1768 | /* Remove from global LRU init */ |
1734 | if (test_and_clear_bit(NFS_INO_ACL_LRU_SET, &NFS_FLAGS(inode))) { | 1769 | if (test_and_clear_bit(NFS_INO_ACL_LRU_SET, &NFS_I(inode)->flags)) { |
1735 | spin_lock(&nfs_access_lru_lock); | 1770 | spin_lock(&nfs_access_lru_lock); |
1736 | list_del_init(&NFS_I(inode)->access_cache_inode_lru); | 1771 | list_del_init(&NFS_I(inode)->access_cache_inode_lru); |
1737 | spin_unlock(&nfs_access_lru_lock); | 1772 | spin_unlock(&nfs_access_lru_lock); |
@@ -1845,7 +1880,7 @@ static void nfs_access_add_cache(struct inode *inode, struct nfs_access_entry *s | |||
1845 | smp_mb__after_atomic_inc(); | 1880 | smp_mb__after_atomic_inc(); |
1846 | 1881 | ||
1847 | /* Add inode to global LRU list */ | 1882 | /* Add inode to global LRU list */ |
1848 | if (!test_and_set_bit(NFS_INO_ACL_LRU_SET, &NFS_FLAGS(inode))) { | 1883 | if (!test_and_set_bit(NFS_INO_ACL_LRU_SET, &NFS_I(inode)->flags)) { |
1849 | spin_lock(&nfs_access_lru_lock); | 1884 | spin_lock(&nfs_access_lru_lock); |
1850 | list_add_tail(&NFS_I(inode)->access_cache_inode_lru, &nfs_access_lru_list); | 1885 | list_add_tail(&NFS_I(inode)->access_cache_inode_lru, &nfs_access_lru_list); |
1851 | spin_unlock(&nfs_access_lru_lock); | 1886 | spin_unlock(&nfs_access_lru_lock); |
diff --git a/fs/nfs/direct.c b/fs/nfs/direct.c index 3c9d16b4f80c..f8e165c7d5a6 100644 --- a/fs/nfs/direct.c +++ b/fs/nfs/direct.c | |||
@@ -188,12 +188,17 @@ static void nfs_direct_req_release(struct nfs_direct_req *dreq) | |||
188 | static ssize_t nfs_direct_wait(struct nfs_direct_req *dreq) | 188 | static ssize_t nfs_direct_wait(struct nfs_direct_req *dreq) |
189 | { | 189 | { |
190 | ssize_t result = -EIOCBQUEUED; | 190 | ssize_t result = -EIOCBQUEUED; |
191 | struct rpc_clnt *clnt; | ||
192 | sigset_t oldset; | ||
191 | 193 | ||
192 | /* Async requests don't wait here */ | 194 | /* Async requests don't wait here */ |
193 | if (dreq->iocb) | 195 | if (dreq->iocb) |
194 | goto out; | 196 | goto out; |
195 | 197 | ||
198 | clnt = NFS_CLIENT(dreq->inode); | ||
199 | rpc_clnt_sigmask(clnt, &oldset); | ||
196 | result = wait_for_completion_interruptible(&dreq->completion); | 200 | result = wait_for_completion_interruptible(&dreq->completion); |
201 | rpc_clnt_sigunmask(clnt, &oldset); | ||
197 | 202 | ||
198 | if (!result) | 203 | if (!result) |
199 | result = dreq->error; | 204 | result = dreq->error; |
@@ -272,6 +277,16 @@ static ssize_t nfs_direct_read_schedule_segment(struct nfs_direct_req *dreq, | |||
272 | unsigned long user_addr = (unsigned long)iov->iov_base; | 277 | unsigned long user_addr = (unsigned long)iov->iov_base; |
273 | size_t count = iov->iov_len; | 278 | size_t count = iov->iov_len; |
274 | size_t rsize = NFS_SERVER(inode)->rsize; | 279 | size_t rsize = NFS_SERVER(inode)->rsize; |
280 | struct rpc_task *task; | ||
281 | struct rpc_message msg = { | ||
282 | .rpc_cred = ctx->cred, | ||
283 | }; | ||
284 | struct rpc_task_setup task_setup_data = { | ||
285 | .rpc_client = NFS_CLIENT(inode), | ||
286 | .rpc_message = &msg, | ||
287 | .callback_ops = &nfs_read_direct_ops, | ||
288 | .flags = RPC_TASK_ASYNC, | ||
289 | }; | ||
275 | unsigned int pgbase; | 290 | unsigned int pgbase; |
276 | int result; | 291 | int result; |
277 | ssize_t started = 0; | 292 | ssize_t started = 0; |
@@ -311,7 +326,7 @@ static ssize_t nfs_direct_read_schedule_segment(struct nfs_direct_req *dreq, | |||
311 | 326 | ||
312 | data->req = (struct nfs_page *) dreq; | 327 | data->req = (struct nfs_page *) dreq; |
313 | data->inode = inode; | 328 | data->inode = inode; |
314 | data->cred = ctx->cred; | 329 | data->cred = msg.rpc_cred; |
315 | data->args.fh = NFS_FH(inode); | 330 | data->args.fh = NFS_FH(inode); |
316 | data->args.context = ctx; | 331 | data->args.context = ctx; |
317 | data->args.offset = pos; | 332 | data->args.offset = pos; |
@@ -321,14 +336,16 @@ static ssize_t nfs_direct_read_schedule_segment(struct nfs_direct_req *dreq, | |||
321 | data->res.fattr = &data->fattr; | 336 | data->res.fattr = &data->fattr; |
322 | data->res.eof = 0; | 337 | data->res.eof = 0; |
323 | data->res.count = bytes; | 338 | data->res.count = bytes; |
339 | msg.rpc_argp = &data->args; | ||
340 | msg.rpc_resp = &data->res; | ||
324 | 341 | ||
325 | rpc_init_task(&data->task, NFS_CLIENT(inode), RPC_TASK_ASYNC, | 342 | task_setup_data.task = &data->task; |
326 | &nfs_read_direct_ops, data); | 343 | task_setup_data.callback_data = data; |
327 | NFS_PROTO(inode)->read_setup(data); | 344 | NFS_PROTO(inode)->read_setup(data, &msg); |
328 | |||
329 | data->task.tk_cookie = (unsigned long) inode; | ||
330 | 345 | ||
331 | rpc_execute(&data->task); | 346 | task = rpc_run_task(&task_setup_data); |
347 | if (!IS_ERR(task)) | ||
348 | rpc_put_task(task); | ||
332 | 349 | ||
333 | dprintk("NFS: %5u initiated direct read call " | 350 | dprintk("NFS: %5u initiated direct read call " |
334 | "(req %s/%Ld, %zu bytes @ offset %Lu)\n", | 351 | "(req %s/%Ld, %zu bytes @ offset %Lu)\n", |
@@ -391,9 +408,7 @@ static ssize_t nfs_direct_read(struct kiocb *iocb, const struct iovec *iov, | |||
391 | unsigned long nr_segs, loff_t pos) | 408 | unsigned long nr_segs, loff_t pos) |
392 | { | 409 | { |
393 | ssize_t result = 0; | 410 | ssize_t result = 0; |
394 | sigset_t oldset; | ||
395 | struct inode *inode = iocb->ki_filp->f_mapping->host; | 411 | struct inode *inode = iocb->ki_filp->f_mapping->host; |
396 | struct rpc_clnt *clnt = NFS_CLIENT(inode); | ||
397 | struct nfs_direct_req *dreq; | 412 | struct nfs_direct_req *dreq; |
398 | 413 | ||
399 | dreq = nfs_direct_req_alloc(); | 414 | dreq = nfs_direct_req_alloc(); |
@@ -405,11 +420,9 @@ static ssize_t nfs_direct_read(struct kiocb *iocb, const struct iovec *iov, | |||
405 | if (!is_sync_kiocb(iocb)) | 420 | if (!is_sync_kiocb(iocb)) |
406 | dreq->iocb = iocb; | 421 | dreq->iocb = iocb; |
407 | 422 | ||
408 | rpc_clnt_sigmask(clnt, &oldset); | ||
409 | result = nfs_direct_read_schedule_iovec(dreq, iov, nr_segs, pos); | 423 | result = nfs_direct_read_schedule_iovec(dreq, iov, nr_segs, pos); |
410 | if (!result) | 424 | if (!result) |
411 | result = nfs_direct_wait(dreq); | 425 | result = nfs_direct_wait(dreq); |
412 | rpc_clnt_sigunmask(clnt, &oldset); | ||
413 | nfs_direct_req_release(dreq); | 426 | nfs_direct_req_release(dreq); |
414 | 427 | ||
415 | return result; | 428 | return result; |
@@ -431,6 +444,15 @@ static void nfs_direct_write_reschedule(struct nfs_direct_req *dreq) | |||
431 | struct inode *inode = dreq->inode; | 444 | struct inode *inode = dreq->inode; |
432 | struct list_head *p; | 445 | struct list_head *p; |
433 | struct nfs_write_data *data; | 446 | struct nfs_write_data *data; |
447 | struct rpc_task *task; | ||
448 | struct rpc_message msg = { | ||
449 | .rpc_cred = dreq->ctx->cred, | ||
450 | }; | ||
451 | struct rpc_task_setup task_setup_data = { | ||
452 | .rpc_client = NFS_CLIENT(inode), | ||
453 | .callback_ops = &nfs_write_direct_ops, | ||
454 | .flags = RPC_TASK_ASYNC, | ||
455 | }; | ||
434 | 456 | ||
435 | dreq->count = 0; | 457 | dreq->count = 0; |
436 | get_dreq(dreq); | 458 | get_dreq(dreq); |
@@ -440,6 +462,9 @@ static void nfs_direct_write_reschedule(struct nfs_direct_req *dreq) | |||
440 | 462 | ||
441 | get_dreq(dreq); | 463 | get_dreq(dreq); |
442 | 464 | ||
465 | /* Use stable writes */ | ||
466 | data->args.stable = NFS_FILE_SYNC; | ||
467 | |||
443 | /* | 468 | /* |
444 | * Reset data->res. | 469 | * Reset data->res. |
445 | */ | 470 | */ |
@@ -451,17 +476,18 @@ static void nfs_direct_write_reschedule(struct nfs_direct_req *dreq) | |||
451 | * Reuse data->task; data->args should not have changed | 476 | * Reuse data->task; data->args should not have changed |
452 | * since the original request was sent. | 477 | * since the original request was sent. |
453 | */ | 478 | */ |
454 | rpc_init_task(&data->task, NFS_CLIENT(inode), RPC_TASK_ASYNC, | 479 | task_setup_data.task = &data->task; |
455 | &nfs_write_direct_ops, data); | 480 | task_setup_data.callback_data = data; |
456 | NFS_PROTO(inode)->write_setup(data, FLUSH_STABLE); | 481 | msg.rpc_argp = &data->args; |
457 | 482 | msg.rpc_resp = &data->res; | |
458 | data->task.tk_priority = RPC_PRIORITY_NORMAL; | 483 | NFS_PROTO(inode)->write_setup(data, &msg); |
459 | data->task.tk_cookie = (unsigned long) inode; | ||
460 | 484 | ||
461 | /* | 485 | /* |
462 | * We're called via an RPC callback, so BKL is already held. | 486 | * We're called via an RPC callback, so BKL is already held. |
463 | */ | 487 | */ |
464 | rpc_execute(&data->task); | 488 | task = rpc_run_task(&task_setup_data); |
489 | if (!IS_ERR(task)) | ||
490 | rpc_put_task(task); | ||
465 | 491 | ||
466 | dprintk("NFS: %5u rescheduled direct write call (req %s/%Ld, %u bytes @ offset %Lu)\n", | 492 | dprintk("NFS: %5u rescheduled direct write call (req %s/%Ld, %u bytes @ offset %Lu)\n", |
467 | data->task.tk_pid, | 493 | data->task.tk_pid, |
@@ -504,9 +530,23 @@ static const struct rpc_call_ops nfs_commit_direct_ops = { | |||
504 | static void nfs_direct_commit_schedule(struct nfs_direct_req *dreq) | 530 | static void nfs_direct_commit_schedule(struct nfs_direct_req *dreq) |
505 | { | 531 | { |
506 | struct nfs_write_data *data = dreq->commit_data; | 532 | struct nfs_write_data *data = dreq->commit_data; |
533 | struct rpc_task *task; | ||
534 | struct rpc_message msg = { | ||
535 | .rpc_argp = &data->args, | ||
536 | .rpc_resp = &data->res, | ||
537 | .rpc_cred = dreq->ctx->cred, | ||
538 | }; | ||
539 | struct rpc_task_setup task_setup_data = { | ||
540 | .task = &data->task, | ||
541 | .rpc_client = NFS_CLIENT(dreq->inode), | ||
542 | .rpc_message = &msg, | ||
543 | .callback_ops = &nfs_commit_direct_ops, | ||
544 | .callback_data = data, | ||
545 | .flags = RPC_TASK_ASYNC, | ||
546 | }; | ||
507 | 547 | ||
508 | data->inode = dreq->inode; | 548 | data->inode = dreq->inode; |
509 | data->cred = dreq->ctx->cred; | 549 | data->cred = msg.rpc_cred; |
510 | 550 | ||
511 | data->args.fh = NFS_FH(data->inode); | 551 | data->args.fh = NFS_FH(data->inode); |
512 | data->args.offset = 0; | 552 | data->args.offset = 0; |
@@ -515,18 +555,16 @@ static void nfs_direct_commit_schedule(struct nfs_direct_req *dreq) | |||
515 | data->res.fattr = &data->fattr; | 555 | data->res.fattr = &data->fattr; |
516 | data->res.verf = &data->verf; | 556 | data->res.verf = &data->verf; |
517 | 557 | ||
518 | rpc_init_task(&data->task, NFS_CLIENT(dreq->inode), RPC_TASK_ASYNC, | 558 | NFS_PROTO(data->inode)->commit_setup(data, &msg); |
519 | &nfs_commit_direct_ops, data); | ||
520 | NFS_PROTO(data->inode)->commit_setup(data, 0); | ||
521 | 559 | ||
522 | data->task.tk_priority = RPC_PRIORITY_NORMAL; | ||
523 | data->task.tk_cookie = (unsigned long)data->inode; | ||
524 | /* Note: task.tk_ops->rpc_release will free dreq->commit_data */ | 560 | /* Note: task.tk_ops->rpc_release will free dreq->commit_data */ |
525 | dreq->commit_data = NULL; | 561 | dreq->commit_data = NULL; |
526 | 562 | ||
527 | dprintk("NFS: %5u initiated commit call\n", data->task.tk_pid); | 563 | dprintk("NFS: %5u initiated commit call\n", data->task.tk_pid); |
528 | 564 | ||
529 | rpc_execute(&data->task); | 565 | task = rpc_run_task(&task_setup_data); |
566 | if (!IS_ERR(task)) | ||
567 | rpc_put_task(task); | ||
530 | } | 568 | } |
531 | 569 | ||
532 | static void nfs_direct_write_complete(struct nfs_direct_req *dreq, struct inode *inode) | 570 | static void nfs_direct_write_complete(struct nfs_direct_req *dreq, struct inode *inode) |
@@ -641,6 +679,16 @@ static ssize_t nfs_direct_write_schedule_segment(struct nfs_direct_req *dreq, | |||
641 | struct inode *inode = ctx->path.dentry->d_inode; | 679 | struct inode *inode = ctx->path.dentry->d_inode; |
642 | unsigned long user_addr = (unsigned long)iov->iov_base; | 680 | unsigned long user_addr = (unsigned long)iov->iov_base; |
643 | size_t count = iov->iov_len; | 681 | size_t count = iov->iov_len; |
682 | struct rpc_task *task; | ||
683 | struct rpc_message msg = { | ||
684 | .rpc_cred = ctx->cred, | ||
685 | }; | ||
686 | struct rpc_task_setup task_setup_data = { | ||
687 | .rpc_client = NFS_CLIENT(inode), | ||
688 | .rpc_message = &msg, | ||
689 | .callback_ops = &nfs_write_direct_ops, | ||
690 | .flags = RPC_TASK_ASYNC, | ||
691 | }; | ||
644 | size_t wsize = NFS_SERVER(inode)->wsize; | 692 | size_t wsize = NFS_SERVER(inode)->wsize; |
645 | unsigned int pgbase; | 693 | unsigned int pgbase; |
646 | int result; | 694 | int result; |
@@ -683,25 +731,27 @@ static ssize_t nfs_direct_write_schedule_segment(struct nfs_direct_req *dreq, | |||
683 | 731 | ||
684 | data->req = (struct nfs_page *) dreq; | 732 | data->req = (struct nfs_page *) dreq; |
685 | data->inode = inode; | 733 | data->inode = inode; |
686 | data->cred = ctx->cred; | 734 | data->cred = msg.rpc_cred; |
687 | data->args.fh = NFS_FH(inode); | 735 | data->args.fh = NFS_FH(inode); |
688 | data->args.context = ctx; | 736 | data->args.context = ctx; |
689 | data->args.offset = pos; | 737 | data->args.offset = pos; |
690 | data->args.pgbase = pgbase; | 738 | data->args.pgbase = pgbase; |
691 | data->args.pages = data->pagevec; | 739 | data->args.pages = data->pagevec; |
692 | data->args.count = bytes; | 740 | data->args.count = bytes; |
741 | data->args.stable = sync; | ||
693 | data->res.fattr = &data->fattr; | 742 | data->res.fattr = &data->fattr; |
694 | data->res.count = bytes; | 743 | data->res.count = bytes; |
695 | data->res.verf = &data->verf; | 744 | data->res.verf = &data->verf; |
696 | 745 | ||
697 | rpc_init_task(&data->task, NFS_CLIENT(inode), RPC_TASK_ASYNC, | 746 | task_setup_data.task = &data->task; |
698 | &nfs_write_direct_ops, data); | 747 | task_setup_data.callback_data = data; |
699 | NFS_PROTO(inode)->write_setup(data, sync); | 748 | msg.rpc_argp = &data->args; |
700 | 749 | msg.rpc_resp = &data->res; | |
701 | data->task.tk_priority = RPC_PRIORITY_NORMAL; | 750 | NFS_PROTO(inode)->write_setup(data, &msg); |
702 | data->task.tk_cookie = (unsigned long) inode; | ||
703 | 751 | ||
704 | rpc_execute(&data->task); | 752 | task = rpc_run_task(&task_setup_data); |
753 | if (!IS_ERR(task)) | ||
754 | rpc_put_task(task); | ||
705 | 755 | ||
706 | dprintk("NFS: %5u initiated direct write call " | 756 | dprintk("NFS: %5u initiated direct write call " |
707 | "(req %s/%Ld, %zu bytes @ offset %Lu)\n", | 757 | "(req %s/%Ld, %zu bytes @ offset %Lu)\n", |
@@ -767,12 +817,10 @@ static ssize_t nfs_direct_write(struct kiocb *iocb, const struct iovec *iov, | |||
767 | size_t count) | 817 | size_t count) |
768 | { | 818 | { |
769 | ssize_t result = 0; | 819 | ssize_t result = 0; |
770 | sigset_t oldset; | ||
771 | struct inode *inode = iocb->ki_filp->f_mapping->host; | 820 | struct inode *inode = iocb->ki_filp->f_mapping->host; |
772 | struct rpc_clnt *clnt = NFS_CLIENT(inode); | ||
773 | struct nfs_direct_req *dreq; | 821 | struct nfs_direct_req *dreq; |
774 | size_t wsize = NFS_SERVER(inode)->wsize; | 822 | size_t wsize = NFS_SERVER(inode)->wsize; |
775 | int sync = 0; | 823 | int sync = NFS_UNSTABLE; |
776 | 824 | ||
777 | dreq = nfs_direct_req_alloc(); | 825 | dreq = nfs_direct_req_alloc(); |
778 | if (!dreq) | 826 | if (!dreq) |
@@ -780,18 +828,16 @@ static ssize_t nfs_direct_write(struct kiocb *iocb, const struct iovec *iov, | |||
780 | nfs_alloc_commit_data(dreq); | 828 | nfs_alloc_commit_data(dreq); |
781 | 829 | ||
782 | if (dreq->commit_data == NULL || count < wsize) | 830 | if (dreq->commit_data == NULL || count < wsize) |
783 | sync = FLUSH_STABLE; | 831 | sync = NFS_FILE_SYNC; |
784 | 832 | ||
785 | dreq->inode = inode; | 833 | dreq->inode = inode; |
786 | dreq->ctx = get_nfs_open_context(nfs_file_open_context(iocb->ki_filp)); | 834 | dreq->ctx = get_nfs_open_context(nfs_file_open_context(iocb->ki_filp)); |
787 | if (!is_sync_kiocb(iocb)) | 835 | if (!is_sync_kiocb(iocb)) |
788 | dreq->iocb = iocb; | 836 | dreq->iocb = iocb; |
789 | 837 | ||
790 | rpc_clnt_sigmask(clnt, &oldset); | ||
791 | result = nfs_direct_write_schedule_iovec(dreq, iov, nr_segs, pos, sync); | 838 | result = nfs_direct_write_schedule_iovec(dreq, iov, nr_segs, pos, sync); |
792 | if (!result) | 839 | if (!result) |
793 | result = nfs_direct_wait(dreq); | 840 | result = nfs_direct_wait(dreq); |
794 | rpc_clnt_sigunmask(clnt, &oldset); | ||
795 | nfs_direct_req_release(dreq); | 841 | nfs_direct_req_release(dreq); |
796 | 842 | ||
797 | return result; | 843 | return result; |
diff --git a/fs/nfs/file.c b/fs/nfs/file.c index b3bb89f7d5d2..ef57a5ae5904 100644 --- a/fs/nfs/file.c +++ b/fs/nfs/file.c | |||
@@ -349,7 +349,9 @@ static int nfs_write_end(struct file *file, struct address_space *mapping, | |||
349 | unlock_page(page); | 349 | unlock_page(page); |
350 | page_cache_release(page); | 350 | page_cache_release(page); |
351 | 351 | ||
352 | return status < 0 ? status : copied; | 352 | if (status < 0) |
353 | return status; | ||
354 | return copied; | ||
353 | } | 355 | } |
354 | 356 | ||
355 | static void nfs_invalidate_page(struct page *page, unsigned long offset) | 357 | static void nfs_invalidate_page(struct page *page, unsigned long offset) |
@@ -392,35 +394,27 @@ static int nfs_vm_page_mkwrite(struct vm_area_struct *vma, struct page *page) | |||
392 | struct file *filp = vma->vm_file; | 394 | struct file *filp = vma->vm_file; |
393 | unsigned pagelen; | 395 | unsigned pagelen; |
394 | int ret = -EINVAL; | 396 | int ret = -EINVAL; |
395 | void *fsdata; | ||
396 | struct address_space *mapping; | 397 | struct address_space *mapping; |
397 | loff_t offset; | ||
398 | 398 | ||
399 | lock_page(page); | 399 | lock_page(page); |
400 | mapping = page->mapping; | 400 | mapping = page->mapping; |
401 | if (mapping != vma->vm_file->f_path.dentry->d_inode->i_mapping) { | 401 | if (mapping != vma->vm_file->f_path.dentry->d_inode->i_mapping) |
402 | unlock_page(page); | 402 | goto out_unlock; |
403 | return -EINVAL; | 403 | |
404 | } | 404 | ret = 0; |
405 | pagelen = nfs_page_length(page); | 405 | pagelen = nfs_page_length(page); |
406 | offset = (loff_t)page->index << PAGE_CACHE_SHIFT; | 406 | if (pagelen == 0) |
407 | unlock_page(page); | 407 | goto out_unlock; |
408 | 408 | ||
409 | /* | 409 | ret = nfs_flush_incompatible(filp, page); |
410 | * we can use mapping after releasing the page lock, because: | 410 | if (ret != 0) |
411 | * we hold mmap_sem on the fault path, which should pin the vma | 411 | goto out_unlock; |
412 | * which should pin the file, which pins the dentry which should | ||
413 | * hold a reference on inode. | ||
414 | */ | ||
415 | 412 | ||
416 | if (pagelen) { | 413 | ret = nfs_updatepage(filp, page, 0, pagelen); |
417 | struct page *page2 = NULL; | 414 | if (ret == 0) |
418 | ret = nfs_write_begin(filp, mapping, offset, pagelen, | 415 | ret = pagelen; |
419 | 0, &page2, &fsdata); | 416 | out_unlock: |
420 | if (!ret) | 417 | unlock_page(page); |
421 | ret = nfs_write_end(filp, mapping, offset, pagelen, | ||
422 | pagelen, page2, fsdata); | ||
423 | } | ||
424 | return ret; | 418 | return ret; |
425 | } | 419 | } |
426 | 420 | ||
diff --git a/fs/nfs/idmap.c b/fs/nfs/idmap.c index d11eb055265c..8ae5dba2d4e5 100644 --- a/fs/nfs/idmap.c +++ b/fs/nfs/idmap.c | |||
@@ -72,39 +72,39 @@ module_param_call(idmap_cache_timeout, param_set_idmap_timeout, param_get_int, | |||
72 | &nfs_idmap_cache_timeout, 0644); | 72 | &nfs_idmap_cache_timeout, 0644); |
73 | 73 | ||
74 | struct idmap_hashent { | 74 | struct idmap_hashent { |
75 | unsigned long ih_expires; | 75 | unsigned long ih_expires; |
76 | __u32 ih_id; | 76 | __u32 ih_id; |
77 | int ih_namelen; | 77 | size_t ih_namelen; |
78 | char ih_name[IDMAP_NAMESZ]; | 78 | char ih_name[IDMAP_NAMESZ]; |
79 | }; | 79 | }; |
80 | 80 | ||
81 | struct idmap_hashtable { | 81 | struct idmap_hashtable { |
82 | __u8 h_type; | 82 | __u8 h_type; |
83 | struct idmap_hashent h_entries[IDMAP_HASH_SZ]; | 83 | struct idmap_hashent h_entries[IDMAP_HASH_SZ]; |
84 | }; | 84 | }; |
85 | 85 | ||
86 | struct idmap { | 86 | struct idmap { |
87 | struct dentry *idmap_dentry; | 87 | struct dentry *idmap_dentry; |
88 | wait_queue_head_t idmap_wq; | 88 | wait_queue_head_t idmap_wq; |
89 | struct idmap_msg idmap_im; | 89 | struct idmap_msg idmap_im; |
90 | struct mutex idmap_lock; /* Serializes upcalls */ | 90 | struct mutex idmap_lock; /* Serializes upcalls */ |
91 | struct mutex idmap_im_lock; /* Protects the hashtable */ | 91 | struct mutex idmap_im_lock; /* Protects the hashtable */ |
92 | struct idmap_hashtable idmap_user_hash; | 92 | struct idmap_hashtable idmap_user_hash; |
93 | struct idmap_hashtable idmap_group_hash; | 93 | struct idmap_hashtable idmap_group_hash; |
94 | }; | 94 | }; |
95 | 95 | ||
96 | static ssize_t idmap_pipe_upcall(struct file *, struct rpc_pipe_msg *, | 96 | static ssize_t idmap_pipe_upcall(struct file *, struct rpc_pipe_msg *, |
97 | char __user *, size_t); | 97 | char __user *, size_t); |
98 | static ssize_t idmap_pipe_downcall(struct file *, const char __user *, | 98 | static ssize_t idmap_pipe_downcall(struct file *, const char __user *, |
99 | size_t); | 99 | size_t); |
100 | static void idmap_pipe_destroy_msg(struct rpc_pipe_msg *); | 100 | static void idmap_pipe_destroy_msg(struct rpc_pipe_msg *); |
101 | 101 | ||
102 | static unsigned int fnvhash32(const void *, size_t); | 102 | static unsigned int fnvhash32(const void *, size_t); |
103 | 103 | ||
104 | static struct rpc_pipe_ops idmap_upcall_ops = { | 104 | static struct rpc_pipe_ops idmap_upcall_ops = { |
105 | .upcall = idmap_pipe_upcall, | 105 | .upcall = idmap_pipe_upcall, |
106 | .downcall = idmap_pipe_downcall, | 106 | .downcall = idmap_pipe_downcall, |
107 | .destroy_msg = idmap_pipe_destroy_msg, | 107 | .destroy_msg = idmap_pipe_destroy_msg, |
108 | }; | 108 | }; |
109 | 109 | ||
110 | int | 110 | int |
@@ -115,19 +115,20 @@ nfs_idmap_new(struct nfs_client *clp) | |||
115 | 115 | ||
116 | BUG_ON(clp->cl_idmap != NULL); | 116 | BUG_ON(clp->cl_idmap != NULL); |
117 | 117 | ||
118 | if ((idmap = kzalloc(sizeof(*idmap), GFP_KERNEL)) == NULL) | 118 | idmap = kzalloc(sizeof(*idmap), GFP_KERNEL); |
119 | return -ENOMEM; | 119 | if (idmap == NULL) |
120 | return -ENOMEM; | ||
120 | 121 | ||
121 | idmap->idmap_dentry = rpc_mkpipe(clp->cl_rpcclient->cl_dentry, "idmap", | 122 | idmap->idmap_dentry = rpc_mkpipe(clp->cl_rpcclient->cl_dentry, "idmap", |
122 | idmap, &idmap_upcall_ops, 0); | 123 | idmap, &idmap_upcall_ops, 0); |
123 | if (IS_ERR(idmap->idmap_dentry)) { | 124 | if (IS_ERR(idmap->idmap_dentry)) { |
124 | error = PTR_ERR(idmap->idmap_dentry); | 125 | error = PTR_ERR(idmap->idmap_dentry); |
125 | kfree(idmap); | 126 | kfree(idmap); |
126 | return error; | 127 | return error; |
127 | } | 128 | } |
128 | 129 | ||
129 | mutex_init(&idmap->idmap_lock); | 130 | mutex_init(&idmap->idmap_lock); |
130 | mutex_init(&idmap->idmap_im_lock); | 131 | mutex_init(&idmap->idmap_im_lock); |
131 | init_waitqueue_head(&idmap->idmap_wq); | 132 | init_waitqueue_head(&idmap->idmap_wq); |
132 | idmap->idmap_user_hash.h_type = IDMAP_TYPE_USER; | 133 | idmap->idmap_user_hash.h_type = IDMAP_TYPE_USER; |
133 | idmap->idmap_group_hash.h_type = IDMAP_TYPE_GROUP; | 134 | idmap->idmap_group_hash.h_type = IDMAP_TYPE_GROUP; |
@@ -192,7 +193,7 @@ idmap_lookup_id(struct idmap_hashtable *h, __u32 id) | |||
192 | * pretty trivial. | 193 | * pretty trivial. |
193 | */ | 194 | */ |
194 | static inline struct idmap_hashent * | 195 | static inline struct idmap_hashent * |
195 | idmap_alloc_name(struct idmap_hashtable *h, char *name, unsigned len) | 196 | idmap_alloc_name(struct idmap_hashtable *h, char *name, size_t len) |
196 | { | 197 | { |
197 | return idmap_name_hash(h, name, len); | 198 | return idmap_name_hash(h, name, len); |
198 | } | 199 | } |
@@ -285,7 +286,7 @@ nfs_idmap_id(struct idmap *idmap, struct idmap_hashtable *h, | |||
285 | memset(im, 0, sizeof(*im)); | 286 | memset(im, 0, sizeof(*im)); |
286 | mutex_unlock(&idmap->idmap_im_lock); | 287 | mutex_unlock(&idmap->idmap_im_lock); |
287 | mutex_unlock(&idmap->idmap_lock); | 288 | mutex_unlock(&idmap->idmap_lock); |
288 | return (ret); | 289 | return ret; |
289 | } | 290 | } |
290 | 291 | ||
291 | /* | 292 | /* |
@@ -354,42 +355,40 @@ nfs_idmap_name(struct idmap *idmap, struct idmap_hashtable *h, | |||
354 | /* RPC pipefs upcall/downcall routines */ | 355 | /* RPC pipefs upcall/downcall routines */ |
355 | static ssize_t | 356 | static ssize_t |
356 | idmap_pipe_upcall(struct file *filp, struct rpc_pipe_msg *msg, | 357 | idmap_pipe_upcall(struct file *filp, struct rpc_pipe_msg *msg, |
357 | char __user *dst, size_t buflen) | 358 | char __user *dst, size_t buflen) |
358 | { | 359 | { |
359 | char *data = (char *)msg->data + msg->copied; | 360 | char *data = (char *)msg->data + msg->copied; |
360 | ssize_t mlen = msg->len - msg->copied; | 361 | size_t mlen = min(msg->len, buflen); |
361 | ssize_t left; | 362 | unsigned long left; |
362 | 363 | ||
363 | if (mlen > buflen) | 364 | left = copy_to_user(dst, data, mlen); |
364 | mlen = buflen; | 365 | if (left == mlen) { |
365 | 366 | msg->errno = -EFAULT; | |
366 | left = copy_to_user(dst, data, mlen); | 367 | return -EFAULT; |
367 | if (left < 0) { | ||
368 | msg->errno = left; | ||
369 | return left; | ||
370 | } | 368 | } |
369 | |||
371 | mlen -= left; | 370 | mlen -= left; |
372 | msg->copied += mlen; | 371 | msg->copied += mlen; |
373 | msg->errno = 0; | 372 | msg->errno = 0; |
374 | return mlen; | 373 | return mlen; |
375 | } | 374 | } |
376 | 375 | ||
377 | static ssize_t | 376 | static ssize_t |
378 | idmap_pipe_downcall(struct file *filp, const char __user *src, size_t mlen) | 377 | idmap_pipe_downcall(struct file *filp, const char __user *src, size_t mlen) |
379 | { | 378 | { |
380 | struct rpc_inode *rpci = RPC_I(filp->f_path.dentry->d_inode); | 379 | struct rpc_inode *rpci = RPC_I(filp->f_path.dentry->d_inode); |
381 | struct idmap *idmap = (struct idmap *)rpci->private; | 380 | struct idmap *idmap = (struct idmap *)rpci->private; |
382 | struct idmap_msg im_in, *im = &idmap->idmap_im; | 381 | struct idmap_msg im_in, *im = &idmap->idmap_im; |
383 | struct idmap_hashtable *h; | 382 | struct idmap_hashtable *h; |
384 | struct idmap_hashent *he = NULL; | 383 | struct idmap_hashent *he = NULL; |
385 | int namelen_in; | 384 | size_t namelen_in; |
386 | int ret; | 385 | int ret; |
387 | 386 | ||
388 | if (mlen != sizeof(im_in)) | 387 | if (mlen != sizeof(im_in)) |
389 | return (-ENOSPC); | 388 | return -ENOSPC; |
390 | 389 | ||
391 | if (copy_from_user(&im_in, src, mlen) != 0) | 390 | if (copy_from_user(&im_in, src, mlen) != 0) |
392 | return (-EFAULT); | 391 | return -EFAULT; |
393 | 392 | ||
394 | mutex_lock(&idmap->idmap_im_lock); | 393 | mutex_lock(&idmap->idmap_im_lock); |
395 | 394 | ||
@@ -487,7 +486,7 @@ static unsigned int fnvhash32(const void *buf, size_t buflen) | |||
487 | hash ^= (unsigned int)*p; | 486 | hash ^= (unsigned int)*p; |
488 | } | 487 | } |
489 | 488 | ||
490 | return (hash); | 489 | return hash; |
491 | } | 490 | } |
492 | 491 | ||
493 | int nfs_map_name_to_uid(struct nfs_client *clp, const char *name, size_t namelen, __u32 *uid) | 492 | int nfs_map_name_to_uid(struct nfs_client *clp, const char *name, size_t namelen, __u32 *uid) |
diff --git a/fs/nfs/inode.c b/fs/nfs/inode.c index db5d96dc6107..3f332e54e760 100644 --- a/fs/nfs/inode.c +++ b/fs/nfs/inode.c | |||
@@ -192,7 +192,7 @@ void nfs_invalidate_atime(struct inode *inode) | |||
192 | */ | 192 | */ |
193 | static void nfs_invalidate_inode(struct inode *inode) | 193 | static void nfs_invalidate_inode(struct inode *inode) |
194 | { | 194 | { |
195 | set_bit(NFS_INO_STALE, &NFS_FLAGS(inode)); | 195 | set_bit(NFS_INO_STALE, &NFS_I(inode)->flags); |
196 | nfs_zap_caches_locked(inode); | 196 | nfs_zap_caches_locked(inode); |
197 | } | 197 | } |
198 | 198 | ||
@@ -229,7 +229,7 @@ nfs_init_locked(struct inode *inode, void *opaque) | |||
229 | struct nfs_find_desc *desc = (struct nfs_find_desc *)opaque; | 229 | struct nfs_find_desc *desc = (struct nfs_find_desc *)opaque; |
230 | struct nfs_fattr *fattr = desc->fattr; | 230 | struct nfs_fattr *fattr = desc->fattr; |
231 | 231 | ||
232 | NFS_FILEID(inode) = fattr->fileid; | 232 | set_nfs_fileid(inode, fattr->fileid); |
233 | nfs_copy_fh(NFS_FH(inode), desc->fh); | 233 | nfs_copy_fh(NFS_FH(inode), desc->fh); |
234 | return 0; | 234 | return 0; |
235 | } | 235 | } |
@@ -291,7 +291,7 @@ nfs_fhget(struct super_block *sb, struct nfs_fh *fh, struct nfs_fattr *fattr) | |||
291 | inode->i_fop = &nfs_dir_operations; | 291 | inode->i_fop = &nfs_dir_operations; |
292 | if (nfs_server_capable(inode, NFS_CAP_READDIRPLUS) | 292 | if (nfs_server_capable(inode, NFS_CAP_READDIRPLUS) |
293 | && fattr->size <= NFS_LIMIT_READDIRPLUS) | 293 | && fattr->size <= NFS_LIMIT_READDIRPLUS) |
294 | set_bit(NFS_INO_ADVISE_RDPLUS, &NFS_FLAGS(inode)); | 294 | set_bit(NFS_INO_ADVISE_RDPLUS, &NFS_I(inode)->flags); |
295 | /* Deal with crossing mountpoints */ | 295 | /* Deal with crossing mountpoints */ |
296 | if (!nfs_fsid_equal(&NFS_SB(sb)->fsid, &fattr->fsid)) { | 296 | if (!nfs_fsid_equal(&NFS_SB(sb)->fsid, &fattr->fsid)) { |
297 | if (fattr->valid & NFS_ATTR_FATTR_V4_REFERRAL) | 297 | if (fattr->valid & NFS_ATTR_FATTR_V4_REFERRAL) |
@@ -461,9 +461,18 @@ int nfs_getattr(struct vfsmount *mnt, struct dentry *dentry, struct kstat *stat) | |||
461 | int need_atime = NFS_I(inode)->cache_validity & NFS_INO_INVALID_ATIME; | 461 | int need_atime = NFS_I(inode)->cache_validity & NFS_INO_INVALID_ATIME; |
462 | int err; | 462 | int err; |
463 | 463 | ||
464 | /* Flush out writes to the server in order to update c/mtime */ | 464 | /* |
465 | if (S_ISREG(inode->i_mode)) | 465 | * Flush out writes to the server in order to update c/mtime. |
466 | * | ||
467 | * Hold the i_mutex to suspend application writes temporarily; | ||
468 | * this prevents long-running writing applications from blocking | ||
469 | * nfs_wb_nocommit. | ||
470 | */ | ||
471 | if (S_ISREG(inode->i_mode)) { | ||
472 | mutex_lock(&inode->i_mutex); | ||
466 | nfs_wb_nocommit(inode); | 473 | nfs_wb_nocommit(inode); |
474 | mutex_unlock(&inode->i_mutex); | ||
475 | } | ||
467 | 476 | ||
468 | /* | 477 | /* |
469 | * We may force a getattr if the user cares about atime. | 478 | * We may force a getattr if the user cares about atime. |
@@ -659,7 +668,7 @@ __nfs_revalidate_inode(struct nfs_server *server, struct inode *inode) | |||
659 | if (status == -ESTALE) { | 668 | if (status == -ESTALE) { |
660 | nfs_zap_caches(inode); | 669 | nfs_zap_caches(inode); |
661 | if (!S_ISDIR(inode->i_mode)) | 670 | if (!S_ISDIR(inode->i_mode)) |
662 | set_bit(NFS_INO_STALE, &NFS_FLAGS(inode)); | 671 | set_bit(NFS_INO_STALE, &NFS_I(inode)->flags); |
663 | } | 672 | } |
664 | goto out; | 673 | goto out; |
665 | } | 674 | } |
@@ -814,8 +823,9 @@ static void nfs_wcc_update_inode(struct inode *inode, struct nfs_fattr *fattr) | |||
814 | if (S_ISDIR(inode->i_mode)) | 823 | if (S_ISDIR(inode->i_mode)) |
815 | nfsi->cache_validity |= NFS_INO_INVALID_DATA; | 824 | nfsi->cache_validity |= NFS_INO_INVALID_DATA; |
816 | } | 825 | } |
817 | if (inode->i_size == fattr->pre_size && nfsi->npages == 0) | 826 | if (inode->i_size == nfs_size_to_loff_t(fattr->pre_size) && |
818 | inode->i_size = fattr->size; | 827 | nfsi->npages == 0) |
828 | inode->i_size = nfs_size_to_loff_t(fattr->size); | ||
819 | } | 829 | } |
820 | } | 830 | } |
821 | 831 | ||
@@ -1019,7 +1029,8 @@ static int nfs_update_inode(struct inode *inode, struct nfs_fattr *fattr) | |||
1019 | dprintk("NFS: mtime change on server for file %s/%ld\n", | 1029 | dprintk("NFS: mtime change on server for file %s/%ld\n", |
1020 | inode->i_sb->s_id, inode->i_ino); | 1030 | inode->i_sb->s_id, inode->i_ino); |
1021 | invalid |= NFS_INO_INVALID_ATTR|NFS_INO_INVALID_DATA; | 1031 | invalid |= NFS_INO_INVALID_ATTR|NFS_INO_INVALID_DATA; |
1022 | nfsi->cache_change_attribute = now; | 1032 | if (S_ISDIR(inode->i_mode)) |
1033 | nfs_force_lookup_revalidate(inode); | ||
1023 | } | 1034 | } |
1024 | /* If ctime has changed we should definitely clear access+acl caches */ | 1035 | /* If ctime has changed we should definitely clear access+acl caches */ |
1025 | if (!timespec_equal(&inode->i_ctime, &fattr->ctime)) | 1036 | if (!timespec_equal(&inode->i_ctime, &fattr->ctime)) |
@@ -1028,7 +1039,8 @@ static int nfs_update_inode(struct inode *inode, struct nfs_fattr *fattr) | |||
1028 | dprintk("NFS: change_attr change on server for file %s/%ld\n", | 1039 | dprintk("NFS: change_attr change on server for file %s/%ld\n", |
1029 | inode->i_sb->s_id, inode->i_ino); | 1040 | inode->i_sb->s_id, inode->i_ino); |
1030 | invalid |= NFS_INO_INVALID_ATTR|NFS_INO_INVALID_DATA|NFS_INO_INVALID_ACCESS|NFS_INO_INVALID_ACL; | 1041 | invalid |= NFS_INO_INVALID_ATTR|NFS_INO_INVALID_DATA|NFS_INO_INVALID_ACCESS|NFS_INO_INVALID_ACL; |
1031 | nfsi->cache_change_attribute = now; | 1042 | if (S_ISDIR(inode->i_mode)) |
1043 | nfs_force_lookup_revalidate(inode); | ||
1032 | } | 1044 | } |
1033 | 1045 | ||
1034 | /* Check if our cached file size is stale */ | 1046 | /* Check if our cached file size is stale */ |
@@ -1133,7 +1145,7 @@ static int nfs_update_inode(struct inode *inode, struct nfs_fattr *fattr) | |||
1133 | void nfs4_clear_inode(struct inode *inode) | 1145 | void nfs4_clear_inode(struct inode *inode) |
1134 | { | 1146 | { |
1135 | /* If we are holding a delegation, return it! */ | 1147 | /* If we are holding a delegation, return it! */ |
1136 | nfs_inode_return_delegation(inode); | 1148 | nfs_inode_return_delegation_noreclaim(inode); |
1137 | /* First call standard NFS clear_inode() code */ | 1149 | /* First call standard NFS clear_inode() code */ |
1138 | nfs_clear_inode(inode); | 1150 | nfs_clear_inode(inode); |
1139 | } | 1151 | } |
diff --git a/fs/nfs/internal.h b/fs/nfs/internal.h index f3acf48412be..0f5619611b8d 100644 --- a/fs/nfs/internal.h +++ b/fs/nfs/internal.h | |||
@@ -21,7 +21,8 @@ struct nfs_clone_mount { | |||
21 | struct nfs_fattr *fattr; | 21 | struct nfs_fattr *fattr; |
22 | char *hostname; | 22 | char *hostname; |
23 | char *mnt_path; | 23 | char *mnt_path; |
24 | struct sockaddr_in *addr; | 24 | struct sockaddr *addr; |
25 | size_t addrlen; | ||
25 | rpc_authflavor_t authflavor; | 26 | rpc_authflavor_t authflavor; |
26 | }; | 27 | }; |
27 | 28 | ||
@@ -41,19 +42,19 @@ struct nfs_parsed_mount_data { | |||
41 | char *client_address; | 42 | char *client_address; |
42 | 43 | ||
43 | struct { | 44 | struct { |
44 | struct sockaddr_in address; | 45 | struct sockaddr_storage address; |
46 | size_t addrlen; | ||
45 | char *hostname; | 47 | char *hostname; |
46 | unsigned int program; | ||
47 | unsigned int version; | 48 | unsigned int version; |
48 | unsigned short port; | 49 | unsigned short port; |
49 | int protocol; | 50 | int protocol; |
50 | } mount_server; | 51 | } mount_server; |
51 | 52 | ||
52 | struct { | 53 | struct { |
53 | struct sockaddr_in address; | 54 | struct sockaddr_storage address; |
55 | size_t addrlen; | ||
54 | char *hostname; | 56 | char *hostname; |
55 | char *export_path; | 57 | char *export_path; |
56 | unsigned int program; | ||
57 | int protocol; | 58 | int protocol; |
58 | } nfs_server; | 59 | } nfs_server; |
59 | }; | 60 | }; |
@@ -62,7 +63,8 @@ struct nfs_parsed_mount_data { | |||
62 | extern struct rpc_program nfs_program; | 63 | extern struct rpc_program nfs_program; |
63 | 64 | ||
64 | extern void nfs_put_client(struct nfs_client *); | 65 | extern void nfs_put_client(struct nfs_client *); |
65 | extern struct nfs_client *nfs_find_client(const struct sockaddr_in *, int); | 66 | extern struct nfs_client *nfs_find_client(const struct sockaddr *, u32); |
67 | extern struct nfs_client *nfs_find_client_next(struct nfs_client *); | ||
66 | extern struct nfs_server *nfs_create_server( | 68 | extern struct nfs_server *nfs_create_server( |
67 | const struct nfs_parsed_mount_data *, | 69 | const struct nfs_parsed_mount_data *, |
68 | struct nfs_fh *); | 70 | struct nfs_fh *); |
@@ -160,6 +162,8 @@ extern struct rpc_stat nfs_rpcstat; | |||
160 | 162 | ||
161 | extern int __init register_nfs_fs(void); | 163 | extern int __init register_nfs_fs(void); |
162 | extern void __exit unregister_nfs_fs(void); | 164 | extern void __exit unregister_nfs_fs(void); |
165 | extern void nfs_sb_active(struct nfs_server *server); | ||
166 | extern void nfs_sb_deactive(struct nfs_server *server); | ||
163 | 167 | ||
164 | /* namespace.c */ | 168 | /* namespace.c */ |
165 | extern char *nfs_path(const char *base, | 169 | extern char *nfs_path(const char *base, |
diff --git a/fs/nfs/namespace.c b/fs/nfs/namespace.c index acfc56f9edc0..be4ce1c3a3d8 100644 --- a/fs/nfs/namespace.c +++ b/fs/nfs/namespace.c | |||
@@ -188,7 +188,7 @@ static struct vfsmount *nfs_do_clone_mount(struct nfs_server *server, | |||
188 | { | 188 | { |
189 | #ifdef CONFIG_NFS_V4 | 189 | #ifdef CONFIG_NFS_V4 |
190 | struct vfsmount *mnt = NULL; | 190 | struct vfsmount *mnt = NULL; |
191 | switch (server->nfs_client->cl_nfsversion) { | 191 | switch (server->nfs_client->rpc_ops->version) { |
192 | case 2: | 192 | case 2: |
193 | case 3: | 193 | case 3: |
194 | mnt = vfs_kern_mount(&nfs_xdev_fs_type, 0, devname, mountdata); | 194 | mnt = vfs_kern_mount(&nfs_xdev_fs_type, 0, devname, mountdata); |
diff --git a/fs/nfs/nfs2xdr.c b/fs/nfs/nfs2xdr.c index 668ab96c7b59..1f7ea675e0c5 100644 --- a/fs/nfs/nfs2xdr.c +++ b/fs/nfs/nfs2xdr.c | |||
@@ -262,7 +262,9 @@ static int | |||
262 | nfs_xdr_readres(struct rpc_rqst *req, __be32 *p, struct nfs_readres *res) | 262 | nfs_xdr_readres(struct rpc_rqst *req, __be32 *p, struct nfs_readres *res) |
263 | { | 263 | { |
264 | struct kvec *iov = req->rq_rcv_buf.head; | 264 | struct kvec *iov = req->rq_rcv_buf.head; |
265 | int status, count, recvd, hdrlen; | 265 | size_t hdrlen; |
266 | u32 count, recvd; | ||
267 | int status; | ||
266 | 268 | ||
267 | if ((status = ntohl(*p++))) | 269 | if ((status = ntohl(*p++))) |
268 | return -nfs_stat_to_errno(status); | 270 | return -nfs_stat_to_errno(status); |
@@ -273,7 +275,7 @@ nfs_xdr_readres(struct rpc_rqst *req, __be32 *p, struct nfs_readres *res) | |||
273 | hdrlen = (u8 *) p - (u8 *) iov->iov_base; | 275 | hdrlen = (u8 *) p - (u8 *) iov->iov_base; |
274 | if (iov->iov_len < hdrlen) { | 276 | if (iov->iov_len < hdrlen) { |
275 | dprintk("NFS: READ reply header overflowed:" | 277 | dprintk("NFS: READ reply header overflowed:" |
276 | "length %d > %Zu\n", hdrlen, iov->iov_len); | 278 | "length %Zu > %Zu\n", hdrlen, iov->iov_len); |
277 | return -errno_NFSERR_IO; | 279 | return -errno_NFSERR_IO; |
278 | } else if (iov->iov_len != hdrlen) { | 280 | } else if (iov->iov_len != hdrlen) { |
279 | dprintk("NFS: READ header is short. iovec will be shifted.\n"); | 281 | dprintk("NFS: READ header is short. iovec will be shifted.\n"); |
@@ -283,11 +285,11 @@ nfs_xdr_readres(struct rpc_rqst *req, __be32 *p, struct nfs_readres *res) | |||
283 | recvd = req->rq_rcv_buf.len - hdrlen; | 285 | recvd = req->rq_rcv_buf.len - hdrlen; |
284 | if (count > recvd) { | 286 | if (count > recvd) { |
285 | dprintk("NFS: server cheating in read reply: " | 287 | dprintk("NFS: server cheating in read reply: " |
286 | "count %d > recvd %d\n", count, recvd); | 288 | "count %u > recvd %u\n", count, recvd); |
287 | count = recvd; | 289 | count = recvd; |
288 | } | 290 | } |
289 | 291 | ||
290 | dprintk("RPC: readres OK count %d\n", count); | 292 | dprintk("RPC: readres OK count %u\n", count); |
291 | if (count < res->count) | 293 | if (count < res->count) |
292 | res->count = count; | 294 | res->count = count; |
293 | 295 | ||
@@ -423,9 +425,10 @@ nfs_xdr_readdirres(struct rpc_rqst *req, __be32 *p, void *dummy) | |||
423 | struct xdr_buf *rcvbuf = &req->rq_rcv_buf; | 425 | struct xdr_buf *rcvbuf = &req->rq_rcv_buf; |
424 | struct kvec *iov = rcvbuf->head; | 426 | struct kvec *iov = rcvbuf->head; |
425 | struct page **page; | 427 | struct page **page; |
426 | int hdrlen, recvd; | 428 | size_t hdrlen; |
429 | unsigned int pglen, recvd; | ||
430 | u32 len; | ||
427 | int status, nr; | 431 | int status, nr; |
428 | unsigned int len, pglen; | ||
429 | __be32 *end, *entry, *kaddr; | 432 | __be32 *end, *entry, *kaddr; |
430 | 433 | ||
431 | if ((status = ntohl(*p++))) | 434 | if ((status = ntohl(*p++))) |
@@ -434,7 +437,7 @@ nfs_xdr_readdirres(struct rpc_rqst *req, __be32 *p, void *dummy) | |||
434 | hdrlen = (u8 *) p - (u8 *) iov->iov_base; | 437 | hdrlen = (u8 *) p - (u8 *) iov->iov_base; |
435 | if (iov->iov_len < hdrlen) { | 438 | if (iov->iov_len < hdrlen) { |
436 | dprintk("NFS: READDIR reply header overflowed:" | 439 | dprintk("NFS: READDIR reply header overflowed:" |
437 | "length %d > %Zu\n", hdrlen, iov->iov_len); | 440 | "length %Zu > %Zu\n", hdrlen, iov->iov_len); |
438 | return -errno_NFSERR_IO; | 441 | return -errno_NFSERR_IO; |
439 | } else if (iov->iov_len != hdrlen) { | 442 | } else if (iov->iov_len != hdrlen) { |
440 | dprintk("NFS: READDIR header is short. iovec will be shifted.\n"); | 443 | dprintk("NFS: READDIR header is short. iovec will be shifted.\n"); |
@@ -576,7 +579,8 @@ nfs_xdr_readlinkres(struct rpc_rqst *req, __be32 *p, void *dummy) | |||
576 | { | 579 | { |
577 | struct xdr_buf *rcvbuf = &req->rq_rcv_buf; | 580 | struct xdr_buf *rcvbuf = &req->rq_rcv_buf; |
578 | struct kvec *iov = rcvbuf->head; | 581 | struct kvec *iov = rcvbuf->head; |
579 | int hdrlen, len, recvd; | 582 | size_t hdrlen; |
583 | u32 len, recvd; | ||
580 | char *kaddr; | 584 | char *kaddr; |
581 | int status; | 585 | int status; |
582 | 586 | ||
@@ -584,14 +588,14 @@ nfs_xdr_readlinkres(struct rpc_rqst *req, __be32 *p, void *dummy) | |||
584 | return -nfs_stat_to_errno(status); | 588 | return -nfs_stat_to_errno(status); |
585 | /* Convert length of symlink */ | 589 | /* Convert length of symlink */ |
586 | len = ntohl(*p++); | 590 | len = ntohl(*p++); |
587 | if (len >= rcvbuf->page_len || len <= 0) { | 591 | if (len >= rcvbuf->page_len) { |
588 | dprintk("nfs: server returned giant symlink!\n"); | 592 | dprintk("nfs: server returned giant symlink!\n"); |
589 | return -ENAMETOOLONG; | 593 | return -ENAMETOOLONG; |
590 | } | 594 | } |
591 | hdrlen = (u8 *) p - (u8 *) iov->iov_base; | 595 | hdrlen = (u8 *) p - (u8 *) iov->iov_base; |
592 | if (iov->iov_len < hdrlen) { | 596 | if (iov->iov_len < hdrlen) { |
593 | dprintk("NFS: READLINK reply header overflowed:" | 597 | dprintk("NFS: READLINK reply header overflowed:" |
594 | "length %d > %Zu\n", hdrlen, iov->iov_len); | 598 | "length %Zu > %Zu\n", hdrlen, iov->iov_len); |
595 | return -errno_NFSERR_IO; | 599 | return -errno_NFSERR_IO; |
596 | } else if (iov->iov_len != hdrlen) { | 600 | } else if (iov->iov_len != hdrlen) { |
597 | dprintk("NFS: READLINK header is short. iovec will be shifted.\n"); | 601 | dprintk("NFS: READLINK header is short. iovec will be shifted.\n"); |
diff --git a/fs/nfs/nfs3proc.c b/fs/nfs/nfs3proc.c index 4cdc2361a669..b353c1a05bfd 100644 --- a/fs/nfs/nfs3proc.c +++ b/fs/nfs/nfs3proc.c | |||
@@ -732,16 +732,9 @@ static int nfs3_read_done(struct rpc_task *task, struct nfs_read_data *data) | |||
732 | return 0; | 732 | return 0; |
733 | } | 733 | } |
734 | 734 | ||
735 | static void nfs3_proc_read_setup(struct nfs_read_data *data) | 735 | static void nfs3_proc_read_setup(struct nfs_read_data *data, struct rpc_message *msg) |
736 | { | 736 | { |
737 | struct rpc_message msg = { | 737 | msg->rpc_proc = &nfs3_procedures[NFS3PROC_READ]; |
738 | .rpc_proc = &nfs3_procedures[NFS3PROC_READ], | ||
739 | .rpc_argp = &data->args, | ||
740 | .rpc_resp = &data->res, | ||
741 | .rpc_cred = data->cred, | ||
742 | }; | ||
743 | |||
744 | rpc_call_setup(&data->task, &msg, 0); | ||
745 | } | 738 | } |
746 | 739 | ||
747 | static int nfs3_write_done(struct rpc_task *task, struct nfs_write_data *data) | 740 | static int nfs3_write_done(struct rpc_task *task, struct nfs_write_data *data) |
@@ -753,24 +746,9 @@ static int nfs3_write_done(struct rpc_task *task, struct nfs_write_data *data) | |||
753 | return 0; | 746 | return 0; |
754 | } | 747 | } |
755 | 748 | ||
756 | static void nfs3_proc_write_setup(struct nfs_write_data *data, int how) | 749 | static void nfs3_proc_write_setup(struct nfs_write_data *data, struct rpc_message *msg) |
757 | { | 750 | { |
758 | struct rpc_message msg = { | 751 | msg->rpc_proc = &nfs3_procedures[NFS3PROC_WRITE]; |
759 | .rpc_proc = &nfs3_procedures[NFS3PROC_WRITE], | ||
760 | .rpc_argp = &data->args, | ||
761 | .rpc_resp = &data->res, | ||
762 | .rpc_cred = data->cred, | ||
763 | }; | ||
764 | |||
765 | data->args.stable = NFS_UNSTABLE; | ||
766 | if (how & FLUSH_STABLE) { | ||
767 | data->args.stable = NFS_FILE_SYNC; | ||
768 | if (NFS_I(data->inode)->ncommit) | ||
769 | data->args.stable = NFS_DATA_SYNC; | ||
770 | } | ||
771 | |||
772 | /* Finalize the task. */ | ||
773 | rpc_call_setup(&data->task, &msg, 0); | ||
774 | } | 752 | } |
775 | 753 | ||
776 | static int nfs3_commit_done(struct rpc_task *task, struct nfs_write_data *data) | 754 | static int nfs3_commit_done(struct rpc_task *task, struct nfs_write_data *data) |
@@ -781,22 +759,17 @@ static int nfs3_commit_done(struct rpc_task *task, struct nfs_write_data *data) | |||
781 | return 0; | 759 | return 0; |
782 | } | 760 | } |
783 | 761 | ||
784 | static void nfs3_proc_commit_setup(struct nfs_write_data *data, int how) | 762 | static void nfs3_proc_commit_setup(struct nfs_write_data *data, struct rpc_message *msg) |
785 | { | 763 | { |
786 | struct rpc_message msg = { | 764 | msg->rpc_proc = &nfs3_procedures[NFS3PROC_COMMIT]; |
787 | .rpc_proc = &nfs3_procedures[NFS3PROC_COMMIT], | ||
788 | .rpc_argp = &data->args, | ||
789 | .rpc_resp = &data->res, | ||
790 | .rpc_cred = data->cred, | ||
791 | }; | ||
792 | |||
793 | rpc_call_setup(&data->task, &msg, 0); | ||
794 | } | 765 | } |
795 | 766 | ||
796 | static int | 767 | static int |
797 | nfs3_proc_lock(struct file *filp, int cmd, struct file_lock *fl) | 768 | nfs3_proc_lock(struct file *filp, int cmd, struct file_lock *fl) |
798 | { | 769 | { |
799 | return nlmclnt_proc(filp->f_path.dentry->d_inode, cmd, fl); | 770 | struct inode *inode = filp->f_path.dentry->d_inode; |
771 | |||
772 | return nlmclnt_proc(NFS_SERVER(inode)->nlm_host, cmd, fl); | ||
800 | } | 773 | } |
801 | 774 | ||
802 | const struct nfs_rpc_ops nfs_v3_clientops = { | 775 | const struct nfs_rpc_ops nfs_v3_clientops = { |
diff --git a/fs/nfs/nfs3xdr.c b/fs/nfs/nfs3xdr.c index 616d3267b7e7..3917e2fa4e40 100644 --- a/fs/nfs/nfs3xdr.c +++ b/fs/nfs/nfs3xdr.c | |||
@@ -506,9 +506,9 @@ nfs3_xdr_readdirres(struct rpc_rqst *req, __be32 *p, struct nfs3_readdirres *res | |||
506 | struct xdr_buf *rcvbuf = &req->rq_rcv_buf; | 506 | struct xdr_buf *rcvbuf = &req->rq_rcv_buf; |
507 | struct kvec *iov = rcvbuf->head; | 507 | struct kvec *iov = rcvbuf->head; |
508 | struct page **page; | 508 | struct page **page; |
509 | int hdrlen, recvd; | 509 | size_t hdrlen; |
510 | u32 len, recvd, pglen; | ||
510 | int status, nr; | 511 | int status, nr; |
511 | unsigned int len, pglen; | ||
512 | __be32 *entry, *end, *kaddr; | 512 | __be32 *entry, *end, *kaddr; |
513 | 513 | ||
514 | status = ntohl(*p++); | 514 | status = ntohl(*p++); |
@@ -527,7 +527,7 @@ nfs3_xdr_readdirres(struct rpc_rqst *req, __be32 *p, struct nfs3_readdirres *res | |||
527 | hdrlen = (u8 *) p - (u8 *) iov->iov_base; | 527 | hdrlen = (u8 *) p - (u8 *) iov->iov_base; |
528 | if (iov->iov_len < hdrlen) { | 528 | if (iov->iov_len < hdrlen) { |
529 | dprintk("NFS: READDIR reply header overflowed:" | 529 | dprintk("NFS: READDIR reply header overflowed:" |
530 | "length %d > %Zu\n", hdrlen, iov->iov_len); | 530 | "length %Zu > %Zu\n", hdrlen, iov->iov_len); |
531 | return -errno_NFSERR_IO; | 531 | return -errno_NFSERR_IO; |
532 | } else if (iov->iov_len != hdrlen) { | 532 | } else if (iov->iov_len != hdrlen) { |
533 | dprintk("NFS: READDIR header is short. iovec will be shifted.\n"); | 533 | dprintk("NFS: READDIR header is short. iovec will be shifted.\n"); |
@@ -549,7 +549,7 @@ nfs3_xdr_readdirres(struct rpc_rqst *req, __be32 *p, struct nfs3_readdirres *res | |||
549 | len = ntohl(*p++); /* string length */ | 549 | len = ntohl(*p++); /* string length */ |
550 | p += XDR_QUADLEN(len) + 2; /* name + cookie */ | 550 | p += XDR_QUADLEN(len) + 2; /* name + cookie */ |
551 | if (len > NFS3_MAXNAMLEN) { | 551 | if (len > NFS3_MAXNAMLEN) { |
552 | dprintk("NFS: giant filename in readdir (len %x)!\n", | 552 | dprintk("NFS: giant filename in readdir (len 0x%x)!\n", |
553 | len); | 553 | len); |
554 | goto err_unmap; | 554 | goto err_unmap; |
555 | } | 555 | } |
@@ -570,7 +570,7 @@ nfs3_xdr_readdirres(struct rpc_rqst *req, __be32 *p, struct nfs3_readdirres *res | |||
570 | len = ntohl(*p++); | 570 | len = ntohl(*p++); |
571 | if (len > NFS3_FHSIZE) { | 571 | if (len > NFS3_FHSIZE) { |
572 | dprintk("NFS: giant filehandle in " | 572 | dprintk("NFS: giant filehandle in " |
573 | "readdir (len %x)!\n", len); | 573 | "readdir (len 0x%x)!\n", len); |
574 | goto err_unmap; | 574 | goto err_unmap; |
575 | } | 575 | } |
576 | p += XDR_QUADLEN(len); | 576 | p += XDR_QUADLEN(len); |
@@ -815,7 +815,8 @@ nfs3_xdr_readlinkres(struct rpc_rqst *req, __be32 *p, struct nfs_fattr *fattr) | |||
815 | { | 815 | { |
816 | struct xdr_buf *rcvbuf = &req->rq_rcv_buf; | 816 | struct xdr_buf *rcvbuf = &req->rq_rcv_buf; |
817 | struct kvec *iov = rcvbuf->head; | 817 | struct kvec *iov = rcvbuf->head; |
818 | int hdrlen, len, recvd; | 818 | size_t hdrlen; |
819 | u32 len, recvd; | ||
819 | char *kaddr; | 820 | char *kaddr; |
820 | int status; | 821 | int status; |
821 | 822 | ||
@@ -827,7 +828,7 @@ nfs3_xdr_readlinkres(struct rpc_rqst *req, __be32 *p, struct nfs_fattr *fattr) | |||
827 | 828 | ||
828 | /* Convert length of symlink */ | 829 | /* Convert length of symlink */ |
829 | len = ntohl(*p++); | 830 | len = ntohl(*p++); |
830 | if (len >= rcvbuf->page_len || len <= 0) { | 831 | if (len >= rcvbuf->page_len) { |
831 | dprintk("nfs: server returned giant symlink!\n"); | 832 | dprintk("nfs: server returned giant symlink!\n"); |
832 | return -ENAMETOOLONG; | 833 | return -ENAMETOOLONG; |
833 | } | 834 | } |
@@ -835,7 +836,7 @@ nfs3_xdr_readlinkres(struct rpc_rqst *req, __be32 *p, struct nfs_fattr *fattr) | |||
835 | hdrlen = (u8 *) p - (u8 *) iov->iov_base; | 836 | hdrlen = (u8 *) p - (u8 *) iov->iov_base; |
836 | if (iov->iov_len < hdrlen) { | 837 | if (iov->iov_len < hdrlen) { |
837 | dprintk("NFS: READLINK reply header overflowed:" | 838 | dprintk("NFS: READLINK reply header overflowed:" |
838 | "length %d > %Zu\n", hdrlen, iov->iov_len); | 839 | "length %Zu > %Zu\n", hdrlen, iov->iov_len); |
839 | return -errno_NFSERR_IO; | 840 | return -errno_NFSERR_IO; |
840 | } else if (iov->iov_len != hdrlen) { | 841 | } else if (iov->iov_len != hdrlen) { |
841 | dprintk("NFS: READLINK header is short. " | 842 | dprintk("NFS: READLINK header is short. " |
@@ -863,7 +864,9 @@ static int | |||
863 | nfs3_xdr_readres(struct rpc_rqst *req, __be32 *p, struct nfs_readres *res) | 864 | nfs3_xdr_readres(struct rpc_rqst *req, __be32 *p, struct nfs_readres *res) |
864 | { | 865 | { |
865 | struct kvec *iov = req->rq_rcv_buf.head; | 866 | struct kvec *iov = req->rq_rcv_buf.head; |
866 | int status, count, ocount, recvd, hdrlen; | 867 | size_t hdrlen; |
868 | u32 count, ocount, recvd; | ||
869 | int status; | ||
867 | 870 | ||
868 | status = ntohl(*p++); | 871 | status = ntohl(*p++); |
869 | p = xdr_decode_post_op_attr(p, res->fattr); | 872 | p = xdr_decode_post_op_attr(p, res->fattr); |
@@ -871,7 +874,7 @@ nfs3_xdr_readres(struct rpc_rqst *req, __be32 *p, struct nfs_readres *res) | |||
871 | if (status != 0) | 874 | if (status != 0) |
872 | return -nfs_stat_to_errno(status); | 875 | return -nfs_stat_to_errno(status); |
873 | 876 | ||
874 | /* Decode reply could and EOF flag. NFSv3 is somewhat redundant | 877 | /* Decode reply count and EOF flag. NFSv3 is somewhat redundant |
875 | * in that it puts the count both in the res struct and in the | 878 | * in that it puts the count both in the res struct and in the |
876 | * opaque data count. */ | 879 | * opaque data count. */ |
877 | count = ntohl(*p++); | 880 | count = ntohl(*p++); |
@@ -886,7 +889,7 @@ nfs3_xdr_readres(struct rpc_rqst *req, __be32 *p, struct nfs_readres *res) | |||
886 | hdrlen = (u8 *) p - (u8 *) iov->iov_base; | 889 | hdrlen = (u8 *) p - (u8 *) iov->iov_base; |
887 | if (iov->iov_len < hdrlen) { | 890 | if (iov->iov_len < hdrlen) { |
888 | dprintk("NFS: READ reply header overflowed:" | 891 | dprintk("NFS: READ reply header overflowed:" |
889 | "length %d > %Zu\n", hdrlen, iov->iov_len); | 892 | "length %Zu > %Zu\n", hdrlen, iov->iov_len); |
890 | return -errno_NFSERR_IO; | 893 | return -errno_NFSERR_IO; |
891 | } else if (iov->iov_len != hdrlen) { | 894 | } else if (iov->iov_len != hdrlen) { |
892 | dprintk("NFS: READ header is short. iovec will be shifted.\n"); | 895 | dprintk("NFS: READ header is short. iovec will be shifted.\n"); |
@@ -896,7 +899,7 @@ nfs3_xdr_readres(struct rpc_rqst *req, __be32 *p, struct nfs_readres *res) | |||
896 | recvd = req->rq_rcv_buf.len - hdrlen; | 899 | recvd = req->rq_rcv_buf.len - hdrlen; |
897 | if (count > recvd) { | 900 | if (count > recvd) { |
898 | dprintk("NFS: server cheating in read reply: " | 901 | dprintk("NFS: server cheating in read reply: " |
899 | "count %d > recvd %d\n", count, recvd); | 902 | "count %u > recvd %u\n", count, recvd); |
900 | count = recvd; | 903 | count = recvd; |
901 | res->eof = 0; | 904 | res->eof = 0; |
902 | } | 905 | } |
diff --git a/fs/nfs/nfs4namespace.c b/fs/nfs/nfs4namespace.c index dd5fef20c702..5f9ba41ed5bf 100644 --- a/fs/nfs/nfs4namespace.c +++ b/fs/nfs/nfs4namespace.c | |||
@@ -114,10 +114,7 @@ static inline int valid_ipaddr4(const char *buf) | |||
114 | * nfs_follow_referral - set up mountpoint when hitting a referral on moved error | 114 | * nfs_follow_referral - set up mountpoint when hitting a referral on moved error |
115 | * @mnt_parent - mountpoint of parent directory | 115 | * @mnt_parent - mountpoint of parent directory |
116 | * @dentry - parent directory | 116 | * @dentry - parent directory |
117 | * @fspath - fs path returned in fs_locations | 117 | * @locations - array of NFSv4 server location information |
118 | * @mntpath - mount path to new server | ||
119 | * @hostname - hostname of new server | ||
120 | * @addr - host addr of new server | ||
121 | * | 118 | * |
122 | */ | 119 | */ |
123 | static struct vfsmount *nfs_follow_referral(const struct vfsmount *mnt_parent, | 120 | static struct vfsmount *nfs_follow_referral(const struct vfsmount *mnt_parent, |
@@ -131,7 +128,8 @@ static struct vfsmount *nfs_follow_referral(const struct vfsmount *mnt_parent, | |||
131 | .authflavor = NFS_SB(mnt_parent->mnt_sb)->client->cl_auth->au_flavor, | 128 | .authflavor = NFS_SB(mnt_parent->mnt_sb)->client->cl_auth->au_flavor, |
132 | }; | 129 | }; |
133 | char *page = NULL, *page2 = NULL; | 130 | char *page = NULL, *page2 = NULL; |
134 | int loc, s, error; | 131 | unsigned int s; |
132 | int loc, error; | ||
135 | 133 | ||
136 | if (locations == NULL || locations->nlocations <= 0) | 134 | if (locations == NULL || locations->nlocations <= 0) |
137 | goto out; | 135 | goto out; |
@@ -174,7 +172,10 @@ static struct vfsmount *nfs_follow_referral(const struct vfsmount *mnt_parent, | |||
174 | 172 | ||
175 | s = 0; | 173 | s = 0; |
176 | while (s < location->nservers) { | 174 | while (s < location->nservers) { |
177 | struct sockaddr_in addr = {}; | 175 | struct sockaddr_in addr = { |
176 | .sin_family = AF_INET, | ||
177 | .sin_port = htons(NFS_PORT), | ||
178 | }; | ||
178 | 179 | ||
179 | if (location->servers[s].len <= 0 || | 180 | if (location->servers[s].len <= 0 || |
180 | valid_ipaddr4(location->servers[s].data) < 0) { | 181 | valid_ipaddr4(location->servers[s].data) < 0) { |
@@ -183,10 +184,9 @@ static struct vfsmount *nfs_follow_referral(const struct vfsmount *mnt_parent, | |||
183 | } | 184 | } |
184 | 185 | ||
185 | mountdata.hostname = location->servers[s].data; | 186 | mountdata.hostname = location->servers[s].data; |
186 | addr.sin_addr.s_addr = in_aton(mountdata.hostname); | 187 | addr.sin_addr.s_addr = in_aton(mountdata.hostname), |
187 | addr.sin_family = AF_INET; | 188 | mountdata.addr = (struct sockaddr *)&addr; |
188 | addr.sin_port = htons(NFS_PORT); | 189 | mountdata.addrlen = sizeof(addr); |
189 | mountdata.addr = &addr; | ||
190 | 190 | ||
191 | snprintf(page, PAGE_SIZE, "%s:%s", | 191 | snprintf(page, PAGE_SIZE, "%s:%s", |
192 | mountdata.hostname, | 192 | mountdata.hostname, |
diff --git a/fs/nfs/nfs4proc.c b/fs/nfs/nfs4proc.c index 9e2e1c7291db..5c189bd57eb2 100644 --- a/fs/nfs/nfs4proc.c +++ b/fs/nfs/nfs4proc.c | |||
@@ -210,7 +210,7 @@ static void update_changeattr(struct inode *dir, struct nfs4_change_info *cinfo) | |||
210 | spin_lock(&dir->i_lock); | 210 | spin_lock(&dir->i_lock); |
211 | nfsi->cache_validity |= NFS_INO_INVALID_ATTR|NFS_INO_REVAL_PAGECACHE|NFS_INO_INVALID_DATA; | 211 | nfsi->cache_validity |= NFS_INO_INVALID_ATTR|NFS_INO_REVAL_PAGECACHE|NFS_INO_INVALID_DATA; |
212 | if (!cinfo->atomic || cinfo->before != nfsi->change_attr) | 212 | if (!cinfo->atomic || cinfo->before != nfsi->change_attr) |
213 | nfsi->cache_change_attribute = jiffies; | 213 | nfs_force_lookup_revalidate(dir); |
214 | nfsi->change_attr = cinfo->after; | 214 | nfsi->change_attr = cinfo->after; |
215 | spin_unlock(&dir->i_lock); | 215 | spin_unlock(&dir->i_lock); |
216 | } | 216 | } |
@@ -718,19 +718,6 @@ int nfs4_open_delegation_recall(struct nfs_open_context *ctx, struct nfs4_state | |||
718 | return err; | 718 | return err; |
719 | } | 719 | } |
720 | 720 | ||
721 | static void nfs4_open_confirm_prepare(struct rpc_task *task, void *calldata) | ||
722 | { | ||
723 | struct nfs4_opendata *data = calldata; | ||
724 | struct rpc_message msg = { | ||
725 | .rpc_proc = &nfs4_procedures[NFSPROC4_CLNT_OPEN_CONFIRM], | ||
726 | .rpc_argp = &data->c_arg, | ||
727 | .rpc_resp = &data->c_res, | ||
728 | .rpc_cred = data->owner->so_cred, | ||
729 | }; | ||
730 | data->timestamp = jiffies; | ||
731 | rpc_call_setup(task, &msg, 0); | ||
732 | } | ||
733 | |||
734 | static void nfs4_open_confirm_done(struct rpc_task *task, void *calldata) | 721 | static void nfs4_open_confirm_done(struct rpc_task *task, void *calldata) |
735 | { | 722 | { |
736 | struct nfs4_opendata *data = calldata; | 723 | struct nfs4_opendata *data = calldata; |
@@ -767,7 +754,6 @@ out_free: | |||
767 | } | 754 | } |
768 | 755 | ||
769 | static const struct rpc_call_ops nfs4_open_confirm_ops = { | 756 | static const struct rpc_call_ops nfs4_open_confirm_ops = { |
770 | .rpc_call_prepare = nfs4_open_confirm_prepare, | ||
771 | .rpc_call_done = nfs4_open_confirm_done, | 757 | .rpc_call_done = nfs4_open_confirm_done, |
772 | .rpc_release = nfs4_open_confirm_release, | 758 | .rpc_release = nfs4_open_confirm_release, |
773 | }; | 759 | }; |
@@ -779,12 +765,26 @@ static int _nfs4_proc_open_confirm(struct nfs4_opendata *data) | |||
779 | { | 765 | { |
780 | struct nfs_server *server = NFS_SERVER(data->dir->d_inode); | 766 | struct nfs_server *server = NFS_SERVER(data->dir->d_inode); |
781 | struct rpc_task *task; | 767 | struct rpc_task *task; |
768 | struct rpc_message msg = { | ||
769 | .rpc_proc = &nfs4_procedures[NFSPROC4_CLNT_OPEN_CONFIRM], | ||
770 | .rpc_argp = &data->c_arg, | ||
771 | .rpc_resp = &data->c_res, | ||
772 | .rpc_cred = data->owner->so_cred, | ||
773 | }; | ||
774 | struct rpc_task_setup task_setup_data = { | ||
775 | .rpc_client = server->client, | ||
776 | .rpc_message = &msg, | ||
777 | .callback_ops = &nfs4_open_confirm_ops, | ||
778 | .callback_data = data, | ||
779 | .flags = RPC_TASK_ASYNC, | ||
780 | }; | ||
782 | int status; | 781 | int status; |
783 | 782 | ||
784 | kref_get(&data->kref); | 783 | kref_get(&data->kref); |
785 | data->rpc_done = 0; | 784 | data->rpc_done = 0; |
786 | data->rpc_status = 0; | 785 | data->rpc_status = 0; |
787 | task = rpc_run_task(server->client, RPC_TASK_ASYNC, &nfs4_open_confirm_ops, data); | 786 | data->timestamp = jiffies; |
787 | task = rpc_run_task(&task_setup_data); | ||
788 | if (IS_ERR(task)) | 788 | if (IS_ERR(task)) |
789 | return PTR_ERR(task); | 789 | return PTR_ERR(task); |
790 | status = nfs4_wait_for_completion_rpc_task(task); | 790 | status = nfs4_wait_for_completion_rpc_task(task); |
@@ -801,13 +801,7 @@ static void nfs4_open_prepare(struct rpc_task *task, void *calldata) | |||
801 | { | 801 | { |
802 | struct nfs4_opendata *data = calldata; | 802 | struct nfs4_opendata *data = calldata; |
803 | struct nfs4_state_owner *sp = data->owner; | 803 | struct nfs4_state_owner *sp = data->owner; |
804 | struct rpc_message msg = { | 804 | |
805 | .rpc_proc = &nfs4_procedures[NFSPROC4_CLNT_OPEN], | ||
806 | .rpc_argp = &data->o_arg, | ||
807 | .rpc_resp = &data->o_res, | ||
808 | .rpc_cred = sp->so_cred, | ||
809 | }; | ||
810 | |||
811 | if (nfs_wait_on_sequence(data->o_arg.seqid, task) != 0) | 805 | if (nfs_wait_on_sequence(data->o_arg.seqid, task) != 0) |
812 | return; | 806 | return; |
813 | /* | 807 | /* |
@@ -832,11 +826,11 @@ static void nfs4_open_prepare(struct rpc_task *task, void *calldata) | |||
832 | data->o_arg.id = sp->so_owner_id.id; | 826 | data->o_arg.id = sp->so_owner_id.id; |
833 | data->o_arg.clientid = sp->so_client->cl_clientid; | 827 | data->o_arg.clientid = sp->so_client->cl_clientid; |
834 | if (data->o_arg.claim == NFS4_OPEN_CLAIM_PREVIOUS) { | 828 | if (data->o_arg.claim == NFS4_OPEN_CLAIM_PREVIOUS) { |
835 | msg.rpc_proc = &nfs4_procedures[NFSPROC4_CLNT_OPEN_NOATTR]; | 829 | task->tk_msg.rpc_proc = &nfs4_procedures[NFSPROC4_CLNT_OPEN_NOATTR]; |
836 | nfs_copy_fh(&data->o_res.fh, data->o_arg.fh); | 830 | nfs_copy_fh(&data->o_res.fh, data->o_arg.fh); |
837 | } | 831 | } |
838 | data->timestamp = jiffies; | 832 | data->timestamp = jiffies; |
839 | rpc_call_setup(task, &msg, 0); | 833 | rpc_call_start(task); |
840 | return; | 834 | return; |
841 | out_no_action: | 835 | out_no_action: |
842 | task->tk_action = NULL; | 836 | task->tk_action = NULL; |
@@ -908,13 +902,26 @@ static int _nfs4_proc_open(struct nfs4_opendata *data) | |||
908 | struct nfs_openargs *o_arg = &data->o_arg; | 902 | struct nfs_openargs *o_arg = &data->o_arg; |
909 | struct nfs_openres *o_res = &data->o_res; | 903 | struct nfs_openres *o_res = &data->o_res; |
910 | struct rpc_task *task; | 904 | struct rpc_task *task; |
905 | struct rpc_message msg = { | ||
906 | .rpc_proc = &nfs4_procedures[NFSPROC4_CLNT_OPEN], | ||
907 | .rpc_argp = o_arg, | ||
908 | .rpc_resp = o_res, | ||
909 | .rpc_cred = data->owner->so_cred, | ||
910 | }; | ||
911 | struct rpc_task_setup task_setup_data = { | ||
912 | .rpc_client = server->client, | ||
913 | .rpc_message = &msg, | ||
914 | .callback_ops = &nfs4_open_ops, | ||
915 | .callback_data = data, | ||
916 | .flags = RPC_TASK_ASYNC, | ||
917 | }; | ||
911 | int status; | 918 | int status; |
912 | 919 | ||
913 | kref_get(&data->kref); | 920 | kref_get(&data->kref); |
914 | data->rpc_done = 0; | 921 | data->rpc_done = 0; |
915 | data->rpc_status = 0; | 922 | data->rpc_status = 0; |
916 | data->cancelled = 0; | 923 | data->cancelled = 0; |
917 | task = rpc_run_task(server->client, RPC_TASK_ASYNC, &nfs4_open_ops, data); | 924 | task = rpc_run_task(&task_setup_data); |
918 | if (IS_ERR(task)) | 925 | if (IS_ERR(task)) |
919 | return PTR_ERR(task); | 926 | return PTR_ERR(task); |
920 | status = nfs4_wait_for_completion_rpc_task(task); | 927 | status = nfs4_wait_for_completion_rpc_task(task); |
@@ -1244,12 +1251,6 @@ static void nfs4_close_prepare(struct rpc_task *task, void *data) | |||
1244 | { | 1251 | { |
1245 | struct nfs4_closedata *calldata = data; | 1252 | struct nfs4_closedata *calldata = data; |
1246 | struct nfs4_state *state = calldata->state; | 1253 | struct nfs4_state *state = calldata->state; |
1247 | struct rpc_message msg = { | ||
1248 | .rpc_proc = &nfs4_procedures[NFSPROC4_CLNT_CLOSE], | ||
1249 | .rpc_argp = &calldata->arg, | ||
1250 | .rpc_resp = &calldata->res, | ||
1251 | .rpc_cred = state->owner->so_cred, | ||
1252 | }; | ||
1253 | int clear_rd, clear_wr, clear_rdwr; | 1254 | int clear_rd, clear_wr, clear_rdwr; |
1254 | 1255 | ||
1255 | if (nfs_wait_on_sequence(calldata->arg.seqid, task) != 0) | 1256 | if (nfs_wait_on_sequence(calldata->arg.seqid, task) != 0) |
@@ -1276,14 +1277,14 @@ static void nfs4_close_prepare(struct rpc_task *task, void *data) | |||
1276 | } | 1277 | } |
1277 | nfs_fattr_init(calldata->res.fattr); | 1278 | nfs_fattr_init(calldata->res.fattr); |
1278 | if (test_bit(NFS_O_RDONLY_STATE, &state->flags) != 0) { | 1279 | if (test_bit(NFS_O_RDONLY_STATE, &state->flags) != 0) { |
1279 | msg.rpc_proc = &nfs4_procedures[NFSPROC4_CLNT_OPEN_DOWNGRADE]; | 1280 | task->tk_msg.rpc_proc = &nfs4_procedures[NFSPROC4_CLNT_OPEN_DOWNGRADE]; |
1280 | calldata->arg.open_flags = FMODE_READ; | 1281 | calldata->arg.open_flags = FMODE_READ; |
1281 | } else if (test_bit(NFS_O_WRONLY_STATE, &state->flags) != 0) { | 1282 | } else if (test_bit(NFS_O_WRONLY_STATE, &state->flags) != 0) { |
1282 | msg.rpc_proc = &nfs4_procedures[NFSPROC4_CLNT_OPEN_DOWNGRADE]; | 1283 | task->tk_msg.rpc_proc = &nfs4_procedures[NFSPROC4_CLNT_OPEN_DOWNGRADE]; |
1283 | calldata->arg.open_flags = FMODE_WRITE; | 1284 | calldata->arg.open_flags = FMODE_WRITE; |
1284 | } | 1285 | } |
1285 | calldata->timestamp = jiffies; | 1286 | calldata->timestamp = jiffies; |
1286 | rpc_call_setup(task, &msg, 0); | 1287 | rpc_call_start(task); |
1287 | } | 1288 | } |
1288 | 1289 | ||
1289 | static const struct rpc_call_ops nfs4_close_ops = { | 1290 | static const struct rpc_call_ops nfs4_close_ops = { |
@@ -1309,6 +1310,16 @@ int nfs4_do_close(struct path *path, struct nfs4_state *state, int wait) | |||
1309 | struct nfs4_closedata *calldata; | 1310 | struct nfs4_closedata *calldata; |
1310 | struct nfs4_state_owner *sp = state->owner; | 1311 | struct nfs4_state_owner *sp = state->owner; |
1311 | struct rpc_task *task; | 1312 | struct rpc_task *task; |
1313 | struct rpc_message msg = { | ||
1314 | .rpc_proc = &nfs4_procedures[NFSPROC4_CLNT_CLOSE], | ||
1315 | .rpc_cred = state->owner->so_cred, | ||
1316 | }; | ||
1317 | struct rpc_task_setup task_setup_data = { | ||
1318 | .rpc_client = server->client, | ||
1319 | .rpc_message = &msg, | ||
1320 | .callback_ops = &nfs4_close_ops, | ||
1321 | .flags = RPC_TASK_ASYNC, | ||
1322 | }; | ||
1312 | int status = -ENOMEM; | 1323 | int status = -ENOMEM; |
1313 | 1324 | ||
1314 | calldata = kmalloc(sizeof(*calldata), GFP_KERNEL); | 1325 | calldata = kmalloc(sizeof(*calldata), GFP_KERNEL); |
@@ -1328,7 +1339,10 @@ int nfs4_do_close(struct path *path, struct nfs4_state *state, int wait) | |||
1328 | calldata->path.mnt = mntget(path->mnt); | 1339 | calldata->path.mnt = mntget(path->mnt); |
1329 | calldata->path.dentry = dget(path->dentry); | 1340 | calldata->path.dentry = dget(path->dentry); |
1330 | 1341 | ||
1331 | task = rpc_run_task(server->client, RPC_TASK_ASYNC, &nfs4_close_ops, calldata); | 1342 | msg.rpc_argp = &calldata->arg, |
1343 | msg.rpc_resp = &calldata->res, | ||
1344 | task_setup_data.callback_data = calldata; | ||
1345 | task = rpc_run_task(&task_setup_data); | ||
1332 | if (IS_ERR(task)) | 1346 | if (IS_ERR(task)) |
1333 | return PTR_ERR(task); | 1347 | return PTR_ERR(task); |
1334 | status = 0; | 1348 | status = 0; |
@@ -2414,18 +2428,10 @@ static int nfs4_read_done(struct rpc_task *task, struct nfs_read_data *data) | |||
2414 | return 0; | 2428 | return 0; |
2415 | } | 2429 | } |
2416 | 2430 | ||
2417 | static void nfs4_proc_read_setup(struct nfs_read_data *data) | 2431 | static void nfs4_proc_read_setup(struct nfs_read_data *data, struct rpc_message *msg) |
2418 | { | 2432 | { |
2419 | struct rpc_message msg = { | ||
2420 | .rpc_proc = &nfs4_procedures[NFSPROC4_CLNT_READ], | ||
2421 | .rpc_argp = &data->args, | ||
2422 | .rpc_resp = &data->res, | ||
2423 | .rpc_cred = data->cred, | ||
2424 | }; | ||
2425 | |||
2426 | data->timestamp = jiffies; | 2433 | data->timestamp = jiffies; |
2427 | 2434 | msg->rpc_proc = &nfs4_procedures[NFSPROC4_CLNT_READ]; | |
2428 | rpc_call_setup(&data->task, &msg, 0); | ||
2429 | } | 2435 | } |
2430 | 2436 | ||
2431 | static int nfs4_write_done(struct rpc_task *task, struct nfs_write_data *data) | 2437 | static int nfs4_write_done(struct rpc_task *task, struct nfs_write_data *data) |
@@ -2443,33 +2449,15 @@ static int nfs4_write_done(struct rpc_task *task, struct nfs_write_data *data) | |||
2443 | return 0; | 2449 | return 0; |
2444 | } | 2450 | } |
2445 | 2451 | ||
2446 | static void nfs4_proc_write_setup(struct nfs_write_data *data, int how) | 2452 | static void nfs4_proc_write_setup(struct nfs_write_data *data, struct rpc_message *msg) |
2447 | { | 2453 | { |
2448 | struct rpc_message msg = { | 2454 | struct nfs_server *server = NFS_SERVER(data->inode); |
2449 | .rpc_proc = &nfs4_procedures[NFSPROC4_CLNT_WRITE], | 2455 | |
2450 | .rpc_argp = &data->args, | ||
2451 | .rpc_resp = &data->res, | ||
2452 | .rpc_cred = data->cred, | ||
2453 | }; | ||
2454 | struct inode *inode = data->inode; | ||
2455 | struct nfs_server *server = NFS_SERVER(inode); | ||
2456 | int stable; | ||
2457 | |||
2458 | if (how & FLUSH_STABLE) { | ||
2459 | if (!NFS_I(inode)->ncommit) | ||
2460 | stable = NFS_FILE_SYNC; | ||
2461 | else | ||
2462 | stable = NFS_DATA_SYNC; | ||
2463 | } else | ||
2464 | stable = NFS_UNSTABLE; | ||
2465 | data->args.stable = stable; | ||
2466 | data->args.bitmask = server->attr_bitmask; | 2456 | data->args.bitmask = server->attr_bitmask; |
2467 | data->res.server = server; | 2457 | data->res.server = server; |
2468 | |||
2469 | data->timestamp = jiffies; | 2458 | data->timestamp = jiffies; |
2470 | 2459 | ||
2471 | /* Finalize the task. */ | 2460 | msg->rpc_proc = &nfs4_procedures[NFSPROC4_CLNT_WRITE]; |
2472 | rpc_call_setup(&data->task, &msg, 0); | ||
2473 | } | 2461 | } |
2474 | 2462 | ||
2475 | static int nfs4_commit_done(struct rpc_task *task, struct nfs_write_data *data) | 2463 | static int nfs4_commit_done(struct rpc_task *task, struct nfs_write_data *data) |
@@ -2484,20 +2472,13 @@ static int nfs4_commit_done(struct rpc_task *task, struct nfs_write_data *data) | |||
2484 | return 0; | 2472 | return 0; |
2485 | } | 2473 | } |
2486 | 2474 | ||
2487 | static void nfs4_proc_commit_setup(struct nfs_write_data *data, int how) | 2475 | static void nfs4_proc_commit_setup(struct nfs_write_data *data, struct rpc_message *msg) |
2488 | { | 2476 | { |
2489 | struct rpc_message msg = { | ||
2490 | .rpc_proc = &nfs4_procedures[NFSPROC4_CLNT_COMMIT], | ||
2491 | .rpc_argp = &data->args, | ||
2492 | .rpc_resp = &data->res, | ||
2493 | .rpc_cred = data->cred, | ||
2494 | }; | ||
2495 | struct nfs_server *server = NFS_SERVER(data->inode); | 2477 | struct nfs_server *server = NFS_SERVER(data->inode); |
2496 | 2478 | ||
2497 | data->args.bitmask = server->attr_bitmask; | 2479 | data->args.bitmask = server->attr_bitmask; |
2498 | data->res.server = server; | 2480 | data->res.server = server; |
2499 | 2481 | msg->rpc_proc = &nfs4_procedures[NFSPROC4_CLNT_COMMIT]; | |
2500 | rpc_call_setup(&data->task, &msg, 0); | ||
2501 | } | 2482 | } |
2502 | 2483 | ||
2503 | /* | 2484 | /* |
@@ -2910,14 +2891,20 @@ int nfs4_proc_setclientid(struct nfs_client *clp, u32 program, unsigned short po | |||
2910 | 2891 | ||
2911 | for(;;) { | 2892 | for(;;) { |
2912 | setclientid.sc_name_len = scnprintf(setclientid.sc_name, | 2893 | setclientid.sc_name_len = scnprintf(setclientid.sc_name, |
2913 | sizeof(setclientid.sc_name), "%s/%u.%u.%u.%u %s %u", | 2894 | sizeof(setclientid.sc_name), "%s/%s %s %s %u", |
2914 | clp->cl_ipaddr, NIPQUAD(clp->cl_addr.sin_addr), | 2895 | clp->cl_ipaddr, |
2896 | rpc_peeraddr2str(clp->cl_rpcclient, | ||
2897 | RPC_DISPLAY_ADDR), | ||
2898 | rpc_peeraddr2str(clp->cl_rpcclient, | ||
2899 | RPC_DISPLAY_PROTO), | ||
2915 | cred->cr_ops->cr_name, | 2900 | cred->cr_ops->cr_name, |
2916 | clp->cl_id_uniquifier); | 2901 | clp->cl_id_uniquifier); |
2917 | setclientid.sc_netid_len = scnprintf(setclientid.sc_netid, | 2902 | setclientid.sc_netid_len = scnprintf(setclientid.sc_netid, |
2918 | sizeof(setclientid.sc_netid), "tcp"); | 2903 | sizeof(setclientid.sc_netid), |
2904 | rpc_peeraddr2str(clp->cl_rpcclient, | ||
2905 | RPC_DISPLAY_NETID)); | ||
2919 | setclientid.sc_uaddr_len = scnprintf(setclientid.sc_uaddr, | 2906 | setclientid.sc_uaddr_len = scnprintf(setclientid.sc_uaddr, |
2920 | sizeof(setclientid.sc_uaddr), "%s.%d.%d", | 2907 | sizeof(setclientid.sc_uaddr), "%s.%u.%u", |
2921 | clp->cl_ipaddr, port >> 8, port & 255); | 2908 | clp->cl_ipaddr, port >> 8, port & 255); |
2922 | 2909 | ||
2923 | status = rpc_call_sync(clp->cl_rpcclient, &msg, 0); | 2910 | status = rpc_call_sync(clp->cl_rpcclient, &msg, 0); |
@@ -2981,25 +2968,11 @@ struct nfs4_delegreturndata { | |||
2981 | struct nfs4_delegreturnres res; | 2968 | struct nfs4_delegreturnres res; |
2982 | struct nfs_fh fh; | 2969 | struct nfs_fh fh; |
2983 | nfs4_stateid stateid; | 2970 | nfs4_stateid stateid; |
2984 | struct rpc_cred *cred; | ||
2985 | unsigned long timestamp; | 2971 | unsigned long timestamp; |
2986 | struct nfs_fattr fattr; | 2972 | struct nfs_fattr fattr; |
2987 | int rpc_status; | 2973 | int rpc_status; |
2988 | }; | 2974 | }; |
2989 | 2975 | ||
2990 | static void nfs4_delegreturn_prepare(struct rpc_task *task, void *calldata) | ||
2991 | { | ||
2992 | struct nfs4_delegreturndata *data = calldata; | ||
2993 | struct rpc_message msg = { | ||
2994 | .rpc_proc = &nfs4_procedures[NFSPROC4_CLNT_DELEGRETURN], | ||
2995 | .rpc_argp = &data->args, | ||
2996 | .rpc_resp = &data->res, | ||
2997 | .rpc_cred = data->cred, | ||
2998 | }; | ||
2999 | nfs_fattr_init(data->res.fattr); | ||
3000 | rpc_call_setup(task, &msg, 0); | ||
3001 | } | ||
3002 | |||
3003 | static void nfs4_delegreturn_done(struct rpc_task *task, void *calldata) | 2976 | static void nfs4_delegreturn_done(struct rpc_task *task, void *calldata) |
3004 | { | 2977 | { |
3005 | struct nfs4_delegreturndata *data = calldata; | 2978 | struct nfs4_delegreturndata *data = calldata; |
@@ -3010,24 +2983,30 @@ static void nfs4_delegreturn_done(struct rpc_task *task, void *calldata) | |||
3010 | 2983 | ||
3011 | static void nfs4_delegreturn_release(void *calldata) | 2984 | static void nfs4_delegreturn_release(void *calldata) |
3012 | { | 2985 | { |
3013 | struct nfs4_delegreturndata *data = calldata; | ||
3014 | |||
3015 | put_rpccred(data->cred); | ||
3016 | kfree(calldata); | 2986 | kfree(calldata); |
3017 | } | 2987 | } |
3018 | 2988 | ||
3019 | static const struct rpc_call_ops nfs4_delegreturn_ops = { | 2989 | static const struct rpc_call_ops nfs4_delegreturn_ops = { |
3020 | .rpc_call_prepare = nfs4_delegreturn_prepare, | ||
3021 | .rpc_call_done = nfs4_delegreturn_done, | 2990 | .rpc_call_done = nfs4_delegreturn_done, |
3022 | .rpc_release = nfs4_delegreturn_release, | 2991 | .rpc_release = nfs4_delegreturn_release, |
3023 | }; | 2992 | }; |
3024 | 2993 | ||
3025 | static int _nfs4_proc_delegreturn(struct inode *inode, struct rpc_cred *cred, const nfs4_stateid *stateid) | 2994 | static int _nfs4_proc_delegreturn(struct inode *inode, struct rpc_cred *cred, const nfs4_stateid *stateid, int issync) |
3026 | { | 2995 | { |
3027 | struct nfs4_delegreturndata *data; | 2996 | struct nfs4_delegreturndata *data; |
3028 | struct nfs_server *server = NFS_SERVER(inode); | 2997 | struct nfs_server *server = NFS_SERVER(inode); |
3029 | struct rpc_task *task; | 2998 | struct rpc_task *task; |
3030 | int status; | 2999 | struct rpc_message msg = { |
3000 | .rpc_proc = &nfs4_procedures[NFSPROC4_CLNT_DELEGRETURN], | ||
3001 | .rpc_cred = cred, | ||
3002 | }; | ||
3003 | struct rpc_task_setup task_setup_data = { | ||
3004 | .rpc_client = server->client, | ||
3005 | .rpc_message = &msg, | ||
3006 | .callback_ops = &nfs4_delegreturn_ops, | ||
3007 | .flags = RPC_TASK_ASYNC, | ||
3008 | }; | ||
3009 | int status = 0; | ||
3031 | 3010 | ||
3032 | data = kmalloc(sizeof(*data), GFP_KERNEL); | 3011 | data = kmalloc(sizeof(*data), GFP_KERNEL); |
3033 | if (data == NULL) | 3012 | if (data == NULL) |
@@ -3039,30 +3018,37 @@ static int _nfs4_proc_delegreturn(struct inode *inode, struct rpc_cred *cred, co | |||
3039 | memcpy(&data->stateid, stateid, sizeof(data->stateid)); | 3018 | memcpy(&data->stateid, stateid, sizeof(data->stateid)); |
3040 | data->res.fattr = &data->fattr; | 3019 | data->res.fattr = &data->fattr; |
3041 | data->res.server = server; | 3020 | data->res.server = server; |
3042 | data->cred = get_rpccred(cred); | 3021 | nfs_fattr_init(data->res.fattr); |
3043 | data->timestamp = jiffies; | 3022 | data->timestamp = jiffies; |
3044 | data->rpc_status = 0; | 3023 | data->rpc_status = 0; |
3045 | 3024 | ||
3046 | task = rpc_run_task(NFS_CLIENT(inode), RPC_TASK_ASYNC, &nfs4_delegreturn_ops, data); | 3025 | task_setup_data.callback_data = data; |
3026 | msg.rpc_argp = &data->args, | ||
3027 | msg.rpc_resp = &data->res, | ||
3028 | task = rpc_run_task(&task_setup_data); | ||
3047 | if (IS_ERR(task)) | 3029 | if (IS_ERR(task)) |
3048 | return PTR_ERR(task); | 3030 | return PTR_ERR(task); |
3031 | if (!issync) | ||
3032 | goto out; | ||
3049 | status = nfs4_wait_for_completion_rpc_task(task); | 3033 | status = nfs4_wait_for_completion_rpc_task(task); |
3050 | if (status == 0) { | 3034 | if (status != 0) |
3051 | status = data->rpc_status; | 3035 | goto out; |
3052 | if (status == 0) | 3036 | status = data->rpc_status; |
3053 | nfs_refresh_inode(inode, &data->fattr); | 3037 | if (status != 0) |
3054 | } | 3038 | goto out; |
3039 | nfs_refresh_inode(inode, &data->fattr); | ||
3040 | out: | ||
3055 | rpc_put_task(task); | 3041 | rpc_put_task(task); |
3056 | return status; | 3042 | return status; |
3057 | } | 3043 | } |
3058 | 3044 | ||
3059 | int nfs4_proc_delegreturn(struct inode *inode, struct rpc_cred *cred, const nfs4_stateid *stateid) | 3045 | int nfs4_proc_delegreturn(struct inode *inode, struct rpc_cred *cred, const nfs4_stateid *stateid, int issync) |
3060 | { | 3046 | { |
3061 | struct nfs_server *server = NFS_SERVER(inode); | 3047 | struct nfs_server *server = NFS_SERVER(inode); |
3062 | struct nfs4_exception exception = { }; | 3048 | struct nfs4_exception exception = { }; |
3063 | int err; | 3049 | int err; |
3064 | do { | 3050 | do { |
3065 | err = _nfs4_proc_delegreturn(inode, cred, stateid); | 3051 | err = _nfs4_proc_delegreturn(inode, cred, stateid, issync); |
3066 | switch (err) { | 3052 | switch (err) { |
3067 | case -NFS4ERR_STALE_STATEID: | 3053 | case -NFS4ERR_STALE_STATEID: |
3068 | case -NFS4ERR_EXPIRED: | 3054 | case -NFS4ERR_EXPIRED: |
@@ -3230,12 +3216,6 @@ static void nfs4_locku_done(struct rpc_task *task, void *data) | |||
3230 | static void nfs4_locku_prepare(struct rpc_task *task, void *data) | 3216 | static void nfs4_locku_prepare(struct rpc_task *task, void *data) |
3231 | { | 3217 | { |
3232 | struct nfs4_unlockdata *calldata = data; | 3218 | struct nfs4_unlockdata *calldata = data; |
3233 | struct rpc_message msg = { | ||
3234 | .rpc_proc = &nfs4_procedures[NFSPROC4_CLNT_LOCKU], | ||
3235 | .rpc_argp = &calldata->arg, | ||
3236 | .rpc_resp = &calldata->res, | ||
3237 | .rpc_cred = calldata->lsp->ls_state->owner->so_cred, | ||
3238 | }; | ||
3239 | 3219 | ||
3240 | if (nfs_wait_on_sequence(calldata->arg.seqid, task) != 0) | 3220 | if (nfs_wait_on_sequence(calldata->arg.seqid, task) != 0) |
3241 | return; | 3221 | return; |
@@ -3245,7 +3225,7 @@ static void nfs4_locku_prepare(struct rpc_task *task, void *data) | |||
3245 | return; | 3225 | return; |
3246 | } | 3226 | } |
3247 | calldata->timestamp = jiffies; | 3227 | calldata->timestamp = jiffies; |
3248 | rpc_call_setup(task, &msg, 0); | 3228 | rpc_call_start(task); |
3249 | } | 3229 | } |
3250 | 3230 | ||
3251 | static const struct rpc_call_ops nfs4_locku_ops = { | 3231 | static const struct rpc_call_ops nfs4_locku_ops = { |
@@ -3260,6 +3240,16 @@ static struct rpc_task *nfs4_do_unlck(struct file_lock *fl, | |||
3260 | struct nfs_seqid *seqid) | 3240 | struct nfs_seqid *seqid) |
3261 | { | 3241 | { |
3262 | struct nfs4_unlockdata *data; | 3242 | struct nfs4_unlockdata *data; |
3243 | struct rpc_message msg = { | ||
3244 | .rpc_proc = &nfs4_procedures[NFSPROC4_CLNT_LOCKU], | ||
3245 | .rpc_cred = ctx->cred, | ||
3246 | }; | ||
3247 | struct rpc_task_setup task_setup_data = { | ||
3248 | .rpc_client = NFS_CLIENT(lsp->ls_state->inode), | ||
3249 | .rpc_message = &msg, | ||
3250 | .callback_ops = &nfs4_locku_ops, | ||
3251 | .flags = RPC_TASK_ASYNC, | ||
3252 | }; | ||
3263 | 3253 | ||
3264 | /* Ensure this is an unlock - when canceling a lock, the | 3254 | /* Ensure this is an unlock - when canceling a lock, the |
3265 | * canceled lock is passed in, and it won't be an unlock. | 3255 | * canceled lock is passed in, and it won't be an unlock. |
@@ -3272,7 +3262,10 @@ static struct rpc_task *nfs4_do_unlck(struct file_lock *fl, | |||
3272 | return ERR_PTR(-ENOMEM); | 3262 | return ERR_PTR(-ENOMEM); |
3273 | } | 3263 | } |
3274 | 3264 | ||
3275 | return rpc_run_task(NFS_CLIENT(lsp->ls_state->inode), RPC_TASK_ASYNC, &nfs4_locku_ops, data); | 3265 | msg.rpc_argp = &data->arg, |
3266 | msg.rpc_resp = &data->res, | ||
3267 | task_setup_data.callback_data = data; | ||
3268 | return rpc_run_task(&task_setup_data); | ||
3276 | } | 3269 | } |
3277 | 3270 | ||
3278 | static int nfs4_proc_unlck(struct nfs4_state *state, int cmd, struct file_lock *request) | 3271 | static int nfs4_proc_unlck(struct nfs4_state *state, int cmd, struct file_lock *request) |
@@ -3331,15 +3324,12 @@ static struct nfs4_lockdata *nfs4_alloc_lockdata(struct file_lock *fl, | |||
3331 | 3324 | ||
3332 | p->arg.fh = NFS_FH(inode); | 3325 | p->arg.fh = NFS_FH(inode); |
3333 | p->arg.fl = &p->fl; | 3326 | p->arg.fl = &p->fl; |
3334 | if (!(lsp->ls_seqid.flags & NFS_SEQID_CONFIRMED)) { | 3327 | p->arg.open_seqid = nfs_alloc_seqid(&lsp->ls_state->owner->so_seqid); |
3335 | p->arg.open_seqid = nfs_alloc_seqid(&lsp->ls_state->owner->so_seqid); | 3328 | if (p->arg.open_seqid == NULL) |
3336 | if (p->arg.open_seqid == NULL) | 3329 | goto out_free; |
3337 | goto out_free; | ||
3338 | |||
3339 | } | ||
3340 | p->arg.lock_seqid = nfs_alloc_seqid(&lsp->ls_seqid); | 3330 | p->arg.lock_seqid = nfs_alloc_seqid(&lsp->ls_seqid); |
3341 | if (p->arg.lock_seqid == NULL) | 3331 | if (p->arg.lock_seqid == NULL) |
3342 | goto out_free; | 3332 | goto out_free_seqid; |
3343 | p->arg.lock_stateid = &lsp->ls_stateid; | 3333 | p->arg.lock_stateid = &lsp->ls_stateid; |
3344 | p->arg.lock_owner.clientid = server->nfs_client->cl_clientid; | 3334 | p->arg.lock_owner.clientid = server->nfs_client->cl_clientid; |
3345 | p->arg.lock_owner.id = lsp->ls_id.id; | 3335 | p->arg.lock_owner.id = lsp->ls_id.id; |
@@ -3348,9 +3338,9 @@ static struct nfs4_lockdata *nfs4_alloc_lockdata(struct file_lock *fl, | |||
3348 | p->ctx = get_nfs_open_context(ctx); | 3338 | p->ctx = get_nfs_open_context(ctx); |
3349 | memcpy(&p->fl, fl, sizeof(p->fl)); | 3339 | memcpy(&p->fl, fl, sizeof(p->fl)); |
3350 | return p; | 3340 | return p; |
3341 | out_free_seqid: | ||
3342 | nfs_free_seqid(p->arg.open_seqid); | ||
3351 | out_free: | 3343 | out_free: |
3352 | if (p->arg.open_seqid != NULL) | ||
3353 | nfs_free_seqid(p->arg.open_seqid); | ||
3354 | kfree(p); | 3344 | kfree(p); |
3355 | return NULL; | 3345 | return NULL; |
3356 | } | 3346 | } |
@@ -3359,31 +3349,20 @@ static void nfs4_lock_prepare(struct rpc_task *task, void *calldata) | |||
3359 | { | 3349 | { |
3360 | struct nfs4_lockdata *data = calldata; | 3350 | struct nfs4_lockdata *data = calldata; |
3361 | struct nfs4_state *state = data->lsp->ls_state; | 3351 | struct nfs4_state *state = data->lsp->ls_state; |
3362 | struct nfs4_state_owner *sp = state->owner; | ||
3363 | struct rpc_message msg = { | ||
3364 | .rpc_proc = &nfs4_procedures[NFSPROC4_CLNT_LOCK], | ||
3365 | .rpc_argp = &data->arg, | ||
3366 | .rpc_resp = &data->res, | ||
3367 | .rpc_cred = sp->so_cred, | ||
3368 | }; | ||
3369 | 3352 | ||
3370 | dprintk("%s: begin!\n", __FUNCTION__); | 3353 | dprintk("%s: begin!\n", __FUNCTION__); |
3354 | if (nfs_wait_on_sequence(data->arg.lock_seqid, task) != 0) | ||
3355 | return; | ||
3371 | /* Do we need to do an open_to_lock_owner? */ | 3356 | /* Do we need to do an open_to_lock_owner? */ |
3372 | if (!(data->arg.lock_seqid->sequence->flags & NFS_SEQID_CONFIRMED)) { | 3357 | if (!(data->arg.lock_seqid->sequence->flags & NFS_SEQID_CONFIRMED)) { |
3373 | if (nfs_wait_on_sequence(data->arg.open_seqid, task) != 0) | 3358 | if (nfs_wait_on_sequence(data->arg.open_seqid, task) != 0) |
3374 | return; | 3359 | return; |
3375 | data->arg.open_stateid = &state->stateid; | 3360 | data->arg.open_stateid = &state->stateid; |
3376 | data->arg.new_lock_owner = 1; | 3361 | data->arg.new_lock_owner = 1; |
3377 | /* Retest in case we raced... */ | 3362 | } else |
3378 | if (!(data->arg.lock_seqid->sequence->flags & NFS_SEQID_CONFIRMED)) | 3363 | data->arg.new_lock_owner = 0; |
3379 | goto do_rpc; | ||
3380 | } | ||
3381 | if (nfs_wait_on_sequence(data->arg.lock_seqid, task) != 0) | ||
3382 | return; | ||
3383 | data->arg.new_lock_owner = 0; | ||
3384 | do_rpc: | ||
3385 | data->timestamp = jiffies; | 3364 | data->timestamp = jiffies; |
3386 | rpc_call_setup(task, &msg, 0); | 3365 | rpc_call_start(task); |
3387 | dprintk("%s: done!, ret = %d\n", __FUNCTION__, data->rpc_status); | 3366 | dprintk("%s: done!, ret = %d\n", __FUNCTION__, data->rpc_status); |
3388 | } | 3367 | } |
3389 | 3368 | ||
@@ -3419,6 +3398,7 @@ static void nfs4_lock_release(void *calldata) | |||
3419 | struct nfs4_lockdata *data = calldata; | 3398 | struct nfs4_lockdata *data = calldata; |
3420 | 3399 | ||
3421 | dprintk("%s: begin!\n", __FUNCTION__); | 3400 | dprintk("%s: begin!\n", __FUNCTION__); |
3401 | nfs_free_seqid(data->arg.open_seqid); | ||
3422 | if (data->cancelled != 0) { | 3402 | if (data->cancelled != 0) { |
3423 | struct rpc_task *task; | 3403 | struct rpc_task *task; |
3424 | task = nfs4_do_unlck(&data->fl, data->ctx, data->lsp, | 3404 | task = nfs4_do_unlck(&data->fl, data->ctx, data->lsp, |
@@ -3428,8 +3408,6 @@ static void nfs4_lock_release(void *calldata) | |||
3428 | dprintk("%s: cancelling lock!\n", __FUNCTION__); | 3408 | dprintk("%s: cancelling lock!\n", __FUNCTION__); |
3429 | } else | 3409 | } else |
3430 | nfs_free_seqid(data->arg.lock_seqid); | 3410 | nfs_free_seqid(data->arg.lock_seqid); |
3431 | if (data->arg.open_seqid != NULL) | ||
3432 | nfs_free_seqid(data->arg.open_seqid); | ||
3433 | nfs4_put_lock_state(data->lsp); | 3411 | nfs4_put_lock_state(data->lsp); |
3434 | put_nfs_open_context(data->ctx); | 3412 | put_nfs_open_context(data->ctx); |
3435 | kfree(data); | 3413 | kfree(data); |
@@ -3446,6 +3424,16 @@ static int _nfs4_do_setlk(struct nfs4_state *state, int cmd, struct file_lock *f | |||
3446 | { | 3424 | { |
3447 | struct nfs4_lockdata *data; | 3425 | struct nfs4_lockdata *data; |
3448 | struct rpc_task *task; | 3426 | struct rpc_task *task; |
3427 | struct rpc_message msg = { | ||
3428 | .rpc_proc = &nfs4_procedures[NFSPROC4_CLNT_LOCK], | ||
3429 | .rpc_cred = state->owner->so_cred, | ||
3430 | }; | ||
3431 | struct rpc_task_setup task_setup_data = { | ||
3432 | .rpc_client = NFS_CLIENT(state->inode), | ||
3433 | .rpc_message = &msg, | ||
3434 | .callback_ops = &nfs4_lock_ops, | ||
3435 | .flags = RPC_TASK_ASYNC, | ||
3436 | }; | ||
3449 | int ret; | 3437 | int ret; |
3450 | 3438 | ||
3451 | dprintk("%s: begin!\n", __FUNCTION__); | 3439 | dprintk("%s: begin!\n", __FUNCTION__); |
@@ -3457,8 +3445,10 @@ static int _nfs4_do_setlk(struct nfs4_state *state, int cmd, struct file_lock *f | |||
3457 | data->arg.block = 1; | 3445 | data->arg.block = 1; |
3458 | if (reclaim != 0) | 3446 | if (reclaim != 0) |
3459 | data->arg.reclaim = 1; | 3447 | data->arg.reclaim = 1; |
3460 | task = rpc_run_task(NFS_CLIENT(state->inode), RPC_TASK_ASYNC, | 3448 | msg.rpc_argp = &data->arg, |
3461 | &nfs4_lock_ops, data); | 3449 | msg.rpc_resp = &data->res, |
3450 | task_setup_data.callback_data = data; | ||
3451 | task = rpc_run_task(&task_setup_data); | ||
3462 | if (IS_ERR(task)) | 3452 | if (IS_ERR(task)) |
3463 | return PTR_ERR(task); | 3453 | return PTR_ERR(task); |
3464 | ret = nfs4_wait_for_completion_rpc_task(task); | 3454 | ret = nfs4_wait_for_completion_rpc_task(task); |
@@ -3631,10 +3621,6 @@ int nfs4_setxattr(struct dentry *dentry, const char *key, const void *buf, | |||
3631 | if (strcmp(key, XATTR_NAME_NFSV4_ACL) != 0) | 3621 | if (strcmp(key, XATTR_NAME_NFSV4_ACL) != 0) |
3632 | return -EOPNOTSUPP; | 3622 | return -EOPNOTSUPP; |
3633 | 3623 | ||
3634 | if (!S_ISREG(inode->i_mode) && | ||
3635 | (!S_ISDIR(inode->i_mode) || inode->i_mode & S_ISVTX)) | ||
3636 | return -EPERM; | ||
3637 | |||
3638 | return nfs4_proc_set_acl(inode, buf, buflen); | 3624 | return nfs4_proc_set_acl(inode, buf, buflen); |
3639 | } | 3625 | } |
3640 | 3626 | ||
diff --git a/fs/nfs/nfs4state.c b/fs/nfs/nfs4state.c index 5a39c6f78acf..f9c7432471dc 100644 --- a/fs/nfs/nfs4state.c +++ b/fs/nfs/nfs4state.c | |||
@@ -644,27 +644,26 @@ void nfs4_copy_stateid(nfs4_stateid *dst, struct nfs4_state *state, fl_owner_t f | |||
644 | 644 | ||
645 | struct nfs_seqid *nfs_alloc_seqid(struct nfs_seqid_counter *counter) | 645 | struct nfs_seqid *nfs_alloc_seqid(struct nfs_seqid_counter *counter) |
646 | { | 646 | { |
647 | struct rpc_sequence *sequence = counter->sequence; | ||
648 | struct nfs_seqid *new; | 647 | struct nfs_seqid *new; |
649 | 648 | ||
650 | new = kmalloc(sizeof(*new), GFP_KERNEL); | 649 | new = kmalloc(sizeof(*new), GFP_KERNEL); |
651 | if (new != NULL) { | 650 | if (new != NULL) { |
652 | new->sequence = counter; | 651 | new->sequence = counter; |
653 | spin_lock(&sequence->lock); | 652 | INIT_LIST_HEAD(&new->list); |
654 | list_add_tail(&new->list, &sequence->list); | ||
655 | spin_unlock(&sequence->lock); | ||
656 | } | 653 | } |
657 | return new; | 654 | return new; |
658 | } | 655 | } |
659 | 656 | ||
660 | void nfs_free_seqid(struct nfs_seqid *seqid) | 657 | void nfs_free_seqid(struct nfs_seqid *seqid) |
661 | { | 658 | { |
662 | struct rpc_sequence *sequence = seqid->sequence->sequence; | 659 | if (!list_empty(&seqid->list)) { |
660 | struct rpc_sequence *sequence = seqid->sequence->sequence; | ||
663 | 661 | ||
664 | spin_lock(&sequence->lock); | 662 | spin_lock(&sequence->lock); |
665 | list_del(&seqid->list); | 663 | list_del(&seqid->list); |
666 | spin_unlock(&sequence->lock); | 664 | spin_unlock(&sequence->lock); |
667 | rpc_wake_up(&sequence->wait); | 665 | rpc_wake_up(&sequence->wait); |
666 | } | ||
668 | kfree(seqid); | 667 | kfree(seqid); |
669 | } | 668 | } |
670 | 669 | ||
@@ -675,6 +674,7 @@ void nfs_free_seqid(struct nfs_seqid *seqid) | |||
675 | */ | 674 | */ |
676 | static void nfs_increment_seqid(int status, struct nfs_seqid *seqid) | 675 | static void nfs_increment_seqid(int status, struct nfs_seqid *seqid) |
677 | { | 676 | { |
677 | BUG_ON(list_first_entry(&seqid->sequence->sequence->list, struct nfs_seqid, list) != seqid); | ||
678 | switch (status) { | 678 | switch (status) { |
679 | case 0: | 679 | case 0: |
680 | break; | 680 | break; |
@@ -726,15 +726,15 @@ int nfs_wait_on_sequence(struct nfs_seqid *seqid, struct rpc_task *task) | |||
726 | struct rpc_sequence *sequence = seqid->sequence->sequence; | 726 | struct rpc_sequence *sequence = seqid->sequence->sequence; |
727 | int status = 0; | 727 | int status = 0; |
728 | 728 | ||
729 | if (sequence->list.next == &seqid->list) | ||
730 | goto out; | ||
731 | spin_lock(&sequence->lock); | 729 | spin_lock(&sequence->lock); |
732 | if (sequence->list.next != &seqid->list) { | 730 | if (list_empty(&seqid->list)) |
733 | rpc_sleep_on(&sequence->wait, task, NULL, NULL); | 731 | list_add_tail(&seqid->list, &sequence->list); |
734 | status = -EAGAIN; | 732 | if (list_first_entry(&sequence->list, struct nfs_seqid, list) == seqid) |
735 | } | 733 | goto unlock; |
734 | rpc_sleep_on(&sequence->wait, task, NULL, NULL); | ||
735 | status = -EAGAIN; | ||
736 | unlock: | ||
736 | spin_unlock(&sequence->lock); | 737 | spin_unlock(&sequence->lock); |
737 | out: | ||
738 | return status; | 738 | return status; |
739 | } | 739 | } |
740 | 740 | ||
@@ -758,8 +758,9 @@ static void nfs4_recover_state(struct nfs_client *clp) | |||
758 | 758 | ||
759 | __module_get(THIS_MODULE); | 759 | __module_get(THIS_MODULE); |
760 | atomic_inc(&clp->cl_count); | 760 | atomic_inc(&clp->cl_count); |
761 | task = kthread_run(reclaimer, clp, "%u.%u.%u.%u-reclaim", | 761 | task = kthread_run(reclaimer, clp, "%s-reclaim", |
762 | NIPQUAD(clp->cl_addr.sin_addr)); | 762 | rpc_peeraddr2str(clp->cl_rpcclient, |
763 | RPC_DISPLAY_ADDR)); | ||
763 | if (!IS_ERR(task)) | 764 | if (!IS_ERR(task)) |
764 | return; | 765 | return; |
765 | nfs4_clear_recover_bit(clp); | 766 | nfs4_clear_recover_bit(clp); |
@@ -970,8 +971,8 @@ out: | |||
970 | module_put_and_exit(0); | 971 | module_put_and_exit(0); |
971 | return 0; | 972 | return 0; |
972 | out_error: | 973 | out_error: |
973 | printk(KERN_WARNING "Error: state recovery failed on NFSv4 server %u.%u.%u.%u with error %d\n", | 974 | printk(KERN_WARNING "Error: state recovery failed on NFSv4 server %s" |
974 | NIPQUAD(clp->cl_addr.sin_addr), -status); | 975 | " with error %d\n", clp->cl_hostname, -status); |
975 | set_bit(NFS4CLNT_LEASE_EXPIRED, &clp->cl_state); | 976 | set_bit(NFS4CLNT_LEASE_EXPIRED, &clp->cl_state); |
976 | goto out; | 977 | goto out; |
977 | } | 978 | } |
diff --git a/fs/nfs/nfs4xdr.c b/fs/nfs/nfs4xdr.c index 51dd3804866f..db1ed9c46ede 100644 --- a/fs/nfs/nfs4xdr.c +++ b/fs/nfs/nfs4xdr.c | |||
@@ -116,10 +116,12 @@ static int nfs4_stat_to_errno(int); | |||
116 | #define decode_renew_maxsz (op_decode_hdr_maxsz) | 116 | #define decode_renew_maxsz (op_decode_hdr_maxsz) |
117 | #define encode_setclientid_maxsz \ | 117 | #define encode_setclientid_maxsz \ |
118 | (op_encode_hdr_maxsz + \ | 118 | (op_encode_hdr_maxsz + \ |
119 | 4 /*server->ip_addr*/ + \ | 119 | XDR_QUADLEN(NFS4_VERIFIER_SIZE) + \ |
120 | 1 /*Netid*/ + \ | 120 | XDR_QUADLEN(NFS4_SETCLIENTID_NAMELEN) + \ |
121 | 6 /*uaddr*/ + \ | 121 | 1 /* sc_prog */ + \ |
122 | 6 + (NFS4_VERIFIER_SIZE >> 2)) | 122 | XDR_QUADLEN(RPCBIND_MAXNETIDLEN) + \ |
123 | XDR_QUADLEN(RPCBIND_MAXUADDRLEN) + \ | ||
124 | 1) /* sc_cb_ident */ | ||
123 | #define decode_setclientid_maxsz \ | 125 | #define decode_setclientid_maxsz \ |
124 | (op_decode_hdr_maxsz + \ | 126 | (op_decode_hdr_maxsz + \ |
125 | 2 + \ | 127 | 2 + \ |
@@ -2515,14 +2517,12 @@ static int decode_attr_files_total(struct xdr_stream *xdr, uint32_t *bitmap, uin | |||
2515 | 2517 | ||
2516 | static int decode_pathname(struct xdr_stream *xdr, struct nfs4_pathname *path) | 2518 | static int decode_pathname(struct xdr_stream *xdr, struct nfs4_pathname *path) |
2517 | { | 2519 | { |
2518 | int n; | 2520 | u32 n; |
2519 | __be32 *p; | 2521 | __be32 *p; |
2520 | int status = 0; | 2522 | int status = 0; |
2521 | 2523 | ||
2522 | READ_BUF(4); | 2524 | READ_BUF(4); |
2523 | READ32(n); | 2525 | READ32(n); |
2524 | if (n < 0) | ||
2525 | goto out_eio; | ||
2526 | if (n == 0) | 2526 | if (n == 0) |
2527 | goto root_path; | 2527 | goto root_path; |
2528 | dprintk("path "); | 2528 | dprintk("path "); |
@@ -2579,13 +2579,11 @@ static int decode_attr_fs_locations(struct xdr_stream *xdr, uint32_t *bitmap, st | |||
2579 | goto out_eio; | 2579 | goto out_eio; |
2580 | res->nlocations = 0; | 2580 | res->nlocations = 0; |
2581 | while (res->nlocations < n) { | 2581 | while (res->nlocations < n) { |
2582 | int m; | 2582 | u32 m; |
2583 | struct nfs4_fs_location *loc = &res->locations[res->nlocations]; | 2583 | struct nfs4_fs_location *loc = &res->locations[res->nlocations]; |
2584 | 2584 | ||
2585 | READ_BUF(4); | 2585 | READ_BUF(4); |
2586 | READ32(m); | 2586 | READ32(m); |
2587 | if (m <= 0) | ||
2588 | goto out_eio; | ||
2589 | 2587 | ||
2590 | loc->nservers = 0; | 2588 | loc->nservers = 0; |
2591 | dprintk("%s: servers ", __FUNCTION__); | 2589 | dprintk("%s: servers ", __FUNCTION__); |
@@ -2598,8 +2596,12 @@ static int decode_attr_fs_locations(struct xdr_stream *xdr, uint32_t *bitmap, st | |||
2598 | if (loc->nservers < NFS4_FS_LOCATION_MAXSERVERS) | 2596 | if (loc->nservers < NFS4_FS_LOCATION_MAXSERVERS) |
2599 | loc->nservers++; | 2597 | loc->nservers++; |
2600 | else { | 2598 | else { |
2601 | int i; | 2599 | unsigned int i; |
2602 | dprintk("%s: using first %d of %d servers returned for location %d\n", __FUNCTION__, NFS4_FS_LOCATION_MAXSERVERS, m, res->nlocations); | 2600 | dprintk("%s: using first %u of %u servers " |
2601 | "returned for location %u\n", | ||
2602 | __FUNCTION__, | ||
2603 | NFS4_FS_LOCATION_MAXSERVERS, | ||
2604 | m, res->nlocations); | ||
2603 | for (i = loc->nservers; i < m; i++) { | 2605 | for (i = loc->nservers; i < m; i++) { |
2604 | unsigned int len; | 2606 | unsigned int len; |
2605 | char *data; | 2607 | char *data; |
@@ -3476,10 +3478,11 @@ static int decode_readdir(struct xdr_stream *xdr, struct rpc_rqst *req, struct n | |||
3476 | struct xdr_buf *rcvbuf = &req->rq_rcv_buf; | 3478 | struct xdr_buf *rcvbuf = &req->rq_rcv_buf; |
3477 | struct page *page = *rcvbuf->pages; | 3479 | struct page *page = *rcvbuf->pages; |
3478 | struct kvec *iov = rcvbuf->head; | 3480 | struct kvec *iov = rcvbuf->head; |
3479 | unsigned int nr, pglen = rcvbuf->page_len; | 3481 | size_t hdrlen; |
3482 | u32 recvd, pglen = rcvbuf->page_len; | ||
3480 | __be32 *end, *entry, *p, *kaddr; | 3483 | __be32 *end, *entry, *p, *kaddr; |
3481 | uint32_t len, attrlen, xlen; | 3484 | unsigned int nr; |
3482 | int hdrlen, recvd, status; | 3485 | int status; |
3483 | 3486 | ||
3484 | status = decode_op_hdr(xdr, OP_READDIR); | 3487 | status = decode_op_hdr(xdr, OP_READDIR); |
3485 | if (status) | 3488 | if (status) |
@@ -3503,6 +3506,7 @@ static int decode_readdir(struct xdr_stream *xdr, struct rpc_rqst *req, struct n | |||
3503 | end = p + ((pglen + readdir->pgbase) >> 2); | 3506 | end = p + ((pglen + readdir->pgbase) >> 2); |
3504 | entry = p; | 3507 | entry = p; |
3505 | for (nr = 0; *p++; nr++) { | 3508 | for (nr = 0; *p++; nr++) { |
3509 | u32 len, attrlen, xlen; | ||
3506 | if (end - p < 3) | 3510 | if (end - p < 3) |
3507 | goto short_pkt; | 3511 | goto short_pkt; |
3508 | dprintk("cookie = %Lu, ", *((unsigned long long *)p)); | 3512 | dprintk("cookie = %Lu, ", *((unsigned long long *)p)); |
@@ -3551,7 +3555,8 @@ static int decode_readlink(struct xdr_stream *xdr, struct rpc_rqst *req) | |||
3551 | { | 3555 | { |
3552 | struct xdr_buf *rcvbuf = &req->rq_rcv_buf; | 3556 | struct xdr_buf *rcvbuf = &req->rq_rcv_buf; |
3553 | struct kvec *iov = rcvbuf->head; | 3557 | struct kvec *iov = rcvbuf->head; |
3554 | int hdrlen, len, recvd; | 3558 | size_t hdrlen; |
3559 | u32 len, recvd; | ||
3555 | __be32 *p; | 3560 | __be32 *p; |
3556 | char *kaddr; | 3561 | char *kaddr; |
3557 | int status; | 3562 | int status; |
@@ -3646,7 +3651,8 @@ static int decode_getacl(struct xdr_stream *xdr, struct rpc_rqst *req, | |||
3646 | if (unlikely(bitmap[0] & (FATTR4_WORD0_ACL - 1U))) | 3651 | if (unlikely(bitmap[0] & (FATTR4_WORD0_ACL - 1U))) |
3647 | return -EIO; | 3652 | return -EIO; |
3648 | if (likely(bitmap[0] & FATTR4_WORD0_ACL)) { | 3653 | if (likely(bitmap[0] & FATTR4_WORD0_ACL)) { |
3649 | int hdrlen, recvd; | 3654 | size_t hdrlen; |
3655 | u32 recvd; | ||
3650 | 3656 | ||
3651 | /* We ignore &savep and don't do consistency checks on | 3657 | /* We ignore &savep and don't do consistency checks on |
3652 | * the attr length. Let userspace figure it out.... */ | 3658 | * the attr length. Let userspace figure it out.... */ |
diff --git a/fs/nfs/pagelist.c b/fs/nfs/pagelist.c index 345bb9b4765b..3b3dbb94393d 100644 --- a/fs/nfs/pagelist.c +++ b/fs/nfs/pagelist.c | |||
@@ -111,13 +111,14 @@ void nfs_unlock_request(struct nfs_page *req) | |||
111 | * nfs_set_page_tag_locked - Tag a request as locked | 111 | * nfs_set_page_tag_locked - Tag a request as locked |
112 | * @req: | 112 | * @req: |
113 | */ | 113 | */ |
114 | static int nfs_set_page_tag_locked(struct nfs_page *req) | 114 | int nfs_set_page_tag_locked(struct nfs_page *req) |
115 | { | 115 | { |
116 | struct nfs_inode *nfsi = NFS_I(req->wb_context->path.dentry->d_inode); | 116 | struct nfs_inode *nfsi = NFS_I(req->wb_context->path.dentry->d_inode); |
117 | 117 | ||
118 | if (!nfs_lock_request(req)) | 118 | if (!nfs_lock_request_dontget(req)) |
119 | return 0; | 119 | return 0; |
120 | radix_tree_tag_set(&nfsi->nfs_page_tree, req->wb_index, NFS_PAGE_TAG_LOCKED); | 120 | if (req->wb_page != NULL) |
121 | radix_tree_tag_set(&nfsi->nfs_page_tree, req->wb_index, NFS_PAGE_TAG_LOCKED); | ||
121 | return 1; | 122 | return 1; |
122 | } | 123 | } |
123 | 124 | ||
@@ -132,9 +133,10 @@ void nfs_clear_page_tag_locked(struct nfs_page *req) | |||
132 | if (req->wb_page != NULL) { | 133 | if (req->wb_page != NULL) { |
133 | spin_lock(&inode->i_lock); | 134 | spin_lock(&inode->i_lock); |
134 | radix_tree_tag_clear(&nfsi->nfs_page_tree, req->wb_index, NFS_PAGE_TAG_LOCKED); | 135 | radix_tree_tag_clear(&nfsi->nfs_page_tree, req->wb_index, NFS_PAGE_TAG_LOCKED); |
136 | nfs_unlock_request(req); | ||
135 | spin_unlock(&inode->i_lock); | 137 | spin_unlock(&inode->i_lock); |
136 | } | 138 | } else |
137 | nfs_unlock_request(req); | 139 | nfs_unlock_request(req); |
138 | } | 140 | } |
139 | 141 | ||
140 | /** | 142 | /** |
@@ -421,6 +423,7 @@ int nfs_scan_list(struct nfs_inode *nfsi, | |||
421 | goto out; | 423 | goto out; |
422 | idx_start = req->wb_index + 1; | 424 | idx_start = req->wb_index + 1; |
423 | if (nfs_set_page_tag_locked(req)) { | 425 | if (nfs_set_page_tag_locked(req)) { |
426 | kref_get(&req->wb_kref); | ||
424 | nfs_list_remove_request(req); | 427 | nfs_list_remove_request(req); |
425 | radix_tree_tag_clear(&nfsi->nfs_page_tree, | 428 | radix_tree_tag_clear(&nfsi->nfs_page_tree, |
426 | req->wb_index, tag); | 429 | req->wb_index, tag); |
diff --git a/fs/nfs/proc.c b/fs/nfs/proc.c index 4f80d88e9fee..5ccf7faee19c 100644 --- a/fs/nfs/proc.c +++ b/fs/nfs/proc.c | |||
@@ -565,16 +565,9 @@ static int nfs_read_done(struct rpc_task *task, struct nfs_read_data *data) | |||
565 | return 0; | 565 | return 0; |
566 | } | 566 | } |
567 | 567 | ||
568 | static void nfs_proc_read_setup(struct nfs_read_data *data) | 568 | static void nfs_proc_read_setup(struct nfs_read_data *data, struct rpc_message *msg) |
569 | { | 569 | { |
570 | struct rpc_message msg = { | 570 | msg->rpc_proc = &nfs_procedures[NFSPROC_READ]; |
571 | .rpc_proc = &nfs_procedures[NFSPROC_READ], | ||
572 | .rpc_argp = &data->args, | ||
573 | .rpc_resp = &data->res, | ||
574 | .rpc_cred = data->cred, | ||
575 | }; | ||
576 | |||
577 | rpc_call_setup(&data->task, &msg, 0); | ||
578 | } | 571 | } |
579 | 572 | ||
580 | static int nfs_write_done(struct rpc_task *task, struct nfs_write_data *data) | 573 | static int nfs_write_done(struct rpc_task *task, struct nfs_write_data *data) |
@@ -584,24 +577,15 @@ static int nfs_write_done(struct rpc_task *task, struct nfs_write_data *data) | |||
584 | return 0; | 577 | return 0; |
585 | } | 578 | } |
586 | 579 | ||
587 | static void nfs_proc_write_setup(struct nfs_write_data *data, int how) | 580 | static void nfs_proc_write_setup(struct nfs_write_data *data, struct rpc_message *msg) |
588 | { | 581 | { |
589 | struct rpc_message msg = { | ||
590 | .rpc_proc = &nfs_procedures[NFSPROC_WRITE], | ||
591 | .rpc_argp = &data->args, | ||
592 | .rpc_resp = &data->res, | ||
593 | .rpc_cred = data->cred, | ||
594 | }; | ||
595 | |||
596 | /* Note: NFSv2 ignores @stable and always uses NFS_FILE_SYNC */ | 582 | /* Note: NFSv2 ignores @stable and always uses NFS_FILE_SYNC */ |
597 | data->args.stable = NFS_FILE_SYNC; | 583 | data->args.stable = NFS_FILE_SYNC; |
598 | 584 | msg->rpc_proc = &nfs_procedures[NFSPROC_WRITE]; | |
599 | /* Finalize the task. */ | ||
600 | rpc_call_setup(&data->task, &msg, 0); | ||
601 | } | 585 | } |
602 | 586 | ||
603 | static void | 587 | static void |
604 | nfs_proc_commit_setup(struct nfs_write_data *data, int how) | 588 | nfs_proc_commit_setup(struct nfs_write_data *data, struct rpc_message *msg) |
605 | { | 589 | { |
606 | BUG(); | 590 | BUG(); |
607 | } | 591 | } |
@@ -609,7 +593,9 @@ nfs_proc_commit_setup(struct nfs_write_data *data, int how) | |||
609 | static int | 593 | static int |
610 | nfs_proc_lock(struct file *filp, int cmd, struct file_lock *fl) | 594 | nfs_proc_lock(struct file *filp, int cmd, struct file_lock *fl) |
611 | { | 595 | { |
612 | return nlmclnt_proc(filp->f_path.dentry->d_inode, cmd, fl); | 596 | struct inode *inode = filp->f_path.dentry->d_inode; |
597 | |||
598 | return nlmclnt_proc(NFS_SERVER(inode)->nlm_host, cmd, fl); | ||
613 | } | 599 | } |
614 | 600 | ||
615 | 601 | ||
diff --git a/fs/nfs/read.c b/fs/nfs/read.c index 4587a86adaac..8fd6dfbe1bc3 100644 --- a/fs/nfs/read.c +++ b/fs/nfs/read.c | |||
@@ -160,12 +160,26 @@ static void nfs_read_rpcsetup(struct nfs_page *req, struct nfs_read_data *data, | |||
160 | const struct rpc_call_ops *call_ops, | 160 | const struct rpc_call_ops *call_ops, |
161 | unsigned int count, unsigned int offset) | 161 | unsigned int count, unsigned int offset) |
162 | { | 162 | { |
163 | struct inode *inode; | 163 | struct inode *inode = req->wb_context->path.dentry->d_inode; |
164 | int flags; | 164 | int swap_flags = IS_SWAPFILE(inode) ? NFS_RPC_SWAPFLAGS : 0; |
165 | struct rpc_task *task; | ||
166 | struct rpc_message msg = { | ||
167 | .rpc_argp = &data->args, | ||
168 | .rpc_resp = &data->res, | ||
169 | .rpc_cred = req->wb_context->cred, | ||
170 | }; | ||
171 | struct rpc_task_setup task_setup_data = { | ||
172 | .task = &data->task, | ||
173 | .rpc_client = NFS_CLIENT(inode), | ||
174 | .rpc_message = &msg, | ||
175 | .callback_ops = call_ops, | ||
176 | .callback_data = data, | ||
177 | .flags = RPC_TASK_ASYNC | swap_flags, | ||
178 | }; | ||
165 | 179 | ||
166 | data->req = req; | 180 | data->req = req; |
167 | data->inode = inode = req->wb_context->path.dentry->d_inode; | 181 | data->inode = inode; |
168 | data->cred = req->wb_context->cred; | 182 | data->cred = msg.rpc_cred; |
169 | 183 | ||
170 | data->args.fh = NFS_FH(inode); | 184 | data->args.fh = NFS_FH(inode); |
171 | data->args.offset = req_offset(req) + offset; | 185 | data->args.offset = req_offset(req) + offset; |
@@ -180,11 +194,7 @@ static void nfs_read_rpcsetup(struct nfs_page *req, struct nfs_read_data *data, | |||
180 | nfs_fattr_init(&data->fattr); | 194 | nfs_fattr_init(&data->fattr); |
181 | 195 | ||
182 | /* Set up the initial task struct. */ | 196 | /* Set up the initial task struct. */ |
183 | flags = RPC_TASK_ASYNC | (IS_SWAPFILE(inode)? NFS_RPC_SWAPFLAGS : 0); | 197 | NFS_PROTO(inode)->read_setup(data, &msg); |
184 | rpc_init_task(&data->task, NFS_CLIENT(inode), flags, call_ops, data); | ||
185 | NFS_PROTO(inode)->read_setup(data); | ||
186 | |||
187 | data->task.tk_cookie = (unsigned long)inode; | ||
188 | 198 | ||
189 | dprintk("NFS: %5u initiated read call (req %s/%Ld, %u bytes @ offset %Lu)\n", | 199 | dprintk("NFS: %5u initiated read call (req %s/%Ld, %u bytes @ offset %Lu)\n", |
190 | data->task.tk_pid, | 200 | data->task.tk_pid, |
@@ -192,6 +202,10 @@ static void nfs_read_rpcsetup(struct nfs_page *req, struct nfs_read_data *data, | |||
192 | (long long)NFS_FILEID(inode), | 202 | (long long)NFS_FILEID(inode), |
193 | count, | 203 | count, |
194 | (unsigned long long)data->args.offset); | 204 | (unsigned long long)data->args.offset); |
205 | |||
206 | task = rpc_run_task(&task_setup_data); | ||
207 | if (!IS_ERR(task)) | ||
208 | rpc_put_task(task); | ||
195 | } | 209 | } |
196 | 210 | ||
197 | static void | 211 | static void |
@@ -208,19 +222,6 @@ nfs_async_read_error(struct list_head *head) | |||
208 | } | 222 | } |
209 | 223 | ||
210 | /* | 224 | /* |
211 | * Start an async read operation | ||
212 | */ | ||
213 | static void nfs_execute_read(struct nfs_read_data *data) | ||
214 | { | ||
215 | struct rpc_clnt *clnt = NFS_CLIENT(data->inode); | ||
216 | sigset_t oldset; | ||
217 | |||
218 | rpc_clnt_sigmask(clnt, &oldset); | ||
219 | rpc_execute(&data->task); | ||
220 | rpc_clnt_sigunmask(clnt, &oldset); | ||
221 | } | ||
222 | |||
223 | /* | ||
224 | * Generate multiple requests to fill a single page. | 225 | * Generate multiple requests to fill a single page. |
225 | * | 226 | * |
226 | * We optimize to reduce the number of read operations on the wire. If we | 227 | * We optimize to reduce the number of read operations on the wire. If we |
@@ -274,7 +275,6 @@ static int nfs_pagein_multi(struct inode *inode, struct list_head *head, unsigne | |||
274 | rsize, offset); | 275 | rsize, offset); |
275 | offset += rsize; | 276 | offset += rsize; |
276 | nbytes -= rsize; | 277 | nbytes -= rsize; |
277 | nfs_execute_read(data); | ||
278 | } while (nbytes != 0); | 278 | } while (nbytes != 0); |
279 | 279 | ||
280 | return 0; | 280 | return 0; |
@@ -312,8 +312,6 @@ static int nfs_pagein_one(struct inode *inode, struct list_head *head, unsigned | |||
312 | req = nfs_list_entry(data->pages.next); | 312 | req = nfs_list_entry(data->pages.next); |
313 | 313 | ||
314 | nfs_read_rpcsetup(req, data, &nfs_read_full_ops, count, 0); | 314 | nfs_read_rpcsetup(req, data, &nfs_read_full_ops, count, 0); |
315 | |||
316 | nfs_execute_read(data); | ||
317 | return 0; | 315 | return 0; |
318 | out_bad: | 316 | out_bad: |
319 | nfs_async_read_error(head); | 317 | nfs_async_read_error(head); |
@@ -338,7 +336,7 @@ int nfs_readpage_result(struct rpc_task *task, struct nfs_read_data *data) | |||
338 | nfs_add_stats(data->inode, NFSIOS_SERVERREADBYTES, data->res.count); | 336 | nfs_add_stats(data->inode, NFSIOS_SERVERREADBYTES, data->res.count); |
339 | 337 | ||
340 | if (task->tk_status == -ESTALE) { | 338 | if (task->tk_status == -ESTALE) { |
341 | set_bit(NFS_INO_STALE, &NFS_FLAGS(data->inode)); | 339 | set_bit(NFS_INO_STALE, &NFS_I(data->inode)->flags); |
342 | nfs_mark_for_revalidate(data->inode); | 340 | nfs_mark_for_revalidate(data->inode); |
343 | } | 341 | } |
344 | return 0; | 342 | return 0; |
diff --git a/fs/nfs/super.c b/fs/nfs/super.c index 0b0c72a072ff..22c49c02897d 100644 --- a/fs/nfs/super.c +++ b/fs/nfs/super.c | |||
@@ -45,6 +45,8 @@ | |||
45 | #include <linux/nfs_idmap.h> | 45 | #include <linux/nfs_idmap.h> |
46 | #include <linux/vfs.h> | 46 | #include <linux/vfs.h> |
47 | #include <linux/inet.h> | 47 | #include <linux/inet.h> |
48 | #include <linux/in6.h> | ||
49 | #include <net/ipv6.h> | ||
48 | #include <linux/nfs_xdr.h> | 50 | #include <linux/nfs_xdr.h> |
49 | #include <linux/magic.h> | 51 | #include <linux/magic.h> |
50 | #include <linux/parser.h> | 52 | #include <linux/parser.h> |
@@ -83,11 +85,11 @@ enum { | |||
83 | Opt_actimeo, | 85 | Opt_actimeo, |
84 | Opt_namelen, | 86 | Opt_namelen, |
85 | Opt_mountport, | 87 | Opt_mountport, |
86 | Opt_mountprog, Opt_mountvers, | 88 | Opt_mountvers, |
87 | Opt_nfsprog, Opt_nfsvers, | 89 | Opt_nfsvers, |
88 | 90 | ||
89 | /* Mount options that take string arguments */ | 91 | /* Mount options that take string arguments */ |
90 | Opt_sec, Opt_proto, Opt_mountproto, | 92 | Opt_sec, Opt_proto, Opt_mountproto, Opt_mounthost, |
91 | Opt_addr, Opt_mountaddr, Opt_clientaddr, | 93 | Opt_addr, Opt_mountaddr, Opt_clientaddr, |
92 | 94 | ||
93 | /* Mount options that are ignored */ | 95 | /* Mount options that are ignored */ |
@@ -137,9 +139,7 @@ static match_table_t nfs_mount_option_tokens = { | |||
137 | { Opt_userspace, "retry=%u" }, | 139 | { Opt_userspace, "retry=%u" }, |
138 | { Opt_namelen, "namlen=%u" }, | 140 | { Opt_namelen, "namlen=%u" }, |
139 | { Opt_mountport, "mountport=%u" }, | 141 | { Opt_mountport, "mountport=%u" }, |
140 | { Opt_mountprog, "mountprog=%u" }, | ||
141 | { Opt_mountvers, "mountvers=%u" }, | 142 | { Opt_mountvers, "mountvers=%u" }, |
142 | { Opt_nfsprog, "nfsprog=%u" }, | ||
143 | { Opt_nfsvers, "nfsvers=%u" }, | 143 | { Opt_nfsvers, "nfsvers=%u" }, |
144 | { Opt_nfsvers, "vers=%u" }, | 144 | { Opt_nfsvers, "vers=%u" }, |
145 | 145 | ||
@@ -148,7 +148,7 @@ static match_table_t nfs_mount_option_tokens = { | |||
148 | { Opt_mountproto, "mountproto=%s" }, | 148 | { Opt_mountproto, "mountproto=%s" }, |
149 | { Opt_addr, "addr=%s" }, | 149 | { Opt_addr, "addr=%s" }, |
150 | { Opt_clientaddr, "clientaddr=%s" }, | 150 | { Opt_clientaddr, "clientaddr=%s" }, |
151 | { Opt_userspace, "mounthost=%s" }, | 151 | { Opt_mounthost, "mounthost=%s" }, |
152 | { Opt_mountaddr, "mountaddr=%s" }, | 152 | { Opt_mountaddr, "mountaddr=%s" }, |
153 | 153 | ||
154 | { Opt_err, NULL } | 154 | { Opt_err, NULL } |
@@ -202,6 +202,7 @@ static int nfs_get_sb(struct file_system_type *, int, const char *, void *, stru | |||
202 | static int nfs_xdev_get_sb(struct file_system_type *fs_type, | 202 | static int nfs_xdev_get_sb(struct file_system_type *fs_type, |
203 | int flags, const char *dev_name, void *raw_data, struct vfsmount *mnt); | 203 | int flags, const char *dev_name, void *raw_data, struct vfsmount *mnt); |
204 | static void nfs_kill_super(struct super_block *); | 204 | static void nfs_kill_super(struct super_block *); |
205 | static void nfs_put_super(struct super_block *); | ||
205 | 206 | ||
206 | static struct file_system_type nfs_fs_type = { | 207 | static struct file_system_type nfs_fs_type = { |
207 | .owner = THIS_MODULE, | 208 | .owner = THIS_MODULE, |
@@ -223,6 +224,7 @@ static const struct super_operations nfs_sops = { | |||
223 | .alloc_inode = nfs_alloc_inode, | 224 | .alloc_inode = nfs_alloc_inode, |
224 | .destroy_inode = nfs_destroy_inode, | 225 | .destroy_inode = nfs_destroy_inode, |
225 | .write_inode = nfs_write_inode, | 226 | .write_inode = nfs_write_inode, |
227 | .put_super = nfs_put_super, | ||
226 | .statfs = nfs_statfs, | 228 | .statfs = nfs_statfs, |
227 | .clear_inode = nfs_clear_inode, | 229 | .clear_inode = nfs_clear_inode, |
228 | .umount_begin = nfs_umount_begin, | 230 | .umount_begin = nfs_umount_begin, |
@@ -325,6 +327,28 @@ void __exit unregister_nfs_fs(void) | |||
325 | unregister_filesystem(&nfs_fs_type); | 327 | unregister_filesystem(&nfs_fs_type); |
326 | } | 328 | } |
327 | 329 | ||
330 | void nfs_sb_active(struct nfs_server *server) | ||
331 | { | ||
332 | atomic_inc(&server->active); | ||
333 | } | ||
334 | |||
335 | void nfs_sb_deactive(struct nfs_server *server) | ||
336 | { | ||
337 | if (atomic_dec_and_test(&server->active)) | ||
338 | wake_up(&server->active_wq); | ||
339 | } | ||
340 | |||
341 | static void nfs_put_super(struct super_block *sb) | ||
342 | { | ||
343 | struct nfs_server *server = NFS_SB(sb); | ||
344 | /* | ||
345 | * Make sure there are no outstanding ops to this server. | ||
346 | * If so, wait for them to finish before allowing the | ||
347 | * unmount to continue. | ||
348 | */ | ||
349 | wait_event(server->active_wq, atomic_read(&server->active) == 0); | ||
350 | } | ||
351 | |||
328 | /* | 352 | /* |
329 | * Deliver file system statistics to userspace | 353 | * Deliver file system statistics to userspace |
330 | */ | 354 | */ |
@@ -455,8 +479,8 @@ static void nfs_show_mount_options(struct seq_file *m, struct nfs_server *nfss, | |||
455 | } | 479 | } |
456 | seq_printf(m, ",proto=%s", | 480 | seq_printf(m, ",proto=%s", |
457 | rpc_peeraddr2str(nfss->client, RPC_DISPLAY_PROTO)); | 481 | rpc_peeraddr2str(nfss->client, RPC_DISPLAY_PROTO)); |
458 | seq_printf(m, ",timeo=%lu", 10U * clp->retrans_timeo / HZ); | 482 | seq_printf(m, ",timeo=%lu", 10U * nfss->client->cl_timeout->to_initval / HZ); |
459 | seq_printf(m, ",retrans=%u", clp->retrans_count); | 483 | seq_printf(m, ",retrans=%u", nfss->client->cl_timeout->to_retries); |
460 | seq_printf(m, ",sec=%s", nfs_pseudoflavour_to_name(nfss->client->cl_auth->au_flavor)); | 484 | seq_printf(m, ",sec=%s", nfs_pseudoflavour_to_name(nfss->client->cl_auth->au_flavor)); |
461 | } | 485 | } |
462 | 486 | ||
@@ -469,8 +493,9 @@ static int nfs_show_options(struct seq_file *m, struct vfsmount *mnt) | |||
469 | 493 | ||
470 | nfs_show_mount_options(m, nfss, 0); | 494 | nfs_show_mount_options(m, nfss, 0); |
471 | 495 | ||
472 | seq_printf(m, ",addr="NIPQUAD_FMT, | 496 | seq_printf(m, ",addr=%s", |
473 | NIPQUAD(nfss->nfs_client->cl_addr.sin_addr)); | 497 | rpc_peeraddr2str(nfss->nfs_client->cl_rpcclient, |
498 | RPC_DISPLAY_ADDR)); | ||
474 | 499 | ||
475 | return 0; | 500 | return 0; |
476 | } | 501 | } |
@@ -507,7 +532,7 @@ static int nfs_show_stats(struct seq_file *m, struct vfsmount *mnt) | |||
507 | seq_printf(m, ",namelen=%d", nfss->namelen); | 532 | seq_printf(m, ",namelen=%d", nfss->namelen); |
508 | 533 | ||
509 | #ifdef CONFIG_NFS_V4 | 534 | #ifdef CONFIG_NFS_V4 |
510 | if (nfss->nfs_client->cl_nfsversion == 4) { | 535 | if (nfss->nfs_client->rpc_ops->version == 4) { |
511 | seq_printf(m, "\n\tnfsv4:\t"); | 536 | seq_printf(m, "\n\tnfsv4:\t"); |
512 | seq_printf(m, "bm0=0x%x", nfss->attr_bitmask[0]); | 537 | seq_printf(m, "bm0=0x%x", nfss->attr_bitmask[0]); |
513 | seq_printf(m, ",bm1=0x%x", nfss->attr_bitmask[1]); | 538 | seq_printf(m, ",bm1=0x%x", nfss->attr_bitmask[1]); |
@@ -575,16 +600,40 @@ static void nfs_umount_begin(struct vfsmount *vfsmnt, int flags) | |||
575 | } | 600 | } |
576 | 601 | ||
577 | /* | 602 | /* |
578 | * Sanity-check a server address provided by the mount command | 603 | * Set the port number in an address. Be agnostic about the address family. |
604 | */ | ||
605 | static void nfs_set_port(struct sockaddr *sap, unsigned short port) | ||
606 | { | ||
607 | switch (sap->sa_family) { | ||
608 | case AF_INET: { | ||
609 | struct sockaddr_in *ap = (struct sockaddr_in *)sap; | ||
610 | ap->sin_port = htons(port); | ||
611 | break; | ||
612 | } | ||
613 | case AF_INET6: { | ||
614 | struct sockaddr_in6 *ap = (struct sockaddr_in6 *)sap; | ||
615 | ap->sin6_port = htons(port); | ||
616 | break; | ||
617 | } | ||
618 | } | ||
619 | } | ||
620 | |||
621 | /* | ||
622 | * Sanity-check a server address provided by the mount command. | ||
623 | * | ||
624 | * Address family must be initialized, and address must not be | ||
625 | * the ANY address for that family. | ||
579 | */ | 626 | */ |
580 | static int nfs_verify_server_address(struct sockaddr *addr) | 627 | static int nfs_verify_server_address(struct sockaddr *addr) |
581 | { | 628 | { |
582 | switch (addr->sa_family) { | 629 | switch (addr->sa_family) { |
583 | case AF_INET: { | 630 | case AF_INET: { |
584 | struct sockaddr_in *sa = (struct sockaddr_in *) addr; | 631 | struct sockaddr_in *sa = (struct sockaddr_in *)addr; |
585 | if (sa->sin_addr.s_addr != INADDR_ANY) | 632 | return sa->sin_addr.s_addr != INADDR_ANY; |
586 | return 1; | 633 | } |
587 | break; | 634 | case AF_INET6: { |
635 | struct in6_addr *sa = &((struct sockaddr_in6 *)addr)->sin6_addr; | ||
636 | return !ipv6_addr_any(sa); | ||
588 | } | 637 | } |
589 | } | 638 | } |
590 | 639 | ||
@@ -592,6 +641,40 @@ static int nfs_verify_server_address(struct sockaddr *addr) | |||
592 | } | 641 | } |
593 | 642 | ||
594 | /* | 643 | /* |
644 | * Parse string addresses passed in via a mount option, | ||
645 | * and construct a sockaddr based on the result. | ||
646 | * | ||
647 | * If address parsing fails, set the sockaddr's address | ||
648 | * family to AF_UNSPEC to force nfs_verify_server_address() | ||
649 | * to punt the mount. | ||
650 | */ | ||
651 | static void nfs_parse_server_address(char *value, | ||
652 | struct sockaddr *sap, | ||
653 | size_t *len) | ||
654 | { | ||
655 | if (strchr(value, ':')) { | ||
656 | struct sockaddr_in6 *ap = (struct sockaddr_in6 *)sap; | ||
657 | u8 *addr = (u8 *)&ap->sin6_addr.in6_u; | ||
658 | |||
659 | ap->sin6_family = AF_INET6; | ||
660 | *len = sizeof(*ap); | ||
661 | if (in6_pton(value, -1, addr, '\0', NULL)) | ||
662 | return; | ||
663 | } else { | ||
664 | struct sockaddr_in *ap = (struct sockaddr_in *)sap; | ||
665 | u8 *addr = (u8 *)&ap->sin_addr.s_addr; | ||
666 | |||
667 | ap->sin_family = AF_INET; | ||
668 | *len = sizeof(*ap); | ||
669 | if (in4_pton(value, -1, addr, '\0', NULL)) | ||
670 | return; | ||
671 | } | ||
672 | |||
673 | sap->sa_family = AF_UNSPEC; | ||
674 | *len = 0; | ||
675 | } | ||
676 | |||
677 | /* | ||
595 | * Error-check and convert a string of mount options from user space into | 678 | * Error-check and convert a string of mount options from user space into |
596 | * a data structure | 679 | * a data structure |
597 | */ | 680 | */ |
@@ -599,6 +682,7 @@ static int nfs_parse_mount_options(char *raw, | |||
599 | struct nfs_parsed_mount_data *mnt) | 682 | struct nfs_parsed_mount_data *mnt) |
600 | { | 683 | { |
601 | char *p, *string; | 684 | char *p, *string; |
685 | unsigned short port = 0; | ||
602 | 686 | ||
603 | if (!raw) { | 687 | if (!raw) { |
604 | dfprintk(MOUNT, "NFS: mount options string was NULL.\n"); | 688 | dfprintk(MOUNT, "NFS: mount options string was NULL.\n"); |
@@ -701,7 +785,7 @@ static int nfs_parse_mount_options(char *raw, | |||
701 | return 0; | 785 | return 0; |
702 | if (option < 0 || option > 65535) | 786 | if (option < 0 || option > 65535) |
703 | return 0; | 787 | return 0; |
704 | mnt->nfs_server.address.sin_port = htons(option); | 788 | port = option; |
705 | break; | 789 | break; |
706 | case Opt_rsize: | 790 | case Opt_rsize: |
707 | if (match_int(args, &mnt->rsize)) | 791 | if (match_int(args, &mnt->rsize)) |
@@ -763,13 +847,6 @@ static int nfs_parse_mount_options(char *raw, | |||
763 | return 0; | 847 | return 0; |
764 | mnt->mount_server.port = option; | 848 | mnt->mount_server.port = option; |
765 | break; | 849 | break; |
766 | case Opt_mountprog: | ||
767 | if (match_int(args, &option)) | ||
768 | return 0; | ||
769 | if (option < 0) | ||
770 | return 0; | ||
771 | mnt->mount_server.program = option; | ||
772 | break; | ||
773 | case Opt_mountvers: | 850 | case Opt_mountvers: |
774 | if (match_int(args, &option)) | 851 | if (match_int(args, &option)) |
775 | return 0; | 852 | return 0; |
@@ -777,13 +854,6 @@ static int nfs_parse_mount_options(char *raw, | |||
777 | return 0; | 854 | return 0; |
778 | mnt->mount_server.version = option; | 855 | mnt->mount_server.version = option; |
779 | break; | 856 | break; |
780 | case Opt_nfsprog: | ||
781 | if (match_int(args, &option)) | ||
782 | return 0; | ||
783 | if (option < 0) | ||
784 | return 0; | ||
785 | mnt->nfs_server.program = option; | ||
786 | break; | ||
787 | case Opt_nfsvers: | 857 | case Opt_nfsvers: |
788 | if (match_int(args, &option)) | 858 | if (match_int(args, &option)) |
789 | return 0; | 859 | return 0; |
@@ -927,24 +997,32 @@ static int nfs_parse_mount_options(char *raw, | |||
927 | string = match_strdup(args); | 997 | string = match_strdup(args); |
928 | if (string == NULL) | 998 | if (string == NULL) |
929 | goto out_nomem; | 999 | goto out_nomem; |
930 | mnt->nfs_server.address.sin_family = AF_INET; | 1000 | nfs_parse_server_address(string, (struct sockaddr *) |
931 | mnt->nfs_server.address.sin_addr.s_addr = | 1001 | &mnt->nfs_server.address, |
932 | in_aton(string); | 1002 | &mnt->nfs_server.addrlen); |
933 | kfree(string); | 1003 | kfree(string); |
934 | break; | 1004 | break; |
935 | case Opt_clientaddr: | 1005 | case Opt_clientaddr: |
936 | string = match_strdup(args); | 1006 | string = match_strdup(args); |
937 | if (string == NULL) | 1007 | if (string == NULL) |
938 | goto out_nomem; | 1008 | goto out_nomem; |
1009 | kfree(mnt->client_address); | ||
939 | mnt->client_address = string; | 1010 | mnt->client_address = string; |
940 | break; | 1011 | break; |
1012 | case Opt_mounthost: | ||
1013 | string = match_strdup(args); | ||
1014 | if (string == NULL) | ||
1015 | goto out_nomem; | ||
1016 | kfree(mnt->mount_server.hostname); | ||
1017 | mnt->mount_server.hostname = string; | ||
1018 | break; | ||
941 | case Opt_mountaddr: | 1019 | case Opt_mountaddr: |
942 | string = match_strdup(args); | 1020 | string = match_strdup(args); |
943 | if (string == NULL) | 1021 | if (string == NULL) |
944 | goto out_nomem; | 1022 | goto out_nomem; |
945 | mnt->mount_server.address.sin_family = AF_INET; | 1023 | nfs_parse_server_address(string, (struct sockaddr *) |
946 | mnt->mount_server.address.sin_addr.s_addr = | 1024 | &mnt->mount_server.address, |
947 | in_aton(string); | 1025 | &mnt->mount_server.addrlen); |
948 | kfree(string); | 1026 | kfree(string); |
949 | break; | 1027 | break; |
950 | 1028 | ||
@@ -957,6 +1035,8 @@ static int nfs_parse_mount_options(char *raw, | |||
957 | } | 1035 | } |
958 | } | 1036 | } |
959 | 1037 | ||
1038 | nfs_set_port((struct sockaddr *)&mnt->nfs_server.address, port); | ||
1039 | |||
960 | return 1; | 1040 | return 1; |
961 | 1041 | ||
962 | out_nomem: | 1042 | out_nomem: |
@@ -987,7 +1067,8 @@ out_unknown: | |||
987 | static int nfs_try_mount(struct nfs_parsed_mount_data *args, | 1067 | static int nfs_try_mount(struct nfs_parsed_mount_data *args, |
988 | struct nfs_fh *root_fh) | 1068 | struct nfs_fh *root_fh) |
989 | { | 1069 | { |
990 | struct sockaddr_in sin; | 1070 | struct sockaddr *sap = (struct sockaddr *)&args->mount_server.address; |
1071 | char *hostname; | ||
991 | int status; | 1072 | int status; |
992 | 1073 | ||
993 | if (args->mount_server.version == 0) { | 1074 | if (args->mount_server.version == 0) { |
@@ -997,25 +1078,32 @@ static int nfs_try_mount(struct nfs_parsed_mount_data *args, | |||
997 | args->mount_server.version = NFS_MNT_VERSION; | 1078 | args->mount_server.version = NFS_MNT_VERSION; |
998 | } | 1079 | } |
999 | 1080 | ||
1081 | if (args->mount_server.hostname) | ||
1082 | hostname = args->mount_server.hostname; | ||
1083 | else | ||
1084 | hostname = args->nfs_server.hostname; | ||
1085 | |||
1000 | /* | 1086 | /* |
1001 | * Construct the mount server's address. | 1087 | * Construct the mount server's address. |
1002 | */ | 1088 | */ |
1003 | if (args->mount_server.address.sin_addr.s_addr != INADDR_ANY) | 1089 | if (args->mount_server.address.ss_family == AF_UNSPEC) { |
1004 | sin = args->mount_server.address; | 1090 | memcpy(sap, &args->nfs_server.address, |
1005 | else | 1091 | args->nfs_server.addrlen); |
1006 | sin = args->nfs_server.address; | 1092 | args->mount_server.addrlen = args->nfs_server.addrlen; |
1093 | } | ||
1094 | |||
1007 | /* | 1095 | /* |
1008 | * autobind will be used if mount_server.port == 0 | 1096 | * autobind will be used if mount_server.port == 0 |
1009 | */ | 1097 | */ |
1010 | sin.sin_port = htons(args->mount_server.port); | 1098 | nfs_set_port(sap, args->mount_server.port); |
1011 | 1099 | ||
1012 | /* | 1100 | /* |
1013 | * Now ask the mount server to map our export path | 1101 | * Now ask the mount server to map our export path |
1014 | * to a file handle. | 1102 | * to a file handle. |
1015 | */ | 1103 | */ |
1016 | status = nfs_mount((struct sockaddr *) &sin, | 1104 | status = nfs_mount(sap, |
1017 | sizeof(sin), | 1105 | args->mount_server.addrlen, |
1018 | args->nfs_server.hostname, | 1106 | hostname, |
1019 | args->nfs_server.export_path, | 1107 | args->nfs_server.export_path, |
1020 | args->mount_server.version, | 1108 | args->mount_server.version, |
1021 | args->mount_server.protocol, | 1109 | args->mount_server.protocol, |
@@ -1023,8 +1111,8 @@ static int nfs_try_mount(struct nfs_parsed_mount_data *args, | |||
1023 | if (status == 0) | 1111 | if (status == 0) |
1024 | return 0; | 1112 | return 0; |
1025 | 1113 | ||
1026 | dfprintk(MOUNT, "NFS: unable to mount server " NIPQUAD_FMT | 1114 | dfprintk(MOUNT, "NFS: unable to mount server %s, error %d", |
1027 | ", error %d\n", NIPQUAD(sin.sin_addr.s_addr), status); | 1115 | hostname, status); |
1028 | return status; | 1116 | return status; |
1029 | } | 1117 | } |
1030 | 1118 | ||
@@ -1043,9 +1131,6 @@ static int nfs_try_mount(struct nfs_parsed_mount_data *args, | |||
1043 | * | 1131 | * |
1044 | * + breaking back: trying proto=udp after proto=tcp, v2 after v3, | 1132 | * + breaking back: trying proto=udp after proto=tcp, v2 after v3, |
1045 | * mountproto=tcp after mountproto=udp, and so on | 1133 | * mountproto=tcp after mountproto=udp, and so on |
1046 | * | ||
1047 | * XXX: as far as I can tell, changing the NFS program number is not | ||
1048 | * supported in the NFS client. | ||
1049 | */ | 1134 | */ |
1050 | static int nfs_validate_mount_data(void *options, | 1135 | static int nfs_validate_mount_data(void *options, |
1051 | struct nfs_parsed_mount_data *args, | 1136 | struct nfs_parsed_mount_data *args, |
@@ -1069,9 +1154,7 @@ static int nfs_validate_mount_data(void *options, | |||
1069 | args->acdirmin = 30; | 1154 | args->acdirmin = 30; |
1070 | args->acdirmax = 60; | 1155 | args->acdirmax = 60; |
1071 | args->mount_server.protocol = XPRT_TRANSPORT_UDP; | 1156 | args->mount_server.protocol = XPRT_TRANSPORT_UDP; |
1072 | args->mount_server.program = NFS_MNT_PROGRAM; | ||
1073 | args->nfs_server.protocol = XPRT_TRANSPORT_TCP; | 1157 | args->nfs_server.protocol = XPRT_TRANSPORT_TCP; |
1074 | args->nfs_server.program = NFS_PROGRAM; | ||
1075 | 1158 | ||
1076 | switch (data->version) { | 1159 | switch (data->version) { |
1077 | case 1: | 1160 | case 1: |
@@ -1102,9 +1185,6 @@ static int nfs_validate_mount_data(void *options, | |||
1102 | memset(mntfh->data + mntfh->size, 0, | 1185 | memset(mntfh->data + mntfh->size, 0, |
1103 | sizeof(mntfh->data) - mntfh->size); | 1186 | sizeof(mntfh->data) - mntfh->size); |
1104 | 1187 | ||
1105 | if (!nfs_verify_server_address((struct sockaddr *) &data->addr)) | ||
1106 | goto out_no_address; | ||
1107 | |||
1108 | /* | 1188 | /* |
1109 | * Translate to nfs_parsed_mount_data, which nfs_fill_super | 1189 | * Translate to nfs_parsed_mount_data, which nfs_fill_super |
1110 | * can deal with. | 1190 | * can deal with. |
@@ -1119,7 +1199,14 @@ static int nfs_validate_mount_data(void *options, | |||
1119 | args->acregmax = data->acregmax; | 1199 | args->acregmax = data->acregmax; |
1120 | args->acdirmin = data->acdirmin; | 1200 | args->acdirmin = data->acdirmin; |
1121 | args->acdirmax = data->acdirmax; | 1201 | args->acdirmax = data->acdirmax; |
1122 | args->nfs_server.address = data->addr; | 1202 | |
1203 | memcpy(&args->nfs_server.address, &data->addr, | ||
1204 | sizeof(data->addr)); | ||
1205 | args->nfs_server.addrlen = sizeof(data->addr); | ||
1206 | if (!nfs_verify_server_address((struct sockaddr *) | ||
1207 | &args->nfs_server.address)) | ||
1208 | goto out_no_address; | ||
1209 | |||
1123 | if (!(data->flags & NFS_MOUNT_TCP)) | 1210 | if (!(data->flags & NFS_MOUNT_TCP)) |
1124 | args->nfs_server.protocol = XPRT_TRANSPORT_UDP; | 1211 | args->nfs_server.protocol = XPRT_TRANSPORT_UDP; |
1125 | /* N.B. caller will free nfs_server.hostname in all cases */ | 1212 | /* N.B. caller will free nfs_server.hostname in all cases */ |
@@ -1322,15 +1409,50 @@ static int nfs_set_super(struct super_block *s, void *data) | |||
1322 | return ret; | 1409 | return ret; |
1323 | } | 1410 | } |
1324 | 1411 | ||
1412 | static int nfs_compare_super_address(struct nfs_server *server1, | ||
1413 | struct nfs_server *server2) | ||
1414 | { | ||
1415 | struct sockaddr *sap1, *sap2; | ||
1416 | |||
1417 | sap1 = (struct sockaddr *)&server1->nfs_client->cl_addr; | ||
1418 | sap2 = (struct sockaddr *)&server2->nfs_client->cl_addr; | ||
1419 | |||
1420 | if (sap1->sa_family != sap2->sa_family) | ||
1421 | return 0; | ||
1422 | |||
1423 | switch (sap1->sa_family) { | ||
1424 | case AF_INET: { | ||
1425 | struct sockaddr_in *sin1 = (struct sockaddr_in *)sap1; | ||
1426 | struct sockaddr_in *sin2 = (struct sockaddr_in *)sap2; | ||
1427 | if (sin1->sin_addr.s_addr != sin2->sin_addr.s_addr) | ||
1428 | return 0; | ||
1429 | if (sin1->sin_port != sin2->sin_port) | ||
1430 | return 0; | ||
1431 | break; | ||
1432 | } | ||
1433 | case AF_INET6: { | ||
1434 | struct sockaddr_in6 *sin1 = (struct sockaddr_in6 *)sap1; | ||
1435 | struct sockaddr_in6 *sin2 = (struct sockaddr_in6 *)sap2; | ||
1436 | if (!ipv6_addr_equal(&sin1->sin6_addr, &sin2->sin6_addr)) | ||
1437 | return 0; | ||
1438 | if (sin1->sin6_port != sin2->sin6_port) | ||
1439 | return 0; | ||
1440 | break; | ||
1441 | } | ||
1442 | default: | ||
1443 | return 0; | ||
1444 | } | ||
1445 | |||
1446 | return 1; | ||
1447 | } | ||
1448 | |||
1325 | static int nfs_compare_super(struct super_block *sb, void *data) | 1449 | static int nfs_compare_super(struct super_block *sb, void *data) |
1326 | { | 1450 | { |
1327 | struct nfs_sb_mountdata *sb_mntdata = data; | 1451 | struct nfs_sb_mountdata *sb_mntdata = data; |
1328 | struct nfs_server *server = sb_mntdata->server, *old = NFS_SB(sb); | 1452 | struct nfs_server *server = sb_mntdata->server, *old = NFS_SB(sb); |
1329 | int mntflags = sb_mntdata->mntflags; | 1453 | int mntflags = sb_mntdata->mntflags; |
1330 | 1454 | ||
1331 | if (memcmp(&old->nfs_client->cl_addr, | 1455 | if (!nfs_compare_super_address(old, server)) |
1332 | &server->nfs_client->cl_addr, | ||
1333 | sizeof(old->nfs_client->cl_addr)) != 0) | ||
1334 | return 0; | 1456 | return 0; |
1335 | /* Note: NFS_MOUNT_UNSHARED == NFS4_MOUNT_UNSHARED */ | 1457 | /* Note: NFS_MOUNT_UNSHARED == NFS4_MOUNT_UNSHARED */ |
1336 | if (old->flags & NFS_MOUNT_UNSHARED) | 1458 | if (old->flags & NFS_MOUNT_UNSHARED) |
@@ -1400,6 +1522,7 @@ static int nfs_get_sb(struct file_system_type *fs_type, | |||
1400 | 1522 | ||
1401 | out: | 1523 | out: |
1402 | kfree(data.nfs_server.hostname); | 1524 | kfree(data.nfs_server.hostname); |
1525 | kfree(data.mount_server.hostname); | ||
1403 | return error; | 1526 | return error; |
1404 | 1527 | ||
1405 | out_err_nosb: | 1528 | out_err_nosb: |
@@ -1528,12 +1651,35 @@ static void nfs4_fill_super(struct super_block *sb) | |||
1528 | } | 1651 | } |
1529 | 1652 | ||
1530 | /* | 1653 | /* |
1654 | * If the user didn't specify a port, set the port number to | ||
1655 | * the NFS version 4 default port. | ||
1656 | */ | ||
1657 | static void nfs4_default_port(struct sockaddr *sap) | ||
1658 | { | ||
1659 | switch (sap->sa_family) { | ||
1660 | case AF_INET: { | ||
1661 | struct sockaddr_in *ap = (struct sockaddr_in *)sap; | ||
1662 | if (ap->sin_port == 0) | ||
1663 | ap->sin_port = htons(NFS_PORT); | ||
1664 | break; | ||
1665 | } | ||
1666 | case AF_INET6: { | ||
1667 | struct sockaddr_in6 *ap = (struct sockaddr_in6 *)sap; | ||
1668 | if (ap->sin6_port == 0) | ||
1669 | ap->sin6_port = htons(NFS_PORT); | ||
1670 | break; | ||
1671 | } | ||
1672 | } | ||
1673 | } | ||
1674 | |||
1675 | /* | ||
1531 | * Validate NFSv4 mount options | 1676 | * Validate NFSv4 mount options |
1532 | */ | 1677 | */ |
1533 | static int nfs4_validate_mount_data(void *options, | 1678 | static int nfs4_validate_mount_data(void *options, |
1534 | struct nfs_parsed_mount_data *args, | 1679 | struct nfs_parsed_mount_data *args, |
1535 | const char *dev_name) | 1680 | const char *dev_name) |
1536 | { | 1681 | { |
1682 | struct sockaddr_in *ap; | ||
1537 | struct nfs4_mount_data *data = (struct nfs4_mount_data *)options; | 1683 | struct nfs4_mount_data *data = (struct nfs4_mount_data *)options; |
1538 | char *c; | 1684 | char *c; |
1539 | 1685 | ||
@@ -1554,18 +1700,21 @@ static int nfs4_validate_mount_data(void *options, | |||
1554 | 1700 | ||
1555 | switch (data->version) { | 1701 | switch (data->version) { |
1556 | case 1: | 1702 | case 1: |
1557 | if (data->host_addrlen != sizeof(args->nfs_server.address)) | 1703 | ap = (struct sockaddr_in *)&args->nfs_server.address; |
1704 | if (data->host_addrlen > sizeof(args->nfs_server.address)) | ||
1558 | goto out_no_address; | 1705 | goto out_no_address; |
1559 | if (copy_from_user(&args->nfs_server.address, | 1706 | if (data->host_addrlen == 0) |
1560 | data->host_addr, | 1707 | goto out_no_address; |
1561 | sizeof(args->nfs_server.address))) | 1708 | args->nfs_server.addrlen = data->host_addrlen; |
1709 | if (copy_from_user(ap, data->host_addr, data->host_addrlen)) | ||
1562 | return -EFAULT; | 1710 | return -EFAULT; |
1563 | if (args->nfs_server.address.sin_port == 0) | ||
1564 | args->nfs_server.address.sin_port = htons(NFS_PORT); | ||
1565 | if (!nfs_verify_server_address((struct sockaddr *) | 1711 | if (!nfs_verify_server_address((struct sockaddr *) |
1566 | &args->nfs_server.address)) | 1712 | &args->nfs_server.address)) |
1567 | goto out_no_address; | 1713 | goto out_no_address; |
1568 | 1714 | ||
1715 | nfs4_default_port((struct sockaddr *) | ||
1716 | &args->nfs_server.address); | ||
1717 | |||
1569 | switch (data->auth_flavourlen) { | 1718 | switch (data->auth_flavourlen) { |
1570 | case 0: | 1719 | case 0: |
1571 | args->auth_flavors[0] = RPC_AUTH_UNIX; | 1720 | args->auth_flavors[0] = RPC_AUTH_UNIX; |
@@ -1623,6 +1772,9 @@ static int nfs4_validate_mount_data(void *options, | |||
1623 | &args->nfs_server.address)) | 1772 | &args->nfs_server.address)) |
1624 | return -EINVAL; | 1773 | return -EINVAL; |
1625 | 1774 | ||
1775 | nfs4_default_port((struct sockaddr *) | ||
1776 | &args->nfs_server.address); | ||
1777 | |||
1626 | switch (args->auth_flavor_len) { | 1778 | switch (args->auth_flavor_len) { |
1627 | case 0: | 1779 | case 0: |
1628 | args->auth_flavors[0] = RPC_AUTH_UNIX; | 1780 | args->auth_flavors[0] = RPC_AUTH_UNIX; |
@@ -1643,21 +1795,16 @@ static int nfs4_validate_mount_data(void *options, | |||
1643 | len = c - dev_name; | 1795 | len = c - dev_name; |
1644 | if (len > NFS4_MAXNAMLEN) | 1796 | if (len > NFS4_MAXNAMLEN) |
1645 | return -ENAMETOOLONG; | 1797 | return -ENAMETOOLONG; |
1646 | args->nfs_server.hostname = kzalloc(len, GFP_KERNEL); | 1798 | /* N.B. caller will free nfs_server.hostname in all cases */ |
1647 | if (args->nfs_server.hostname == NULL) | 1799 | args->nfs_server.hostname = kstrndup(dev_name, len, GFP_KERNEL); |
1648 | return -ENOMEM; | ||
1649 | strncpy(args->nfs_server.hostname, dev_name, len - 1); | ||
1650 | 1800 | ||
1651 | c++; /* step over the ':' */ | 1801 | c++; /* step over the ':' */ |
1652 | len = strlen(c); | 1802 | len = strlen(c); |
1653 | if (len > NFS4_MAXPATHLEN) | 1803 | if (len > NFS4_MAXPATHLEN) |
1654 | return -ENAMETOOLONG; | 1804 | return -ENAMETOOLONG; |
1655 | args->nfs_server.export_path = kzalloc(len + 1, GFP_KERNEL); | 1805 | args->nfs_server.export_path = kstrndup(c, len, GFP_KERNEL); |
1656 | if (args->nfs_server.export_path == NULL) | ||
1657 | return -ENOMEM; | ||
1658 | strncpy(args->nfs_server.export_path, c, len); | ||
1659 | 1806 | ||
1660 | dprintk("MNTPATH: %s\n", args->nfs_server.export_path); | 1807 | dprintk("NFS: MNTPATH: '%s'\n", args->nfs_server.export_path); |
1661 | 1808 | ||
1662 | if (args->client_address == NULL) | 1809 | if (args->client_address == NULL) |
1663 | goto out_no_client_address; | 1810 | goto out_no_client_address; |
diff --git a/fs/nfs/unlink.c b/fs/nfs/unlink.c index 233ad38161f9..757415363422 100644 --- a/fs/nfs/unlink.c +++ b/fs/nfs/unlink.c | |||
@@ -14,6 +14,8 @@ | |||
14 | #include <linux/sched.h> | 14 | #include <linux/sched.h> |
15 | #include <linux/wait.h> | 15 | #include <linux/wait.h> |
16 | 16 | ||
17 | #include "internal.h" | ||
18 | |||
17 | struct nfs_unlinkdata { | 19 | struct nfs_unlinkdata { |
18 | struct hlist_node list; | 20 | struct hlist_node list; |
19 | struct nfs_removeargs args; | 21 | struct nfs_removeargs args; |
@@ -69,24 +71,6 @@ static void nfs_dec_sillycount(struct inode *dir) | |||
69 | } | 71 | } |
70 | 72 | ||
71 | /** | 73 | /** |
72 | * nfs_async_unlink_init - Initialize the RPC info | ||
73 | * task: rpc_task of the sillydelete | ||
74 | */ | ||
75 | static void nfs_async_unlink_init(struct rpc_task *task, void *calldata) | ||
76 | { | ||
77 | struct nfs_unlinkdata *data = calldata; | ||
78 | struct inode *dir = data->dir; | ||
79 | struct rpc_message msg = { | ||
80 | .rpc_argp = &data->args, | ||
81 | .rpc_resp = &data->res, | ||
82 | .rpc_cred = data->cred, | ||
83 | }; | ||
84 | |||
85 | NFS_PROTO(dir)->unlink_setup(&msg, dir); | ||
86 | rpc_call_setup(task, &msg, 0); | ||
87 | } | ||
88 | |||
89 | /** | ||
90 | * nfs_async_unlink_done - Sillydelete post-processing | 74 | * nfs_async_unlink_done - Sillydelete post-processing |
91 | * @task: rpc_task of the sillydelete | 75 | * @task: rpc_task of the sillydelete |
92 | * | 76 | * |
@@ -113,32 +97,45 @@ static void nfs_async_unlink_release(void *calldata) | |||
113 | struct nfs_unlinkdata *data = calldata; | 97 | struct nfs_unlinkdata *data = calldata; |
114 | 98 | ||
115 | nfs_dec_sillycount(data->dir); | 99 | nfs_dec_sillycount(data->dir); |
100 | nfs_sb_deactive(NFS_SERVER(data->dir)); | ||
116 | nfs_free_unlinkdata(data); | 101 | nfs_free_unlinkdata(data); |
117 | } | 102 | } |
118 | 103 | ||
119 | static const struct rpc_call_ops nfs_unlink_ops = { | 104 | static const struct rpc_call_ops nfs_unlink_ops = { |
120 | .rpc_call_prepare = nfs_async_unlink_init, | ||
121 | .rpc_call_done = nfs_async_unlink_done, | 105 | .rpc_call_done = nfs_async_unlink_done, |
122 | .rpc_release = nfs_async_unlink_release, | 106 | .rpc_release = nfs_async_unlink_release, |
123 | }; | 107 | }; |
124 | 108 | ||
125 | static int nfs_do_call_unlink(struct dentry *parent, struct inode *dir, struct nfs_unlinkdata *data) | 109 | static int nfs_do_call_unlink(struct dentry *parent, struct inode *dir, struct nfs_unlinkdata *data) |
126 | { | 110 | { |
111 | struct rpc_message msg = { | ||
112 | .rpc_argp = &data->args, | ||
113 | .rpc_resp = &data->res, | ||
114 | .rpc_cred = data->cred, | ||
115 | }; | ||
116 | struct rpc_task_setup task_setup_data = { | ||
117 | .rpc_message = &msg, | ||
118 | .callback_ops = &nfs_unlink_ops, | ||
119 | .callback_data = data, | ||
120 | .flags = RPC_TASK_ASYNC, | ||
121 | }; | ||
127 | struct rpc_task *task; | 122 | struct rpc_task *task; |
128 | struct dentry *alias; | 123 | struct dentry *alias; |
129 | 124 | ||
130 | alias = d_lookup(parent, &data->args.name); | 125 | alias = d_lookup(parent, &data->args.name); |
131 | if (alias != NULL) { | 126 | if (alias != NULL) { |
132 | int ret = 0; | 127 | int ret = 0; |
128 | |||
133 | /* | 129 | /* |
134 | * Hey, we raced with lookup... See if we need to transfer | 130 | * Hey, we raced with lookup... See if we need to transfer |
135 | * the sillyrename information to the aliased dentry. | 131 | * the sillyrename information to the aliased dentry. |
136 | */ | 132 | */ |
137 | nfs_free_dname(data); | 133 | nfs_free_dname(data); |
138 | spin_lock(&alias->d_lock); | 134 | spin_lock(&alias->d_lock); |
139 | if (!(alias->d_flags & DCACHE_NFSFS_RENAMED)) { | 135 | if (alias->d_inode != NULL && |
136 | !(alias->d_flags & DCACHE_NFSFS_RENAMED)) { | ||
140 | alias->d_fsdata = data; | 137 | alias->d_fsdata = data; |
141 | alias->d_flags ^= DCACHE_NFSFS_RENAMED; | 138 | alias->d_flags |= DCACHE_NFSFS_RENAMED; |
142 | ret = 1; | 139 | ret = 1; |
143 | } | 140 | } |
144 | spin_unlock(&alias->d_lock); | 141 | spin_unlock(&alias->d_lock); |
@@ -151,10 +148,14 @@ static int nfs_do_call_unlink(struct dentry *parent, struct inode *dir, struct n | |||
151 | nfs_dec_sillycount(dir); | 148 | nfs_dec_sillycount(dir); |
152 | return 0; | 149 | return 0; |
153 | } | 150 | } |
151 | nfs_sb_active(NFS_SERVER(dir)); | ||
154 | data->args.fh = NFS_FH(dir); | 152 | data->args.fh = NFS_FH(dir); |
155 | nfs_fattr_init(&data->res.dir_attr); | 153 | nfs_fattr_init(&data->res.dir_attr); |
156 | 154 | ||
157 | task = rpc_run_task(NFS_CLIENT(dir), RPC_TASK_ASYNC, &nfs_unlink_ops, data); | 155 | NFS_PROTO(dir)->unlink_setup(&msg, dir); |
156 | |||
157 | task_setup_data.rpc_client = NFS_CLIENT(dir); | ||
158 | task = rpc_run_task(&task_setup_data); | ||
158 | if (!IS_ERR(task)) | 159 | if (!IS_ERR(task)) |
159 | rpc_put_task(task); | 160 | rpc_put_task(task); |
160 | return 1; | 161 | return 1; |
diff --git a/fs/nfs/write.c b/fs/nfs/write.c index 51cc1bd6a116..5ac5b27b639a 100644 --- a/fs/nfs/write.c +++ b/fs/nfs/write.c | |||
@@ -196,7 +196,7 @@ static int nfs_writepage_setup(struct nfs_open_context *ctx, struct page *page, | |||
196 | } | 196 | } |
197 | /* Update file length */ | 197 | /* Update file length */ |
198 | nfs_grow_file(page, offset, count); | 198 | nfs_grow_file(page, offset, count); |
199 | nfs_unlock_request(req); | 199 | nfs_clear_page_tag_locked(req); |
200 | return 0; | 200 | return 0; |
201 | } | 201 | } |
202 | 202 | ||
@@ -252,7 +252,6 @@ static int nfs_page_async_flush(struct nfs_pageio_descriptor *pgio, | |||
252 | struct page *page) | 252 | struct page *page) |
253 | { | 253 | { |
254 | struct inode *inode = page->mapping->host; | 254 | struct inode *inode = page->mapping->host; |
255 | struct nfs_inode *nfsi = NFS_I(inode); | ||
256 | struct nfs_page *req; | 255 | struct nfs_page *req; |
257 | int ret; | 256 | int ret; |
258 | 257 | ||
@@ -263,10 +262,10 @@ static int nfs_page_async_flush(struct nfs_pageio_descriptor *pgio, | |||
263 | spin_unlock(&inode->i_lock); | 262 | spin_unlock(&inode->i_lock); |
264 | return 0; | 263 | return 0; |
265 | } | 264 | } |
266 | if (nfs_lock_request_dontget(req)) | 265 | if (nfs_set_page_tag_locked(req)) |
267 | break; | 266 | break; |
268 | /* Note: If we hold the page lock, as is the case in nfs_writepage, | 267 | /* Note: If we hold the page lock, as is the case in nfs_writepage, |
269 | * then the call to nfs_lock_request_dontget() will always | 268 | * then the call to nfs_set_page_tag_locked() will always |
270 | * succeed provided that someone hasn't already marked the | 269 | * succeed provided that someone hasn't already marked the |
271 | * request as dirty (in which case we don't care). | 270 | * request as dirty (in which case we don't care). |
272 | */ | 271 | */ |
@@ -280,7 +279,7 @@ static int nfs_page_async_flush(struct nfs_pageio_descriptor *pgio, | |||
280 | if (test_bit(PG_NEED_COMMIT, &req->wb_flags)) { | 279 | if (test_bit(PG_NEED_COMMIT, &req->wb_flags)) { |
281 | /* This request is marked for commit */ | 280 | /* This request is marked for commit */ |
282 | spin_unlock(&inode->i_lock); | 281 | spin_unlock(&inode->i_lock); |
283 | nfs_unlock_request(req); | 282 | nfs_clear_page_tag_locked(req); |
284 | nfs_pageio_complete(pgio); | 283 | nfs_pageio_complete(pgio); |
285 | return 0; | 284 | return 0; |
286 | } | 285 | } |
@@ -288,8 +287,6 @@ static int nfs_page_async_flush(struct nfs_pageio_descriptor *pgio, | |||
288 | spin_unlock(&inode->i_lock); | 287 | spin_unlock(&inode->i_lock); |
289 | BUG(); | 288 | BUG(); |
290 | } | 289 | } |
291 | radix_tree_tag_set(&nfsi->nfs_page_tree, req->wb_index, | ||
292 | NFS_PAGE_TAG_LOCKED); | ||
293 | spin_unlock(&inode->i_lock); | 290 | spin_unlock(&inode->i_lock); |
294 | nfs_pageio_add_request(pgio, req); | 291 | nfs_pageio_add_request(pgio, req); |
295 | return 0; | 292 | return 0; |
@@ -381,6 +378,7 @@ static int nfs_inode_add_request(struct inode *inode, struct nfs_page *req) | |||
381 | set_page_private(req->wb_page, (unsigned long)req); | 378 | set_page_private(req->wb_page, (unsigned long)req); |
382 | nfsi->npages++; | 379 | nfsi->npages++; |
383 | kref_get(&req->wb_kref); | 380 | kref_get(&req->wb_kref); |
381 | radix_tree_tag_set(&nfsi->nfs_page_tree, req->wb_index, NFS_PAGE_TAG_LOCKED); | ||
384 | return 0; | 382 | return 0; |
385 | } | 383 | } |
386 | 384 | ||
@@ -596,7 +594,7 @@ static struct nfs_page * nfs_update_request(struct nfs_open_context* ctx, | |||
596 | spin_lock(&inode->i_lock); | 594 | spin_lock(&inode->i_lock); |
597 | req = nfs_page_find_request_locked(page); | 595 | req = nfs_page_find_request_locked(page); |
598 | if (req) { | 596 | if (req) { |
599 | if (!nfs_lock_request_dontget(req)) { | 597 | if (!nfs_set_page_tag_locked(req)) { |
600 | int error; | 598 | int error; |
601 | 599 | ||
602 | spin_unlock(&inode->i_lock); | 600 | spin_unlock(&inode->i_lock); |
@@ -646,7 +644,7 @@ static struct nfs_page * nfs_update_request(struct nfs_open_context* ctx, | |||
646 | || req->wb_page != page | 644 | || req->wb_page != page |
647 | || !nfs_dirty_request(req) | 645 | || !nfs_dirty_request(req) |
648 | || offset > rqend || end < req->wb_offset) { | 646 | || offset > rqend || end < req->wb_offset) { |
649 | nfs_unlock_request(req); | 647 | nfs_clear_page_tag_locked(req); |
650 | return ERR_PTR(-EBUSY); | 648 | return ERR_PTR(-EBUSY); |
651 | } | 649 | } |
652 | 650 | ||
@@ -755,7 +753,7 @@ static void nfs_writepage_release(struct nfs_page *req) | |||
755 | nfs_clear_page_tag_locked(req); | 753 | nfs_clear_page_tag_locked(req); |
756 | } | 754 | } |
757 | 755 | ||
758 | static inline int flush_task_priority(int how) | 756 | static int flush_task_priority(int how) |
759 | { | 757 | { |
760 | switch (how & (FLUSH_HIGHPRI|FLUSH_LOWPRI)) { | 758 | switch (how & (FLUSH_HIGHPRI|FLUSH_LOWPRI)) { |
761 | case FLUSH_HIGHPRI: | 759 | case FLUSH_HIGHPRI: |
@@ -775,15 +773,31 @@ static void nfs_write_rpcsetup(struct nfs_page *req, | |||
775 | unsigned int count, unsigned int offset, | 773 | unsigned int count, unsigned int offset, |
776 | int how) | 774 | int how) |
777 | { | 775 | { |
778 | struct inode *inode; | 776 | struct inode *inode = req->wb_context->path.dentry->d_inode; |
779 | int flags; | 777 | int flags = (how & FLUSH_SYNC) ? 0 : RPC_TASK_ASYNC; |
778 | int priority = flush_task_priority(how); | ||
779 | struct rpc_task *task; | ||
780 | struct rpc_message msg = { | ||
781 | .rpc_argp = &data->args, | ||
782 | .rpc_resp = &data->res, | ||
783 | .rpc_cred = req->wb_context->cred, | ||
784 | }; | ||
785 | struct rpc_task_setup task_setup_data = { | ||
786 | .rpc_client = NFS_CLIENT(inode), | ||
787 | .task = &data->task, | ||
788 | .rpc_message = &msg, | ||
789 | .callback_ops = call_ops, | ||
790 | .callback_data = data, | ||
791 | .flags = flags, | ||
792 | .priority = priority, | ||
793 | }; | ||
780 | 794 | ||
781 | /* Set up the RPC argument and reply structs | 795 | /* Set up the RPC argument and reply structs |
782 | * NB: take care not to mess about with data->commit et al. */ | 796 | * NB: take care not to mess about with data->commit et al. */ |
783 | 797 | ||
784 | data->req = req; | 798 | data->req = req; |
785 | data->inode = inode = req->wb_context->path.dentry->d_inode; | 799 | data->inode = inode = req->wb_context->path.dentry->d_inode; |
786 | data->cred = req->wb_context->cred; | 800 | data->cred = msg.rpc_cred; |
787 | 801 | ||
788 | data->args.fh = NFS_FH(inode); | 802 | data->args.fh = NFS_FH(inode); |
789 | data->args.offset = req_offset(req) + offset; | 803 | data->args.offset = req_offset(req) + offset; |
@@ -791,6 +805,12 @@ static void nfs_write_rpcsetup(struct nfs_page *req, | |||
791 | data->args.pages = data->pagevec; | 805 | data->args.pages = data->pagevec; |
792 | data->args.count = count; | 806 | data->args.count = count; |
793 | data->args.context = req->wb_context; | 807 | data->args.context = req->wb_context; |
808 | data->args.stable = NFS_UNSTABLE; | ||
809 | if (how & FLUSH_STABLE) { | ||
810 | data->args.stable = NFS_DATA_SYNC; | ||
811 | if (!NFS_I(inode)->ncommit) | ||
812 | data->args.stable = NFS_FILE_SYNC; | ||
813 | } | ||
794 | 814 | ||
795 | data->res.fattr = &data->fattr; | 815 | data->res.fattr = &data->fattr; |
796 | data->res.count = count; | 816 | data->res.count = count; |
@@ -798,12 +818,7 @@ static void nfs_write_rpcsetup(struct nfs_page *req, | |||
798 | nfs_fattr_init(&data->fattr); | 818 | nfs_fattr_init(&data->fattr); |
799 | 819 | ||
800 | /* Set up the initial task struct. */ | 820 | /* Set up the initial task struct. */ |
801 | flags = (how & FLUSH_SYNC) ? 0 : RPC_TASK_ASYNC; | 821 | NFS_PROTO(inode)->write_setup(data, &msg); |
802 | rpc_init_task(&data->task, NFS_CLIENT(inode), flags, call_ops, data); | ||
803 | NFS_PROTO(inode)->write_setup(data, how); | ||
804 | |||
805 | data->task.tk_priority = flush_task_priority(how); | ||
806 | data->task.tk_cookie = (unsigned long)inode; | ||
807 | 822 | ||
808 | dprintk("NFS: %5u initiated write call " | 823 | dprintk("NFS: %5u initiated write call " |
809 | "(req %s/%Ld, %u bytes @ offset %Lu)\n", | 824 | "(req %s/%Ld, %u bytes @ offset %Lu)\n", |
@@ -812,16 +827,10 @@ static void nfs_write_rpcsetup(struct nfs_page *req, | |||
812 | (long long)NFS_FILEID(inode), | 827 | (long long)NFS_FILEID(inode), |
813 | count, | 828 | count, |
814 | (unsigned long long)data->args.offset); | 829 | (unsigned long long)data->args.offset); |
815 | } | ||
816 | |||
817 | static void nfs_execute_write(struct nfs_write_data *data) | ||
818 | { | ||
819 | struct rpc_clnt *clnt = NFS_CLIENT(data->inode); | ||
820 | sigset_t oldset; | ||
821 | 830 | ||
822 | rpc_clnt_sigmask(clnt, &oldset); | 831 | task = rpc_run_task(&task_setup_data); |
823 | rpc_execute(&data->task); | 832 | if (!IS_ERR(task)) |
824 | rpc_clnt_sigunmask(clnt, &oldset); | 833 | rpc_put_task(task); |
825 | } | 834 | } |
826 | 835 | ||
827 | /* | 836 | /* |
@@ -868,7 +877,6 @@ static int nfs_flush_multi(struct inode *inode, struct list_head *head, unsigned | |||
868 | wsize, offset, how); | 877 | wsize, offset, how); |
869 | offset += wsize; | 878 | offset += wsize; |
870 | nbytes -= wsize; | 879 | nbytes -= wsize; |
871 | nfs_execute_write(data); | ||
872 | } while (nbytes != 0); | 880 | } while (nbytes != 0); |
873 | 881 | ||
874 | return 0; | 882 | return 0; |
@@ -916,7 +924,6 @@ static int nfs_flush_one(struct inode *inode, struct list_head *head, unsigned i | |||
916 | /* Set up the argument struct */ | 924 | /* Set up the argument struct */ |
917 | nfs_write_rpcsetup(req, data, &nfs_write_full_ops, count, 0, how); | 925 | nfs_write_rpcsetup(req, data, &nfs_write_full_ops, count, 0, how); |
918 | 926 | ||
919 | nfs_execute_write(data); | ||
920 | return 0; | 927 | return 0; |
921 | out_bad: | 928 | out_bad: |
922 | while (!list_empty(head)) { | 929 | while (!list_empty(head)) { |
@@ -932,7 +939,7 @@ static int nfs_flush_one(struct inode *inode, struct list_head *head, unsigned i | |||
932 | static void nfs_pageio_init_write(struct nfs_pageio_descriptor *pgio, | 939 | static void nfs_pageio_init_write(struct nfs_pageio_descriptor *pgio, |
933 | struct inode *inode, int ioflags) | 940 | struct inode *inode, int ioflags) |
934 | { | 941 | { |
935 | int wsize = NFS_SERVER(inode)->wsize; | 942 | size_t wsize = NFS_SERVER(inode)->wsize; |
936 | 943 | ||
937 | if (wsize < PAGE_CACHE_SIZE) | 944 | if (wsize < PAGE_CACHE_SIZE) |
938 | nfs_pageio_init(pgio, inode, nfs_flush_multi, wsize, ioflags); | 945 | nfs_pageio_init(pgio, inode, nfs_flush_multi, wsize, ioflags); |
@@ -1146,19 +1153,33 @@ static void nfs_commit_rpcsetup(struct list_head *head, | |||
1146 | struct nfs_write_data *data, | 1153 | struct nfs_write_data *data, |
1147 | int how) | 1154 | int how) |
1148 | { | 1155 | { |
1149 | struct nfs_page *first; | 1156 | struct nfs_page *first = nfs_list_entry(head->next); |
1150 | struct inode *inode; | 1157 | struct inode *inode = first->wb_context->path.dentry->d_inode; |
1151 | int flags; | 1158 | int flags = (how & FLUSH_SYNC) ? 0 : RPC_TASK_ASYNC; |
1159 | int priority = flush_task_priority(how); | ||
1160 | struct rpc_task *task; | ||
1161 | struct rpc_message msg = { | ||
1162 | .rpc_argp = &data->args, | ||
1163 | .rpc_resp = &data->res, | ||
1164 | .rpc_cred = first->wb_context->cred, | ||
1165 | }; | ||
1166 | struct rpc_task_setup task_setup_data = { | ||
1167 | .task = &data->task, | ||
1168 | .rpc_client = NFS_CLIENT(inode), | ||
1169 | .rpc_message = &msg, | ||
1170 | .callback_ops = &nfs_commit_ops, | ||
1171 | .callback_data = data, | ||
1172 | .flags = flags, | ||
1173 | .priority = priority, | ||
1174 | }; | ||
1152 | 1175 | ||
1153 | /* Set up the RPC argument and reply structs | 1176 | /* Set up the RPC argument and reply structs |
1154 | * NB: take care not to mess about with data->commit et al. */ | 1177 | * NB: take care not to mess about with data->commit et al. */ |
1155 | 1178 | ||
1156 | list_splice_init(head, &data->pages); | 1179 | list_splice_init(head, &data->pages); |
1157 | first = nfs_list_entry(data->pages.next); | ||
1158 | inode = first->wb_context->path.dentry->d_inode; | ||
1159 | 1180 | ||
1160 | data->inode = inode; | 1181 | data->inode = inode; |
1161 | data->cred = first->wb_context->cred; | 1182 | data->cred = msg.rpc_cred; |
1162 | 1183 | ||
1163 | data->args.fh = NFS_FH(data->inode); | 1184 | data->args.fh = NFS_FH(data->inode); |
1164 | /* Note: we always request a commit of the entire inode */ | 1185 | /* Note: we always request a commit of the entire inode */ |
@@ -1170,14 +1191,13 @@ static void nfs_commit_rpcsetup(struct list_head *head, | |||
1170 | nfs_fattr_init(&data->fattr); | 1191 | nfs_fattr_init(&data->fattr); |
1171 | 1192 | ||
1172 | /* Set up the initial task struct. */ | 1193 | /* Set up the initial task struct. */ |
1173 | flags = (how & FLUSH_SYNC) ? 0 : RPC_TASK_ASYNC; | 1194 | NFS_PROTO(inode)->commit_setup(data, &msg); |
1174 | rpc_init_task(&data->task, NFS_CLIENT(inode), flags, &nfs_commit_ops, data); | ||
1175 | NFS_PROTO(inode)->commit_setup(data, how); | ||
1176 | 1195 | ||
1177 | data->task.tk_priority = flush_task_priority(how); | ||
1178 | data->task.tk_cookie = (unsigned long)inode; | ||
1179 | |||
1180 | dprintk("NFS: %5u initiated commit call\n", data->task.tk_pid); | 1196 | dprintk("NFS: %5u initiated commit call\n", data->task.tk_pid); |
1197 | |||
1198 | task = rpc_run_task(&task_setup_data); | ||
1199 | if (!IS_ERR(task)) | ||
1200 | rpc_put_task(task); | ||
1181 | } | 1201 | } |
1182 | 1202 | ||
1183 | /* | 1203 | /* |
@@ -1197,7 +1217,6 @@ nfs_commit_list(struct inode *inode, struct list_head *head, int how) | |||
1197 | /* Set up the argument struct */ | 1217 | /* Set up the argument struct */ |
1198 | nfs_commit_rpcsetup(head, data, how); | 1218 | nfs_commit_rpcsetup(head, data, how); |
1199 | 1219 | ||
1200 | nfs_execute_write(data); | ||
1201 | return 0; | 1220 | return 0; |
1202 | out_bad: | 1221 | out_bad: |
1203 | while (!list_empty(head)) { | 1222 | while (!list_empty(head)) { |
diff --git a/fs/splice.c b/fs/splice.c index 0a0b79b01d05..1577a7391d23 100644 --- a/fs/splice.c +++ b/fs/splice.c | |||
@@ -1031,7 +1031,11 @@ ssize_t splice_direct_to_actor(struct file *in, struct splice_desc *sd, | |||
1031 | goto out_release; | 1031 | goto out_release; |
1032 | } | 1032 | } |
1033 | 1033 | ||
1034 | done: | ||
1034 | pipe->nrbufs = pipe->curbuf = 0; | 1035 | pipe->nrbufs = pipe->curbuf = 0; |
1036 | if (bytes > 0) | ||
1037 | file_accessed(in); | ||
1038 | |||
1035 | return bytes; | 1039 | return bytes; |
1036 | 1040 | ||
1037 | out_release: | 1041 | out_release: |
@@ -1047,16 +1051,11 @@ out_release: | |||
1047 | buf->ops = NULL; | 1051 | buf->ops = NULL; |
1048 | } | 1052 | } |
1049 | } | 1053 | } |
1050 | pipe->nrbufs = pipe->curbuf = 0; | ||
1051 | |||
1052 | /* | ||
1053 | * If we transferred some data, return the number of bytes: | ||
1054 | */ | ||
1055 | if (bytes > 0) | ||
1056 | return bytes; | ||
1057 | 1054 | ||
1058 | return ret; | 1055 | if (!bytes) |
1056 | bytes = ret; | ||
1059 | 1057 | ||
1058 | goto done; | ||
1060 | } | 1059 | } |
1061 | EXPORT_SYMBOL(splice_direct_to_actor); | 1060 | EXPORT_SYMBOL(splice_direct_to_actor); |
1062 | 1061 | ||