Skip to content

Commit

Permalink
Clickfs: Add read-parameter support by opening with O_RDWR.
Browse files Browse the repository at this point in the history
Again, original version from Meraki.
  • Loading branch information
kohler committed Sep 24, 2013
1 parent 22e084c commit d679193
Showing 1 changed file with 69 additions and 16 deletions.
85 changes: 69 additions & 16 deletions linuxmodule/clickfs.cc
Original file line number Diff line number Diff line change
Expand Up @@ -202,7 +202,11 @@ click_inode(struct super_block *sb, ino_t ino)
if (click_ino.is_handler(ino)) {
int hi = click_ino.ino_handler(ino);
if (const Handler *h = Router::handler(click_router, hi)) {
inode->i_mode = S_IFREG | (h->read_visible() ? click_fsmode.read : 0) | (h->write_visible() ? click_fsmode.write : 0);
inode->i_mode = S_IFREG;
if (h->read_visible())
inode->i_mode |= click_fsmode.read;
if (h->write_visible() || (h->read_visible() && h->read_param()))
inode->i_mode |= click_fsmode.write;
inode->i_uid = click_fsmode.uid;
inode->i_gid = click_fsmode.gid;
inode->i_op = click_handler_inode_ops;
Expand Down Expand Up @@ -507,9 +511,8 @@ click_delete_dentry(struct dentry *)
// see static_assert below
#define HS_ALIVE 1
#define HS_READING 2
#define HS_WRITING 4
#define HS_DONE 8
#define HS_RAW 16
#define HS_DONE 4
#define HS_RAW 8
#define HS_DIRECT HANDLER_DIRECT
#define HS_WRITE_UNLIMITED HANDLER_WRITE_UNLIMITED

Expand Down Expand Up @@ -619,23 +622,23 @@ handler_open(struct inode *inode, struct file *filp)
{
LOCK_CONFIG_READ();

bool reading = (filp->f_flags & O_ACCMODE) != O_WRONLY;
bool writing = (filp->f_flags & O_ACCMODE) != O_RDONLY;
bool reading = (filp->f_mode & FMODE_READ) != 0;
bool writing = (filp->f_mode & FMODE_WRITE) != 0;

int retval = 0;
HandlerString* hs = 0;
const Handler *h;

if ((reading && writing)
|| (filp->f_flags & O_APPEND)
|| (writing && !(filp->f_flags & O_TRUNC)))
if ((filp->f_flags & O_APPEND)
|| (!reading && writing && !(filp->f_flags & O_TRUNC)))
retval = -EACCES;
else if ((retval = click_ino_check(inode, -EIO)) < 0)
/* save retval */;
else if (!(h = Router::handler(click_router, click_ino.ino_handler(inode->i_ino))))
retval = -EIO;
else if ((reading && !h->read_visible())
|| (writing && !h->write_visible()))
else if (reading && writing && (h->flags() & HANDLER_DIRECT))
retval = -EACCES;
else if (reading ? !h->read_visible() : !h->write_visible())
retval = -EPERM;
else if (!(hs = alloc_handler_string(h)))
retval = -ENOMEM;
Expand Down Expand Up @@ -702,6 +705,43 @@ handler_prepare_read(HandlerString* hs, struct file* filp,
return retval;
}

static loff_t
handler_llseek(struct file* filp, loff_t offset, int origin)
{
HandlerString* hs = FILP_HS(filp);
if (!hs)
return -EIO;

if ((filp->f_mode & FMODE_READ) && (filp->f_mode & FMODE_WRITE))
return -ESPIPE;

if (origin == SEEK_END) {
// ensure the string's existence before seeking
if ((filp->f_mode & FMODE_READ)
&& (hs->flags & (HS_DIRECT | HS_DONE)) != HS_DONE) {
ssize_t r = handler_prepare_read(hs, filp, 0, 0, 0);
if (r < 0)
return r;
}
offset += hs->data.length();
} else if (origin == SEEK_CUR)
offset += filp->f_pos;

if (offset >= 0 && offset <= 0x7FFFFFFF) {
if (offset != filp->f_pos) {
filp->f_pos = offset;
#if LINUX_VERSION_CODE >= KERNEL_VERSION(2, 6, 0)
filp->f_version = 0;
#else
filp->f_reada = 0;
filp->f_version = ++event;
#endif
}
return offset;
} else
return -EINVAL;
}

static ssize_t
handler_read(struct file *filp, char *buffer, size_t count, loff_t *store_f_pos)
{
Expand All @@ -711,6 +751,13 @@ handler_read(struct file *filp, char *buffer, size_t count, loff_t *store_f_pos)
if (!hs)
return r;

// read-write handler: reset file position if switching to reading
if ((filp->f_mode & FMODE_READ) && (filp->f_mode & FMODE_WRITE)
&& !(hs->flags & HS_READING)) {
f_pos = 0;
hs->flags |= HS_READING;
}

// (re)read handler if necessary
if ((hs->flags & (HS_DIRECT | HS_DONE)) != HS_DONE) {
r = handler_prepare_read(hs, filp, buffer, count, store_f_pos);
Expand Down Expand Up @@ -749,6 +796,12 @@ handler_write(struct file *filp, const char *buffer, size_t count, loff_t *store
&& !(hs->flags & HS_WRITE_UNLIMITED))
return -EFBIG;
#endif
// read-write handler: reset file position if switching to writing
if ((filp->f_mode & FMODE_READ) && (filp->f_mode & FMODE_WRITE)
&& (hs->flags & HS_READING)) {
f_pos = 0;
hs->flags &= ~HS_READING;
}

if (f_pos + count > old_length) {
s.append_fill(0, f_pos + count - old_length);
Expand All @@ -769,7 +822,7 @@ handler_write(struct file *filp, const char *buffer, size_t count, loff_t *store
if (copy_from_user(data + f_pos, buffer, count) > 0)
return -EFAULT;

*store_f_pos += count;
*store_f_pos = f_pos + count;
return count;
}

Expand Down Expand Up @@ -870,7 +923,7 @@ handler_flush(struct file *filp
#endif
)
{
bool writing = (filp->f_flags & O_ACCMODE) != O_RDONLY;
bool writing = (filp->f_mode & FMODE_WRITE) && !(filp->f_mode & FMODE_READ);
HandlerString* hs = FILP_WRITE_HS(filp);
int retval = 0;

Expand All @@ -880,8 +933,7 @@ handler_flush(struct file *filp
int f_count = atomic_read(&filp->f_count);
#endif

if (writing && f_count == 1 && hs
&& !(hs->flags & HS_DONE)) {
if (writing && f_count == 1 && hs && !(hs->flags & HS_DONE)) {
LOCK_CONFIG_WRITE();
retval = handler_do_write(filp, 0);
UNLOCK_CONFIG_WRITE();
Expand Down Expand Up @@ -1031,7 +1083,7 @@ init_clickfs()
static_assert(sizeof(((struct inode *)0)->u) >= sizeof(ClickInodeInfo), "The file-system-specific data in struct inode isn't big enough.");
#endif
static_assert(HANDLER_DIRECT + HANDLER_WRITE_UNLIMITED < Handler::USER_FLAG_0, "Too few driver handler flags available.");
static_assert(((HS_DIRECT | HS_WRITE_UNLIMITED) & (HS_READING | HS_WRITING | HS_DONE | HS_RAW)) == 0, "Handler flag overlap.");
static_assert(((HS_DIRECT | HS_WRITE_UNLIMITED) & (HS_READING | HS_DONE | HS_RAW)) == 0, "Handler flag overlap.");

mutex_init(&handler_strings_lock);
mutex_init(&clickfs_lock);
Expand Down Expand Up @@ -1068,6 +1120,7 @@ init_clickfs()
click_dir_inode_ops->revalidate = click_dir_revalidate;
#endif

click_handler_file_ops->llseek = handler_llseek;
click_handler_file_ops->read = handler_read;
click_handler_file_ops->write = handler_write;
#if HAVE_UNLOCKED_IOCTL
Expand Down

0 comments on commit d679193

Please sign in to comment.