|
@@ -24,6 +24,7 @@ struct hostfs_inode_info {
|
|
int fd;
|
|
int fd;
|
|
fmode_t mode;
|
|
fmode_t mode;
|
|
struct inode vfs_inode;
|
|
struct inode vfs_inode;
|
|
|
|
+ struct mutex open_mutex;
|
|
};
|
|
};
|
|
|
|
|
|
static inline struct hostfs_inode_info *HOSTFS_I(struct inode *inode)
|
|
static inline struct hostfs_inode_info *HOSTFS_I(struct inode *inode)
|
|
@@ -92,16 +93,22 @@ static char *__dentry_name(struct dentry *dentry, char *name)
|
|
__putname(name);
|
|
__putname(name);
|
|
return NULL;
|
|
return NULL;
|
|
}
|
|
}
|
|
|
|
+
|
|
|
|
+ /*
|
|
|
|
+ * This function relies on the fact that dentry_path_raw() will place
|
|
|
|
+ * the path name at the end of the provided buffer.
|
|
|
|
+ */
|
|
|
|
+ BUG_ON(p + strlen(p) + 1 != name + PATH_MAX);
|
|
|
|
+
|
|
strlcpy(name, root, PATH_MAX);
|
|
strlcpy(name, root, PATH_MAX);
|
|
if (len > p - name) {
|
|
if (len > p - name) {
|
|
__putname(name);
|
|
__putname(name);
|
|
return NULL;
|
|
return NULL;
|
|
}
|
|
}
|
|
- if (p > name + len) {
|
|
|
|
- char *s = name + len;
|
|
|
|
- while ((*s++ = *p++) != '\0')
|
|
|
|
- ;
|
|
|
|
- }
|
|
|
|
|
|
+
|
|
|
|
+ if (p > name + len)
|
|
|
|
+ strcpy(name + len, p);
|
|
|
|
+
|
|
return name;
|
|
return name;
|
|
}
|
|
}
|
|
|
|
|
|
@@ -135,21 +142,19 @@ static char *follow_link(char *link)
|
|
int len, n;
|
|
int len, n;
|
|
char *name, *resolved, *end;
|
|
char *name, *resolved, *end;
|
|
|
|
|
|
- len = 64;
|
|
|
|
- while (1) {
|
|
|
|
|
|
+ name = __getname();
|
|
|
|
+ if (!name) {
|
|
n = -ENOMEM;
|
|
n = -ENOMEM;
|
|
- name = kmalloc(len, GFP_KERNEL);
|
|
|
|
- if (name == NULL)
|
|
|
|
- goto out;
|
|
|
|
-
|
|
|
|
- n = hostfs_do_readlink(link, name, len);
|
|
|
|
- if (n < len)
|
|
|
|
- break;
|
|
|
|
- len *= 2;
|
|
|
|
- kfree(name);
|
|
|
|
|
|
+ goto out_free;
|
|
}
|
|
}
|
|
|
|
+
|
|
|
|
+ n = hostfs_do_readlink(link, name, PATH_MAX);
|
|
if (n < 0)
|
|
if (n < 0)
|
|
goto out_free;
|
|
goto out_free;
|
|
|
|
+ else if (n == PATH_MAX) {
|
|
|
|
+ n = -E2BIG;
|
|
|
|
+ goto out_free;
|
|
|
|
+ }
|
|
|
|
|
|
if (*name == '/')
|
|
if (*name == '/')
|
|
return name;
|
|
return name;
|
|
@@ -168,13 +173,12 @@ static char *follow_link(char *link)
|
|
}
|
|
}
|
|
|
|
|
|
sprintf(resolved, "%s%s", link, name);
|
|
sprintf(resolved, "%s%s", link, name);
|
|
- kfree(name);
|
|
|
|
|
|
+ __putname(name);
|
|
kfree(link);
|
|
kfree(link);
|
|
return resolved;
|
|
return resolved;
|
|
|
|
|
|
out_free:
|
|
out_free:
|
|
- kfree(name);
|
|
|
|
- out:
|
|
|
|
|
|
+ __putname(name);
|
|
return ERR_PTR(n);
|
|
return ERR_PTR(n);
|
|
}
|
|
}
|
|
|
|
|
|
@@ -225,6 +229,7 @@ static struct inode *hostfs_alloc_inode(struct super_block *sb)
|
|
hi->fd = -1;
|
|
hi->fd = -1;
|
|
hi->mode = 0;
|
|
hi->mode = 0;
|
|
inode_init_once(&hi->vfs_inode);
|
|
inode_init_once(&hi->vfs_inode);
|
|
|
|
+ mutex_init(&hi->open_mutex);
|
|
return &hi->vfs_inode;
|
|
return &hi->vfs_inode;
|
|
}
|
|
}
|
|
|
|
|
|
@@ -257,6 +262,9 @@ static int hostfs_show_options(struct seq_file *seq, struct dentry *root)
|
|
if (strlen(root_path) > offset)
|
|
if (strlen(root_path) > offset)
|
|
seq_printf(seq, ",%s", root_path + offset);
|
|
seq_printf(seq, ",%s", root_path + offset);
|
|
|
|
|
|
|
|
+ if (append)
|
|
|
|
+ seq_puts(seq, ",append");
|
|
|
|
+
|
|
return 0;
|
|
return 0;
|
|
}
|
|
}
|
|
|
|
|
|
@@ -284,6 +292,7 @@ static int hostfs_readdir(struct file *file, struct dir_context *ctx)
|
|
if (dir == NULL)
|
|
if (dir == NULL)
|
|
return -error;
|
|
return -error;
|
|
next = ctx->pos;
|
|
next = ctx->pos;
|
|
|
|
+ seek_dir(dir, next);
|
|
while ((name = read_dir(dir, &next, &ino, &len, &type)) != NULL) {
|
|
while ((name = read_dir(dir, &next, &ino, &len, &type)) != NULL) {
|
|
if (!dir_emit(ctx, name, len, ino, type))
|
|
if (!dir_emit(ctx, name, len, ino, type))
|
|
break;
|
|
break;
|
|
@@ -293,13 +302,12 @@ static int hostfs_readdir(struct file *file, struct dir_context *ctx)
|
|
return 0;
|
|
return 0;
|
|
}
|
|
}
|
|
|
|
|
|
-static int hostfs_file_open(struct inode *ino, struct file *file)
|
|
|
|
|
|
+static int hostfs_open(struct inode *ino, struct file *file)
|
|
{
|
|
{
|
|
- static DEFINE_MUTEX(open_mutex);
|
|
|
|
char *name;
|
|
char *name;
|
|
- fmode_t mode = 0;
|
|
|
|
|
|
+ fmode_t mode;
|
|
int err;
|
|
int err;
|
|
- int r = 0, w = 0, fd;
|
|
|
|
|
|
+ int r, w, fd;
|
|
|
|
|
|
mode = file->f_mode & (FMODE_READ | FMODE_WRITE);
|
|
mode = file->f_mode & (FMODE_READ | FMODE_WRITE);
|
|
if ((mode & HOSTFS_I(ino)->mode) == mode)
|
|
if ((mode & HOSTFS_I(ino)->mode) == mode)
|
|
@@ -308,12 +316,12 @@ static int hostfs_file_open(struct inode *ino, struct file *file)
|
|
mode |= HOSTFS_I(ino)->mode;
|
|
mode |= HOSTFS_I(ino)->mode;
|
|
|
|
|
|
retry:
|
|
retry:
|
|
|
|
+ r = w = 0;
|
|
|
|
+
|
|
if (mode & FMODE_READ)
|
|
if (mode & FMODE_READ)
|
|
r = 1;
|
|
r = 1;
|
|
if (mode & FMODE_WRITE)
|
|
if (mode & FMODE_WRITE)
|
|
- w = 1;
|
|
|
|
- if (w)
|
|
|
|
- r = 1;
|
|
|
|
|
|
+ r = w = 1;
|
|
|
|
|
|
name = dentry_name(file->f_path.dentry);
|
|
name = dentry_name(file->f_path.dentry);
|
|
if (name == NULL)
|
|
if (name == NULL)
|
|
@@ -324,15 +332,16 @@ retry:
|
|
if (fd < 0)
|
|
if (fd < 0)
|
|
return fd;
|
|
return fd;
|
|
|
|
|
|
- mutex_lock(&open_mutex);
|
|
|
|
|
|
+ mutex_lock(&HOSTFS_I(ino)->open_mutex);
|
|
/* somebody else had handled it first? */
|
|
/* somebody else had handled it first? */
|
|
if ((mode & HOSTFS_I(ino)->mode) == mode) {
|
|
if ((mode & HOSTFS_I(ino)->mode) == mode) {
|
|
- mutex_unlock(&open_mutex);
|
|
|
|
|
|
+ mutex_unlock(&HOSTFS_I(ino)->open_mutex);
|
|
|
|
+ close_file(&fd);
|
|
return 0;
|
|
return 0;
|
|
}
|
|
}
|
|
if ((mode | HOSTFS_I(ino)->mode) != mode) {
|
|
if ((mode | HOSTFS_I(ino)->mode) != mode) {
|
|
mode |= HOSTFS_I(ino)->mode;
|
|
mode |= HOSTFS_I(ino)->mode;
|
|
- mutex_unlock(&open_mutex);
|
|
|
|
|
|
+ mutex_unlock(&HOSTFS_I(ino)->open_mutex);
|
|
close_file(&fd);
|
|
close_file(&fd);
|
|
goto retry;
|
|
goto retry;
|
|
}
|
|
}
|
|
@@ -342,12 +351,12 @@ retry:
|
|
err = replace_file(fd, HOSTFS_I(ino)->fd);
|
|
err = replace_file(fd, HOSTFS_I(ino)->fd);
|
|
close_file(&fd);
|
|
close_file(&fd);
|
|
if (err < 0) {
|
|
if (err < 0) {
|
|
- mutex_unlock(&open_mutex);
|
|
|
|
|
|
+ mutex_unlock(&HOSTFS_I(ino)->open_mutex);
|
|
return err;
|
|
return err;
|
|
}
|
|
}
|
|
}
|
|
}
|
|
HOSTFS_I(ino)->mode = mode;
|
|
HOSTFS_I(ino)->mode = mode;
|
|
- mutex_unlock(&open_mutex);
|
|
|
|
|
|
+ mutex_unlock(&HOSTFS_I(ino)->open_mutex);
|
|
|
|
|
|
return 0;
|
|
return 0;
|
|
}
|
|
}
|
|
@@ -382,7 +391,7 @@ static const struct file_operations hostfs_file_fops = {
|
|
.read_iter = generic_file_read_iter,
|
|
.read_iter = generic_file_read_iter,
|
|
.write_iter = generic_file_write_iter,
|
|
.write_iter = generic_file_write_iter,
|
|
.mmap = generic_file_mmap,
|
|
.mmap = generic_file_mmap,
|
|
- .open = hostfs_file_open,
|
|
|
|
|
|
+ .open = hostfs_open,
|
|
.release = hostfs_file_release,
|
|
.release = hostfs_file_release,
|
|
.fsync = hostfs_fsync,
|
|
.fsync = hostfs_fsync,
|
|
};
|
|
};
|
|
@@ -391,6 +400,8 @@ static const struct file_operations hostfs_dir_fops = {
|
|
.llseek = generic_file_llseek,
|
|
.llseek = generic_file_llseek,
|
|
.iterate = hostfs_readdir,
|
|
.iterate = hostfs_readdir,
|
|
.read = generic_read_dir,
|
|
.read = generic_read_dir,
|
|
|
|
+ .open = hostfs_open,
|
|
|
|
+ .fsync = hostfs_fsync,
|
|
};
|
|
};
|
|
|
|
|
|
static int hostfs_writepage(struct page *page, struct writeback_control *wbc)
|
|
static int hostfs_writepage(struct page *page, struct writeback_control *wbc)
|
|
@@ -398,7 +409,7 @@ static int hostfs_writepage(struct page *page, struct writeback_control *wbc)
|
|
struct address_space *mapping = page->mapping;
|
|
struct address_space *mapping = page->mapping;
|
|
struct inode *inode = mapping->host;
|
|
struct inode *inode = mapping->host;
|
|
char *buffer;
|
|
char *buffer;
|
|
- unsigned long long base;
|
|
|
|
|
|
+ loff_t base = page_offset(page);
|
|
int count = PAGE_CACHE_SIZE;
|
|
int count = PAGE_CACHE_SIZE;
|
|
int end_index = inode->i_size >> PAGE_CACHE_SHIFT;
|
|
int end_index = inode->i_size >> PAGE_CACHE_SHIFT;
|
|
int err;
|
|
int err;
|
|
@@ -407,7 +418,6 @@ static int hostfs_writepage(struct page *page, struct writeback_control *wbc)
|
|
count = inode->i_size & (PAGE_CACHE_SIZE-1);
|
|
count = inode->i_size & (PAGE_CACHE_SIZE-1);
|
|
|
|
|
|
buffer = kmap(page);
|
|
buffer = kmap(page);
|
|
- base = ((unsigned long long) page->index) << PAGE_CACHE_SHIFT;
|
|
|
|
|
|
|
|
err = write_file(HOSTFS_I(inode)->fd, &base, buffer, count);
|
|
err = write_file(HOSTFS_I(inode)->fd, &base, buffer, count);
|
|
if (err != count) {
|
|
if (err != count) {
|
|
@@ -432,26 +442,29 @@ static int hostfs_writepage(struct page *page, struct writeback_control *wbc)
|
|
static int hostfs_readpage(struct file *file, struct page *page)
|
|
static int hostfs_readpage(struct file *file, struct page *page)
|
|
{
|
|
{
|
|
char *buffer;
|
|
char *buffer;
|
|
- long long start;
|
|
|
|
- int err = 0;
|
|
|
|
|
|
+ loff_t start = page_offset(page);
|
|
|
|
+ int bytes_read, ret = 0;
|
|
|
|
|
|
- start = (long long) page->index << PAGE_CACHE_SHIFT;
|
|
|
|
buffer = kmap(page);
|
|
buffer = kmap(page);
|
|
- err = read_file(FILE_HOSTFS_I(file)->fd, &start, buffer,
|
|
|
|
|
|
+ bytes_read = read_file(FILE_HOSTFS_I(file)->fd, &start, buffer,
|
|
PAGE_CACHE_SIZE);
|
|
PAGE_CACHE_SIZE);
|
|
- if (err < 0)
|
|
|
|
|
|
+ if (bytes_read < 0) {
|
|
|
|
+ ClearPageUptodate(page);
|
|
|
|
+ SetPageError(page);
|
|
|
|
+ ret = bytes_read;
|
|
goto out;
|
|
goto out;
|
|
|
|
+ }
|
|
|
|
|
|
- memset(&buffer[err], 0, PAGE_CACHE_SIZE - err);
|
|
|
|
|
|
+ memset(buffer + bytes_read, 0, PAGE_CACHE_SIZE - bytes_read);
|
|
|
|
|
|
- flush_dcache_page(page);
|
|
|
|
|
|
+ ClearPageError(page);
|
|
SetPageUptodate(page);
|
|
SetPageUptodate(page);
|
|
- if (PageError(page)) ClearPageError(page);
|
|
|
|
- err = 0;
|
|
|
|
|
|
+
|
|
out:
|
|
out:
|
|
|
|
+ flush_dcache_page(page);
|
|
kunmap(page);
|
|
kunmap(page);
|
|
unlock_page(page);
|
|
unlock_page(page);
|
|
- return err;
|
|
|
|
|
|
+ return ret;
|
|
}
|
|
}
|
|
|
|
|
|
static int hostfs_write_begin(struct file *file, struct address_space *mapping,
|
|
static int hostfs_write_begin(struct file *file, struct address_space *mapping,
|
|
@@ -528,11 +541,13 @@ static int read_name(struct inode *ino, char *name)
|
|
init_special_inode(ino, st.mode & S_IFMT, rdev);
|
|
init_special_inode(ino, st.mode & S_IFMT, rdev);
|
|
ino->i_op = &hostfs_iops;
|
|
ino->i_op = &hostfs_iops;
|
|
break;
|
|
break;
|
|
-
|
|
|
|
- default:
|
|
|
|
|
|
+ case S_IFREG:
|
|
ino->i_op = &hostfs_iops;
|
|
ino->i_op = &hostfs_iops;
|
|
ino->i_fop = &hostfs_file_fops;
|
|
ino->i_fop = &hostfs_file_fops;
|
|
ino->i_mapping->a_ops = &hostfs_aops;
|
|
ino->i_mapping->a_ops = &hostfs_aops;
|
|
|
|
+ break;
|
|
|
|
+ default:
|
|
|
|
+ return -EIO;
|
|
}
|
|
}
|
|
|
|
|
|
ino->i_ino = st.ino;
|
|
ino->i_ino = st.ino;
|
|
@@ -566,10 +581,7 @@ static int hostfs_create(struct inode *dir, struct dentry *dentry, umode_t mode,
|
|
if (name == NULL)
|
|
if (name == NULL)
|
|
goto out_put;
|
|
goto out_put;
|
|
|
|
|
|
- fd = file_create(name,
|
|
|
|
- mode & S_IRUSR, mode & S_IWUSR, mode & S_IXUSR,
|
|
|
|
- mode & S_IRGRP, mode & S_IWGRP, mode & S_IXGRP,
|
|
|
|
- mode & S_IROTH, mode & S_IWOTH, mode & S_IXOTH);
|
|
|
|
|
|
+ fd = file_create(name, mode & S_IFMT);
|
|
if (fd < 0)
|
|
if (fd < 0)
|
|
error = fd;
|
|
error = fd;
|
|
else
|
|
else
|