5 * Manipulate snapshot tables
9 #define DEBUG_SUBSYSTEM S_SNAP
11 #include <linux/module.h>
12 #include <linux/kmod.h>
13 #include <linux/init.h>
15 #include <linux/slab.h>
16 #include <linux/string.h>
17 #include <linux/snap.h>
18 #include <linux/time.h>
19 #include <asm/uaccess.h>
20 #include "snapfs_internal.h"
23 struct snap_table snap_tables[SNAP_MAX_TABLES];
25 int snap_index2slot(struct snap_table *snap_table, int snap_index)
29 for ( slot=0 ; slot < snap_table->tbl_count ; slot++ )
30 if ( snap_table->snap_items[slot].index == snap_index )
37 /* latest snap: returns
38 - the index of the latest snapshot before NOW
39 - hence it returns 0 in case all the volume snapshots lie in the future
40 - this is the index where a COW will land (will be created)
43 void snap_last(struct snap_cache *info, struct snap *snap)
46 time_t now = CURRENT_TIME;
47 struct snap_table *table;
48 int tableno = info->cache_snap_tableno;
51 if ( tableno < 0 || tableno > SNAP_MAX_TABLES ) {
52 CERROR("invalid table no %d\n", tableno);
56 table = &snap_tables[tableno];
58 /* start at the highest index in the superblock
60 i = table->tbl_count - 1;
62 /* NOTE: i>0 is an unnecessary check */
63 snap->index = table->snap_items[i].index;
64 snap->time = table->snap_items[i].time;
65 snap->gen = table->snap_items[i].gen;
66 CDEBUG(D_SNAP, "index: %d, time[i]: %ld, now: %ld\n",
67 snap->index, snap->time, now);
71 /* return -1 if no COW is needed, otherwise the index of the
72 clone to COW to is returned
75 int snap_needs_cow(struct inode *inode)
78 struct snap_cache *cache;
79 struct filter_inode_info *filter_info;
83 cache = snap_find_cache(inode->i_dev);
87 filter_info = (struct filter_inode_info *) inode->i_filterdata;
88 /* here we find the time of the last snap to compare with */
90 snap_last(cache, &snap);
91 /* decision .... if the snapshot is more recent than the object,
92 * then any change to the object should cause a COW.
94 if (filter_info && filter_info->generation < snap.gen ) {
98 CDEBUG(D_SNAP, "snap_needs_cow, ino %lu , get index %d\n",
102 } /* snap_needs_cow */
104 int snap_print_table(struct ioc_snap_tbl_data *data, char *buf, int *buflen)
106 struct snap_table *table;
107 struct ioc_snap_tbl_data *stbl_out;
108 int tableno = data->no;
109 int i, rc = 0, nleft = (*buflen);
113 if (tableno < 0 || tableno > SNAP_MAX_TABLES) {
114 CERROR("invalid table number %d\n", tableno);
118 table = &snap_tables[tableno];
119 stbl_out = (struct ioc_snap_tbl_data *)buf;
120 stbl_out->count = table->tbl_count - 1;
121 stbl_out->no = tableno;
122 buf_ptr = (char*)stbl_out->snaps;
123 nleft -= buf_ptr - buf;
124 for (i = 1; i < table->tbl_count; i++) {
125 memcpy(buf_ptr, &table->snap_items[i], sizeof(struct snap));
127 nleft -= sizeof(struct snap);
129 CERROR("can not get enough space to print snaptable\n");
133 buf_ptr += sizeof(struct snap);
138 (*buflen) = (*buflen) - nleft;
141 static int inline get_index_of_item(struct snap_table *table, char *name)
143 int count = table->tbl_count;
146 for (i = 0; i < SNAP_MAX; i++) {
147 if (!strcmp(name, table->snap_items[i].name))
150 for (i = 0; i < SNAP_MAX; i++) {
152 for (j = 0; j < (count + 1); j++) {
153 if (table->snap_items[j].index == i) {
163 /* This function will write one item(a snapshot) to snaptable
164 * and will also write to disk.
166 static int snaptable_add_item(struct ioc_snap_tbl_data *data)
168 struct snap_table *table;
169 struct snap_disk_table *disk_snap_table;
170 struct snapshot_operations *snapops;
171 struct snap_cache *cache;
172 int tableno , index, i, count, rc;
174 if (!(cache = snap_find_cache((kdev_t)data->dev)))
177 snapops = filter_c2csnapops(cache->cache_filter);
178 if (!snapops || !snapops->set_meta_attr)
182 if (tableno < 0 || tableno > SNAP_MAX_TABLES) {
183 CERROR("invalid table number %d\n", tableno);
186 table = &snap_tables[tableno];
187 count = table->tbl_count;
189 /* XXX Is down this sema necessary*/
190 down_interruptible(&table->tbl_sema);
192 /*add item in snap_table set generation*/
193 table->snap_items[count].gen = table->generation + 1;
194 table->snap_items[count].time = CURRENT_TIME;
195 /* find table index */
196 index = get_index_of_item(table, data->snaps[0].name);
198 CERROR("snaptable full Or Duplicate name in snaptable\n");
199 GOTO(exit, rc = -EINVAL);
202 table->snap_items[count].index = index;
203 table->snap_items[count].flags = 0;
204 memcpy(&table->snap_items[count].name[0],
205 data->snaps[0].name, SNAP_MAX_NAMELEN);
206 /* we will write the whole snap_table to disk */
207 SNAP_ALLOC(disk_snap_table, sizeof(struct snap_disk_table));
208 if (!disk_snap_table)
209 GOTO(exit, rc = -ENOMEM);
210 disk_snap_table->magic = cpu_to_le32((__u32)DISK_SNAP_TABLE_MAGIC);
211 disk_snap_table->count = cpu_to_le32((__u32)table->tbl_count);
212 disk_snap_table->generation = cpu_to_le32((__u32)table->generation + 1);
213 memset(&disk_snap_table->snap_items[0], 0,
214 SNAP_MAX * sizeof(struct snap_disk));
216 for (i = 1; i <= count; i++) {
217 struct snap *item = &table->snap_items[i];
218 disk_snap_table->snap_items[i-1].time = cpu_to_le64((__u64)item->time);
219 disk_snap_table->snap_items[i-1].gen = cpu_to_le32((__u32)item->gen);
220 disk_snap_table->snap_items[i-1].flags = cpu_to_le32((__u32)item->flags);
221 disk_snap_table->snap_items[i-1].index = cpu_to_le32((__u32)item->index);
222 memcpy(&disk_snap_table->snap_items[i-1].name , item->name, SNAP_MAX_NAMELEN);
224 rc = snapops->set_meta_attr(cache->cache_sb, DISK_SNAPTABLE_ATTR,
225 (char*)disk_snap_table, sizeof(struct snap_disk_table));
227 SNAP_FREE(disk_snap_table, sizeof(struct snap_disk_table));
231 up(&table->tbl_sema);
235 static int delete_inode(struct inode *primary, void *param)
237 struct snap_iterdata * data;
242 struct inode *redirect;
244 struct snap_table *table;
248 struct inode *next_ind = NULL;
249 int my_table[SNAP_MAX];
253 if(!primary) RETURN(0);
255 data = (struct snap_iterdata*) param;
259 tableno = data->tableno;
262 CDEBUG(D_SNAP, "delete_inode ino %lu, index %d\n", primary->i_ino, index);
264 table = &snap_tables[tableno];
266 redirect = snap_get_indirect(primary, NULL, index);
269 CDEBUG(D_SNAP, "redirect inode index %d not exist \n", index);
272 old_ind = redirect->i_ino;
275 /* In destroy indirect inode, we lock the primary inode here */
276 down(&primary->i_sem);
277 slot = snap_index2slot(table, index) - 1;
279 this_index = table->snap_items[slot].index;
280 redirect = snap_get_indirect(primary, NULL, this_index);
284 snap_set_indirect(primary, old_ind, this_index, 0);
285 snap_set_indirect(primary, 0, index, 0);
291 delete_slot = snap_index2slot(table, index);
292 for (slot = table->tbl_count - 1; slot > delete_slot; slot --) {
293 my_table[slot - delete_slot] = table->snap_items[slot].index;
296 this_index = table->tbl_count - delete_slot - 1;
297 next_ind = snap_get_indirect(primary, my_table, this_index);
299 if (next_ind && (next_ind->i_ino == primary->i_ino)) {
303 rc = snap_destroy_indirect(primary, index, next_ind);
307 if (next_ind) iput(next_ind);
310 CERROR("snap_destroy_indirect(ino %lu,index %d),ret %d\n",
311 primary->i_ino, index, rc);
315 static int snap_delete(struct super_block *sb, struct snap_iterdata *data)
317 CDEBUG(D_SNAP, "dev %d, tableno %d, index %d, time %lu\n",
318 data->dev, data->tableno, data->index, data->time );
320 snap_iterate(sb, &delete_inode, NULL, data, SNAP_ITERATE_COWED_INODE);
325 /* This function will delete one item(a snapshot) in the snaptable
326 * and will also delete the item in the disk.
327 * FIXME later, this should be in a transaction.
329 int snaptable_delete_item(struct super_block *sb, struct snap_iterdata *data)
331 struct snap_table *table;
332 struct snap_disk_table *disk_snap_table;
333 struct snapshot_operations *snapops;
334 struct snap_cache *cache;
335 int tableno = data->tableno;
336 int index, i, del_slot, rc;
338 if (!(cache = snap_find_cache((kdev_t)data->dev)))
341 if (tableno < 0 || tableno > SNAP_MAX_TABLES) {
342 CERROR("invalid table number %d\n", tableno);
346 snapops = filter_c2csnapops(cache->cache_filter);
347 if (!snapops || !snapops->set_meta_attr)
351 if (clonefs_mounted(cache, index)) {
352 CERROR("Please first umount this clonefs \n");
355 /*first delete the snapshot
356 * FIXME if snap delete error, how to handle this error*/
357 rc = snap_delete(sb, data);
360 /*delete item in snaptable */
361 table = &snap_tables[tableno];
363 del_slot = snap_index2slot(table, index);
367 down_interruptible(&table->tbl_sema);
369 SNAP_ALLOC(disk_snap_table, sizeof(struct snap_disk_table));
371 if (!disk_snap_table) {
372 up(&table->tbl_sema);
376 /* we will delete the item snap_table to disk */
379 /*Move the items after the delete slot forward one step*/
380 memset(&table->snap_items[index], 0, sizeof(struct snap));
381 while(index < table->tbl_count - 1) {
382 struct snap *item = &table->snap_items[index];
384 item->time = table->snap_items[index + 1].time;
385 item->flags = table->snap_items[index + 1].flags;
386 item->gen = table->snap_items[index + 1].gen;
387 item->index = table->snap_items[index + 1].index;
388 memcpy(&item->name[0], &table->snap_items[index + 1].name[0],
395 disk_snap_table->magic = cpu_to_le32((__u32)DISK_SNAP_TABLE_MAGIC);
396 disk_snap_table->count = cpu_to_le32((__u32)table->tbl_count - 1);
397 disk_snap_table->generation = cpu_to_le32((__u32)table->generation + 1);
398 memset(&disk_snap_table->snap_items[0], 0,
399 SNAP_MAX * sizeof(struct snap_disk));
401 for (i = 0; i < table->tbl_count - 1; i++) {
402 struct snap_disk *disk_item = &disk_snap_table->snap_items[i];
403 struct snap *item = &table->snap_items[i+1];
405 disk_item[i].time = cpu_to_le64((__u64)item->time);
406 disk_item[i].gen = cpu_to_le32((__u32)item->gen);
407 disk_item[i].flags = cpu_to_le32((__u32)item->flags);
408 disk_item[i].index = cpu_to_le32((__u32)item->index);
409 memcpy(&disk_item[i].name , item->name, SNAP_MAX_NAMELEN);
412 rc = snapops->set_meta_attr(cache->cache_sb, DISK_SNAPTABLE_ATTR,
413 (char*)disk_snap_table, sizeof(struct snap_disk_table));
415 SNAP_FREE(disk_snap_table, sizeof(struct snap_disk_table));
417 up(&table->tbl_sema);
421 int snapfs_read_snaptable(struct snap_cache *cache, int tableno)
423 struct snap_table *table;
424 struct snap_disk_table *disk_snap_table;
425 struct snapshot_operations *snapops;
430 snapops = filter_c2csnapops(cache->cache_filter);
431 if (!snapops || !snapops->get_meta_attr)
434 SNAP_ALLOC(disk_snap_table, sizeof(struct snap_disk_table));
436 size = sizeof(struct snap_disk_table);
439 table = &snap_tables[tableno];
441 memset(table, 0, sizeof(struct snap_table));
442 init_MUTEX(&table->tbl_sema);
444 /*Initialized table */
445 table->tbl_count = 1;
446 rc = snapops->get_meta_attr(cache->cache_sb, DISK_SNAPTABLE_ATTR,
447 (char*)disk_snap_table, &size);
449 SNAP_FREE(disk_snap_table, sizeof(struct snap_disk_table));
453 if (le32_to_cpu(disk_snap_table->magic) != DISK_SNAP_TABLE_MAGIC) {
454 CERROR("On disk snaptable is not right \n");
457 table->generation = le32_to_cpu(disk_snap_table->generation);
458 table->tbl_count += le32_to_cpu(disk_snap_table->count);
459 for ( i = 0; i < disk_snap_table->count; i++) {
460 struct snap *item = &table->snap_items[i + 1];
461 item->time = le64_to_cpu(disk_snap_table->snap_items[i].time);
462 item->gen = le32_to_cpu(disk_snap_table->snap_items[i].gen);
463 item->flags = le32_to_cpu(disk_snap_table->snap_items[i].flags);
464 item->index = le32_to_cpu(disk_snap_table->snap_items[i].index);
465 memcpy(&item->name[0], &disk_snap_table->snap_items[i].name[0],
468 SNAP_FREE(disk_snap_table, sizeof(struct snap_disk_table));
472 static int getdata(struct ioc_data *input, void **karg)
476 if (!input->ioc_inlen || !input->ioc_inbuf)
479 SNAP_ALLOC(tmp, input->ioc_inlen);
483 CDEBUG(D_SNAP, "snap_alloc:len %d, add %p\n", input->ioc_inlen, tmp);
485 memset(tmp, 0, input->ioc_inlen);
486 if (copy_from_user(tmp, input->ioc_inbuf, input->ioc_inlen)) {
487 CERROR("get inbuf data error \n");
488 SNAP_FREE(tmp, input->ioc_inlen);
496 static inline void freedata(void *data, struct ioc_data *input)
498 SNAP_FREE(data, input->ioc_inlen);
499 CDEBUG(D_SNAP, "snap_free:len %d, add %p\n", input->ioc_inlen, data);
502 static int get_next_inode(struct inode *pri, void *ino)
504 static ino_t prev_ino = -1 ;
505 ino_t this_ino = pri->i_ino;
506 ino_t find_ino = *(ino_t *)ino;
514 if( find_ino == prev_ino ) {
525 static int snap_get_next_inode(struct snap_ino_list_data *data, ino_t *found_ino, ino_t *parent_ino)
527 kdev_t dev = data->dev;
528 ino_t this_ino = data->ino;
530 struct snap_cache *cache;
533 struct dentry * dentry;
537 cache = snap_find_cache(dev);
543 snap_iterate( cache->cache_sb, &get_next_inode, NULL, &(data->ino),
544 SNAP_ITERATE_COWED_INODE);
546 if( data->ino == this_ino ) {
550 *found_ino = data->ino;
552 if( !(*found_ino) ) return 0;
555 inode = iget (cache->cache_sb, *found_ino);
556 if (list_empty(&inode->i_dentry)) {
557 CERROR("No dentry for ino %lu, Error(XXX)! \n", inode->i_ino);
562 dentry = dget(list_entry(inode->i_dentry.next, struct dentry, d_alias));
564 if( dentry->d_parent->d_inode)
565 *parent_ino = dentry->d_parent->d_inode->i_ino;
575 static int print_inode(struct inode *pri,void *param)
577 CDEBUG(D_SNAP, "cowed inode list: ino %lu \n", pri->i_ino);
581 static int snap_print(struct super_block *sb, void *data)
583 snap_iterate(sb, &print_inode, NULL, data, SNAP_ITERATE_COWED_INODE);
587 static int delete_new_inode(struct inode *pri, void *param)
589 struct snap_iterdata * data;
592 time_t restore_time = 0xFFFFFFFF;
599 if(snap_is_redirector(pri))
602 data = (struct snap_iterdata*) param;
606 restore_time = data->time;
609 CDEBUG(D_SNAP, "ino %lu, index=%d, time=%lu\n",
610 pri->i_ino, index, restore_time);
613 if( pri->i_mtime > restore_time || pri->i_ctime > restore_time ) {
614 struct list_head *head = &pri->i_dentry, *pos;
616 CDEBUG(D_SNAP, "snap_restore ino %lu is newer, delete \n",pri->i_ino);
617 for( pos = head->next; pos != head; pos = pos->next ){
618 d_drop( list_entry(pos, struct dentry, d_alias) );
625 static int restore_inode(struct inode *pri, void *param)
627 struct snap_iterdata * data;
631 time_t restore_time = 0xFFFFFFFF;
633 struct inode *ind = NULL;
636 struct snap_table *table;
643 data = (struct snap_iterdata*) param;
647 tableno = data->tableno;
648 restore_time = data->time;
651 CDEBUG(D_SNAP, "ino %lu, index=%d, time=%lu, tableno %d\n",
652 pri->i_ino, index, restore_time, tableno);
654 /* XXX: should we have = here? */
655 if(pri->i_mtime > restore_time || pri->i_ctime > restore_time) {
656 restore_index = index;
657 table = &snap_tables[tableno];
658 /* first find if there are indirected at the index */
659 ind = snap_get_indirect(pri, NULL, index);
660 /* if not found, get the FIRST index after this and before NOW*/
661 /* XXX fix this later, now use tbl_count, not NOW */
663 restore_slot = snap_index2slot(table, index);
664 for(slot = restore_slot; slot <= table->tbl_count;
666 ind = snap_get_indirect (pri, NULL,
667 table->snap_items[slot].index);
669 restore_index = table->snap_items[slot].index;
676 CDEBUG(D_SNAP, "restore ino %lu with index %d\n",
677 pri->i_ino, restore_index);
679 snap_restore_indirect(pri, restore_index);
681 //delete_inode(pri, param);
682 snap_destroy_indirect(pri, restore_index, NULL);
685 CDEBUG(D_SNAP, "ERROR:restore ino %lu\n", pri->i_ino);
689 CDEBUG(D_SNAP, "ino %lu is older, don't restore\n", pri->i_ino);
694 //int snap_restore(struct super_block *sb, void *data)
695 static int snap_restore(struct super_block *sb, struct snap_iterdata *data)
697 CDEBUG(D_SNAP, "dev %d, tableno %d, index %d, time %lu\n",
698 data->dev, data->tableno, data->index, data->time );
700 snap_iterate(sb, &delete_new_inode, NULL, data, SNAP_ITERATE_ALL_INODE);
701 snap_iterate(sb, &restore_inode, NULL, data, SNAP_ITERATE_COWED_INODE );
705 /* return the index number of a name in a table */
706 int snap_get_index_from_name(int tableno, char *name)
708 struct snap_table *table;
711 if ( tableno < 0 || tableno > SNAP_MAX_TABLES ) {
712 CERROR("invalid table number %d\n", tableno);
716 table = &snap_tables[tableno];
718 for ( slot = 0 ; slot < table->tbl_count; slot++) {
719 if (!strcmp(&table->snap_items[slot].name[0], name)) {
720 return table->snap_items[slot].index;
726 int snap_iterate_func( struct ioc_snap_tbl_data *data, unsigned int cmd)
728 struct snapshot_operations *snapops;
729 struct snap_iterdata iterate_data;
730 struct super_block *sb;
731 struct snap_cache *cache;
732 struct snap_table *table;
733 int index, tableno, slot, rc;
737 if (!(cache = snap_find_cache((kdev_t)data->dev)))
740 snapops = filter_c2csnapops(cache->cache_filter);
741 if (!snapops || !snapops->set_meta_attr)
745 if (tableno < 0 || tableno > SNAP_MAX_TABLES) {
746 CERROR("invalid table number %d\n", tableno);
750 sb = cache->cache_sb;
751 table = &snap_tables[tableno];
753 index = snap_get_index_from_name(tableno, data->snaps[0].name);
755 CERROR("Could not find %s in snaptable\n",
756 data->snaps[0].name);
759 iterate_data.dev = (kdev_t)data->dev;
760 iterate_data.index = index;
761 iterate_data.tableno = tableno;
762 slot = snap_index2slot (table, index);
766 iterate_data.time = table->snap_items[slot].time;
767 CDEBUG(D_SNAP, "dev %d, tableno %d, index %d, time %lu\n",
768 iterate_data.dev, iterate_data.tableno,
769 iterate_data.index, iterate_data.time);
773 rc = snap_print(sb, &iterate_data);
775 case IOC_SNAP_DELETE:
776 rc = snaptable_delete_item(sb, &iterate_data);
778 case IOC_SNAP_RESTORE:
779 rc = snap_restore(sb, &iterate_data);
782 CERROR("unrecognized cmd %d \n", cmd);
789 #define BUF_SIZE 1024
790 int snap_ioctl (struct inode * inode, struct file * filp,
791 unsigned int cmd, unsigned long arg)
793 struct ioc_data input;
800 dev = MINOR(inode->i_rdev);
801 if (dev != SNAP_PSDEV_MINOR)
805 CDEBUG(D_IOCTL, "invalid inode\n");
809 if ( _IOC_TYPE(cmd) != IOC_SNAP_TYPE ||
810 _IOC_NR(cmd) < IOC_SNAP_MIN_NR ||
811 _IOC_NR(cmd) > IOC_SNAP_MAX_NR ) {
812 /*FIXME: Sometimes Gettimeof the day will come here
813 * still do not know the reason*/
814 CDEBUG(D_IOCTL, "invalid ioctl ( type %d, nr %d, size %d )\n",
815 _IOC_TYPE(cmd), _IOC_NR(cmd), _IOC_SIZE(cmd));
819 /* get data structures */
820 rc = copy_from_user(&input, (void *)arg, sizeof(input));
823 /* get data from the input data*/
824 rc = getdata(&input, &karg);
829 rc = snaptable_add_item(karg);
832 case IOC_SNAP_PRINTTABLE: {
833 struct ioc_data *output;
836 SNAP_ALLOC(tmp, BUF_SIZE);
837 output=(struct ioc_data*)tmp;
838 output->ioc_inbuf = output->ioc_bulk;
839 output->ioc_inlen = BUF_SIZE - sizeof(int) - sizeof(unsigned long);
840 snap_print_table(karg, output->ioc_inbuf, &(output->ioc_inlen));
842 rc = copy_to_user((char *)arg, output,
843 (output->ioc_inlen + sizeof(int) + sizeof(unsigned long)));
844 SNAP_FREE(tmp, BUF_SIZE);
848 case IOC_SNAP_GETINDEXFROMNAME: {
850 char name[SNAP_MAX_NAMELEN];
852 struct snap_cache *cache;
856 struct get_index_struct {
858 char name[SNAP_MAX_NAMELEN];
861 struct get_index_struct *data = karg;
863 name_len = input.ioc_inlen - sizeof(kdev_t);
865 memset(name, 0, SNAP_MAX_NAMELEN);
866 if(name_len > SNAP_MAX_NAMELEN)
867 name_len = SNAP_MAX_NAMELEN;
870 /*for(i=0 ; i< name_len; i++) {
871 name[i] = data->name[i];
874 memcpy(name, data->name, name_len);
875 printk("dev %d , len %d, name_len %d, find name is [%s]\n",
876 dev, input.ioc_inlen, name_len, name);
877 cache = snap_find_cache(dev);
883 tableno = cache->cache_snap_tableno;
885 index = snap_get_index_from_name(tableno, name);
886 rc = copy_to_user((char *)arg, &index, sizeof(index));
889 case IOC_SNAP_GET_NEXT_INO: {
890 struct get_ino_struct{
894 get_ino.found_ino = 0;
895 get_ino.parent_ino = 0;
896 rc = snap_get_next_inode(karg, &get_ino.found_ino, &get_ino.parent_ino);
897 rc = copy_to_user((char *)arg, &get_ino, sizeof(get_ino));
900 case IOC_SNAP_GET_INO_INFO: {
906 struct snap_cache *cache;
909 struct ioc_ino_info *data = karg;
912 cache = snap_find_cache(data->dev);
918 printk("get_ino_info, dev %d, ino %lu, index %d\n",
919 data->dev, data->ino, data->index);
920 pri = iget(cache->cache_sb, data->ino);
921 ind = snap_get_indirect(pri, NULL, data->index);
923 ind_ino = ind->i_ino;
927 printk("get_ino_info, get ind %lu\n", ind_ino);
928 rc = copy_to_user((char *)arg, &ind_ino, sizeof(ino_t));
931 case IOC_SNAP_DELETE:
932 case IOC_SNAP_RESTORE:
934 rc = snap_iterate_func(karg, cmd);
937 case IOC_SNAP_DEVFAIL:
938 snap_debug_failcode = (unsigned int)arg;
941 case IOC_SNAP_SHOW_DOTSNAP: {
942 struct ioc_show_info{
946 struct snap_cache *cache;
947 struct ioc_show_info *data = karg;
949 cache = snap_find_cache(data->dev);
955 cache->cache_show_dotsnap = (char)data->show;
956 CDEBUG(D_IOCTL, "Set show dotsnap: %s\n",
957 data->show ? "Yes" : "No");
966 freedata(karg, &input);