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];
26 static void snap_lock_table(int table_no)
29 spin_lock(snap_tables[table_no].tbl_lock);
33 static void snap_unlock_table(int table_no)
36 spin_unlock(snap_tables[table_no].tbl_lock);
41 int snap_index2slot(struct snap_table *snap_table, int snap_index)
45 for ( slot=0 ; slot < snap_table->tbl_count ; slot++ )
46 if ( snap_table->snap_items[slot].index == snap_index )
53 /* latest snap: returns
54 - the index of the latest snapshot before NOW
55 - hence it returns 0 in case all the volume snapshots lie in the future
56 - this is the index where a COW will land (will be created)
59 void snap_last(struct snap_cache *info, struct snap *snap)
62 time_t now = CURRENT_TIME;
63 struct snap_table *table;
64 int tableno = info->cache_snap_tableno;
67 if ( tableno < 0 || tableno > SNAP_MAX_TABLES ) {
68 CERROR("invalid table no %d\n", tableno);
72 table = &snap_tables[tableno];
74 /* start at the highest index in the superblock
76 i = table->tbl_count - 1;
78 /* NOTE: i>0 is an unnecessary check */
79 snap->index = table->snap_items[i].index;
80 snap->time = table->snap_items[i].time;
81 snap->gen = table->snap_items[i].gen;
82 CDEBUG(D_SNAP, "index: %d, time[i]: %ld, now: %ld\n",
83 snap->index, snap->time, now);
87 /* return -1 if no COW is needed, otherwise the index of the
88 clone to COW to is returned
91 int snap_needs_cow(struct inode *inode)
94 struct snap_cache *cache;
95 struct filter_inode_info *filter_info;
99 cache = snap_find_cache(inode->i_dev);
103 filter_info = (struct filter_inode_info *) inode->i_filterdata;
104 /* here we find the time of the last snap to compare with */
106 snap_last(cache, &snap);
107 /* decision .... if the snapshot is more recent than the object,
108 * then any change to the object should cause a COW.
110 if (filter_info && filter_info->generation < snap.gen ) {
114 CDEBUG(D_SNAP, "snap_needs_cow, ino %lu , get index %d\n",
115 inode->i_ino, index);
118 } /* snap_needs_cow */
120 int snap_print_table(struct ioc_snap_tbl_data *data, char *buf, int *buflen)
122 struct snap_table *table;
123 struct ioc_snap_tbl_data *stbl_out;
124 int tableno = data->no;
125 int i, rc = 0, nleft = (*buflen);
129 if (tableno < 0 || tableno > SNAP_MAX_TABLES) {
130 CERROR("invalid table number %d\n", tableno);
134 table = &snap_tables[tableno];
135 stbl_out = (struct ioc_snap_tbl_data *)buf;
136 stbl_out->count = table->tbl_count - 1;
137 stbl_out->no = tableno;
138 buf_ptr = (char*)stbl_out->snaps;
139 nleft -= buf_ptr - buf;
140 for (i = 1; i < table->tbl_count; i++) {
141 memcpy(buf_ptr, &table->snap_items[i], sizeof(struct snap));
143 nleft -= sizeof(struct snap);
145 CERROR("can not get enough space to print snaptable\n");
149 buf_ptr += sizeof(struct snap);
154 (*buflen) = (*buflen) - nleft;
157 static int inline get_index_of_item(struct snap_table *table, char *name)
159 int count = table->tbl_count;
162 for (i = 0; i < SNAP_MAX; i++) {
163 if (!strcmp(name, table->snap_items[i].name))
166 for (i = 0; i < SNAP_MAX; i++) {
168 for (j = 0; j < (count + 1); j++) {
169 if (table->snap_items[j].index == i) {
179 /* This function will write one item(a snapshot) to snaptable
180 * and will also write to disk.
182 static int snaptable_add_item(struct ioc_snap_tbl_data *data)
184 struct snap_table *table;
185 struct snap_disk_table *disk_snap_table;
186 struct snapshot_operations *snapops;
187 struct snap_cache *cache;
188 int tableno , index, i, count, rc;
190 if (!(cache = snap_find_cache((kdev_t)data->dev)))
193 snapops = filter_c2csnapops(cache->cache_filter);
194 if (!snapops || !snapops->set_meta_attr)
198 if (tableno < 0 || tableno > SNAP_MAX_TABLES) {
199 CERROR("invalid table number %d\n", tableno);
202 table = &snap_tables[tableno];
203 count = table->tbl_count;
205 /* XXX Is down this sema necessary*/
206 down_interruptible(&table->tbl_sema);
208 /*add item in snap_table set generation*/
209 table->snap_items[count].gen = table->generation + 1;
210 table->snap_items[count].time = CURRENT_TIME;
211 /* find table index */
212 index = get_index_of_item(table, data->snaps[0].name);
214 GOTO(exit, rc = -EINVAL);
216 table->snap_items[count].index = index;
217 table->snap_items[count].flags = 0;
218 memcpy(&table->snap_items[count].name[0],
219 data->snaps[0].name, SNAP_MAX_NAMELEN);
220 /* we will write the whole snap_table to disk */
221 SNAP_ALLOC(disk_snap_table, sizeof(struct snap_disk_table));
222 if (!disk_snap_table)
223 GOTO(exit, rc = -ENOMEM);
224 disk_snap_table->magic = cpu_to_le32((__u32)DISK_SNAP_TABLE_MAGIC);
225 disk_snap_table->count = cpu_to_le32((__u32)table->tbl_count);
226 disk_snap_table->generation = cpu_to_le32((__u32)table->generation + 1);
227 memset(&disk_snap_table->snap_items[0], 0,
228 SNAP_MAX * sizeof(struct snap_disk));
230 for (i = 1; i <= count; i++) {
231 struct snap *item = &table->snap_items[i];
232 disk_snap_table->snap_items[i-1].time = cpu_to_le64((__u64)item->time);
233 disk_snap_table->snap_items[i-1].gen = cpu_to_le32((__u32)item->gen);
234 disk_snap_table->snap_items[i-1].flags = cpu_to_le32((__u32)item->flags);
235 disk_snap_table->snap_items[i-1].index = cpu_to_le32((__u32)item->index);
236 memcpy(&disk_snap_table->snap_items[i-1].name , item->name, SNAP_MAX_NAMELEN);
238 rc = snapops->set_meta_attr(cache->cache_sb, DISK_SNAPTABLE_ATTR,
239 (char*)disk_snap_table, sizeof(struct snap_disk_table));
241 SNAP_FREE(disk_snap_table, sizeof(struct snap_disk_table));
245 up(&table->tbl_sema);
249 static int delete_inode(struct inode *primary, void *param)
251 struct snap_iterdata * data;
256 struct inode *redirect;
258 struct snap_table *table;
262 struct inode *next_ind = NULL;
263 int my_table[SNAP_MAX];
265 if(!primary) return 0;
267 data = (struct snap_iterdata*) param;
271 tableno = data->tableno;
274 CDEBUG(D_INODE, "delete_inode ino %lu, index %d\n", primary->i_ino, index);
276 table = &snap_tables[tableno];
278 redirect = snap_get_indirect(primary, NULL, index);
283 old_ind = redirect->i_ino;
285 slot = snap_index2slot(table, index) - 1;
287 this_index = table->snap_items[slot].index;
288 redirect = snap_get_indirect(primary, NULL, this_index);
292 snap_set_indirect(primary, old_ind, this_index, 0);
293 snap_set_indirect(primary, 0, index, 0);
298 /* get the FIRST index after this and before NOW */
299 /* used for destroy_indirect and block level cow */
300 /* XXX fix this later, now use tbl_count, not NOW */
301 delete_slot = snap_index2slot(table, index);
302 for(slot = table->tbl_count; slot > delete_slot; slot --)
304 my_table[slot - delete_slot] = table->snap_items[slot].index;
306 next_ind = snap_get_indirect
307 (primary, my_table, table->tbl_count - delete_slot );
308 if( next_ind && (next_ind->i_ino == primary->i_ino) ) {
313 if( next_ind && (next_ind->i_ino == old_ind) ) {
318 rc = snap_destroy_indirect(primary, index, next_ind);
320 if(next_ind) iput(next_ind);
323 CERROR("snap_destroy_indirect(ino %lu,index %d),ret %d\n",
324 primary->i_ino, index, rc);
328 static int snap_delete(struct super_block *sb, struct snap_iterdata *data)
330 CDEBUG(D_SNAP, "dev %d, tableno %d, index %d, time %lu\n",
331 data->dev, data->tableno, data->index, data->time );
333 snap_iterate(sb, &delete_inode, NULL, data, SNAP_ITERATE_COWED_INODE);
338 /* This function will delete one item(a snapshot) in the snaptable
339 * and will also delete the item in the disk.
341 int snaptable_delete_item(struct super_block *sb, struct snap_iterdata *data)
343 struct snap_table *table;
344 struct snap_disk_table *disk_snap_table;
345 struct snapshot_operations *snapops;
346 struct snap_cache *cache;
347 int tableno = data->tableno, index, i, slot, rc, count;
349 if (!(cache = snap_find_cache((kdev_t)data->dev)))
352 snapops = filter_c2csnapops(cache->cache_filter);
353 if (!snapops || !snapops->set_meta_attr)
356 if (tableno < 0 || tableno > SNAP_MAX_TABLES) {
357 CERROR("invalid table number %d\n", tableno);
360 /*first delete the snapshot
361 * FIXME if snap delete error, how to handle this error*/
362 rc = snap_delete(sb, data);
365 /*delete item in snaptable */
366 table = &snap_tables[tableno];
369 slot = snap_index2slot(table, index);
373 down_interruptible(&table->tbl_sema);
374 while(slot < table->tbl_count) {
375 struct snap *item = &table->snap_items[slot];
376 item->time = table->snap_items[slot + 1].time;
377 item->flags = table->snap_items[slot + 1].flags;
378 item->gen = table->snap_items[slot + 1].gen;
379 item->index = table->snap_items[slot + 1].index;
380 memcpy(&item->name[0], &table->snap_items[slot + 1].name[0],
386 SNAP_ALLOC(disk_snap_table, sizeof(struct snap_disk_table));
388 if (!disk_snap_table)
390 /* we will delete the item snap_table to disk */
392 disk_snap_table->magic = cpu_to_le32((__u32)DISK_SNAP_TABLE_MAGIC);
393 disk_snap_table->count = cpu_to_le32((__u32)table->tbl_count);
394 disk_snap_table->generation = cpu_to_le32((__u32)table->generation);
395 memset(&disk_snap_table->snap_items[0], 0,
396 SNAP_MAX * sizeof(struct snap_disk));
398 count = table->tbl_count;
400 for (i = 1; i <= count; i++) {
401 struct snap *item = &table->snap_items[i];
402 disk_snap_table->snap_items[i].time = cpu_to_le64((__u64)item->time);
403 disk_snap_table->snap_items[i].gen = cpu_to_le32((__u32)item->gen);
404 disk_snap_table->snap_items[i].flags = cpu_to_le32((__u32)item->flags);
405 disk_snap_table->snap_items[i].index = cpu_to_le32((__u32)item->index);
406 memcpy(&disk_snap_table->snap_items[i].name , item->name, SNAP_MAX_NAMELEN);
408 rc = snapops->set_meta_attr(cache->cache_sb, DISK_SNAPTABLE_ATTR,
409 (char*)disk_snap_table, sizeof(struct snap_disk_table));
411 SNAP_FREE(disk_snap_table, sizeof(struct snap_disk_table));
413 up(&table->tbl_sema);
418 int snapfs_read_snaptable(struct snap_cache *cache, int tableno)
420 struct snap_table *table;
421 struct snap_disk_table *disk_snap_table;
422 struct snapshot_operations *snapops;
427 snapops = filter_c2csnapops(cache->cache_filter);
428 if (!snapops || !snapops->get_meta_attr)
431 SNAP_ALLOC(disk_snap_table, sizeof(struct snap_disk_table));
433 size = sizeof(struct snap_disk_table);
436 table = &snap_tables[tableno];
438 memset(table, 0, sizeof(struct snap_table));
439 init_MUTEX(&table->tbl_sema);
441 /*Initialized table */
442 table->tbl_count = 1;
443 rc = snapops->get_meta_attr(cache->cache_sb, DISK_SNAPTABLE_ATTR,
444 (char*)disk_snap_table, &size);
446 SNAP_FREE(disk_snap_table, sizeof(struct snap_disk_table));
450 if (le32_to_cpu(disk_snap_table->magic) != DISK_SNAP_TABLE_MAGIC) {
451 CERROR("On disk snaptable is not right \n");
454 table->generation = le32_to_cpu(disk_snap_table->generation);
455 table->tbl_count += le32_to_cpu(disk_snap_table->count);
456 for ( i = 0; i < disk_snap_table->count; i++) {
457 struct snap *item = &table->snap_items[i + 1];
458 item->time = le64_to_cpu(disk_snap_table->snap_items[i].time);
459 item->gen = le32_to_cpu(disk_snap_table->snap_items[i].gen);
460 item->flags = le32_to_cpu(disk_snap_table->snap_items[i].flags);
461 item->index = le32_to_cpu(disk_snap_table->snap_items[i].index);
462 memcpy(&item->name[0], &disk_snap_table->snap_items[i].name[0],
465 SNAP_FREE(disk_snap_table, sizeof(struct snap_disk_table));
469 static int getdata(struct ioc_data *input, void **karg)
473 if (!input->ioc_inlen || !input->ioc_inbuf)
476 SNAP_ALLOC(tmp, input->ioc_inlen);
480 CDEBUG(D_SNAP, "snap_alloc:len %d, add %p\n", input->ioc_inlen, tmp);
482 memset(tmp, 0, input->ioc_inlen);
483 if (copy_from_user(tmp, input->ioc_inbuf, input->ioc_inlen)) {
484 CERROR("get inbuf data error \n");
485 SNAP_FREE(tmp, input->ioc_inlen);
493 static inline void freedata(void *data, struct ioc_data *input)
495 SNAP_FREE(data, input->ioc_inlen);
496 CDEBUG(D_SNAP, "snap_free:len %d, add %p\n", input->ioc_inlen, data);
499 static int get_next_inode(struct inode *pri, void *ino)
501 static ino_t prev_ino = -1 ;
502 ino_t this_ino = pri->i_ino;
503 ino_t find_ino = *(ino_t *)ino;
511 if( find_ino == prev_ino ) {
522 static int snap_get_next_inode(struct snap_ino_list_data *data, ino_t *found_ino, ino_t *parent_ino)
524 kdev_t dev = data->dev;
525 ino_t this_ino = data->ino;
527 struct snap_cache *cache;
530 struct dentry * dentry;
534 cache = snap_find_cache(dev);
540 snap_iterate( cache->cache_sb, &get_next_inode, NULL, &(data->ino),
541 SNAP_ITERATE_COWED_INODE);
543 if( data->ino == this_ino ) {
547 *found_ino = data->ino;
549 if( !(*found_ino) ) return 0;
552 inode = iget (cache->cache_sb, *found_ino);
553 if (list_empty(&inode->i_dentry)) {
554 CERROR("No dentry for ino %lu, Error(XXX)! \n", inode->i_ino);
559 dentry = dget(list_entry(inode->i_dentry.next, struct dentry, d_alias));
561 if( dentry->d_parent->d_inode)
562 *parent_ino = dentry->d_parent->d_inode->i_ino;
572 static int print_inode(struct inode *pri,void *param)
574 CDEBUG(D_SNAP, "cowed inode list: ino %lu \n", pri->i_ino);
578 static int snap_print(struct super_block *sb, void *data)
580 snap_iterate(sb, &print_inode, NULL, data, SNAP_ITERATE_COWED_INODE);
584 static int delete_new_inode(struct inode *pri, void *param)
586 struct snap_iterdata * data;
589 time_t restore_time = 0xFFFFFFFF;
595 if(snap_is_redirector(pri)){
600 data = (struct snap_iterdata*) param;
604 restore_time = data->time;
607 CDEBUG(D_SNAP, "ino %lu, index=%d, time=%lu\n",
608 pri->i_ino, index, restore_time);
611 if( pri->i_mtime > restore_time || pri->i_ctime > restore_time ) {
612 struct list_head *head = &pri->i_dentry, *pos;
614 CDEBUG(D_SNAP, "snap_restore ino %lu is newer, delete \n",pri->i_ino);
615 for( pos = head->next; pos != head; pos = pos->next ){
616 d_drop( list_entry(pos, struct dentry, d_alias) );
624 static int restore_inode(struct inode *pri, void *param)
626 struct snap_iterdata * data;
627 // struct snap_cache *cache;
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);
695 //int snap_restore(struct super_block *sb, void *data)
696 static int snap_restore(struct super_block *sb, struct snap_iterdata *data)
698 CDEBUG(D_SNAP, "dev %d, tableno %d, index %d, time %lu\n",
699 data->dev, data->tableno, data->index, data->time );
701 snap_iterate(sb, &delete_new_inode, NULL, data, SNAP_ITERATE_ALL_INODE);
702 snap_iterate(sb, &restore_inode, NULL, data, SNAP_ITERATE_COWED_INODE );
706 /* return the index number of a name in a table */
707 int snap_get_index_from_name(int tableno, char *name)
709 struct snap_table *table;
712 if ( tableno < 0 || tableno > SNAP_MAX_TABLES ) {
713 CERROR("invalid table number %d\n", tableno);
717 table = &snap_tables[tableno];
719 for ( slot = 0 ; slot < SNAP_MAX ; slot++ ) {
720 if(strncmp (&table->snap_items[slot].name[0], name,
721 SNAP_MAX_NAMELEN) == 0 ) {
722 return table->snap_items[slot].index;
728 int snap_iterate_func(int len, struct snap_ioc_data *ioc_data, unsigned int cmd)
730 struct snap_iterdata data;
731 struct super_block *sb;
732 struct snap_cache *cache;
733 struct snap_table *table;
734 char name[SNAP_MAX_NAMELEN];
735 int index, tableno, name_len, slot, rc;
742 cache = snap_find_cache(dev);
746 sb = cache->cache_sb;
747 tableno = cache->cache_snap_tableno;
748 table = &snap_tables[tableno];
750 name_len = len - sizeof(kdev_t);
751 memset(name, 0, SNAP_MAX_NAMELEN);
752 if(name_len > SNAP_MAX_NAMELEN)
753 name_len = SNAP_MAX_NAMELEN;
756 memcpy(name, ioc_data->name, name_len);
758 if ((index = snap_get_index_from_name (tableno, name)) < 0)
763 data.tableno = tableno;
764 slot = snap_index2slot (table, index);
768 data.time = table->snap_items[slot].time;
769 CDEBUG(D_SNAP, "dev %d, tableno %d, index %d, time %lu\n",
770 data.dev, data.tableno, data.index, data.time );
774 rc = snap_print(sb, &data);
776 case IOC_SNAP_DELETE:
777 rc = snaptable_delete_item(sb, &data);
779 case IOC_SNAP_RESTORE:
780 rc = snap_restore(sb, &data);
783 CERROR("unrecognized cmd %d \n", cmd);
790 #define BUF_SIZE 1024
791 int snap_ioctl (struct inode * inode, struct file * filp,
792 unsigned int cmd, unsigned long arg)
794 struct ioc_data input;
801 dev = MINOR(inode->i_rdev);
802 if (dev != SNAP_PSDEV_MINOR)
806 CDEBUG(D_IOCTL, "invalid inode\n");
810 if ( _IOC_TYPE(cmd) != IOC_SNAP_TYPE ||
811 _IOC_NR(cmd) < IOC_SNAP_MIN_NR ||
812 _IOC_NR(cmd) > IOC_SNAP_MAX_NR ) {
813 /*FIXME: Sometimes Gettimeof the day will come here
814 * still do not know the reason*/
815 CDEBUG(D_IOCTL, "invalid ioctl ( type %d, nr %d, size %d )\n",
816 _IOC_TYPE(cmd), _IOC_NR(cmd), _IOC_SIZE(cmd));
820 /* get data structures */
821 rc = copy_from_user(&input, (void *)arg, sizeof(input));
824 /* get data from the input data*/
825 rc = getdata(&input, &karg);
830 rc = snaptable_add_item(karg);
833 case IOC_SNAP_PRINTTABLE: {
834 struct ioc_data *output;
837 SNAP_ALLOC(tmp, BUF_SIZE);
838 output=(struct ioc_data*)tmp;
839 output->ioc_inbuf = output->ioc_bulk;
840 output->ioc_inlen = BUF_SIZE - sizeof(int) - sizeof(unsigned long);
841 snap_print_table(karg, output->ioc_inbuf, &(output->ioc_inlen));
843 rc = copy_to_user((char *)arg, output,
844 (output->ioc_inlen + sizeof(int) + sizeof(unsigned long)));
845 SNAP_FREE(tmp, BUF_SIZE);
849 case IOC_SNAP_GETINDEXFROMNAME: {
851 char name[SNAP_MAX_NAMELEN];
853 struct snap_cache *cache;
857 struct get_index_struct {
859 char name[SNAP_MAX_NAMELEN];
862 struct get_index_struct *data = karg;
864 name_len = input.ioc_inlen - sizeof(kdev_t);
866 memset(name, 0, SNAP_MAX_NAMELEN);
867 if(name_len > SNAP_MAX_NAMELEN)
868 name_len = SNAP_MAX_NAMELEN;
871 /*for(i=0 ; i< name_len; i++) {
872 name[i] = data->name[i];
875 memcpy(name, data->name, name_len);
876 printk("dev %d , len %d, name_len %d, find name is [%s]\n", 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(input.ioc_inlen, 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);