s3 onefs: Add missing newlines to debug statements in the onefs module
[ira/wip.git] / source3 / modules / onefs_open.c
index a86d39948d835ecb5690e2876c9cf4abcc6295c9..d628443ef90e113f50f0db3104a01815c29c5fe5 100644 (file)
  * along with this program; if not, see <http://www.gnu.org/licenses/>.
  */
 
+#include "includes.h"
 #include "onefs.h"
+#include "onefs_config.h"
+#include "oplock_onefs.h"
+#include "smbd/globals.h"
 
 extern const struct generic_mapping file_generic_mapping;
-extern bool global_client_failed_oplock_break;
 
-struct deferred_open_record {
-       bool delayed_for_oplocks;
-       bool failed; /* added for onefs_oplocks */
-       struct file_id id;
+struct onefs_fsp_data {
+       uint64_t oplock_callback_id;
 };
 
 static NTSTATUS onefs_create_file_unixpath(connection_struct *conn,
@@ -55,9 +56,9 @@ static NTSTATUS onefs_create_file_unixpath(connection_struct *conn,
                              uint64_t allocation_size,
                              struct security_descriptor *sd,
                              struct ea_list *ea_list,
-
                              files_struct **result,
                              int *pinfo,
+                             struct onefs_fsp_data *fsp_data,
                              SMB_STRUCT_STAT *psbuf);
 
 /****************************************************************************
@@ -88,6 +89,9 @@ static NTSTATUS onefs_open_file(files_struct *fsp,
        int local_flags = flags;
        bool file_existed = VALID_STAT(*psbuf);
        const char *wild;
+       char *base = NULL;
+       char *stream = NULL;
+       int base_fd = -1;
 
        fsp->fh->fd = -1;
        errno = EPERM;
@@ -186,14 +190,42 @@ static NTSTATUS onefs_open_file(files_struct *fsp,
                flags |= O_NOFOLLOW;
        }
 #endif
-       /* Don't request an oplock if oplocks are turned off for the
-        * share. */
-       if (!lp_oplocks(SNUM(conn)))
-               oplock_request = 0;
+       /* Stream handling */
+       if (is_ntfs_stream_name(path)) {
+               status = onefs_split_ntfs_stream_name(talloc_tos(), path,
+                                                     &base, &stream);
+       }
+       /* It's a stream, so pass in the base_fd */
+       if ((conn->fs_capabilities & FILE_NAMED_STREAMS) && stream != NULL) {
+               SMB_ASSERT(fsp->base_fsp);
+
+               /*
+                * We have never seen an oplock taken on a stream, and our
+                * current implementation doesn't support it.  If a request is
+                * seen, log a loud error message and ignore the requested
+                * oplock.
+                */
+               if ((oplock_request & ~SAMBA_PRIVATE_OPLOCK_MASK) !=
+                    NO_OPLOCK) {
+                       DEBUG(0, ("Oplock(%d) being requested on a stream! "
+                                 "Ignoring oplock request: base=%s, "
+                                 "stream=%s\n",
+                                 oplock_request & ~SAMBA_PRIVATE_OPLOCK_MASK,
+                                 base, stream));
+                       /* Recover by requesting NO_OPLOCK instead. */
+                       oplock_request &= SAMBA_PRIVATE_OPLOCK_MASK;
+               }
+
+               DEBUG(10,("Opening a stream: base=%s(%d), stream=%s\n",
+                         base, fsp->base_fsp->fh->fd, stream));
+
+               base_fd = fsp->base_fsp->fh->fd;
+       }
 
        fsp->fh->fd = onefs_sys_create_file(conn,
-                                           -1,
-                                           path,
+                                           base_fd,
+                                           stream != NULL ? stream :
+                                           (base != NULL ? base : path),
                                            access_mask,
                                            open_access_mask,
                                            share_access,
@@ -223,8 +255,8 @@ static NTSTATUS onefs_open_file(files_struct *fsp,
 
                status = map_nt_error_from_unix(errno);
                DEBUG(3,("Error opening file %s (%s) (local_flags=%d) "
-                         "(flags=%d)\n",
-                         path,nt_errstr(status),local_flags,flags));
+                       "(flags=%d)\n",
+                       path, strerror(errno), local_flags, flags));
                return status;
        }
 
@@ -355,15 +387,6 @@ static void defer_open(struct share_mode_lock *lck,
                exit_server("push_deferred_smb_message failed");
        }
        add_deferred_open(lck, req->mid, request_time, state->id);
-
-       /*
-        * Push the MID of this packet on the signing queue.
-        * We only do this once, the first time we push the packet
-        * onto the deferred open queue, as this has a side effect
-        * of incrementing the response sequence number.
-        */
-
-       srv_defer_sign_response(req->mid);
 }
 
 static void schedule_defer_open(struct share_mode_lock *lck,
@@ -388,7 +411,11 @@ static void schedule_defer_open(struct share_mode_lock *lck,
         * measure here in case the other smbd is stuck
         * somewhere else. */
 
-       timeout = timeval_set(OPLOCK_BREAK_TIMEOUT*2, 0);
+       /*
+        * On OneFS, the kernel will always send an oplock_revoked message
+        * before this timeout is hit.
+        */
+       timeout = timeval_set(OPLOCK_BREAK_TIMEOUT*10, 0);
 
        /* Nothing actually uses state.delayed_for_oplocks
           but it's handy to differentiate in debug messages
@@ -396,7 +423,7 @@ static void schedule_defer_open(struct share_mode_lock *lck,
           a 1 second delay for share mode conflicts. */
 
        state.delayed_for_oplocks = True;
-       state.failed = False;
+       state.failed = false;
        state.id = lck->id;
 
        if (!request_timed_out(request_time, timeout)) {
@@ -419,6 +446,7 @@ NTSTATUS onefs_open_file_ntcreate(connection_struct *conn,
                                  struct security_descriptor *sd,
                                  files_struct *fsp,
                                  int *pinfo,
+                                 struct onefs_fsp_data *fsp_data,
                                  SMB_STRUCT_STAT *psbuf)
 {
        int flags=0;
@@ -427,6 +455,7 @@ NTSTATUS onefs_open_file_ntcreate(connection_struct *conn,
        bool def_acl = False;
        bool posix_open = False;
        bool new_file_created = False;
+       bool clear_ads = False;
        struct file_id id;
        mode_t new_unx_mode = (mode_t)0;
        mode_t unx_mode = (mode_t)0;
@@ -441,7 +470,7 @@ NTSTATUS onefs_open_file_ntcreate(connection_struct *conn,
        char *parent_dir;
        const char *newname;
        int granted_oplock;
-       uint64 oplock_waiter;
+       uint64_t oplock_callback_id = 0;
        uint32 createfile_attributes = 0;
 
        ZERO_STRUCT(id);
@@ -485,6 +514,30 @@ NTSTATUS onefs_open_file_ntcreate(connection_struct *conn,
                  create_disposition, create_options, unx_mode,
                  oplock_request));
 
+       /*
+        * Any non-stat-only open has the potential to contend oplocks, which
+        * means to avoid blocking in the kernel (which is unacceptable), the
+        * open must be deferred.  In order to defer opens, req must not be
+        * NULL.  The known cases of calling with a NULL req:
+        *
+        *   1. Open the base file of a stream: Always done stat-only
+        *
+        *   2. Open the stream: Oplocks are disallowed on streams, so an
+        *      oplock will never be contended.
+        *
+        *   3. open_file_fchmod(), which is called from 3 places:
+        *      A. try_chown: Posix acls only. Never called on onefs.
+        *      B. set_ea_dos_attributes: Can't be called from onefs, because
+        *         SMB_VFS_SETXATTR return ENOSYS.
+        *      C. file_set_dos_mode: This would only happen if the "dos
+        *         filemode" smb.conf parameter is set to yes.  We ship with
+        *         it off, but if a customer were to turn it on it would be
+        *         bad.
+        */
+       if (req == NULL && !is_stat_open(access_mask) && !is_ntfs_stream_name(fname)) {
+               smb_panic("NULL req on a non-stat-open!");
+       }
+
        if ((req == NULL) && ((oplock_request & INTERNAL_OPEN_ONLY) == 0)) {
                DEBUG(0, ("No smb request but not an internal only open!\n"));
                return NT_STATUS_INTERNAL_ERROR;
@@ -575,8 +628,6 @@ NTSTATUS onefs_open_file_ntcreate(connection_struct *conn,
                 * (requiring delete access) then recreates it.
                 */
                case FILE_SUPERSEDE:
-                       /* If file exists replace/overwrite. If file doesn't
-                        * exist create. */
                        /**
                         * @todo: Clear all file attributes?
                         * http://www.osronline.com/article.cfm?article=302
@@ -586,12 +637,14 @@ NTSTATUS onefs_open_file_ntcreate(connection_struct *conn,
                         * exist create.
                         */
                        flags2 |= (O_CREAT | O_TRUNC);
+                       clear_ads = true;
                        break;
 
                case FILE_OVERWRITE_IF:
                        /* If file exists replace/overwrite. If file doesn't
                         * exist create. */
                        flags2 |= (O_CREAT | O_TRUNC);
+                       clear_ads = true;
                        break;
 
                case FILE_OPEN:
@@ -617,6 +670,7 @@ NTSTATUS onefs_open_file_ntcreate(connection_struct *conn,
                                return NT_STATUS_OBJECT_NAME_NOT_FOUND;
                        }
                        flags2 |= O_TRUNC;
+                       clear_ads = true;
                        break;
 
                case FILE_CREATE:
@@ -685,6 +739,11 @@ NTSTATUS onefs_open_file_ntcreate(connection_struct *conn,
                open_access_mask |= FILE_WRITE_DATA;
        }
 
+       if (lp_parm_bool(SNUM(fsp->conn), PARM_ONEFS_TYPE,
+               PARM_IGNORE_SACLS, PARM_IGNORE_SACLS_DEFAULT)) {
+               access_mask &= ~SYSTEM_SECURITY_ACCESS;
+       }
+
        DEBUG(10, ("onefs_open_file_ntcreate: fname=%s, after mapping "
                   "open_access_mask=%#x, access_mask=0x%x\n",
                   fname, open_access_mask, access_mask));
@@ -748,19 +807,8 @@ NTSTATUS onefs_open_file_ntcreate(connection_struct *conn,
                 */
                flags2 &= ~(O_CREAT|O_TRUNC);
 
-               /**
-                * XXX: TODO
-                * Apparently this is necessary because we ship with
-                * lp_acl_check_permissions = no.  It is set to no because our
-                * ifs_createfile does the access check correctly.  This check
-                * was added in the last merge, and the question is why is it
-                * necessary?  Check out Bug 25547 and Bug 14596.  The key is
-                * to figure out what case this is covering, and do some
-                * testing to see if it's actually necessary.  If it is, maybe
-                * it should go upstream in open.c.
-                */
-               if (!lp_acl_check_permissions(SNUM(conn)) &&
-                   (access_mask & DELETE_ACCESS)) {
+               /* Deny DELETE_ACCESS explicitly if the share is read only. */
+               if (access_mask & DELETE_ACCESS) {
                        return map_nt_error_from_unix(EACCES);
                }
        }
@@ -829,10 +877,22 @@ NTSTATUS onefs_open_file_ntcreate(connection_struct *conn,
                 (unsigned int)unx_mode, (unsigned int)access_mask,
                 (unsigned int)open_access_mask));
 
-       oplock_waiter = 1; //ifs_oplock_wait_record(mid);
-
-       if (oplock_waiter == 0) {
-               return NT_STATUS_NO_MEMORY;
+       /*
+        * Since the open is guaranteed to be stat only if req == NULL, a
+        * callback record is only needed if req != NULL.
+        */
+       if (req) {
+               SMB_ASSERT(fsp_data);
+               oplock_callback_id = onefs_oplock_wait_record(req->mid);
+               if (oplock_callback_id == 0) {
+                       return NT_STATUS_NO_MEMORY;
+               }
+       } else {
+               /*
+                * It is also already asserted it's either a stream or a
+                * stat-only open at this point.
+                */
+               SMB_ASSERT(fsp->oplock_type == NO_OPLOCK);
        }
 
        /* Do the open. */
@@ -848,7 +908,7 @@ NTSTATUS onefs_open_file_ntcreate(connection_struct *conn,
                                 access_mask,
                                 open_access_mask,
                                 fsp->oplock_type,
-                                oplock_waiter,
+                                oplock_callback_id,
                                 share_access,
                                 create_options,
                                 createfile_attributes,
@@ -900,6 +960,9 @@ NTSTATUS onefs_open_file_ntcreate(connection_struct *conn,
                                goto cleanup_destroy;
                        }
                        /* Waiting for an oplock */
+                       DEBUG(5,("Async createfile because a client has an "
+                                "oplock on %s\n", fname));
+
                        SMB_ASSERT(req);
                        schedule_defer_open(lck, request_time, req);
                        goto cleanup;
@@ -1034,7 +1097,9 @@ NTSTATUS onefs_open_file_ntcreate(connection_struct *conn,
                 * Normal error, for example EACCES
                 */
         cleanup_destroy:
-               //destroy_ifs_callback_record(oplock_waiter);
+               if (oplock_callback_id != 0) {
+                       destroy_onefs_callback_record(oplock_callback_id);
+               }
         cleanup:
                TALLOC_FREE(lck);
                return status;
@@ -1042,9 +1107,12 @@ NTSTATUS onefs_open_file_ntcreate(connection_struct *conn,
 
        fsp->oplock_type = granted_oplock;
 
-       /* XXX uncomment for oplocks */
-       //ifs_set_oplock_callback(oplock_waiter, fsp);
-       //fsp->oplock_callback_id = oplock_waiter;
+       if (oplock_callback_id != 0) {
+               onefs_set_oplock_callback(oplock_callback_id, fsp);
+               fsp_data->oplock_callback_id = oplock_callback_id;
+       } else {
+               SMB_ASSERT(fsp->oplock_type == NO_OPLOCK);
+       }
 
        if (!file_existed) {
                struct timespec old_write_time = get_mtimespec(psbuf);
@@ -1111,6 +1179,16 @@ NTSTATUS onefs_open_file_ntcreate(connection_struct *conn,
 
        SMB_ASSERT(lck != NULL);
 
+       /* Delete streams if create_disposition requires it */
+       if (file_existed && clear_ads && !is_ntfs_stream_name(fname)) {
+               status = delete_all_streams(conn, fname);
+               if (!NT_STATUS_IS_OK(status)) {
+                       TALLOC_FREE(lck);
+                       fd_close(fsp);
+                       return status;
+               }
+       }
+
        /* note that we ignore failure for the following. It is
            basically a hack for NFS, and NFS will never set one of
            these only read them. Nobody but Samba can ever set a deny
@@ -1175,6 +1253,16 @@ NTSTATUS onefs_open_file_ntcreate(connection_struct *conn,
                }
        }
 
+       if (fsp->oplock_type == LEVEL_II_OPLOCK &&
+           (!lp_level2_oplocks(SNUM(conn)) ||
+               !(global_client_caps & CAP_LEVEL_II_OPLOCKS))) {
+
+               DEBUG(5, ("Downgrading level2 oplock on open "
+                         "because level2 oplocks = off\n"));
+
+               release_file_oplock(fsp);
+       }
+
        if (info == FILE_WAS_OVERWRITTEN || info == FILE_WAS_CREATED ||
            info == FILE_WAS_SUPERSEDED) {
                new_file_created = True;
@@ -1552,116 +1640,6 @@ static NTSTATUS onefs_open_directory(connection_struct *conn,
        return NT_STATUS_OK;
 }
 
-/*
- * If a main file is opened for delete, all streams need to be checked for
- * !FILE_SHARE_DELETE. Do this by opening with DELETE_ACCESS.
- * If that works, delete them all by setting the delete on close and close.
- */
-
-static NTSTATUS open_streams_for_delete(connection_struct *conn,
-                                       const char *fname)
-{
-       struct stream_struct *stream_info;
-       files_struct **streams;
-       int i;
-       unsigned int num_streams;
-       TALLOC_CTX *frame = talloc_stackframe();
-       NTSTATUS status;
-
-       status = SMB_VFS_STREAMINFO(conn, NULL, fname, talloc_tos(),
-                                   &num_streams, &stream_info);
-
-       if (NT_STATUS_EQUAL(status, NT_STATUS_NOT_IMPLEMENTED)
-           || NT_STATUS_EQUAL(status, NT_STATUS_OBJECT_NAME_NOT_FOUND)) {
-               DEBUG(10, ("no streams around\n"));
-               TALLOC_FREE(frame);
-               return NT_STATUS_OK;
-       }
-
-       if (!NT_STATUS_IS_OK(status)) {
-               DEBUG(10, ("SMB_VFS_STREAMINFO failed: %s\n",
-                          nt_errstr(status)));
-               goto fail;
-       }
-
-       DEBUG(10, ("open_streams_for_delete found %d streams\n",
-                  num_streams));
-
-       if (num_streams == 0) {
-               TALLOC_FREE(frame);
-               return NT_STATUS_OK;
-       }
-
-       streams = TALLOC_ARRAY(talloc_tos(), files_struct *, num_streams);
-       if (streams == NULL) {
-               DEBUG(0, ("talloc failed\n"));
-               status = NT_STATUS_NO_MEMORY;
-               goto fail;
-       }
-
-       for (i=0; i<num_streams; i++) {
-               char *streamname;
-
-               if (strequal(stream_info[i].name, "::$DATA")) {
-                       streams[i] = NULL;
-                       continue;
-               }
-
-               streamname = talloc_asprintf(talloc_tos(), "%s%s", fname,
-                                            stream_info[i].name);
-
-               if (streamname == NULL) {
-                       DEBUG(0, ("talloc_aprintf failed\n"));
-                       status = NT_STATUS_NO_MEMORY;
-                       goto fail;
-               }
-
-               status = onefs_create_file_unixpath
-                       (conn,                  /* conn */
-                        NULL,                  /* req */
-                        streamname,            /* fname */
-                        DELETE_ACCESS,         /* access_mask */
-                        FILE_SHARE_READ | FILE_SHARE_WRITE
-                        | FILE_SHARE_DELETE,   /* share_access */
-                        FILE_OPEN,             /* create_disposition*/
-                        NTCREATEX_OPTIONS_PRIVATE_STREAM_DELETE, /* create_options */
-                        FILE_ATTRIBUTE_NORMAL, /* file_attributes */
-                        0,                     /* oplock_request */
-                        0,                     /* allocation_size */
-                        NULL,                  /* sd */
-                        NULL,                  /* ea_list */
-                        &streams[i],           /* result */
-                        NULL,                  /* pinfo */
-                        NULL);                 /* psbuf */
-
-               TALLOC_FREE(streamname);
-
-               if (!NT_STATUS_IS_OK(status)) {
-                       DEBUG(10, ("Could not open stream %s: %s\n",
-                                  streamname, nt_errstr(status)));
-                       break;
-               }
-       }
-
-       /*
-        * don't touch the variable "status" beyond this point :-)
-        */
-
-       for (i -= 1 ; i >= 0; i--) {
-               if (streams[i] == NULL) {
-                       continue;
-               }
-
-               DEBUG(10, ("Closing stream # %d, %s\n", i,
-                          streams[i]->fsp_name));
-               close_file(NULL, streams[i], NORMAL_CLOSE);
-       }
-
- fail:
-       TALLOC_FREE(frame);
-       return status;
-}
-
 /*
  * Wrapper around onefs_open_file_ntcreate and onefs_open_directory.
  */
@@ -1679,6 +1657,7 @@ static NTSTATUS onefs_create_file_unixpath(connection_struct *conn,
                                           struct ea_list *ea_list,
                                           files_struct **result,
                                           int *pinfo,
+                                          struct onefs_fsp_data *fsp_data,
                                           SMB_STRUCT_STAT *psbuf)
 {
        SMB_STRUCT_STAT sbuf;
@@ -1711,6 +1690,8 @@ static NTSTATUS onefs_create_file_unixpath(connection_struct *conn,
        }
 
        if (req == NULL) {
+               SMB_ASSERT((oplock_request & ~SAMBA_PRIVATE_OPLOCK_MASK) ==
+                           NO_OPLOCK);
                oplock_request |= INTERNAL_OPEN_ONLY;
        }
 
@@ -1738,8 +1719,7 @@ static NTSTATUS onefs_create_file_unixpath(connection_struct *conn,
        }
 
        if ((conn->fs_capabilities & FILE_NAMED_STREAMS)
-           && is_ntfs_stream_name(fname)
-           && (!(create_options & NTCREATEX_OPTIONS_PRIVATE_STREAM_DELETE))) {
+           && is_ntfs_stream_name(fname)) {
                char *base;
                uint32 base_create_disposition;
 
@@ -1748,8 +1728,8 @@ static NTSTATUS onefs_create_file_unixpath(connection_struct *conn,
                        goto fail;
                }
 
-               status = split_ntfs_stream_name(talloc_tos(), fname,
-                                               &base, NULL);
+               status = onefs_split_ntfs_stream_name(talloc_tos(), fname,
+                                                     &base, NULL);
                if (!NT_STATUS_IS_OK(status)) {
                        DEBUG(10, ("onefs_create_file_unixpath: "
                                  "split_ntfs_stream_name failed: %s\n",
@@ -1772,19 +1752,20 @@ static NTSTATUS onefs_create_file_unixpath(connection_struct *conn,
                        conn,                           /* conn */
                        NULL,                           /* req */
                        base,                           /* fname */
-                       0,                              /* access_mask */
+                       SYNCHRONIZE_ACCESS,             /* access_mask */
                        (FILE_SHARE_READ |
                            FILE_SHARE_WRITE |
                            FILE_SHARE_DELETE),         /* share_access */
                        base_create_disposition,        /* create_disposition*/
                        0,                              /* create_options */
-                       0,                              /* file_attributes */
+                       file_attributes,                /* file_attributes */
                        NO_OPLOCK,                      /* oplock_request */
                        0,                              /* allocation_size */
                        NULL,                           /* sd */
                        NULL,                           /* ea_list */
                        &base_fsp,                      /* result */
                        NULL,                           /* pinfo */
+                       NULL,                           /* fsp_data */
                        NULL);                          /* psbuf */
 
                if (!NT_STATUS_IS_OK(status)) {
@@ -1792,11 +1773,6 @@ static NTSTATUS onefs_create_file_unixpath(connection_struct *conn,
                                  "failed: %s\n", base, nt_errstr(status)));
                        goto fail;
                }
-               /*
-                * we don't need to low level fd: This might conflict with
-                * OneFS streams.
-                */
-               fd_close(base_fsp);
        }
 
        /* Covert generic bits in the security descriptor. */
@@ -1874,6 +1850,7 @@ static NTSTATUS onefs_create_file_unixpath(connection_struct *conn,
                        sd,                             /* sd */
                        fsp,                            /* result */
                        &info,                          /* pinfo */
+                       fsp_data,                       /* fsp_data */
                        &sbuf);                         /* psbuf */
 
                if(!NT_STATUS_IS_OK(status)) {
@@ -1997,6 +1974,13 @@ static NTSTATUS onefs_create_file_unixpath(connection_struct *conn,
        return status;
 }
 
+static void destroy_onefs_fsp_data(void *p_data)
+{
+       struct onefs_fsp_data *fsp_data = (struct onefs_fsp_data *)p_data;
+
+       destroy_onefs_callback_record(fsp_data->oplock_callback_id);
+}
+
 /**
  * SMB_VFS_CREATE_FILE interface to onefs.
  */
@@ -2020,6 +2004,7 @@ NTSTATUS onefs_create_file(vfs_handle_struct *handle,
 {
        connection_struct *conn = handle->conn;
        struct case_semantics_state *case_state = NULL;
+       struct onefs_fsp_data fsp_data = {};
        SMB_STRUCT_STAT sbuf;
        int info = FILE_WAS_OPENED;
        files_struct *fsp = NULL;
@@ -2123,6 +2108,7 @@ NTSTATUS onefs_create_file(vfs_handle_struct *handle,
                ea_list,                                /* ea_list */
                &fsp,                                   /* result */
                &info,                                  /* pinfo */
+               &fsp_data,                              /* fsp_data */
                &sbuf);                                 /* psbuf */
 
        if (!NT_STATUS_IS_OK(status)) {
@@ -2131,6 +2117,26 @@ NTSTATUS onefs_create_file(vfs_handle_struct *handle,
 
        DEBUG(10, ("onefs_create_file: info=%d\n", info));
 
+       /*
+        * Setup private onefs_fsp_data.  Currently the private data struct is
+        * only used to store the oplock_callback_id so that when the file is
+        * closed, the onefs_callback_record can be properly cleaned up in the
+        * oplock_onefs sub-system.
+        */
+       if (fsp) {
+               struct onefs_fsp_data *fsp_data_tmp = NULL;
+               fsp_data_tmp = (struct onefs_fsp_data *)
+                   VFS_ADD_FSP_EXTENSION(handle, fsp, struct onefs_fsp_data,
+                       &destroy_onefs_fsp_data);
+
+               if (fsp_data_tmp == NULL) {
+                       status = NT_STATUS_NO_MEMORY;
+                       goto fail;
+               }
+
+               *fsp_data_tmp = fsp_data;
+       }
+
        *result = fsp;
        if (pinfo != NULL) {
                *pinfo = info;