smbd: Fix a typo in a few places
[samba.git] / source3 / modules / vfs_tsmsm.c
index 791e8cfcd0662026d9ab8dd4bebe7433344a44f1..89191f7e3ae55be0d38083365fc33754efcacc3e 100644 (file)
@@ -27,7 +27,7 @@
         where <operation> is currently 'offline' to set offline status of the <filepath>
 
   tsmsm: online ratio = ratio to check reported size against actual file size (0.5 by default)
-  tsmsm: attribute name = name of DMAPI attribute that is present when a file is offline. 
+  tsmsm: dmapi attribute = name of DMAPI attribute that is present when a file is offline.
   Default is "IBMobj" (which is what GPFS uses)
 
   The TSMSM VFS module tries to avoid calling expensive DMAPI calls with some heuristics
@@ -39,6 +39,8 @@
  */
 
 #include "includes.h"
+#include "smbd/smbd.h"
+#include "lib/util/tevent_unix.h"
 
 #ifndef USE_DMAPI
 #error "This module requires DMAPI support!"
@@ -72,6 +74,7 @@ struct tsmsm_struct {
        float online_ratio;
        char *hsmscript;
        const char *attrib_name;
+       const char *attrib_value;
 };
 
 static void tsmsm_free_data(void **pptr) {
@@ -86,16 +89,26 @@ static void tsmsm_free_data(void **pptr) {
 static int tsmsm_connect(struct vfs_handle_struct *handle,
                         const char *service,
                         const char *user) {
-       struct tsmsm_struct *tsmd = TALLOC_ZERO_P(handle, struct tsmsm_struct);
+       const struct loadparm_substitution *lp_sub =
+               loadparm_s3_global_substitution();
+       struct tsmsm_struct *tsmd;
        const char *fres;
        const char *tsmname;
-       
+        int ret = SMB_VFS_NEXT_CONNECT(handle, service, user);
+
+       if (ret < 0) {
+               return ret;
+       }
+
+       tsmd = talloc_zero(handle, struct tsmsm_struct);
        if (!tsmd) {
+               SMB_VFS_NEXT_DISCONNECT(handle);
                DEBUG(0,("tsmsm_connect: out of memory!\n"));
                return -1;
        }
 
        if (!dmapi_have_session()) {
+               SMB_VFS_NEXT_DISCONNECT(handle);
                DEBUG(0,("tsmsm_connect: no DMAPI session for Samba is available!\n"));
                TALLOC_FREE(tsmd);
                return -1;
@@ -104,14 +117,21 @@ static int tsmsm_connect(struct vfs_handle_struct *handle,
        tsmname = (handle->param ? handle->param : "tsmsm");
        
        /* Get 'hsm script' and 'dmapi attribute' parameters to tsmd context */
-       tsmd->hsmscript = lp_parm_talloc_string(SNUM(handle->conn), tsmname,
-                                               "hsm script", NULL);
+       tsmd->hsmscript = lp_parm_substituted_string(
+               tsmd, lp_sub, SNUM(handle->conn), tsmname,
+               "hsm script", NULL);
        talloc_steal(tsmd, tsmd->hsmscript);
        
-       tsmd->attrib_name = lp_parm_talloc_string(SNUM(handle->conn), tsmname, 
-                                                 "dmapi attribute", DM_ATTRIB_OBJECT);
+       tsmd->attrib_name = lp_parm_substituted_string(
+               tsmd, lp_sub, SNUM(handle->conn), tsmname,
+               "dmapi attribute", DM_ATTRIB_OBJECT);
        talloc_steal(tsmd, tsmd->attrib_name);
-
+       
+       tsmd->attrib_value = lp_parm_substituted_string(
+               tsmd, lp_sub, SNUM(handle->conn), tsmname,
+               "dmapi value", NULL);
+       talloc_steal(tsmd, tsmd->attrib_value);
+       
        /* retrieve 'online ratio'. In case of error default to FILE_IS_ONLINE_RATIO */
        fres = lp_parm_const_string(SNUM(handle->conn), tsmname, 
                                    "online ratio", NULL);
@@ -129,12 +149,13 @@ static int tsmsm_connect(struct vfs_handle_struct *handle,
         /* Store the private data. */
         SMB_VFS_HANDLE_SET_DATA(handle, tsmd, tsmsm_free_data,
                                 struct tsmsm_struct, return -1);
-        return SMB_VFS_NEXT_CONNECT(handle, service, user); 
+        return 0;
 }
 
 static bool tsmsm_is_offline(struct vfs_handle_struct *handle, 
-                           const char *path,
-                           SMB_STRUCT_STAT *stbuf) {
+                            const struct smb_filename *fname,
+                            SMB_STRUCT_STAT *stbuf)
+{
        struct tsmsm_struct *tsmd = (struct tsmsm_struct *) handle->data;
        const dm_sessid_t *dmsession_id;
        void *dmhandle = NULL;
@@ -143,13 +164,25 @@ static bool tsmsm_is_offline(struct vfs_handle_struct *handle,
        dm_attrname_t dmname;
        int ret, lerrno;
        bool offline;
-       char buf[1];
+       char *buf = NULL;
+       size_t buflen;
+       NTSTATUS status;
+       char *path;
+
+        status = get_full_smb_filename(talloc_tos(), fname, &path);
+        if (!NT_STATUS_IS_OK(status)) {
+                errno = map_errno_from_nt_status(status);
+                return false;
+        }
 
         /* if the file has more than FILE_IS_ONLINE_RATIO of blocks available,
           then assume it is not offline (it may not be 100%, as it could be sparse) */
-       if (512 * (off_t)stbuf->st_blocks >= stbuf->st_size * tsmd->online_ratio) {
-               DEBUG(10,("%s not offline: st_blocks=%ld st_size=%ld online_ratio=%.2f\n", 
-                         path, stbuf->st_blocks, stbuf->st_size, tsmd->online_ratio));
+       if (512 * stbuf->st_ex_blocks >=
+           stbuf->st_ex_size * tsmd->online_ratio) {
+               DEBUG(10,("%s not offline: st_blocks=%llu st_size=%llu "
+                         "online_ratio=%.2f\n", path,
+                         (unsigned long long)stbuf->st_ex_blocks,
+                         (unsigned long long)stbuf->st_ex_size, tsmd->online_ratio));
                return false;
        }
 
@@ -164,7 +197,7 @@ static bool tsmsm_is_offline(struct vfs_handle_struct *handle,
         * become_root() is just as good anyway (tridge) 
         */
 
-       /* Also, AIX has DMAPI but no POSIX capablities support. In this case,
+       /* Also, AIX has DMAPI but no POSIX capabilities support. In this case,
         * we need to be root to do DMAPI manipulations.
         */
        become_root();
@@ -180,11 +213,24 @@ static bool tsmsm_is_offline(struct vfs_handle_struct *handle,
        memset(&dmname, 0, sizeof(dmname));
        strlcpy((char *)&dmname.an_chars[0], tsmd->attrib_name, sizeof(dmname.an_chars));
 
-       lerrno = 0;
+       if (tsmd->attrib_value != NULL) {
+               buflen = strlen(tsmd->attrib_value);
+       } else {
+               buflen = 1;
+       }
+       buf = talloc_zero_size(tsmd, buflen);
+       if (buf == NULL) {
+               DEBUG(0,("out of memory in tsmsm_is_offline -- assuming online (%s)\n", path));
+               errno = ENOMEM;
+               offline = false;
+               goto done;
+       }
 
        do {
+               lerrno = 0;
+
                ret = dm_get_dmattr(*dmsession_id, dmhandle, dmhandle_len, 
-                                   DM_NO_TOKEN, &dmname, sizeof(buf), buf, &rlen);
+                                   DM_NO_TOKEN, &dmname, buflen, buf, &rlen);
                if (ret == -1 && errno == EINVAL) {
                        DEBUG(0, ("Stale DMAPI session, re-creating it.\n"));
                        lerrno = EINVAL;
@@ -201,8 +247,14 @@ static bool tsmsm_is_offline(struct vfs_handle_struct *handle,
                }
        } while (ret == -1 && lerrno == EINVAL);
 
-       /* its offline if the specified DMAPI attribute exists */
-       offline = (ret == 0 || (ret == -1 && errno == E2BIG));
+       /* check if we need a specific attribute value */
+       if (tsmd->attrib_value != NULL) {
+               offline = (ret == 0 && rlen == buflen && 
+                           memcmp(buf, tsmd->attrib_value, buflen) == 0);
+       } else {
+               /* its offline if the specified DMAPI attribute exists */
+               offline = (ret == 0 || (ret == -1 && errno == E2BIG));
+       }
 
        DEBUG(10,("dm_get_dmattr %s ret=%d (%s)\n", path, ret, strerror(errno)));
 
@@ -211,10 +263,24 @@ static bool tsmsm_is_offline(struct vfs_handle_struct *handle,
        dm_handle_free(dmhandle, dmhandle_len); 
 
 done:
+       talloc_free(buf);
        unbecome_root();
        return offline;
 }
 
+static NTSTATUS tsmsm_fget_dos_attributes(struct vfs_handle_struct *handle,
+                                         files_struct *fsp,
+                                         uint32_t *dosmode)
+{
+       bool offline;
+
+       offline = tsmsm_is_offline(handle, fsp->fsp_name, &fsp->fsp_name->st);
+       if (offline) {
+               *dosmode |= FILE_ATTRIBUTE_OFFLINE;
+       }
+
+       return SMB_VFS_NEXT_FGET_DOS_ATTRIBUTES(handle, fsp, dosmode);
+}
 
 static bool tsmsm_aio_force(struct vfs_handle_struct *handle, struct files_struct *fsp)
 {
@@ -226,35 +292,154 @@ static bool tsmsm_aio_force(struct vfs_handle_struct *handle, struct files_struc
           if the file might be offline
        */
        if(SMB_VFS_FSTAT(fsp, &sbuf) == 0) {
-               DEBUG(10,("tsmsm_aio_force st_blocks=%ld st_size=%ld online_ratio=%.2f\n", 
-                         sbuf.st_blocks, sbuf.st_size, tsmd->online_ratio));
-               return !(512 * (off_t)sbuf.st_blocks >= sbuf.st_size * tsmd->online_ratio);
+               DEBUG(10,("tsmsm_aio_force st_blocks=%llu st_size=%llu "
+                         "online_ratio=%.2f\n", (unsigned long long)sbuf.st_ex_blocks,
+                         (unsigned long long)sbuf.st_ex_size, tsmd->online_ratio));
+               return !(512 * sbuf.st_ex_blocks >=
+                        sbuf.st_ex_size * tsmd->online_ratio);
        }
        return false;
 }
 
-static ssize_t tsmsm_aio_return(struct vfs_handle_struct *handle, struct files_struct *fsp, 
-                               SMB_STRUCT_AIOCB *aiocb)
+struct tsmsm_pread_state {
+       struct files_struct *fsp;
+       ssize_t ret;
+       bool was_offline;
+       struct vfs_aio_state vfs_aio_state;
+};
+
+static void tsmsm_pread_done(struct tevent_req *subreq);
+
+static struct tevent_req *tsmsm_pread_send(struct vfs_handle_struct *handle,
+                                          TALLOC_CTX *mem_ctx,
+                                          struct tevent_context *ev,
+                                          struct files_struct *fsp,
+                                          void *data, size_t n, off_t offset)
 {
-       ssize_t result;
+       struct tevent_req *req, *subreq;
+       struct tsmsm_pread_state *state;
 
-       result = SMB_VFS_NEXT_AIO_RETURN(handle, fsp, aiocb);
-       if(result >= 0) {
-               notify_fname(handle->conn, NOTIFY_ACTION_MODIFIED,
+       req = tevent_req_create(mem_ctx, &state, struct tsmsm_pread_state);
+       if (req == NULL) {
+               return NULL;
+       }
+       state->fsp = fsp;
+       state->was_offline = tsmsm_aio_force(handle, fsp);
+       subreq = SMB_VFS_NEXT_PREAD_SEND(state, ev, handle, fsp, data,
+                                        n, offset);
+       if (tevent_req_nomem(subreq, req)) {
+               return tevent_req_post(req, ev);
+       }
+       tevent_req_set_callback(subreq, tsmsm_pread_done, req);
+       return req;
+}
+
+static void tsmsm_pread_done(struct tevent_req *subreq)
+{
+       struct tevent_req *req = tevent_req_callback_data(
+               subreq, struct tevent_req);
+       struct tsmsm_pread_state *state = tevent_req_data(
+               req, struct tsmsm_pread_state);
+
+       state->ret = SMB_VFS_PREAD_RECV(subreq, &state->vfs_aio_state);
+       TALLOC_FREE(subreq);
+       tevent_req_done(req);
+}
+
+static ssize_t tsmsm_pread_recv(struct tevent_req *req,
+                               struct vfs_aio_state *vfs_aio_state)
+{
+       struct tsmsm_pread_state *state = tevent_req_data(
+               req, struct tsmsm_pread_state);
+
+       if (tevent_req_is_unix_error(req, &vfs_aio_state->error)) {
+               return -1;
+       }
+       if (state->ret >= 0 && state->was_offline) {
+               struct files_struct *fsp = state->fsp;
+               notify_fname(fsp->conn, NOTIFY_ACTION_MODIFIED,
                             FILE_NOTIFY_CHANGE_ATTRIBUTES,
-                            fsp->fsp_name);
+                            fsp->fsp_name->base_name);
        }
+       *vfs_aio_state = state->vfs_aio_state;
+       return state->ret;
+}
 
-       return result;
+struct tsmsm_pwrite_state {
+       struct files_struct *fsp;
+       ssize_t ret;
+       bool was_offline;
+       struct vfs_aio_state vfs_aio_state;
+};
+
+static void tsmsm_pwrite_done(struct tevent_req *subreq);
+
+static struct tevent_req *tsmsm_pwrite_send(struct vfs_handle_struct *handle,
+                                           TALLOC_CTX *mem_ctx,
+                                           struct tevent_context *ev,
+                                           struct files_struct *fsp,
+                                           const void *data, size_t n,
+                                           off_t offset)
+{
+       struct tevent_req *req, *subreq;
+       struct tsmsm_pwrite_state *state;
+
+       req = tevent_req_create(mem_ctx, &state, struct tsmsm_pwrite_state);
+       if (req == NULL) {
+               return NULL;
+       }
+       state->fsp = fsp;
+       state->was_offline = tsmsm_aio_force(handle, fsp);
+       subreq = SMB_VFS_NEXT_PWRITE_SEND(state, ev, handle, fsp, data,
+                                         n, offset);
+       if (tevent_req_nomem(subreq, req)) {
+               return tevent_req_post(req, ev);
+       }
+       tevent_req_set_callback(subreq, tsmsm_pwrite_done, req);
+       return req;
+}
+
+static void tsmsm_pwrite_done(struct tevent_req *subreq)
+{
+       struct tevent_req *req = tevent_req_callback_data(
+               subreq, struct tevent_req);
+       struct tsmsm_pwrite_state *state = tevent_req_data(
+               req, struct tsmsm_pwrite_state);
+
+       state->ret = SMB_VFS_PWRITE_RECV(subreq, &state->vfs_aio_state);
+       TALLOC_FREE(subreq);
+       tevent_req_done(req);
+}
+
+static ssize_t tsmsm_pwrite_recv(struct tevent_req *req,
+                                struct vfs_aio_state *vfs_aio_state)
+{
+       struct tsmsm_pwrite_state *state = tevent_req_data(
+               req, struct tsmsm_pwrite_state);
+
+       if (tevent_req_is_unix_error(req, &vfs_aio_state->error)) {
+               return -1;
+       }
+       if (state->ret >= 0 && state->was_offline) {
+               struct files_struct *fsp = state->fsp;
+               notify_fname(fsp->conn, NOTIFY_ACTION_MODIFIED,
+                            FILE_NOTIFY_CHANGE_ATTRIBUTES,
+                            fsp->fsp_name->base_name);
+       }
+       *vfs_aio_state = state->vfs_aio_state;
+       return state->ret;
 }
 
 static ssize_t tsmsm_sendfile(vfs_handle_struct *handle, int tofd, files_struct *fsp, const DATA_BLOB *hdr,
-                             SMB_OFF_T offset, size_t n)
+                             off_t offset, size_t n)
 {
-       bool file_online = tsmsm_aio_force(handle, fsp);
+       bool file_offline = tsmsm_aio_force(handle, fsp);
 
-       if(!file_online) 
-           return ENOSYS;
+       if (file_offline) {
+               DEBUG(10,("tsmsm_sendfile on offline file - rejecting\n"));
+               errno = ENOSYS;
+               return -1;
+       }
            
        return SMB_VFS_NEXT_SENDFILE(handle, tofd, fsp, hdr, offset, n);
 }
@@ -262,7 +447,7 @@ static ssize_t tsmsm_sendfile(vfs_handle_struct *handle, int tofd, files_struct
 /* We do overload pread to allow notification when file becomes online after offline status */
 /* We don't intercept SMB_VFS_READ here because all file I/O now goes through SMB_VFS_PREAD instead */
 static ssize_t tsmsm_pread(struct vfs_handle_struct *handle, struct files_struct *fsp, 
-                          void *data, size_t n, SMB_OFF_T offset) {
+                          void *data, size_t n, off_t offset) {
        ssize_t result;
        bool notify_online = tsmsm_aio_force(handle, fsp);
 
@@ -273,14 +458,14 @@ static ssize_t tsmsm_pread(struct vfs_handle_struct *handle, struct files_struct
            */
                notify_fname(handle->conn, NOTIFY_ACTION_MODIFIED,
                             FILE_NOTIFY_CHANGE_ATTRIBUTES,
-                            fsp->fsp_name);
+                            fsp->fsp_name->base_name);
        }
 
        return result;
 }
 
 static ssize_t tsmsm_pwrite(struct vfs_handle_struct *handle, struct files_struct *fsp, 
-                          void *data, size_t n, SMB_OFF_T offset) {
+                           const void *data, size_t n, off_t offset) {
        ssize_t result;
        bool notify_online = tsmsm_aio_force(handle, fsp);
 
@@ -291,75 +476,98 @@ static ssize_t tsmsm_pwrite(struct vfs_handle_struct *handle, struct files_struc
            */
                notify_fname(handle->conn, NOTIFY_ACTION_MODIFIED,
                             FILE_NOTIFY_CHANGE_ATTRIBUTES,
-                            fsp->fsp_name);
+                            fsp->fsp_name->base_name);
        }
 
        return result;
 }
 
-static int tsmsm_set_offline(struct vfs_handle_struct *handle, 
-                            const char *path) {
+static NTSTATUS tsmsm_set_offline(struct vfs_handle_struct *handle,
+                                 const struct smb_filename *fname)
+{
        struct tsmsm_struct *tsmd = (struct tsmsm_struct *) handle->data;
        int result = 0;
        char *command;
+       NTSTATUS status;
+       char *path;
 
        if (tsmd->hsmscript == NULL) {
                /* no script enabled */
-               DEBUG(1, ("tsmsm_set_offline: No tsmsm:hsmscript configured\n"));
-               return 0;
+               DEBUG(1, ("tsmsm_set_offline: No 'tsmsm:hsm script' configured\n"));
+               return NT_STATUS_OK;
        }
 
+        status = get_full_smb_filename(talloc_tos(), fname, &path);
+        if (!NT_STATUS_IS_OK(status)) {
+               return status;
+        }
+
        /* Now, call the script */
        command = talloc_asprintf(tsmd, "%s offline \"%s\"", tsmd->hsmscript, path);
        if(!command) {
-               DEBUG(1, ("tsmsm_set_offline: can't allocate memory to run hsm script"));
-               return -1;
+               DEBUG(1, ("tsmsm_set_offline: can't allocate memory to run hsm script\n"));
+               return NT_STATUS_NO_MEMORY;
        }
        DEBUG(10, ("tsmsm_set_offline: Running [%s]\n", command));
-       if((result = smbrun(command, NULL)) != 0) {
+       result = smbrun(command, NULL, NULL);
+       if(result != 0) {
                DEBUG(1,("tsmsm_set_offline: Running [%s] returned %d\n", command, result));
+               TALLOC_FREE(command);
+               return NT_STATUS_INTERNAL_ERROR;
        }
        TALLOC_FREE(command);
-       return result;
+       return NT_STATUS_OK;
+}
+
+static NTSTATUS tsmsm_fset_dos_attributes(struct vfs_handle_struct *handle,
+                                         struct files_struct *fsp,
+                                         uint32_t dosmode)
+{
+       NTSTATUS status;
+       uint32_t old_dosmode;
+
+       old_dosmode = fdos_mode(fsp);
+
+       status = SMB_VFS_NEXT_FSET_DOS_ATTRIBUTES(handle, fsp, dosmode);
+       if (!NT_STATUS_IS_OK(status)) {
+               return status;
+       }
+
+       if (!(old_dosmode & FILE_ATTRIBUTE_OFFLINE) &&
+           (dosmode & FILE_ATTRIBUTE_OFFLINE))
+       {
+               return NT_STATUS_OK;
+       }
+
+       return tsmsm_set_offline(handle, fsp->fsp_name);
 }
 
-static uint32_t tsmsm_fs_capabilities(struct vfs_handle_struct *handle)
+static uint32_t tsmsm_fs_capabilities(struct vfs_handle_struct *handle,
+                       enum timestamp_set_resolution *p_ts_res)
 {
-       return SMB_VFS_NEXT_FS_CAPABILITIES(handle) | FILE_SUPPORTS_REMOTE_STORAGE | FILE_SUPPORTS_REPARSE_POINTS;
+       return SMB_VFS_NEXT_FS_CAPABILITIES(handle, p_ts_res) | FILE_SUPPORTS_REMOTE_STORAGE | FILE_SUPPORTS_REPARSE_POINTS;
 }
 
-static vfs_op_tuple vfs_tsmsm_ops[] = {
-
-       /* Disk operations */
-
-       {SMB_VFS_OP(tsmsm_connect),     SMB_VFS_OP_CONNECT,
-        SMB_VFS_LAYER_TRANSPARENT},
-       {SMB_VFS_OP(tsmsm_fs_capabilities),     SMB_VFS_OP_FS_CAPABILITIES,
-        SMB_VFS_LAYER_TRANSPARENT},
-       {SMB_VFS_OP(tsmsm_aio_force),   SMB_VFS_OP_AIO_FORCE,
-        SMB_VFS_LAYER_TRANSPARENT},
-       {SMB_VFS_OP(tsmsm_aio_return),  SMB_VFS_OP_AIO_RETURN,
-        SMB_VFS_LAYER_TRANSPARENT},
-       {SMB_VFS_OP(tsmsm_pread),       SMB_VFS_OP_PREAD,
-        SMB_VFS_LAYER_TRANSPARENT},
-       {SMB_VFS_OP(tsmsm_pwrite),      SMB_VFS_OP_PWRITE,
-        SMB_VFS_LAYER_TRANSPARENT},
-       {SMB_VFS_OP(tsmsm_sendfile),    SMB_VFS_OP_SENDFILE,
-        SMB_VFS_LAYER_TRANSPARENT},
-       {SMB_VFS_OP(tsmsm_is_offline),  SMB_VFS_OP_IS_OFFLINE,
-        SMB_VFS_LAYER_OPAQUE},
-       {SMB_VFS_OP(tsmsm_set_offline), SMB_VFS_OP_SET_OFFLINE,
-        SMB_VFS_LAYER_OPAQUE},
-
-       /* Finish VFS operations definition */
-
-       {SMB_VFS_OP(NULL),              SMB_VFS_OP_NOOP,
-        SMB_VFS_LAYER_NOOP}
+static struct vfs_fn_pointers tsmsm_fns = {
+       .connect_fn = tsmsm_connect,
+       .fs_capabilities_fn = tsmsm_fs_capabilities,
+       .aio_force_fn = tsmsm_aio_force,
+       .pread_fn = tsmsm_pread,
+       .pread_send_fn = tsmsm_pread_send,
+       .pread_recv_fn = tsmsm_pread_recv,
+       .pwrite_fn = tsmsm_pwrite,
+       .pwrite_send_fn = tsmsm_pwrite_send,
+       .pwrite_recv_fn = tsmsm_pwrite_recv,
+       .sendfile_fn = tsmsm_sendfile,
+       .fset_dos_attributes_fn = tsmsm_fset_dos_attributes,
+       .get_dos_attributes_send_fn = vfs_not_implemented_get_dos_attributes_send,
+       .get_dos_attributes_recv_fn = vfs_not_implemented_get_dos_attributes_recv,
+       .fget_dos_attributes_fn = tsmsm_fget_dos_attributes,
 };
 
-NTSTATUS vfs_tsmsm_init(void);
-NTSTATUS vfs_tsmsm_init(void)
+static_decl_vfs;
+NTSTATUS vfs_tsmsm_init(TALLOC_CTX *ctx)
 {
        return smb_register_vfs(SMB_VFS_INTERFACE_VERSION,
-                               "tsmsm", vfs_tsmsm_ops);
+                               "tsmsm", &tsmsm_fns);
 }