/* * Object creation/destruction. */ LinuxSystemRoot* newLinuxSystemRoot(void) { LinuxSystemRoot* object; unsigned m_seq = 0; object = talpa_alloc(sizeof(template_LinuxSystemRoot)); if ( object ) { struct task_struct* inittask; memcpy(object, &template_LinuxSystemRoot, sizeof(template_LinuxSystemRoot)); object->i_ISystemRoot.object = object; talpa_tasklist_lock(); inittask = talpa_find_task_by_pid(1); talpa_tasklist_unlock(); if ( inittask ) { struct fs_struct *init_fs; struct vfsmount *rootmnt; task_lock(inittask); init_fs = inittask->fs; if ( init_fs ) { #if LINUX_VERSION_CODE >= KERNEL_VERSION(2,6,30) #if LINUX_VERSION_CODE >= KERNEL_VERSION(2,6,36) spin_lock(&init_fs->lock); #else write_lock(&init_fs->lock); #endif init_fs->users++; #if LINUX_VERSION_CODE >= KERNEL_VERSION(2,6,36) spin_unlock(&init_fs->lock); #else write_unlock(&init_fs->lock); #endif #else atomic_inc(&init_fs->count); #endif } task_unlock(inittask); if ( init_fs ) { #if LINUX_VERSION_CODE >= KERNEL_VERSION(2,6,36) spin_lock(&init_fs->lock); #else write_lock(&init_fs->lock); #endif restart_mnt: talpa_vfsmount_lock(&m_seq); // locks dcache_lock on 2.4 for (rootmnt = talpa_fs_mnt(init_fs); rootmnt != getParent(rootmnt); rootmnt = getParent(rootmnt)); object->mMnt = mntget(rootmnt); object->mDentry = dget(rootmnt->mnt_root); if (talpa_vfsmount_unlock(&m_seq)) // unlocks dcache_lock on 2.4 { goto restart_mnt; } #if LINUX_VERSION_CODE >= KERNEL_VERSION(2,6,30) init_fs->users--; #else atomic_dec(&init_fs->count); #endif #if LINUX_VERSION_CODE >= KERNEL_VERSION(2,6,36) spin_unlock(&init_fs->lock); #else write_unlock(&init_fs->lock); #endif } } if ( !object->mMnt || !object->mDentry ) { if ( object->mMnt ) { mntput(object->mMnt); } if ( object->mDentry ) { dput(object->mDentry); } talpa_free(object); return NULL; } } return object; }
/** * d_path - return the path of a dentry * @dentry: dentry to report * @vfsmnt: vfsmnt to which the dentry belongs * @root: root dentry * @rootmnt: vfsmnt to which the root dentry belongs * @buffer: buffer to return value in * @buflen: buffer length * * Convert a dentry into an ASCII path name. If the entry has been deleted * the string " (deleted)" is appended. Note that this is ambiguous. * * Returns the buffer or an error code if the path was too long. * * "buflen" should be positive. Caller holds the dcache_lock. */ static char * __talpa_d_path( struct dentry *dentry, struct vfsmount *vfsmnt, struct dentry *root, struct vfsmount *rootmnt, char *buffer, int buflen) { char * end = buffer+buflen; char * retval; int namelen; unsigned m_seq = 1; *--end = '\0'; buflen--; if (!IS_ROOT(dentry) && d_unhashed(dentry)) { buflen -= 10; end -= 10; if (buflen < 0) goto Elong; memcpy(end, " (deleted)", 10); } if (buflen < 1) goto Elong; /* Get '/' right */ retval = end-1; *retval = '/'; for (;;) { struct dentry * parent; if (dentry == root && vfsmnt == rootmnt) break; if (dentry == vfsmnt->mnt_root || IS_ROOT(dentry)) { /* Global root? */ talpa_vfsmount_lock(&m_seq); if (vfsmnt->mnt_parent == vfsmnt) { talpa_vfsmount_unlock(&m_seq); goto global_root; } dentry = vfsmnt->mnt_mountpoint; vfsmnt = vfsmnt->mnt_parent; talpa_vfsmount_unlock(&m_seq); continue; } parent = dentry->d_parent; prefetch(parent); namelen = dentry->d_name.len; buflen -= namelen + 1; if (buflen < 0) goto Elong; end -= namelen; memcpy(end, dentry->d_name.name, namelen); *--end = '/'; retval = end; dentry = parent; } return retval; global_root: namelen = dentry->d_name.len; buflen -= namelen; if (buflen < 0) goto Elong; retval -= namelen-1; /* hit the slash */ memcpy(retval, dentry->d_name.name, namelen); return retval; Elong: return ERR_PTR(-ENAMETOOLONG); }
/** * We iterate all the possible parents of our mount point, * and see if they also have a mount on the same mount point. */ int countPropagationPoints(struct vfsmount* vmnt) { #ifdef TALPA_SHARED_MOUNTS talpa_mount_struct *mnt = real_mount(vmnt); talpa_mount_struct *parent = mnt->mnt_parent; talpa_mount_struct *child = NULL; talpa_mount_struct *m; int ret = 1; unsigned m_seq = 1; #ifdef DEBUG_PROPAGATION_POINTS talpa_mnt_namespace_t* ns; size_t path_size = 0; char* path = talpa_alloc_path_atomic(&path_size); const char* p = absolutePath(mnt->mnt_mountpoint,vfs_mount(parent), path, path_size); if (unlikely( path == NULL )) { warn("talpa_alloc_path failed"); return 0; } ns = mnt->mnt_ns; dbg("PATH START: %s ns=%p ns.ns.inum=%u",p,ns,PROC_INUM_FROM_MNT_NAMESPACE(ns)); ns = parent->mnt_ns; p = absolutePath(parent->mnt_mountpoint,vfs_mount(parent->mnt_parent), path, path_size); dbg("PARENT: %s ns=%p ns.ns.inum=%u",p,ns,PROC_INUM_FROM_MNT_NAMESPACE(ns)); #endif /* DEBUG_PROPAGATION_POINTS */ talpa_vfsmount_lock(&m_seq); /* locks dcache_lock on 2.4 */ /** * Iterate all possible shared/slave destination parents for copies of vmnt */ for (m = propagation_next(parent, parent); m; m = propagation_next(m, parent)) { child = talpa_lookup_mnt_last(vfs_mount(m), mnt->mnt_mountpoint); if (child) { #ifdef DEBUG_PROPAGATION_POINTS /* absolutePath() locks up in d_path() if vfsmount_lock is already held */ p = child->mnt_mountpoint->d_name.name; ns = child->mnt_ns; dbg("CHILD: %s ns=%p ns.ns.inum=%u",p,ns,PROC_INUM_FROM_MNT_NAMESPACE(ns)); #endif /* DEBUG_PROPAGATION_POINTS */ if (list_empty(&child->mnt_mounts)) { ret += 1; } } } talpa_vfsmount_unlock(&m_seq); /* unlocks dcache_lock on 2.4 */ #ifdef DEBUG_PROPAGATION_POINTS talpa_free_path(path); #endif return ret; #else /* ! TALPA_SHARED_MOUNTS */ return 1; #endif /* TALPA_SHARED_MOUNTS */ }
char* talpa__d_namespace_path( struct dentry *dentry, struct vfsmount *vfsmnt, struct dentry *root, struct vfsmount *rootmnt, char *buffer, int buflen, bool* nonRootNamespaceOut, bool* inProcessNamespaceOut) { char* path; #ifdef TALPA_MNT_NAMESPACE struct vfsmount *ns_root_mnt = NULL; struct dentry *ns_root_dentry; unsigned m_seq = 1; struct vfsmount *process_root_mnt; struct dentry *process_root_dentry; struct task_struct* proc; proc = current; if ( likely(proc->fs != NULL) ) { talpa_proc_fs_lock(&proc->fs->lock); process_root_mnt = mntget(talpa_task_root_mnt(proc)); process_root_dentry = dget(talpa_task_root_dentry(proc)); talpa_proc_fs_unlock(&proc->fs->lock); if (inProcessNamespaceOut) { if ( likely( proc->nsproxy != NULL ) ) { *inProcessNamespaceOut = (getNamespaceInfo(vfsmnt) == proc->nsproxy->mnt_ns); } else { *inProcessNamespaceOut = false; } } talpa_vfsmount_lock(&m_seq); if (getNamespaceInfo(process_root_mnt)) { ns_root_mnt = mntget(getNamespaceRoot(process_root_mnt)); } talpa_vfsmount_unlock(&m_seq); dbg("root dentry %s dentry=%p vfsmnt=%p",process_root_dentry->d_name.name,process_root_dentry,process_root_mnt); if(ns_root_mnt) { ns_root_dentry = dget(ns_root_mnt->mnt_root); dbg("ns_root_dentry %s dentry=%p vfsmnt=%p",ns_root_dentry->d_name.name,ns_root_dentry,ns_root_mnt); path = talpa__d_path(dentry, vfsmnt, ns_root_dentry, ns_root_mnt, buffer, buflen, NULL); dbg("talpa__d_namespace_path: found d_namespace_path: %s", path); if (nonRootNamespaceOut) { *nonRootNamespaceOut = (ns_root_mnt != rootmnt); } dput(ns_root_dentry); mntput(ns_root_mnt); } else { path = talpa__d_path(dentry, vfsmnt, process_root_dentry, process_root_mnt, buffer, buflen, nonRootNamespaceOut); dbg("talpa__d_namespace_path: found non namespace path: %s", path); } dput(process_root_dentry); mntput(process_root_mnt); } else { dbg("proc->fs == NULL, cannot get namespace path"); if (inProcessNamespaceOut) { *inProcessNamespaceOut = false; } #else /* !TALPA_MNT_NAMESPACE */ { if (inProcessNamespaceOut) { *inProcessNamespaceOut = true; } #endif path = talpa__d_path(dentry, vfsmnt, root, rootmnt, buffer, buflen, nonRootNamespaceOut); dbg("talpa__d_namespace_path: found non namespace path: %s", path); } return path; } #ifdef TALPA_MNT_NAMESPACE static void debugPathWalk( struct dentry *dentry, struct vfsmount *vfsmnt, struct dentry *root, struct vfsmount *rootmnt) { /* Debug - try and evaluate roots */ int count = 50; struct dentry *td = dentry; struct vfsmount *temp_vfsmnt = vfsmnt; err("DEBUG: expected root node %s dentry=%p vfsmnt=%p",root->d_name.name,root,rootmnt); while (td != root || temp_vfsmnt != rootmnt) { count--; if (count == 0) { err("DEBUG: reached count limit!"); break; } err("DEBUG: examining %s %p",td->d_name.name,td); if (td == temp_vfsmnt->mnt_root || IS_ROOT(td)) { struct vfsmount *temp2_vfsmnt = getParent(temp_vfsmnt); if (td == temp_vfsmnt->mnt_root) { err("DEBUG: found root dentry td == temp_vfsmnt->mnt_root %p",td); } if (IS_ROOT(td)) { err("DEBUG: found root dentry IS_ROOT(td) %p",td); } err("DEBUG: going to parent: %p -> %p",temp_vfsmnt,temp2_vfsmnt); if (temp_vfsmnt != temp2_vfsmnt) { td = getVfsMountPoint(temp_vfsmnt); err("DEBUG: going to mountpoint %s dentry=%p", td->d_name.name, td); temp_vfsmnt = temp2_vfsmnt; } else { err("DEBUG: Got to temp_vfsmnt = temp2_vfsmnt!"); } } if (td == td->d_parent) { err("DEBUG: td == td->d_parent"); break; } else if (td->d_parent == NULL) { err("DEBUG: td->d_parent == NULL"); break; } td = td->d_parent; } err("DEBUG: actual root node %s dentry=%p vfsmnt=%p",td->d_name.name,td,temp_vfsmnt); if (td == root && temp_vfsmnt == rootmnt) { err("DEBUG: Found the correct root"); } else { err("DEBUG: Found wrong root td=%p (name=%s) vfsmnt=%p", td, td->d_name.name, temp_vfsmnt); err("DEBUG: Expected root=%p (name=%s) vfsmnt=%p", root, root->d_name.name, rootmnt); } }
int iterateFilesystems(struct vfsmount* root, int (*callback) (struct vfsmount* mnt, unsigned long flags, bool fromMount)) { talpa_mount_struct *mnt, *nextmnt, *prevmnt; struct list_head *nexthead = NULL; int ret; unsigned m_seq = 1; mnt = real_mount(root); talpa_mntget(mnt); /* Take extra reference count for the loop */ do { struct vfsmount* vfsmnt = vfs_mount(mnt); dbg("VFSMNT: 0x%p (at 0x%p), sb: 0x%p, dev: %s, flags: 0x%lx, fs: %s", mnt, mnt->mnt_parent, vfsmnt->mnt_sb, mnt->mnt_devname, vfsmnt->mnt_sb->s_flags, vfsmnt->mnt_sb->s_type->name); ret = callback(vfsmnt, vfsmnt->mnt_sb->s_flags, false); if (ret) { break; } talpa_vfsmount_lock(&m_seq); /* locks dcache_lock on 2.4 */ /* Go down the tree for a child if there is one */ if ( !list_empty(&mnt->mnt_mounts) ) { nextmnt = list_entry(mnt->mnt_mounts.next, talpa_mount_struct, mnt_child); } else { nextmnt = mnt; /* If no children, go up until we found some. Abort on root. */ while ( nextmnt != nextmnt->mnt_parent ) { nexthead = nextmnt->mnt_child.next; /* Take next child if available */ if ( nexthead != &nextmnt->mnt_parent->mnt_mounts ) { break; } /* Otherwise go up the tree */ nextmnt = nextmnt->mnt_parent; } /* Abort if we are at the root */ if ( nextmnt == nextmnt->mnt_parent ) { talpa_vfsmount_unlock(&m_seq); /* unlocks dcache_lock on 2.4 */ talpa_mntput(mnt); break; } /* Take next mount from the list */ nextmnt = list_entry(nexthead, talpa_mount_struct, mnt_child); } talpa_mntget(nextmnt); prevmnt = mnt; mnt = nextmnt; talpa_vfsmount_unlock(&m_seq); /* unlocks dcache_lock on 2.4 */ talpa_mntput(prevmnt); } while (mnt); /* Don't mntput root as we didn't take a reference for ourselves */ return ret; }