diff --git a/Makefile b/Makefile index 31adc46..c04eba0 100644 --- a/Makefile +++ b/Makefile @@ -19,12 +19,13 @@ EXTRA_CFLAGS += ${HEPUNION_DEF_CONFIG} MakeMod = ${MAKE} -C ${KDIR} M=${CURDIR}/fs/hepunion EXTRA_CFLAGS="${EXTRA_CFLAGS}" -all: hepunion.ko usr/include/linux/hepunion_type.h +all: hepunion.ko include/linux/hepunion_type.h clean: ${MakeMod} $@ find . -type f -name '*~' | xargs -r ${RM} ${RM} -r hepunion.ko usr + ${MAKE} -C tests clean install: fs/hepunion/hepunion.ko ${MakeMod} modules_install @@ -50,3 +51,8 @@ usr/include/linux/hepunion_type.h: -f Makefile \ obj=${d}/include/linux dst=${d}/usr/include/linux test -s $@ + +tests: + ${MAKE} -C tests + +.PHONY: tests diff --git a/fs/hepunion/cow.c b/fs/hepunion/cow.c index 128b7c0..04b4324 100644 --- a/fs/hepunion/cow.c +++ b/fs/hepunion/cow.c @@ -33,10 +33,9 @@ #include "hepunion.h" static int copy_child(void *buf, const char *name, int namlen, loff_t offset, u64 ino, unsigned d_type) { - char tmp_path[PATH_MAX]; - char tmp_ro_path[PATH_MAX]; - char tmp_rw_path[PATH_MAX]; + int ret = -ENOMEM; struct readdir_context *ctx = (struct readdir_context*)buf; + char *tmp_path = NULL, *tmp_ro_path = NULL, *tmp_rw_path = NULL; pr_info("copy_child: %p, %s, %d, %llx, %llx, %d\n", buf, name, namlen, offset, ino, d_type); @@ -45,29 +44,62 @@ static int copy_child(void *buf, const char *name, int namlen, loff_t offset, u6 return 0; } + /* Dynamic allocations to avoid stack errors + * TODO: Optimize later on with lookaside allocations + */ + tmp_path = kmalloc(PATH_MAX, GFP_KERNEL); + if(!tmp_path) { + return -ENOMEM; + } + + tmp_ro_path = kmalloc(PATH_MAX, GFP_KERNEL); + if(!tmp_ro_path) { + goto cleanup; + } + + tmp_rw_path = kmalloc(PATH_MAX, GFP_KERNEL); + if(!tmp_rw_path) { + goto cleanup; + } + if (snprintf(tmp_ro_path, PATH_MAX, "%s/%s", ctx->ro_path, name) > PATH_MAX) { - return -ENAMETOOLONG; + ret = -ENAMETOOLONG; + goto cleanup; } if (snprintf(tmp_path, PATH_MAX, "%s/%s", ctx->path, name) > PATH_MAX) { - return -ENAMETOOLONG; + ret = -ENAMETOOLONG; + goto cleanup; } /* Recreate everything recursively */ - return create_copyup(tmp_path, tmp_ro_path, tmp_rw_path, ctx->context); + ret = create_copyup(tmp_path, tmp_ro_path, tmp_rw_path, ctx->context); + +cleanup: + if (tmp_path) { + kfree(tmp_path); + } + + if (tmp_ro_path) { + kfree(tmp_ro_path); + } + + if (tmp_rw_path) { + kfree(tmp_rw_path); + } + + return ret; } int create_copyup(const char *path, const char *ro_path, char *rw_path, struct hepunion_sb_info *context) { - /* Once here, two things are sure: + /* Once here, two things are sure: * RO exists, RW does not */ - int err, len; - char tmp[PATH_MAX]; - char me_path[PATH_MAX]; + int err = -ENOMEM, len; + char *tmp = NULL, *me_path = NULL, *buf = NULL; struct kstat kstbuf; struct file *ro_fd, *rw_fd; ssize_t rcount; - char buf[MAXSIZE]; struct dentry *dentry; struct iattr attr; struct readdir_context ctx; @@ -75,16 +107,31 @@ int create_copyup(const char *path, const char *ro_path, char *rw_path, struct h pr_info("create_copyup: %s, %s, %s, %p\n", path, ro_path, rw_path, context); + tmp = kmalloc(PATH_MAX, GFP_KERNEL); + if(!tmp) { + return -ENOMEM; + } + + me_path = kmalloc(PATH_MAX, GFP_KERNEL); + if(!me_path) { + goto cleanup; + } + + buf = kmalloc(MAXSIZE, GFP_KERNEL); + if(!buf) { + goto cleanup; + } + /* Get file attributes */ err = get_file_attr_worker(path, ro_path, context, &kstbuf); if (err < 0) { - return err; + goto cleanup; } /* Copyup dirs if required */ err = find_path(path, rw_path, context); if (err < 0) { - return err; + goto cleanup; } /* Handle the file properly */ @@ -94,14 +141,15 @@ int create_copyup(const char *path, const char *ro_path, char *rw_path, struct h /* Read destination */ len = readlink(ro_path, tmp, context, sizeof(tmp) - 1); if (len < 0) { - return len; + err = len; + goto cleanup; } tmp[len] = '\0'; /* And create a new symbolic link */ err = symlink_worker(tmp, rw_path, context); if (err < 0) { - return err; + goto cleanup; } break; @@ -110,14 +158,16 @@ int create_copyup(const char *path, const char *ro_path, char *rw_path, struct h /* Open read only... */ ro_fd = open_worker(ro_path, context, O_RDONLY); if (IS_ERR(ro_fd)) { - return PTR_ERR(ro_fd); + err = PTR_ERR(ro_fd); + goto cleanup; } /* Then, create copyup... */ rw_fd = open_worker_2(rw_path, context, O_CREAT | O_WRONLY | O_EXCL, kstbuf.mode); if (IS_ERR(rw_fd)) { filp_close(ro_fd, NULL); - return PTR_ERR(rw_fd); + err = PTR_ERR(rw_fd); + goto cleanup; } @@ -140,7 +190,8 @@ int create_copyup(const char *path, const char *ro_path, char *rw_path, struct h /* Delete copyup */ unlink(rw_path, context); - return rcount; + err = rcount; + goto cleanup; } else if (rcount == 0) { break; } @@ -159,7 +210,8 @@ int create_copyup(const char *path, const char *ro_path, char *rw_path, struct h /* Delete copyup */ unlink(rw_path, context); - return rcount; + err = rcount; + goto cleanup; } } } @@ -177,7 +229,7 @@ int create_copyup(const char *path, const char *ro_path, char *rw_path, struct h /* Recreate a node */ err = mknod_worker(rw_path, context, kstbuf.mode, kstbuf.rdev); if (err < 0) { - return err; + goto cleanup; } break; @@ -185,14 +237,15 @@ int create_copyup(const char *path, const char *ro_path, char *rw_path, struct h /* Recreate a dir */ err = mkdir_worker(rw_path, context, kstbuf.mode); if (err < 0) { - return err; + goto cleanup; } /* Recreate dir structure */ ro_fd = open_worker(ro_path, context, O_RDONLY); if (IS_ERR(ro_fd)) { unlink(rw_path, context); - return PTR_ERR(ro_fd); + err = PTR_ERR(ro_fd); + goto cleanup; } /* Create a copyup of each file & dir */ @@ -207,7 +260,7 @@ int create_copyup(const char *path, const char *ro_path, char *rw_path, struct h /* Handle failure */ if (err < 0) { unlink(rw_path, context); - return err; + goto cleanup; } break; @@ -216,7 +269,7 @@ int create_copyup(const char *path, const char *ro_path, char *rw_path, struct h /* Recreate FIFO */ err = mkfifo_worker(rw_path, context, kstbuf.mode); if (err < 0) { - return err; + goto cleanup; } break; } @@ -224,7 +277,8 @@ int create_copyup(const char *path, const char *ro_path, char *rw_path, struct h /* Get dentry for the copyup */ dentry = get_path_dentry(rw_path, context, LOOKUP_REVAL); if (IS_ERR(dentry)) { - return PTR_ERR(dentry); + err = PTR_ERR(dentry); + goto cleanup; } /* Set copyup attributes */ @@ -244,7 +298,7 @@ int create_copyup(const char *path, const char *ro_path, char *rw_path, struct h vfs_unlink(dentry->d_parent->d_inode, dentry); pop_root(); dput(dentry); - return err; + goto cleanup; } dput(dentry); @@ -254,15 +308,27 @@ int create_copyup(const char *path, const char *ro_path, char *rw_path, struct h unlink(me_path, context); } - return 0; + err = 0; +cleanup: + if (tmp) { + kfree(tmp); + } + + if (me_path) { + kfree(me_path); + } + + if (buf) { + kfree(buf); + } + + return err; } static int find_path_worker(const char *path, char *real_path, struct hepunion_sb_info *context) { /* Try to find that tree */ - int err; - char read_only[PATH_MAX]; - char tree_path[PATH_MAX]; - char real_tree_path[PATH_MAX]; + int err = -ENOMEM; + char *read_only = NULL, *tree_path = NULL, *real_tree_path = NULL; types tree_path_present; char *old_directory; char *directory; @@ -278,40 +344,62 @@ static int find_path_worker(const char *path, char *real_path, struct hepunion_s return -EINVAL; } + read_only = kmalloc(PATH_MAX, GFP_KERNEL); + if(!read_only) { + return -ENOMEM; + } + + tree_path = kmalloc(PATH_MAX, GFP_KERNEL); + if(!tree_path) { + goto cleanup; + } + + real_tree_path = kmalloc(PATH_MAX, GFP_KERNEL); + if(!real_tree_path) { + goto cleanup; + } + memcpy(tree_path, path, last - path + 1); tree_path[last - path + 1] = '\0'; tree_path_present = find_file(tree_path, real_tree_path, context, 0); /* Path should at least exist RO */ if (tree_path_present < 0) { - return -tree_path_present; + err = -tree_path_present; + goto cleanup; } /* Path is already present, nothing to do */ else if (tree_path_present == READ_WRITE) { /* Execpt filing in output buffer */ if (snprintf(real_path, PATH_MAX, "%s%s", context->read_write_branch, path) > PATH_MAX) { - return -ENAMETOOLONG; + err = -ENAMETOOLONG; + goto cleanup; } - return 0; + err = 0; + goto cleanup; } /* Once here, recreating tree by COW is mandatory */ if (snprintf(real_path, PATH_MAX, "%s/", context->read_write_branch) > PATH_MAX) { - return -ENAMETOOLONG; + err = -ENAMETOOLONG; + goto cleanup; } /* Also prepare for RO branch */ if (snprintf(read_only, PATH_MAX, "%s/", context->read_only_branch) > PATH_MAX) { - return -ENAMETOOLONG; + err = -ENAMETOOLONG; + goto cleanup; } /* If that's last (creating dir at root) */ if (last == path) { if (snprintf(real_path, PATH_MAX, "%s/", context->read_write_branch) > PATH_MAX) { - return -ENAMETOOLONG; + err = -ENAMETOOLONG; + goto cleanup; } - return 0; + err = 0; + goto cleanup; } /* Really get directory */ @@ -327,20 +415,21 @@ static int find_path_worker(const char *path, char *real_path, struct hepunion_s /* Get previous dir properties */ err = lstat(read_only, context, &kstbuf); if (err < 0) { - return err; + goto cleanup; } /* Create directory */ err = mkdir_worker(real_path, context, kstbuf.mode); if (err < 0) { - return err; + goto cleanup; } /* Now, set all the previous attributes */ dentry = get_path_dentry(real_path, context, LOOKUP_DIRECTORY); if (IS_ERR(dentry)) { /* FIXME: Should delete in case of failure */ - return PTR_ERR(dentry); + err = PTR_ERR(dentry); + goto cleanup; } attr.ia_valid = ATTR_ATIME | ATTR_MTIME | ATTR_UID | ATTR_GID; @@ -355,7 +444,7 @@ static int find_path_worker(const char *path, char *real_path, struct hepunion_s if (err < 0) { vfs_rmdir(dentry->d_parent->d_inode, dentry); dput(dentry); - return err; + goto cleanup; } dput(dentry); @@ -370,26 +459,51 @@ static int find_path_worker(const char *path, char *real_path, struct hepunion_s /* Append name to create */ strcat(real_path, last); + /* It's over */ - return 0; + err = 0; + +cleanup: + if (read_only) { + kfree(read_only); + } + + if (tree_path) { + kfree(tree_path); + } + + if (real_tree_path) { + kfree(real_tree_path); + } + + return err; } int find_path(const char *path, char *real_path, struct hepunion_sb_info *context) { - pr_info("find_path: %s, %s, %p\n", path, real_path, context); + int ret; + pr_info("find_path: %s, %s, %p\n", path, real_path, context); + if (real_path) { return find_path_worker(path, real_path, context); } else { - char tmp_path[PATH_MAX]; - return find_path_worker(path, tmp_path, context); + char *tmp_path; + tmp_path = kmalloc(PATH_MAX, GFP_KERNEL); + if(!tmp_path) { + return -ENOMEM; + } + + ret = find_path_worker(path, tmp_path, context); + kfree(tmp_path); + return ret; } } int unlink_copyup(const char *path, const char *copyup_path, struct hepunion_sb_info *context) { int err; + char *real_path; struct kstat kstbuf; - char real_path[PATH_MAX]; pr_info("unlink_copyup: %s, %s\n", path, copyup_path); @@ -405,14 +519,22 @@ int unlink_copyup(const char *path, const char *copyup_path, struct hepunion_sb_ return err; } + real_path = kmalloc(PATH_MAX, GFP_KERNEL); + if(!real_path) { + return -ENOMEM; + } + /* Now, find RO file */ if (find_file(path, real_path, context, 0) == -ENOENT) { /* File doesn't exist anylonger? * Don't bother and work less */ + kfree(real_path); return 0; } /* Create me if required */ - return set_me(path, real_path, &kstbuf, context, MODE | TIME | OWNER); + err = set_me(path, real_path, &kstbuf, context, MODE | TIME | OWNER); + kfree(real_path); + return err; } diff --git a/fs/hepunion/helpers.c b/fs/hepunion/helpers.c index feb6003..95b330d 100644 --- a/fs/hepunion/helpers.c +++ b/fs/hepunion/helpers.c @@ -12,10 +12,12 @@ #include "hepunion.h" + int can_access(const char *path, const char *real_path, struct hepunion_sb_info *context, int mode) { struct kstat stbuf; int err; - + uid_t fsuid; + gid_t fsgid; pr_info("can_access: %s, %s, %p, %x\n", path, real_path, context, mode); /* Get file attributes */ @@ -24,8 +26,12 @@ int can_access(const char *path, const char *real_path, struct hepunion_sb_info return err; } + /* Get IDs */ + fsuid = current_fsuid(); + fsgid = current_fsgid(); + /* If root user, allow almost everything */ - if (current->fsuid == 0) { + if (fsuid == 0) { if (mode & MAY_EXEC) { /* Root needs at least on X * For rights details, see below @@ -59,10 +65,10 @@ int can_access(const char *path, const char *real_path, struct hepunion_sb_info * Check is done from more specific to general. * This explains order and values */ - if (current->fsuid == stbuf.uid) { + if (fsuid == stbuf.uid) { mode <<= (RIGHTS_MASK * 2); } - else if (current->fsgid == stbuf.gid) { + else if (fsgid == stbuf.gid) { mode <<= RIGHTS_MASK; } @@ -76,8 +82,8 @@ int can_access(const char *path, const char *real_path, struct hepunion_sb_info } int can_remove(const char *path, const char *real_path, struct hepunion_sb_info *context) { - char parent_path[PATH_MAX]; - + char *parent_path; + int ret; /* Find parent directory */ char *parent = strrchr(real_path, '/'); @@ -88,32 +94,50 @@ int can_remove(const char *path, const char *real_path, struct hepunion_sb_info return -EACCES; } + parent_path = kmalloc(PATH_MAX, GFP_KERNEL); + if (!parent_path) { + return -ENOMEM; + } + strncpy(parent_path, real_path, parent - real_path); parent_path[parent - real_path] = '\0'; /* Caller must be able to write in parent dir */ - return can_access(path, parent_path, context, MAY_WRITE); + ret = can_access(path, parent_path, context, MAY_WRITE); + kfree(parent_path); + return ret; } int can_traverse(const char *path, struct hepunion_sb_info *context) { - char short_path[PATH_MAX]; - char long_path[PATH_MAX]; - int err; + char *short_path = NULL, *long_path = NULL; + int err = -ENOMEM; char *last, *old_directory, *directory; pr_info("can_traverse: %s, %p\n", path, context); + short_path = kmalloc(PATH_MAX, GFP_KERNEL); + if (!short_path) { + return -ENOMEM; + } + + long_path = kmalloc(PATH_MAX, GFP_KERNEL);//dynamic allocation to avoid stack error + if (!long_path) { + goto cleanup; + } + /* Prepare strings */ snprintf(short_path, PATH_MAX, "%c", '/'); if (snprintf(long_path, PATH_MAX, "%s/", context->read_only_branch) > PATH_MAX) { - return -ENAMETOOLONG; + err = -ENAMETOOLONG; + goto cleanup; } /* Get directory */ last = strrchr(path, '/'); /* If that's last (traversing root is always possible) */ if (path == last) { - return 0; + err = 0; + goto cleanup; } /* Really get directory */ @@ -124,7 +148,7 @@ int can_traverse(const char *path, struct hepunion_sb_info *context) { strncat(long_path, old_directory, (directory - old_directory) / sizeof(char)); err = can_access(short_path, long_path, context, MAY_EXEC); if (err < 0) { - return err; + goto cleanup; } /* Next iteration (skip /) */ @@ -133,31 +157,54 @@ int can_traverse(const char *path, struct hepunion_sb_info *context) { } /* If that point is reached, it can access */ - return 0; + err = 0; + +cleanup: + if (short_path) { + kfree(short_path); + } + + if (long_path) { + kfree(long_path); + } + + return err; } int check_exist(const char *pathname, struct hepunion_sb_info *context, int flag) { int err; +#if LINUX_VERSION_CODE == KERNEL_VERSION(2,6,18) struct nameidata nd; +#else + struct path path; +#endif + pr_info("check_exist: %s, %p, %x\n", pathname, context, flag); push_root(); +#if LINUX_VERSION_CODE == KERNEL_VERSION(2,6,18) err = path_lookup(pathname, flag, &nd); +#else + err = kern_path(pathname, flag, &path); +#endif pop_root(); if (err) { return err; } +#if LINUX_VERSION_CODE == KERNEL_VERSION(2,6,18) path_release(&nd); +#else + path_put(&path); +#endif return 0; } int find_file(const char *path, char *real_path, struct hepunion_sb_info *context, char flags) { - int err; - char tmp_path[PATH_MAX]; - char wh_path[PATH_MAX]; + int err = -ENOMEM; + char *tmp_path = NULL, *wh_path = NULL; pr_info("find_file: %s, %p, %p, %x\n", path, real_path, context, flags); @@ -188,79 +235,109 @@ int find_file(const char *path, char *real_path, struct hepunion_sb_info *contex } } + tmp_path = kmalloc(PATH_MAX, GFP_KERNEL); + if (!tmp_path) { + return -ENOMEM; + } + + wh_path = kmalloc(PATH_MAX, GFP_KERNEL); + if (!wh_path) { + goto cleanup; + } + /* Be smart, we might have to create a copyup */ if (is_flag_set(flags, CREATE_COPYUP)) { if (make_ro_path(path, tmp_path) > PATH_MAX) { - return -ENAMETOOLONG; + err = -ENAMETOOLONG; + goto cleanup; } err = check_exist(tmp_path, context, 0); if (err < 0) { /* If file does not exist, even in RO, fail */ - return err; + goto cleanup; } if (!is_flag_set(flags, IGNORE_WHITEOUT)) { /* Check whether it was deleted */ err = find_whiteout(path, context, wh_path); if (err == 0) { - return -ENOENT; + err = -ENOENT; + goto cleanup; } } /* Check for access */ err = can_traverse(path, context); if (err < 0) { - return err; + goto cleanup; } err = create_copyup(path, tmp_path, real_path, context); if (err == 0) { - return READ_WRITE_COPYUP; + err = READ_WRITE_COPYUP; + goto cleanup; } } else { /* It was not found on RW, try RO */ if (make_ro_path(path, real_path) > PATH_MAX) { - return -ENAMETOOLONG; + err = -ENAMETOOLONG; + goto cleanup; } err = check_exist(real_path, context, 0); if (err < 0) { - return err; + goto cleanup; } if (!is_flag_set(flags, IGNORE_WHITEOUT)) { /* Check whether it was deleted */ err = find_whiteout(path, context, wh_path); if (err == 0) { - return -ENOENT; + err = -ENOENT; + goto cleanup; } } /* Check for access */ err = can_traverse(path, context); if (err < 0) { - return err; + goto cleanup; } - return READ_ONLY; + /* We fall back here instead of deleting, to get the memory freed */ + err = READ_ONLY; + } + + /* If we arrive here, it was not found at all (excepted for upper case) */ +cleanup: + if (tmp_path) { + kfree(tmp_path); + } + + if (wh_path) { + kfree(wh_path); } - /* It was not found at all */ return err; } int get_full_path_i(const struct inode *inode, char *real_path) { int len = -EBADF; struct dentry *dentry; - struct list_head *entry = inode->i_dentry.next; +#if LINUX_VERSION_CODE != KERNEL_VERSION(2,6,18) + struct hlist_node *entry; +#endif pr_info("get_full_path_i: %p, %p\n", inode, real_path); /* Try to browse all the dentry, till we find one nice */ - while (entry != &inode->i_dentry) { - dentry = list_entry(entry, struct dentry, d_alias); +#if LINUX_VERSION_CODE == KERNEL_VERSION(2,6,18) + list_for_each_entry(dentry, &inode->i_dentry, d_alias) { +#else + hlist_for_each_entry(dentry, entry, &inode->i_dentry, d_alias) { +#endif /* Get full path for the given inode */ len = get_full_path_d(dentry, real_path); if (len > 0) { @@ -269,9 +346,6 @@ int get_full_path_i(const struct inode *inode, char *real_path) { break; } } - - /* Jump to next dentry */ - entry = entry->next; } return len; @@ -279,28 +353,40 @@ int get_full_path_i(const struct inode *inode, char *real_path) { /* Adapted from nfs_path function */ int get_full_path_d(const struct dentry *dentry, char *real_path) { - char tmp_path[PATH_MAX]; - char *end = tmp_path + PATH_MAX; + char *tmp_path = NULL, *end; int namelen = 0, buflen = PATH_MAX; - + pr_info("get_full_path_d: %p, %p\n", dentry, real_path); - pr_info("Getting full path of: %s\n", dentry->d_name.name); + tmp_path = kmalloc(PATH_MAX, GFP_KERNEL); + if (!tmp_path) { + return -ENOMEM; + } + end = tmp_path + PATH_MAX; + *--end = '\0'; buflen--; +#if LINUX_VERSION_CODE == KERNEL_VERSION(2,6,18) spin_lock(&dcache_lock); +#else + /* FIXME: Use rename lock */ +#endif while (!IS_ROOT(dentry)) { namelen = dentry->d_name.len; buflen -= namelen + 1; - if (buflen < 0) - goto Elong_unlock; + if (buflen < 0) { + buflen = -ENAMETOOLONG; + goto cleanup; + } end -= namelen; memcpy(end, dentry->d_name.name, namelen); *--end = '/'; dentry = dentry->d_parent; } +#if LINUX_VERSION_CODE == KERNEL_VERSION(2,6,18) spin_unlock(&dcache_lock); +#endif if (buflen == PATH_MAX - 1) { *--end = '/'; @@ -312,40 +398,62 @@ int get_full_path_d(const struct dentry *dentry, char *real_path) { pr_info("Full path: %s\n", real_path); - return buflen; - -Elong_unlock: +cleanup: +#if LINUX_VERSION_CODE == KERNEL_VERSION(2,6,18) spin_unlock(&dcache_lock); - return -ENAMETOOLONG; +#endif + kfree(tmp_path); + return buflen; } struct dentry * get_path_dentry(const char *pathname, struct hepunion_sb_info *context, int flag) { int err; struct dentry *dentry; +#if LINUX_VERSION_CODE == KERNEL_VERSION(2,6,18) struct nameidata nd; +#else + struct path path; +#endif pr_info("get_path_dentry: %s, %p, %x\n", pathname, context, flag); push_root(); +#if LINUX_VERSION_CODE == KERNEL_VERSION(2,6,18) err = path_lookup(pathname, flag, &nd); +#else + err = kern_path(pathname, flag, &path); +#endif pop_root(); if (err) { return ERR_PTR(err); } +#if LINUX_VERSION_CODE == KERNEL_VERSION(2,6,18) dentry = nd.dentry; +#else + dentry = path.dentry; +#endif dget(dentry); +#if LINUX_VERSION_CODE == KERNEL_VERSION(2,6,18) path_release(&nd); +#else + path_put(&path); +#endif return dentry; } int get_relative_path(const struct inode *inode, const struct dentry *dentry, const struct hepunion_sb_info *context, char *path, int is_ours) { int len; - char real_path[PATH_MAX]; + char *real_path; pr_info("get_relative_path: %p, %p, %p, %p, %d\n", inode, dentry, context, path, is_ours); + real_path = kmalloc(PATH_MAX, GFP_KERNEL); + if (!real_path) { + return -ENOMEM; + } + /* First, get full path */ if (dentry) { len = get_full_path_d(dentry, real_path); @@ -353,7 +461,7 @@ int get_relative_path(const struct inode *inode, const struct dentry *dentry, co len = get_full_path_i(inode, real_path); } if (len < 0) { - return len; + goto cleanup; } /* If those structures are owned by HEPunion, there's no @@ -361,22 +469,29 @@ int get_relative_path(const struct inode *inode, const struct dentry *dentry, co */ if (is_ours) { memcpy(path, real_path, len); - return 0; + len = 0; + goto cleanup; } /* Check if it's on RO */ if (strncmp(context->read_only_branch, real_path, context->ro_len) == 0) { memcpy(path, real_path + 1 + context->ro_len, len - 1 - context->ro_len); - return 0; + len = 0; + goto cleanup; } /* Check if it's on RW */ if (strncmp(context->read_write_branch, real_path, context->rw_len) == 0) { memcpy(path, real_path + 1 + context->rw_len, len - 1 - context->rw_len); - return 0; + len = 0; + goto cleanup; } - return -EINVAL; + len = -EINVAL; + +cleanup: + kfree(real_path); + return len; } int get_relative_path_for_file(const struct inode *dir, const struct dentry *dentry, const struct hepunion_sb_info *context, char *path, int is_ours) { @@ -446,9 +561,9 @@ int path_to_special(const char *path, specials type, const struct hepunion_sb_in return 0; } +#if LINUX_VERSION_CODE == KERNEL_VERSION(2,6,18) /* Imported for Linux kernel and simplified */ -int lstat(const char *pathname, struct hepunion_sb_info *context, struct kstat *stat) -{ +int lstat(const char *pathname, struct hepunion_sb_info *context, struct kstat *stat) { struct nameidata nd; int error; @@ -466,7 +581,37 @@ int lstat(const char *pathname, struct hepunion_sb_info *context, struct kstat * return error; } +#else +/* Imported for Linux kernel and simplified */ +int lstat(const char *pathname, struct hepunion_sb_info *context, struct kstat *stat) { + struct path path; + int error = -EINVAL; + unsigned int lookup_flags = 0; + + pr_info("lstat: %s, %p\n", pathname, stat); + +retry: + push_root(); + error = kern_path(pathname, lookup_flags, &path); + pop_root(); + if (error) { + return error; + } + + push_root(); + error = vfs_getattr(path.mnt, path.dentry, stat); + pop_root(); + path_put(&path); + if (retry_estale(error, lookup_flags)) { + lookup_flags |= LOOKUP_REVAL; + goto retry; + } + return error; +} +#endif + +#if LINUX_VERSION_CODE == KERNEL_VERSION(2,6,18) /* Imported for Linux kernel */ long mkdir(const char *pathname, struct hepunion_sb_info *context, int mode) { int error = 0; @@ -488,8 +633,9 @@ long mkdir(const char *pathname, struct hepunion_sb_info *context, int mode) { error = PTR_ERR(dentry); if (!IS_ERR(dentry)) { - if (!IS_POSIXACL(nd.dentry->d_inode)) + if (!IS_POSIXACL(nd.dentry->d_inode)) { mode &= ~current->fs->umask; + } push_root(); error = vfs_mkdir(nd.dentry->d_inode, dentry, mode); pop_root(); @@ -500,7 +646,43 @@ long mkdir(const char *pathname, struct hepunion_sb_info *context, int mode) { return error; } +#else +/* Imported for Linux kernel */ +long mkdir(const char *pathname, struct hepunion_sb_info *context, umode_t mode) { + struct dentry *dentry; + struct path path; + int error; + unsigned int lookup_flags = LOOKUP_DIRECTORY; + + pr_info("mkdir: %s, %p, %x\n", pathname, context, mode); +retry: + push_root(); + dentry = kern_path_create(AT_FDCWD, pathname, &path, lookup_flags); + pop_root(); + if (IS_ERR(dentry)) { + return PTR_ERR(dentry); + } + + if (!IS_POSIXACL(path.dentry->d_inode)) { + mode &= ~current_umask(); + } + push_root(); + error = security_path_mkdir(&path, dentry, mode); + if (!error) { + error = vfs_mkdir(path.dentry->d_inode, dentry, mode); + } + pop_root(); + done_path_create(&path, dentry); + if (retry_estale(error, lookup_flags)) { + lookup_flags |= LOOKUP_REVAL; + goto retry; + } + return error; +} +#endif + +#if LINUX_VERSION_CODE == KERNEL_VERSION(2,6,18) /* Imported from Linux kernel */ long mknod(const char *pathname, struct hepunion_sb_info *context, int mode, unsigned dev) { int error = 0; @@ -556,8 +738,60 @@ long mknod(const char *pathname, struct hepunion_sb_info *context, int mode, uns return error; } +#else +/* Imported from Linux kernel */ +long mknod(const char *pathname, struct hepunion_sb_info *context, umode_t mode, unsigned dev) { + struct dentry *dentry; + struct path path; + int error; + unsigned int lookup_flags = 0; + + pr_info("mknod: %s, %p, %x, %u\n", pathname, context, mode, dev); + +retry: + push_root(); + dentry = kern_path_create(AT_FDCWD, pathname, &path, lookup_flags); + pop_root(); + if (IS_ERR(dentry)) { + return PTR_ERR(dentry); + } + + if (!IS_POSIXACL(path.dentry->d_inode)) { + mode &= ~current_umask(); + } + push_root(); + error = security_path_mknod(&path, dentry, mode, dev); + if (error) { + goto out; + } + switch (mode & S_IFMT) { + case 0: case S_IFREG: + error = vfs_create(path.dentry->d_inode, dentry, mode, true); + break; + case S_IFCHR: case S_IFBLK: + error = vfs_mknod(path.dentry->d_inode, dentry, mode, + new_decode_dev(dev)); + break; + case S_IFIFO: case S_IFSOCK: + error = vfs_mknod(path.dentry->d_inode, dentry, mode, 0); + break; + } + pop_root(); +out: + done_path_create(&path, dentry); + if (retry_estale(error, lookup_flags)) { + lookup_flags |= LOOKUP_REVAL; + goto retry; + } + return error; +} +#endif +#if LINUX_VERSION_CODE == KERNEL_VERSION(2,6,18) int mkfifo(const char *pathname, struct hepunion_sb_info *context, int mode) { +#else +int mkfifo(const char *pathname, struct hepunion_sb_info *context, umode_t mode) { +#endif pr_info("mkfifo: %s, %p, %x\n", pathname, context, mode); /* Ensure FIFO mode is set */ @@ -567,6 +801,7 @@ int mkfifo(const char *pathname, struct hepunion_sb_info *context, int mode) { return mknod(pathname, context, mode, 0); } +#if LINUX_VERSION_CODE == KERNEL_VERSION(2,6,18) /* Imported from Linux kernel */ long symlink(const char *oldname, const char *newname, struct hepunion_sb_info *context) { int error = 0; @@ -597,7 +832,40 @@ long symlink(const char *oldname, const char *newname, struct hepunion_sb_info * return error; } +#else +/* Imported from Linux kernel */ +long symlink(const char *oldname, const char *newname, struct hepunion_sb_info *context) { + int error; + struct dentry *dentry; + struct path path; + unsigned int lookup_flags = 0; + pr_info("symlink: %s, %s, %p\n", oldname, newname, context); + +retry: + push_root(); + dentry = kern_path_create(AT_FDCWD, newname, &path, lookup_flags); + error = PTR_ERR(dentry); + if (IS_ERR(dentry)) { + return error; + } + + error = security_path_symlink(&path, dentry, oldname); + if (!error) { + error = vfs_symlink(path.dentry->d_inode, dentry, oldname); + } + pop_root(); + done_path_create(&path, dentry); + if (retry_estale(error, lookup_flags)) { + lookup_flags |= LOOKUP_REVAL; + goto retry; + } + + return error; +} +#endif + +#if LINUX_VERSION_CODE == KERNEL_VERSION(2,6,18) /* Imported from Linux kernel - simplified */ long link(const char *oldname, const char *newname, struct hepunion_sb_info *context) { struct dentry *new_dentry; @@ -639,13 +907,68 @@ long link(const char *oldname, const char *newname, struct hepunion_sb_info *con return error; } +#else +/* Imported from Linux kernel - simplified */ +long link(const char *oldname, const char *newname, struct hepunion_sb_info *context) { + struct dentry *new_dentry; + struct path old_path, new_path; + int how = 0; + int error; + + pr_info("link: %s, %s, %p\n", oldname, newname, context); + +retry: + push_root(); + error = kern_path(oldname, how, &old_path); + pop_root(); + if (error) { + return error; + } + + push_root(); + new_dentry = kern_path_create(AT_FDCWD, newname, &new_path, (how & LOOKUP_REVAL)); + pop_root(); + error = PTR_ERR(new_dentry); + if (IS_ERR(new_dentry)) { + goto out; + } + + error = -EXDEV; + if (old_path.mnt != new_path.mnt) { + goto out_dput; + } + push_root(); + error = security_path_link(old_path.dentry, &new_path, new_dentry); + pop_root(); + if (error) { + goto out_dput; + } + push_root(); + error = vfs_link(old_path.dentry, new_path.dentry->d_inode, new_dentry); + pop_root(); +out_dput: + done_path_create(&new_path, new_dentry); + if (retry_estale(error, how)) { + how |= LOOKUP_REVAL; + goto retry; + } +out: + path_put(&old_path); + + return error; +} +#endif /* Imported from Linux kernel */ long readlink(const char *path, char *buf, struct hepunion_sb_info *context, int bufsiz) { struct inode *inode; - struct nameidata nd; int error; mm_segment_t oldfs; +#if LINUX_VERSION_CODE == KERNEL_VERSION(2,6,18) + struct nameidata nd; +#else + struct path spath; +#endif pr_info("readlink: %s, %p, %p, %d\n", path, buf, context, bufsiz); @@ -653,23 +976,45 @@ long readlink(const char *path, char *buf, struct hepunion_sb_info *context, int return -EINVAL; push_root(); +#if LINUX_VERSION_CODE == KERNEL_VERSION(2,6,18) error = path_lookup(path, 0, &nd); +#else + error = kern_path(path, 0, &spath); +#endif pop_root(); if (!error) { +#if LINUX_VERSION_CODE == KERNEL_VERSION(2,6,18) inode = nd.dentry->d_inode; +#else + inode = spath.dentry->d_inode; +#endif error = -EINVAL; if (inode->i_op && inode->i_op->readlink) { push_root(); +#if LINUX_VERSION_CODE == KERNEL_VERSION(2,6,18) error = security_inode_readlink(nd.dentry); +#else + error = security_inode_readlink(spath.dentry); +#endif if (!error) { +#if LINUX_VERSION_CODE == KERNEL_VERSION(2,6,18) touch_atime(nd.mnt, nd.dentry); call_usermode(); error = inode->i_op->readlink(nd.dentry, buf, bufsiz); +#else + touch_atime(&spath); + call_usermode(); + error = inode->i_op->readlink(spath.dentry, buf, bufsiz); +#endif restore_kernelmode(); } pop_root(); } +#if LINUX_VERSION_CODE == KERNEL_VERSION(2,6,18) path_release(&nd); +#else + path_put(&spath); +#endif } return error; } @@ -678,8 +1023,12 @@ long rmdir(const char *pathname, struct hepunion_sb_info *context) { int err; short lookup = 0; struct inode *dir; - struct nameidata nd; struct dentry *dentry; +#if LINUX_VERSION_CODE == KERNEL_VERSION(2,6,18) + struct nameidata nd; +#else + struct path path; +#endif pr_info("rmdir: %s, %p\n", pathname, context); @@ -692,13 +1041,21 @@ long rmdir(const char *pathname, struct hepunion_sb_info *context) { /* Get parent inode */ dir = dentry->d_parent->d_inode; if (dir == NULL) { +#if LINUX_VERSION_CODE == KERNEL_VERSION(2,6,18) err = path_lookup(pathname, LOOKUP_PARENT, &nd); +#else + err = kern_path(pathname, LOOKUP_PARENT, &path); +#endif if (err) { dput(dentry); return err; } +#if LINUX_VERSION_CODE == KERNEL_VERSION(2,6,18) dir = nd.dentry->d_inode; +#else + dir = path.dentry->d_inode; +#endif lookup = 1; } @@ -709,7 +1066,11 @@ long rmdir(const char *pathname, struct hepunion_sb_info *context) { pop_root(); mutex_unlock(&dir->i_mutex); if (lookup) { +#if LINUX_VERSION_CODE == KERNEL_VERSION(2,6,18) path_release(&nd); +#else + path_put(&path); +#endif } dput(dentry); @@ -720,9 +1081,12 @@ long unlink(const char *pathname, struct hepunion_sb_info *context) { int err; short lookup = 0; struct inode *dir; - struct nameidata nd; struct dentry *dentry; - +#if LINUX_VERSION_CODE == KERNEL_VERSION(2,6,18) + struct nameidata nd; +#else + struct path path; +#endif pr_info("unlink: %s, %p\n", pathname, context); /* Get file dentry */ @@ -734,13 +1098,21 @@ long unlink(const char *pathname, struct hepunion_sb_info *context) { /* Get parent inode */ dir = dentry->d_parent->d_inode; if (dir == NULL) { +#if LINUX_VERSION_CODE == KERNEL_VERSION(2,6,18) err = path_lookup(pathname, LOOKUP_PARENT, &nd); +#else + err = kern_path(pathname, LOOKUP_PARENT, &path); +#endif if (err) { dput(dentry); return err; } +#if LINUX_VERSION_CODE == KERNEL_VERSION(2,6,18) dir = nd.dentry->d_inode; +#else + dir = path.dentry->d_inode; +#endif lookup = 1; } @@ -751,7 +1123,11 @@ long unlink(const char *pathname, struct hepunion_sb_info *context) { pop_root(); mutex_unlock(&dir->i_mutex); if (lookup) { +#if LINUX_VERSION_CODE == KERNEL_VERSION(2,6,18) path_release(&nd); +#else + path_put(&path); +#endif } dput(dentry); diff --git a/fs/hepunion/hepunion.h b/fs/hepunion/hepunion.h index ed8c518..83f8c4d 100644 --- a/fs/hepunion/hepunion.h +++ b/fs/hepunion/hepunion.h @@ -19,6 +19,7 @@ #ifdef __KERNEL__ +#include #include #include #include @@ -28,6 +29,11 @@ #include #include #include +#if LINUX_VERSION_CODE != KERNEL_VERSION(2,6,18) +#include +#endif +#include +#include #include "hash.h" #include "recursivemutex.h" @@ -99,6 +105,9 @@ struct hepunion_sb_info { * lookup */ struct list_head read_inode_head; + + struct cred *new; + const struct cred *old; }; struct readdir_context { @@ -299,7 +308,7 @@ extern struct file_operations hepunion_dir_fops; * Mask that defines all the modes of a file that can be changed using the * metadata mechanism */ -#define VALID_MODES_MASK (S_ISUID | S_ISGID | S_ISVTX | \ +#define VALID_MODES_MASK (S_ISUID | S_ISGID | S_ISVTX | \ S_IRWXU | S_IRUSR | S_IWUSR | S_IXUSR | \ S_IRWXG | S_IRGRP | S_IWGRP | S_IXGRP | \ S_IRWXO | S_IROTH | S_IWOTH | S_IXOTH) @@ -353,6 +362,25 @@ extern struct file_operations hepunion_dir_fops; (l == 2 && n[0] == '.' && \ n[1] == '.')) +#if LINUX_VERSION_CODE == KERNEL_VERSION(2,6,18) +/** + * Get current FS uid + * \return It returns current FS uid + */ +#define current_fsuid() current->fsuid +/** + * Get current FS gid + * \return It returns current FS gid + */ +#define current_fsgid() current->fsgid +/** + * Set inode number of links + * \param[in] i Inode on which to set links count + * \param[in] n Link count + */ +#define set_nlink(i, n) i->i_nlink = n +#endif + /** * Get current context associated with dentry * \param[in] d dentry pointer @@ -379,6 +407,7 @@ extern struct file_operations hepunion_dir_fops; * \return The number of caracters written to r */ #define make_rw_path(p, r) snprintf(r, PATH_MAX, "%s%s", context->read_write_branch, p) +#if LINUX_VERSION_CODE == KERNEL_VERSION(2,6,18) /** * Switch the current context user and group to root to allow * modifications on child file systems @@ -387,15 +416,38 @@ extern struct file_operations hepunion_dir_fops; current->fsuid = context->uid; \ current->fsgid = context->gid; \ recursive_mutex_unlock(&context->id_lock) -/** +/** * Switch the current context back to real user and real group */ -#define push_root() \ +#define push_root() \ recursive_mutex_lock(&context->id_lock); \ context->uid = current->fsuid; \ context->gid = current->fsgid; \ current->fsuid = 0; \ current->fsgid = 0 +#else +/** + * Switch the current context user and group to root to allow + * modifications on child file systems + */ +#define pop_root() \ + do { \ + revert_creds(context->old); \ + put_cred(context->new); \ + } while(0); \ + recursive_mutex_unlock(&context->id_lock) +/** + * Switch the current context back to real user and real group + */ +#define push_root() \ + recursive_mutex_lock(&context->id_lock); \ + do { \ + context->new = prepare_creds(); \ + context->new->uid = 0; \ + context->new->gid = 0; \ + context->old = override_creds(context->new);\ + } while(0) +#endif /** * Switch the current data segment to disable buffers checking * To be used when calling a VFS function wanting an usermode @@ -707,7 +759,11 @@ int lstat(const char *pathname, struct hepunion_sb_info *context, struct kstat * * \param[in] mode Mode to set to the directory (see mkdir man page) * \return 0 in case of a success, -err otherwise */ +#if LINUX_VERSION_CODE == KERNEL_VERSION(2,6,18) long mkdir(const char *pathname, struct hepunion_sb_info *context, int mode); +#else +long mkdir(const char *pathname, struct hepunion_sb_info *context, umode_t mode); +#endif /** * Wrapper for mknod that allows creation of a FIFO file using pathname. * \param[in] pathname FIFO file to create @@ -715,7 +771,11 @@ long mkdir(const char *pathname, struct hepunion_sb_info *context, int mode); * \param[in] mode Mode to set to the file (see mkfifo man page) * \return 0 in case of a success, -err otherwise */ +#if LINUX_VERSION_CODE == KERNEL_VERSION(2,6,18) int mkfifo(const char *pathname, struct hepunion_sb_info *context, int mode); +#else +int mkfifo(const char *pathname, struct hepunion_sb_info *context, umode_t mode); +#endif /** * Implementation taken from Linux kernel. It's here to allow creation of a special * file using pathname. @@ -725,7 +785,11 @@ int mkfifo(const char *pathname, struct hepunion_sb_info *context, int mode); * \param[in] dev Special device * \return 0 in case of a success, -err otherwise */ +#if LINUX_VERSION_CODE == KERNEL_VERSION(2,6,18) long mknod(const char *pathname, struct hepunion_sb_info *context, int mode, unsigned dev); +#else +long mknod(const char *pathname, struct hepunion_sb_info *context, umode_t mode, unsigned dev); +#endif /** * Implementation taken from Linux kernel. It's here to allow link readding (seems like * that's not the job vfs_readdlink is doing). diff --git a/fs/hepunion/main.c b/fs/hepunion/main.c index dbeaa1c..c6f02b5 100644 --- a/fs/hepunion/main.c +++ b/fs/hepunion/main.c @@ -211,13 +211,18 @@ static int get_branches(struct super_block *sb, const char *arg) { root_i->i_ctime = ctime; root_i->i_op = &hepunion_dir_iops; root_i->i_fop = &hepunion_dir_fops; - root_i->i_nlink = 2; + set_nlink(root_i, 2); #ifdef _DEBUG_ root_i->i_private = (void *)HEPUNION_MAGIC; #endif /* Create its directory entry */ +#if LINUX_VERSION_CODE == KERNEL_VERSION(2,6,18) sb->s_root = d_alloc_root(root_i); +#else + sb->s_root = d_make_root(root_i); +#endif + if (IS_ERR(sb->s_root)) { pr_crit("Failed allocating new dentry for /!\n"); iput(root_i); @@ -286,6 +291,7 @@ static int hepunion_read_super(struct super_block *sb, void *raw_data, return 0; } +#if LINUX_VERSION_CODE == KERNEL_VERSION(2,6,18) static int hepunion_get_sb(struct file_system_type *fs_type, int flags, const char *dev_name, void *raw_data, struct vfsmount *mnt) { @@ -294,6 +300,16 @@ static int hepunion_get_sb(struct file_system_type *fs_type, return err; } +#else +static struct dentry * hepunion_mount_sb(struct file_system_type *fs_type, + int flags, const char *dev_name, + void *raw_data) { + struct dentry * dentry; + + dentry = mount_nodev(fs_type, flags, raw_data, hepunion_read_super); + return dentry; +} +#endif static void hepunion_kill_sb(struct super_block *sb) { struct hepunion_sb_info *sb_info; @@ -316,9 +332,13 @@ static void hepunion_kill_sb(struct super_block *sb) { static struct file_system_type hepunion_fs_type = { .owner = THIS_MODULE, .name = HEPUNION_NAME, +#if LINUX_VERSION_CODE == KERNEL_VERSION(2,6,18) .get_sb = hepunion_get_sb, +#else + .mount = hepunion_mount_sb, +#endif .kill_sb = hepunion_kill_sb, - .fs_flags = FS_REVAL_DOT, + .fs_flags = FS_REVAL_DOT }; static int __init init_hepunion_fs(void) { diff --git a/fs/hepunion/me.c b/fs/hepunion/me.c index 573fe60..8dc4e0e 100644 --- a/fs/hepunion/me.c +++ b/fs/hepunion/me.c @@ -99,34 +99,49 @@ int find_me(const char *path, struct hepunion_sb_info *context, char *me_path, s } int get_file_attr(const char *path, struct hepunion_sb_info *context, struct kstat *kstbuf) { - char real_path[PATH_MAX]; + char *real_path; int err; - pr_info("get_file_attr: %s, %p, %p\n", path, context, kstbuf); + real_path = kmalloc(PATH_MAX, GFP_KERNEL); + if (!real_path) { + return -ENOMEM; + } + /* First, find file */ err = find_file(path, real_path, context, 0); if (err < 0) { + kfree(real_path); return err; } /* Call worker */ - return get_file_attr_worker(path, real_path, context, kstbuf); + err = get_file_attr_worker(path, real_path, context, kstbuf); + kfree(real_path); + return err; } int get_file_attr_worker(const char *path, const char *real_path, struct hepunion_sb_info *context, struct kstat *kstbuf) { int err; char me; struct kstat kstme; - char me_file[PATH_MAX]; + char *me_file; pr_info("get_file_attr_worker: %s, %s, %p, %p\n", path, real_path, context, kstbuf); + me_file = kmalloc(PATH_MAX, GFP_KERNEL);//dynamic array to solve stack problem + if (!me_file) { + return -ENOMEM; + } + /* Look for a me file */ me = (find_me(path, context, me_file, &kstme) >= 0); pr_info("me file status: %d\n", me); + /* We don't need its name info about */ + kfree(me_file); + /* Get attributes */ err = lstat(real_path, context, kstbuf); if (err < 0) { @@ -184,7 +199,7 @@ int set_me(const char *path, const char *real_path, struct kstat *kstbuf, struct int set_me_worker(const char *path, const char *real_path, struct iattr *attr, struct hepunion_sb_info *context) { int err; char me; - char me_path[PATH_MAX]; + char *me_path; struct kstat kstme; struct file *fd; umode_t mode; @@ -194,6 +209,11 @@ int set_me_worker(const char *path, const char *real_path, struct iattr *attr, s /* Ensure input is correct */ attr->ia_valid &= ATTR_UID | ATTR_GID | ATTR_ATIME | ATTR_MTIME | ATTR_MODE; + me_path = kmalloc(PATH_MAX, GFP_KERNEL);//dynamic array to solve stack problem + if (!me_path) { + return -ENOMEM; + } + /* Look for a me file */ me = (find_me(path, context, me_path, &kstme) >= 0); @@ -201,13 +221,13 @@ int set_me_worker(const char *path, const char *real_path, struct iattr *attr, s /* Read real file info */ err = lstat(real_path, context, &kstme); if (err < 0) { - return err; + goto cleanup; } /* Recreate path up to the .me. file */ err = find_path(path, NULL, context); if (err < 0) { - return err; + goto cleanup; } /* .me. does not exist, create it with appropriate mode */ @@ -216,7 +236,8 @@ int set_me_worker(const char *path, const char *real_path, struct iattr *attr, s fd = creat_worker(me_path, context, mode); if (IS_ERR(fd)) { - return PTR_ERR(fd); + err = PTR_ERR(fd); + goto cleanup; } /* Remove mode if it was set */ @@ -245,7 +266,8 @@ int set_me_worker(const char *path, const char *real_path, struct iattr *attr, s else { fd = open_worker(me_path, context, O_RDWR); if (IS_ERR(fd)) { - return PTR_ERR(fd); + err = PTR_ERR(fd); + goto cleanup; } /* Only change if there are changes */ @@ -263,5 +285,7 @@ int set_me_worker(const char *path, const char *real_path, struct iattr *attr, s pop_root(); } +cleanup: + kfree(me_path); return err; } diff --git a/fs/hepunion/opts.c b/fs/hepunion/opts.c index 6f95fed..42750cd 100644 --- a/fs/hepunion/opts.c +++ b/fs/hepunion/opts.c @@ -48,7 +48,11 @@ static int hepunion_closedir(struct inode *inode, struct file *filp) { return 0; } +#if LINUX_VERSION_CODE == KERNEL_VERSION(2,6,18) static int hepunion_create(struct inode *dir, struct dentry *dentry, int mode, struct nameidata *nameidata) { +#else +static int hepunion_create(struct inode *dir, struct dentry *dentry, umode_t mode, bool want_excl) { +#endif int err; struct hepunion_sb_info *context = get_context_i(dir); char *path = context->global1; @@ -57,7 +61,11 @@ static int hepunion_create(struct inode *dir, struct dentry *dentry, int mode, s struct iattr attr; struct inode *inode; +#if LINUX_VERSION_CODE == KERNEL_VERSION(2,6,18) pr_info("hepunion_create: %p, %p, %x, %p\n", dir, dentry, mode, nameidata); +#else + pr_info("hepunion_create: %p, %p, %x, %u\n", dir, dentry, mode, want_excl); +#endif will_use_buffers(context); validate_inode(dir); @@ -102,8 +110,8 @@ static int hepunion_create(struct inode *dir, struct dentry *dentry, int mode, s } /* Set its correct owner in case of creation */ - attr.ia_uid = current->uid; - attr.ia_gid = current->gid; + attr.ia_uid = current_fsuid(); + attr.ia_gid = current_fsgid(); attr.ia_valid = ATTR_UID | ATTR_GID; push_root(); @@ -126,9 +134,9 @@ static int hepunion_create(struct inode *dir, struct dentry *dentry, int mode, s } /* And fill it in */ - dir->i_nlink++; - inode->i_uid = current->fsuid; - inode->i_gid = current->fsgid; + inc_nlink(dir); + inode->i_uid = current_fsuid(); + inode->i_gid = current_fsgid(); inode->i_mtime = CURRENT_TIME; inode->i_atime = CURRENT_TIME; inode->i_ctime = CURRENT_TIME; @@ -137,12 +145,12 @@ static int hepunion_create(struct inode *dir, struct dentry *dentry, int mode, s inode->i_op = &hepunion_iops; inode->i_fop = &hepunion_fops; inode->i_mode = mode; - inode->i_nlink = 1; + set_nlink(inode, 1); inode->i_ino = name_to_ino(path); #ifdef _DEBUG_ inode->i_private = (void *)HEPUNION_MAGIC; #endif - insert_inode_hash(inode); + insert_inode_hash(inode); d_instantiate(dentry, inode); mark_inode_dirty(dir); @@ -188,9 +196,7 @@ static int hepunion_link(struct dentry *old_dentry, struct inode *dir, struct de struct hepunion_sb_info *context = get_context_d(old_dentry); char *from = context->global1; char *to = context->global2; - char real_from[PATH_MAX]; - char real_to[PATH_MAX]; - + char *real_from = NULL, *real_to = NULL; pr_info("hepunion_link: %p, %p, %p\n", old_dentry, dir, dentry); will_use_buffers(context); @@ -201,71 +207,88 @@ static int hepunion_link(struct dentry *old_dentry, struct inode *dir, struct de /* First, find file */ err = get_relative_path(NULL, old_dentry, context, from, 1); if (err < 0) { - release_buffers(context); - return err; + goto cleanup; + } + + real_from = kmalloc(PATH_MAX, GFP_KERNEL); + if (!real_from) { + err = -ENOMEM; + goto cleanup; + } + + real_to = kmalloc(PATH_MAX, GFP_KERNEL); + if (!real_to) { + err = -ENOMEM; + goto cleanup; } origin = find_file(from, real_from, context, 0); if (origin < 0) { - release_buffers(context); - return origin; + err = origin; + goto cleanup; } /* Find destination */ err = get_relative_path_for_file(dir, dentry, context, to, 1); if (err < 0) { - release_buffers(context); - return err; + goto cleanup; } /* And ensure it doesn't exist */ err = find_file(to, real_to, context, 0); if (err >= 0) { - release_buffers(context); - return -EEXIST; + err = -EEXIST; + goto cleanup; } /* Check access */ err = can_create(to, real_to, context); if (err < 0) { - release_buffers(context); - return err; + goto cleanup; } /* Create path if needed */ err = find_path(to, real_to, context); if (err < 0) { - release_buffers(context); - return err; + goto cleanup; } if (origin == READ_ONLY) { /* Here, fallback to a symlink */ err = symlink_worker(real_from, real_to, context); if (err < 0) { - release_buffers(context); - return err; + goto cleanup; } } else { /* Get RW name */ if (make_rw_path(to, real_to) > PATH_MAX) { - release_buffers(context); - return -ENAMETOOLONG; + err = -ENAMETOOLONG; + goto cleanup; } err = link_worker(real_from, real_to, context); if (err < 0) { - release_buffers(context); - return err; + goto cleanup; } } /* Remove possible whiteout */ unlink_whiteout(to, context); + err = 0; + +cleanup: + if (real_from) { + kfree(real_from); + } + + if (real_to) { + kfree(real_to); + } release_buffers(context); - return 0; + + return err; } static loff_t hepunion_llseek(struct file *file, loff_t offset, int origin) { @@ -280,7 +303,11 @@ static loff_t hepunion_llseek(struct file *file, loff_t offset, int origin) { return ret; } +#if LINUX_VERSION_CODE == KERNEL_VERSION(2,6,18) static struct dentry * hepunion_lookup(struct inode *dir, struct dentry *dentry, struct nameidata *nameidata) { +#else +static struct dentry * hepunion_lookup(struct inode *dir, struct dentry *dentry, unsigned int flags) { +#endif /* We are looking for "dentry" in "dir" */ int err; struct hepunion_sb_info *context = get_context_i(dir); @@ -291,7 +318,11 @@ static struct dentry * hepunion_lookup(struct inode *dir, struct dentry *dentry, size_t namelen; unsigned long ino; +#if LINUX_VERSION_CODE == KERNEL_VERSION(2,6,18) pr_info("hepunion_lookup: %p, %p, %p\n", dir, dentry, nameidata); +#else + pr_info("hepunion_lookup: %p, %p, %#X\n", dir, dentry, flags); +#endif will_use_buffers(context); validate_inode(dir); @@ -339,7 +370,7 @@ static struct dentry * hepunion_lookup(struct inode *dir, struct dentry *dentry, list_add(&ctx->read_inode_entry, &context->read_inode_head); /* Get inode */ - inode = iget(dir->i_sb, ino); + inode = iget_locked(dir->i_sb, ino); if (!inode) { inode = ERR_PTR(-EACCES); } else { @@ -358,7 +389,11 @@ static struct dentry * hepunion_lookup(struct inode *dir, struct dentry *dentry, return NULL; } +#if LINUX_VERSION_CODE == KERNEL_VERSION(2,6,18) static int hepunion_mkdir(struct inode *dir, struct dentry *dentry, int mode) { +#else +static int hepunion_mkdir(struct inode *dir, struct dentry *dentry, umode_t mode) { +#endif int err; struct inode *inode; struct hepunion_sb_info *context = get_context_i(dir); @@ -434,9 +469,9 @@ static int hepunion_mkdir(struct inode *dir, struct dentry *dentry, int mode) { } /* And fill it in */ - dir->i_nlink++; - inode->i_uid = current->fsuid; - inode->i_gid = current->fsgid; + inc_nlink(dir); + inode->i_uid = current_fsuid(); + inode->i_gid = current_fsgid(); inode->i_mtime = CURRENT_TIME; inode->i_atime = CURRENT_TIME; inode->i_ctime = CURRENT_TIME; @@ -445,7 +480,7 @@ static int hepunion_mkdir(struct inode *dir, struct dentry *dentry, int mode) { inode->i_op = &hepunion_dir_iops; inode->i_fop = &hepunion_dir_fops; inode->i_mode = mode; - inode->i_nlink = 1; + set_nlink(inode, 1); inode->i_ino = name_to_ino(path); #ifdef _DEBUG_ inode->i_private = (void *)HEPUNION_MAGIC; @@ -463,7 +498,11 @@ static int hepunion_mkdir(struct inode *dir, struct dentry *dentry, int mode) { return 0; } +#if LINUX_VERSION_CODE == KERNEL_VERSION(2,6,18) static int hepunion_mknod(struct inode *dir, struct dentry *dentry, int mode, dev_t rdev) { +#else +static int hepunion_mknod(struct inode *dir, struct dentry *dentry, umode_t mode, dev_t rdev) { +#endif int err; struct hepunion_sb_info *context = get_context_i(dir); char *path = context->global1; @@ -589,8 +628,7 @@ static int hepunion_opendir(struct inode *inode, struct file *file) { char *path = context->global1; char *real_path = context->global2; struct opendir_context *ctx; - char ro_path[PATH_MAX]; - char rw_path[PATH_MAX]; + char *ro_path = NULL, *rw_path = NULL; size_t ro_len = 0; size_t rw_len = 0; @@ -616,6 +654,18 @@ static int hepunion_opendir(struct inode *inode, struct file *file) { return err; } + ro_path = kmalloc(PATH_MAX, GFP_KERNEL); + if (!ro_path) { + err = -ENOMEM; + goto cleanup; + } + + rw_path = kmalloc(PATH_MAX, GFP_KERNEL); + if (!rw_path) { + err = -ENOMEM; + goto cleanup; + } + if (find_file(path, rw_path, context, MUST_READ_WRITE) >= 0) { rw_len = strlen(rw_path); } @@ -627,8 +677,8 @@ static int hepunion_opendir(struct inode *inode, struct file *file) { /* Allocate readdir context */ ctx = kmalloc(sizeof(struct opendir_context) + rw_len + ro_len + 2 * sizeof(char), GFP_KERNEL); if (!ctx) { - release_buffers(context); - return -ENOMEM; + err = -ENOMEM; + goto cleanup; } /* Copy strings - RO first */ @@ -670,26 +720,52 @@ static int hepunion_opendir(struct inode *inode, struct file *file) { file->private_data = ctx; + err = 0; + +cleanup: release_buffers(context); - return 0; + + if (ro_path) { + kfree(ro_path); + } + + if (rw_path) { + kfree(rw_path); + } + + return err; } +#if LINUX_VERSION_CODE == KERNEL_VERSION(2,6,18) static int hepunion_permission(struct inode *inode, int mask, struct nameidata *nd) { +#else +static int hepunion_permission(struct inode *inode, int mask) { +#endif int err; struct hepunion_sb_info *context = get_context_i(inode); char *path = context->global1; char *real_path = context->global2; - pr_info("hepunion_permission: %p, %x, %p\n", inode, mask, nd); +#if LINUX_VERSION_CODE == KERNEL_VERSION(2,6,18) + pr_info("hepunion_permission: %p, %#X, %p\n", inode, mask, nd); +#else + pr_info("hepunion_permission: %p, %#X\n", inode, mask); +#endif will_use_buffers(context); validate_inode(inode); + +#if LINUX_VERSION_CODE == KERNEL_VERSION(2,6,18) if (nd && nd->dentry) { validate_dentry(nd->dentry); } /* Get path */ err = get_relative_path(inode, (nd ? nd->dentry : NULL), context, path, 1); +#else + /* Get path */ + err = get_relative_path(inode, NULL, context, path, 1); +#endif if (err) { release_buffers(context); return err; @@ -719,6 +795,7 @@ static ssize_t hepunion_read(struct file *file, char __user *buf, size_t count, return ret; } +#if LINUX_VERSION_CODE == KERNEL_VERSION(2,6,18) static void hepunion_read_inode(struct inode *inode) { int err; struct kstat kstbuf; @@ -779,12 +856,84 @@ static void hepunion_read_inode(struct inode *inode) { inode->i_private = (void *)HEPUNION_MAGIC; #endif } +#endif + +#if 0 // Looks wrong +/*this function has replaced hepunion_read_inode*/ +struct inode *hepunion_iget(struct super_block *sb, unsigned long ino) { + int err; + struct kstat kstbuf; + struct list_head *entry; + struct read_inode_context *ctx; + struct inode *inode; + + inode = iget_locked(sb, ino); + struct hepunion_sb_info *context = get_context_i(inode); + pr_info("hepunion_read_inode: %p\n", inode); + + if(!inode) + return; + + /* Get path */ + entry = context->read_inode_head.next; + while (entry != &context->read_inode_head) { + ctx = list_entry(entry, struct read_inode_context, read_inode_entry); + if (ctx->ino == inode->i_ino) { + break; + } + + entry = entry->next; + } + + /* Quit if no context found */ + if (entry == &context->read_inode_head) { + pr_info("Context not found for: %lu\n", inode->i_ino); + return; + } + + pr_info("Reading inode: %s\n", ctx->name); + + /* Call worker */ + err = get_file_attr(ctx->name, context, &kstbuf); + if (err < 0) { + pr_info("read_inode: %d\n", err); + return; + } + + /* Set inode */ + inode->i_mode = kstbuf.mode; + inode->i_atime = kstbuf.atime; + inode->i_mtime = kstbuf.mtime; + inode->i_ctime = kstbuf.ctime; + inode->i_uid = kstbuf.uid; + inode->i_gid = kstbuf.gid; + inode->i_size = kstbuf.size; + set_nlink(inode, kstbuf.nlink); + inode->i_blocks = kstbuf.blocks; + inode->i_blkbits = kstbuf.blksize; + + /* Set operations */ + if (inode->i_mode & S_IFDIR) { + inode->i_op = &hepunion_dir_iops; + inode->i_fop = &hepunion_dir_fops; + } else { + inode->i_op = &hepunion_iops; + inode->i_fop = &hepunion_fops; + } + +#ifdef _DEBUG_ + inode->i_private = (void *)HEPUNION_MAGIC; +#endif + unlock_new_inode(inode); + return inode; +} +#endif static int read_rw_branch(void *buf, const char *name, int namlen, loff_t offset, u64 ino, unsigned d_type) { struct readdir_file *entry; struct opendir_context *ctx = (struct opendir_context *)buf; struct hepunion_sb_info *context = ctx->context; - char complete_path[PATH_MAX]; + char *complete_path; char *path; size_t len; @@ -828,11 +977,17 @@ static int read_rw_branch(void *buf, const char *name, int namlen, loff_t offset } } else { + complete_path = kmalloc(PATH_MAX, GFP_KERNEL); + if (!complete_path) { + return -ENOMEM; + } + /* This is a normal entry * Just add it to the list */ entry = kmalloc(sizeof(struct readdir_file) + namlen + sizeof(char), GFP_KERNEL); if (!entry) { + kfree(complete_path); return -ENOMEM; } @@ -849,6 +1004,8 @@ static int read_rw_branch(void *buf, const char *name, int namlen, loff_t offset path = (char *)(ctx->rw_off + (unsigned long)ctx); len = ctx->rw_len - context->rw_len; if (len + namlen + 1 > PATH_MAX) { + /* FIXME: What to do with entry? */ + kfree(complete_path); return -ENAMETOOLONG; } memcpy(complete_path, path + context->rw_len, len); @@ -856,6 +1013,7 @@ static int read_rw_branch(void *buf, const char *name, int namlen, loff_t offset complete_path[len + namlen] = '\0'; entry->ino = name_to_ino(complete_path); + kfree(complete_path); } return 0; @@ -864,7 +1022,7 @@ static int read_rw_branch(void *buf, const char *name, int namlen, loff_t offset static int read_ro_branch(void *buf, const char *name, int namlen, loff_t offset, u64 ino, unsigned d_type) { struct opendir_context *ctx = (struct opendir_context *)buf; struct hepunion_sb_info *context = ctx->context; - char complete_path[PATH_MAX]; + char *complete_path; char *path; size_t len; struct readdir_file *entry; @@ -911,6 +1069,12 @@ static int read_ro_branch(void *buf, const char *name, int namlen, loff_t offset return -ENOMEM; } + complete_path = kmalloc(PATH_MAX, GFP_KERNEL); + if (!complete_path) { + kfree(entry); + return -ENOMEM; + } + /* Add it to list */ list_add(&entry->files_entry, &ctx->files_head); @@ -924,6 +1088,8 @@ static int read_ro_branch(void *buf, const char *name, int namlen, loff_t offset path = (char *)(ctx->ro_off + (unsigned long)ctx); len = ctx->ro_len - context->ro_len; if (len + namlen + 1 > PATH_MAX) { + /* FIXME: What to do with entry? */ + kfree(complete_path); return -ENAMETOOLONG; } memcpy(complete_path, path + context->ro_len, len); @@ -931,6 +1097,7 @@ static int read_ro_branch(void *buf, const char *name, int namlen, loff_t offset complete_path[len + namlen] = '\0'; entry->ino = name_to_ino(complete_path); + kfree(complete_path); return 0; } @@ -1039,6 +1206,7 @@ static int hepunion_readdir(struct file *filp, void *dirent, filldir_t filldir) return err; } +#if LINUX_VERSION_CODE == KERNEL_VERSION(2,6,18) static ssize_t hepunion_readv(struct file *file, const struct iovec *vector, unsigned long count, loff_t *offset) { struct file *real_file = (struct file *)file->private_data; ssize_t ret; @@ -1050,9 +1218,17 @@ static ssize_t hepunion_readv(struct file *file, const struct iovec *vector, uns return ret; } +#endif +#if LINUX_VERSION_CODE == KERNEL_VERSION(2,6,18) static int hepunion_revalidate(struct dentry *dentry, struct nameidata *nd) { + pr_info("hepunion_revalidate: %p, %p\n", dentry, nd); +#else +static int hepunion_revalidate(struct dentry *dentry, unsigned int flags) { + + pr_info("hepunion_revalidate: %p, %#X\n", dentry, flags); +#endif if (dentry->d_inode == NULL) { return 0; @@ -1064,9 +1240,7 @@ static int hepunion_revalidate(struct dentry *dentry, struct nameidata *nd) { static int hepunion_rmdir(struct inode *dir, struct dentry *dentry) { int err; struct kstat kstbuf; - char me_path[PATH_MAX]; - char wh_path[PATH_MAX]; - char ro_path[PATH_MAX]; + char *me_path = NULL, *wh_path = NULL, *ro_path = NULL; char has_ro = 0; struct hepunion_sb_info *context = get_context_i(dir); char *path = context->global1; @@ -1085,6 +1259,12 @@ static int hepunion_rmdir(struct inode *dir, struct dentry *dentry) { return err; } + wh_path = kmalloc(PATH_MAX, GFP_KERNEL); + if (!wh_path) { + release_buffers(context); + return -ENOMEM; + } + /* Then, find dir */ err = find_file(path, real_path, context, 0); switch (err) { @@ -1092,6 +1272,12 @@ static int hepunion_rmdir(struct inode *dir, struct dentry *dentry) { /* On RW, just remove it */ case READ_WRITE_COPYUP: // Can't happen case READ_WRITE: + ro_path = kmalloc(PATH_MAX, GFP_KERNEL); + if (!ro_path) { + err = -ENOMEM; + break; + } + /* Check if RO exists */ if (find_file(path, ro_path, context, MUST_READ_ONLY) >= 0) { has_ro = 1; @@ -1136,6 +1322,12 @@ static int hepunion_rmdir(struct inode *dir, struct dentry *dentry) { break; } + me_path = kmalloc(PATH_MAX, GFP_KERNEL); + if(!me_path) { + err = -ENOMEM; + break; + } + /* Get me first */ if (find_me(path, context, me_path, &kstbuf) >= 0) { has_me = 1; @@ -1159,6 +1351,19 @@ static int hepunion_rmdir(struct inode *dir, struct dentry *dentry) { } release_buffers(context); + + if (me_path) { + kfree(me_path); + } + + if (wh_path) { + kfree(wh_path); + } + + if (ro_path) { + kfree(ro_path); + } + return err; } @@ -1277,6 +1482,7 @@ static int hepunion_symlink(struct inode *dir, struct dentry *dentry, const char return 0; } +/* used by df to show it up */ static int hepunion_statfs(struct dentry *dentry, struct kstatfs *buf) { struct super_block *sb = dentry->d_sb; struct hepunion_sb_info * sb_info = sb->s_fs_info; @@ -1296,7 +1502,11 @@ static int hepunion_statfs(struct dentry *dentry, struct kstatfs *buf) { return PTR_ERR(filp); } +#if LINUX_VERSION_CODE == KERNEL_VERSION(2,6,18) err = vfs_statfs(filp->f_dentry, buf); +#else + err = vfs_statfs(&filp->f_path, buf); +#endif filp_close(filp, NULL); if (unlikely(err)) { @@ -1317,8 +1527,7 @@ static int hepunion_unlink(struct inode *dir, struct dentry *dentry) { char *path = context->global1; char *real_path = context->global2; struct kstat kstbuf; - char me_path[PATH_MAX]; - char wh_path[PATH_MAX]; + char *me_path = NULL, *wh_path = NULL; pr_info("hepunion_unlink: %p, %p\n", dir, dentry); @@ -1351,6 +1560,19 @@ static int hepunion_unlink(struct inode *dir, struct dentry *dentry) { break; } + me_path = kmalloc(PATH_MAX, GFP_KERNEL); + if (!me_path) { + err = -ENOMEM; + break; + } + + /* Allocate now to make failure path easier */ + wh_path = kmalloc(PATH_MAX, GFP_KERNEL); + if (!wh_path) { + err = -ENOMEM; + break; + } + /* Get me first */ if (find_me(path, context, me_path, &kstbuf) >= 0) { has_me = 1; @@ -1375,13 +1597,22 @@ static int hepunion_unlink(struct inode *dir, struct dentry *dentry) { /* Kill the inode now */ if (err == 0) { - dir->i_nlink--; + drop_nlink(dir); mark_inode_dirty(dir); - dentry->d_inode->i_nlink--; + drop_nlink(dentry->d_inode); mark_inode_dirty(dentry->d_inode); } release_buffers(context); + + if (me_path) { + kfree(me_path); + } + + if (wh_path) { + kfree(wh_path); + } + return err; } @@ -1397,6 +1628,19 @@ static ssize_t hepunion_write(struct file *file, const char __user *buf, size_t return ret; } +static void hepunion_put_super(struct super_block *sb) +{ + /* this function used for umounting the fs*/ + struct hepunion_sb_info * sb_info = sb->s_fs_info; + pr_info("hepunion_put_super\n"); + if (sb_info) + { + kfree(sb_info); + sb->s_fs_info = NULL; + } +} + +#if LINUX_VERSION_CODE == KERNEL_VERSION(2,6,18) static ssize_t hepunion_writev(struct file *file, const struct iovec *vector, unsigned long count, loff_t *offset) { struct file *real_file = (struct file *)file->private_data; ssize_t ret; @@ -1408,6 +1652,7 @@ static ssize_t hepunion_writev(struct file *file, const struct iovec *vector, un return ret; } +#endif struct inode_operations hepunion_iops = { .getattr = hepunion_getattr, @@ -1415,7 +1660,7 @@ struct inode_operations hepunion_iops = { #if 0 .readlink = generic_readlink, /* dentry will already point on the right file */ #endif - .setattr = hepunion_setattr, + .setattr = hepunion_setattr }; struct inode_operations hepunion_dir_iops = { @@ -1429,30 +1674,37 @@ struct inode_operations hepunion_dir_iops = { .rmdir = hepunion_rmdir, .setattr = hepunion_setattr, .symlink = hepunion_symlink, - .unlink = hepunion_unlink, + .unlink = hepunion_unlink }; struct super_operations hepunion_sops = { +#if LINUX_VERSION_CODE == KERNEL_VERSION(2,6,18) .read_inode = hepunion_read_inode, +#endif .statfs = hepunion_statfs, + .put_super = hepunion_put_super, }; struct dentry_operations hepunion_dops = { - .d_revalidate = hepunion_revalidate, + .d_revalidate = hepunion_revalidate }; struct file_operations hepunion_fops = { .llseek = hepunion_llseek, .open = hepunion_open, .read = hepunion_read, +#if LINUX_VERSION_CODE == KERNEL_VERSION(2,6,18) .readv = hepunion_readv, +#endif .release = hepunion_close, .write = hepunion_write, +#if LINUX_VERSION_CODE == KERNEL_VERSION(2,6,18) .writev = hepunion_writev, +#endif }; struct file_operations hepunion_dir_fops = { .open = hepunion_opendir, .readdir = hepunion_readdir, - .release = hepunion_closedir, + .release = hepunion_closedir }; diff --git a/fs/hepunion/recursivemutex.c b/fs/hepunion/recursivemutex.c index 6b629f2..255ad27 100644 --- a/fs/hepunion/recursivemutex.c +++ b/fs/hepunion/recursivemutex.c @@ -20,21 +20,22 @@ void recursive_mutex_init(recursive_mutex_t *mutex) { } void recursive_mutex_lock(recursive_mutex_t *mutex) { - struct task_struct *task = current; + struct task_struct *task =current; + struct thread_info* ti= task_thread_info(task); /* Increase reference count */ int count = atomic_add_return(1, &mutex->count); /* If noone was locking it, lock */ if (count == 1) { spin_lock(&mutex->lock); /* And set owner */ - mutex->owner = task->thread_info; + mutex->owner = ti; } else { /* Otherwise, someone was locking, then * ensure it's no ourselves. * If it's ourselves, just do nothing * If not, wait for spin lock */ - if (mutex->owner != task->thread_info) { + if (mutex->owner != ti) { spin_lock(&mutex->lock); } } diff --git a/fs/hepunion/wh.c b/fs/hepunion/wh.c index d9f642e..83980db 100644 --- a/fs/hepunion/wh.c +++ b/fs/hepunion/wh.c @@ -26,13 +26,14 @@ #include "hepunion.h" + static int hide_entry(void *buf, const char *name, int namlen, loff_t offset, u64 ino, unsigned d_type); static int check_whiteout(void *buf, const char *name, int namlen, loff_t offset, u64 ino, unsigned d_type) { - char wh_path[PATH_MAX]; - char file_path[PATH_MAX]; + int err = -ENOMEM; + char *wh_path = NULL, *file_path = NULL; struct readdir_context *ctx = (struct readdir_context*)buf; - + pr_info("check_whiteout: %p, %s, %d, %llx, %llx, %d\n", buf, name, namlen, offset, ino, d_type); /* Ignore specials */ @@ -40,13 +41,35 @@ static int check_whiteout(void *buf, const char *name, int namlen, loff_t offset return 0; } + wh_path = kmalloc(PATH_MAX, GFP_KERNEL); + if (!wh_path) { + return -ENOMEM; + } + + file_path = kmalloc(PATH_MAX, GFP_KERNEL); + if (!file_path) { + goto cleanup; + } + /* Get file path */ if (snprintf(file_path, PATH_MAX, "%s%s", ctx->path, name) > PATH_MAX) { - return -ENAMETOOLONG; + err = -ENAMETOOLONG; + goto cleanup; } /* Look for whiteout */ - return find_whiteout(file_path, ctx->context, wh_path); + err = find_whiteout(file_path, ctx->context, wh_path); + +cleanup: + if (wh_path) { + kfree(wh_path); + } + + if (file_path) { + kfree(file_path); + } + + return err; } static int check_writable(void *buf, const char *name, int namlen, loff_t offset, u64 ino, unsigned d_type) { @@ -129,7 +152,9 @@ int create_whiteout(const char *path, char *wh_path, struct hepunion_sb_info *co } static int delete_whiteout(void *buf, const char *name, int namlen, loff_t offset, u64 ino, unsigned d_type) { - char wh_path[PATH_MAX]; + int err; + char *wh_path; + struct readdir_context *ctx = (struct readdir_context*)buf; struct hepunion_sb_info *context = ctx->context; @@ -137,13 +162,23 @@ static int delete_whiteout(void *buf, const char *name, int namlen, loff_t offse /* assert(is_whiteout(name, namlen)); */ + wh_path = kmalloc(PATH_MAX, GFP_KERNEL); + if (!wh_path) { + return -ENOMEM; + } + /* Get whiteout path */ if (snprintf(wh_path, PATH_MAX, "%s%s", ctx->path, name) > PATH_MAX) { + kfree(wh_path); return -ENAMETOOLONG; } /* Remove file */ - return unlink(wh_path, context); + err = unlink(wh_path, context); + + kfree(wh_path); + + return err; } int find_whiteout(const char *path, struct hepunion_sb_info *context, char *wh_path) { @@ -162,34 +197,47 @@ int find_whiteout(const char *path, struct hepunion_sb_info *context, char *wh_p } int hide_directory_contents(const char *path, struct hepunion_sb_info *context) { - int err; + int err = -ENOMEM; struct file *ro_fd; - char rw_path[PATH_MAX]; - char ro_path[PATH_MAX]; + char *rw_path = NULL, *ro_path = NULL; pr_info("hide_directory_contents: %s, %p\n", path, context); + rw_path = kmalloc(PATH_MAX, GFP_KERNEL); + if (!rw_path) { + return -ENOMEM; + } + + ro_path = kmalloc(PATH_MAX, GFP_KERNEL); + if (!ro_path) { + goto cleanup; + } + if (snprintf(ro_path, PATH_MAX, "%s%s", context->read_only_branch, path) > PATH_MAX) { - return -ENAMETOOLONG; + err = -ENAMETOOLONG; + goto cleanup; } /* If RO even does not exist, all correct */ err = check_exist(ro_path, context, 0); if (err < 0) { if (err == -ENOENT) { - return 0; + err = 0; + goto cleanup; } else { - return err; + goto cleanup; } } if (snprintf(rw_path, PATH_MAX, "%s%s", context->read_write_branch, path) > PATH_MAX) { - return -ENAMETOOLONG; + err = -ENAMETOOLONG; + goto cleanup; } ro_fd = open_worker(ro_path, context, O_RDONLY); if (IS_ERR(ro_fd)) { - return PTR_ERR(ro_fd); + err = PTR_ERR(ro_fd); + goto cleanup; } /* Hide all entries */ @@ -198,20 +246,40 @@ int hide_directory_contents(const char *path, struct hepunion_sb_info *context) filp_close(ro_fd, NULL); pop_root(); +cleanup: + if (rw_path) { + kfree(rw_path); + } + + if (ro_path) { + kfree(ro_path); + } + return err; } static int hide_entry(void *buf, const char *name, int namlen, loff_t offset, u64 ino, unsigned d_type) { - char wh_path[PATH_MAX]; + int err; + char *wh_path; struct readdir_context *ctx = (struct readdir_context*)buf; pr_info("hide_entry: %p, %s, %d, %llx, %llx, %d\n", buf, name, namlen, offset, ino, d_type); + wh_path = kmalloc(PATH_MAX, GFP_KERNEL);//dynamic array to solve stack problem + if (!wh_path) { + return -ENOMEM; + } + if (snprintf(wh_path, PATH_MAX, "%s/.wh.%s", ctx->path, name) > PATH_MAX) { + kfree(wh_path); return -ENAMETOOLONG; } - return create_whiteout_worker(wh_path, ctx->context); + err = create_whiteout_worker(wh_path, ctx->context); + + kfree(wh_path); + + return err; } int is_empty_dir(const char *path, const char *ro_path, const char *rw_path, struct hepunion_sb_info *context) { @@ -271,11 +339,15 @@ int is_empty_dir(const char *path, const char *ro_path, const char *rw_path, str int unlink_rw_file(const char *path, const char *rw_path, struct hepunion_sb_info *context, char has_ro_sure) { int err; char has_ro = 0; - char ro_path[PATH_MAX]; - char wh_path[PATH_MAX]; + char *ro_path, *wh_path; pr_info("unlink_rw_file: %s, %s, %p, %u\n", path, rw_path, context, has_ro_sure); + ro_path = kmalloc(PATH_MAX, GFP_KERNEL); + if (!ro_path) { + return -ENOMEM; + } + /* Check if RO exists */ if (!has_ro_sure && find_file(path, ro_path, context, MUST_READ_ONLY) >= 0) { has_ro = 1; @@ -284,15 +356,25 @@ int unlink_rw_file(const char *path, const char *rw_path, struct hepunion_sb_inf has_ro = 1; } + /* No needed any longer */ + kfree(ro_path); + + wh_path = kmalloc(PATH_MAX, GFP_KERNEL); + if (!wh_path) { + return -ENOMEM; + } + /* Check if user can unlink file */ err = can_remove(path, rw_path, context); if (err < 0) { + kfree(wh_path); return err; } /* Remove file */ err = unlink(rw_path, context); if (err < 0) { + kfree(wh_path); return err; } @@ -301,21 +383,33 @@ int unlink_rw_file(const char *path, const char *rw_path, struct hepunion_sb_inf create_whiteout(path, wh_path, context); } + kfree(wh_path); + return 0; } int unlink_whiteout(const char *path, struct hepunion_sb_info *context) { int err; - char wh_path[PATH_MAX]; + char *wh_path; pr_info("unlink_whiteout: %s, %p\n", path, context); + wh_path = kmalloc(PATH_MAX, GFP_KERNEL); + if (!wh_path) { + return -ENOMEM; + } + /* Get wh path */ err = path_to_special(path, WH, context, wh_path); if (err < 0) { + kfree(wh_path); return err; } /* Now unlink whiteout */ - return unlink(wh_path, context); + err = unlink(wh_path, context); + + kfree(wh_path); + + return err; }