NFS: Introduce a vector of migration recovery ops
[linux-2.6-block.git] / fs / nfs / nfs4proc.c
index 989bb9d3074d0d4c88d63a486f05491423b090d4..2aacd1357dc52ad1449d050a2fc6a1480bd8003a 100644 (file)
@@ -912,6 +912,7 @@ struct nfs4_opendata {
        struct iattr attrs;
        unsigned long timestamp;
        unsigned int rpc_done : 1;
+       unsigned int file_created : 1;
        unsigned int is_recover : 1;
        int rpc_status;
        int cancelled;
@@ -1317,31 +1318,24 @@ _nfs4_opendata_reclaim_to_nfs4_state(struct nfs4_opendata *data)
        int ret;
 
        if (!data->rpc_done) {
-               ret = data->rpc_status;
-               goto err;
+               if (data->rpc_status) {
+                       ret = data->rpc_status;
+                       goto err;
+               }
+               /* cached opens have already been processed */
+               goto update;
        }
 
-       ret = -ESTALE;
-       if (!(data->f_attr.valid & NFS_ATTR_FATTR_TYPE) ||
-           !(data->f_attr.valid & NFS_ATTR_FATTR_FILEID) ||
-           !(data->f_attr.valid & NFS_ATTR_FATTR_CHANGE))
-               goto err;
-
-       ret = -ENOMEM;
-       state = nfs4_get_open_state(inode, data->owner);
-       if (state == NULL)
-               goto err;
-
        ret = nfs_refresh_inode(inode, &data->f_attr);
        if (ret)
                goto err;
 
-       nfs_setsecurity(inode, &data->f_attr, data->f_label);
-
        if (data->o_res.delegation_type != 0)
                nfs4_opendata_check_deleg(data, state);
+update:
        update_open_stateid(state, &data->o_res.stateid, NULL,
                            data->o_arg.fmode);
+       atomic_inc(&state->count);
 
        return state;
 err:
@@ -1946,8 +1940,13 @@ static int _nfs4_proc_open(struct nfs4_opendata *data)
 
        nfs_fattr_map_and_free_names(server, &data->f_attr);
 
-       if (o_arg->open_flags & O_CREAT)
+       if (o_arg->open_flags & O_CREAT) {
                update_changeattr(dir, &o_res->cinfo);
+               if (o_arg->open_flags & O_EXCL)
+                       data->file_created = 1;
+               else if (o_res->cinfo.before != o_res->cinfo.after)
+                       data->file_created = 1;
+       }
        if ((o_res->rflags & NFS4_OPEN_RESULT_LOCKTYPE_POSIX) == 0)
                server->caps &= ~NFS_CAP_POSIX_LOCK;
        if(o_res->rflags & NFS4_OPEN_RESULT_CONFIRM) {
@@ -2191,7 +2190,8 @@ static int _nfs4_do_open(struct inode *dir,
                        struct nfs_open_context *ctx,
                        int flags,
                        struct iattr *sattr,
-                       struct nfs4_label *label)
+                       struct nfs4_label *label,
+                       int *opened)
 {
        struct nfs4_state_owner  *sp;
        struct nfs4_state     *state = NULL;
@@ -2261,6 +2261,8 @@ static int _nfs4_do_open(struct inode *dir,
                        nfs_setsecurity(state->inode, opendata->o_res.f_attr, olabel);
                }
        }
+       if (opendata->file_created)
+               *opened |= FILE_CREATED;
 
        if (pnfs_use_threshold(ctx_th, opendata->f_attr.mdsthreshold, server))
                *ctx_th = opendata->f_attr.mdsthreshold;
@@ -2289,7 +2291,8 @@ static struct nfs4_state *nfs4_do_open(struct inode *dir,
                                        struct nfs_open_context *ctx,
                                        int flags,
                                        struct iattr *sattr,
-                                       struct nfs4_label *label)
+                                       struct nfs4_label *label,
+                                       int *opened)
 {
        struct nfs_server *server = NFS_SERVER(dir);
        struct nfs4_exception exception = { };
@@ -2297,7 +2300,7 @@ static struct nfs4_state *nfs4_do_open(struct inode *dir,
        int status;
 
        do {
-               status = _nfs4_do_open(dir, ctx, flags, sattr, label);
+               status = _nfs4_do_open(dir, ctx, flags, sattr, label, opened);
                res = ctx->state;
                trace_nfs4_open_file(ctx, flags, status);
                if (status == 0)
@@ -2659,7 +2662,8 @@ out:
 }
 
 static struct inode *
-nfs4_atomic_open(struct inode *dir, struct nfs_open_context *ctx, int open_flags, struct iattr *attr)
+nfs4_atomic_open(struct inode *dir, struct nfs_open_context *ctx,
+               int open_flags, struct iattr *attr, int *opened)
 {
        struct nfs4_state *state;
        struct nfs4_label l = {0, 0, 0, NULL}, *label = NULL;
@@ -2667,7 +2671,7 @@ nfs4_atomic_open(struct inode *dir, struct nfs_open_context *ctx, int open_flags
        label = nfs4_label_init_security(dir, ctx->dentry, attr, &l);
 
        /* Protect against concurrent sillydeletes */
-       state = nfs4_do_open(dir, ctx, open_flags, attr, label);
+       state = nfs4_do_open(dir, ctx, open_flags, attr, label, opened);
 
        nfs4_label_release_security(label);
 
@@ -3332,6 +3336,7 @@ nfs4_proc_create(struct inode *dir, struct dentry *dentry, struct iattr *sattr,
        struct nfs4_label l, *ilabel = NULL;
        struct nfs_open_context *ctx;
        struct nfs4_state *state;
+       int opened = 0;
        int status = 0;
 
        ctx = alloc_nfs_open_context(dentry, FMODE_READ);
@@ -3341,7 +3346,7 @@ nfs4_proc_create(struct inode *dir, struct dentry *dentry, struct iattr *sattr,
        ilabel = nfs4_label_init_security(dir, dentry, sattr, &l);
 
        sattr->ia_mode &= ~current_umask();
-       state = nfs4_do_open(dir, ctx, flags, sattr, ilabel);
+       state = nfs4_do_open(dir, ctx, flags, sattr, ilabel, &opened);
        if (IS_ERR(state)) {
                status = PTR_ERR(state);
                goto out;
@@ -5094,6 +5099,7 @@ static int _nfs4_proc_getlk(struct nfs4_state *state, int cmd, struct file_lock
                        status = 0;
        }
        request->fl_ops->fl_release_private(request);
+       request->fl_ops = NULL;
 out:
        return status;
 }
@@ -7564,8 +7570,10 @@ nfs41_find_root_sec(struct nfs_server *server, struct nfs_fh *fhandle,
 {
        int err;
        struct page *page;
-       rpc_authflavor_t flavor;
+       rpc_authflavor_t flavor = RPC_AUTH_MAXFLAVOR;
        struct nfs4_secinfo_flavors *flavors;
+       struct nfs4_secinfo4 *secinfo;
+       int i;
 
        page = alloc_page(GFP_KERNEL);
        if (!page) {
@@ -7587,9 +7595,31 @@ nfs41_find_root_sec(struct nfs_server *server, struct nfs_fh *fhandle,
        if (err)
                goto out_freepage;
 
-       flavor = nfs_find_best_sec(flavors);
-       if (err == 0)
-               err = nfs4_lookup_root_sec(server, fhandle, info, flavor);
+       for (i = 0; i < flavors->num_flavors; i++) {
+               secinfo = &flavors->flavors[i];
+
+               switch (secinfo->flavor) {
+               case RPC_AUTH_NULL:
+               case RPC_AUTH_UNIX:
+               case RPC_AUTH_GSS:
+                       flavor = rpcauth_get_pseudoflavor(secinfo->flavor,
+                                       &secinfo->flavor_info);
+                       break;
+               default:
+                       flavor = RPC_AUTH_MAXFLAVOR;
+                       break;
+               }
+
+               if (flavor != RPC_AUTH_MAXFLAVOR) {
+                       err = nfs4_lookup_root_sec(server, fhandle,
+                                                  info, flavor);
+                       if (!err)
+                               break;
+               }
+       }
+
+       if (flavor == RPC_AUTH_MAXFLAVOR)
+               err = -EPERM;
 
 out_freepage:
        put_page(page);
@@ -7851,6 +7881,14 @@ static const struct nfs4_state_maintenance_ops nfs41_state_renewal_ops = {
 };
 #endif
 
+static const struct nfs4_mig_recovery_ops nfs40_mig_recovery_ops = {
+};
+
+#if defined(CONFIG_NFS_V4_1)
+static const struct nfs4_mig_recovery_ops nfs41_mig_recovery_ops = {
+};
+#endif /* CONFIG_NFS_V4_1 */
+
 static const struct nfs4_minor_version_ops nfs_v4_0_minor_ops = {
        .minor_version = 0,
        .init_caps = NFS_CAP_READDIRPLUS
@@ -7866,6 +7904,7 @@ static const struct nfs4_minor_version_ops nfs_v4_0_minor_ops = {
        .reboot_recovery_ops = &nfs40_reboot_recovery_ops,
        .nograce_recovery_ops = &nfs40_nograce_recovery_ops,
        .state_renewal_ops = &nfs40_state_renewal_ops,
+       .mig_recovery_ops = &nfs40_mig_recovery_ops,
 };
 
 #if defined(CONFIG_NFS_V4_1)
@@ -7886,6 +7925,7 @@ static const struct nfs4_minor_version_ops nfs_v4_1_minor_ops = {
        .reboot_recovery_ops = &nfs41_reboot_recovery_ops,
        .nograce_recovery_ops = &nfs41_nograce_recovery_ops,
        .state_renewal_ops = &nfs41_state_renewal_ops,
+       .mig_recovery_ops = &nfs41_mig_recovery_ops,
 };
 #endif