diff options
author | Linus Torvalds <torvalds@linux-foundation.org> | 2013-05-09 13:24:54 -0400 |
---|---|---|
committer | Linus Torvalds <torvalds@linux-foundation.org> | 2013-05-09 13:24:54 -0400 |
commit | 8cbc95ee748741939222c3d38584a40c92bedcdd (patch) | |
tree | 7fc4ace333ef68e6f17ef531138bf16b711def88 /fs/nfs | |
parent | ea44083a7081ac8d9cc84d49525e6041025a7a17 (diff) | |
parent | c23266d532b4de796a346f57a66587c5db17d27e (diff) |
Merge tag 'nfs-for-3.10-2' of git://git.linux-nfs.org/projects/trondmy/linux-nfs
Pull more NFS client bugfixes from Trond Myklebust:
- Ensure that we match the 'sec=' mount flavour against the server list
- Fix the NFSv4 byte range locking in the presence of delegations
- Ensure that we conform to the NFSv4.1 spec w.r.t. freeing lock
stateids
- Fix a pNFS data server connection race
* tag 'nfs-for-3.10-2' of git://git.linux-nfs.org/projects/trondmy/linux-nfs:
NFS4.1 Fix data server connection race
NFSv3: match sec= flavor against server list
NFSv4.1: Ensure that we free the lock stateid on the server
NFSv4: Convert nfs41_free_stateid to use an asynchronous RPC call
SUNRPC: Don't spam syslog with "Pseudoflavor not found" messages
NFSv4.x: Fix handling of partially delegated locks
Diffstat (limited to 'fs/nfs')
-rw-r--r-- | fs/nfs/nfs4_fs.h | 3 | ||||
-rw-r--r-- | fs/nfs/nfs4filelayout.h | 2 | ||||
-rw-r--r-- | fs/nfs/nfs4filelayoutdev.c | 26 | ||||
-rw-r--r-- | fs/nfs/nfs4proc.c | 119 | ||||
-rw-r--r-- | fs/nfs/nfs4state.c | 11 | ||||
-rw-r--r-- | fs/nfs/nfs4xdr.c | 2 | ||||
-rw-r--r-- | fs/nfs/super.c | 48 |
7 files changed, 169 insertions, 42 deletions
diff --git a/fs/nfs/nfs4_fs.h b/fs/nfs/nfs4_fs.h index 553a83cc4106..a1dd768d0a35 100644 --- a/fs/nfs/nfs4_fs.h +++ b/fs/nfs/nfs4_fs.h | |||
@@ -47,6 +47,8 @@ struct nfs4_minor_version_ops { | |||
47 | const nfs4_stateid *); | 47 | const nfs4_stateid *); |
48 | int (*find_root_sec)(struct nfs_server *, struct nfs_fh *, | 48 | int (*find_root_sec)(struct nfs_server *, struct nfs_fh *, |
49 | struct nfs_fsinfo *); | 49 | struct nfs_fsinfo *); |
50 | int (*free_lock_state)(struct nfs_server *, | ||
51 | struct nfs4_lock_state *); | ||
50 | const struct nfs4_state_recovery_ops *reboot_recovery_ops; | 52 | const struct nfs4_state_recovery_ops *reboot_recovery_ops; |
51 | const struct nfs4_state_recovery_ops *nograce_recovery_ops; | 53 | const struct nfs4_state_recovery_ops *nograce_recovery_ops; |
52 | const struct nfs4_state_maintenance_ops *state_renewal_ops; | 54 | const struct nfs4_state_maintenance_ops *state_renewal_ops; |
@@ -234,7 +236,6 @@ extern int nfs4_proc_fs_locations(struct rpc_clnt *, struct inode *, const struc | |||
234 | extern struct rpc_clnt *nfs4_proc_lookup_mountpoint(struct inode *, struct qstr *, | 236 | extern struct rpc_clnt *nfs4_proc_lookup_mountpoint(struct inode *, struct qstr *, |
235 | struct nfs_fh *, struct nfs_fattr *); | 237 | struct nfs_fh *, struct nfs_fattr *); |
236 | extern int nfs4_proc_secinfo(struct inode *, const struct qstr *, struct nfs4_secinfo_flavors *); | 238 | extern int nfs4_proc_secinfo(struct inode *, const struct qstr *, struct nfs4_secinfo_flavors *); |
237 | extern int nfs4_release_lockowner(struct nfs4_lock_state *); | ||
238 | extern const struct xattr_handler *nfs4_xattr_handlers[]; | 239 | extern const struct xattr_handler *nfs4_xattr_handlers[]; |
239 | extern int nfs4_set_rw_stateid(nfs4_stateid *stateid, | 240 | extern int nfs4_set_rw_stateid(nfs4_stateid *stateid, |
240 | const struct nfs_open_context *ctx, | 241 | const struct nfs_open_context *ctx, |
diff --git a/fs/nfs/nfs4filelayout.h b/fs/nfs/nfs4filelayout.h index b8da95548d3d..235ff952d3c8 100644 --- a/fs/nfs/nfs4filelayout.h +++ b/fs/nfs/nfs4filelayout.h | |||
@@ -70,6 +70,8 @@ struct nfs4_pnfs_ds { | |||
70 | struct list_head ds_addrs; | 70 | struct list_head ds_addrs; |
71 | struct nfs_client *ds_clp; | 71 | struct nfs_client *ds_clp; |
72 | atomic_t ds_count; | 72 | atomic_t ds_count; |
73 | unsigned long ds_state; | ||
74 | #define NFS4DS_CONNECTING 0 /* ds is establishing connection */ | ||
73 | }; | 75 | }; |
74 | 76 | ||
75 | struct nfs4_file_layout_dsaddr { | 77 | struct nfs4_file_layout_dsaddr { |
diff --git a/fs/nfs/nfs4filelayoutdev.c b/fs/nfs/nfs4filelayoutdev.c index 1fe284f01f8b..661a0f611215 100644 --- a/fs/nfs/nfs4filelayoutdev.c +++ b/fs/nfs/nfs4filelayoutdev.c | |||
@@ -775,6 +775,22 @@ nfs4_fl_select_ds_fh(struct pnfs_layout_segment *lseg, u32 j) | |||
775 | return flseg->fh_array[i]; | 775 | return flseg->fh_array[i]; |
776 | } | 776 | } |
777 | 777 | ||
778 | static void nfs4_wait_ds_connect(struct nfs4_pnfs_ds *ds) | ||
779 | { | ||
780 | might_sleep(); | ||
781 | wait_on_bit(&ds->ds_state, NFS4DS_CONNECTING, | ||
782 | nfs_wait_bit_killable, TASK_KILLABLE); | ||
783 | } | ||
784 | |||
785 | static void nfs4_clear_ds_conn_bit(struct nfs4_pnfs_ds *ds) | ||
786 | { | ||
787 | smp_mb__before_clear_bit(); | ||
788 | clear_bit(NFS4DS_CONNECTING, &ds->ds_state); | ||
789 | smp_mb__after_clear_bit(); | ||
790 | wake_up_bit(&ds->ds_state, NFS4DS_CONNECTING); | ||
791 | } | ||
792 | |||
793 | |||
778 | struct nfs4_pnfs_ds * | 794 | struct nfs4_pnfs_ds * |
779 | nfs4_fl_prepare_ds(struct pnfs_layout_segment *lseg, u32 ds_idx) | 795 | nfs4_fl_prepare_ds(struct pnfs_layout_segment *lseg, u32 ds_idx) |
780 | { | 796 | { |
@@ -791,16 +807,22 @@ nfs4_fl_prepare_ds(struct pnfs_layout_segment *lseg, u32 ds_idx) | |||
791 | filelayout_mark_devid_invalid(devid); | 807 | filelayout_mark_devid_invalid(devid); |
792 | return NULL; | 808 | return NULL; |
793 | } | 809 | } |
810 | if (ds->ds_clp) | ||
811 | return ds; | ||
794 | 812 | ||
795 | if (!ds->ds_clp) { | 813 | if (test_and_set_bit(NFS4DS_CONNECTING, &ds->ds_state) == 0) { |
796 | struct nfs_server *s = NFS_SERVER(lseg->pls_layout->plh_inode); | 814 | struct nfs_server *s = NFS_SERVER(lseg->pls_layout->plh_inode); |
797 | int err; | 815 | int err; |
798 | 816 | ||
799 | err = nfs4_ds_connect(s, ds); | 817 | err = nfs4_ds_connect(s, ds); |
800 | if (err) { | 818 | if (err) { |
801 | nfs4_mark_deviceid_unavailable(devid); | 819 | nfs4_mark_deviceid_unavailable(devid); |
802 | return NULL; | 820 | ds = NULL; |
803 | } | 821 | } |
822 | nfs4_clear_ds_conn_bit(ds); | ||
823 | } else { | ||
824 | /* Either ds is connected, or ds is NULL */ | ||
825 | nfs4_wait_ds_connect(ds); | ||
804 | } | 826 | } |
805 | return ds; | 827 | return ds; |
806 | } | 828 | } |
diff --git a/fs/nfs/nfs4proc.c b/fs/nfs/nfs4proc.c index 9da4bd55eb30..8fbc10054115 100644 --- a/fs/nfs/nfs4proc.c +++ b/fs/nfs/nfs4proc.c | |||
@@ -4766,9 +4766,9 @@ static int nfs4_proc_unlck(struct nfs4_state *state, int cmd, struct file_lock * | |||
4766 | if (status != 0) | 4766 | if (status != 0) |
4767 | goto out; | 4767 | goto out; |
4768 | /* Is this a delegated lock? */ | 4768 | /* Is this a delegated lock? */ |
4769 | if (test_bit(NFS_DELEGATED_STATE, &state->flags)) | ||
4770 | goto out; | ||
4771 | lsp = request->fl_u.nfs4_fl.owner; | 4769 | lsp = request->fl_u.nfs4_fl.owner; |
4770 | if (test_bit(NFS_LOCK_INITIALIZED, &lsp->ls_flags) == 0) | ||
4771 | goto out; | ||
4772 | seqid = nfs_alloc_seqid(&lsp->ls_seqid, GFP_KERNEL); | 4772 | seqid = nfs_alloc_seqid(&lsp->ls_seqid, GFP_KERNEL); |
4773 | status = -ENOMEM; | 4773 | status = -ENOMEM; |
4774 | if (seqid == NULL) | 4774 | if (seqid == NULL) |
@@ -5238,9 +5238,8 @@ static const struct rpc_call_ops nfs4_release_lockowner_ops = { | |||
5238 | .rpc_release = nfs4_release_lockowner_release, | 5238 | .rpc_release = nfs4_release_lockowner_release, |
5239 | }; | 5239 | }; |
5240 | 5240 | ||
5241 | int nfs4_release_lockowner(struct nfs4_lock_state *lsp) | 5241 | static int nfs4_release_lockowner(struct nfs_server *server, struct nfs4_lock_state *lsp) |
5242 | { | 5242 | { |
5243 | struct nfs_server *server = lsp->ls_state->owner->so_server; | ||
5244 | struct nfs_release_lockowner_data *data; | 5243 | struct nfs_release_lockowner_data *data; |
5245 | struct rpc_message msg = { | 5244 | struct rpc_message msg = { |
5246 | .rpc_proc = &nfs4_procedures[NFSPROC4_CLNT_RELEASE_LOCKOWNER], | 5245 | .rpc_proc = &nfs4_procedures[NFSPROC4_CLNT_RELEASE_LOCKOWNER], |
@@ -6783,26 +6782,76 @@ static int nfs41_test_stateid(struct nfs_server *server, nfs4_stateid *stateid) | |||
6783 | return err; | 6782 | return err; |
6784 | } | 6783 | } |
6785 | 6784 | ||
6786 | static int _nfs4_free_stateid(struct nfs_server *server, nfs4_stateid *stateid) | 6785 | struct nfs_free_stateid_data { |
6787 | { | 6786 | struct nfs_server *server; |
6788 | struct nfs41_free_stateid_args args = { | 6787 | struct nfs41_free_stateid_args args; |
6789 | .stateid = stateid, | ||
6790 | }; | ||
6791 | struct nfs41_free_stateid_res res; | 6788 | struct nfs41_free_stateid_res res; |
6789 | }; | ||
6790 | |||
6791 | static void nfs41_free_stateid_prepare(struct rpc_task *task, void *calldata) | ||
6792 | { | ||
6793 | struct nfs_free_stateid_data *data = calldata; | ||
6794 | nfs41_setup_sequence(nfs4_get_session(data->server), | ||
6795 | &data->args.seq_args, | ||
6796 | &data->res.seq_res, | ||
6797 | task); | ||
6798 | } | ||
6799 | |||
6800 | static void nfs41_free_stateid_done(struct rpc_task *task, void *calldata) | ||
6801 | { | ||
6802 | struct nfs_free_stateid_data *data = calldata; | ||
6803 | |||
6804 | nfs41_sequence_done(task, &data->res.seq_res); | ||
6805 | |||
6806 | switch (task->tk_status) { | ||
6807 | case -NFS4ERR_DELAY: | ||
6808 | if (nfs4_async_handle_error(task, data->server, NULL) == -EAGAIN) | ||
6809 | rpc_restart_call_prepare(task); | ||
6810 | } | ||
6811 | } | ||
6812 | |||
6813 | static void nfs41_free_stateid_release(void *calldata) | ||
6814 | { | ||
6815 | kfree(calldata); | ||
6816 | } | ||
6817 | |||
6818 | const struct rpc_call_ops nfs41_free_stateid_ops = { | ||
6819 | .rpc_call_prepare = nfs41_free_stateid_prepare, | ||
6820 | .rpc_call_done = nfs41_free_stateid_done, | ||
6821 | .rpc_release = nfs41_free_stateid_release, | ||
6822 | }; | ||
6823 | |||
6824 | static struct rpc_task *_nfs41_free_stateid(struct nfs_server *server, | ||
6825 | nfs4_stateid *stateid, | ||
6826 | bool privileged) | ||
6827 | { | ||
6792 | struct rpc_message msg = { | 6828 | struct rpc_message msg = { |
6793 | .rpc_proc = &nfs4_procedures[NFSPROC4_CLNT_FREE_STATEID], | 6829 | .rpc_proc = &nfs4_procedures[NFSPROC4_CLNT_FREE_STATEID], |
6794 | .rpc_argp = &args, | ||
6795 | .rpc_resp = &res, | ||
6796 | }; | 6830 | }; |
6797 | int status; | 6831 | struct rpc_task_setup task_setup = { |
6832 | .rpc_client = server->client, | ||
6833 | .rpc_message = &msg, | ||
6834 | .callback_ops = &nfs41_free_stateid_ops, | ||
6835 | .flags = RPC_TASK_ASYNC, | ||
6836 | }; | ||
6837 | struct nfs_free_stateid_data *data; | ||
6798 | 6838 | ||
6799 | dprintk("NFS call free_stateid %p\n", stateid); | 6839 | dprintk("NFS call free_stateid %p\n", stateid); |
6800 | nfs41_init_sequence(&args.seq_args, &res.seq_res, 0); | 6840 | data = kmalloc(sizeof(*data), GFP_NOFS); |
6801 | nfs4_set_sequence_privileged(&args.seq_args); | 6841 | if (!data) |
6802 | status = nfs4_call_sync_sequence(server->client, server, &msg, | 6842 | return ERR_PTR(-ENOMEM); |
6803 | &args.seq_args, &res.seq_res); | 6843 | data->server = server; |
6804 | dprintk("NFS reply free_stateid: %d\n", status); | 6844 | nfs4_stateid_copy(&data->args.stateid, stateid); |
6805 | return status; | 6845 | |
6846 | task_setup.callback_data = data; | ||
6847 | |||
6848 | msg.rpc_argp = &data->args; | ||
6849 | msg.rpc_resp = &data->res; | ||
6850 | nfs41_init_sequence(&data->args.seq_args, &data->res.seq_res, 0); | ||
6851 | if (privileged) | ||
6852 | nfs4_set_sequence_privileged(&data->args.seq_args); | ||
6853 | |||
6854 | return rpc_run_task(&task_setup); | ||
6806 | } | 6855 | } |
6807 | 6856 | ||
6808 | /** | 6857 | /** |
@@ -6816,15 +6865,29 @@ static int _nfs4_free_stateid(struct nfs_server *server, nfs4_stateid *stateid) | |||
6816 | */ | 6865 | */ |
6817 | static int nfs41_free_stateid(struct nfs_server *server, nfs4_stateid *stateid) | 6866 | static int nfs41_free_stateid(struct nfs_server *server, nfs4_stateid *stateid) |
6818 | { | 6867 | { |
6819 | struct nfs4_exception exception = { }; | 6868 | struct rpc_task *task; |
6820 | int err; | 6869 | int ret; |
6821 | do { | 6870 | |
6822 | err = _nfs4_free_stateid(server, stateid); | 6871 | task = _nfs41_free_stateid(server, stateid, true); |
6823 | if (err != -NFS4ERR_DELAY) | 6872 | if (IS_ERR(task)) |
6824 | break; | 6873 | return PTR_ERR(task); |
6825 | nfs4_handle_exception(server, err, &exception); | 6874 | ret = rpc_wait_for_completion_task(task); |
6826 | } while (exception.retry); | 6875 | if (!ret) |
6827 | return err; | 6876 | ret = task->tk_status; |
6877 | rpc_put_task(task); | ||
6878 | return ret; | ||
6879 | } | ||
6880 | |||
6881 | static int nfs41_free_lock_state(struct nfs_server *server, struct nfs4_lock_state *lsp) | ||
6882 | { | ||
6883 | struct rpc_task *task; | ||
6884 | |||
6885 | task = _nfs41_free_stateid(server, &lsp->ls_stateid, false); | ||
6886 | nfs4_free_lock_state(server, lsp); | ||
6887 | if (IS_ERR(task)) | ||
6888 | return PTR_ERR(task); | ||
6889 | rpc_put_task(task); | ||
6890 | return 0; | ||
6828 | } | 6891 | } |
6829 | 6892 | ||
6830 | static bool nfs41_match_stateid(const nfs4_stateid *s1, | 6893 | static bool nfs41_match_stateid(const nfs4_stateid *s1, |
@@ -6916,6 +6979,7 @@ static const struct nfs4_minor_version_ops nfs_v4_0_minor_ops = { | |||
6916 | .call_sync = _nfs4_call_sync, | 6979 | .call_sync = _nfs4_call_sync, |
6917 | .match_stateid = nfs4_match_stateid, | 6980 | .match_stateid = nfs4_match_stateid, |
6918 | .find_root_sec = nfs4_find_root_sec, | 6981 | .find_root_sec = nfs4_find_root_sec, |
6982 | .free_lock_state = nfs4_release_lockowner, | ||
6919 | .reboot_recovery_ops = &nfs40_reboot_recovery_ops, | 6983 | .reboot_recovery_ops = &nfs40_reboot_recovery_ops, |
6920 | .nograce_recovery_ops = &nfs40_nograce_recovery_ops, | 6984 | .nograce_recovery_ops = &nfs40_nograce_recovery_ops, |
6921 | .state_renewal_ops = &nfs40_state_renewal_ops, | 6985 | .state_renewal_ops = &nfs40_state_renewal_ops, |
@@ -6933,6 +6997,7 @@ static const struct nfs4_minor_version_ops nfs_v4_1_minor_ops = { | |||
6933 | .call_sync = nfs4_call_sync_sequence, | 6997 | .call_sync = nfs4_call_sync_sequence, |
6934 | .match_stateid = nfs41_match_stateid, | 6998 | .match_stateid = nfs41_match_stateid, |
6935 | .find_root_sec = nfs41_find_root_sec, | 6999 | .find_root_sec = nfs41_find_root_sec, |
7000 | .free_lock_state = nfs41_free_lock_state, | ||
6936 | .reboot_recovery_ops = &nfs41_reboot_recovery_ops, | 7001 | .reboot_recovery_ops = &nfs41_reboot_recovery_ops, |
6937 | .nograce_recovery_ops = &nfs41_nograce_recovery_ops, | 7002 | .nograce_recovery_ops = &nfs41_nograce_recovery_ops, |
6938 | .state_renewal_ops = &nfs41_state_renewal_ops, | 7003 | .state_renewal_ops = &nfs41_state_renewal_ops, |
diff --git a/fs/nfs/nfs4state.c b/fs/nfs/nfs4state.c index 0b32f9483b7a..300d17d85c0e 100644 --- a/fs/nfs/nfs4state.c +++ b/fs/nfs/nfs4state.c | |||
@@ -921,6 +921,7 @@ static struct nfs4_lock_state *nfs4_get_lock_state(struct nfs4_state *state, fl_ | |||
921 | */ | 921 | */ |
922 | void nfs4_put_lock_state(struct nfs4_lock_state *lsp) | 922 | void nfs4_put_lock_state(struct nfs4_lock_state *lsp) |
923 | { | 923 | { |
924 | struct nfs_server *server; | ||
924 | struct nfs4_state *state; | 925 | struct nfs4_state *state; |
925 | 926 | ||
926 | if (lsp == NULL) | 927 | if (lsp == NULL) |
@@ -932,11 +933,13 @@ void nfs4_put_lock_state(struct nfs4_lock_state *lsp) | |||
932 | if (list_empty(&state->lock_states)) | 933 | if (list_empty(&state->lock_states)) |
933 | clear_bit(LK_STATE_IN_USE, &state->flags); | 934 | clear_bit(LK_STATE_IN_USE, &state->flags); |
934 | spin_unlock(&state->state_lock); | 935 | spin_unlock(&state->state_lock); |
936 | server = state->owner->so_server; | ||
935 | if (test_bit(NFS_LOCK_INITIALIZED, &lsp->ls_flags)) { | 937 | if (test_bit(NFS_LOCK_INITIALIZED, &lsp->ls_flags)) { |
936 | if (nfs4_release_lockowner(lsp) == 0) | 938 | struct nfs_client *clp = server->nfs_client; |
937 | return; | 939 | |
938 | } | 940 | clp->cl_mvops->free_lock_state(server, lsp); |
939 | nfs4_free_lock_state(lsp->ls_state->owner->so_server, lsp); | 941 | } else |
942 | nfs4_free_lock_state(server, lsp); | ||
940 | } | 943 | } |
941 | 944 | ||
942 | static void nfs4_fl_copy_lock(struct file_lock *dst, struct file_lock *src) | 945 | static void nfs4_fl_copy_lock(struct file_lock *dst, struct file_lock *src) |
diff --git a/fs/nfs/nfs4xdr.c b/fs/nfs/nfs4xdr.c index 3c79c5878c6d..4be8d135ed61 100644 --- a/fs/nfs/nfs4xdr.c +++ b/fs/nfs/nfs4xdr.c | |||
@@ -2003,7 +2003,7 @@ static void encode_free_stateid(struct xdr_stream *xdr, | |||
2003 | struct compound_hdr *hdr) | 2003 | struct compound_hdr *hdr) |
2004 | { | 2004 | { |
2005 | encode_op_hdr(xdr, OP_FREE_STATEID, decode_free_stateid_maxsz, hdr); | 2005 | encode_op_hdr(xdr, OP_FREE_STATEID, decode_free_stateid_maxsz, hdr); |
2006 | encode_nfs4_stateid(xdr, args->stateid); | 2006 | encode_nfs4_stateid(xdr, &args->stateid); |
2007 | } | 2007 | } |
2008 | #endif /* CONFIG_NFS_V4_1 */ | 2008 | #endif /* CONFIG_NFS_V4_1 */ |
2009 | 2009 | ||
diff --git a/fs/nfs/super.c b/fs/nfs/super.c index 1bb071dca9ab..a366107a7331 100644 --- a/fs/nfs/super.c +++ b/fs/nfs/super.c | |||
@@ -1610,16 +1610,15 @@ out_security_failure: | |||
1610 | /* | 1610 | /* |
1611 | * Select a security flavor for this mount. The selected flavor | 1611 | * Select a security flavor for this mount. The selected flavor |
1612 | * is planted in args->auth_flavors[0]. | 1612 | * is planted in args->auth_flavors[0]. |
1613 | * | ||
1614 | * Returns 0 on success, -EACCES on failure. | ||
1613 | */ | 1615 | */ |
1614 | static void nfs_select_flavor(struct nfs_parsed_mount_data *args, | 1616 | static int nfs_select_flavor(struct nfs_parsed_mount_data *args, |
1615 | struct nfs_mount_request *request) | 1617 | struct nfs_mount_request *request) |
1616 | { | 1618 | { |
1617 | unsigned int i, count = *(request->auth_flav_len); | 1619 | unsigned int i, count = *(request->auth_flav_len); |
1618 | rpc_authflavor_t flavor; | 1620 | rpc_authflavor_t flavor; |
1619 | 1621 | ||
1620 | if (args->auth_flavors[0] != RPC_AUTH_MAXFLAVOR) | ||
1621 | goto out; | ||
1622 | |||
1623 | /* | 1622 | /* |
1624 | * The NFSv2 MNT operation does not return a flavor list. | 1623 | * The NFSv2 MNT operation does not return a flavor list. |
1625 | */ | 1624 | */ |
@@ -1634,6 +1633,25 @@ static void nfs_select_flavor(struct nfs_parsed_mount_data *args, | |||
1634 | goto out_default; | 1633 | goto out_default; |
1635 | 1634 | ||
1636 | /* | 1635 | /* |
1636 | * If the sec= mount option is used, the specified flavor or AUTH_NULL | ||
1637 | * must be in the list returned by the server. | ||
1638 | * | ||
1639 | * AUTH_NULL has a special meaning when it's in the server list - it | ||
1640 | * means that the server will ignore the rpc creds, so any flavor | ||
1641 | * can be used. | ||
1642 | */ | ||
1643 | if (args->auth_flavors[0] != RPC_AUTH_MAXFLAVOR) { | ||
1644 | for (i = 0; i < count; i++) { | ||
1645 | if (args->auth_flavors[0] == request->auth_flavs[i] || | ||
1646 | request->auth_flavs[i] == RPC_AUTH_NULL) | ||
1647 | goto out; | ||
1648 | } | ||
1649 | dfprintk(MOUNT, "NFS: auth flavor %d not supported by server\n", | ||
1650 | args->auth_flavors[0]); | ||
1651 | goto out_err; | ||
1652 | } | ||
1653 | |||
1654 | /* | ||
1637 | * RFC 2623, section 2.7 suggests we SHOULD prefer the | 1655 | * RFC 2623, section 2.7 suggests we SHOULD prefer the |
1638 | * flavor listed first. However, some servers list | 1656 | * flavor listed first. However, some servers list |
1639 | * AUTH_NULL first. Avoid ever choosing AUTH_NULL. | 1657 | * AUTH_NULL first. Avoid ever choosing AUTH_NULL. |
@@ -1653,12 +1671,29 @@ static void nfs_select_flavor(struct nfs_parsed_mount_data *args, | |||
1653 | } | 1671 | } |
1654 | } | 1672 | } |
1655 | 1673 | ||
1674 | /* | ||
1675 | * As a last chance, see if the server list contains AUTH_NULL - | ||
1676 | * if it does, use the default flavor. | ||
1677 | */ | ||
1678 | for (i = 0; i < count; i++) { | ||
1679 | if (request->auth_flavs[i] == RPC_AUTH_NULL) | ||
1680 | goto out_default; | ||
1681 | } | ||
1682 | |||
1683 | dfprintk(MOUNT, "NFS: no auth flavors in common with server\n"); | ||
1684 | goto out_err; | ||
1685 | |||
1656 | out_default: | 1686 | out_default: |
1657 | flavor = RPC_AUTH_UNIX; | 1687 | /* use default if flavor not already set */ |
1688 | flavor = (args->auth_flavors[0] == RPC_AUTH_MAXFLAVOR) ? | ||
1689 | RPC_AUTH_UNIX : args->auth_flavors[0]; | ||
1658 | out_set: | 1690 | out_set: |
1659 | args->auth_flavors[0] = flavor; | 1691 | args->auth_flavors[0] = flavor; |
1660 | out: | 1692 | out: |
1661 | dfprintk(MOUNT, "NFS: using auth flavor %d\n", args->auth_flavors[0]); | 1693 | dfprintk(MOUNT, "NFS: using auth flavor %d\n", args->auth_flavors[0]); |
1694 | return 0; | ||
1695 | out_err: | ||
1696 | return -EACCES; | ||
1662 | } | 1697 | } |
1663 | 1698 | ||
1664 | /* | 1699 | /* |
@@ -1721,8 +1756,7 @@ static int nfs_request_mount(struct nfs_parsed_mount_data *args, | |||
1721 | return status; | 1756 | return status; |
1722 | } | 1757 | } |
1723 | 1758 | ||
1724 | nfs_select_flavor(args, &request); | 1759 | return nfs_select_flavor(args, &request); |
1725 | return 0; | ||
1726 | } | 1760 | } |
1727 | 1761 | ||
1728 | struct dentry *nfs_try_mount(int flags, const char *dev_name, | 1762 | struct dentry *nfs_try_mount(int flags, const char *dev_name, |